Re: [RFC] Partial support for dwarf3 DW_AT_ranges

Elena Zannoni
2003-01-30T01:02:35Z

Daniel Jacobowitz writes:
> On Wed, Jan 29, 2003 at 01:13:36PM -0500, Elena Zannoni wrote:
> > If you have time, I'd appreciate it. I have adapted the patch to the
> > current sources, but even with it, I wasn't able to make Jakub's
> > example work. The example is in PR 833.
> > I can send you the diffs I have, if it helps.
>
> This is pretty similar to what you sent me, cleaned up a little to
> match my reading of the standard. It works to fix my testcase for PR
> gdb/961, which is a simpler case of disappearing local variables.
> I'll submit that for the testsuite separately but I don't know quite
> how to do it yet; the problem is not going to show up if you don't have
> optimization.
>

cool! i think there is a testcase in gdb.base somewhere that turns
optimization up to -O2, so you could copy that (mips-pro.exp and
break.exp), if this is what you are asking.

> This doesn't solve PR gdb/833, for the reasons outlined in my previous
> message.
>
> How does this patch look?
>

ok with me.

thanks!!

elena

> --
> Daniel Jacobowitz
> MontaVista Software Debian GNU/Linux Developer
>
> 2003-01-29 Richard Henderson <rth@redhat.com>
> Elena Zannoni <ezannoni@redhat.com>
> Daniel Jacobowitz <drow@mvista.com>
>
> Fix PR gdb/961.
> * dwarf2read.c (dwarf_ranges_offset, dwarf_ranges_size): New
> variables.
> (RANGES_SECTION): New.
> (dwarf_ranges_buffer): New variable.
> (struct comp_unit_head): Add member "die".
> (struct dwarf2_pinfo): Add dwarf_ranges_buffer, dwarf_ranges_size.
> (DWARF_RANGES_BUFFER, DWARF_RANGES_SIZE): New.
> (dwarf2_has_info): Init dwarf_ranges_offset and dwarf_ranges_size.
> (dwarf2_locate_sections): Likewise.
> (dwarf2_build_psymtabs): Read .debug_ranges.
> (dwarf2_build_psymtabs_hard): Swap dwarf_ranges out.
> (psymtab_to_symtab_1): Swap dwarf_ranges in. Set cu_header.die.
> (RANGES_SECTION): New.

twice mentioned

> (dwarf2_get_pc_bounds): New cu_header argument; adjust all callers.
> Look for DW_AT_ranges and return the bounding box.
>
> Index: dwarf2read.c
> ===================================================================
> RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2read.c,v
> retrieving revision 1.79
> diff -u -p -r1.79 dwarf2read.c
> --- dwarf2read.c 18 Jan 2003 15:55:51 -0000 1.79
> +++ dwarf2read.c 30 Jan 2003 00:41:19 -0000
> @@ -133,6 +133,7 @@ static file_ptr dwarf_aranges_offset;
> static file_ptr dwarf_loc_offset;
> static file_ptr dwarf_macinfo_offset;
> static file_ptr dwarf_str_offset;
> +static file_ptr dwarf_ranges_offset;
> file_ptr dwarf_frame_offset;
> file_ptr dwarf_eh_frame_offset;
>
> @@ -144,6 +145,7 @@ static unsigned int dwarf_aranges_size;
> static unsigned int dwarf_loc_size;
> static unsigned int dwarf_macinfo_size;
> static unsigned int dwarf_str_size;
> +static unsigned int dwarf_ranges_size;
> unsigned int dwarf_frame_size;
> unsigned int dwarf_eh_frame_size;
>
> @@ -157,6 +159,7 @@ unsigned int dwarf_eh_frame_size;
> #define LOC_SECTION ".debug_loc"
> #define MACINFO_SECTION ".debug_macinfo"
> #define STR_SECTION ".debug_str"
> +#define RANGES_SECTION ".debug_ranges"
> #define FRAME_SECTION ".debug_frame"
> #define EH_FRAME_SECTION ".eh_frame"
>
> @@ -202,6 +205,10 @@ struct comp_unit_head
> /* DWARF abbreviation table associated with this compilation unit */
>
> struct abbrev_info *dwarf2_abbrevs[ABBREV_HASH_SIZE];
> +
> + /* Pointer to the DIE associated with the compilation unit. */
> +
> + struct die_info *die;
> };
>
> /* The line number information for a compilation unit (found in the
> @@ -373,6 +380,7 @@ static char *dwarf_abbrev_buffer;
> static char *dwarf_line_buffer;
> static char *dwarf_str_buffer;
> static char *dwarf_macinfo_buffer;
> +static char *dwarf_ranges_buffer;
>
> /* A zeroed version of a partial die for initialization purposes. */
> static struct partial_die_info zeroed_partial_die;
> @@ -481,6 +489,14 @@ struct dwarf2_pinfo
>
> unsigned int dwarf_macinfo_size;
>
> + /* Pointer to start of dwarf ranges buffer for the objfile. */
> +
> + char *dwarf_ranges_buffer;
> +
> + /* Size of dwarf ranges buffer for the objfile. */
> +
> + unsigned int dwarf_ranges_size;
> +
> };
>
> #define PST_PRIVATE(p) ((struct dwarf2_pinfo *)(p)->read_symtab_private)
> @@ -494,6 +510,8 @@ struct dwarf2_pinfo
> #define DWARF_STR_SIZE(p) (PST_PRIVATE(p)->dwarf_str_size)
> #define DWARF_MACINFO_BUFFER(p) (PST_PRIVATE(p)->dwarf_macinfo_buffer)
> #define DWARF_MACINFO_SIZE(p) (PST_PRIVATE(p)->dwarf_macinfo_size)
> +#define DWARF_RANGES_BUFFER(p) (PST_PRIVATE(p)->dwarf_ranges_buffer)
> +#define DWARF_RANGES_SIZE(p) (PST_PRIVATE(p)->dwarf_ranges_size)
>
> /* Maintain an array of referenced fundamental types for the current
> compilation unit being read. For DWARF version 1, we have to construct
> @@ -751,7 +769,8 @@ static void read_lexical_block_scope (st
> const struct comp_unit_head *);
>
> static int dwarf2_get_pc_bounds (struct die_info *,
> - CORE_ADDR *, CORE_ADDR *, struct objfile *);
> + CORE_ADDR *, CORE_ADDR *, struct objfile *,
> + const struct comp_unit_head *);
>
> static void dwarf2_add_field (struct field_info *, struct die_info *,
> struct objfile *, const struct comp_unit_head *);
> @@ -886,6 +905,8 @@ dwarf2_has_info (bfd *abfd)
> dwarf_macinfo_offset = 0;
> dwarf_frame_offset = 0;
> dwarf_eh_frame_offset = 0;
> + dwarf_ranges_offset = 0;
> +
> bfd_map_over_sections (abfd, dwarf2_locate_sections, NULL);
> if (dwarf_info_offset && dwarf_abbrev_offset)
> {
> @@ -954,6 +975,11 @@ dwarf2_locate_sections (bfd *ignore_abfd
> dwarf_eh_frame_offset = sectp->filepos;
> dwarf_eh_frame_size = bfd_get_section_size_before_reloc (sectp);
> }
> + else if (STREQ (sectp->name, RANGES_SECTION))
> + {
> + dwarf_ranges_offset = sectp->filepos;
> + dwarf_ranges_size = bfd_get_section_size_before_reloc (sectp);
> + }
> }
>
> /* Build a partial symbol table. */
> @@ -992,6 +1018,13 @@ dwarf2_build_psymtabs (struct objfile *o
> else
> dwarf_macinfo_buffer = NULL;
>
> + if (dwarf_ranges_offset)
> + dwarf_ranges_buffer = dwarf2_read_section (objfile,
> + dwarf_ranges_offset,
> + dwarf_ranges_size);
> + else
> + dwarf_ranges_buffer = NULL;
> +
> if (mainline
> || (objfile->global_psymbols.size == 0
> && objfile->static_psymbols.size == 0))
> @@ -1207,6 +1240,8 @@ dwarf2_build_psymtabs_hard (struct objfi
> DWARF_STR_SIZE (pst) = dwarf_str_size;
> DWARF_MACINFO_BUFFER (pst) = dwarf_macinfo_buffer;
> DWARF_MACINFO_SIZE (pst) = dwarf_macinfo_size;
> + DWARF_RANGES_BUFFER (pst) = dwarf_ranges_buffer;
> + DWARF_RANGES_SIZE (pst) = dwarf_ranges_size;
> baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
>
> /* Store the function that reads in the rest of the symbol table */
> @@ -1543,6 +1578,8 @@ psymtab_to_symtab_1 (struct partial_symt
> dwarf_str_size = DWARF_STR_SIZE (pst);
> dwarf_macinfo_buffer = DWARF_MACINFO_BUFFER (pst);
> dwarf_macinfo_size = DWARF_MACINFO_SIZE (pst);
> + dwarf_ranges_buffer = DWARF_RANGES_BUFFER (pst);
> + dwarf_ranges_size = DWARF_RANGES_SIZE (pst);
> baseaddr = ANOFFSET (pst->section_offsets, SECT_OFF_TEXT (objfile));
> cu_header_offset = offset;
> info_ptr = dwarf_info_buffer + offset;
> @@ -1565,9 +1602,10 @@ psymtab_to_symtab_1 (struct partial_symt
> make_cleanup_free_die_list (dies);
>
> /* Do line number decoding in read_file_scope () */
> + cu_header.die = dies;
> process_die (dies, objfile, &cu_header);
>
> - if (!dwarf2_get_pc_bounds (dies, &lowpc, &highpc, objfile))
> + if (!dwarf2_get_pc_bounds (dies, &lowpc, &highpc, objfile, &cu_header))
> {
> /* Some compilers don't define a DW_AT_high_pc attribute for
> the compilation unit. If the DW_AT_high_pc is missing,
> @@ -1582,7 +1620,8 @@ psymtab_to_symtab_1 (struct partial_symt
> {
> CORE_ADDR low, high;
>
> - if (dwarf2_get_pc_bounds (child_die, &low, &high, objfile))
> + if (dwarf2_get_pc_bounds (child_die, &low, &high,
> + objfile, &cu_header))
> {
> highpc = max (highpc, high);
> }
> @@ -1711,7 +1750,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, objfile))
> + if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, objfile, cu_header))
> {
> if (die->has_children)
> {
> @@ -1722,7 +1761,8 @@ read_file_scope (struct die_info *die, s
> {
> CORE_ADDR low, high;
>
> - if (dwarf2_get_pc_bounds (child_die, &low, &high, objfile))
> + if (dwarf2_get_pc_bounds (child_die, &low, &high,
> + objfile, cu_header))
> {
> lowpc = min (lowpc, low);
> highpc = max (highpc, high);
> @@ -1868,7 +1908,7 @@ read_func_scope (struct die_info *die, s
>
> /* Ignore functions with missing or empty names and functions with
> missing or invalid low and high pc attributes. */
> - if (name == NULL || !dwarf2_get_pc_bounds (die, &lowpc, &highpc, objfile))
> + if (name == NULL || !dwarf2_get_pc_bounds (die, &lowpc, &highpc, objfile, cu_header))
> return;
>
> lowpc += baseaddr;
> @@ -1966,7 +2006,11 @@ read_lexical_block_scope (struct die_inf
> struct die_info *child_die;
>
> /* Ignore blocks with missing or invalid low and high pc attributes. */
> - if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, objfile))
> + /* ??? Perhaps consider discontiguous blocks defined by DW_AT_ranges
> + as multiple lexical blocks? Handling children in a sane way would
> + be nasty. Might be easier to properly extend generic blocks to
> + describe ranges. */
> + if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, objfile, cu_header))
> return;
> lowpc += baseaddr;
> highpc += baseaddr;
> @@ -1991,27 +2035,159 @@ read_lexical_block_scope (struct die_inf
> local_symbols = new->locals;
> }
>
> -/* Get low and high pc attributes from a die.
> - Return 1 if the attributes are present and valid, otherwise, return 0. */
> -
> +/* Get low and high pc attributes from a die. Return 1 if the attributes
> + are present and valid, otherwise, return 0. Return -1 if the range is
> + discontinuous, i.e. derived from DW_AT_ranges information. */
> static int
> -dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc, CORE_ADDR *highpc,
> - struct objfile *objfile)
> +dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
> + CORE_ADDR *highpc, struct objfile *objfile,
> + const struct comp_unit_head *cu_header)
> {
> struct attribute *attr;
> - CORE_ADDR low;
> - CORE_ADDR high;
> + bfd *obfd = objfile->obfd;
> + CORE_ADDR low = 0;
> + CORE_ADDR high = 0;
> + int ret = 0;
>
> - attr = dwarf_attr (die, DW_AT_low_pc);
> - if (attr)
> - low = DW_ADDR (attr);
> - else
> - return 0;
> attr = dwarf_attr (die, DW_AT_high_pc);
> if (attr)
> - high = DW_ADDR (attr);
> + {
> + high = DW_ADDR (attr);
> + attr = dwarf_attr (die, DW_AT_low_pc);
> + if (attr)
> + low = DW_ADDR (attr);
> + else
> + /* Found high w/o low attribute. */
> + return 0;
> +
> + /* Found consecutive range of addresses. */
> + ret = 1;
> + }
> else
> - return 0;
> + {
> + attr = dwarf_attr (die, DW_AT_ranges);
> + if (attr != NULL)
> + {
> + unsigned int addr_size = cu_header->addr_size;
> + CORE_ADDR mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
> + /* Value of the DW_AT_ranges attribute is the offset in the
> + .debug_renges section. */
> + unsigned int offset = DW_UNSND (attr);
> + /* Base address selection entry. */
> + CORE_ADDR base = 0;
> + int found_base = 0;
> + int dummy;
> + unsigned int i;
> + char *buffer;
> + CORE_ADDR marker;
> + int low_set;
> +
> + /* The applicable base address is determined by (1) the closest
> + preceding base address selection entry in the range list or
> + (2) the DW_AT_low_pc of the compilation unit. */
> +
> + /* ??? Was in dwarf3 draft4, and has since been removed.
> + GCC still uses it though. */
> + attr = dwarf_attr (cu_header->die, DW_AT_entry_pc);
> + if (attr)
> + {
> + base = DW_ADDR (attr);
> + found_base = 1;
> + }
> +
> + if (!found_base)
> + {
> + attr = dwarf_attr (cu_header->die, DW_AT_low_pc);
> + if (attr)
> + {
> + base = DW_ADDR (attr);
> + found_base = 1;
> + }
> + }
> +
> + buffer = dwarf_ranges_buffer + offset;
> +
> +
> + /* Read in the largest possible address. */
> + marker = read_address (obfd, buffer, cu_header, &dummy);
> + if ((marker & mask) == mask)
> + {
> + /* If we found the largest possible address, then
> + read the base address. */
> + base = read_address (obfd, buffer + addr_size,
> + cu_header, &dummy);
> + buffer += 2 * addr_size;
> + offset += 2 * addr_size;
> + found_base = 1;
> + }
> +
> + low_set = 0;
> +
> + while (1)
> + {
> + CORE_ADDR range_beginning, range_end;
> +
> + range_beginning = read_address (obfd, buffer,
> + cu_header, &dummy);
> + buffer += addr_size;
> + range_end = read_address (obfd, buffer, cu_header, &dummy);
> + buffer += addr_size;
> + offset += 2 * addr_size;
> +
> + /* An end of list marker is a pair of zero addresses. */
> + if (range_beginning == 0 && range_end == 0)
> + /* Found the end of list entry. */
> + break;
> +
> + /* Each base address selection entry is a pair of 2 values.
> + The first is the largest possible address, the second is
> + the base address. Check for a base address here. */
> + if ((range_beginning & mask) == mask)
> + {
> + /* If we found the largest possible address, then
> + read the base address. */
> + base = read_address (obfd, buffer + addr_size,
> + cu_header, &dummy);
> + found_base = 1;
> + continue;
> + }
> +
> + if (!found_base)
> + {
> + /* We have no valid base address for the ranges
> + data. */
> + complaint (&symfile_complaints,
> + "Invalid .debug_ranges data (no base address)");
> + return 0;
> + }
> +
> + /* FIXME: This is recording everything as a low-high
> + segment of consecutive addresses. We should have a
> + data structure for discontiguous block ranges
> + instead. */
> + if (! low_set)
> + {
> + low = range_beginning;
> + high = range_end;
> + low_set = 1;
> + }
> + else
> + {
> + if (range_beginning < low)
> + low = range_beginning;
> + if (range_end > high)
> + high = range_end;
> + }
> + }
> +
> + if (! low_set)
> + /* If the first entry is an end-of-list marker, the range
> + describes an empty scope, i.e. no instructions. */
> + return 0;
> +
> + ret = -1;
> + }
> + }
>
> if (high < low)
> return 0;
> @@ -2024,12 +2200,12 @@ dwarf2_get_pc_bounds (struct die_info *d
> labels are not in the output, so the relocs get a value of 0.
> If this is a discarded function, mark the pc bounds as invalid,
> so that GDB will ignore it. */
> - if (low == 0 && (bfd_get_file_flags (objfile->obfd) & HAS_RELOC) == 0)
> + if (low == 0 && (bfd_get_file_flags (obfd) & HAS_RELOC) == 0)
> return 0;
>
> *lowpc = low;
> *highpc = high;
> - return 1;
> + return ret;
> }
>
> /* Add an aggregate field to the field list. */