* 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:
Jan Kratochvil 2011-12-02 22:26:54 +00:00
parent 1b31d05e6b
commit 2268b414f4
15 changed files with 764 additions and 7 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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>

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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+");

View File

@ -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;

View File

@ -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);

View File

@ -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 (&current_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 ();

View File

@ -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. */

View File

@ -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

View File

@ -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"