From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 16585 invoked by alias); 18 Jun 2007 15:02:14 -0000 Received: (qmail 16566 invoked by uid 22791); 18 Jun 2007 15:02:08 -0000 X-Spam-Check-By: sourceware.org Received: from NaN.false.org (HELO nan.false.org) (208.75.86.248) by sourceware.org (qpsmtpd/0.31) with ESMTP; Mon, 18 Jun 2007 15:01:58 +0000 Received: from nan.false.org (localhost [127.0.0.1]) by nan.false.org (Postfix) with ESMTP id 25175982F9; Mon, 18 Jun 2007 15:01:56 +0000 (GMT) Received: from caradoc.them.org (22.svnf5.xdsl.nauticom.net [209.195.183.55]) by nan.false.org (Postfix) with ESMTP id 7337E982E3; Mon, 18 Jun 2007 15:01:55 +0000 (GMT) Received: from drow by caradoc.them.org with local (Exim 4.67) (envelope-from ) id 1I0Ik7-0006Es-26; Mon, 18 Jun 2007 11:02:11 -0400 Date: Mon, 18 Jun 2007 15:02:00 -0000 From: Daniel Jacobowitz To: gdb-patches@sourceware.org Cc: Ulrich Weigand , Pedro Alves Subject: [rfc] Shared libraries over the remote protocol, take two Message-ID: <20070618150211.GA23415@caradoc.them.org> Mail-Followup-To: gdb-patches@sourceware.org, Ulrich Weigand , Pedro Alves MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.15 (2007-04-09) X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2007-06/txt/msg00334.txt.bz2 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 * 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 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 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 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 . */ + +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 (¤t_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 + + + + + +@end smallexample + +The format of a library list is described by this DTD: + +@smallexample + + + + + + + +@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 @@ + + + + + + + + + + +