This is the mail archive of the gdb-patches@sourceware.org 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]
Other format: [Raw text]

[rfc/preview] Support for disjoint blocks and local vars in inlined functions


While debugging the bs15503.exp crash yesterday, I got extremely
frustrated at my inability to print out, well, much of anything without
rebuilding an unoptimized GDB.  Jim pointed me at his "addrset"
abstraction from 2001, and I wired that into our "struct block".

This is far from complete.  Before committing it I'd want to try again
to audit every use of BLOCK_START/BLOCK_END; the new vectors are only
used as auxilliary information.

Also, I have a patch for GCC that I'm currently testing which fixes the
most egregious problem I found in generating DW_AT_ranges information.
And there are plenty more places where debug information for optimized
code isn't good enough.

Anyway, I've worked half a day on this and need to get back to other
projects for a bit.  I'm posting this for anyone who wants to try it or
comment on it (or finish it); I hope I'll get back to it soon, but I
don't know when.

-- 
Daniel Jacobowitz
CodeSourcery

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.833
diff -u -p -r1.833 Makefile.in
--- Makefile.in	19 Jul 2006 23:23:35 -0000	1.833
+++ Makefile.in	21 Jul 2006 16:58:20 -0000
@@ -510,7 +510,7 @@ TARGET_FLAGS_TO_PASS = \
 # SFILES is used in building the distribution archive.
 
 SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c  \
-	ax-general.c ax-gdb.c \
+	addrset.c ax-general.c ax-gdb.c \
 	bcache.c \
 	bfd-target.c \
 	block.c blockframe.c breakpoint.c buildsym.c \
@@ -633,6 +633,7 @@ nm_h =		@nm_h@
 
 ada_lang_h = ada-lang.h $(value_h) $(gdbtypes_h) $(breakpoint_h)
 ada_lex_c = ada-lex.c $(gdb_string_h)
+addrset_h = addrset.h
 alphabsd_tdep_h = alphabsd-tdep.h
 alpha_tdep_h = alpha-tdep.h
 amd64_nat_h = amd64-nat.h
@@ -907,7 +908,7 @@ TAGFILES_WITH_SRCDIR = $(HFILES_WITH_SRC
 
 COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	version.o \
-	annotate.o \
+	addrset.o annotate.o \
 	auxv.o \
 	bfd-target.o \
 	blockframe.o breakpoint.o findvar.o regcache.o \
@@ -1690,6 +1691,7 @@ ada-valprint.o: ada-valprint.c $(defs_h)
 	$(gdbtypes_h) $(expression_h) $(value_h) $(demangle_h) $(valprint_h) \
 	$(language_h) $(annotate_h) $(ada_lang_h) $(c_lang_h) $(infcall_h) \
 	$(exceptions_h)
+addrset.o: addrset.c $(defs_h) $(obstack_h) $(gdb_assert_h) $(addrset_h)
 aix-thread.o: aix-thread.c $(defs_h) $(gdb_assert_h) $(gdbthread_h) \
 	$(target_h) $(inferior_h) $(regcache_h) $(gdbcmd_h) $(ppc_tdep_h) \
 	$(gdb_string_h)
@@ -1805,7 +1807,7 @@ bcache.o: bcache.c $(defs_h) $(gdb_obsta
 bfd-target.o: bfd-target.c $(defs_h) $(target_h) $(bfd_target_h) \
 	$(gdb_assert_h) $(gdb_string_h)
 block.o: block.c $(defs_h) $(block_h) $(symtab_h) $(symfile_h) \
-	$(gdb_obstack_h) $(cp_support_h)
+	$(gdb_obstack_h) $(cp_support_h) $(addrset_h) $(gdb_assert_h)
 blockframe.o: blockframe.c $(defs_h) $(symtab_h) $(bfd_h) $(objfiles_h) \
 	$(frame_h) $(gdbcore_h) $(value_h) $(target_h) $(inferior_h) \
 	$(annotate_h) $(regcache_h) $(gdb_assert_h) $(dummy_frame_h) \
@@ -2398,7 +2400,8 @@ objc-lang.o: objc-lang.c $(defs_h) $(sym
 objfiles.o: objfiles.c $(defs_h) $(bfd_h) $(symtab_h) $(symfile_h) \
 	$(objfiles_h) $(gdb_stabs_h) $(target_h) $(bcache_h) $(mdebugread_h) \
 	$(gdb_assert_h) $(gdb_stat_h) $(gdb_obstack_h) $(gdb_string_h) \
-	$(hashtab_h) $(breakpoint_h) $(block_h) $(dictionary_h) $(source_h)
+	$(hashtab_h) $(breakpoint_h) $(block_h) $(dictionary_h) $(source_h) \
+	$(addrset_h)
 observer.o: observer.c $(defs_h) $(observer_h) $(command_h) $(gdbcmd_h) \
 	$(observer_inc)
 obsd-tdep.o: obsd-tdep.c $(defs_h) $(frame_h) $(symtab_h) $(obsd_tdep_h)
Index: addrset.c
===================================================================
RCS file: addrset.c
diff -N addrset.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ addrset.c	21 Jul 2006 16:58:20 -0000
@@ -0,0 +1,515 @@
+/* addrset.c --- implementation of the address set datatype  
+   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.  */
+
+#include "defs.h"
+#include "obstack.h"
+#include "gdb_assert.h"
+#include "addrset.h"
+
+struct addrset {
+
+  /* Two singly-linked lists of nodes; each node represents a range of
+     addresses in the addrset.  None of these nodes' address ranges
+     overlap or abut each other.  `before' is sorted in order of
+     decreasing addresses, `after' in order of increasing addresses.
+     All nodes in `before' have lower addresses than all the nodes in
+     `after'.
+
+     Generally, whenever we operate on the list, we try split it
+     between `before' and `after' so that the division comes directly
+     after the last node we operated on.  That way, sequential access
+     happens in constant time.  Since we split it *after* the last
+     node we operate on, we're slightly biased towards traversal
+     towards increasing address, but it's not too bad if we want to go
+     the other way.  */
+  struct node *before, *after;
+
+  /* If this is non-zero, allocate new nodes from this obstack.
+     Otherwise, allocate nodes using xmalloc.  */
+  struct obstack *obstack;
+
+  /* We can't free nodes allocated from an obstack, so we might as
+     well keep them in a free list, and reuse them.  This list can't
+     be global, as different obstacks have different lifetimes.
+     Ideally, it would be per-obstack, so a node could be freed from
+     one addrset and then re-used by another addrset in the same
+     obstack.  But we don't have any convenient way to store
+     per-obstack info.  So the free list is per-addrset.
+
+     For addrsets allocated using xmalloc, we simply xfree nodes, and
+     hope malloc manages small blocks well; this field is always zero.  */
+  struct node *free;
+
+};
+
+/* One contiguous range of addresses in an addrset.  */
+struct node {
+  struct node *next;
+
+  /* The start and end addresses, inclusive, of the address range.
+     Obviously, start <= end.  If start == end, that's a one-byte
+     range.  */
+  CORE_ADDR start, end;       
+};
+
+
+struct addrset *
+addrset_new (struct obstack *obstack)
+{
+  struct addrset *new;
+
+  if (obstack)
+    new = obstack_alloc (obstack, sizeof (*new));
+  else
+    new = xmalloc (sizeof (*new));
+
+  memset (new, 0, sizeof (*new));
+
+  new->obstack = obstack;
+
+  return new;
+}
+
+
+static void
+xfree_node_list (struct node *n)
+{
+  while (n)
+    {
+      struct node *next = n->next;
+
+      xfree (n);
+      n = next;
+    }
+}
+
+
+void
+addrset_free (struct addrset *addrset)
+{
+  /* You can't free an addrset allocated in an obstack.  */
+  gdb_assert (! addrset->obstack);
+
+  /* If it wasn't allocated on an obstack, it had better not have a
+     free list.  */
+  gdb_assert (! addrset->free);
+
+  xfree_node_list (addrset->before);
+  xfree_node_list (addrset->after);
+}
+
+
+static struct node *
+new_node (struct addrset *addrset,
+          CORE_ADDR start, CORE_ADDR end)
+{
+  struct node *new;
+
+  if (addrset->obstack)
+    {
+      /* If we have any nodes on the free list, use them.  */
+      if (addrset->free)
+        {
+          new = addrset->free;
+          addrset->free = new->next;
+        }
+      else
+        new = obstack_alloc (addrset->obstack, sizeof (*new));
+    }
+  else
+    new = xmalloc (sizeof (*new));
+
+  new->next = 0;
+  new->start = start;
+  new->end = end;
+
+  return new;
+}
+
+
+static void
+free_node (struct addrset *addrset, struct node *node)
+{
+  if (addrset->obstack)
+    {
+      node->next = addrset->free;
+      addrset->free = node;
+    }
+  else
+    xfree (node);
+}
+
+
+/* Return true if A is less than B, and there is at least one
+   address between them.  */
+static int
+less_and_separate (CORE_ADDR a, CORE_ADDR b)
+{
+  /* We need both tests; think about what happens, for example, when
+     B is zero and A is (CORE_ADDR) -1.  */ 
+  return (a < b && b - a >= 2);
+}
+
+
+/* Shift nodes from `before' to `after', or in the other direction,
+   until the split falls at the right place.  By `the right place', we
+   mean:
+   - any nodes on `after' are after, and do not abut, the range from
+     START to END, and
+   - any nodes on `before' are either completely before, abut, or overlap
+     the range from START to END.
+   Once this is done, any nodes on `after' are irrelevant to our
+   operation, and any nodes that abut or overlap our range are at the
+   head of `before'.  */
+static void
+resplit (struct addrset *addrset, CORE_ADDR start, CORE_ADDR end)
+{
+  struct node *node;
+
+  /* We know the `before' and `after' lists are each sorted in the
+     proper direction, and contain non-overlapping, non-adjacent
+     ranges.
+
+     The first step is to move all ranges from `after' to `before'
+     that are before, overlap, or abut the range we're operating on.
+     Be careful of nodes abutting either end of the address space.  */
+  while ((node = addrset->after) != 0
+         && ! less_and_separate (end, node->start))
+    {
+      addrset->after = node->next;
+      node->next = addrset->before;
+      addrset->before = node;
+    }
+
+  /* Now, any ranges in `after' are after and do not abut the range
+     we're operating on.  This means that all those nodes are
+     irrelevant to this operation, and we can ignore them.
+
+     Thus, any nodes we care about are somewhere in `before'.  Bring
+     them to the head of that list by shifting any nodes from `before'
+     to `after' that are completely after the range we're operating
+     on.
+
+     The astute reader will note that the condition for moving a node
+     in this loop is the complement of that for the previous loop.
+     That is, the condition for moving a node in one direction is the
+     opposite of moving it in the other direction.  This means that
+     only one of these two loops' bodies will ever be executed in a
+     given call.  */
+  while ((node = addrset->before) != 0
+         && less_and_separate (end, node->start))
+    {
+      addrset->before = node->next;
+      node->next = addrset->after;
+      addrset->after = node;
+    }
+}
+
+
+void
+addrset_add (struct addrset *addrset, CORE_ADDR start, CORE_ADDR end)
+{
+  struct node *node, *save;
+
+  gdb_assert (start <= end);
+
+  resplit (addrset, start, end);
+
+  /* Now we know that any ranges in `after' are irrelevant to this
+     operation, and that zero or more nodes at the head of `before'
+     abut or overlap the range we're adding.  Remove any such nodes
+     from `before', and absorb their ranges into ours.  */
+  save = 0;
+  while ((node = addrset->before) != 0
+         && ! less_and_separate (node->end, start))
+    {
+      if (node->start < start)
+        start = node->start;
+      if (node->end > end)
+        end = node->end;
+      addrset->before = node->next;
+
+      /* We want to remove this node from the list, but we know we're
+         going to insert a new one in a bit, so hold onto the first
+         node we delete, just to save a call to xfree and xmalloc.  */
+      if (save)
+        free_node (addrset, node);
+      else
+        save = node;
+    }
+
+  /* Create a node for the new range.  */
+  if (save)
+    {
+      save->start = start;
+      save->end = end;
+    }
+  else
+    save = new_node (addrset, start, end);
+
+  /* Stick it on the head of the `before' list.  */
+  save->next = addrset->before;
+  addrset->before = save;
+}
+
+
+void
+addrset_remove (struct addrset *addrset, CORE_ADDR start, CORE_ADDR end)
+{
+  struct node *node;
+
+  gdb_assert (start <= end);
+
+  /* This could end up moving a bunch of nodes to `before' that we're
+     just going to delete anyway.  But our running time is linear in
+     the number of ranges we're going to delete anyway, and this lets
+     us deal with the `before' list only; otherwise, we'd have to
+     write out the code twice, once for each list.  */
+  resplit (addrset, start, end);
+
+  /* Now we know that any ranges in `after' are irrelevant to this
+     operation, and that zero or more nodes at the head of `before'
+     abut or overlap the range we're adding.
+
+     If the node at the head of the `before' list extends after our
+     range, either truncate it and shift it to `after', or split it in
+     two.  */
+  if ((node = addrset->before) != 0
+      && end < node->end)
+    {
+      /* If it also extends before the range we're deleting, we need
+         to split it into two nodes: one for the part before and one
+         for the part after.  And we know we don't need to do anything
+         else to the `before' list.  */
+      if (node->start < start)
+        {
+          struct node *right_part = new_node (addrset, end + 1, node->end);
+          right_part->next = addrset->after;
+          addrset->after = right_part;
+          node->end = start - 1;
+          return;
+        }
+
+      /* Just shift the node onto `after', and adjust its size.  */
+      addrset->before = node->next;
+      node->next = addrset->after;
+      addrset->after = node;
+      node->start = end + 1;
+
+      /* There may be more nodes on `before' that we need to adjust.  */
+    }
+
+  /* Now we know that the head of `before' doesn't extend beyond the
+     end of the range we're deleting.  Nothing will need to be added
+     to `after'.
+
+     Remove any nodes completely contained in the region we're
+     deleting.  */
+  while ((node = addrset->before) != 0
+         && start <= node->start)
+    {
+      addrset->before = node->next;
+      free_node (addrset, node);
+    }
+
+  /* The head of `before' (if any) isn't completely contained in the
+     range we're deleting, but it may partially overlap it at the low
+     end.  If that's the case, adjust its endpoint.  */
+  if ((node = addrset->before) != 0
+      && start <= node->end)
+    node->end = start - 1;
+}
+
+
+/* Shift *ADDR by OFFSET, and check that the direction of change from
+   OLD to NEW is consistent with *DIR.  If it isn't, raise an internal
+   error.  OFFSET must be non-zero.  See offset_node_list for the
+   meaning of *DIR.  */
+static void
+shift_addr (CORE_ADDR *addr, CORE_ADDR offset, int *dir)
+{
+  CORE_ADDR old = *addr;
+  CORE_ADDR new = (*addr += offset);
+
+  if (new < old)
+    {
+      if (! *dir)
+        *dir = -1;
+      else
+        gdb_assert (*dir == -1);
+    }
+  else
+    {
+      if (! *dir)
+        *dir = 1;
+      else
+        gdb_assert (*dir == 1);
+    }
+}
+
+
+/* Offset addresses in NODE and its successors by OFFSET.
+   OFFSET must be non-zero.
+   *DIR is the direction of the shift, used for error checking.
+   - If *DIR is zero, then we don't know which direction things will be
+     shifted yet.
+   - If *DIR is -1 or +1, then OFFSET shifted other addresses in other nodes
+     downwards or upwards, and we should raise an internal_error if any
+     of our addresses go in the other direction.  */
+static void
+offset_node_list (struct node *node, CORE_ADDR offset, int *dir)
+{
+  while (node)
+    {
+      shift_addr (&node->start, offset, dir);
+      shift_addr (&node->end, offset, dir);
+
+      node = node->next;
+    }
+}
+
+
+void
+addrset_offset (struct addrset *addrset, CORE_ADDR offset)
+{
+  int dir = 0;
+
+  if (offset == 0)
+    return;
+
+  offset_node_list (addrset->before, offset, &dir);
+  offset_node_list (addrset->after, offset, &dir);
+}
+
+
+int
+addrset_in (struct addrset *addrset, CORE_ADDR addr)
+{
+  struct node *node;
+
+  resplit (addrset, addr, addr);
+
+  /* Now any node containing addr would have to be on `before'.  */
+  return ((node = addrset->before) != 0
+          && node->start <= addr && addr <= node->end);
+}
+
+
+int
+addrset_span (struct addrset *addrset,
+              CORE_ADDR addr,
+              CORE_ADDR *start,
+              CORE_ADDR *end)
+{
+  struct node *node;
+
+  resplit (addrset, addr, addr);
+
+  /* Now any node containing addr would have to be on `before'.  */
+  if ((node = addrset->before) != 0
+      && node->start <= addr && addr <= node->end)
+    {
+      *start = node->start;
+      *end = node->end;
+      return 1;
+    }
+  else
+    return 0;
+}
+
+
+void
+addrset_first_range (struct addrset *addrset,
+                     CORE_ADDR *start,
+                     CORE_ADDR *end)
+{
+  struct node *node;
+  
+  resplit (addrset, 0, 0);
+  
+  /* If there's anything on `before', that's our first range.
+     Otherwise, if there's anything on after, that's it.  */
+  if ((node = addrset->before) != 0
+      || (node = addrset->after) != 0)
+    {
+      *start = node->start;
+      *end = node->end;
+    }
+  else
+    {
+      /* ADDRSET is empty.  */
+      *start = 1;
+      *end = 0;
+    }
+}
+
+
+void
+addrset_next_range (struct addrset *addrset,
+                    CORE_ADDR after,
+                    CORE_ADDR *start,
+                    CORE_ADDR *end)
+{
+  struct node *node;
+
+  resplit (addrset, after, after);
+
+  /* The first node on `before' might extend beyond our range.  */
+  if ((node = addrset->before) != 0
+      && after < node->end)
+    {
+      *start = after + 1;
+      *end = node->end;
+    }
+
+  /* Otherwise, the first node on `after' is the one we want.  */
+  else if ((node = addrset->after) != 0)
+    {
+      *start = node->start;
+      *end = node->end;
+    }
+
+  /* Otherwise, there are no more addresses in ADDRSET after AFTER.  */
+  else
+    {
+      *start = 1;
+      *end = 0;
+    }
+}
+
+
+void
+addrset_print (struct addrset *addrset, struct ui_file *outfile)
+{
+  CORE_ADDR start, end;
+  int first = 1;
+
+  for (addrset_first_range (addrset, &start, &end);
+       start <= end;
+       addrset_next_range (addrset, end, &start, &end))
+    {
+      if (! first)
+        fprintf_filtered (outfile, ", ");
+      deprecated_print_address_numeric (start, 1, outfile);
+      fprintf_filtered (outfile, "-");
+      deprecated_print_address_numeric (end, 1, outfile);
+      first = 0;
+    }
+}
Index: addrset.h
===================================================================
RCS file: addrset.h
diff -N addrset.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ addrset.h	21 Jul 2006 16:58:20 -0000
@@ -0,0 +1,148 @@
+/* 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
+   `deprecated_print_address_numeric'.  */
+void addrset_print (struct addrset *addrset, struct ui_file *outfile);
+
+
+#endif /* ADDRSET_H */
Index: block.c
===================================================================
RCS file: /cvs/src/src/gdb/block.c,v
retrieving revision 1.10
diff -u -p -r1.10 block.c
--- block.c	17 Dec 2005 22:33:59 -0000	1.10
+++ block.c	21 Jul 2006 16:58:21 -0000
@@ -23,8 +23,11 @@
 #include "block.h"
 #include "symtab.h"
 #include "symfile.h"
-#include "gdb_obstack.h"
 #include "cp-support.h"
+#include "addrset.h"
+
+#include "gdb_assert.h"
+#include "gdb_obstack.h"
 
 /* This is used by struct block to store namespace-related info for
    C++ files, namely using declarations and the current namespace in
@@ -77,6 +80,8 @@ blockvector_for_pc_sect (CORE_ADDR pc, s
   struct block *b;
   int bot, top, half;
   struct blockvector *bl;
+  CORE_ADDR best_size, span_start, span_end;
+  int best_index;
 
   if (symtab == 0)		/* if no symtab specified by caller */
     {
@@ -111,13 +116,53 @@ blockvector_for_pc_sect (CORE_ADDR pc, s
     {
       b = BLOCKVECTOR_BLOCK (bl, bot);
       if (BLOCK_END (b) > pc)
+	break;
+      bot--;
+    }
+  if (bot < 0)
+    return 0;
+
+  best_size = 0;
+  best_index = 0;
+  for (; bot >= 0; bot--)
+    {
+      CORE_ADDR size;
+
+      b = BLOCKVECTOR_BLOCK (bl, bot);
+      /* FIXME: In the current data structure, it seems we need to search back to
+	 the beginning of the blockvector.  */
+
+      if (BLOCK_ADDRSET (b) == NULL)
 	{
-	  if (pindex)
-	    *pindex = bot;
-	  return bl;
+	  if (BLOCK_START (b) <= pc && BLOCK_END (b) > pc)
+	    size = BLOCK_END (b) - BLOCK_START (b);
+	  else
+	    continue;
+	}
+      else
+	{
+	  if (addrset_span (BLOCK_ADDRSET (b), pc, &span_start, &span_end))
+	    size = span_end - span_start + 1;
+	  else
+	    /* Block doesn't really contain this address.  */
+	    continue;
+	}
+
+      gdb_assert (size > 0);
+      if (best_size == 0 || size < best_size)
+	{
+	  best_size = size;
+	  best_index = bot;
 	}
-      bot--;
     }
+
+  if (best_size > 0)
+    {
+      if (pindex)
+	*pindex = best_index;
+      return bl;
+    }
+
   return 0;
 }
 
@@ -290,6 +335,7 @@ allocate_block (struct obstack *obstack)
   BLOCK_DICT (bl) = NULL;
   BLOCK_NAMESPACE (bl) = NULL;
   BLOCK_GCC_COMPILED (bl) = 0;
+  BLOCK_ADDRSET (bl) = NULL;
 
   return bl;
 }
Index: block.h
===================================================================
RCS file: /cvs/src/src/gdb/block.h,v
retrieving revision 1.11
diff -u -p -r1.11 block.h
--- block.h	17 Dec 2005 22:33:59 -0000	1.11
+++ block.h	21 Jul 2006 16:58:21 -0000
@@ -30,6 +30,7 @@ struct block_namespace_info;
 struct using_direct;
 struct obstack;
 struct dictionary;
+struct addrset;
 
 /* All of the name-scope contours of the program
    are represented by `struct block' objects.
@@ -65,6 +66,10 @@ struct block
   CORE_ADDR startaddr;
   CORE_ADDR endaddr;
 
+  /* The addresses in the block, in more detail.  STARTADDR and
+     ENDADDR are always set; and if this is NULL, they are trusted.  */
+  struct addrset *addrs;
+
   /* The symbol that names this block, if the block is the body of a
      function; otherwise, zero.  */
 
@@ -118,6 +123,7 @@ struct block
 #define BLOCK_GCC_COMPILED(bl)	(bl)->gcc_compile_flag
 #define BLOCK_DICT(bl)		(bl)->dict
 #define BLOCK_NAMESPACE(bl)   (bl)->language_specific.cplus_specific.namespace
+#define BLOCK_ADDRSET(bl)	(bl)->addrs
 
 /* Macro to loop through all symbols in a block BL, in no particular
    order.  ITER helps keep track of the iteration, and should be a
Index: buildsym.c
===================================================================
RCS file: /cvs/src/src/gdb/buildsym.c,v
retrieving revision 1.42
diff -u -p -r1.42 buildsym.c
--- buildsym.c	17 Dec 2005 22:33:59 -0000	1.42
+++ buildsym.c	21 Jul 2006 16:58:22 -0000
@@ -222,6 +222,7 @@ void
 finish_block (struct symbol *symbol, struct pending **listhead,
 	      struct pending_block *old_blocks,
 	      CORE_ADDR start, CORE_ADDR end,
+	      struct addrset *addrs,
 	      struct objfile *objfile)
 {
   struct pending *next, *next1;
@@ -244,6 +245,7 @@ finish_block (struct symbol *symbol, str
 
   BLOCK_START (block) = start;
   BLOCK_END (block) = end;
+  BLOCK_ADDRSET (block) = addrs;
   /* Superblock filled in when containing block is made */
   BLOCK_SUPERBLOCK (block) = NULL;
   BLOCK_NAMESPACE (block) = NULL;
@@ -828,7 +830,7 @@ end_symtab (CORE_ADDR end_addr, struct o
       cstk = pop_context ();
       /* Make a block for the local symbols within.  */
       finish_block (cstk->name, &local_symbols, cstk->old_blocks,
-		    cstk->start_addr, end_addr, objfile);
+		    cstk->start_addr, end_addr, NULL, objfile);
 
       if (context_stack_depth > 0)
 	{
@@ -903,9 +905,9 @@ end_symtab (CORE_ADDR end_addr, struct o
       /* Define the STATIC_BLOCK & GLOBAL_BLOCK, and build the
          blockvector.  */
       finish_block (0, &file_symbols, 0, last_source_start_addr, end_addr,
-		    objfile);
+		    NULL, objfile);
       finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr,
-		    objfile);
+		    NULL, objfile);
       blockvector = make_blockvector (objfile);
       cp_finalize_namespace (BLOCKVECTOR_BLOCK (blockvector, STATIC_BLOCK),
 			     &objfile->objfile_obstack);
Index: buildsym.h
===================================================================
RCS file: /cvs/src/src/gdb/buildsym.h,v
retrieving revision 1.13
diff -u -p -r1.13 buildsym.h
--- buildsym.h	17 Dec 2005 22:33:59 -0000	1.13
+++ buildsym.h	21 Jul 2006 16:58:23 -0000
@@ -24,6 +24,7 @@
 
 struct objfile;
 struct symbol;
+struct addrset;
 
 /* This module provides definitions used for creating and adding to
    the symbol table.  These routines are called from various symbol-
@@ -236,6 +237,7 @@ extern void finish_block (struct symbol 
 			  struct pending **listhead,
 			  struct pending_block *old_blocks,
 			  CORE_ADDR start, CORE_ADDR end,
+			  struct addrset *addrs,
 			  struct objfile *objfile);
 
 extern void really_free_pendings (void *dummy);
Index: coffread.c
===================================================================
RCS file: /cvs/src/src/gdb/coffread.c,v
retrieving revision 1.63
diff -u -p -r1.63 coffread.c
--- coffread.c	17 Dec 2005 22:33:59 -0000	1.63
+++ coffread.c	21 Jul 2006 16:58:23 -0000
@@ -1035,7 +1035,7 @@ coff_symtab_read (long symtab_offset, un
 			    + fcn_aux_saved.x_sym.x_misc.x_fsize
 			    + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)),
 #endif
-			    objfile
+			    NULL, objfile
 		);
 	      within_function = 0;
 	    }
@@ -1072,7 +1072,7 @@ coff_symtab_read (long symtab_offset, un
 		    cs->c_value + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
 		  /* Make a block for the local symbols within.  */
 		  finish_block (0, &local_symbols, new->old_blocks,
-				new->start_addr, tmpaddr, objfile);
+				new->start_addr, tmpaddr, NULL, objfile);
 		}
 	      /* Now pop locals of block just finished.  */
 	      local_symbols = new->locals;
Index: dbxread.c
===================================================================
RCS file: /cvs/src/src/gdb/dbxread.c,v
retrieving revision 1.81
diff -u -p -r1.81 dbxread.c
--- dbxread.c	17 Dec 2005 22:33:59 -0000	1.81
+++ dbxread.c	21 Jul 2006 16:58:26 -0000
@@ -2724,7 +2724,7 @@ process_one_symbol (int type, int desc, 
 	  /* Make a block for the local symbols within.  */
 	  finish_block (new->name, &local_symbols, new->old_blocks,
 			new->start_addr, new->start_addr + valu,
-			objfile);
+			NULL, objfile);
 
 	  /* May be switching to an assembler file which may not be using
 	     block relative stabs, so reset the offset.  */
@@ -2840,7 +2840,7 @@ no enclosing block"));
 		}
 	      /* Make a block for the local symbols within.  */
 	      finish_block (0, &local_symbols, new->old_blocks,
-			    new->start_addr, valu, objfile);
+			    new->start_addr, valu, NULL, objfile);
 	    }
 	}
       else
@@ -3139,7 +3139,7 @@ no enclosing block"));
 		  new = pop_context ();
 		  /* Make a block for the local symbols within.  */
 		  finish_block (new->name, &local_symbols, new->old_blocks,
-				new->start_addr, valu, objfile);
+				new->start_addr, valu, NULL, objfile);
 		}
 
 	      new = push_context (0, valu);
Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.200
diff -u -p -r1.200 dwarf2read.c
--- dwarf2read.c	12 Jul 2006 21:14:57 -0000	1.200
+++ dwarf2read.c	21 Jul 2006 16:58:30 -0000
@@ -48,6 +48,7 @@
 #include "hashtab.h"
 #include "command.h"
 #include "gdbcmd.h"
+#include "addrset.h"
 
 #include <fcntl.h>
 #include "gdb_string.h"
@@ -887,7 +888,9 @@ static void read_func_scope (struct die_
 static void read_lexical_block_scope (struct die_info *, struct dwarf2_cu *);
 
 static int dwarf2_get_pc_bounds (struct die_info *,
-				 CORE_ADDR *, CORE_ADDR *, struct dwarf2_cu *);
+				 CORE_ADDR *, CORE_ADDR *,
+				 struct addrset **,
+				 struct dwarf2_cu *);
 
 static void get_scope_pc_bounds (struct die_info *,
 				 CORE_ADDR *, CORE_ADDR *,
@@ -2639,10 +2642,11 @@ process_die (struct die_info *die, struc
       read_func_scope (die, cu);
       break;
     case DW_TAG_inlined_subroutine:
-      /* FIXME:  These are ignored for now.
-         They could be used to set breakpoints on all inlined instances
-         of a function and make GDB `next' properly over inlined functions.  */
-      break;
+      /* FIXME: These are still mostly ignored.  They could be used to
+         set breakpoints on all inlined instances of a function and
+         make GDB `next' properly over inlined functions.  But at least
+	 we can see their local variables now.  */
+      /* FALLTHROUGH */
     case DW_TAG_lexical_block:
     case DW_TAG_try_block:
     case DW_TAG_catch_block:
@@ -2879,6 +2883,7 @@ read_func_scope (struct die_info *die, s
   const char *previous_prefix = processing_current_prefix;
   struct cleanup *back_to = NULL;
   CORE_ADDR baseaddr;
+  struct addrset *addrs = NULL;
 
   baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
 
@@ -2886,7 +2891,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, cu))
+  if (name == NULL || !dwarf2_get_pc_bounds (die, &lowpc, &highpc, &addrs, cu))
     return;
 
   if (cu->language == language_cplus
@@ -2926,6 +2931,8 @@ read_func_scope (struct die_info *die, s
 
   lowpc += baseaddr;
   highpc += baseaddr;
+  if (addrs)
+    addrset_offset (addrs, baseaddr);
 
   /* Record the function range for dwarf_decode_lines.  */
   add_to_cu_func_list (name, lowpc, highpc, cu);
@@ -2963,7 +2970,7 @@ read_func_scope (struct die_info *die, s
   new = pop_context ();
   /* Make a block for the local symbols within.  */
   finish_block (new->name, &local_symbols, new->old_blocks,
-		lowpc, highpc, objfile);
+		lowpc, highpc, addrs, objfile);
   
   /* In C++, we can have functions nested inside functions (e.g., when
      a function declares a class that has methods).  This means that
@@ -2993,18 +3000,17 @@ read_lexical_block_scope (struct die_inf
   CORE_ADDR lowpc, highpc;
   struct die_info *child_die;
   CORE_ADDR baseaddr;
+  struct addrset *addrs = NULL;
 
   baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
 
   /* Ignore blocks with missing or invalid low and high pc attributes.  */
-  /* ??? 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, cu))
+  if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, &addrs, cu))
     return;
   lowpc += baseaddr;
   highpc += baseaddr;
+  if (addrs)
+    addrset_offset (addrs, baseaddr);
 
   push_context (0, lowpc);
   if (die->child != NULL)
@@ -3021,17 +3027,20 @@ read_lexical_block_scope (struct die_inf
   if (local_symbols != NULL)
     {
       finish_block (0, &local_symbols, new->old_blocks, new->start_addr,
-		    highpc, objfile);
+		    highpc, addrs, objfile);
     }
   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.  Return -1 if the range is
-   discontinuous, i.e. derived from DW_AT_ranges information.  */
+   discontinuous, i.e. derived from DW_AT_ranges information.  If ADDRS
+   is non-NULL, and the range is discontinuous, *ADDRS is set to an address
+   set describing the range.  */
 static int
 dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
-		      CORE_ADDR *highpc, struct dwarf2_cu *cu)
+		      CORE_ADDR *highpc, struct addrset **addrs,
+		      struct dwarf2_cu *cu)
 {
   struct objfile *objfile = cu->objfile;
   struct comp_unit_head *cu_header = &cu->header;
@@ -3072,7 +3081,7 @@ dwarf2_get_pc_bounds (struct die_info *d
 	  gdb_byte *buffer;
 	  CORE_ADDR marker;
 	  int low_set;
- 
+
 	  found_base = cu_header->base_known;
 	  base = cu_header->base_address;
 
@@ -3085,6 +3094,9 @@ dwarf2_get_pc_bounds (struct die_info *d
 	    }
 	  buffer = dwarf2_per_objfile->ranges_buffer + offset;
 
+	  if (addrs)
+	    *addrs = addrset_new (&cu->objfile->objfile_obstack);
+
 	  /* Read in the largest possible address.  */
 	  marker = read_address (obfd, buffer, cu, &dummy);
 	  if ((marker & mask) == mask)
@@ -3121,7 +3133,7 @@ dwarf2_get_pc_bounds (struct die_info *d
 		{
 		  /* If we found the largest possible address, then
 		     read the base address.  */
-		  base = read_address (obfd, buffer + addr_size, cu, &dummy);
+		  base = range_end;
 		  found_base = 1;
 		  continue;
 		}
@@ -3138,10 +3150,14 @@ dwarf2_get_pc_bounds (struct die_info *d
 	      range_beginning += base;
 	      range_end += base;
 
-	      /* FIXME: This is recording everything as a low-high
-		 segment of consecutive addresses.  We should have a
-		 data structure for discontiguous block ranges
-		 instead.  */
+	      /* FIXME: If *addrs is NULL, we're discarding information.
+		 Every data structure which can be built from DW_AT_ranges
+		 should be updated to include an address set.  */
+	      if (*addrs)
+		addrset_add (*addrs, range_beginning, range_end + 1);
+	      fprintf_unfiltered (gdb_stderr, "Read range 0x%lx - 0x%lx at 0x%x\n",
+				  range_beginning, range_end, offset);
+
 	      if (! low_set)
 		{
 		  low = range_beginning;
@@ -3198,7 +3214,7 @@ get_scope_pc_bounds (struct die_info *di
   CORE_ADDR best_high = (CORE_ADDR) 0;
   CORE_ADDR current_low, current_high;
 
-  if (dwarf2_get_pc_bounds (die, &current_low, &current_high, cu))
+  if (dwarf2_get_pc_bounds (die, &current_low, &current_high, NULL, cu))
     {
       best_low = current_low;
       best_high = current_high;
@@ -3211,7 +3227,8 @@ get_scope_pc_bounds (struct die_info *di
 	{
 	  switch (child->tag) {
 	  case DW_TAG_subprogram:
-	    if (dwarf2_get_pc_bounds (child, &current_low, &current_high, cu))
+	    if (dwarf2_get_pc_bounds (child, &current_low, &current_high,
+				      NULL, cu))
 	      {
 		best_low = min (best_low, current_low);
 		best_high = max (best_high, current_high);
@@ -6984,7 +7001,11 @@ new_symbol (struct die_info *die, struct
 	    {
 	      var_decode_location (attr, sym, cu);
 	      /* FIXME drow/2003-07-31: Is LOC_COMPUTED_ARG necessary?  */
-	      if (SYMBOL_CLASS (sym) == LOC_COMPUTED)
+	      /* FIXME drow/2006-07-21: When we have better support for
+		 inlined functions, the tag check should be removed,
+		 if this whole block is still here.  */
+	      if (SYMBOL_CLASS (sym) == LOC_COMPUTED
+		  && die->parent->tag != DW_TAG_inlined_subroutine)
 		SYMBOL_CLASS (sym) = LOC_COMPUTED_ARG;
 	    }
 	  attr = dwarf2_attr (die, DW_AT_const_value, cu);
Index: dwarfread.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarfread.c,v
retrieving revision 1.45
diff -u -p -r1.45 dwarfread.c
--- dwarfread.c	17 Dec 2005 22:33:59 -0000	1.45
+++ dwarfread.c	21 Jul 2006 16:58:32 -0000
@@ -738,7 +738,7 @@ read_lexical_block_scope (struct dieinfo
   if (local_symbols != NULL)
     {
       finish_block (0, &local_symbols, new->old_blocks, new->start_addr,
-		    dip->at_high_pc, objfile);
+		    dip->at_high_pc, NULL, objfile);
     }
   local_symbols = new->locals;
 }
@@ -1800,7 +1800,7 @@ read_func_scope (struct dieinfo *dip, ch
   new = pop_context ();
   /* Make a block for the local symbols within.  */
   finish_block (new->name, &local_symbols, new->old_blocks,
-		new->start_addr, dip->at_high_pc, objfile);
+		new->start_addr, dip->at_high_pc, NULL, objfile);
   list_in_scope = &file_symbols;
 }
 
Index: hpread.c
===================================================================
RCS file: /cvs/src/src/gdb/hpread.c,v
retrieving revision 1.58
diff -u -p -r1.58 hpread.c
--- hpread.c	17 Dec 2005 22:34:01 -0000	1.58
+++ hpread.c	21 Jul 2006 16:58:35 -0000
@@ -5589,7 +5589,7 @@ hpread_process_one_debug_symbol (union d
 	  new = pop_context ();
 	  /* Make a block for the local symbols within.  */
 	  finish_block (new->name, &local_symbols, new->old_blocks,
-			new->start_addr, valu, objfile);
+			new->start_addr, valu, NULL, objfile);
 	  WITHIN_FUNCTION (objfile) = 0;	/* This may have to change for Pascal */
 	  local_symbols = new->locals;
 	  param_symbols = new->params;
@@ -5618,7 +5618,7 @@ hpread_process_one_debug_symbol (union d
 
 	      /* Make a block for the local symbols within.  */
 	      finish_block (new->name, &local_symbols, new->old_blocks,
-			    new->start_addr, valu, objfile);
+			    new->start_addr, valu, NULL, objfile);
 	      local_symbols = new->locals;
 	      param_symbols = new->params;
 	    }
@@ -5653,7 +5653,7 @@ hpread_process_one_debug_symbol (union d
 	    lbrac_mismatch_complaint ((char *) symnum);
 	  /* Make a block for the local symbols within.  */
 	  finish_block (new->name, &local_symbols, new->old_blocks,
-			new->start_addr, valu, objfile);
+			new->start_addr, valu, NULL, objfile);
 	  local_symbols = new->locals;
 	  param_symbols = new->params;
 #endif
Index: objfiles.c
===================================================================
RCS file: /cvs/src/src/gdb/objfiles.c,v
retrieving revision 1.64
diff -u -p -r1.64 objfiles.c
--- objfiles.c	1 Feb 2006 23:14:10 -0000	1.64
+++ objfiles.c	21 Jul 2006 16:58:36 -0000
@@ -34,6 +34,7 @@
 #include "target.h"
 #include "bcache.h"
 #include "mdebugread.h"
+#include "addrset.h"
 #include "gdb_assert.h"
 #include <sys/types.h>
 #include "gdb_stat.h"
@@ -557,6 +558,8 @@ objfile_relocate (struct objfile *objfil
 	  b = BLOCKVECTOR_BLOCK (bv, i);
 	  BLOCK_START (b) += ANOFFSET (delta, s->block_line_section);
 	  BLOCK_END (b) += ANOFFSET (delta, s->block_line_section);
+	  if (BLOCK_ADDRSET (b))
+	    addrset_offset (BLOCK_ADDRSET (b), ANOFFSET (delta, s->block_line_section));
 
 	  ALL_BLOCK_SYMBOLS (b, iter, sym)
 	    {
Index: xcoffread.c
===================================================================
RCS file: /cvs/src/src/gdb/xcoffread.c,v
retrieving revision 1.48
diff -u -p -r1.48 xcoffread.c
--- xcoffread.c	2 Jan 2006 04:31:57 -0000	1.48
+++ xcoffread.c	21 Jul 2006 16:58:38 -0000
@@ -1302,7 +1302,7 @@ read_xcoff_symtab (struct partial_symtab
 			     + fcn_aux_saved.x_sym.x_misc.x_fsize
 			     + ANOFFSET (objfile->section_offsets,
 					 SECT_OFF_TEXT (objfile))),
-			    objfile);
+			    NULL, objfile);
 	      within_function = 0;
 	    }
 	  break;
@@ -1393,7 +1393,7 @@ read_xcoff_symtab (struct partial_symtab
 				(cs->c_value
 				 + ANOFFSET (objfile->section_offsets,
 					     SECT_OFF_TEXT (objfile))),
-				objfile);
+				NULL, objfile);
 		}
 	      local_symbols = new->locals;
 	    }


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