From cfa9d6d99135b1d59ecf0756247305cc24869549 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Mon, 2 Jul 2007 22:01:09 +0000 Subject: [PATCH] * 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/ChangeLog | 25 +++ gdb/Makefile.in | 5 + gdb/NEWS | 12 ++ gdb/doc/ChangeLog | 10 + 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 +- 12 files changed, 657 insertions(+), 37 deletions(-) create mode 100644 gdb/features/library-list.dtd create mode 100644 gdb/solib-target.c diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 3a517a9a605..e1f7e3efdb2 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,28 @@ +2007-07-02 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. + 2007-07-02 Daniel Jacobowitz * infrun.c (inferior_ignoring_startup_exec_events): Delete. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 3d0fa409a30..5d7185565ff 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -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) $(elf_external_h) $(elf_common_h) \ $(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) diff --git a/gdb/NEWS b/gdb/NEWS index 19d78624cb9..81480738c4c 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -44,6 +44,12 @@ segment base addresses (rather than offsets) are available. * 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. diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index aec7b2c1bd3..24cfe28ba5c 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,13 @@ +2007-07-02 Daniel Jacobowitz + + * 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. + 2007-07-01 Jan Kratochvil * gdb.texinfo (Attach): Fixed GDB exit inferior detachment. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 5ce205fd1f4..ee592d91cb4 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -12859,58 +12859,80 @@ If you do, that may be a bug in your remote debugging stub, or a bug 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 wait timeout. * 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{S} response, except that the 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 multiple targets. 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 features and their properties: @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{qXfer:auxv:read} packet 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} annex. 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 + + + + + +@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 diff --git a/gdb/features/library-list.dtd b/gdb/features/library-list.dtd new file mode 100644 index 00000000000..44aa8c8194c --- /dev/null +++ b/gdb/features/library-list.dtd @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/gdb/remote.c b/gdb/remote.c index 8b4c4430eda..050930a3a31 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -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_protocol_features[] = { 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_waitstatus *status) 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 target_waitstatus *status) 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 target_waitstatus *status) /* 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, enum target_object object, (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 connected to (e.g. /dev/ttya)."; 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 bits) in a memory packet."), NULL, 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); diff --git a/gdb/solib-som.c b/gdb/solib-som.c index 9ef770892fb..dcc5f63cbb4 100644 --- a/gdb/solib-som.c +++ b/gdb/solib-som.c @@ -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; diff --git a/gdb/solib-target.c b/gdb/solib-target.c new file mode 100644 index 00000000000..2009df4176a --- /dev/null +++ b/gdb/solib-target.c @@ -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 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 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); + 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 . */ + +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); + 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; +} diff --git a/gdb/solib.c b/gdb/solib.c index 4cdb3a532cc..f48b0a2aae3 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -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, int from_tty) } 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"); diff --git a/gdb/solist.h b/gdb/solist.h index 08d8e7690b9..c8836867b46 100644 --- a/gdb/solist.h +++ b/gdb/solist.h @@ -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 diff --git a/gdb/target.h b/gdb/target.h index 7cde49b6450..d6e82e254a6 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -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, ... */ }; -- 2.30.2