[rfa] pc bounds checking and namespaces

David Carlton
2004-01-17T00:49:22Z

When calculating the pc bounds for a block in dwarf2read.c, we assume
that all functions contained in that block are immediate children of
the block. I was using a patched version of GCC where this doesn't
hold - the dies associated to definitions of functions in namespaces
are children of a DW_TAG_namespace die instead of the
DW_TAG_compile_unit die. I don't know where GCC 3.4 puts the
relevant dies, so this might not be an issue with GCC 3.4, but it
might be; it seems like fixing that assumption is a good idea in any
case.

So this patch takes the code to calculate the lowpc/highpc out of
psymtab_to_symtab_1 and read_file_scope (where that functionality had
been duplicated), extracts it to a new function get_scope_pc_bounds,
and then modifies that new function to handle DW_TAG_namespace
appropriately.

I tried to come up with a test case for this, but I wasn't
successful. :-( I can say that, before this patch, I used to see a lot
of "pc 0xNNNN in read in psymtab, but not in symtab" messages when
debugging, and now I don't.

Tested on GCC 3.2 both with and without DW_TAG_namespace,
i686-pc-linux-gnu, DWARF-2; no regressions. OK to commit?

David Carlton
carlton@kealia.com

2004-01-16 David Carlton <carlton@kealia.com>

* dwarf2read.c (psymtab_to_symtab_1): Calculate lowpc, highpc via
get_scope_pc_bounds.
(read_file_scope): Ditto.
(get_scope_pc_bounds): New function, produced by extracting code
from the above two functions, consolidating it, and adding support
for DW_TAG_namespace.

Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.120
diff -u -p -r1.120 dwarf2read.c
--- dwarf2read.c 14 Jan 2004 16:54:41 -0000 1.120
+++ dwarf2read.c 17 Jan 2004 00:27:04 -0000
@@ -805,6 +805,10 @@ static void read_lexical_block_scope (st
static int dwarf2_get_pc_bounds (struct die_info *,
CORE_ADDR *, CORE_ADDR *, struct dwarf2_cu *);

+static void get_scope_pc_bounds (struct die_info *,
+ CORE_ADDR *, CORE_ADDR *,
+ struct dwarf2_cu *);
+
static void dwarf2_add_field (struct field_info *, struct die_info *,
struct dwarf2_cu *);

@@ -1882,30 +1886,8 @@ psymtab_to_symtab_1 (struct partial_symt
/* Do line number decoding in read_file_scope () */
process_die (dies, &cu);

- if (!dwarf2_get_pc_bounds (dies, &lowpc, &highpc, &cu))
- {
- /* Some compilers don't define a DW_AT_high_pc attribute for
- the compilation unit. If the DW_AT_high_pc is missing,
- synthesize it, by scanning the DIE's below the compilation unit. */
- highpc = 0;
- if (dies->child != NULL)
- {
- child_die = dies->child;
- while (child_die && child_die->tag)
- {
- if (child_die->tag == DW_TAG_subprogram)
- {
- CORE_ADDR low, high;
+ get_scope_pc_bounds (dies, &lowpc, &highpc, &cu);

- if (dwarf2_get_pc_bounds (child_die, &low, &high, &cu))
- {
- highpc = max (highpc, high);
- }
- }
- child_die = sibling_die (child_die);
- }
- }
- }
symtab = end_symtab (highpc + baseaddr, objfile, SECT_OFF_TEXT (objfile));

/* Set symtab language to language from DW_AT_language.
@@ -2029,27 +2011,7 @@ read_file_scope (struct die_info *die, s
bfd *abfd = objfile->obfd;
struct line_header *line_header = 0;

- if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu))
- {
- if (die->child != NULL)
- {
- child_die = die->child;
- while (child_die && child_die->tag)
- {
- if (child_die->tag == DW_TAG_subprogram)
- {
- CORE_ADDR low, high;
-
- if (dwarf2_get_pc_bounds (child_die, &low, &high, cu))
- {
- lowpc = min (lowpc, low);
- highpc = max (highpc, high);
- }
- }
- child_die = sibling_die (child_die);
- }
- }
- }
+ get_scope_pc_bounds (die, &lowpc, &highpc, cu);

/* If we didn't find a lowpc, set it to highpc to avoid complaints
from finish_block. */
@@ -2438,6 +2400,68 @@ dwarf2_get_pc_bounds (struct die_info *d
*lowpc = low;
*highpc = high;
return ret;
+}
+
+/* Get the low and high pc's represented by the scope DIE, and store
+ them in *LOWPC and *HIGHPC. If the correct values can't be
+ determined, set *LOWPC to -1 and *HIGHPC to 0. */
+
+static void
+get_scope_pc_bounds (struct die_info *die,
+ CORE_ADDR *lowpc, CORE_ADDR *highpc,
+ struct dwarf2_cu *cu)
+{
+ CORE_ADDR best_low = (CORE_ADDR) -1;
+ CORE_ADDR best_high = (CORE_ADDR) 0;
+ CORE_ADDR current_low, current_high;
+
+ if (dwarf2_get_pc_bounds (die, &current_low, &current_high, cu))
+ {
+ best_low = current_low;
+ best_high = current_high;
+ }
+ else
+ {
+ struct die_info *child = die->child;
+
+ while (child && child->tag)
+ {
+ switch (child->tag) {
+ case DW_TAG_subprogram:
+ if (dwarf2_get_pc_bounds (child, &current_low, &current_high, cu))
+ {
+ best_low = min (best_low, current_low);
+ best_high = max (best_high, current_high);
+ }
+ break;
+ case DW_TAG_namespace:
+ /* FIXME: carlton/2004-01-16: Should we do this for
+ DW_TAG_class_type/DW_TAG_structure_type, too? I think
+ that current GCC's always emit the DIEs corresponding
+ to definitions of methods of classes as children of a
+ DW_TAG_compile_unit or DW_TAG_namespace (as opposed to
+ the DIEs giving the declarations, which could be
+ anywhere). But I don't see any reason why the
+ standards says that they have to be there. */
+ get_scope_pc_bounds (child, &current_low, &current_high, cu);
+
+ if (current_low != ((CORE_ADDR) -1))
+ {
+ best_low = min (best_low, current_low);
+ best_high = max (best_high, current_high);
+ }
+ break;
+ default:
+ /* Ignore. */
+ break;
+ }
+
+ child = sibling_die (child);
+ }
+ }
+
+ *lowpc = best_low;
+ *highpc = best_high;
}

/* Add an aggregate field to the field list. */