mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-08-06 14:49:38 +08:00
gdb, gdbserver: support dlmopen()
In glibc, the r_debug structure contains (amongst others) the following fields: int r_version: Version number for this protocol. It should be greater than 0. If r_version is 2, struct r_debug is extended to struct r_debug_extended with one additional field: struct r_debug_extended *r_next; Link to the next r_debug_extended structure. Each r_debug_extended structure represents a different namespace. The first r_debug_extended structure is for the default namespace. 1. Change solib_svr4_r_map argument to take the debug base. 2. Add solib_svr4_r_next to find the link map in the next namespace from the r_next field. 3. Update svr4_current_sos_direct to get the link map in the next namespace from the r_next field. 4. Don't check shared libraries in other namespaces when updating shared libraries in a new namespace. 5. Update svr4_same to check the load offset in addition to the name 6. Update svr4_default_sos to also set l_addr_inferior 7. Change the flat solib_list into a per-namespace list using the namespace's r_debug address to identify the namespace. Add gdb.base/dlmopen.exp to test this. To remain backwards compatible with older gdbserver, we reserve the namespace zero for a flat list of solibs from all namespaces. Subsequent patches will extend RSP to allow listing libraries grouped by namespace. This fixes PR 11839. Co-authored-by: Lu, Hongjiu <hongjiu.lu@intel.com>
This commit is contained in:
@ -6443,6 +6443,9 @@ struct link_map_offsets
|
||||
/* Offset and size of r_debug.r_map. */
|
||||
int r_map_offset;
|
||||
|
||||
/* Offset of r_debug_extended.r_next. */
|
||||
int r_next_offset;
|
||||
|
||||
/* Offset to l_addr field in struct link_map. */
|
||||
int l_addr_offset;
|
||||
|
||||
@ -6459,6 +6462,98 @@ struct link_map_offsets
|
||||
int l_prev_offset;
|
||||
};
|
||||
|
||||
static const link_map_offsets lmo_32bit_offsets =
|
||||
{
|
||||
0, /* r_version offset. */
|
||||
4, /* r_debug.r_map offset. */
|
||||
20, /* r_debug_extended.r_next. */
|
||||
0, /* l_addr offset in link_map. */
|
||||
4, /* l_name offset in link_map. */
|
||||
8, /* l_ld offset in link_map. */
|
||||
12, /* l_next offset in link_map. */
|
||||
16 /* l_prev offset in link_map. */
|
||||
};
|
||||
|
||||
static const link_map_offsets lmo_64bit_offsets =
|
||||
{
|
||||
0, /* r_version offset. */
|
||||
8, /* r_debug.r_map offset. */
|
||||
40, /* r_debug_extended.r_next. */
|
||||
0, /* l_addr offset in link_map. */
|
||||
8, /* l_name offset in link_map. */
|
||||
16, /* l_ld offset in link_map. */
|
||||
24, /* l_next offset in link_map. */
|
||||
32 /* l_prev offset in link_map. */
|
||||
};
|
||||
|
||||
/* Get the loaded shared libraries from one namespace. */
|
||||
|
||||
static void
|
||||
read_link_map (std::string &document, CORE_ADDR lm_addr, CORE_ADDR lm_prev,
|
||||
int ptr_size, const link_map_offsets *lmo, bool ignore_first,
|
||||
int &header_done)
|
||||
{
|
||||
CORE_ADDR l_name, l_addr, l_ld, l_next, l_prev;
|
||||
|
||||
while (lm_addr
|
||||
&& read_one_ptr (lm_addr + lmo->l_name_offset,
|
||||
&l_name, ptr_size) == 0
|
||||
&& read_one_ptr (lm_addr + lmo->l_addr_offset,
|
||||
&l_addr, ptr_size) == 0
|
||||
&& read_one_ptr (lm_addr + lmo->l_ld_offset,
|
||||
&l_ld, ptr_size) == 0
|
||||
&& read_one_ptr (lm_addr + lmo->l_prev_offset,
|
||||
&l_prev, ptr_size) == 0
|
||||
&& read_one_ptr (lm_addr + lmo->l_next_offset,
|
||||
&l_next, ptr_size) == 0)
|
||||
{
|
||||
unsigned char libname[PATH_MAX];
|
||||
|
||||
if (lm_prev != l_prev)
|
||||
{
|
||||
warning ("Corrupted shared library list: 0x%s != 0x%s",
|
||||
paddress (lm_prev), paddress (l_prev));
|
||||
break;
|
||||
}
|
||||
|
||||
/* Ignore the first entry even if it has valid name as the first entry
|
||||
corresponds to the main executable. The first entry should not be
|
||||
skipped if the dynamic loader was loaded late by a static executable
|
||||
(see solib-svr4.c parameter ignore_first). But in such case the main
|
||||
executable does not have PT_DYNAMIC present and this function already
|
||||
exited above due to failed get_r_debug. */
|
||||
if (ignore_first && lm_prev == 0)
|
||||
string_appendf (document, " main-lm=\"0x%s\"", paddress (lm_addr));
|
||||
else
|
||||
{
|
||||
/* Not checking for error because reading may stop before
|
||||
we've got PATH_MAX worth of characters. */
|
||||
libname[0] = '\0';
|
||||
linux_read_memory (l_name, libname, sizeof (libname) - 1);
|
||||
libname[sizeof (libname) - 1] = '\0';
|
||||
if (libname[0] != '\0')
|
||||
{
|
||||
if (!header_done)
|
||||
{
|
||||
/* Terminate `<library-list-svr4'. */
|
||||
document += '>';
|
||||
header_done = 1;
|
||||
}
|
||||
|
||||
string_appendf (document, "<library name=\"");
|
||||
xml_escape_text_append (&document, (char *) libname);
|
||||
string_appendf (document, "\" lm=\"0x%s\" l_addr=\"0x%s\" "
|
||||
"l_ld=\"0x%s\"/>",
|
||||
paddress (lm_addr), paddress (l_addr),
|
||||
paddress (l_ld));
|
||||
}
|
||||
}
|
||||
|
||||
lm_prev = lm_addr;
|
||||
lm_addr = l_next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Construct qXfer:libraries-svr4:read reply. */
|
||||
|
||||
int
|
||||
@ -6470,33 +6565,8 @@ linux_process_target::qxfer_libraries_svr4 (const char *annex,
|
||||
struct process_info_private *const priv = current_process ()->priv;
|
||||
char filename[PATH_MAX];
|
||||
int pid, is_elf64;
|
||||
|
||||
static const struct link_map_offsets lmo_32bit_offsets =
|
||||
{
|
||||
0, /* r_version offset. */
|
||||
4, /* r_debug.r_map offset. */
|
||||
0, /* l_addr offset in link_map. */
|
||||
4, /* l_name offset in link_map. */
|
||||
8, /* l_ld offset in link_map. */
|
||||
12, /* l_next offset in link_map. */
|
||||
16 /* l_prev offset in link_map. */
|
||||
};
|
||||
|
||||
static const struct link_map_offsets lmo_64bit_offsets =
|
||||
{
|
||||
0, /* r_version offset. */
|
||||
8, /* r_debug.r_map offset. */
|
||||
0, /* l_addr offset in link_map. */
|
||||
8, /* l_name offset in link_map. */
|
||||
16, /* l_ld offset in link_map. */
|
||||
24, /* l_next offset in link_map. */
|
||||
32 /* l_prev offset in link_map. */
|
||||
};
|
||||
const struct link_map_offsets *lmo;
|
||||
unsigned int machine;
|
||||
int ptr_size;
|
||||
CORE_ADDR lm_addr = 0, lm_prev = 0;
|
||||
CORE_ADDR l_name, l_addr, l_ld, l_next, l_prev;
|
||||
int header_done = 0;
|
||||
|
||||
if (writebuf != NULL)
|
||||
@ -6507,8 +6577,18 @@ linux_process_target::qxfer_libraries_svr4 (const char *annex,
|
||||
pid = lwpid_of (current_thread);
|
||||
xsnprintf (filename, sizeof filename, "/proc/%d/exe", pid);
|
||||
is_elf64 = elf_64_file_p (filename, &machine);
|
||||
lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
|
||||
ptr_size = is_elf64 ? 8 : 4;
|
||||
const link_map_offsets *lmo;
|
||||
int ptr_size;
|
||||
if (is_elf64)
|
||||
{
|
||||
lmo = &lmo_64bit_offsets;
|
||||
ptr_size = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
lmo = &lmo_32bit_offsets;
|
||||
ptr_size = 4;
|
||||
}
|
||||
|
||||
while (annex[0] != '\0')
|
||||
{
|
||||
@ -6537,95 +6617,74 @@ linux_process_target::qxfer_libraries_svr4 (const char *annex,
|
||||
annex = decode_address_to_semicolon (addrp, sep + 1);
|
||||
}
|
||||
|
||||
if (lm_addr == 0)
|
||||
{
|
||||
int r_version = 0;
|
||||
std::string document = "<library-list-svr4 version=\"1.0\"";
|
||||
|
||||
if (priv->r_debug == 0)
|
||||
priv->r_debug = get_r_debug (pid, is_elf64);
|
||||
/* When the starting LM_ADDR is passed in the annex, only traverse that
|
||||
namespace.
|
||||
|
||||
Otherwise, start with R_DEBUG and traverse all namespaces we find. */
|
||||
if (lm_addr != 0)
|
||||
read_link_map (document, lm_addr, lm_prev, ptr_size, lmo, false,
|
||||
header_done);
|
||||
else
|
||||
{
|
||||
if (lm_prev != 0)
|
||||
warning ("ignoring prev=0x%s without start", paddress (lm_prev));
|
||||
|
||||
CORE_ADDR r_debug = priv->r_debug;
|
||||
if (r_debug == 0)
|
||||
r_debug = priv->r_debug = get_r_debug (pid, is_elf64);
|
||||
|
||||
/* We failed to find DT_DEBUG. Such situation will not change
|
||||
for this inferior - do not retry it. Report it to GDB as
|
||||
E01, see for the reasons at the GDB solib-svr4.c side. */
|
||||
if (priv->r_debug == (CORE_ADDR) -1)
|
||||
if (r_debug == (CORE_ADDR) -1)
|
||||
return -1;
|
||||
|
||||
if (priv->r_debug != 0)
|
||||
bool ignore_first = true;
|
||||
while (r_debug != 0)
|
||||
{
|
||||
if (linux_read_memory (priv->r_debug + lmo->r_version_offset,
|
||||
int r_version = 0;
|
||||
if (linux_read_memory (r_debug + lmo->r_version_offset,
|
||||
(unsigned char *) &r_version,
|
||||
sizeof (r_version)) != 0
|
||||
|| r_version < 1)
|
||||
sizeof (r_version)) != 0)
|
||||
{
|
||||
warning ("unable to read r_version from 0x%s",
|
||||
paddress (r_debug + lmo->r_version_offset));
|
||||
break;
|
||||
}
|
||||
|
||||
if (r_version < 1)
|
||||
{
|
||||
warning ("unexpected r_debug version %d", r_version);
|
||||
break;
|
||||
}
|
||||
else if (read_one_ptr (priv->r_debug + lmo->r_map_offset,
|
||||
&lm_addr, ptr_size) != 0)
|
||||
|
||||
if (read_one_ptr (r_debug + lmo->r_map_offset, &lm_addr,
|
||||
ptr_size) != 0)
|
||||
{
|
||||
warning ("unable to read r_map from 0x%lx",
|
||||
(long) priv->r_debug + lmo->r_map_offset);
|
||||
warning ("unable to read r_map from 0x%s",
|
||||
paddress (r_debug + lmo->r_map_offset));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string document = "<library-list-svr4 version=\"1.0\"";
|
||||
read_link_map (document, lm_addr, 0, ptr_size, lmo,
|
||||
ignore_first, header_done);
|
||||
|
||||
while (lm_addr
|
||||
&& read_one_ptr (lm_addr + lmo->l_name_offset,
|
||||
&l_name, ptr_size) == 0
|
||||
&& read_one_ptr (lm_addr + lmo->l_addr_offset,
|
||||
&l_addr, ptr_size) == 0
|
||||
&& read_one_ptr (lm_addr + lmo->l_ld_offset,
|
||||
&l_ld, ptr_size) == 0
|
||||
&& read_one_ptr (lm_addr + lmo->l_prev_offset,
|
||||
&l_prev, ptr_size) == 0
|
||||
&& read_one_ptr (lm_addr + lmo->l_next_offset,
|
||||
&l_next, ptr_size) == 0)
|
||||
{
|
||||
unsigned char libname[PATH_MAX];
|
||||
if (r_version < 2)
|
||||
break;
|
||||
|
||||
if (lm_prev != l_prev)
|
||||
{
|
||||
warning ("Corrupted shared library list: 0x%lx != 0x%lx",
|
||||
(long) lm_prev, (long) l_prev);
|
||||
break;
|
||||
}
|
||||
/* Only applies to the default namespace. */
|
||||
ignore_first = false;
|
||||
|
||||
/* Ignore the first entry even if it has valid name as the first entry
|
||||
corresponds to the main executable. The first entry should not be
|
||||
skipped if the dynamic loader was loaded late by a static executable
|
||||
(see solib-svr4.c parameter ignore_first). But in such case the main
|
||||
executable does not have PT_DYNAMIC present and this function already
|
||||
exited above due to failed get_r_debug. */
|
||||
if (lm_prev == 0)
|
||||
string_appendf (document, " main-lm=\"0x%lx\"", (unsigned long) lm_addr);
|
||||
else
|
||||
{
|
||||
/* Not checking for error because reading may stop before
|
||||
we've got PATH_MAX worth of characters. */
|
||||
libname[0] = '\0';
|
||||
linux_read_memory (l_name, libname, sizeof (libname) - 1);
|
||||
libname[sizeof (libname) - 1] = '\0';
|
||||
if (libname[0] != '\0')
|
||||
if (read_one_ptr (r_debug + lmo->r_next_offset, &r_debug,
|
||||
ptr_size) != 0)
|
||||
{
|
||||
if (!header_done)
|
||||
{
|
||||
/* Terminate `<library-list-svr4'. */
|
||||
document += '>';
|
||||
header_done = 1;
|
||||
}
|
||||
|
||||
string_appendf (document, "<library name=\"");
|
||||
xml_escape_text_append (&document, (char *) libname);
|
||||
string_appendf (document, "\" lm=\"0x%lx\" "
|
||||
"l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
|
||||
(unsigned long) lm_addr, (unsigned long) l_addr,
|
||||
(unsigned long) l_ld);
|
||||
warning ("unable to read r_next from 0x%s",
|
||||
paddress (r_debug + lmo->r_next_offset));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lm_prev = lm_addr;
|
||||
lm_addr = l_next;
|
||||
}
|
||||
|
||||
if (!header_done)
|
||||
|
Reference in New Issue
Block a user