From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 8765 invoked by alias); 10 Oct 2011 02:44:01 -0000 Received: (qmail 8712 invoked by uid 22791); 10 Oct 2011 02:43:57 -0000 X-SWARE-Spam-Status: No, hits=-2.4 required=5.0 tests=AWL,BAYES_00,DKIM_SIGNED,DKIM_VALID,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,TW_CP,TW_XS X-Spam-Check-By: sourceware.org Received: from mail-ey0-f169.google.com (HELO mail-ey0-f169.google.com) (209.85.215.169) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 10 Oct 2011 02:43:39 +0000 Received: by eye4 with SMTP id 4so184346eye.0 for ; Sun, 09 Oct 2011 19:43:37 -0700 (PDT) MIME-Version: 1.0 Received: by 10.14.10.208 with SMTP id 56mr1379904eev.125.1318214616258; Sun, 09 Oct 2011 19:43:36 -0700 (PDT) Received: by 10.14.47.9 with HTTP; Sun, 9 Oct 2011 19:43:36 -0700 (PDT) In-Reply-To: <20111003215530.GC20272@host1.jankratochvil.net> References: <20111003215530.GC20272@host1.jankratochvil.net> Date: Mon, 10 Oct 2011 02:44:00 -0000 Message-ID: Subject: Re: [patch 3/3] Implement qXfer:libraries for Linux/gdbserver #2 From: Daniel Jacobowitz To: Jan Kratochvil Cc: gdb-patches@sourceware.org, Paul Pluzhnikov Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable 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-10/txt/msg00250.txt.bz2 On Mon, Oct 3, 2011 at 5:55 PM, Jan Kratochvil wrote: > Hi Paul, > > this is updated: > =A0 =A0 =A0 =A0Re: [patch] Implement qXfer:libraries for Linux/gdbserver > =A0 =A0 =A0 =A0http://sourceware.org/ml/gdb-patches/2011-08/msg00204.html > > I gave up on the unification way. =A0solib-svr4.c just needs too much more > information than the former format to: (a) Make the format > compatible, (b) make the gdbserver producer meaningful to unify, (c) gdb > consumer likewise. > > It could for example use absolute base address instead of the l_addr bias= to > be compatible with established . =A0But it would need to p= ass > additionally l_ld for dealing with PIE+PIC displacement and also `struct > link_map' addresses for TLS. =A0And it would be complicated for both prod= ucer > and consumer side to construct and use the absolute library base addresse= s. I would be a whole lot happier if we could use the same elements for SVR4. There may be some creative interpretations we can use to make it work... yes, we'd likely have to pass the link map addresses as additional information; fortunately that's easy. I'm not sure I understand the issue with dealing with absolute library base addresses. But in short, the way to think about this is to move all the complicated bits of library processing to the target agent, and give GDB a simplified view of what's really going on. If that's not practical, then +1 to Pedro's suggestion; if you're bulk-reading the link maps, or doing some svr4-specific semantics, we should express it that way. > > The testcase would benefit from some gdbserver -> gdb in-protocol channel= used > for the `warning' calls in gdbserver. > > No regressions on {x86_64,x86_64-m32,i686}-fedora16pre-linux-gnu and with > gdbserver and with gdbserver+PIE. > > > Thanks, > Jan > > > gdb/ > 2011-10-03 =A0Paul Pluzhnikov =A0 > =A0 =A0 =A0 =A0 =A0 =A0Jan Kratochvil =A0 > > =A0 =A0 =A0 =A0* features/library-list.dtd: Add attributes library-list.m= ain-lm, > =A0 =A0 =A0 =A0library.lm, library.l_addr and library.l_ld. > =A0 =A0 =A0 =A0* solib-svr4.c (struct svr4_library_list): New. > =A0 =A0 =A0 =A0[HAVE_LIBEXPAT]: Include xml-support.h. > =A0 =A0 =A0 =A0[HAVE_LIBEXPAT] (library_list_start_library, library_list_= start_list) > =A0 =A0 =A0 =A0(library_attributes, library_list_children, library_list_a= ttributes) > =A0 =A0 =A0 =A0(library_list_elements, svr4_parse_libraries) > =A0 =A0 =A0 =A0(svr4_current_sos_via_xfer_libraries): New. > =A0 =A0 =A0 =A0[!HAVE_LIBEXPAT] (svr4_current_sos_via_xfer_libraries): Ne= w. > =A0 =A0 =A0 =A0(svr4_read_so_list): Extend the corruption message by addr= esses. > =A0 =A0 =A0 =A0(svr4_current_sos): New variable library_list, call > =A0 =A0 =A0 =A0svr4_current_sos_via_xfer_libraries. > > gdb/gdbserver/ > 2011-10-03 =A0Paul Pluzhnikov =A0 > =A0 =A0 =A0 =A0 =A0 =A0Jan Kratochvil =A0 > > =A0 =A0 =A0 =A0* linux-low.c (get_phdr_phnum_from_proc_auxv, get_dynamic,= get_r_debug) > =A0 =A0 =A0 =A0(read_one_ptr, struct link_map_offsets, linux_refresh_libr= aries): New. > =A0 =A0 =A0 =A0(struct linux_target_ops): Install linux_qxfer_libraries. > =A0 =A0 =A0 =A0* linux-low.h (struct process_info_private): New member r_= debug. > =A0 =A0 =A0 =A0* server.c (handle_qxfer_libraries): Call the_target->qxfe= r_libraries. > =A0 =A0 =A0 =A0* target.h (struct target_ops): New member qxfer_libraries. > > gdb/doc/ > 2011-10-03 =A0Jan Kratochvil =A0 > > =A0 =A0 =A0 =A0* gdb.texinfo (Library List Format): Add SVR4 format descr= iption. > > gdb/testsuite/ > 2011-10-03 =A0Jan Kratochvil =A0 > > =A0 =A0 =A0 =A0* gdb.base/solib-corrupted.exp: Suppress test on is_remote= target. > =A0 =A0 =A0 =A0(corrupted list): Adjust the expectation. > > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -36412,15 +36412,21 @@ are loaded. > > =A0The @samp{qXfer:libraries:read} packet returns an XML document which > =A0lists loaded libraries and their offsets. =A0Each library has an > -associated name and one or more segment or section base addresses, > -which report where the library was loaded in memory. > +associated name and one or more segment, section base addresses or SVR4 = linker > +parameters, which report where the library was loaded in memory. > > =A0For the common case of libraries that are fully linked binaries, the > =A0library should have a list of segments. =A0If the target supports > =A0dynamic linking of a relocatable object file, its library XML element > =A0should instead include a list of allocated sections. =A0The segment or > =A0section bases are start addresses, not relocation offsets; they do not > -depend on the library's link-time base addresses. > +depend on the library's link-time base addresses. =A0For SVR4 systems > +are reported parameters @{lm} with address of @code{struct link_map} > +used for TLS (Thread Local Storage) access, @code{l_addr} specifying > +bias of the mapped memory address minus the prelinked base address > +and also @code{l_ld} which is memory address of the @code{PT_DYNAMIC} > +segment. =A0SVR4 systems additionally specify @code{struct link_map} > +address of the main executable in the @code{} element. > > =A0@value{GDBN} must be linked with the Expat library to support XML > =A0library lists. =A0@xref{Expat}. > @@ -36449,23 +36455,38 @@ allocated sections (.text, .data, .bss), looks = like this: > =A0 > =A0@end smallexample > > +SVR4 systems report: > + > +@smallexample > + > + =A0 + =A0 =A0 =A0 =A0 =A0 l_ld=3D"0xe4eefc"/> > + =A0 + =A0 =A0 =A0 =A0 =A0 l_ld=3D"0x152350"/> > + > +@end smallexample > + > =A0The format of a library list is described by this DTD: > > =A0@smallexample > =A0 > =A0 > =A0 > + > =A0 > =A0 > + > + > + > =A0 > =A0 > =A0 > =A0 > =A0@end smallexample > > -In addition, segments and section descriptors cannot be mixed within a > -single library element, and you must supply at least one segment or > -section for each library. > +In addition, segments, section and SVR4 descriptors cannot be mixed > +within a single library element, and you must supply at least one > +segment or section or both @code{l_addr} and @code{l_ld} for each librar= y. > > =A0@node Memory Map Format > =A0@section Memory Map Format > --- a/gdb/features/library-list.dtd > +++ b/gdb/features/library-list.dtd > @@ -7,9 +7,13 @@ > =A0 > =A0 > =A0 > + > > =A0 > =A0 > + > + > + > > =A0 > =A0 > --- a/gdb/gdbserver/linux-low.c > +++ b/gdb/gdbserver/linux-low.c > @@ -4906,6 +4906,377 @@ linux_emit_ops (void) > =A0 =A0 return NULL; > =A0} > > +/* Extract &phdr and num_phdr in the inferior. =A0Return 0 on success. = =A0*/ > + > +static int > +get_phdr_phnum_from_proc_auxv (const int pid, const int is_elf64, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0CORE_ADDR *p= hdr_memaddr, int *num_phdr) > +{ > + =A0char filename[PATH_MAX]; > + =A0int fd; > + =A0const int auxv_size =3D is_elf64 > + =A0 =A0? sizeof (Elf64_auxv_t) : sizeof (Elf32_auxv_t); > + =A0char buf[sizeof (Elf64_auxv_t)]; =A0/* The larger of the two. =A0*/ > + > + =A0xsnprintf (filename, sizeof filename, "/proc/%d/auxv", pid); > + > + =A0fd =3D open (filename, O_RDONLY); > + =A0if (fd < 0) > + =A0 =A0return 1; > + > + =A0*phdr_memaddr =3D 0; > + =A0*num_phdr =3D 0; > + =A0while (read (fd, buf, auxv_size) =3D=3D auxv_size > + =A0 =A0 =A0 =A0&& (*phdr_memaddr =3D=3D 0 || *num_phdr =3D=3D 0)) > + =A0 =A0{ > + =A0 =A0 =A0if (is_elf64) > + =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 Elf64_auxv_t *const aux =3D (Elf64_auxv_t *) buf; > + > + =A0 =A0 =A0 =A0 switch (aux->a_type) > + =A0 =A0 =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 =A0 case AT_PHDR: > + =A0 =A0 =A0 =A0 =A0 =A0 *phdr_memaddr =3D aux->a_un.a_val; > + =A0 =A0 =A0 =A0 =A0 =A0 break; > + =A0 =A0 =A0 =A0 =A0 case AT_PHNUM: > + =A0 =A0 =A0 =A0 =A0 =A0 *num_phdr =3D aux->a_un.a_val; > + =A0 =A0 =A0 =A0 =A0 =A0 break; > + =A0 =A0 =A0 =A0 =A0 } > + =A0 =A0 =A0 } > + =A0 =A0 =A0else > + =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 Elf32_auxv_t *const aux =3D (Elf32_auxv_t *) buf; > + > + =A0 =A0 =A0 =A0 switch (aux->a_type) > + =A0 =A0 =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 =A0 case AT_PHDR: > + =A0 =A0 =A0 =A0 =A0 =A0 *phdr_memaddr =3D aux->a_un.a_val; > + =A0 =A0 =A0 =A0 =A0 =A0 break; > + =A0 =A0 =A0 =A0 =A0 case AT_PHNUM: > + =A0 =A0 =A0 =A0 =A0 =A0 *num_phdr =3D aux->a_un.a_val; > + =A0 =A0 =A0 =A0 =A0 =A0 break; > + =A0 =A0 =A0 =A0 =A0 } > + =A0 =A0 =A0 } > + =A0 =A0} > + > + =A0close (fd); > + > + =A0if (*phdr_memaddr =3D=3D 0 || *num_phdr =3D=3D 0) > + =A0 =A0{ > + =A0 =A0 =A0warning ("Unexpected missing AT_PHDR and/or AT_PHNUM: " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0"phdr_memaddr =3D %ld, phdr_num =3D %d", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0(long) *phdr_memaddr, *num_phdr); > + =A0 =A0 =A0return 2; > + =A0 =A0} > + > + =A0return 0; > +} > + > +/* Return &_DYNAMIC (via PT_DYNAMIC) in the inferior, or 0 if not presen= t. =A0*/ > + > +static CORE_ADDR > +get_dynamic (const int pid, const int is_elf64) > +{ > + =A0CORE_ADDR phdr_memaddr, relocation; > + =A0int num_phdr, i; > + =A0unsigned char *phdr_buf; > + =A0const int phdr_size =3D is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf= 32_Phdr); > + > + =A0if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &nu= m_phdr)) > + =A0 =A0return 0; > + > + =A0gdb_assert (num_phdr < 100); =A0/* Basic sanity check. =A0*/ > + =A0phdr_buf =3D alloca (num_phdr * phdr_size); > + > + =A0if (linux_read_memory (phdr_memaddr, phdr_buf, num_phdr * phdr_size)) > + =A0 =A0return 0; > + > + =A0/* Compute relocation: it is expected to be 0 for "regular" executab= les, > + =A0 =A0 non-zero for PIE ones. =A0*/ > + =A0relocation =3D -1; > + =A0for (i =3D 0; relocation =3D=3D -1 && i < num_phdr; i++) > + =A0 =A0if (is_elf64) > + =A0 =A0 =A0{ > + =A0 =A0 =A0 Elf64_Phdr *const p =3D (Elf64_Phdr *) (phdr_buf + i * phdr= _size); > + > + =A0 =A0 =A0 if (p->p_type =3D=3D PT_PHDR) > + =A0 =A0 =A0 =A0 relocation =3D phdr_memaddr - p->p_vaddr; > + =A0 =A0 =A0} > + =A0 =A0else > + =A0 =A0 =A0{ > + =A0 =A0 =A0 Elf32_Phdr *const p =3D (Elf32_Phdr *) (phdr_buf + i * phdr= _size); > + > + =A0 =A0 =A0 if (p->p_type =3D=3D PT_PHDR) > + =A0 =A0 =A0 =A0 relocation =3D phdr_memaddr - p->p_vaddr; > + =A0 =A0 =A0} > + > + =A0if (relocation =3D=3D -1) > + =A0 =A0{ > + =A0 =A0 =A0warning ("Unexpected missing PT_PHDR"); > + =A0 =A0 =A0return 0; > + =A0 =A0} > + > + =A0for (i =3D 0; i < num_phdr; i++) > + =A0 =A0{ > + =A0 =A0 =A0if (is_elf64) > + =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 Elf64_Phdr *const p =3D (Elf64_Phdr *) (phdr_buf + i * = phdr_size); > + > + =A0 =A0 =A0 =A0 if (p->p_type =3D=3D PT_DYNAMIC) > + =A0 =A0 =A0 =A0 =A0 return p->p_vaddr + relocation; > + =A0 =A0 =A0 } > + =A0 =A0 =A0else > + =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 Elf32_Phdr *const p =3D (Elf32_Phdr *) (phdr_buf + i * = phdr_size); > + > + =A0 =A0 =A0 =A0 if (p->p_type =3D=3D PT_DYNAMIC) > + =A0 =A0 =A0 =A0 =A0 return p->p_vaddr + relocation; > + =A0 =A0 =A0 } > + =A0 =A0} > + > + =A0return 0; > +} > + > +/* Return &_r_debug in the inferior, or -1 if not present. =A0Return val= ue > + =A0 can be 0 if the inferior does not yet have the library list initial= ized. =A0*/ > + > +static CORE_ADDR > +get_r_debug (const int pid, const int is_elf64) > +{ > + =A0CORE_ADDR dynamic_memaddr; > + =A0const int dyn_size =3D is_elf64 ? sizeof (Elf64_Dyn) : sizeof (Elf32= _Dyn); > + =A0unsigned char buf[sizeof (Elf64_Dyn)]; =A0/* The larger of the two. = =A0*/ > + > + =A0dynamic_memaddr =3D get_dynamic (pid, is_elf64); > + =A0if (dynamic_memaddr =3D=3D 0) > + =A0 =A0return (CORE_ADDR) -1; > + > + =A0while (linux_read_memory (dynamic_memaddr, buf, dyn_size) =3D=3D 0) > + =A0 =A0{ > + =A0 =A0 =A0if (is_elf64) > + =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 Elf64_Dyn *const dyn =3D (Elf64_Dyn *) buf; > + > + =A0 =A0 =A0 =A0 if (dyn->d_tag =3D=3D DT_DEBUG) > + =A0 =A0 =A0 =A0 =A0 return dyn->d_un.d_val; > + > + =A0 =A0 =A0 =A0 if (dyn->d_tag =3D=3D DT_NULL) > + =A0 =A0 =A0 =A0 =A0 break; > + =A0 =A0 =A0 } > + =A0 =A0 =A0else > + =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 Elf32_Dyn *const dyn =3D (Elf32_Dyn *) buf; > + > + =A0 =A0 =A0 =A0 if (dyn->d_tag =3D=3D DT_DEBUG) > + =A0 =A0 =A0 =A0 =A0 return dyn->d_un.d_val; > + > + =A0 =A0 =A0 =A0 if (dyn->d_tag =3D=3D DT_NULL) > + =A0 =A0 =A0 =A0 =A0 break; > + =A0 =A0 =A0 } > + > + =A0 =A0 =A0dynamic_memaddr +=3D dyn_size; > + =A0 =A0} > + > + =A0return (CORE_ADDR) -1; > +} > + > +/* Read one pointer from MEMADDR in the inferior. =A0*/ > + > +static int > +read_one_ptr (CORE_ADDR memaddr, CORE_ADDR *ptr, int ptr_size) > +{ > + =A0*ptr =3D 0; > + =A0return linux_read_memory (memaddr, (unsigned char *) ptr, ptr_size); > +} > + > +struct link_map_offsets > + =A0{ > + =A0 =A0/* Offset and size of r_debug.r_version. =A0*/ > + =A0 =A0int r_version_offset; > + > + =A0 =A0/* Offset and size of r_debug.r_map. =A0*/ > + =A0 =A0int r_map_offset; > + > + =A0 =A0/* Offset to l_addr field in struct link_map. =A0*/ > + =A0 =A0int l_addr_offset; > + > + =A0 =A0/* Offset to l_name field in struct link_map. =A0*/ > + =A0 =A0int l_name_offset; > + > + =A0 =A0/* Offset to l_ld field in struct link_map. =A0*/ > + =A0 =A0int l_ld_offset; > + > + =A0 =A0/* Offset to l_next field in struct link_map. =A0*/ > + =A0 =A0int l_next_offset; > + > + =A0 =A0/* Offset to l_prev field in struct link_map. =A0*/ > + =A0 =A0int l_prev_offset; > + =A0}; > + > +/* Construct qXfer:libraries:read reply. =A0*/ > + > +static int > +linux_qxfer_libraries (const char *annex, unsigned char *readbuf, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned const char *writebu= f, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0CORE_ADDR offset, int len) > +{ > + =A0char *document; > + =A0unsigned document_len; > + =A0struct process_info_private *const priv =3D current_process ()->priv= ate; > + =A0char filename[PATH_MAX]; > + =A0int pid, is_elf64; > + > + =A0static const struct link_map_offsets lmo_32bit_offsets =3D > + =A0 =A0{ > + =A0 =A0 =A00, =A0 =A0 /* r_version offset. */ > + =A0 =A0 =A04, =A0 =A0 /* r_debug.r_map offset. =A0*/ > + =A0 =A0 =A00, =A0 =A0 /* l_addr offset in link_map. =A0*/ > + =A0 =A0 =A04, =A0 =A0 /* l_name offset in link_map. =A0*/ > + =A0 =A0 =A08, =A0 =A0 /* l_ld offset in link_map. =A0*/ > + =A0 =A0 =A012, =A0 =A0/* l_next offset in link_map. =A0*/ > + =A0 =A0 =A016 =A0 =A0 /* l_prev offset in link_map. =A0*/ > + =A0 =A0}; > + > + =A0static const struct link_map_offsets lmo_64bit_offsets =3D > + =A0 =A0{ > + =A0 =A0 =A00, =A0 =A0 /* r_version offset. */ > + =A0 =A0 =A08, =A0 =A0 /* r_debug.r_map offset. =A0*/ > + =A0 =A0 =A00, =A0 =A0 /* l_addr offset in link_map. =A0*/ > + =A0 =A0 =A08, =A0 =A0 /* l_name offset in link_map. =A0*/ > + =A0 =A0 =A016, =A0 =A0/* l_ld offset in link_map. =A0*/ > + =A0 =A0 =A024, =A0 =A0/* l_next offset in link_map. =A0*/ > + =A0 =A0 =A032 =A0 =A0 /* l_prev offset in link_map. =A0*/ > + =A0 =A0}; > + =A0const struct link_map_offsets *lmo; > + > + =A0if (writebuf !=3D NULL) > + =A0 =A0return -2; > + =A0if (readbuf =3D=3D NULL) > + =A0 =A0return -1; > + > + =A0pid =3D lwpid_of (get_thread_lwp (current_inferior)); > + =A0xsnprintf (filename, sizeof filename, "/proc/%d/exe", pid); > + =A0is_elf64 =3D elf_64_file_p (filename); > + =A0lmo =3D is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets; > + > + =A0if (priv->r_debug =3D=3D 0) > + =A0 =A0priv->r_debug =3D get_r_debug (pid, is_elf64); > + > + =A0if (priv->r_debug =3D=3D (CORE_ADDR) -1 || priv->r_debug =3D=3D 0) > + =A0 =A0{ > + =A0 =A0 =A0document =3D xstrdup ("\n"); > + =A0 =A0} > + =A0else > + =A0 =A0{ > + =A0 =A0 =A0int allocated =3D 1024; > + =A0 =A0 =A0char *p; > + =A0 =A0 =A0const int ptr_size =3D is_elf64 ? 8 : 4; > + =A0 =A0 =A0CORE_ADDR lm_addr, lm_prev, l_name, l_addr, l_ld, l_next, l_= prev; > + =A0 =A0 =A0int r_version, header_done =3D 0; > + > + =A0 =A0 =A0document =3D xmalloc (allocated); > + =A0 =A0 =A0strcpy (document, " + =A0 =A0 =A0p =3D document + strlen (document); > + > + =A0 =A0 =A0r_version =3D 0; > + =A0 =A0 =A0if (linux_read_memory (priv->r_debug + lmo->r_version_offset, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(unsigned char *= ) &r_version, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sizeof (r_versio= n)) !=3D 0 > + =A0 =A0 =A0 =A0 || r_version !=3D 1) > + =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 warning ("unexpected r_debug version %d", r_version); > + =A0 =A0 =A0 =A0 goto done; > + =A0 =A0 =A0 } > + > + =A0 =A0 =A0if (read_one_ptr (priv->r_debug + lmo->r_map_offset, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &lm_addr, ptr_size) !=3D 0) > + =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 warning ("unable to read r_map from 0x%lx", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(long) priv->r_debug + lmo->r_map_of= fset); > + =A0 =A0 =A0 =A0 goto done; > + =A0 =A0 =A0 } > + > + =A0 =A0 =A0lm_prev =3D 0; > + =A0 =A0 =A0while (read_one_ptr (lm_addr + lmo->l_name_offset, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&l_name, ptr_size) = =3D=3D 0 > + =A0 =A0 =A0 =A0 =A0 =A0&& read_one_ptr (lm_addr + lmo->l_addr_offset, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &l_addr, ptr_si= ze) =3D=3D 0 > + =A0 =A0 =A0 =A0 =A0 =A0&& read_one_ptr (lm_addr + lmo->l_ld_offset, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &l_ld, ptr_size= ) =3D=3D 0 > + =A0 =A0 =A0 =A0 =A0 =A0&& read_one_ptr (lm_addr + lmo->l_prev_offset, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &l_prev, ptr_si= ze) =3D=3D 0 > + =A0 =A0 =A0 =A0 =A0 =A0&& read_one_ptr (lm_addr + lmo->l_next_offset, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &l_next, ptr_si= ze) =3D=3D 0) > + =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 unsigned char libname[PATH_MAX]; > + > + =A0 =A0 =A0 =A0 if (lm_prev !=3D l_prev) > + =A0 =A0 =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 =A0 =A0 warning ("Corrupted shared library list: 0x%lx = !=3D 0x%lx", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(long) lm_prev, (long) l_pre= v); > + =A0 =A0 =A0 =A0 =A0 =A0 break; > + =A0 =A0 =A0 =A0 =A0 } > + > + =A0 =A0 =A0 =A0 /* Not checking for error because reading may stop befo= re > + =A0 =A0 =A0 =A0 =A0 =A0we've got PATH_MAX worth of characters. =A0*/ > + =A0 =A0 =A0 =A0 libname[0] =3D '\0'; > + =A0 =A0 =A0 =A0 linux_read_memory (l_name, libname, sizeof (libname) - = 1); > + =A0 =A0 =A0 =A0 libname[sizeof (libname) - 1] =3D '\0'; > + =A0 =A0 =A0 =A0 if (libname[0] !=3D '\0') > + =A0 =A0 =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 =A0 =A0 size_t len =3D strlen ((char *) libname); > + =A0 =A0 =A0 =A0 =A0 =A0 char *name; > + > + =A0 =A0 =A0 =A0 =A0 =A0 if (!header_done) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Terminate ` + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *p++ =3D '>'; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 header_done =3D 1; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } > + > + =A0 =A0 =A0 =A0 =A0 =A0 while (allocated < p - document + len + 100) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Expand to guarantee sufficient stora= ge. =A0*/ > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 uintptr_t document_len =3D p - document; > + > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 document =3D xrealloc (document, 2 * al= located); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 allocated *=3D 2; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 p =3D document + document_len; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } > + > + =A0 =A0 =A0 =A0 =A0 =A0 name =3D xml_escape_text ((char *) libname); > + =A0 =A0 =A0 =A0 =A0 =A0 p +=3D sprintf (p, " + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"l_addr=3D\"= 0x%lx\" l_ld=3D\"0x%lx\"/>", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 name, (unsigned lon= g) lm_addr, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (unsigned long) l_a= ddr, (unsigned long) l_ld); > + =A0 =A0 =A0 =A0 =A0 =A0 free (name); > + =A0 =A0 =A0 =A0 =A0 } > + =A0 =A0 =A0 =A0 else if (lm_prev =3D=3D 0) > + =A0 =A0 =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 =A0 =A0 sprintf (p, " main-lm=3D\"0x%lx\"", (unsigned l= ong) lm_addr); > + =A0 =A0 =A0 =A0 =A0 =A0 p =3D p + strlen (p); > + =A0 =A0 =A0 =A0 =A0 } > + > + =A0 =A0 =A0 =A0 if (l_next =3D=3D 0) > + =A0 =A0 =A0 =A0 =A0 break; > + > + =A0 =A0 =A0 =A0 lm_prev =3D lm_addr; > + =A0 =A0 =A0 =A0 lm_addr =3D l_next; > + =A0 =A0 =A0 } > + =A0 =A0done: > + =A0 =A0 =A0strcpy (p, ""); > + =A0 =A0} > + > + =A0document_len =3D strlen (document + offset); > + =A0if (len > document_len) > + =A0 =A0len =3D document_len; > + > + =A0memcpy (readbuf, document + offset, len); > + =A0xfree (document); > + > + =A0return len; > +} > + > =A0static struct target_ops linux_target_ops =3D { > =A0 linux_create_inferior, > =A0 linux_attach, > @@ -4965,7 +5336,8 @@ static struct target_ops linux_target_ops =3D { > =A0 linux_cancel_breakpoints, > =A0 linux_stabilize_threads, > =A0 linux_install_fast_tracepoint_jump_pad, > - =A0linux_emit_ops > + =A0linux_emit_ops, > + =A0linux_qxfer_libraries > =A0}; > > =A0static void > --- a/gdb/gdbserver/linux-low.h > +++ b/gdb/gdbserver/linux-low.h > @@ -56,6 +56,9 @@ struct process_info_private > =A0 /* libthread_db-specific additions. =A0Not NULL if this process has l= oaded > =A0 =A0 =A0thread_db, and it is active. =A0*/ > =A0 struct thread_db *thread_db; > + > + =A0/* &_r_debug. =A00 if not yet determined. =A0-1 if no PT_DYNAMIC in = Phdrs. =A0*/ > + =A0CORE_ADDR r_debug; > =A0}; > > =A0struct lwp_info; > --- a/gdb/gdbserver/server.c > +++ b/gdb/gdbserver/server.c > @@ -917,6 +917,9 @@ handle_qxfer_libraries (const char *annex, > =A0 if (annex[0] !=3D '\0' || !target_running ()) > =A0 =A0 return -1; > > + =A0if (the_target->qxfer_libraries !=3D NULL) > + =A0 =A0return the_target->qxfer_libraries (annex, readbuf, writebuf, of= fset, len); > + > =A0 /* Over-estimate the necessary memory. =A0Assume that every character > =A0 =A0 =A0in the library name must be escaped. =A0*/ > =A0 total_len =3D 64; > --- a/gdb/gdbserver/target.h > +++ b/gdb/gdbserver/target.h > @@ -377,6 +377,11 @@ struct target_ops > =A0 /* Return the bytecode operations vector for the current inferior. > =A0 =A0 =A0Returns NULL if bytecode compilation is not supported. =A0*/ > =A0 struct emit_ops *(*emit_ops) (void); > + > + =A0/* Read solib info. =A0*/ > + =A0int (*qxfer_libraries) (const char *annex, unsigned char *readbuf, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned const char *wr= itebuf, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 CORE_ADDR offset, int l= en); > =A0}; > > =A0extern struct target_ops *the_target; > --- a/gdb/solib-svr4.c > +++ b/gdb/solib-svr4.c > @@ -916,6 +916,104 @@ open_symbol_file_object (void *from_ttyp) > =A0 return 1; > =A0} > > +/* Data exchange structure for the XML parser as returned by > + =A0 svr4_current_sos_via_xfer_libraries. =A0*/ > + > +struct svr4_library_list > +{ > + =A0struct so_list *head, **tailp; > + =A0CORE_ADDR main_lm; > +}; > + > +#ifdef HAVE_LIBEXPAT > + > +#include "xml-support.h" > + > +/* Handle the start of a element. =A0Note: new elements are ad= ded > + =A0 at the tail of the list, keeping the list in order. =A0*/ > + > +static void > +library_list_start_library (struct gdb_xml_parser *parser, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 const struct gdb_xm= l_element *element, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 void *user_data, VE= C(gdb_xml_value_s) *attributes) > +{ > + =A0struct svr4_library_list *list =3D user_data; > + =A0const char *name =3D xml_find_attribute (attributes, "name")->value; > + =A0ULONGEST *lmp =3D xml_find_attribute (attributes, "lm")->value; > + =A0ULONGEST *l_addrp =3D xml_find_attribute (attributes, "l_addr")->val= ue; > + =A0ULONGEST *l_ldp =3D xml_find_attribute (attributes, "l_ld")->value; > + =A0struct so_list *new_elem; > + > + =A0new_elem =3D XZALLOC (struct so_list); > + =A0new_elem->lm_info =3D XZALLOC (struct lm_info); > + =A0new_elem->lm_info->lm_addr =3D *lmp; > + =A0new_elem->lm_info->l_addr_inferior =3D *l_addrp; > + =A0new_elem->lm_info->l_ld =3D *l_ldp; > + > + =A0strncpy (new_elem->so_name, name, sizeof (new_elem->so_name) - 1); > + =A0new_elem->so_name[sizeof (new_elem->so_name) - 1] =3D 0; > + =A0strcpy (new_elem->so_original_name, new_elem->so_name); > + > + =A0*list->tailp =3D new_elem; > + =A0list->tailp =3D &new_elem->next; > +} > + > +/* Handle the start of a element. =A0*/ > + > +static void > +library_list_start_list (struct gdb_xml_parser *parser, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const struct gdb_xml_ele= ment *element, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0void *user_data, VEC(gdb= _xml_value_s) *attributes) > +{ > + =A0struct svr4_library_list *list =3D user_data; > + =A0char *version =3D xml_find_attribute (attributes, "version")->value; > + =A0struct gdb_xml_value *main_lm =3D xml_find_attribute (attributes, "m= ain-lm"); > + > + =A0if (strcmp (version, "1.0") !=3D 0) > + =A0 =A0gdb_xml_error (parser, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0_("Library list has unsupported vers= ion \"%s\""), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0version); > + > + =A0if (main_lm) > + =A0 =A0list->main_lm =3D *(ULONGEST *) main_lm->value; > +} > + > +/* The allowed elements and attributes for an XML library list. > + =A0 The root element is a . =A0*/ > + > +static const struct gdb_xml_attribute library_attributes[] =3D > +{ > + =A0{ "name", GDB_XML_AF_NONE, NULL, NULL }, > + =A0{ "lm", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, > + =A0{ "l_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, > + =A0{ "l_ld", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, > + =A0{ NULL, GDB_XML_AF_NONE, NULL, NULL } > +}; > + > +static const struct gdb_xml_element library_list_children[] =3D > +{ > + =A0{ > + =A0 =A0"library", library_attributes, NULL, > + =A0 =A0GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL, > + =A0 =A0library_list_start_library, NULL > + =A0}, > + =A0{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } > +}; > + > +static const struct gdb_xml_attribute library_list_attributes[] =3D > +{ > + =A0{ "version", GDB_XML_AF_NONE, NULL, NULL }, > + =A0{ "main-lm", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL = }, > + =A0{ NULL, GDB_XML_AF_NONE, NULL, NULL } > +}; > + > +static const struct gdb_xml_element library_list_elements[] =3D > +{ > + =A0{ "library-list", library_list_attributes, library_list_children, > + =A0 =A0GDB_XML_EF_NONE, library_list_start_list, NULL }, > + =A0{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } > +}; > + > =A0/* Implementation for target_so_ops.free_so. =A0*/ > > =A0static void > @@ -940,6 +1038,69 @@ svr4_free_library_list (void *p_list) > =A0 =A0 } > =A0} > > +/* Parse qXfer:libraries:read packet into *SO_LIST_RETURN. =A0Return 1 if > + > + =A0 Return 0 if packet not supported, *SO_LIST_RETURN is not modified i= n such > + =A0 case. =A0Return 1 if *SO_LIST_RETURN contains the library list, it = may be > + =A0 empty, caller is responsible for freeing all its entries. =A0*/ > + > +static int > +svr4_parse_libraries (const char *document, struct svr4_library_list *li= st) > +{ > + =A0struct cleanup *back_to =3D make_cleanup (svr4_free_library_list, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 &list->head); > + > + =A0memset (list, 0, sizeof (*list)); > + =A0list->tailp =3D &list->head; > + =A0if (gdb_xml_parse_quick (_("target library list"), "library-list.dtd= ", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0library_list_element= s, document, list) =3D=3D 0) > + =A0 =A0{ > + =A0 =A0 =A0/* Parsed successfully, keep the result. =A0*/ > + =A0 =A0 =A0discard_cleanups (back_to); > + =A0 =A0 =A0return 1; > + =A0 =A0} > + > + =A0do_cleanups (back_to); > + =A0return 0; > +} > + > +/* Attempt to get so_list from target via qXfer:libraries:read packet. > + > + =A0 Return 0 if packet not supported, *SO_LIST_RETURN is not modified i= n such > + =A0 case. =A0Return 1 if *SO_LIST_RETURN contains the library list, it = may be > + =A0 empty, caller is responsible for freeing all its entries. =A0*/ > + > +static int > +svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list) > +{ > + =A0char *library_document; > + =A0int result; > + =A0struct cleanup *back_to; > + > + =A0/* Fetch the list of shared libraries. =A0*/ > + =A0library_document =3D target_read_stralloc (¤t_target, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0TARGET_OBJECT_LIBRARIES, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0NULL); > + =A0if (library_document =3D=3D NULL) > + =A0 =A0return 0; > + > + =A0back_to =3D make_cleanup (xfree, library_document); > + =A0result =3D svr4_parse_libraries (library_document, list); > + =A0do_cleanups (back_to); > + > + =A0return result; > +} > + > +#else > + > +static int > +svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list) > +{ > + =A0return 0; > +} > + > +#endif > + > =A0/* If no shared library information is available from the dynamic > =A0 =A0linker, build a fallback list from other sources. =A0*/ > > @@ -999,7 +1160,9 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***l= ink_ptr_ptr, > > =A0 =A0 =A0 if (new->lm_info->l_prev !=3D prev_lm) > =A0 =A0 =A0 =A0{ > - =A0 =A0 =A0 =A0 warning (_("Corrupted shared library list")); > + =A0 =A0 =A0 =A0 warning (_("Corrupted shared library list: %s !=3D %s"), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0paddress (target_gdbarch, prev_lm), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0paddress (target_gdbarch, new->lm_in= fo->l_prev)); > =A0 =A0 =A0 =A0 =A0do_cleanups (old_chain); > =A0 =A0 =A0 =A0 =A0break; > =A0 =A0 =A0 =A0} > @@ -1060,6 +1223,18 @@ svr4_current_sos (void) > =A0 struct svr4_info *info; > =A0 struct cleanup *back_to; > =A0 int ignore_first; > + =A0struct svr4_library_list library_list; > + > + =A0if (svr4_current_sos_via_xfer_libraries (&library_list)) > + =A0 =A0{ > + =A0 =A0 =A0if (library_list.main_lm) > + =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 info =3D get_svr4_info (); > + =A0 =A0 =A0 =A0 info->main_lm_addr =3D library_list.main_lm; > + =A0 =A0 =A0 } > + > + =A0 =A0 =A0return library_list.head ? library_list.head : svr4_default_= sos (); > + =A0 =A0} > > =A0 info =3D get_svr4_info (); > > --- a/gdb/testsuite/gdb.base/solib-corrupted.exp > +++ b/gdb/testsuite/gdb.base/solib-corrupted.exp > @@ -17,6 +17,12 @@ if {[skip_shlib_tests]} { > =A0 =A0 return 0 > =A0} > > +if {[is_remote target]} { > + =A0 =A0# gdbserver prints the warning message but expect is parsing onl= y the GDB > + =A0 =A0# output, not the gdbserver output. > + =A0 =A0return 0 > +} > + > =A0set testfile "solib-corrupted" > =A0set srcfile start.c > > @@ -47,4 +53,4 @@ gdb_test_multiple "p/x _r_debug->r_map->l_next =3D _r_d= ebug->r_map" $test { > =A0 =A0 =A0 =A0pass $test > =A0 =A0 } > =A0} > -gdb_test "info sharedlibrary" "warning: Corrupted shared library list\r\= n.*" "corrupted list" > +gdb_test "info sharedlibrary" "warning: Corrupted shared library list: .= *" "corrupted list" > --=20 Thanks, Daniel