Copy-Relocate debug error

Michael Eager
2012-01-30T20:08:04Z

Here is a small test program which uses copy-relocate on X86_64.
Gdb-7.2 gives the wrong value when a global symbol is printed when
stopping in a function in the shared library. gdb-7.3 (and later)
give the correct result. I'm not sure that they get the correct
result because a problem in gdb-7.2 was fixed rather than by accident.

Here's the test program:

$ cat tmp.c
extern int tab[100];

int
main (void)
{
tab[10] = 10;
sub ();
return 0;
}
$ cat libtmp.c
int tab[100] = {2,4,6};

void
sub (void)
{
tab[20] = 20;
}
$ gcc -fpic --shared -g -o libtmp.so libtmp.c
$ gcc -g tmp.c libtmp.so -Wl,-R,`pwd`

Running gdb:

$ gdb a.out
(gdb) b sub
(gdb) run
(gdb) info addr tab
Symbol "tab" is static storage at address 0xxxxxx.

On gdb-7.2, the address given is for the copy of 'tab' in the
shared library. This is not the one which sub() is using. Sub()
references 'tab' indirectly through the GOT, which the run time
loader has set to point to the copy of 'tab' in the executable
which it created as a result of the R_X86_64_COPY for 'tab' in tmp.c.

The code to reference 'tab' in sub() is:
mov 0x200285(%rip),%rax # 200890 <_DYNAMIC+0x1d0>

When gdb-7.2 searches for 'tab', it finds the symbol in the
shared library symbol table with the address specified by this
DWARF location:
DW_OP_addr tab

This is incorrect. The correct DWARF should describe the code:
DW_OP_addr tab@GOT
DW_OP_deref

If I change the DWARF data for 'tab', gdb complains that this is
a "complex expression", which is not supported.

gdb-head gives the correct result because the symbols for a.out
are read as a side-effect of walking the frame chain and it finds
the global definition for 'tab' in a.out, never looking at the
symbols (or DWARF info) for 'tab' in libtmp.so. This does not
happen in gdb-7.2 (I'm not sure why), so it finds the (incorrect)
definition in libtmp.so. If I stop in main() before stopping in
sub(), then gdb-7.2 resolves the address correctly.

I'm looking for suggestions on how to correct this in gdb-7.2.
(I don't have the option of moving to a more recent version.)

I can modify gdb to recognize DW_OP_deref (I would guess in
locexpr_describe_location_piece()). I can (somehow) force gdb
to always read the symbols from the executable. (Anyone know
if this was an intentional change or a side effect of some other
patch?)

Any other suggestions?

--
Michael Eager eager@eagercon.com
1960 Park Blvd., Palo Alto, CA 94306 650-325-8077