From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 4135 invoked by alias); 2 Dec 2011 22:33:06 -0000 Received: (qmail 4122 invoked by uid 22791); 2 Dec 2011 22:33:03 -0000 X-SWARE-Spam-Status: No, hits=-4.3 required=5.0 tests=AWL,BAYES_00,KAM_STOCKTIP,RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,SPF_HELO_PASS,TW_CP,TW_QX,TW_XS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 02 Dec 2011 22:32:45 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id pB2MWfhF025453 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Fri, 2 Dec 2011 17:32:41 -0500 Received: from host2.jankratochvil.net (ovpn-116-69.ams2.redhat.com [10.36.116.69]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id pB2MWITv028117 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO); Fri, 2 Dec 2011 17:32:20 -0500 Date: Fri, 02 Dec 2011 22:33:00 -0000 From: Jan Kratochvil To: gdb-patches@sourceware.org Cc: Paul Pluzhnikov , Pedro Alves Subject: [commit] [patch] Implement qXfer:libraries-svr4 for Linux/gdbserver #4 Message-ID: <20111202223217.GA32698@host2.jankratochvil.net> References: <20111003215530.GC20272@host1.jankratochvil.net> <201110062009.24796.pedro@codesourcery.com> <20111021094258.GA23101@host1.jankratochvil.net> <201110211205.06852.pedro@codesourcery.com> <20111103213010.GA2480@host1.jankratochvil.net> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20111103213010.GA2480@host1.jankratochvil.net> User-Agent: Mutt/1.5.21 (2010-09-15) 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: 2011-12/txt/msg00062.txt.bz2 Hi, checked in, therefore introducing the new and TARGET_OBJECT_LIBRARIES_SVR4 protocol (not reusing ). Some gdbserver memory corruption has been fixed. The patch uses now always the version="1.0" attribute as #FIXED, provided by gdbserver and required by gdb. A similar change I suggested for existing in: [patch] gdbserver and its #FIXED version="1.0" http://sourceware.org/ml/gdb-patches/2011-11/msg00099.html No regressions on {x86_64,x86_64-m32,i686}-fedora16-linux-gnu in both nat and gdbserver mode. Thanks, Jan http://sourceware.org/ml/gdb-cvs/2011-12/msg00012.html --- src/gdb/ChangeLog 2011/12/02 17:01:17 1.13568 +++ src/gdb/ChangeLog 2011/12/02 22:26:50 1.13569 @@ -1,3 +1,25 @@ +2011-12-02 Paul Pluzhnikov + Jan Kratochvil + + * Makefile.in (XMLFILES): Add library-list-svr4.dtd. + * features/library-list-svr4.dtd: New file. + * remote.c (PACKET_qXfer_libraries_svr4): New. + (remote_protocol_features): new entry for PACKET_qXfer_libraries_svr4. + (remote_xfer_partial): Handle TARGET_OBJECT_LIBRARIES_SVR4. + * solib-svr4.c (struct svr4_library_list): New. + [HAVE_LIBEXPAT]: Include xml-support.h. + [HAVE_LIBEXPAT] (svr4_library_list_start_library) + [HAVE_LIBEXPAT] (svr4_library_list_start_list, svr4_library_attributes) + [HAVE_LIBEXPAT] (svr4_library_list_children) + [HAVE_LIBEXPAT] (svr4_library_list_attributes) + [HAVE_LIBEXPAT] (svr4_library_list_elements, svr4_parse_libraries) + [HAVE_LIBEXPAT] (svr4_current_sos_via_xfer_libraries) + [!HAVE_LIBEXPAT] (svr4_current_sos_via_xfer_libraries): New. + (svr4_read_so_list): Extend the corruption message by addresses. + (svr4_current_sos): New variable library_list, call + svr4_current_sos_via_xfer_libraries. + * target.h (enum target_object): New TARGET_OBJECT_LIBRARIES_SVR4. + 2011-12-02 Jan Kratochvil PR threads/13448 --- src/gdb/doc/ChangeLog 2011/12/01 20:27:27 1.1252 +++ src/gdb/doc/ChangeLog 2011/12/02 22:26:52 1.1253 @@ -1,3 +1,10 @@ +2011-12-02 Jan Kratochvil + + * gdb.texinfo (Requirements, Remote Protocol): Reference also `Library + List Format for SVR4 Targets'. + (General Query Packets): New item qXfer:libraries-svr4:read. + (Library List Format for SVR4 Targets): New node. + 2011-12-01 Tom Tromey * gdb.texinfo (Writing a Pretty-Printer): Use append method, not --- src/gdb/gdbserver/ChangeLog 2011/11/30 16:06:55 1.514 +++ src/gdb/gdbserver/ChangeLog 2011/12/02 22:26:52 1.515 @@ -1,3 +1,20 @@ +2011-12-02 Paul Pluzhnikov + Jan Kratochvil + + * linux-low.c (get_phdr_phnum_from_proc_auxv, get_dynamic, get_r_debug) + (read_one_ptr, struct link_map_offsets, linux_qxfer_libraries_svr4): + New. + (struct linux_target_ops): Install linux_qxfer_libraries_svr4. + * linux-low.h (struct process_info_private): New member r_debug. + * server.c (handle_qxfer_libraries): Call + the_target->qxfer_libraries_svr4. + (handle_qxfer_libraries_svr4): New function. + (qxfer_packets): New entry "libraries-svr4". + (handle_query): Check QXFER_LIBRARIES_SVR4 and report libraries-svr4. + * target.h (struct target_ops): New member qxfer_libraries_svr4. + * remote.c (remote_xfer_partial): Call add_packet_config_cmd for + PACKET_qXfer_libraries_svr4. + 2011-11-30 Ulrich Weigand * linux-s390-low.c (s390_collect_ptrace_register): Fully convert --- src/gdb/testsuite/ChangeLog 2011/12/02 17:01:20 1.2957 +++ src/gdb/testsuite/ChangeLog 2011/12/02 22:26:53 1.2958 @@ -1,5 +1,10 @@ 2011-12-02 Jan Kratochvil + * gdb.base/solib-corrupted.exp: Suppress test on is_remote target. + (corrupted list): Adjust the expectation. + +2011-12-02 Jan Kratochvil + PR threads/13448 * gdb.dwarf2/dw2-var-zero-addr.S: New file. * gdb.dwarf2/dw2-var-zero-addr.exp: New file. --- src/gdb/Makefile.in 2011/11/20 08:59:56 1.1178 +++ src/gdb/Makefile.in 2011/12/02 22:26:51 1.1179 @@ -495,7 +495,8 @@ # XML files to build in to GDB. XMLFILES = $(srcdir)/features/gdb-target.dtd $(srcdir)/features/xinclude.dtd \ - $(srcdir)/features/library-list.dtd $(srcdir)/features/osdata.dtd \ + $(srcdir)/features/library-list.dtd \ + $(srcdir)/features/library-list-svr4.dtd $(srcdir)/features/osdata.dtd \ $(srcdir)/features/threads.dtd $(srcdir)/features/traceframe-info.dtd # This is ser-unix.o for any system which supports a v7/BSD/SYSV/POSIX --- src/gdb/remote.c 2011/11/27 17:39:30 1.472 +++ src/gdb/remote.c 2011/12/02 22:26:51 1.473 @@ -1243,6 +1243,7 @@ PACKET_qXfer_auxv, PACKET_qXfer_features, PACKET_qXfer_libraries, + PACKET_qXfer_libraries_svr4, PACKET_qXfer_memory_map, PACKET_qXfer_spu_read, PACKET_qXfer_spu_write, @@ -3748,6 +3749,8 @@ PACKET_qXfer_features }, { "qXfer:libraries:read", PACKET_DISABLE, remote_supported_packet, PACKET_qXfer_libraries }, + { "qXfer:libraries-svr4:read", PACKET_DISABLE, remote_supported_packet, + PACKET_qXfer_libraries_svr4 }, { "qXfer:memory-map:read", PACKET_DISABLE, remote_supported_packet, PACKET_qXfer_memory_map }, { "qXfer:spu:read", PACKET_DISABLE, remote_supported_packet, @@ -8356,6 +8359,11 @@ (ops, "libraries", annex, readbuf, offset, len, &remote_protocol_packets[PACKET_qXfer_libraries]); + case TARGET_OBJECT_LIBRARIES_SVR4: + return remote_read_qxfer + (ops, "libraries-svr4", annex, readbuf, offset, len, + &remote_protocol_packets[PACKET_qXfer_libraries_svr4]); + case TARGET_OBJECT_MEMORY_MAP: gdb_assert (annex == NULL); return remote_read_qxfer (ops, "memory-map", annex, readbuf, offset, len, @@ -11078,6 +11086,9 @@ add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_libraries], "qXfer:libraries:read", "library-info", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_libraries_svr4], + "qXfer:libraries-svr4:read", "library-info-svr4", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_memory_map], "qXfer:memory-map:read", "memory-map", 0); --- src/gdb/solib-svr4.c 2011/10/18 14:00:41 1.158 +++ src/gdb/solib-svr4.c 2011/12/02 22:26:51 1.159 @@ -949,6 +949,107 @@ return 1; } +/* Data exchange structure for the XML parser as returned by + svr4_current_sos_via_xfer_libraries. */ + +struct svr4_library_list +{ + struct so_list *head, **tailp; + + /* Inferior address of struct link_map used for the main executable. It is + NULL if not known. */ + CORE_ADDR main_lm; +}; + +#ifdef HAVE_LIBEXPAT + +#include "xml-support.h" + +/* Handle the start of a element. Note: new elements are added + at the tail of the list, keeping the list in order. */ + +static void +library_list_start_library (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, VEC(gdb_xml_value_s) *attributes) +{ + struct svr4_library_list *list = user_data; + const char *name = xml_find_attribute (attributes, "name")->value; + ULONGEST *lmp = xml_find_attribute (attributes, "lm")->value; + ULONGEST *l_addrp = xml_find_attribute (attributes, "l_addr")->value; + ULONGEST *l_ldp = xml_find_attribute (attributes, "l_ld")->value; + struct so_list *new_elem; + + new_elem = XZALLOC (struct so_list); + new_elem->lm_info = XZALLOC (struct lm_info); + new_elem->lm_info->lm_addr = *lmp; + new_elem->lm_info->l_addr_inferior = *l_addrp; + new_elem->lm_info->l_ld = *l_ldp; + + strncpy (new_elem->so_name, name, sizeof (new_elem->so_name) - 1); + new_elem->so_name[sizeof (new_elem->so_name) - 1] = 0; + strcpy (new_elem->so_original_name, new_elem->so_name); + + *list->tailp = new_elem; + list->tailp = &new_elem->next; +} + +/* Handle the start of a element. */ + +static void +svr4_library_list_start_list (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, VEC(gdb_xml_value_s) *attributes) +{ + struct svr4_library_list *list = user_data; + const char *version = xml_find_attribute (attributes, "version")->value; + struct gdb_xml_value *main_lm = xml_find_attribute (attributes, "main-lm"); + + if (strcmp (version, "1.0") != 0) + gdb_xml_error (parser, + _("SVR4 Library list has unsupported version \"%s\""), + version); + + if (main_lm) + list->main_lm = *(ULONGEST *) main_lm->value; +} + +/* The allowed elements and attributes for an XML library list. + The root element is a . */ + +static const struct gdb_xml_attribute svr4_library_attributes[] = +{ + { "name", GDB_XML_AF_NONE, NULL, NULL }, + { "lm", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { "l_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { "l_ld", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_element svr4_library_list_children[] = +{ + { + "library", svr4_library_attributes, NULL, + GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL, + library_list_start_library, NULL + }, + { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_attribute svr4_library_list_attributes[] = +{ + { "version", GDB_XML_AF_NONE, NULL, NULL }, + { "main-lm", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL }, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_element svr4_library_list_elements[] = +{ + { "library-list-svr4", svr4_library_list_attributes, svr4_library_list_children, + GDB_XML_EF_NONE, svr4_library_list_start_list, NULL }, + { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +}; + /* Implementation for target_so_ops.free_so. */ static void @@ -973,6 +1074,69 @@ } } +/* Parse qXfer:libraries:read packet into *SO_LIST_RETURN. Return 1 if + + Return 0 if packet not supported, *SO_LIST_RETURN is not modified in such + case. Return 1 if *SO_LIST_RETURN contains the library list, it may be + empty, caller is responsible for freeing all its entries. */ + +static int +svr4_parse_libraries (const char *document, struct svr4_library_list *list) +{ + struct cleanup *back_to = make_cleanup (svr4_free_library_list, + &list->head); + + memset (list, 0, sizeof (*list)); + list->tailp = &list->head; + if (gdb_xml_parse_quick (_("target library list"), "library-list.dtd", + svr4_library_list_elements, document, list) == 0) + { + /* Parsed successfully, keep the result. */ + discard_cleanups (back_to); + return 1; + } + + do_cleanups (back_to); + return 0; +} + +/* Attempt to get so_list from target via qXfer:libraries:read packet. + + Return 0 if packet not supported, *SO_LIST_RETURN is not modified in such + case. Return 1 if *SO_LIST_RETURN contains the library list, it may be + empty, caller is responsible for freeing all its entries. */ + +static int +svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list) +{ + char *svr4_library_document; + int result; + struct cleanup *back_to; + + /* Fetch the list of shared libraries. */ + svr4_library_document = target_read_stralloc (¤t_target, + TARGET_OBJECT_LIBRARIES_SVR4, + NULL); + if (svr4_library_document == NULL) + return 0; + + back_to = make_cleanup (xfree, svr4_library_document); + result = svr4_parse_libraries (svr4_library_document, list); + do_cleanups (back_to); + + return result; +} + +#else + +static int +svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list) +{ + return 0; +} + +#endif + /* If no shared library information is available from the dynamic linker, build a fallback list from other sources. */ @@ -1032,7 +1196,9 @@ if (new->lm_info->l_prev != prev_lm) { - warning (_("Corrupted shared library list")); + warning (_("Corrupted shared library list: %s != %s"), + paddress (target_gdbarch, prev_lm), + paddress (target_gdbarch, new->lm_info->l_prev)); do_cleanups (old_chain); break; } @@ -1093,6 +1259,18 @@ struct svr4_info *info; struct cleanup *back_to; int ignore_first; + struct svr4_library_list library_list; + + if (svr4_current_sos_via_xfer_libraries (&library_list)) + { + if (library_list.main_lm) + { + info = get_svr4_info (); + info->main_lm_addr = library_list.main_lm; + } + + return library_list.head ? library_list.head : svr4_default_sos (); + } info = get_svr4_info (); --- src/gdb/target.h 2011/11/20 23:59:47 1.219 +++ src/gdb/target.h 2011/12/02 22:26:51 1.220 @@ -255,6 +255,8 @@ TARGET_OBJECT_AVAILABLE_FEATURES, /* Currently loaded libraries, in XML format. */ TARGET_OBJECT_LIBRARIES, + /* Currently loaded libraries specific for SVR4 systems, in XML format. */ + TARGET_OBJECT_LIBRARIES_SVR4, /* Get OS specific data. The ANNEX specifies the type (running processes, etc.). The data being transfered is expected to follow the DTD specified in features/osdata.dtd. */ --- src/gdb/doc/gdb.texinfo 2011/12/01 20:27:28 1.902 +++ src/gdb/doc/gdb.texinfo 2011/12/02 22:26:52 1.903 @@ -32448,7 +32448,8 @@ @item Target descriptions (@pxref{Target Descriptions}) @item -Remote shared library lists (@pxref{Library List Format}) +Remote shared library lists (@xref{Library List Format}, +or alternatively @pxref{Library List Format for SVR4 Targets}) @item MS-Windows shared libraries (@pxref{Shared Libraries}) @item @@ -33285,6 +33286,7 @@ * Examples:: * File-I/O Remote Protocol Extension:: * Library List Format:: +* Library List Format for SVR4 Targets:: * Memory Map Format:: * Thread List Format:: * Traceframe Info Format:: @@ -34986,6 +34988,10 @@ The remote stub understands the @samp{qXfer:libraries:read} packet (@pxref{qXfer library list read}). +@item qXfer:libraries-svr4:read +The remote stub understands the @samp{qXfer:libraries-svr4:read} packet +(@pxref{qXfer svr4 library list read}). + @item qXfer:memory-map:read The remote stub understands the @samp{qXfer:memory-map:read} packet (@pxref{qXfer memory map read}). @@ -35231,6 +35237,18 @@ This packet is not probed by default; the remote stub must request it, by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). +@item qXfer:libraries-svr4:read:@var{annex}:@var{offset},@var{length} +@anchor{qXfer svr4 library list read} +Access the target's list of loaded libraries when the target is an SVR4 +platform. @xref{Library List Format for SVR4 Targets}. The annex part +of the generic @samp{qXfer} packet must be empty (@pxref{qXfer read}). + +This packet is optional for better performance on SVR4 targets. +@value{GDBN} uses memory read packets to read the SVR4 library list otherwise. + +This packet is not probed by default; the remote stub must request it, +by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). + @item qXfer:memory-map:read::@var{offset},@var{length} @anchor{qXfer memory map read} Access the target's @dfn{memory-map}. @xref{Memory Map Format}. The @@ -37542,6 +37560,68 @@ single library element, and you must supply at least one segment or section for each library. +@node Library List Format for SVR4 Targets +@section Library List Format for SVR4 Targets +@cindex library list format, remote protocol + +On SVR4 platforms @value{GDBN} can use the symbol table of a dynamic loader +(e.g.@: @file{ld.so}) and normal memory operations to maintain a list of +shared libraries. Still a special library list provided by this packet is +more efficient for the @value{GDBN} remote protocol. + +The @samp{qXfer:libraries-svr4:read} packet returns an XML document which lists +loaded libraries and their SVR4 linker parameters. For each library on SVR4 +target, the following parameters are reported: + +@itemize @minus +@item +@code{name}, the absolute file name from the @code{l_name} field of +@code{struct link_map}. +@item +@code{lm} with address of @code{struct link_map} used for TLS +(Thread Local Storage) access. +@item +@code{l_addr}, the displacement as read from the field @code{l_addr} of +@code{struct link_map}. For prelinked libraries this is not an absolute +memory address. It is a displacement of absolute memory address against +address the file was prelinked to during the library load. +@item +@code{l_ld}, which is memory address of the @code{PT_DYNAMIC} segment +@end itemize + +Additionally the single @code{main-lm} attribute specifies address of +@code{struct link_map} used for the main executable. This parameter is used +for TLS access and its presence is optional. + +@value{GDBN} must be linked with the Expat library to support XML +SVR4 library lists. @xref{Expat}. + +A simple memory map, with two loaded libraries (which do not use prelink), +looks like this: + +@smallexample + + + + +@end smallexample + +The format of an SVR4 library list is described by this DTD: + +@smallexample + + + + + + + + + +@end smallexample + @node Memory Map Format @section Memory Map Format @cindex memory map format --- src/gdb/features/library-list-svr4.dtd +++ src/gdb/features/library-list-svr4.dtd 2011-12-02 22:27:46.927012000 +0000 @@ -0,0 +1,16 @@ + + + + + + + + + + + + --- src/gdb/gdbserver/linux-low.c 2011/11/14 20:07:24 1.179 +++ src/gdb/gdbserver/linux-low.c 2011/12/02 22:26:52 1.180 @@ -4964,6 +4964,382 @@ return (*the_low_target.get_min_fast_tracepoint_insn_len) (); } +/* Extract &phdr and num_phdr in the inferior. Return 0 on success. */ + +static int +get_phdr_phnum_from_proc_auxv (const int pid, const int is_elf64, + CORE_ADDR *phdr_memaddr, int *num_phdr) +{ + char filename[PATH_MAX]; + int fd; + const int auxv_size = is_elf64 + ? sizeof (Elf64_auxv_t) : sizeof (Elf32_auxv_t); + char buf[sizeof (Elf64_auxv_t)]; /* The larger of the two. */ + + xsnprintf (filename, sizeof filename, "/proc/%d/auxv", pid); + + fd = open (filename, O_RDONLY); + if (fd < 0) + return 1; + + *phdr_memaddr = 0; + *num_phdr = 0; + while (read (fd, buf, auxv_size) == auxv_size + && (*phdr_memaddr == 0 || *num_phdr == 0)) + { + if (is_elf64) + { + Elf64_auxv_t *const aux = (Elf64_auxv_t *) buf; + + switch (aux->a_type) + { + case AT_PHDR: + *phdr_memaddr = aux->a_un.a_val; + break; + case AT_PHNUM: + *num_phdr = aux->a_un.a_val; + break; + } + } + else + { + Elf32_auxv_t *const aux = (Elf32_auxv_t *) buf; + + switch (aux->a_type) + { + case AT_PHDR: + *phdr_memaddr = aux->a_un.a_val; + break; + case AT_PHNUM: + *num_phdr = aux->a_un.a_val; + break; + } + } + } + + close (fd); + + if (*phdr_memaddr == 0 || *num_phdr == 0) + { + warning ("Unexpected missing AT_PHDR and/or AT_PHNUM: " + "phdr_memaddr = %ld, phdr_num = %d", + (long) *phdr_memaddr, *num_phdr); + return 2; + } + + return 0; +} + +/* Return &_DYNAMIC (via PT_DYNAMIC) in the inferior, or 0 if not present. */ + +static CORE_ADDR +get_dynamic (const int pid, const int is_elf64) +{ + CORE_ADDR phdr_memaddr, relocation; + int num_phdr, i; + unsigned char *phdr_buf; + const int phdr_size = is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr); + + if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &num_phdr)) + return 0; + + gdb_assert (num_phdr < 100); /* Basic sanity check. */ + phdr_buf = alloca (num_phdr * phdr_size); + + if (linux_read_memory (phdr_memaddr, phdr_buf, num_phdr * phdr_size)) + return 0; + + /* Compute relocation: it is expected to be 0 for "regular" executables, + non-zero for PIE ones. */ + relocation = -1; + for (i = 0; relocation == -1 && i < num_phdr; i++) + if (is_elf64) + { + Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size); + + if (p->p_type == PT_PHDR) + relocation = phdr_memaddr - p->p_vaddr; + } + else + { + Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size); + + if (p->p_type == PT_PHDR) + relocation = phdr_memaddr - p->p_vaddr; + } + + if (relocation == -1) + { + warning ("Unexpected missing PT_PHDR"); + return 0; + } + + for (i = 0; i < num_phdr; i++) + { + if (is_elf64) + { + Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size); + + if (p->p_type == PT_DYNAMIC) + return p->p_vaddr + relocation; + } + else + { + Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size); + + if (p->p_type == PT_DYNAMIC) + return p->p_vaddr + relocation; + } + } + + return 0; +} + +/* Return &_r_debug in the inferior, or -1 if not present. Return value + can be 0 if the inferior does not yet have the library list initialized. */ + +static CORE_ADDR +get_r_debug (const int pid, const int is_elf64) +{ + CORE_ADDR dynamic_memaddr; + const int dyn_size = is_elf64 ? sizeof (Elf64_Dyn) : sizeof (Elf32_Dyn); + unsigned char buf[sizeof (Elf64_Dyn)]; /* The larger of the two. */ + + dynamic_memaddr = get_dynamic (pid, is_elf64); + if (dynamic_memaddr == 0) + return (CORE_ADDR) -1; + + while (linux_read_memory (dynamic_memaddr, buf, dyn_size) == 0) + { + if (is_elf64) + { + Elf64_Dyn *const dyn = (Elf64_Dyn *) buf; + + if (dyn->d_tag == DT_DEBUG) + return dyn->d_un.d_val; + + if (dyn->d_tag == DT_NULL) + break; + } + else + { + Elf32_Dyn *const dyn = (Elf32_Dyn *) buf; + + if (dyn->d_tag == DT_DEBUG) + return dyn->d_un.d_val; + + if (dyn->d_tag == DT_NULL) + break; + } + + dynamic_memaddr += dyn_size; + } + + return (CORE_ADDR) -1; +} + +/* Read one pointer from MEMADDR in the inferior. */ + +static int +read_one_ptr (CORE_ADDR memaddr, CORE_ADDR *ptr, int ptr_size) +{ + *ptr = 0; + return linux_read_memory (memaddr, (unsigned char *) ptr, ptr_size); +} + +struct link_map_offsets + { + /* Offset and size of r_debug.r_version. */ + int r_version_offset; + + /* Offset and size of r_debug.r_map. */ + int r_map_offset; + + /* Offset to l_addr field in struct link_map. */ + int l_addr_offset; + + /* Offset to l_name field in struct link_map. */ + int l_name_offset; + + /* Offset to l_ld field in struct link_map. */ + int l_ld_offset; + + /* Offset to l_next field in struct link_map. */ + int l_next_offset; + + /* Offset to l_prev field in struct link_map. */ + int l_prev_offset; + }; + +/* Construct qXfer:libraries:read reply. */ + +static int +linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf, + unsigned const char *writebuf, + CORE_ADDR offset, int len) +{ + char *document; + unsigned document_len; + struct process_info_private *const priv = current_process ()->private; + char filename[PATH_MAX]; + int pid, is_elf64; + + static const struct link_map_offsets lmo_32bit_offsets = + { + 0, /* r_version offset. */ + 4, /* r_debug.r_map offset. */ + 0, /* l_addr offset in link_map. */ + 4, /* l_name offset in link_map. */ + 8, /* l_ld offset in link_map. */ + 12, /* l_next offset in link_map. */ + 16 /* l_prev offset in link_map. */ + }; + + static const struct link_map_offsets lmo_64bit_offsets = + { + 0, /* r_version offset. */ + 8, /* r_debug.r_map offset. */ + 0, /* l_addr offset in link_map. */ + 8, /* l_name offset in link_map. */ + 16, /* l_ld offset in link_map. */ + 24, /* l_next offset in link_map. */ + 32 /* l_prev offset in link_map. */ + }; + const struct link_map_offsets *lmo; + + if (writebuf != NULL) + return -2; + if (readbuf == NULL) + return -1; + + pid = lwpid_of (get_thread_lwp (current_inferior)); + xsnprintf (filename, sizeof filename, "/proc/%d/exe", pid); + is_elf64 = elf_64_file_p (filename); + lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets; + + if (priv->r_debug == 0) + priv->r_debug = get_r_debug (pid, is_elf64); + + if (priv->r_debug == (CORE_ADDR) -1 || priv->r_debug == 0) + { + document = xstrdup ("\n"); + } + else + { + int allocated = 1024; + char *p; + const int ptr_size = is_elf64 ? 8 : 4; + CORE_ADDR lm_addr, lm_prev, l_name, l_addr, l_ld, l_next, l_prev; + int r_version, header_done = 0; + + document = xmalloc (allocated); + strcpy (document, "r_debug + lmo->r_version_offset, + (unsigned char *) &r_version, + sizeof (r_version)) != 0 + || r_version != 1) + { + warning ("unexpected r_debug version %d", r_version); + goto done; + } + + if (read_one_ptr (priv->r_debug + lmo->r_map_offset, + &lm_addr, ptr_size) != 0) + { + warning ("unable to read r_map from 0x%lx", + (long) priv->r_debug + lmo->r_map_offset); + goto done; + } + + lm_prev = 0; + while (read_one_ptr (lm_addr + lmo->l_name_offset, + &l_name, ptr_size) == 0 + && read_one_ptr (lm_addr + lmo->l_addr_offset, + &l_addr, ptr_size) == 0 + && read_one_ptr (lm_addr + lmo->l_ld_offset, + &l_ld, ptr_size) == 0 + && read_one_ptr (lm_addr + lmo->l_prev_offset, + &l_prev, ptr_size) == 0 + && read_one_ptr (lm_addr + lmo->l_next_offset, + &l_next, ptr_size) == 0) + { + unsigned char libname[PATH_MAX]; + + if (lm_prev != l_prev) + { + warning ("Corrupted shared library list: 0x%lx != 0x%lx", + (long) lm_prev, (long) l_prev); + break; + } + + /* Not checking for error because reading may stop before + we've got PATH_MAX worth of characters. */ + libname[0] = '\0'; + linux_read_memory (l_name, libname, sizeof (libname) - 1); + libname[sizeof (libname) - 1] = '\0'; + if (libname[0] != '\0') + { + /* 6x the size for xml_escape_text below. */ + size_t len = 6 * strlen ((char *) libname); + char *name; + + if (!header_done) + { + /* Terminate `", + name, (unsigned long) lm_addr, + (unsigned long) l_addr, (unsigned long) l_ld); + free (name); + } + else if (lm_prev == 0) + { + sprintf (p, " main-lm=\"0x%lx\"", (unsigned long) lm_addr); + p = p + strlen (p); + } + + if (l_next == 0) + break; + + lm_prev = lm_addr; + lm_addr = l_next; + } + done: + strcpy (p, ""); + } + + document_len = strlen (document); + if (offset < document_len) + document_len -= offset; + else + document_len = 0; + if (len > document_len) + len = document_len; + + memcpy (readbuf, document + offset, len); + xfree (document); + + return len; +} + static struct target_ops linux_target_ops = { linux_create_inferior, linux_attach, @@ -5026,6 +5402,7 @@ linux_emit_ops, linux_supports_disable_randomization, linux_get_min_fast_tracepoint_insn_len, + linux_qxfer_libraries_svr4, }; static void --- src/gdb/gdbserver/linux-low.h 2011/11/14 20:07:24 1.48 +++ src/gdb/gdbserver/linux-low.h 2011/12/02 22:26:53 1.49 @@ -56,6 +56,9 @@ /* libthread_db-specific additions. Not NULL if this process has loaded thread_db, and it is active. */ struct thread_db *thread_db; + + /* &_r_debug. 0 if not yet determined. -1 if no PT_DYNAMIC in Phdrs. */ + CORE_ADDR r_debug; }; struct lwp_info; --- src/gdb/gdbserver/server.c 2011/11/14 15:18:51 1.151 +++ src/gdb/gdbserver/server.c 2011/12/02 22:26:53 1.152 @@ -942,6 +942,10 @@ if (annex[0] != '\0' || !target_running ()) return -1; + /* Do not confuse this packet with qXfer:libraries-svr4:read. */ + if (the_target->qxfer_libraries_svr4 != NULL) + return 0; + /* Over-estimate the necessary memory. Assume that every character in the library name must be escaped. */ total_len = 64; @@ -992,6 +996,23 @@ return len; } +/* Handle qXfer:libraries-svr4:read. */ + +static int +handle_qxfer_libraries_svr4 (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + if (writebuf != NULL) + return -2; + + if (annex[0] != '\0' || !target_running () + || the_target->qxfer_libraries_svr4 == NULL) + return -1; + + return the_target->qxfer_libraries_svr4 (annex, readbuf, writebuf, offset, len); +} + /* Handle qXfer:osadata:read. */ static int @@ -1216,6 +1237,7 @@ { "fdpic", handle_qxfer_fdpic}, { "features", handle_qxfer_features }, { "libraries", handle_qxfer_libraries }, + { "libraries-svr4", handle_qxfer_libraries_svr4 }, { "osdata", handle_qxfer_osdata }, { "siginfo", handle_qxfer_siginfo }, { "spu", handle_qxfer_spu }, @@ -1536,9 +1558,14 @@ sprintf (own_buf, "PacketSize=%x;QPassSignals+", PBUFSIZ - 1); - /* We do not have any hook to indicate whether the target backend - supports qXfer:libraries:read, so always report it. */ - strcat (own_buf, ";qXfer:libraries:read+"); + if (the_target->qxfer_libraries_svr4 != NULL) + strcat (own_buf, ";qXfer:libraries-svr4:read+"); + else + { + /* We do not have any hook to indicate whether the non-SVR4 target + backend supports qXfer:libraries:read, so always report it. */ + strcat (own_buf, ";qXfer:libraries:read+"); + } if (the_target->read_auxv != NULL) strcat (own_buf, ";qXfer:auxv:read+"); --- src/gdb/gdbserver/target.h 2011/11/14 20:07:24 1.59 +++ src/gdb/gdbserver/target.h 2011/12/02 22:26:53 1.60 @@ -390,6 +390,11 @@ /* Return the minimum length of an instruction that can be safely overwritten for use as a fast tracepoint. */ int (*get_min_fast_tracepoint_insn_len) (void); + + /* Read solib info on SVR4 platforms. */ + int (*qxfer_libraries_svr4) (const char *annex, unsigned char *readbuf, + unsigned const char *writebuf, + CORE_ADDR offset, int len); }; extern struct target_ops *the_target; --- src/gdb/testsuite/gdb.base/solib-corrupted.exp 2011/01/01 15:33:42 1.4 +++ src/gdb/testsuite/gdb.base/solib-corrupted.exp 2011/12/02 22:26:54 1.5 @@ -17,6 +17,12 @@ return 0 } +if {[is_remote target]} { + # gdbserver prints the warning message but expect is parsing only the GDB + # output, not the gdbserver output. + return 0 +} + set testfile "solib-corrupted" set srcfile start.c @@ -47,4 +53,4 @@ pass $test } } -gdb_test "info sharedlibrary" "warning: Corrupted shared library list\r\n.*" "corrupted list" +gdb_test "info sharedlibrary" "warning: Corrupted shared library list: .*" "corrupted list"