diff options
author | Markus Metzger <markus.t.metzger@intel.com> | 2021-10-04 10:24:35 +0200 |
---|---|---|
committer | Markus Metzger <markus.t.metzger@intel.com> | 2022-10-18 14:16:08 +0200 |
commit | 8d56636a0ecbe6c38bf52b0683326ee21693c548 (patch) | |
tree | d31ea425eab963a5849039435427ea2880dba1c2 /gdbserver | |
parent | 60d09f0a0d8000359b8f1dd14b51e7f013ea9e5c (diff) | |
download | binutils-8d56636a0ecbe6c38bf52b0683326ee21693c548.zip binutils-8d56636a0ecbe6c38bf52b0683326ee21693c548.tar.gz binutils-8d56636a0ecbe6c38bf52b0683326ee21693c548.tar.bz2 |
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>
Diffstat (limited to 'gdbserver')
-rw-r--r-- | gdbserver/linux-low.cc | 247 |
1 files changed, 153 insertions, 94 deletions
diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc index 2f71360..af3c4b3 100644 --- a/gdbserver/linux-low.cc +++ b/gdbserver/linux-low.cc @@ -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) + std::string document = "<library-list-svr4 version=\"1.0\""; + + /* 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 { - int r_version = 0; + if (lm_prev != 0) + warning ("ignoring prev=0x%s without start", paddress (lm_prev)); - if (priv->r_debug == 0) - priv->r_debug = get_r_debug (pid, is_elf64); + 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) |