This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[rfc/preview] Support for disjoint blocks and local vars in inlined functions
- From: Daniel Jacobowitz <drow at false dot org>
- To: gdb-patches at sourceware dot org
- Date: Fri, 21 Jul 2006 13:15:07 -0400
- Subject: [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, ¤t_low, ¤t_high, cu))
+ if (dwarf2_get_pc_bounds (die, ¤t_low, ¤t_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, ¤t_low, ¤t_high, cu))
+ if (dwarf2_get_pc_bounds (child, ¤t_low, ¤t_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;
}