This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: RFC: partial symbol table address range generalization



Daniel Jacobowitz <drow@mvista.com> writes:
> I'd like to point you at my thoughts from the first time I noticed this
> behavior:
>   <http://sources.redhat.com/ml/gdb/2001-08/msg00161.html>

That's messed up.  The compiler produces SO stabs that describe only
the .text section, while happily placing code in other sections.  So
the SO stabs' addresses are useless.

If you want to hack on the stabs reader to handle these cases, that
would be great.


> > There is some logic in GDB's lookup functions to cope with overlapping
> > partial symtabs, and they've been working pretty well on our behalf.
> > However, they're fragile, and do break in everyday use.  For example,
> > in the executable produced from the source file above, if you try to
> > set a breakpoint on a library routine compiled without debug
> > information, GDB will set the breakpoint in `main' instead.  (On some
> > platforms, `_exit' is such a function.)
> 
> This particular problem should be avoidable anyway.  I would appreciate
> it if you would look at:
>  <http://sources.redhat.com/ml/gdb/2001-09/msg00068.html>

Well, okay.  But I'd much prefer to see the problem fixed by making
the symbol table contents more accurate than by adding another
heuristic for recognizing insane data.  When checks like that get into
the code, they never go away, because nobody's ever really sure
whether the circumstances it was meant to cope with happen any more.

If I can finish up the addrset patch for Dwarf 2, would you be
interested in taking a shot at spiffing up stabs?

> As far as getting this information from the stabs reader, we should be
> able to do it if we know separate "possible" and "definite" ranges, I
> think.  I'm not sure if we have enough information to do this.  We
> don't for the general case, but we should generally have one "definite"
> range per file (corresponding to the main .text segment).  It would be
> nice to at least take this region out of any symtabs that seem to
> encompass it, so that if the main program is built without
> -ffunction-sections, we will behave sanely in the presence of (say)
> libstdc++.a.

I encourage you to take a shot at it.  The idea is to have `struct
addrset' support a bunch of groovy operations (like set subtraction,
testing for intersections between two sets, etc.), carefully coded and
gotten right once and for all, that make it easy to do this kind of
sanity checking and refinement.  Here's the header file for the code
I've got now; imagine adding the setwise ops you want here, and then
using them in the stabs reader.



/* addrset.h --- interface to `struct addrset' type. 
   Copyright 2001 Free Software Foundation, Inc.

   This file is part of GDB.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  */

#ifndef ADDRSET_H
#define ADDRSET_H

/* An address set represents an arbitrary set of CORE_ADDR's.  Storage
   required is proportional to the smallest number of contiguous
   ranges necessary to represent the set.  It's efficient to add and
   delete address ranges, ask whether a given address is in the range,
   and walk the set a range at a time.

   We use it to track which pieces of code belong to which `struct
   partial_symtab', for example.  With C++, the machine code from a
   particular .o file no longer appears in the executable file in one
   contiguous clump; instead, the .text sections from all .o files
   appear first, followed by .gnu.linkonce.t.* sections from all .o
   files, holding class methods, destructors, and so on.  Since each
   method/etc. gets its own .gnu.linkonce.t.* section, there's no real
   limit to the number of discontiguous sections a single .o's code
   might occupy.

   In general, this interface uses pairs of start and end addresses,
   both *inclusive*, to describe ranges.  This is less graceful in
   some ways than using the more traditional start-inclusive,
   end-exclusive ranges, or a start-and-length form.  However, the
   first two each have certain ranges they are unable to represent
   clearly:

   - How should we represent a range that abuts the top end of the
     address space?  In start-inclusive, end-inclusive form, we can
     simply say (foo, (CORE_ADDR) -1), but in start-inclusive,
     end-exclusive form the endpoint can't fit in a CORE_ADDR, and
     ends up being zero; ranges of the form (foo, 0) are weird to
     think about.

   - How should we represent the range that includes the entire
     address space?  In start-inclusive, end-inclusive form, we can
     simply say (0, (CORE_ADDR) -1).  In start-inclusive,
     end-exclusive form this would be (0, 0), which looks like an
     empty range.  In start-and-length form, this would also be (0,
     0), which has the same problem.

   Horribly anal-retentive?  Yes, okay, fine.  I'm sick and tired of
   GDB screwing up at corner cases.  At least this one module won't be
   at fault.  */

struct addrset;


/* Allocate and return a new, empty addrset.
   If OBSTACK is non-zero, allocate the addrset's storage in OBSTACK.
   Otherwise, allocate its components using xmalloc.  */
struct addrset *addrset_new (struct obstack *obstack);


/* Free ADDRSET.  It must have been allocated using xmalloc; that is,
   the OBSTACK argument to `new_addrset' must have been zero.  */
void addrset_free (struct addrset *addrset);


/* Add the addresses from START to END (inclusive!) to ADDRSET.  */
void addrset_add (struct addrset *addrset, CORE_ADDR start, CORE_ADDR end);


/* Remove the addresses from START to END (inclusive!) from ADDRSET.  */
void addrset_remove (struct addrset *addrset, CORE_ADDR start, CORE_ADDR end);


/* Shift all addresses in ADDRSET by OFFSET.  That is, the address (A
   + OFFSET) will be in ADDRSET after this call if and only if the
   address A was in ADDRSET before the call.  The addition is done
   modulo the range of CORE_ADDR.

   In general, it's not possible for this function to detect
   wraparound: since CORE_ADDR is unsigned, adding a very large
   CORE_ADDR value is the only way to shift the set towards lower
   addresses.  However, this function will signal an error if all the
   addresses are not shifted *in the same direction*.  That is, if
   some addresses wrap around, but others don't, then that's almost
   certainly not what was intended.  */
void addrset_offset (struct addrset *addrset, CORE_ADDR offset);   


/* Return non-zero if ADDR is in ADDRSET, zero otherwise.  */
int addrset_in (struct addrset *addrset, CORE_ADDR addr);


/* If ADDR is in ADDRSET, return non-zero and set *START and *END to
   the start and end (inclusive) of the largest contiguous range of
   addresses in ADDRSET containing ADDR.  If ADDR is not in ADDRSET,
   return zero.  */
int addrset_span (struct addrset *addrset, CORE_ADDR addr,
                  CORE_ADDR *start, CORE_ADDR *end);


/* You can use the two functions below to traverse an address set, as
   follows:

     for (addrset_first_range (addrset, &start, &end);
          start <= end;
          addr = addrset_next_range (addrset, end, &start, &end))
       ... do something with the range start -- end ...  

*/


/* Set *START and *END to the first and last addresses (inclusive) of
   the first contiguous range of addresses in ADDRSET.  If ADDRSET is
   empty, set *START to 1 and *END to zero.  */
void addrset_first_range (struct addrset *addrset,
                          CORE_ADDR *start,
                          CORE_ADDR *end);

/* Set *START and *END to the first and last addresses (inclusive) of
   the first contiguous range of addresses in ADDRSET after AFTER.
   (That is, AFTER will not be included in the returned range.)
   If there are no addresses in ADDRSET that are > AFTER, then
   set *START to 1 and *END to zero.  */
void addrset_next_range (struct addrset *addrset,
                         CORE_ADDR after,
                         CORE_ADDR *start,
                         CORE_ADDR *end);


/* Print ADDRSET on OUTFILE, using filtered output and
   `print_address_numeric'.  */
void addrset_print (struct addrset *addrset, struct ui_file *outfile);


#endif /* ADDRSET_H */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]