diff options
author | Jim Blandy <jimb@codesourcery.com> | 2007-12-04 23:43:57 +0000 |
---|---|---|
committer | Jim Blandy <jimb@codesourcery.com> | 2007-12-04 23:43:57 +0000 |
commit | 801e3a5b5681c44b2fec1b392dddec386870647c (patch) | |
tree | fc5540169fef73f5721542765234f47023c7763d /gdb/dwarf2read.c | |
parent | c420411fe81ad583b2154fd9338fd0076761d99d (diff) | |
download | gdb-801e3a5b5681c44b2fec1b392dddec386870647c.zip gdb-801e3a5b5681c44b2fec1b392dddec386870647c.tar.gz gdb-801e3a5b5681c44b2fec1b392dddec386870647c.tar.bz2 |
Support lexical blocks and function bodies that occupy
non-contiguous address ranges.
* addrmap.c, addrmap.h: New files.
* block.h (struct addrmap): New forward declaration.
(struct blockvector): New member, 'map'.
(BLOCKVECTOR_MAP): New accessor macro.
* block.c: #include "addrmap.h"
(blockvector_for_pc_sect): If the blockvector we've found has
an address map, use it instead of searching the blocks.
* buildsym.c: #include "addrmap.h"
(pending_addrmap_obstack, pending_addrmap_interesting): New static
variables.
(really_free_pendings): If we have a pending addrmap, free it too.
(record_block_range): New function.
(make_blockvector): If we have an interesting pending addrmap,
record it in the new blockvector.
(start_symtab, buildsym_init): Assert that there is no pending
addrmap now; we should have cleaned up any addrmaps we'd built
previously.
(end_symtab): If there is a pending addrmap left over that didn't
get included in the blockvector, free it.
* buildsym.h (struct addrmap): New forward declaration.
(record_block_range): New prototype.
* objfiles.c: #include "addrmap.h".
(objfile_relocate): Relocate the blockvector's address map, if
present.
* dwarf2read.c (dwarf2_record_block_ranges): New function.
(read_func_scope, read_lexical_block_scope): Call it.
* Makefile.in (SFILES): Add addrmap.c.
(addrmap_h): New header dependency variable.
(COMMON_OBS): Add addrmap.o.
(addrmap.o): New rule.l
(block.o, objfiles.o, buildsym.o): Depend on $(addrmap_h).
* block.c (blockvector_for_pc, blockvector_for_pc_sect): Return a
pointer to the block, not its index in the blockvector.
(block_for_pc_sect): Use the returned block, instead of looking it
up ourselves.
* block.h (blockvector_for_pc, blockvector_for_pc_sect): Update
declarations.
* breakpoint.c (resolve_sal_pc): Use returned block, instead of
looking it up ourselves.
* stack.c (print_frame_label_vars): Disable function, which
depends on the block's index.
* buildsym.c (finish_block): Return the block we've built.
* buildsym.h (finish_block): Update prototype.
* defs.h (CORE_ADDR_MAX): New constant.
Diffstat (limited to 'gdb/dwarf2read.c')
-rw-r--r-- | gdb/dwarf2read.c | 122 |
1 files changed, 118 insertions, 4 deletions
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index fa5d3c8..eb2564e 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -895,6 +895,9 @@ static void get_scope_pc_bounds (struct die_info *, CORE_ADDR *, CORE_ADDR *, struct dwarf2_cu *); +static void dwarf2_record_block_ranges (struct die_info *, struct block *, + CORE_ADDR, struct dwarf2_cu *); + static void dwarf2_add_field (struct field_info *, struct die_info *, struct dwarf2_cu *); @@ -2910,6 +2913,7 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) const char *previous_prefix = processing_current_prefix; struct cleanup *back_to = NULL; CORE_ADDR baseaddr; + struct block *block; baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); @@ -2993,8 +2997,11 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) new = pop_context (); /* Make a block for the local symbols within. */ - finish_block (new->name, &local_symbols, new->old_blocks, - lowpc, highpc, objfile); + block = finish_block (new->name, &local_symbols, new->old_blocks, + lowpc, highpc, objfile); + + /* If we have address ranges, record them. */ + dwarf2_record_block_ranges (die, block, baseaddr, cu); /* In C++, we can have functions nested inside functions (e.g., when a function declares a class that has methods). This means that @@ -3051,8 +3058,21 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu) if (local_symbols != NULL) { - finish_block (0, &local_symbols, new->old_blocks, new->start_addr, - highpc, objfile); + struct block *block + = finish_block (0, &local_symbols, new->old_blocks, new->start_addr, + highpc, objfile); + + /* Note that recording ranges after traversing children, as we + do here, means that recording a parent's ranges entails + walking across all its children's ranges as they appear in + the address map, which is quadratic behavior. + + It would be nicer to record the parent's ranges before + traversing its children, simply overriding whatever you find + there. But since we don't even decide whether to create a + block until after we've traversed its children, that's hard + to do. */ + dwarf2_record_block_ranges (die, block, baseaddr, cu); } local_symbols = new->locals; } @@ -3296,6 +3316,100 @@ get_scope_pc_bounds (struct die_info *die, *highpc = best_high; } +/* Record the address ranges for BLOCK, offset by BASEADDR, as given + in DIE. */ +static void +dwarf2_record_block_ranges (struct die_info *die, struct block *block, + CORE_ADDR baseaddr, struct dwarf2_cu *cu) +{ + struct attribute *attr; + + attr = dwarf2_attr (die, DW_AT_high_pc, cu); + if (attr) + { + CORE_ADDR high = DW_ADDR (attr); + attr = dwarf2_attr (die, DW_AT_low_pc, cu); + if (attr) + { + CORE_ADDR low = DW_ADDR (attr); + record_block_range (block, baseaddr + low, baseaddr + high - 1); + } + } + + attr = dwarf2_attr (die, DW_AT_ranges, cu); + if (attr) + { + bfd *obfd = cu->objfile->obfd; + + /* The value of the DW_AT_ranges attribute is the offset of the + address range list in the .debug_ranges section. */ + unsigned long offset = DW_UNSND (attr); + gdb_byte *buffer = dwarf2_per_objfile->ranges_buffer + offset; + + /* For some target architectures, but not others, the + read_address function sign-extends the addresses it returns. + To recognize base address selection entries, we need a + mask. */ + unsigned int addr_size = cu->header.addr_size; + CORE_ADDR base_select_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1)); + + /* The base address, to which the next pair is relative. Note + that this 'base' is a DWARF concept: most entries in a range + list are relative, to reduce the number of relocs against the + debugging information. This is separate from this function's + 'baseaddr' argument, which GDB uses to relocate debugging + information from a shared library based on the address at + which the library was loaded. */ + CORE_ADDR base = cu->header.base_address; + int base_known = cu->header.base_known; + + if (offset >= dwarf2_per_objfile->ranges_size) + { + complaint (&symfile_complaints, + _("Offset %lu out of bounds for DW_AT_ranges attribute"), + offset); + return; + } + + for (;;) + { + unsigned int bytes_read; + CORE_ADDR start, end; + + start = read_address (obfd, buffer, cu, &bytes_read); + buffer += bytes_read; + end = read_address (obfd, buffer, cu, &bytes_read); + buffer += bytes_read; + + /* Did we find the end of the range list? */ + if (start == 0 && end == 0) + break; + + /* Did we find a base address selection entry? */ + else if ((start & base_select_mask) == base_select_mask) + { + base = end; + base_known = 1; + } + + /* We found an ordinary address range. */ + else + { + if (!base_known) + { + complaint (&symfile_complaints, + _("Invalid .debug_ranges data (no base address)")); + return; + } + + record_block_range (block, + baseaddr + base + start, + baseaddr + base + end - 1); + } + } + } +} + /* Add an aggregate field to the field list. */ static void |