[PATCH] Fix a bug of addrmap

Jie Zhang
2008-10-21T04:44:00Z

[-- Attachment #1: Type: text/plain, Size: 1158 bytes --]

Hi,

I encountered a problem when trying CVS HEAD gdb with gcc-4.1, which has
no .debug_ranges support. Below is the test case:

$ cat main.c
int main ()
{
return 0;
}

extern void __attribute__ ((__section__ (".init.text"))) foo_init (void);
void foo_init ()
{
return;
}

$ cat foo.c
int foo ()
{
return 0;
}

$ gcc-4.1 -o test main.c foo.c -g

CVS HEAD gdb cannot show the source line of foo.
$ gdb test
GNU gdb (GDB) 6.8.50.20081020-cvs
[snip]
(gdb) b foo
Breakpoint 1 at 0x400458

while gdb-6.8 can
$ gdb test
GNU gdb 6.8
[snip]
(gdb) b foo
Breakpoint 1 at 0x400458: file foo.c, line 3.

Since gcc-4.1 does not generate .debug_ranges, gdb tries to create
addrmap from low_pc and high_pc. When creating mutable addrmap, the
address range of main.c is treated as contiguous, e.g. [0x400448,
0x40053e], while foo.c is e.g. [0x400454, 0x40045f], which is embedded
in the former. In current gdb, the value of the start and end
transitions for foo.c are initialized as same as the value of the start
one for main.c. Then later in addrmap_mutable_set_empty, those
transitions are removed.

This patch should fix this case. Is it OK?

Regards,
Jie

[-- Attachment #2: gdb-addrmap-embedded-range.diff --]
[-- Type: text/x-patch, Size: 2480 bytes --]

* addrmap.c (force_transition): Add new argument start.
(addrmap_mutable_set_empty): Establish the end transition
before the start transition.

Index: addrmap.c
===================================================================
RCS file: /cvs/src/src/gdb/addrmap.c,v
retrieving revision 1.4
diff -u -p -r1.4 addrmap.c
--- addrmap.c 1 Jan 2008 22:53:09 -0000 1.4
+++ addrmap.c 21 Oct 2008 03:42:19 -0000
@@ -291,18 +291,27 @@ addrmap_splay_tree_insert (struct addrma

/* Without changing the mapping of any address, ensure that there is a
tree node at ADDR, even if it would represent a "transition" from
- one value to the same value. */
+ one value to the same value. If START is non-zero, this is the
+ start transition of the address range. Otherwise, it's the end
+ transition. */
static void
-force_transition (struct addrmap_mutable *this, CORE_ADDR addr)
+force_transition (struct addrmap_mutable *this, CORE_ADDR addr, int start)
{
splay_tree_node n
= addrmap_splay_tree_lookup (this, addr);

if (! n)
{
- n = addrmap_splay_tree_predecessor (this, addr);
- addrmap_splay_tree_insert (this, addr,
- n ? addrmap_node_value (n) : NULL);
+ void *value;
+
+ if (start)
+ value = NULL;
+ else
+ {
+ n = addrmap_splay_tree_predecessor (this, addr);
+ value = n ? addrmap_node_value (n) : NULL;
+ }
+ addrmap_splay_tree_insert (this, addr, value);
}
}

@@ -328,10 +337,16 @@ addrmap_mutable_set_empty (struct addrma
- First pass: change all NULL regions to OBJ.
- Second pass: remove any unnecessary transitions. */

- /* Establish transitions at the start and end. */
- force_transition (map, start);
+ /* Establish transitions at the start and end. The end transition
+ is established first such that its value will be initialized as
+ same as the value of its predecessor. The value of the start
+ transition will always be initialized to NULL. With this
+ establishing order, the value of these transitions will be set
+ properly later even if the given address range is embedded in
+ another address range. */
if (end_inclusive < CORE_ADDR_MAX)
- force_transition (map, end_inclusive + 1);
+ force_transition (map, end_inclusive + 1, 0);
+ force_transition (map, start, 1);

/* Walk the area, changing all NULL regions to OBJ. */
for (n = addrmap_splay_tree_lookup (map, start), gdb_assert (n);