mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-11-28 22:40:24 +00:00
gdb/
* Makefile.in (XMLFILES): Add library-list-svr4.dtd. * features/library-list-svr4.dtd: New file. * remote.c (PACKET_qXfer_libraries_svr4): New. (remote_protocol_features): new entry for PACKET_qXfer_libraries_svr4. (remote_xfer_partial): Handle TARGET_OBJECT_LIBRARIES_SVR4. * solib-svr4.c (struct svr4_library_list): New. [HAVE_LIBEXPAT]: Include xml-support.h. [HAVE_LIBEXPAT] (svr4_library_list_start_library) [HAVE_LIBEXPAT] (svr4_library_list_start_list, svr4_library_attributes) [HAVE_LIBEXPAT] (svr4_library_list_children) [HAVE_LIBEXPAT] (svr4_library_list_attributes) [HAVE_LIBEXPAT] (svr4_library_list_elements, svr4_parse_libraries) [HAVE_LIBEXPAT] (svr4_current_sos_via_xfer_libraries) [!HAVE_LIBEXPAT] (svr4_current_sos_via_xfer_libraries): New. (svr4_read_so_list): Extend the corruption message by addresses. (svr4_current_sos): New variable library_list, call svr4_current_sos_via_xfer_libraries. * target.h (enum target_object): New TARGET_OBJECT_LIBRARIES_SVR4. gdb/gdbserver/ * linux-low.c (get_phdr_phnum_from_proc_auxv, get_dynamic, get_r_debug) (read_one_ptr, struct link_map_offsets, linux_qxfer_libraries_svr4): New. (struct linux_target_ops): Install linux_qxfer_libraries_svr4. * linux-low.h (struct process_info_private): New member r_debug. * server.c (handle_qxfer_libraries): Call the_target->qxfer_libraries_svr4. (handle_qxfer_libraries_svr4): New function. (qxfer_packets): New entry "libraries-svr4". (handle_query): Check QXFER_LIBRARIES_SVR4 and report libraries-svr4. * target.h (struct target_ops): New member qxfer_libraries_svr4. * remote.c (remote_xfer_partial): Call add_packet_config_cmd for PACKET_qXfer_libraries_svr4. gdb/doc/ * gdb.texinfo (Requirements, Remote Protocol): Reference also `Library List Format for SVR4 Targets'. (General Query Packets): New item qXfer:libraries-svr4:read. (Library List Format for SVR4 Targets): New node. gdb/testsuite/ * gdb.base/solib-corrupted.exp: Suppress test on is_remote target. (corrupted list): Adjust the expectation.
This commit is contained in:
parent
1b31d05e6b
commit
2268b414f4
@ -1,3 +1,25 @@
|
||||
2011-12-02 Paul Pluzhnikov <ppluzhnikov@google.com>
|
||||
Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
* Makefile.in (XMLFILES): Add library-list-svr4.dtd.
|
||||
* features/library-list-svr4.dtd: New file.
|
||||
* remote.c (PACKET_qXfer_libraries_svr4): New.
|
||||
(remote_protocol_features): new entry for PACKET_qXfer_libraries_svr4.
|
||||
(remote_xfer_partial): Handle TARGET_OBJECT_LIBRARIES_SVR4.
|
||||
* solib-svr4.c (struct svr4_library_list): New.
|
||||
[HAVE_LIBEXPAT]: Include xml-support.h.
|
||||
[HAVE_LIBEXPAT] (svr4_library_list_start_library)
|
||||
[HAVE_LIBEXPAT] (svr4_library_list_start_list, svr4_library_attributes)
|
||||
[HAVE_LIBEXPAT] (svr4_library_list_children)
|
||||
[HAVE_LIBEXPAT] (svr4_library_list_attributes)
|
||||
[HAVE_LIBEXPAT] (svr4_library_list_elements, svr4_parse_libraries)
|
||||
[HAVE_LIBEXPAT] (svr4_current_sos_via_xfer_libraries)
|
||||
[!HAVE_LIBEXPAT] (svr4_current_sos_via_xfer_libraries): New.
|
||||
(svr4_read_so_list): Extend the corruption message by addresses.
|
||||
(svr4_current_sos): New variable library_list, call
|
||||
svr4_current_sos_via_xfer_libraries.
|
||||
* target.h (enum target_object): New TARGET_OBJECT_LIBRARIES_SVR4.
|
||||
|
||||
2011-12-02 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
PR threads/13448
|
||||
|
@ -495,7 +495,8 @@ RUNTESTFLAGS=
|
||||
|
||||
# XML files to build in to GDB.
|
||||
XMLFILES = $(srcdir)/features/gdb-target.dtd $(srcdir)/features/xinclude.dtd \
|
||||
$(srcdir)/features/library-list.dtd $(srcdir)/features/osdata.dtd \
|
||||
$(srcdir)/features/library-list.dtd \
|
||||
$(srcdir)/features/library-list-svr4.dtd $(srcdir)/features/osdata.dtd \
|
||||
$(srcdir)/features/threads.dtd $(srcdir)/features/traceframe-info.dtd
|
||||
|
||||
# This is ser-unix.o for any system which supports a v7/BSD/SYSV/POSIX
|
||||
|
@ -1,3 +1,10 @@
|
||||
2011-12-02 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
* gdb.texinfo (Requirements, Remote Protocol): Reference also `Library
|
||||
List Format for SVR4 Targets'.
|
||||
(General Query Packets): New item qXfer:libraries-svr4:read.
|
||||
(Library List Format for SVR4 Targets): New node.
|
||||
|
||||
2011-12-01 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* gdb.texinfo (Writing a Pretty-Printer): Use append method, not
|
||||
|
@ -32448,7 +32448,8 @@ Remote protocol memory maps (@pxref{Memory Map Format})
|
||||
@item
|
||||
Target descriptions (@pxref{Target Descriptions})
|
||||
@item
|
||||
Remote shared library lists (@pxref{Library List Format})
|
||||
Remote shared library lists (@xref{Library List Format},
|
||||
or alternatively @pxref{Library List Format for SVR4 Targets})
|
||||
@item
|
||||
MS-Windows shared libraries (@pxref{Shared Libraries})
|
||||
@item
|
||||
@ -33285,6 +33286,7 @@ Show the current setting of the target wait timeout.
|
||||
* Examples::
|
||||
* File-I/O Remote Protocol Extension::
|
||||
* Library List Format::
|
||||
* Library List Format for SVR4 Targets::
|
||||
* Memory Map Format::
|
||||
* Thread List Format::
|
||||
* Traceframe Info Format::
|
||||
@ -34986,6 +34988,10 @@ The remote stub understands the @samp{qXfer:features:read} packet
|
||||
The remote stub understands the @samp{qXfer:libraries:read} packet
|
||||
(@pxref{qXfer library list read}).
|
||||
|
||||
@item qXfer:libraries-svr4:read
|
||||
The remote stub understands the @samp{qXfer:libraries-svr4:read} packet
|
||||
(@pxref{qXfer svr4 library list read}).
|
||||
|
||||
@item qXfer:memory-map:read
|
||||
The remote stub understands the @samp{qXfer:memory-map:read} packet
|
||||
(@pxref{qXfer memory map read}).
|
||||
@ -35231,6 +35237,18 @@ the operating system manages the list of loaded libraries.
|
||||
This packet is not probed by default; the remote stub must request it,
|
||||
by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
|
||||
|
||||
@item qXfer:libraries-svr4:read:@var{annex}:@var{offset},@var{length}
|
||||
@anchor{qXfer svr4 library list read}
|
||||
Access the target's list of loaded libraries when the target is an SVR4
|
||||
platform. @xref{Library List Format for SVR4 Targets}. The annex part
|
||||
of the generic @samp{qXfer} packet must be empty (@pxref{qXfer read}).
|
||||
|
||||
This packet is optional for better performance on SVR4 targets.
|
||||
@value{GDBN} uses memory read packets to read the SVR4 library list otherwise.
|
||||
|
||||
This packet is not probed by default; the remote stub must request it,
|
||||
by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
|
||||
|
||||
@item qXfer:memory-map:read::@var{offset},@var{length}
|
||||
@anchor{qXfer memory map read}
|
||||
Access the target's @dfn{memory-map}. @xref{Memory Map Format}. The
|
||||
@ -37542,6 +37560,68 @@ In addition, segments and section descriptors cannot be mixed within a
|
||||
single library element, and you must supply at least one segment or
|
||||
section for each library.
|
||||
|
||||
@node Library List Format for SVR4 Targets
|
||||
@section Library List Format for SVR4 Targets
|
||||
@cindex library list format, remote protocol
|
||||
|
||||
On SVR4 platforms @value{GDBN} can use the symbol table of a dynamic loader
|
||||
(e.g.@: @file{ld.so}) and normal memory operations to maintain a list of
|
||||
shared libraries. Still a special library list provided by this packet is
|
||||
more efficient for the @value{GDBN} remote protocol.
|
||||
|
||||
The @samp{qXfer:libraries-svr4:read} packet returns an XML document which lists
|
||||
loaded libraries and their SVR4 linker parameters. For each library on SVR4
|
||||
target, the following parameters are reported:
|
||||
|
||||
@itemize @minus
|
||||
@item
|
||||
@code{name}, the absolute file name from the @code{l_name} field of
|
||||
@code{struct link_map}.
|
||||
@item
|
||||
@code{lm} with address of @code{struct link_map} used for TLS
|
||||
(Thread Local Storage) access.
|
||||
@item
|
||||
@code{l_addr}, the displacement as read from the field @code{l_addr} of
|
||||
@code{struct link_map}. For prelinked libraries this is not an absolute
|
||||
memory address. It is a displacement of absolute memory address against
|
||||
address the file was prelinked to during the library load.
|
||||
@item
|
||||
@code{l_ld}, which is memory address of the @code{PT_DYNAMIC} segment
|
||||
@end itemize
|
||||
|
||||
Additionally the single @code{main-lm} attribute specifies address of
|
||||
@code{struct link_map} used for the main executable. This parameter is used
|
||||
for TLS access and its presence is optional.
|
||||
|
||||
@value{GDBN} must be linked with the Expat library to support XML
|
||||
SVR4 library lists. @xref{Expat}.
|
||||
|
||||
A simple memory map, with two loaded libraries (which do not use prelink),
|
||||
looks like this:
|
||||
|
||||
@smallexample
|
||||
<library-list-svr4 version="1.0" main-lm="0xe4f8f8">
|
||||
<library name="/lib/ld-linux.so.2" lm="0xe4f51c" l_addr="0xe2d000"
|
||||
l_ld="0xe4eefc"/>
|
||||
<library name="/lib/libc.so.6" lm="0xe4fbe8" l_addr="0x154000"
|
||||
l_ld="0x152350"/>
|
||||
</library-list-svr>
|
||||
@end smallexample
|
||||
|
||||
The format of an SVR4 library list is described by this DTD:
|
||||
|
||||
@smallexample
|
||||
<!-- library-list-svr4: Root element with versioning -->
|
||||
<!ELEMENT library-list-svr4 (library)*>
|
||||
<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
|
||||
<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
|
||||
<!ELEMENT library EMPTY>
|
||||
<!ATTLIST library name CDATA #REQUIRED>
|
||||
<!ATTLIST library lm CDATA #REQUIRED>
|
||||
<!ATTLIST library l_addr CDATA #REQUIRED>
|
||||
<!ATTLIST library l_ld CDATA #REQUIRED>
|
||||
@end smallexample
|
||||
|
||||
@node Memory Map Format
|
||||
@section Memory Map Format
|
||||
@cindex memory map format
|
||||
|
16
gdb/features/library-list-svr4.dtd
Normal file
16
gdb/features/library-list-svr4.dtd
Normal file
@ -0,0 +1,16 @@
|
||||
<!-- Copyright (C) 2011 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. -->
|
||||
|
||||
<!-- library-list-svr4: Root element with versioning -->
|
||||
<!ELEMENT library-list-svr4 (library)*>
|
||||
<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
|
||||
<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
|
||||
|
||||
<!ELEMENT library EMPTY>
|
||||
<!ATTLIST library name CDATA #REQUIRED>
|
||||
<!ATTLIST library lm CDATA #REQUIRED>
|
||||
<!ATTLIST library l_addr CDATA #REQUIRED>
|
||||
<!ATTLIST library l_ld CDATA #REQUIRED>
|
@ -1,3 +1,20 @@
|
||||
2011-12-02 Paul Pluzhnikov <ppluzhnikov@google.com>
|
||||
Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
* linux-low.c (get_phdr_phnum_from_proc_auxv, get_dynamic, get_r_debug)
|
||||
(read_one_ptr, struct link_map_offsets, linux_qxfer_libraries_svr4):
|
||||
New.
|
||||
(struct linux_target_ops): Install linux_qxfer_libraries_svr4.
|
||||
* linux-low.h (struct process_info_private): New member r_debug.
|
||||
* server.c (handle_qxfer_libraries): Call
|
||||
the_target->qxfer_libraries_svr4.
|
||||
(handle_qxfer_libraries_svr4): New function.
|
||||
(qxfer_packets): New entry "libraries-svr4".
|
||||
(handle_query): Check QXFER_LIBRARIES_SVR4 and report libraries-svr4.
|
||||
* target.h (struct target_ops): New member qxfer_libraries_svr4.
|
||||
* remote.c (remote_xfer_partial): Call add_packet_config_cmd for
|
||||
PACKET_qXfer_libraries_svr4.
|
||||
|
||||
2011-11-30 Ulrich Weigand <uweigand@de.ibm.com>
|
||||
|
||||
* linux-s390-low.c (s390_collect_ptrace_register): Fully convert
|
||||
|
@ -4964,6 +4964,382 @@ linux_get_min_fast_tracepoint_insn_len (void)
|
||||
return (*the_low_target.get_min_fast_tracepoint_insn_len) ();
|
||||
}
|
||||
|
||||
/* Extract &phdr and num_phdr in the inferior. Return 0 on success. */
|
||||
|
||||
static int
|
||||
get_phdr_phnum_from_proc_auxv (const int pid, const int is_elf64,
|
||||
CORE_ADDR *phdr_memaddr, int *num_phdr)
|
||||
{
|
||||
char filename[PATH_MAX];
|
||||
int fd;
|
||||
const int auxv_size = is_elf64
|
||||
? sizeof (Elf64_auxv_t) : sizeof (Elf32_auxv_t);
|
||||
char buf[sizeof (Elf64_auxv_t)]; /* The larger of the two. */
|
||||
|
||||
xsnprintf (filename, sizeof filename, "/proc/%d/auxv", pid);
|
||||
|
||||
fd = open (filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return 1;
|
||||
|
||||
*phdr_memaddr = 0;
|
||||
*num_phdr = 0;
|
||||
while (read (fd, buf, auxv_size) == auxv_size
|
||||
&& (*phdr_memaddr == 0 || *num_phdr == 0))
|
||||
{
|
||||
if (is_elf64)
|
||||
{
|
||||
Elf64_auxv_t *const aux = (Elf64_auxv_t *) buf;
|
||||
|
||||
switch (aux->a_type)
|
||||
{
|
||||
case AT_PHDR:
|
||||
*phdr_memaddr = aux->a_un.a_val;
|
||||
break;
|
||||
case AT_PHNUM:
|
||||
*num_phdr = aux->a_un.a_val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Elf32_auxv_t *const aux = (Elf32_auxv_t *) buf;
|
||||
|
||||
switch (aux->a_type)
|
||||
{
|
||||
case AT_PHDR:
|
||||
*phdr_memaddr = aux->a_un.a_val;
|
||||
break;
|
||||
case AT_PHNUM:
|
||||
*num_phdr = aux->a_un.a_val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close (fd);
|
||||
|
||||
if (*phdr_memaddr == 0 || *num_phdr == 0)
|
||||
{
|
||||
warning ("Unexpected missing AT_PHDR and/or AT_PHNUM: "
|
||||
"phdr_memaddr = %ld, phdr_num = %d",
|
||||
(long) *phdr_memaddr, *num_phdr);
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return &_DYNAMIC (via PT_DYNAMIC) in the inferior, or 0 if not present. */
|
||||
|
||||
static CORE_ADDR
|
||||
get_dynamic (const int pid, const int is_elf64)
|
||||
{
|
||||
CORE_ADDR phdr_memaddr, relocation;
|
||||
int num_phdr, i;
|
||||
unsigned char *phdr_buf;
|
||||
const int phdr_size = is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr);
|
||||
|
||||
if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &num_phdr))
|
||||
return 0;
|
||||
|
||||
gdb_assert (num_phdr < 100); /* Basic sanity check. */
|
||||
phdr_buf = alloca (num_phdr * phdr_size);
|
||||
|
||||
if (linux_read_memory (phdr_memaddr, phdr_buf, num_phdr * phdr_size))
|
||||
return 0;
|
||||
|
||||
/* Compute relocation: it is expected to be 0 for "regular" executables,
|
||||
non-zero for PIE ones. */
|
||||
relocation = -1;
|
||||
for (i = 0; relocation == -1 && i < num_phdr; i++)
|
||||
if (is_elf64)
|
||||
{
|
||||
Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size);
|
||||
|
||||
if (p->p_type == PT_PHDR)
|
||||
relocation = phdr_memaddr - p->p_vaddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size);
|
||||
|
||||
if (p->p_type == PT_PHDR)
|
||||
relocation = phdr_memaddr - p->p_vaddr;
|
||||
}
|
||||
|
||||
if (relocation == -1)
|
||||
{
|
||||
warning ("Unexpected missing PT_PHDR");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_phdr; i++)
|
||||
{
|
||||
if (is_elf64)
|
||||
{
|
||||
Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size);
|
||||
|
||||
if (p->p_type == PT_DYNAMIC)
|
||||
return p->p_vaddr + relocation;
|
||||
}
|
||||
else
|
||||
{
|
||||
Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size);
|
||||
|
||||
if (p->p_type == PT_DYNAMIC)
|
||||
return p->p_vaddr + relocation;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
static CORE_ADDR
|
||||
get_r_debug (const int pid, const int is_elf64)
|
||||
{
|
||||
CORE_ADDR dynamic_memaddr;
|
||||
const int dyn_size = is_elf64 ? sizeof (Elf64_Dyn) : sizeof (Elf32_Dyn);
|
||||
unsigned char buf[sizeof (Elf64_Dyn)]; /* The larger of the two. */
|
||||
|
||||
dynamic_memaddr = get_dynamic (pid, is_elf64);
|
||||
if (dynamic_memaddr == 0)
|
||||
return (CORE_ADDR) -1;
|
||||
|
||||
while (linux_read_memory (dynamic_memaddr, buf, dyn_size) == 0)
|
||||
{
|
||||
if (is_elf64)
|
||||
{
|
||||
Elf64_Dyn *const dyn = (Elf64_Dyn *) buf;
|
||||
|
||||
if (dyn->d_tag == DT_DEBUG)
|
||||
return dyn->d_un.d_val;
|
||||
|
||||
if (dyn->d_tag == DT_NULL)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Elf32_Dyn *const dyn = (Elf32_Dyn *) buf;
|
||||
|
||||
if (dyn->d_tag == DT_DEBUG)
|
||||
return dyn->d_un.d_val;
|
||||
|
||||
if (dyn->d_tag == DT_NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
dynamic_memaddr += dyn_size;
|
||||
}
|
||||
|
||||
return (CORE_ADDR) -1;
|
||||
}
|
||||
|
||||
/* Read one pointer from MEMADDR in the inferior. */
|
||||
|
||||
static int
|
||||
read_one_ptr (CORE_ADDR memaddr, CORE_ADDR *ptr, int ptr_size)
|
||||
{
|
||||
*ptr = 0;
|
||||
return linux_read_memory (memaddr, (unsigned char *) ptr, ptr_size);
|
||||
}
|
||||
|
||||
struct link_map_offsets
|
||||
{
|
||||
/* Offset and size of r_debug.r_version. */
|
||||
int r_version_offset;
|
||||
|
||||
/* Offset and size of r_debug.r_map. */
|
||||
int r_map_offset;
|
||||
|
||||
/* Offset to l_addr field in struct link_map. */
|
||||
int l_addr_offset;
|
||||
|
||||
/* Offset to l_name field in struct link_map. */
|
||||
int l_name_offset;
|
||||
|
||||
/* Offset to l_ld field in struct link_map. */
|
||||
int l_ld_offset;
|
||||
|
||||
/* Offset to l_next field in struct link_map. */
|
||||
int l_next_offset;
|
||||
|
||||
/* Offset to l_prev field in struct link_map. */
|
||||
int l_prev_offset;
|
||||
};
|
||||
|
||||
/* Construct qXfer:libraries:read reply. */
|
||||
|
||||
static int
|
||||
linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
|
||||
unsigned const char *writebuf,
|
||||
CORE_ADDR offset, int len)
|
||||
{
|
||||
char *document;
|
||||
unsigned document_len;
|
||||
struct process_info_private *const priv = current_process ()->private;
|
||||
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;
|
||||
|
||||
if (writebuf != NULL)
|
||||
return -2;
|
||||
if (readbuf == NULL)
|
||||
return -1;
|
||||
|
||||
pid = lwpid_of (get_thread_lwp (current_inferior));
|
||||
xsnprintf (filename, sizeof filename, "/proc/%d/exe", pid);
|
||||
is_elf64 = elf_64_file_p (filename);
|
||||
lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
|
||||
|
||||
if (priv->r_debug == 0)
|
||||
priv->r_debug = get_r_debug (pid, is_elf64);
|
||||
|
||||
if (priv->r_debug == (CORE_ADDR) -1 || priv->r_debug == 0)
|
||||
{
|
||||
document = xstrdup ("<library-list-svr4 version=\"1.0\"/>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
int allocated = 1024;
|
||||
char *p;
|
||||
const int ptr_size = is_elf64 ? 8 : 4;
|
||||
CORE_ADDR lm_addr, lm_prev, l_name, l_addr, l_ld, l_next, l_prev;
|
||||
int r_version, header_done = 0;
|
||||
|
||||
document = xmalloc (allocated);
|
||||
strcpy (document, "<library-list-svr4 version=\"1.0\"");
|
||||
p = document + strlen (document);
|
||||
|
||||
r_version = 0;
|
||||
if (linux_read_memory (priv->r_debug + lmo->r_version_offset,
|
||||
(unsigned char *) &r_version,
|
||||
sizeof (r_version)) != 0
|
||||
|| r_version != 1)
|
||||
{
|
||||
warning ("unexpected r_debug version %d", r_version);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (read_one_ptr (priv->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);
|
||||
goto done;
|
||||
}
|
||||
|
||||
lm_prev = 0;
|
||||
while (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%lx != 0x%lx",
|
||||
(long) lm_prev, (long) l_prev);
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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')
|
||||
{
|
||||
/* 6x the size for xml_escape_text below. */
|
||||
size_t len = 6 * strlen ((char *) libname);
|
||||
char *name;
|
||||
|
||||
if (!header_done)
|
||||
{
|
||||
/* Terminate `<library-list-svr4'. */
|
||||
*p++ = '>';
|
||||
header_done = 1;
|
||||
}
|
||||
|
||||
while (allocated < p - document + len + 200)
|
||||
{
|
||||
/* Expand to guarantee sufficient storage. */
|
||||
uintptr_t document_len = p - document;
|
||||
|
||||
document = xrealloc (document, 2 * allocated);
|
||||
allocated *= 2;
|
||||
p = document + document_len;
|
||||
}
|
||||
|
||||
name = xml_escape_text ((char *) libname);
|
||||
p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" "
|
||||
"l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
|
||||
name, (unsigned long) lm_addr,
|
||||
(unsigned long) l_addr, (unsigned long) l_ld);
|
||||
free (name);
|
||||
}
|
||||
else if (lm_prev == 0)
|
||||
{
|
||||
sprintf (p, " main-lm=\"0x%lx\"", (unsigned long) lm_addr);
|
||||
p = p + strlen (p);
|
||||
}
|
||||
|
||||
if (l_next == 0)
|
||||
break;
|
||||
|
||||
lm_prev = lm_addr;
|
||||
lm_addr = l_next;
|
||||
}
|
||||
done:
|
||||
strcpy (p, "</library-list-svr4>");
|
||||
}
|
||||
|
||||
document_len = strlen (document);
|
||||
if (offset < document_len)
|
||||
document_len -= offset;
|
||||
else
|
||||
document_len = 0;
|
||||
if (len > document_len)
|
||||
len = document_len;
|
||||
|
||||
memcpy (readbuf, document + offset, len);
|
||||
xfree (document);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static struct target_ops linux_target_ops = {
|
||||
linux_create_inferior,
|
||||
linux_attach,
|
||||
@ -5026,6 +5402,7 @@ static struct target_ops linux_target_ops = {
|
||||
linux_emit_ops,
|
||||
linux_supports_disable_randomization,
|
||||
linux_get_min_fast_tracepoint_insn_len,
|
||||
linux_qxfer_libraries_svr4,
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -56,6 +56,9 @@ struct process_info_private
|
||||
/* libthread_db-specific additions. Not NULL if this process has loaded
|
||||
thread_db, and it is active. */
|
||||
struct thread_db *thread_db;
|
||||
|
||||
/* &_r_debug. 0 if not yet determined. -1 if no PT_DYNAMIC in Phdrs. */
|
||||
CORE_ADDR r_debug;
|
||||
};
|
||||
|
||||
struct lwp_info;
|
||||
|
@ -942,6 +942,10 @@ handle_qxfer_libraries (const char *annex,
|
||||
if (annex[0] != '\0' || !target_running ())
|
||||
return -1;
|
||||
|
||||
/* Do not confuse this packet with qXfer:libraries-svr4:read. */
|
||||
if (the_target->qxfer_libraries_svr4 != NULL)
|
||||
return 0;
|
||||
|
||||
/* Over-estimate the necessary memory. Assume that every character
|
||||
in the library name must be escaped. */
|
||||
total_len = 64;
|
||||
@ -992,6 +996,23 @@ handle_qxfer_libraries (const char *annex,
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Handle qXfer:libraries-svr4:read. */
|
||||
|
||||
static int
|
||||
handle_qxfer_libraries_svr4 (const char *annex,
|
||||
gdb_byte *readbuf, const gdb_byte *writebuf,
|
||||
ULONGEST offset, LONGEST len)
|
||||
{
|
||||
if (writebuf != NULL)
|
||||
return -2;
|
||||
|
||||
if (annex[0] != '\0' || !target_running ()
|
||||
|| the_target->qxfer_libraries_svr4 == NULL)
|
||||
return -1;
|
||||
|
||||
return the_target->qxfer_libraries_svr4 (annex, readbuf, writebuf, offset, len);
|
||||
}
|
||||
|
||||
/* Handle qXfer:osadata:read. */
|
||||
|
||||
static int
|
||||
@ -1216,6 +1237,7 @@ static const struct qxfer qxfer_packets[] =
|
||||
{ "fdpic", handle_qxfer_fdpic},
|
||||
{ "features", handle_qxfer_features },
|
||||
{ "libraries", handle_qxfer_libraries },
|
||||
{ "libraries-svr4", handle_qxfer_libraries_svr4 },
|
||||
{ "osdata", handle_qxfer_osdata },
|
||||
{ "siginfo", handle_qxfer_siginfo },
|
||||
{ "spu", handle_qxfer_spu },
|
||||
@ -1536,9 +1558,14 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||
|
||||
sprintf (own_buf, "PacketSize=%x;QPassSignals+", PBUFSIZ - 1);
|
||||
|
||||
/* We do not have any hook to indicate whether the target backend
|
||||
supports qXfer:libraries:read, so always report it. */
|
||||
strcat (own_buf, ";qXfer:libraries:read+");
|
||||
if (the_target->qxfer_libraries_svr4 != NULL)
|
||||
strcat (own_buf, ";qXfer:libraries-svr4:read+");
|
||||
else
|
||||
{
|
||||
/* We do not have any hook to indicate whether the non-SVR4 target
|
||||
backend supports qXfer:libraries:read, so always report it. */
|
||||
strcat (own_buf, ";qXfer:libraries:read+");
|
||||
}
|
||||
|
||||
if (the_target->read_auxv != NULL)
|
||||
strcat (own_buf, ";qXfer:auxv:read+");
|
||||
|
@ -390,6 +390,11 @@ struct target_ops
|
||||
/* Return the minimum length of an instruction that can be safely overwritten
|
||||
for use as a fast tracepoint. */
|
||||
int (*get_min_fast_tracepoint_insn_len) (void);
|
||||
|
||||
/* Read solib info on SVR4 platforms. */
|
||||
int (*qxfer_libraries_svr4) (const char *annex, unsigned char *readbuf,
|
||||
unsigned const char *writebuf,
|
||||
CORE_ADDR offset, int len);
|
||||
};
|
||||
|
||||
extern struct target_ops *the_target;
|
||||
|
11
gdb/remote.c
11
gdb/remote.c
@ -1243,6 +1243,7 @@ enum {
|
||||
PACKET_qXfer_auxv,
|
||||
PACKET_qXfer_features,
|
||||
PACKET_qXfer_libraries,
|
||||
PACKET_qXfer_libraries_svr4,
|
||||
PACKET_qXfer_memory_map,
|
||||
PACKET_qXfer_spu_read,
|
||||
PACKET_qXfer_spu_write,
|
||||
@ -3748,6 +3749,8 @@ static struct protocol_feature remote_protocol_features[] = {
|
||||
PACKET_qXfer_features },
|
||||
{ "qXfer:libraries:read", PACKET_DISABLE, remote_supported_packet,
|
||||
PACKET_qXfer_libraries },
|
||||
{ "qXfer:libraries-svr4:read", PACKET_DISABLE, remote_supported_packet,
|
||||
PACKET_qXfer_libraries_svr4 },
|
||||
{ "qXfer:memory-map:read", PACKET_DISABLE, remote_supported_packet,
|
||||
PACKET_qXfer_memory_map },
|
||||
{ "qXfer:spu:read", PACKET_DISABLE, remote_supported_packet,
|
||||
@ -8356,6 +8359,11 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
|
||||
(ops, "libraries", annex, readbuf, offset, len,
|
||||
&remote_protocol_packets[PACKET_qXfer_libraries]);
|
||||
|
||||
case TARGET_OBJECT_LIBRARIES_SVR4:
|
||||
return remote_read_qxfer
|
||||
(ops, "libraries-svr4", annex, readbuf, offset, len,
|
||||
&remote_protocol_packets[PACKET_qXfer_libraries_svr4]);
|
||||
|
||||
case TARGET_OBJECT_MEMORY_MAP:
|
||||
gdb_assert (annex == NULL);
|
||||
return remote_read_qxfer (ops, "memory-map", annex, readbuf, offset, len,
|
||||
@ -11078,6 +11086,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
|
||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_libraries],
|
||||
"qXfer:libraries:read", "library-info", 0);
|
||||
|
||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_libraries_svr4],
|
||||
"qXfer:libraries-svr4:read", "library-info-svr4", 0);
|
||||
|
||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_memory_map],
|
||||
"qXfer:memory-map:read", "memory-map", 0);
|
||||
|
||||
|
180
gdb/solib-svr4.c
180
gdb/solib-svr4.c
@ -949,6 +949,107 @@ open_symbol_file_object (void *from_ttyp)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Data exchange structure for the XML parser as returned by
|
||||
svr4_current_sos_via_xfer_libraries. */
|
||||
|
||||
struct svr4_library_list
|
||||
{
|
||||
struct so_list *head, **tailp;
|
||||
|
||||
/* Inferior address of struct link_map used for the main executable. It is
|
||||
NULL if not known. */
|
||||
CORE_ADDR main_lm;
|
||||
};
|
||||
|
||||
#ifdef HAVE_LIBEXPAT
|
||||
|
||||
#include "xml-support.h"
|
||||
|
||||
/* Handle the start of a <library> element. Note: new elements are added
|
||||
at the tail of the list, keeping the list in order. */
|
||||
|
||||
static void
|
||||
library_list_start_library (struct gdb_xml_parser *parser,
|
||||
const struct gdb_xml_element *element,
|
||||
void *user_data, VEC(gdb_xml_value_s) *attributes)
|
||||
{
|
||||
struct svr4_library_list *list = user_data;
|
||||
const char *name = xml_find_attribute (attributes, "name")->value;
|
||||
ULONGEST *lmp = xml_find_attribute (attributes, "lm")->value;
|
||||
ULONGEST *l_addrp = xml_find_attribute (attributes, "l_addr")->value;
|
||||
ULONGEST *l_ldp = xml_find_attribute (attributes, "l_ld")->value;
|
||||
struct so_list *new_elem;
|
||||
|
||||
new_elem = XZALLOC (struct so_list);
|
||||
new_elem->lm_info = XZALLOC (struct lm_info);
|
||||
new_elem->lm_info->lm_addr = *lmp;
|
||||
new_elem->lm_info->l_addr_inferior = *l_addrp;
|
||||
new_elem->lm_info->l_ld = *l_ldp;
|
||||
|
||||
strncpy (new_elem->so_name, name, sizeof (new_elem->so_name) - 1);
|
||||
new_elem->so_name[sizeof (new_elem->so_name) - 1] = 0;
|
||||
strcpy (new_elem->so_original_name, new_elem->so_name);
|
||||
|
||||
*list->tailp = new_elem;
|
||||
list->tailp = &new_elem->next;
|
||||
}
|
||||
|
||||
/* Handle the start of a <library-list-svr4> element. */
|
||||
|
||||
static void
|
||||
svr4_library_list_start_list (struct gdb_xml_parser *parser,
|
||||
const struct gdb_xml_element *element,
|
||||
void *user_data, VEC(gdb_xml_value_s) *attributes)
|
||||
{
|
||||
struct svr4_library_list *list = user_data;
|
||||
const char *version = xml_find_attribute (attributes, "version")->value;
|
||||
struct gdb_xml_value *main_lm = xml_find_attribute (attributes, "main-lm");
|
||||
|
||||
if (strcmp (version, "1.0") != 0)
|
||||
gdb_xml_error (parser,
|
||||
_("SVR4 Library list has unsupported version \"%s\""),
|
||||
version);
|
||||
|
||||
if (main_lm)
|
||||
list->main_lm = *(ULONGEST *) main_lm->value;
|
||||
}
|
||||
|
||||
/* The allowed elements and attributes for an XML library list.
|
||||
The root element is a <library-list>. */
|
||||
|
||||
static const struct gdb_xml_attribute svr4_library_attributes[] =
|
||||
{
|
||||
{ "name", GDB_XML_AF_NONE, NULL, NULL },
|
||||
{ "lm", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
|
||||
{ "l_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
|
||||
{ "l_ld", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
|
||||
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
static const struct gdb_xml_element svr4_library_list_children[] =
|
||||
{
|
||||
{
|
||||
"library", svr4_library_attributes, NULL,
|
||||
GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
|
||||
library_list_start_library, NULL
|
||||
},
|
||||
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
static const struct gdb_xml_attribute svr4_library_list_attributes[] =
|
||||
{
|
||||
{ "version", GDB_XML_AF_NONE, NULL, NULL },
|
||||
{ "main-lm", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
|
||||
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
static const struct gdb_xml_element svr4_library_list_elements[] =
|
||||
{
|
||||
{ "library-list-svr4", svr4_library_list_attributes, svr4_library_list_children,
|
||||
GDB_XML_EF_NONE, svr4_library_list_start_list, NULL },
|
||||
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
/* Implementation for target_so_ops.free_so. */
|
||||
|
||||
static void
|
||||
@ -973,6 +1074,69 @@ svr4_free_library_list (void *p_list)
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse qXfer:libraries:read packet into *SO_LIST_RETURN. Return 1 if
|
||||
|
||||
Return 0 if packet not supported, *SO_LIST_RETURN is not modified in such
|
||||
case. Return 1 if *SO_LIST_RETURN contains the library list, it may be
|
||||
empty, caller is responsible for freeing all its entries. */
|
||||
|
||||
static int
|
||||
svr4_parse_libraries (const char *document, struct svr4_library_list *list)
|
||||
{
|
||||
struct cleanup *back_to = make_cleanup (svr4_free_library_list,
|
||||
&list->head);
|
||||
|
||||
memset (list, 0, sizeof (*list));
|
||||
list->tailp = &list->head;
|
||||
if (gdb_xml_parse_quick (_("target library list"), "library-list.dtd",
|
||||
svr4_library_list_elements, document, list) == 0)
|
||||
{
|
||||
/* Parsed successfully, keep the result. */
|
||||
discard_cleanups (back_to);
|
||||
return 1;
|
||||
}
|
||||
|
||||
do_cleanups (back_to);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Attempt to get so_list from target via qXfer:libraries:read packet.
|
||||
|
||||
Return 0 if packet not supported, *SO_LIST_RETURN is not modified in such
|
||||
case. Return 1 if *SO_LIST_RETURN contains the library list, it may be
|
||||
empty, caller is responsible for freeing all its entries. */
|
||||
|
||||
static int
|
||||
svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
|
||||
{
|
||||
char *svr4_library_document;
|
||||
int result;
|
||||
struct cleanup *back_to;
|
||||
|
||||
/* Fetch the list of shared libraries. */
|
||||
svr4_library_document = target_read_stralloc (¤t_target,
|
||||
TARGET_OBJECT_LIBRARIES_SVR4,
|
||||
NULL);
|
||||
if (svr4_library_document == NULL)
|
||||
return 0;
|
||||
|
||||
back_to = make_cleanup (xfree, svr4_library_document);
|
||||
result = svr4_parse_libraries (svr4_library_document, list);
|
||||
do_cleanups (back_to);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int
|
||||
svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* If no shared library information is available from the dynamic
|
||||
linker, build a fallback list from other sources. */
|
||||
|
||||
@ -1032,7 +1196,9 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
|
||||
|
||||
if (new->lm_info->l_prev != prev_lm)
|
||||
{
|
||||
warning (_("Corrupted shared library list"));
|
||||
warning (_("Corrupted shared library list: %s != %s"),
|
||||
paddress (target_gdbarch, prev_lm),
|
||||
paddress (target_gdbarch, new->lm_info->l_prev));
|
||||
do_cleanups (old_chain);
|
||||
break;
|
||||
}
|
||||
@ -1093,6 +1259,18 @@ svr4_current_sos (void)
|
||||
struct svr4_info *info;
|
||||
struct cleanup *back_to;
|
||||
int ignore_first;
|
||||
struct svr4_library_list library_list;
|
||||
|
||||
if (svr4_current_sos_via_xfer_libraries (&library_list))
|
||||
{
|
||||
if (library_list.main_lm)
|
||||
{
|
||||
info = get_svr4_info ();
|
||||
info->main_lm_addr = library_list.main_lm;
|
||||
}
|
||||
|
||||
return library_list.head ? library_list.head : svr4_default_sos ();
|
||||
}
|
||||
|
||||
info = get_svr4_info ();
|
||||
|
||||
|
@ -255,6 +255,8 @@ enum target_object
|
||||
TARGET_OBJECT_AVAILABLE_FEATURES,
|
||||
/* Currently loaded libraries, in XML format. */
|
||||
TARGET_OBJECT_LIBRARIES,
|
||||
/* Currently loaded libraries specific for SVR4 systems, in XML format. */
|
||||
TARGET_OBJECT_LIBRARIES_SVR4,
|
||||
/* Get OS specific data. The ANNEX specifies the type (running
|
||||
processes, etc.). The data being transfered is expected to follow
|
||||
the DTD specified in features/osdata.dtd. */
|
||||
|
@ -1,3 +1,8 @@
|
||||
2011-12-02 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
* gdb.base/solib-corrupted.exp: Suppress test on is_remote target.
|
||||
(corrupted list): Adjust the expectation.
|
||||
|
||||
2011-12-02 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
PR threads/13448
|
||||
|
@ -17,6 +17,12 @@ if {[skip_shlib_tests]} {
|
||||
return 0
|
||||
}
|
||||
|
||||
if {[is_remote target]} {
|
||||
# gdbserver prints the warning message but expect is parsing only the GDB
|
||||
# output, not the gdbserver output.
|
||||
return 0
|
||||
}
|
||||
|
||||
set testfile "solib-corrupted"
|
||||
set srcfile start.c
|
||||
|
||||
@ -47,4 +53,4 @@ gdb_test_multiple "p/x _r_debug->r_map->l_next = _r_debug->r_map" $test {
|
||||
pass $test
|
||||
}
|
||||
}
|
||||
gdb_test "info sharedlibrary" "warning: Corrupted shared library list\r\n.*" "corrupted list"
|
||||
gdb_test "info sharedlibrary" "warning: Corrupted shared library list: .*" "corrupted list"
|
||||
|
Loading…
Reference in New Issue
Block a user