Re: [PATCH 1/3] Check function is GC'ed

Yao Qi
2014-08-28T10:50:19Z

Doug Evans <dje@google.com> writes:

> I'd like to solve this for both partial syms and .gdb_index.
>
> We want to, essentially, discard the entry if address is outside the
> range of the cu (the range needn't be contiguous, but for the task
> at hand I don't think it matters). I haven't dug into this too deeply,
> but if we have lowpc (which for example is that read_file_scope has
> before it calls handle_DW_AT_stmt_list (which calls dwarf_decode_lines),
> can we use that in the test? Can we arrange for all callers of
> dwarf_decode_lines_1 pass lowpc down to it? [Or both lowpc,highpc
> for a more complete test, but for the task at hand we've only been
> checking, effectively, lowpc all along so I don't mind leaving it at that
> for now.]

Hi Doug,
Patch below implemented what you suggested, if I understand you correct
:)

A new argument 'lowpc' is added to both dwarf2_build_include_psymtabs
and handle_DW_AT_stmt_list, to keep the similarity between them. I
thought about merging them into one function, but still need more
thinking.

--
Yao (齐尧)

Subject: [PATCH] Check function is GC'ed

I see the following fail on arm-none-eabi target,

(gdb) b 24^M
Breakpoint 1 at 0x4: file
../../../../git/gdb/testsuite/gdb.base/break-on-linker-gcd-function.cc,
line 24.^M
(gdb) FAIL: gdb.base/break-on-linker-gcd-function.exp: b 24

Currently, we are using flag has_section_at_zero to determine whether
address zero in debug info means the corresponding code has been
GC'ed, like this:

case DW_LNE_set_address:
address = read_address (abfd, line_ptr, cu, &bytes_read);

if (address == 0 && !dwarf2_per_objfile->has_section_at_zero)
{
/* This line table is for a function which has been
GCd by the linker. Ignore it. PR gdb/12528 */

However, this is incorrect on some bare metal targets, as .text
section is located at 0x0, so dwarf2_per_objfile->has_section_at_zero
is true. If a function is GC'ed by linker, the address is zero. GDB
thinks address zero is a function's address rather than this function
is GC'ed.

In this patch, we choose 'lowpc' got in read_file_scope to check
whether 'lowpc' is greater than zero. If it isn't, address zero really
means the function is GC'ed. In this patch, we pass 'lowpc' in
read_file_scope through handle_DW_AT_stmt_list and dwarf_decode_lines,
and to dwarf_decode_lines_1 finally.

This patch fixes the fail above. This patch also covers the path that
partial symbol isn't used, which is tested by starting gdb with
--readnow option.

It is regression tested on x86-linux with
target_board=dwarf4-gdb-index, and arm-none-eabi. OK to apply?

gdb:

2014-08-27 Yao Qi <yao@codesourcery.com>

* dwarf2read.c (dwarf_decode_lines): Update declaration.
(handle_DW_AT_stmt_list): Add argument 'lowpc'. Update
comments. Callers update.
(dwarf_decode_lines): Likewise.
(dwarf2_build_include_psymtabs): Likewise.
(dwarf_decode_lines_1): Add argument 'lowpc'. Update
comments. Skip the line table if 'lowpc' is greater than
'address'.

gdb/testsuite:

2014-08-27 Yao Qi <yao@codesourcery.com>

* gdb.base/break-on-linker-gcd-function.exp: Move test into new
proc set_breakpoint_on_gcd_function. Invoke
set_breakpoint_on_gcd_function. Restart GDB with --readnow and
invoke set_breakpoint_on_gcd_function again.
---
gdb/dwarf2read.c | 35 ++++++++++++++--------
.../gdb.base/break-on-linker-gcd-function.exp | 24 +++++++++++----
2 files changed, 41 insertions(+), 18 deletions(-)

diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index be32309..8fdae74 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -1512,7 +1512,8 @@ static struct line_header *dwarf_decode_line_header (unsigned int offset,
struct dwarf2_cu *cu);

static void dwarf_decode_lines (struct line_header *, const char *,
- struct dwarf2_cu *, struct partial_symtab *);
+ struct dwarf2_cu *, struct partial_symtab *,
+ CORE_ADDR);

static void dwarf2_start_subfile (const char *, const char *, const char *);

@@ -4436,7 +4437,8 @@ dwarf2_create_include_psymtab (const char *name, struct partial_symtab *pst,
static void
dwarf2_build_include_psymtabs (struct dwarf2_cu *cu,
struct die_info *die,
- struct partial_symtab *pst)
+ struct partial_symtab *pst,
+ CORE_ADDR lowpc)
{
struct line_header *lh = NULL;
struct attribute *attr;
@@ -4448,7 +4450,7 @@ dwarf2_build_include_psymtabs (struct dwarf2_cu *cu,
return; /* No linetable, so no includes. */

/* NOTE: pst->dirname is DW_AT_comp_dir (if present). */
- dwarf_decode_lines (lh, pst->dirname, cu, pst);
+ dwarf_decode_lines (lh, pst->dirname, cu, pst, lowpc);

free_line_header (lh);
}
@@ -5954,7 +5956,7 @@ process_psymtab_comp_unit_reader (const struct die_reader_specs *reader,

/* Get the list of files included in the current compilation unit,
and build a psymtab for each of them. */
- dwarf2_build_include_psymtabs (cu, comp_unit_die, pst);
+ dwarf2_build_include_psymtabs (cu, comp_unit_die, pst, pst->textlow);

if (dwarf2_read_debug)
{
@@ -8967,11 +8969,12 @@ find_file_and_directory (struct die_info *die, struct dwarf2_cu *cu,

/* Handle DW_AT_stmt_list for a compilation unit.
DIE is the DW_TAG_compile_unit die for CU.
- COMP_DIR is the compilation directory. */
+ COMP_DIR is the compilation directory. LOWPC is passed to
+ dwarf_decode_lines. See dwarf_decode_lines comments about it. */

static void
handle_DW_AT_stmt_list (struct die_info *die, struct dwarf2_cu *cu,
- const char *comp_dir) /* ARI: editCase function */
+ const char *comp_dir, CORE_ADDR lowpc) /* ARI: editCase function */
{
struct attribute *attr;

@@ -8988,7 +8991,7 @@ handle_DW_AT_stmt_list (struct die_info *die, struct dwarf2_cu *cu,
{
cu->line_header = line_header;
make_cleanup (free_cu_line_header, cu);
- dwarf_decode_lines (line_header, comp_dir, cu, NULL);
+ dwarf_decode_lines (line_header, comp_dir, cu, NULL, lowpc);
}
}
}
@@ -9039,7 +9042,7 @@ read_file_scope (struct die_info *die, struct dwarf2_cu *cu)
/* Decode line number information if present. We do this before
processing child DIEs, so that the line header table is available
for DW_AT_decl_file. */
- handle_DW_AT_stmt_list (die, cu, comp_dir);
+ handle_DW_AT_stmt_list (die, cu, comp_dir, lowpc);

/* Process all dies in compilation unit. */
if (die->child != NULL)
@@ -17252,7 +17255,8 @@ dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile,

static void
dwarf_decode_lines_1 (struct line_header *lh, const char *comp_dir,
- struct dwarf2_cu *cu, const int decode_for_pst_p)
+ struct dwarf2_cu *cu, const int decode_for_pst_p,
+ CORE_ADDR lowpc)
{
const gdb_byte *line_ptr, *extended_end;
const gdb_byte *line_end;
@@ -17375,7 +17379,9 @@ dwarf_decode_lines_1 (struct line_header *lh, const char *comp_dir,
case DW_LNE_set_address:
address = read_address (abfd, line_ptr, cu, &bytes_read);

- if (address == 0 && !dwarf2_per_objfile->has_section_at_zero)
+ if (address == 0
+ && (!dwarf2_per_objfile->has_section_at_zero
+ || lowpc > address))
{
/* This line table is for a function which has been
GCd by the linker. Ignore it. PR gdb/12528 */
@@ -17595,17 +17601,20 @@ dwarf_decode_lines_1 (struct line_header *lh, const char *comp_dir,
as the corresponding symtab. Since COMP_DIR is not used in the name of the
symtab we don't use it in the name of the psymtabs we create.
E.g. expand_line_sal requires this when finding psymtabs to expand.
- A good testcase for this is mb-inline.exp. */
+ A good testcase for this is mb-inline.exp.
+
+ LOWPC is the lowest address in CU (or 0 if not known). */

static void
dwarf_decode_lines (struct line_header *lh, const char *comp_dir,
- struct dwarf2_cu *cu, struct partial_symtab *pst)
+ struct dwarf2_cu *cu, struct partial_symtab *pst,
+ CORE_ADDR lowpc)
{
struct objfile *objfile = cu->objfile;
const int decode_for_pst_p = (pst != NULL);
struct subfile *first_subfile = current_subfile;

- dwarf_decode_lines_1 (lh, comp_dir, cu, decode_for_pst_p);
+ dwarf_decode_lines_1 (lh, comp_dir, cu, decode_for_pst_p, lowpc);

if (decode_for_pst_p)
{
diff --git a/gdb/testsuite/gdb.base/break-on-linker-gcd-function.exp b/gdb/testsuite/gdb.base/break-on-linker-gcd-function.exp
index e593b51..b8de1cd 100644
--- a/gdb/testsuite/gdb.base/break-on-linker-gcd-function.exp
+++ b/gdb/testsuite/gdb.base/break-on-linker-gcd-function.exp
@@ -41,9 +41,23 @@ if {[build_executable_from_specs $testfile.exp $testfile \

clean_restart $testfile

-# Single hex digit
-set xd {[0-9a-f]}
+proc set_breakpoint_on_gcd_function {} {
+ # Single hex digit
+ set xd {[0-9a-f]}
+
+ # This accepts e.g. "Breakpoint 1 at 0x40968a" (fixed GDB)
+ # but rejects e.g. "Breakpoint 1 at 0x4" (broken GDB).
+ gdb_test "b [gdb_get_line_number "gdb break here"]" \
+ "Breakpoint \[0-9\] at 0x${xd}${xd}+: .*"
+}
+
+set_breakpoint_on_gcd_function

-# This accepts e.g. "Breakpoint 1 at 0x40968a" (fixed GDB)
-# but rejects e.g. "Breakpoint 1 at 0x4" (broken GDB).
-gdb_test "b [gdb_get_line_number "gdb break here"]" "Breakpoint \[0-9\] at 0x${xd}${xd}+: .*"
+set saved_gdbflags $GDBFLAGS
+set GDBFLAGS "$GDBFLAGS --readnow"
+clean_restart ${testfile}
+set GDBFLAGS $saved_gdbflags
+
+with_test_prefix "readnow" {
+ set_breakpoint_on_gcd_function
+}
--
1.9.3