[rfc] Shared libraries over the remote protocol, take two

Daniel Jacobowitz
2007-06-18T15:02:14Z

Here is a new attempt at remote shared library events. The major
protocol changes since last time are the elimination of load/unload
events (just query the whole list again), the use of target objects
(so that this can be used more easily for other targets, like AIX)
, and the use XML (because I had to both escape the entire message
and then the library name - my rule of thumb is that when I need to
invent a new way to escape special characters, I should probably use
XML, since it offers a standard way to do that "for free").

I have tested this on native Windows and using a Windows gdbserver,
both with the patch coming up next. It seems to work fine. It's also
much simpler to explain how it works, and about half the lines of code
of the previous version.

--
Daniel Jacobowitz
CodeSourcery

2007-05-09 Daniel Jacobowitz <dan@codesourcery.com>

* Makefile.in (XMLFILES): Add library-list.dtd.
(ALLDEPFILES): Add solib-target.o.
(solib-target.o): New rule.
* remote.c (PACKET_qXfer_libraries): New constant.
(remote_protocol_features): Add qXfer:libraries:read.
(remote_wait): Recognize library stop replies.
(remote_async_wait): Likewise. Fix typo.
(remote_xfer_partial): Handle TARGET_OBJECT_LIBRARIES.
(init_remote_async_ops): Fix typo.
(_initialize_remote): Register "set remote library-info-packet".
* solib-som.c (som_current_sos): Set addr_low and addr_high.
* solib-target.c: New file.
* solib.c (solib_map_sections): Use addr_low and addr_high instead
of textsection.
(info_sharedlibrary_command): Likewise.
(solib_add_library, solib_remove_library): New.
* solist.h (struct so_list): Replace textsection with addr_low and
addr_high.
* target.h (enum target_object): Add TARGET_OBJECT_LIBRARIES.
* NEWS: Describe new qXfer:libraries:read and shared library
event support.
* features/library-list.dtd: New.

* gdb.texinfo (Remote Configuration): Document library-info-packet.
Add other missing entries. Adjust the table size to fit.
(Stop Reply Packets): Use @itemize instead of @enumerate. Document
stop reasons including the new "library" event.
(General Query Packets): Adjust table widths for qSupported. Mention
qXfer:libraries:read reply to qSupported and document the new packet.
(Library List Format): New section.

---
gdb/Makefile.in | 5
gdb/NEWS | 12 +
gdb/doc/gdb.texinfo | 153 ++++++++++++++--
gdb/features/library-list.dtd | 15 +
gdb/remote.c | 59 +++++-
gdb/solib-som.c | 3
gdb/solib-target.c | 388 ++++++++++++++++++++++++++++++++++++++++++
gdb/solib.c | 18 +
gdb/solist.h | 6
gdb/target.h | 4
10 files changed, 626 insertions(+), 37 deletions(-)

Index: gdb/Makefile.in
===================================================================
--- gdb/Makefile.in.orig 2007-06-18 10:15:05.000000000 -0400
+++ gdb/Makefile.in 2007-06-18 10:22:28.000000000 -0400
@@ -403,6 +403,7 @@ RUNTESTFLAGS=

# XML files to build in to GDB.
XMLFILES = $(srcdir)/features/gdb-target.dtd $(srcdir)/features/xinclude.dtd \
+ $(srcdir)/features/library-list.dtd \
$(TDEP_XML)

# This is ser-unix.o for any system which supports a v7/BSD/SYSV/POSIX
@@ -1471,6 +1472,7 @@ ALLDEPFILES = \
mips64obsd-nat.c mips64obsd-tdep.c \
nbsd-nat.c nbsd-tdep.c obsd-tdep.c \
solib-osf.c \
+ solib-target.c \
somread.c solib-som.c \
posix-hdep.c \
ppc-sysv-tdep.c ppc-linux-nat.c ppc-linux-tdep.c \
@@ -2594,6 +2596,9 @@ solib-svr4.o: solib-svr4.c $(defs_h) $(e
$(gdbcore_h) $(target_h) $(inferior_h) $(gdb_assert_h) \
$(solist_h) $(solib_h) $(solib_svr4_h) $(bfd_target_h) $(elf_bfd_h) \
$(exec_h)
+solib-target.o: solib-target.c $(defs_h) $(objfiles_h) $(solist_h) \
+ $(symtab_h) $(symfile_h) $(target_h) $(vec_h) $(xml_support_h) \
+ $(gdb_string_h)
sol-thread.o: sol-thread.c $(defs_h) $(gdbthread_h) $(target_h) \
$(inferior_h) $(gdb_stat_h) $(gdbcmd_h) $(gdbcore_h) $(regcache_h) \
$(solib_h) $(symfile_h) $(observer_h) $(gdb_string_h) $(gregset_h)
Index: gdb/remote.c
===================================================================
--- gdb/remote.c.orig 2007-06-18 10:15:05.000000000 -0400
+++ gdb/remote.c 2007-06-18 10:15:14.000000000 -0400
@@ -907,6 +907,7 @@ enum {
PACKET_Z4,
PACKET_qXfer_auxv,
PACKET_qXfer_features,
+ PACKET_qXfer_libraries,
PACKET_qXfer_memory_map,
PACKET_qXfer_spu_read,
PACKET_qXfer_spu_write,
@@ -2378,6 +2379,8 @@ static struct protocol_feature remote_pr
PACKET_qXfer_auxv },
{ "qXfer:features:read", PACKET_DISABLE, remote_supported_packet,
PACKET_qXfer_features },
+ { "qXfer:libraries:read", PACKET_DISABLE, remote_supported_packet,
+ PACKET_qXfer_libraries },
{ "qXfer:memory-map:read", PACKET_DISABLE, remote_supported_packet,
PACKET_qXfer_memory_map },
{ "QPassSignals", PACKET_DISABLE, remote_supported_packet,
@@ -3179,6 +3182,7 @@ remote_wait (ptid_t ptid, struct target_
struct remote_arch_state *rsa = get_remote_arch_state ();
ULONGEST thread_num = -1;
ULONGEST addr;
+ int solibs_changed = 0;

status->kind = TARGET_WAITKIND_EXITED;
status->value.integer = 0;
@@ -3264,6 +3268,16 @@ Packet: '%s'\n"),
p = unpack_varlen_hex (++p1, &addr);
remote_watch_data_address = (CORE_ADDR)addr;
}
+ else if (strncmp (p, "library", p1 - p) == 0)
+ {
+ p1++;
+ p_temp = p1;
+ while (*p_temp && *p_temp != ';')
+ p_temp++;
+
+ solibs_changed = 1;
+ p = p_temp;
+ }
else
{
/* Silently skip unknown optional info. */
@@ -3305,9 +3319,14 @@ Packet: '%s'\n"),
}
/* fall through */
case 'S': /* Old style status, just signal only. */
- status->kind = TARGET_WAITKIND_STOPPED;
- status->value.sig = (enum target_signal)
- (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
+ if (solibs_changed)
+ status->kind = TARGET_WAITKIND_LOADED;
+ else
+ {
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = (enum target_signal)
+ (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
+ }

if (buf[3] == 'p')
{
@@ -3370,6 +3389,7 @@ remote_async_wait (ptid_t ptid, struct t
struct remote_arch_state *rsa = get_remote_arch_state ();
ULONGEST thread_num = -1;
ULONGEST addr;
+ int solibs_changed = 0;

status->kind = TARGET_WAITKIND_EXITED;
status->value.integer = 0;
@@ -3431,7 +3451,7 @@ remote_async_wait (ptid_t ptid, struct t
/* If this packet is an awatch packet, don't parse the 'a'
as a register number. */

- if (!strncmp (p, "awatch", strlen ("awatch")) != 0)
+ if (strncmp (p, "awatch", strlen("awatch")) != 0)
{
/* Read the register number. */
pnum = strtol (p, &p_temp, 16);
@@ -3461,6 +3481,16 @@ Packet: '%s'\n"),
p = unpack_varlen_hex (++p1, &addr);
remote_watch_data_address = (CORE_ADDR)addr;
}
+ else if (strncmp (p, "library", p1 - p) == 0)
+ {
+ p1++;
+ p_temp = p1;
+ while (*p_temp && *p_temp != ';')
+ p_temp++;
+
+ solibs_changed = 1;
+ p = p_temp;
+ }
else
{
/* Silently skip unknown optional info. */
@@ -3501,9 +3531,14 @@ Packet: '%s'\n"),
}
/* fall through */
case 'S': /* Old style status, just signal only. */
- status->kind = TARGET_WAITKIND_STOPPED;
- status->value.sig = (enum target_signal)
- (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
+ if (solibs_changed)
+ status->kind = TARGET_WAITKIND_LOADED;
+ else
+ {
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = (enum target_signal)
+ (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
+ }

if (buf[3] == 'p')
{
@@ -5789,6 +5824,11 @@ remote_xfer_partial (struct target_ops *
(ops, "features", annex, readbuf, offset, len,
&remote_protocol_packets[PACKET_qXfer_features]);

+ case TARGET_OBJECT_LIBRARIES:
+ return remote_read_qxfer
+ (ops, "libraries", annex, readbuf, offset, len,
+ &remote_protocol_packets[PACKET_qXfer_libraries]);
+
case TARGET_OBJECT_MEMORY_MAP:
gdb_assert (annex == NULL);
return remote_read_qxfer (ops, "memory-map", annex, readbuf, offset, len,
@@ -6406,7 +6446,7 @@ Specify the serial device it is connecte
remote_async_ops.to_memory_map = remote_memory_map;
remote_async_ops.to_flash_erase = remote_flash_erase;
remote_async_ops.to_flash_done = remote_flash_done;
- remote_ops.to_read_description = remote_read_description;
+ remote_async_ops.to_read_description = remote_read_description;
}

/* Set up the async extended remote vector by making a copy of the standard
@@ -6656,6 +6696,9 @@ Show the maximum size of the address (in
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_features],
"qXfer:features:read", "target-features", 0);

+ 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_memory_map],
"qXfer:memory-map:read", "memory-map", 0);

Index: gdb/solib-som.c
===================================================================
--- gdb/solib-som.c.orig 2007-06-18 10:15:05.000000000 -0400
+++ gdb/solib-som.c 2007-06-18 10:15:14.000000000 -0400
@@ -623,6 +623,9 @@ som_current_sos (void)
paddr_nz (new->lm_info->tsd_start_addr));
#endif

+ new->addr_low = lmi->text_addr;
+ new->addr_high = lmi->text_end;
+
/* Link the new object onto the list. */
new->next = NULL;
*link_ptr = new;
Index: gdb/solib-target.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb/solib-target.c 2007-06-18 10:15:14.000000000 -0400
@@ -0,0 +1,388 @@
+/* Definitions for targets which report shared library events.
+
+ Copyright (C) 2007
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#include "defs.h"
+#include "objfiles.h"
+#include "solist.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "target.h"
+#include "vec.h"
+
+#include "gdb_string.h"
+
+/* Private data for each loaded library. */
+struct lm_info
+{
+ /* The library's name. The name is normally kept in the struct
+ so_list; it is only here during XML parsing. */
+ char *name;
+
+ /* The number of entries in SEGMENT_BASES. */
+ int num_bases;
+
+ /* The base addresses for each independently relocatable segment of
+ this shared library. */
+ CORE_ADDR *segment_bases;
+
+ /* The cached offsets for each section of this shared library,
+ determined from SEGMENT_BASES. */
+ struct section_offsets *offsets;
+};
+
+typedef struct lm_info *lm_info_p;
+DEF_VEC_P(lm_info_p);
+
+#if !defined(HAVE_LIBEXPAT)
+
+static VEC(lm_info_p)
+solib_target_parse_libraries (const char *library)
+{
+ static int have_warned;
+
+ if (!have_warned)
+ {
+ have_warned = 1;
+ warning (_("Can not parse XML library list; XML support was disabled "
+ "at compile time"));
+ }
+
+ return NULL;
+}
+
+#else /* HAVE_LIBEXPAT */
+
+#include "xml-support.h"
+
+/* Handle the start of a <segment> element. */
+
+static void
+library_list_start_segment (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data, VEC(gdb_xml_value_s) *attributes)
+{
+ VEC(lm_info_p) **list = user_data;
+ struct lm_info *last = VEC_last (lm_info_p, *list);
+ ULONGEST *address_p = VEC_index (gdb_xml_value_s, attributes, 0)->value;
+
+ last->num_bases++;
+ last->segment_bases = xrealloc (last->segment_bases,
+ last->num_bases * sizeof (CORE_ADDR));
+ last->segment_bases[last->num_bases - 1] = *address_p;
+}
+
+/* Handle the start of a <library> element. */
+
+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)
+{
+ VEC(lm_info_p) **list = user_data;
+ struct lm_info *item = XZALLOC (struct lm_info);
+ const char *name = VEC_index (gdb_xml_value_s, attributes, 0)->value;
+
+ item->name = xstrdup (name);
+ VEC_safe_push (lm_info_p, *list, item);
+}
+
+/* Handle the start of a <library-list> element. */
+
+static void
+library_list_start_list (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data, VEC(gdb_xml_value_s) *attributes)
+{
+ char *version = VEC_index (gdb_xml_value_s, attributes, 0)->value;
+
+ if (strcmp (version, "1.0") != 0)
+ gdb_xml_error (parser,
+ _("Library list has unsupported version \"%s\""),
+ version);
+}
+
+/* Discard the constructed library list. */
+
+static void
+solib_target_free_library_list (void *p)
+{
+ VEC(lm_info_p) **result = p;
+ struct lm_info *info;
+ int ix;
+
+ for (ix = 0; VEC_iterate (lm_info_p, *result, ix, info); ix++)
+ {
+ xfree (info->name);
+ xfree (info->segment_bases);
+ xfree (info);
+ }
+ VEC_free (lm_info_p, *result);
+ *result = NULL;
+}
+
+/* The allowed elements and attributes for an XML library list.
+ The root element is a <library-list>. */
+
+const struct gdb_xml_attribute segment_attributes[] = {
+ { "address", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+const struct gdb_xml_element library_children[] = {
+ { "segment", segment_attributes, NULL, GDB_XML_EF_REPEATABLE,
+ library_list_start_segment, NULL },
+ { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+const struct gdb_xml_attribute library_attributes[] = {
+ { "name", GDB_XML_AF_NONE, NULL, NULL },
+ { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+const struct gdb_xml_element library_list_children[] = {
+ { "library", library_attributes, library_children,
+ GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
+ library_list_start_library, NULL },
+ { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+const struct gdb_xml_attribute library_list_attributes[] = {
+ { "version", GDB_XML_AF_NONE, NULL, NULL },
+ { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+const struct gdb_xml_element library_list_elements[] = {
+ { "library-list", library_list_attributes, library_list_children,
+ GDB_XML_EF_NONE, library_list_start_list, NULL },
+ { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+static VEC(lm_info_p) *
+solib_target_parse_libraries (const char *library)
+{
+ struct gdb_xml_parser *parser;
+ VEC(lm_info_p) *result = NULL;
+ struct cleanup *before_deleting_result, *back_to;
+
+ back_to = make_cleanup (null_cleanup, NULL);
+ parser = gdb_xml_create_parser_and_cleanup (_("target library list"),
+ library_list_elements, &result);
+ gdb_xml_use_dtd (parser, "library-list.dtd");
+
+ before_deleting_result = make_cleanup (solib_target_free_library_list,
+ &result);
+
+ if (gdb_xml_parse (parser, library) == 0)
+ /* Parsed successfully, don't need to delete the result. */
+ discard_cleanups (before_deleting_result);
+
+ do_cleanups (back_to);
+ return result;
+}
+#endif
+
+static struct so_list *
+solib_target_current_sos (void)
+{
+ struct so_list *new_solib, *start = NULL, *last = NULL;
+ const char *library_document;
+ VEC(lm_info_p) *library_list;
+ struct lm_info *info;
+ int ix;
+
+ /* Fetch the list of shared libraries. */
+ library_document = target_read_stralloc (&current_target,
+ TARGET_OBJECT_LIBRARIES,
+ NULL);
+ if (library_document == NULL)
+ return NULL;
+
+ /* Parse the list. */
+ library_list = solib_target_parse_libraries (library_document);
+ if (library_list == NULL)
+ return NULL;
+
+ /* Build a struct so_list for each entry on the list. */
+ for (ix = 0; VEC_iterate (lm_info_p, library_list, ix, info); ix++)
+ {
+ new_solib = XZALLOC (struct so_list);
+ strncpy (new_solib->so_name, info->name, SO_NAME_MAX_PATH_SIZE - 1);
+ new_solib->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+ strncpy (new_solib->so_original_name, info->name,
+ SO_NAME_MAX_PATH_SIZE - 1);
+ new_solib->so_original_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+ new_solib->lm_info = info;
+
+ /* We no longer need this copy of the name. */
+ xfree (info->name);
+ info->name = NULL;
+
+ /* Add it to the list. */
+ if (!start)
+ last = start = new_solib;
+ else
+ {
+ last->next = new_solib;
+ last = new_solib;
+ }
+ }
+
+ /* Free the library list, but not its members. */
+ VEC_free (lm_info_p, library_list);
+
+ return start;
+}
+
+static void
+solib_target_special_symbol_handling (void)
+{
+ /* Nothing needed. */
+}
+
+static void
+solib_target_solib_create_inferior_hook (void)
+{
+ /* Nothing needed. */
+}
+
+static void
+solib_target_clear_solib (void)
+{
+ /* Nothing needed. */
+}
+
+static void
+solib_target_free_so (struct so_list *so)
+{
+ gdb_assert (so->lm_info->name == NULL);
+ xfree (so->lm_info->offsets);
+ xfree (so->lm_info->segment_bases);
+ xfree (so->lm_info);
+}
+
+static void
+solib_target_relocate_section_addresses (struct so_list *so,
+ struct section_table *sec)
+{
+ int flags = bfd_get_section_flags (sec->bfd, sec->the_bfd_section);
+ CORE_ADDR offset;
+
+ /* Build the offset table only once per object file. We can not do
+ it any earlier, since we need to open the file first. */
+ if (so->lm_info->offsets == NULL)
+ {
+ struct symfile_segment_data *data;
+ int num_sections = bfd_count_sections (so->abfd);
+
+ so->lm_info->offsets = xzalloc (SIZEOF_N_SECTION_OFFSETS (num_sections));
+
+ data = get_symfile_segment_data (so->abfd);
+ if (data == NULL)
+ warning (_("Could not relocate shared library \"%s\": no segments"),
+ so->so_name);
+ else
+ {
+ ULONGEST orig_delta;
+ int i;
+
+ if (!symfile_map_offsets_to_segments (so->abfd, data,
+ so->lm_info->offsets,
+ so->lm_info->num_bases,
+ so->lm_info->segment_bases))
+ warning (_("Could not relocate shared library \"%s\": bad offsets"),
+ so->so_name);
+
+ /* Find the range of addresses to report for this library in
+ "info sharedlibrary". Report any consecutive segments
+ which were relocated as a single unit. */
+ gdb_assert (so->lm_info->num_bases > 0);
+ orig_delta = so->lm_info->segment_bases[0] - data->segment_bases[0];
+
+ for (i = 1; i < data->num_segments; i++)
+ {
+ ULONGEST delta;
+
+ /* If we have run out of offsets, assume all remaining segments
+ have the same offset. */
+ if (i >= so->lm_info->num_bases)
+ continue;
+
+ /* If this segment does not have the same offset, do not include
+ it in the library's range. */
+ delta = so->lm_info->segment_bases[i] - data->segment_bases[i];
+ if (delta != orig_delta)
+ break;
+ }
+
+ so->addr_low = so->lm_info->segment_bases[0];
+ so->addr_high = (data->segment_bases[i - 1]
+ + data->segment_sizes[i - 1]);
+
+ free_symfile_segment_data (data);
+ }
+ }
+
+ offset = so->lm_info->offsets->offsets[sec->the_bfd_section->index];
+ sec->addr += offset;
+ sec->endaddr += offset;
+}
+
+static int
+solib_target_open_symbol_file_object (void *from_ttyp)
+{
+ /* We can't locate the main symbol file based on the target's
+ knowledge; the user has to specify it. */
+ return 0;
+}
+
+static int
+solib_target_in_dynsym_resolve_code (CORE_ADDR pc)
+{
+ /* We don't have a range of addresses for the dynamic linker; there
+ may not be one in the program's address space. So only report
+ PLT entries (which may be import stubs). */
+ return in_plt_section (pc, NULL);
+}
+
+static struct target_so_ops solib_target_so_ops;
+
+extern initialize_file_ftype _initialize_solib_target; /* -Wmissing-prototypes */
+
+void
+_initialize_solib_target (void)
+{
+ solib_target_so_ops.relocate_section_addresses
+ = solib_target_relocate_section_addresses;
+ solib_target_so_ops.free_so = solib_target_free_so;
+ solib_target_so_ops.clear_solib = solib_target_clear_solib;
+ solib_target_so_ops.solib_create_inferior_hook
+ = solib_target_solib_create_inferior_hook;
+ solib_target_so_ops.special_symbol_handling
+ = solib_target_special_symbol_handling;
+ solib_target_so_ops.current_sos = solib_target_current_sos;
+ solib_target_so_ops.open_symbol_file_object
+ = solib_target_open_symbol_file_object;
+ solib_target_so_ops.in_dynsym_resolve_code
+ = solib_target_in_dynsym_resolve_code;
+
+ current_target_so_ops = &solib_target_so_ops;
+}
Index: gdb/solib.c
===================================================================
--- gdb/solib.c.orig 2007-06-18 10:15:05.000000000 -0400
+++ gdb/solib.c 2007-06-18 10:15:14.000000000 -0400
@@ -316,9 +316,15 @@ solib_map_sections (void *arg)
object's file by the base address to which the object was actually
mapped. */
ops->relocate_section_addresses (so, p);
- if (strcmp (p->the_bfd_section->name, ".text") == 0)
+
+ /* If the target didn't provide information about the address
+ range of the shared object, assume we want the location of
+ the .text section. */
+ if (so->addr_low == 0 && so->addr_high == 0
+ && strcmp (p->the_bfd_section->name, ".text") == 0)
{
- so->textsection = p;
+ so->addr_low = p->addr;
+ so->addr_high = p->endaddr;
}
}

@@ -742,15 +748,15 @@ info_sharedlibrary_command (char *ignore
}

printf_unfiltered ("%-*s", addr_width,
- so->textsection != NULL
+ so->addr_high != 0
? hex_string_custom (
- (LONGEST) so->textsection->addr,
+ (LONGEST) so->addr_low,
addr_width - 4)
: "");
printf_unfiltered ("%-*s", addr_width,
- so->textsection != NULL
+ so->addr_high != 0
? hex_string_custom (
- (LONGEST) so->textsection->endaddr,
+ (LONGEST) so->addr_high,
addr_width - 4)
: "");
printf_unfiltered ("%-12s", so->symbols_loaded ? "Yes" : "No");
Index: gdb/solist.h
===================================================================
--- gdb/solist.h.orig 2007-06-18 10:15:05.000000000 -0400
+++ gdb/solist.h 2007-06-18 10:15:14.000000000 -0400
@@ -64,7 +64,11 @@ struct so_list
struct objfile *objfile; /* objfile for loaded lib */
struct section_table *sections;
struct section_table *sections_end;
- struct section_table *textsection;
+
+ /* Record the range of addresses belonging to this shared library.
+ There may not be just one (e.g. if two segments are relocated
+ differently); but this is only used for "info sharedlibrary". */
+ CORE_ADDR addr_low, addr_high;
};

struct target_so_ops
Index: gdb/target.h
===================================================================
--- gdb/target.h.orig 2007-06-18 10:15:05.000000000 -0400
+++ gdb/target.h 2007-06-18 10:15:14.000000000 -0400
@@ -212,7 +212,9 @@ enum target_object
TARGET_OBJECT_FLASH,
/* Available target-specific features, e.g. registers and coprocessors.
See "target-descriptions.c". ANNEX should never be empty. */
- TARGET_OBJECT_AVAILABLE_FEATURES
+ TARGET_OBJECT_AVAILABLE_FEATURES,
+ /* Currently loaded libraries, in XML format. */
+ TARGET_OBJECT_LIBRARIES
/* Possible future objects: TARGET_OBJECT_FILE, TARGET_OBJECT_PROC, ... */
};

Index: gdb/NEWS
===================================================================
--- gdb/NEWS.orig 2007-06-18 10:15:05.000000000 -0400
+++ gdb/NEWS 2007-06-18 10:15:14.000000000 -0400
@@ -41,6 +41,12 @@ has been rewritten to use the standard G
layout. It also supports a TextSeg= and DataSeg= response when only
segment base addresses (rather than offsets) are available.

+* The GDB remote protocol "T" stop reply packet now supports a
+"library" response. Combined with the new "qXfer:libraries:read"
+packet, this response allows GDB to debug shared libraries on targets
+where the operating system manages the list of loaded libraries (e.g.
+Windows and SymbianOS).
+
* New commands

set remoteflow
@@ -104,6 +110,12 @@ qXfer:features:read:
Read an XML target description from the target, which describes its
features.

+qXfer:libraries:read:
+ Report the loaded shared libraries. Combined with new "T" packet
+ response, this packet allows GDB to debug shared libraries on
+ targets where the operating system manages the list of loaded
+ libraries (e.g. Windows and SymbianOS).
+
* Removed targets

Support for these obsolete configurations has been removed.
Index: gdb/doc/gdb.texinfo
===================================================================
--- gdb/doc/gdb.texinfo.orig 2007-06-18 10:15:05.000000000 -0400
+++ gdb/doc/gdb.texinfo 2007-06-18 10:15:14.000000000 -0400
@@ -12856,58 +12856,80 @@ If you do, that may be a bug in your rem
in @value{GDBN}. You may want to report the problem to the
@value{GDBN} developers.

-The available settings are:
+For each packet @var{name}, the command to enable or disable the
+packet is @code{set remote @var{name}-packet}. The available settings
+are:

-@multitable @columnfractions 0.3 0.2 0.35
+@multitable @columnfractions 0.28 0.32 0.25
@item Command Name
@tab Remote Packet
@tab Related Features

-@item @code{fetch-register-packet}
+@item @code{fetch-register}
@tab @code{p}
@tab @code{info registers}

-@item @code{set-register-packet}
+@item @code{set-register}
@tab @code{P}
@tab @code{set}

-@item @code{binary-download-packet}
+@item @code{binary-download}
@tab @code{X}
@tab @code{load}, @code{set}

-@item @code{read-aux-vector-packet}
+@item @code{read-aux-vector}
@tab @code{qXfer:auxv:read}
@tab @code{info auxv}

-@item @code{symbol-lookup-packet}
+@item @code{symbol-lookup}
@tab @code{qSymbol}
@tab Detecting multiple threads

-@item @code{verbose-resume-packet}
+@item @code{verbose-resume}
@tab @code{vCont}
@tab Stepping or resuming multiple threads

-@item @code{software-breakpoint-packet}
+@item @code{software-breakpoint}
@tab @code{Z0}
@tab @code{break}

-@item @code{hardware-breakpoint-packet}
+@item @code{hardware-breakpoint}
@tab @code{Z1}
@tab @code{hbreak}

-@item @code{write-watchpoint-packet}
+@item @code{write-watchpoint}
@tab @code{Z2}
@tab @code{watch}

-@item @code{read-watchpoint-packet}
+@item @code{read-watchpoint}
@tab @code{Z3}
@tab @code{rwatch}

-@item @code{access-watchpoint-packet}
+@item @code{access-watchpoint}
@tab @code{Z4}
@tab @code{awatch}

-@item @code{get-thread-local-storage-address-packet}
+@item @code{target-features}
+@tab @code{qXfer:features:read}
+@tab @code{set architecture}
+
+@item @code{library-info}
+@tab @code{qXfer:libraries:read}
+@tab @code{info sharedlibrary}
+
+@item @code{memory-map}
+@tab @code{qXfer:memory-map:read}
+@tab @code{info mem}
+
+@item @code{read-spu-object}
+@tab @code{qXfer:spu:read}
+@tab @code{info spu}
+
+@item @code{write-spu-object}
+@tab @code{qXfer:spu:write}
+@tab @code{info spu}
+
+@item @code{get-thread-local-@*storage-address}
@tab @code{qGetTLSAddr}
@tab Displaying @code{__thread} variables

@@ -12915,7 +12937,7 @@ The available settings are:
@tab @code{qSupported}
@tab Remote communications parameters

-@item @code{pass-signals-packet}
+@item @code{pass-signals}
@tab @code{QPassSignals}
@tab @code{handle @var{signal}}

@@ -22503,6 +22525,7 @@ Show the current setting of the target w
* Interrupts::
* Examples::
* File-I/O Remote Protocol Extension::
+* Library List Format::
* Memory Map Format::
@end menu

@@ -23220,24 +23243,45 @@ number). This is equivalent to an @samp
and other information directly in the stop reply packet, reducing
round-trip latency. Single-step and breakpoint traps are reported
this way. Each @samp{@var{n}:@var{r}} pair is interpreted as follows:
-@enumerate
+
+@itemize @bullet
@item
If @var{n} is a hexadecimal number, it is a register number, and the
corresponding @var{r} gives that register's value. @var{r} is a
series of bytes in target byte order, with each byte given by a
two-digit hex number.
+
@item
If @var{n} is @samp{thread}, then @var{r} is the thread process ID, in
hex.
+
@item
-If @var{n} is @samp{watch}, @samp{rwatch}, or @samp{awatch}, then the
-packet indicates a watchpoint hit, and @var{r} is the data address, in
-hex.
+If @var{n} is a recognized @dfn{stop reason}, it describes a more
+specific event that stopped the target. The currently defined stop
+reasons are listed below. @var{aa} should be @samp{05}, the trap
+signal. At most one stop reason should be present.
+
@item
Otherwise, @value{GDBN} should ignore this @samp{@var{n}:@var{r}} pair
and go on to the next; this allows us to extend the protocol in the
future.
-@end enumerate
+@end itemize
+
+The currently defined stop reasons are:
+
+@itemize @bullet
+@item
+If @var{n} is @samp{watch}, @samp{rwatch}, or @samp{awatch}, then the
+packet indicates a watchpoint hit, and @var{r} is the data address, in
+hex.
+
+@item
+@cindex shared library events, remote reply
+If @var{n} is @samp{library}, then the packet indicates that the
+loaded libraries have changed. @value{GDBN} should use
+@samp{qXfer:libraries:read} to fetch a new list of loaded libraries.
+@var{r} is ignored.
+@end itemize

@item W @var{AA}
The process exited, and @var{AA} is the exit status. This is only
@@ -23623,7 +23667,7 @@ stubs which may be configured for multip

These are the currently defined stub features and their properties:

-@multitable @columnfractions 0.25 0.2 0.2 0.2
+@multitable @columnfractions 0.35 0.2 0.12 0.2
@c NOTE: The first row should be @headitem, but we do not yet require
@c a new enough version of Texinfo (4.7) to use @headitem.
@item Feature Name
@@ -23646,6 +23690,11 @@ These are the currently defined stub fea
@tab @samp{-}
@tab Yes

+@item @samp{qXfer:libraries:read}
+@tab No
+@tab @samp{-}
+@tab Yes
+
@item @samp{qXfer:memory-map:read}
@tab No
@tab @samp{-}
@@ -23690,6 +23739,10 @@ The remote stub understands the @samp{qX
The remote stub understands the @samp{qXfer:features:read} packet
(@pxref{qXfer target description read}).

+@item qXfer:libraries:read
+The remote stub understands the @samp{qXfer:libraries:read} packet
+(@pxref{qXfer library list read}).
+
@item qXfer:memory-map:read
The remote stub understands the @samp{qXfer:memory-map:read} packet
(@pxref{qXfer memory map read}).
@@ -23812,6 +23865,19 @@ always loaded from the @samp{target.xml}
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:read:@var{annex}:@var{offset},@var{length}
+@anchor{qXfer library list read}
+Access the target's list of loaded libraries. @xref{Library List Format}.
+The annex part of the generic @samp{qXfer} packet must be empty
+(@pxref{qXfer read}).
+
+Targets which maintain a list of libraries in the program's memory do
+not need to implement this packet; it is designed for platforms where
+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:memory-map:read::@var{offset},@var{length}
@anchor{qXfer memory map read}
Access the target's @dfn{memory-map}. @xref{Memory Map Format}. The
@@ -25328,6 +25394,51 @@ host is called:
<- @code{T02}
@end smallexample

+@node Library List Format
+@section Library List Format
+@cindex library list format, remote protocol
+
+On some platforms, a dynamic loader (e.g.@: @file{ld.so}) runs in the
+same process as your application to manage libraries. In this case,
+@value{GDBN} can use the loader's symbol table and normal memory
+operations to maintain a list of shared libraries. On other
+platforms, the operating system manages loaded libraries.
+@value{GDBN} can not retrieve the list of currently loaded libraries
+through memory operations, so it uses the @samp{qXfer:libraries:read}
+packet (@pxref{qXfer library list read}) instead. The remote stub
+queries the target's operating system and reports which libraries
+are loaded.
+
+The @samp{qXfer:libraries:read} packet returns an XML document which
+lists loaded libraries and their offsets. Each library has an
+associated name and one or more segment base addresses, which report
+where the library was loaded in memory. The segment bases are start
+addresses, not relocation offsets; they do not depend on the library's
+link-time base addresses.
+
+A simple memory map, with one loaded library relocated by a single
+offset, looks like this:
+
+@smallexample
+<library-list>
+ <library name="/lib/libc.so.6">
+ <segment address="0x10000000"/>
+ </library>
+</library-list>
+@end smallexample
+
+The format of a library list is described by this DTD:
+
+@smallexample
+
+<!ELEMENT library-list (library)*>
+<!ATTLIST library-list version CDATA #FIXED "1.0">
+<!ELEMENT library (segment)*>
+<!ATTLIST library name CDATA #REQUIRED>
+<!ELEMENT segment EMPTY>
+<!ATTLIST segment address CDATA #REQUIRED>
+@end smallexample
+
@node Memory Map Format
@section Memory Map Format
@cindex memory map format
Index: gdb/features/library-list.dtd
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb/features/library-list.dtd 2007-06-15 18:08:54.000000000 -0400
@@ -0,0 +1,15 @@
+<!-- Copyright (C) 2007 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. -->
+
+
+<!ELEMENT library-list (library)*>
+<!ATTLIST library-list version CDATA #FIXED "1.0">
+
+<!ELEMENT library (segment)*>
+<!ATTLIST library name CDATA #REQUIRED>
+
+<!ELEMENT segment EMPTY>
+<!ATTLIST segment address CDATA #REQUIRED>