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

Daniel Jacobowitz
2007-07-02T22:01:50Z

On Mon, Jun 18, 2007 at 11:02:11AM -0400, Daniel Jacobowitz wrote:
> 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 checked this in.

--
Daniel Jacobowitz
CodeSourcery

2007-07-02 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.

2007-07-02 Daniel Jacobowitz <dan@codesourcery.com>

* 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 | 384 ++++++++++++++++++++++++++++++++++++++++++
gdb/solib.c | 18 +
gdb/solist.h | 6
gdb/target.h | 4
10 files changed, 622 insertions(+), 37 deletions(-)

Index: gdb/Makefile.in
===================================================================
--- gdb/Makefile.in.orig 2007-07-02 14:56:41.000000000 -0400
+++ gdb/Makefile.in 2007-07-02 15:16:42.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 \
@@ -2596,6 +2598,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-07-02 14:56:51.000000000 -0400
+++ gdb/remote.c 2007-07-02 14:58:13.000000000 -0400
@@ -905,6 +905,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,
@@ -2376,6 +2377,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 },
{ "qXfer:spu:read", PACKET_DISABLE, remote_supported_packet,
@@ -3181,6 +3184,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;
@@ -3266,6 +3270,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. */
@@ -3307,9 +3321,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')
{
@@ -3372,6 +3391,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;
@@ -3433,7 +3453,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);
@@ -3463,6 +3483,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. */
@@ -3504,9 +3534,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')
{
@@ -5799,6 +5834,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,
@@ -6416,7 +6456,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-07-02 14:56:17.000000000 -0400
+++ gdb/solib-som.c 2007-07-02 14:58:13.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-07-02 15:17:02.000000000 -0400
@@ -0,0 +1,384 @@
+/* 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"
+
+DEF_VEC_O(CORE_ADDR);
+
+/* 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 base addresses for each independently relocatable segment of
+ this shared library. */
+ VEC(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;
+
+ VEC_safe_push (CORE_ADDR, last->segment_bases, 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);
+ VEC_free (CORE_ADDR, 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);
+ VEC_free (CORE_ADDR, 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;
+ int num_bases = VEC_length (CORE_ADDR, so->lm_info->segment_bases);
+ CORE_ADDR *segment_bases = VEC_address (CORE_ADDR,
+ so->lm_info->segment_bases);
+
+ if (!symfile_map_offsets_to_segments (so->abfd, data,
+ so->lm_info->offsets,
+ num_bases, 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 (num_bases > 0);
+ orig_delta = segment_bases[0] - data->segment_bases[0];
+
+ for (i = 1; i < data->num_segments; i++)
+ {
+ /* If we have run out of offsets, assume all remaining segments
+ have the same offset. */
+ if (i >= num_bases)
+ continue;
+
+ /* If this segment does not have the same offset, do not include
+ it in the library's range. */
+ if (segment_bases[i] - data->segment_bases[i] != orig_delta)
+ break;
+ }
+
+ so->addr_low = segment_bases[0];
+ so->addr_high = (data->segment_bases[i - 1]
+ + data->segment_sizes[i - 1]
+ /* FIXME this must be needed! + orig_delta */);
+
+ 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-07-02 14:56:52.000000000 -0400
+++ gdb/solib.c 2007-07-02 14:58:13.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-07-02 14:56:17.000000000 -0400
+++ gdb/solist.h 2007-07-02 14:58:13.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-07-02 14:56:17.000000000 -0400
+++ gdb/target.h 2007-07-02 14:58:13.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-07-02 14:56:41.000000000 -0400
+++ gdb/NEWS 2007-07-02 14:58:13.000000000 -0400
@@ -44,6 +44,12 @@ segment base addresses (rather than offs
* The /i format now outputs any trailing branch delay slot instructions
immediately following the last instruction within the count specified.

+* 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
@@ -117,6 +123,12 @@ qXfer:spu:write:
Read or write contents of an spufs file on the target system. These
packets are available only on the Cell/B.E. SPU architecture.

+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-07-02 14:56:56.000000000 -0400
+++ gdb/doc/gdb.texinfo 2007-07-02 15:01:59.000000000 -0400
@@ -12859,58 +12859,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

@@ -12918,7 +12940,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}}

@@ -22506,6 +22528,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

@@ -23223,24 +23246,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:
+
+@table @samp
+@item watch
+@itemx rwatch
+@itemx awatch
+The packet indicates a watchpoint hit, and @var{r} is the data address, in
+hex.
+
+@cindex shared library events, remote reply
+@item library
+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 table

@item W @var{AA}
The process exited, and @var{AA} is the exit status. This is only
@@ -23626,7 +23670,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
@@ -23649,6 +23693,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{-}
@@ -23693,6 +23742,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}).
@@ -23815,6 +23868,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
@@ -25331,6 +25397,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-07-02 14:58:13.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>