Re: [RFC] Partial support for dwarf3 DW_AT_ranges

Daniel Jacobowitz
2003-01-29T15:53:20Z

On Fri, Jan 04, 2002 at 12:00:07PM -0500, Elena Zannoni wrote:
> Richard Henderson writes:
> > GCC began emitting DW_AT_ranges back in September to deal with
> > lexical scopes made discontiguous by basic block reordering.
> >
> > As of today, it may also create discontiguous lexical scopes
> > due to scheduling. (Before today under the same circumstances
> > we'd lose track of which instructions belonged to which scope
> > and fail to emit any debug information whatsoever.)
> >
>
> Richard, there was some initial effort to deal with this problem
> in gdb's symbol tables structures back in October.
> See the thread at:
> http://sources.redhat.com/ml/gdb-patches/2001-10/msg00304.html
> However, no real changes have been made to the symbol tables yet.
>
> > However, GDB doesn't recognize DW_AT_ranges as a valid way of
> > marking a lexical scope, which causes it to discard the scope
> > entirely. Which is probably the least useful thing that could
> > be done.
> >
> > The following does not add proper support for discontiguous
> > address ranges. I couldn't figure out how to do that in any
> > way that wasn't horribly invasive. I'm willing to expend a
> > significant amount of effort on this if someone is willing to
> > provide some direction.
> >
>
> The thread mentioned above has some initial implementation of an
> address set for partial symbol tables which would be used in case of
> non contiguous addr ranges. You should coordinate with Jim.
>
> > What this does do is find the "bounding box" of the discontiguous
> > range and use that. Yes, that will do the wrong thing in some
> > circumstances, but the current behaviour is wrong under all
> > circumstances, so it may be a net improvement.
> >
>
> I am OK with committing some initial support. At least now gdb can
> read the info.
>
> I have a few comments on your changes. Maybe I am missing it, but is
> the -1 value returned by dwarf2_get_pc_bounds used anywhere yet? If
> not, I would suggest we don't bother with it right now, given that the
> final solution will probably have to restructure that function again.
> Also, I would not want to introduce more goto's in gdb. I think that
> that sequence can be rewritten w/o goto's pretty easily. Also there
> is some formatting problem (white spaces around operators, full names
> for variables). Adding some comments on how the .debug_ranges list is
> organized would be helpful too.
>
> I think JimB is the one which has the last say on this however, since
> he has a patch in the works.
>

Ping out there, folks.

This lack of support for DW_AT_ranges is responsible for at least one,
probably two or more of the current PRs about "missing local
variables". Affected GCC versions have been shipping for some time; at
least 3.2 generates DW_AT_ranges, maybe earlier.

Since nothing ever came of the grand plans to support ranges in the
symbol table directly, can we at least move forwards on this year-old
patch? If so, I'll update it for current GDB.

> thanks
> Elena
>
>
> > My test case for this was
> >
> > static int foo(int *);
> > static void bar(int *);
> >
> > int main()
> > {
> > {
> > int x = 0, r;
> > r = foo(&x);
> > if (__builtin_expect (r, 1))
> > return 0;
> > bar (&x);
> > return 1;
> > }
> > }
> >
> > static int foo(int *p)
> > {
> > *p = 1;
> > return 0;
> > }
> >
> > static void bar(int *p)
> > {
> > *p = 2;
> > }
> >
> > For any GCC target that can emit epilogues as rtl, we will
> > arrange the code here as
> >
> > x = 0
> > call foo
> > if r == 0 goto L1
> > ret = 0
> > L0:
> > return ret
> > L1:
> > call bar
> > ret = 1
> > goto L0
> >
> > The lexical scope created by the extra set of braces doesn't
> > cover the epilogue, so the scope's range is the block before
> > L0, plus the block after L1.
> >
> >
> > r~
>
> > -/* 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)
> > {
> > + bfd *obfd = objfile->obfd;
> > struct attribute *attr;
> > CORE_ADDR low;
> > CORE_ADDR high;
> > + int ret;
> >
> > - 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);
> > - else
> > - return 0;
> > + {
> > + high = DW_ADDR (attr);
> > + attr = dwarf_attr (die, DW_AT_low_pc);
> > + if (attr)
> > + low = DW_ADDR (attr);
> > + else
> > + return 0;
> > + ret = 1;
> > + }
> > + else if ((attr = dwarf_attr (die, DW_AT_ranges)) != NULL)
> > + {
> > + unsigned int addr_size = cu_header->addr_size;
> > + CORE_ADDR mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
> > + unsigned int offset = DW_UNSND (attr);
> > + CORE_ADDR base;
> > + int dummy;
> > + unsigned int i;
> > + char *buffer;
> >
> > + /* 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. */
> > + /* ??? We definitely need some sort of indexed data structure here.
> > + At minimum we should recognize the common case of there being
> > + no base address selection entries. */
> > +
> > + buffer = dwarf_ranges_buffer + offset;
> > + for (i = offset; i > 2 * addr_size; )
> > + {
> > + CORE_ADDR marker;
> > +
> > + i -= 2 * addr_size;
> > + buffer -= 2 * addr_size;
> > +
> > + marker = read_address (obfd, buffer, cu_header, &dummy);
> > + if ((marker & mask) == mask)
> > + {
> > + base = read_address (obfd, buffer+addr_size, cu_header, &dummy);
> > + goto found_base;
> > + }
> > + }
> > +
> > + /* ??? 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);
> > + goto found_base;
> > + }
> > +
> > + attr = dwarf_attr (cu_header->die, DW_AT_low_pc);
> > + if (attr)
> > + {
> > + base = DW_ADDR (attr);
> > + goto found_base;
> > + }
> > +
> > + /* We have no valid base address for the ranges data. */
> > + return 0;
> > +
> > + found_base:
> > + buffer = dwarf_ranges_buffer + offset;
> > + low = read_address (obfd, buffer, cu_header, &dummy);
> > + buffer += addr_size;
> > + high = read_address (obfd, buffer, cu_header, &dummy);
> > + buffer += addr_size;
> > + if (low == 0 && high == 0)
> > + /* If the first entry is an end-of-list marker, the range
> > + describes an empty scope, i.e. no instructions. */
> > + return 0;
> > +
> > + while (1)
> > + {
> > + CORE_ADDR b, e;
> > + offset += 2 * addr_size;
> > +
> > + b = read_address (obfd, buffer, cu_header, &dummy);
> > + buffer += addr_size;
> > + e = read_address (obfd, buffer, cu_header, &dummy);
> > + buffer += addr_size;
> > + if (b == 0 && e == 0)
> > + break;
> > + if (b < low)
> > + low = b;
> > + if (e > high)
> > + high = e;
> > + }
> > +
> > + low += base;
> > + high += base;
> > + ret = -1;
> > + }
> > +
> > if (high < low)
> > return 0;
> >
> > @@ -1800,12 +1908,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. */
>

--
Daniel Jacobowitz