[PATCH] gdbserver: Handle DT_MIPS_RLD_MAP dynamic tag

Maciej W. Rozycki
2012-04-03T20:48:11Z

Hi,

While working on a test case for an unrelated issue I have noticed
single-stepping over system library calls is broken on the MIPS/Linux
target when `gdbserver' is used. On closer inspection I have observed
`gdbserver' reports no shared libraries loaded. Further investigation has
revealed that the newly-added support for the `qXfer:libraries-svr4:read'
packet does not handle the DT_MIPS_RLD_MAP dynamic tag and therefore
cannot locate the link map on the MIPS target.

Such support has been long present in gdb/solib-svr4.c, hence a fix
turned out rather mechanical; here's a piece of code ported from there
over to linux-low.c, likewise making no special exception just for the
MIPS platform and applying to generic code instead. This change has fixed
the single-stepping problem observed for me.

Just to be safe I have regression-tested this change for the
mips-linux-gnu remote target, o32/big-endian multilib (using an x86 Linux
host) with 139 failures removed starting from:

(gdb) PASS: gdb.base/break.exp: backtrace from factorial(5.1)
break exit
Function "exit" not defined.
(gdb) FAIL: gdb.base/break.exp: setting breakpoint at exit

and no new ones. I didn't test the change for any other target, but then
DT_MIPS_RLD_MAP tags are not expected to appear on non-MIPS binaries,
hence the "dyn->d_tag == DT_MIPS_RLD_MAP" conditional is not expected to
trigger there.

OK to apply?

2012-04-03 Maciej W. Rozycki <macro@codesourcery.com>

gdb/gdbserver/
* linux-low.c (get_r_debug): Handle DT_MIPS_RLD_MAP.

Maciej

gdb-gdbserver-rld-map.diff
Index: gdb-fsf-trunk-quilt/gdb/gdbserver/linux-low.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/gdbserver/linux-low.c 2012-04-03 13:38:58.575561428 +0100
+++ gdb-fsf-trunk-quilt/gdb/gdbserver/linux-low.c 2012-04-03 13:39:17.315624148 +0100
@@ -5419,7 +5419,9 @@ get_dynamic (const int pid, const int is
}

/* Return &_r_debug in the inferior, or -1 if not present. Return value
- can be 0 if the inferior does not yet have the library list initialized. */
+ can be 0 if the inferior does not yet have the library list initialized.
+ We look for DT_MIPS_RLD_MAP first. MIPS executables use this instead of
+ DT_DEBUG, although they sometimes contain an unused DT_DEBUG entry too. */

static CORE_ADDR
get_r_debug (const int pid, const int is_elf64)
@@ -5437,6 +5439,21 @@ get_r_debug (const int pid, const int is
if (is_elf64)
{
Elf64_Dyn *const dyn = (Elf64_Dyn *) buf;
+ union
+ {
+ Elf64_Xword map;
+ unsigned char buf[sizeof (Elf64_Xword)];
+ }
+ rld_map;
+
+ if (dyn->d_tag == DT_MIPS_RLD_MAP)
+ {
+ if (linux_read_memory (dyn->d_un.d_val,
+ rld_map.buf, sizeof (rld_map.buf)) == 0)
+ return rld_map.map;
+ else
+ break;
+ }

if (dyn->d_tag == DT_DEBUG)
return dyn->d_un.d_val;
@@ -5447,6 +5464,21 @@ get_r_debug (const int pid, const int is
else
{
Elf32_Dyn *const dyn = (Elf32_Dyn *) buf;
+ union
+ {
+ Elf32_Word map;
+ unsigned char buf[sizeof (Elf32_Word)];
+ }
+ rld_map;
+
+ if (dyn->d_tag == DT_MIPS_RLD_MAP)
+ {
+ if (linux_read_memory (dyn->d_un.d_val,
+ rld_map.buf, sizeof (rld_map.buf)) == 0)
+ return rld_map.map;
+ else
+ break;
+ }

if (dyn->d_tag == DT_DEBUG)
return dyn->d_un.d_val;