+2013-05-15  Joel Brobecker  <brobecker@adacore.com>
+
+       * gdbarch.sh (core_xfer_shared_libraries_aix): New method.
+       * gdbarch.h, gdbarch.c: Regenerate.
+       * corelow.c (core_xfer_partial): Add TARGET_OBJECT_LIBRARIES_AIX
+       handling.
+
+       * rs6000-aix-tdep.h: New file.
+       * Makefile.in (HFILES_NO_SRCDIR): Add rs6000-aix-tdep.h.
+       * rs6000-aix-tdep.c: Include "rs6000-aix-tdep.h" and
+       "xml-utils.h".
+       (struct field_info, struct ld_info_desc): New types.
+       (ld_info32_desc, ld_info64_desc): New static constants.
+       (struct ld_info): New type.
+       (rs6000_aix_extract_ld_info): New function.
+       (rs6000_aix_shared_library_to_xml): Likewise.
+       (rs6000_aix_ld_info_to_xml): Likewise.
+       (rs6000_aix_core_xfer_shared_libraries_aix): Likewise.
+       (rs6000_aix_init_osabi): Add call to
+       set_gdbarch_core_xfer_shared_libraries_aix.
+       * rs6000-nat.c: Add "rs6000-aix-tdep.h" include.
+       Remove "xml-utils.h" include.
+       (LdInfo): Delete typedef.
+       (ARCH64_DECL, LDI_FIELD, LDI_NEXT, LDI_FD, LDI_FILENAME):
+       Delete macros.
+       (rs6000_ptrace_ldinfo): Change return type to gdb_byte *.
+       Adjust code accordingly.
+       (rs6000_core_ldinfo): Delete, folded into
+       rs6000_aix_core_xfer_shared_libraries_aix.
+       (rs6000_xfer_shared_library): Delete.
+       (rs6000_xfer_shared_libraries): Reimplement.
+
 2013-05-15  Markus Metzger  <markus.t.metzger@intel.com>
 
        * record.c (record_goto_cmdlist): New.
 
 sparc64-tdep.h monitor.h ppcobsd-tdep.h srec.h solib-pa64.h \
 coff-pe-read.h parser-defs.h gdb_ptrace.h mips-linux-tdep.h \
 m68k-tdep.h spu-tdep.h jv-lang.h environ.h solib-irix.h amd64-tdep.h \
-doublest.h regset.h hppa-tdep.h ppc-linux-tdep.h ppc64-tdep.h rs6000-tdep.h \
+doublest.h regset.h hppa-tdep.h ppc-linux-tdep.h ppc64-tdep.h \
+rs6000-tdep.h rs6000-aix-tdep.h \
 common/gdb_locale.h common/gdb_dirent.h arch-utils.h trad-frame.h gnu-nat.h \
 language.h nbsd-tdep.h solib-svr4.h \
 macroexp.h ui-file.h regcache.h tracepoint.h i386-tdep.h \
 
        }
       /* FALL THROUGH */
 
+    case TARGET_OBJECT_LIBRARIES_AIX:
+      if (core_gdbarch
+         && gdbarch_core_xfer_shared_libraries_aix_p (core_gdbarch))
+       {
+         if (writebuf)
+           return -1;
+         return
+           gdbarch_core_xfer_shared_libraries_aix (core_gdbarch,
+                                                   readbuf, offset, len);
+       }
+      /* FALL THROUGH */
+
     case TARGET_OBJECT_SPU:
       if (readbuf && annex)
        {
 
   gdbarch_elfcore_write_linux_prpsinfo_ftype *elfcore_write_linux_prpsinfo;
   gdbarch_find_memory_regions_ftype *find_memory_regions;
   gdbarch_core_xfer_shared_libraries_ftype *core_xfer_shared_libraries;
+  gdbarch_core_xfer_shared_libraries_aix_ftype *core_xfer_shared_libraries_aix;
   gdbarch_core_pid_to_str_ftype *core_pid_to_str;
   const char * gcore_bfd_target;
   int vtable_function_descriptors;
   0,  /* elfcore_write_linux_prpsinfo */
   0,  /* find_memory_regions */
   0,  /* core_xfer_shared_libraries */
+  0,  /* core_xfer_shared_libraries_aix */
   0,  /* core_pid_to_str */
   0,  /* gcore_bfd_target */
   0,  /* vtable_function_descriptors */
   /* Skip verify of elfcore_write_linux_prpsinfo, has predicate.  */
   /* Skip verify of find_memory_regions, has predicate.  */
   /* Skip verify of core_xfer_shared_libraries, has predicate.  */
+  /* Skip verify of core_xfer_shared_libraries_aix, has predicate.  */
   /* Skip verify of core_pid_to_str, has predicate.  */
   /* Skip verify of gcore_bfd_target, has predicate.  */
   /* Skip verify of vtable_function_descriptors, invalid_p == 0 */
   fprintf_unfiltered (file,
                       "gdbarch_dump: core_xfer_shared_libraries = <%s>\n",
                       host_address_to_string (gdbarch->core_xfer_shared_libraries));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_core_xfer_shared_libraries_aix_p() = %d\n",
+                      gdbarch_core_xfer_shared_libraries_aix_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: core_xfer_shared_libraries_aix = <%s>\n",
+                      host_address_to_string (gdbarch->core_xfer_shared_libraries_aix));
   fprintf_unfiltered (file,
                       "gdbarch_dump: decr_pc_after_break = %s\n",
                       core_addr_to_string_nz (gdbarch->decr_pc_after_break));
   gdbarch->core_xfer_shared_libraries = core_xfer_shared_libraries;
 }
 
+int
+gdbarch_core_xfer_shared_libraries_aix_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->core_xfer_shared_libraries_aix != NULL;
+}
+
+LONGEST
+gdbarch_core_xfer_shared_libraries_aix (struct gdbarch *gdbarch, gdb_byte *readbuf, ULONGEST offset, LONGEST len)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->core_xfer_shared_libraries_aix != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_core_xfer_shared_libraries_aix called\n");
+  return gdbarch->core_xfer_shared_libraries_aix (gdbarch, readbuf, offset, len);
+}
+
+void
+set_gdbarch_core_xfer_shared_libraries_aix (struct gdbarch *gdbarch,
+                                            gdbarch_core_xfer_shared_libraries_aix_ftype core_xfer_shared_libraries_aix)
+{
+  gdbarch->core_xfer_shared_libraries_aix = core_xfer_shared_libraries_aix;
+}
+
 int
 gdbarch_core_pid_to_str_p (struct gdbarch *gdbarch)
 {
 
 extern LONGEST gdbarch_core_xfer_shared_libraries (struct gdbarch *gdbarch, gdb_byte *readbuf, ULONGEST offset, LONGEST len);
 extern void set_gdbarch_core_xfer_shared_libraries (struct gdbarch *gdbarch, gdbarch_core_xfer_shared_libraries_ftype *core_xfer_shared_libraries);
 
+/* Read offset OFFSET of TARGET_OBJECT_LIBRARIES_AIX formatted shared
+   libraries list from core file into buffer READBUF with length LEN. */
+
+extern int gdbarch_core_xfer_shared_libraries_aix_p (struct gdbarch *gdbarch);
+
+typedef LONGEST (gdbarch_core_xfer_shared_libraries_aix_ftype) (struct gdbarch *gdbarch, gdb_byte *readbuf, ULONGEST offset, LONGEST len);
+extern LONGEST gdbarch_core_xfer_shared_libraries_aix (struct gdbarch *gdbarch, gdb_byte *readbuf, ULONGEST offset, LONGEST len);
+extern void set_gdbarch_core_xfer_shared_libraries_aix (struct gdbarch *gdbarch, gdbarch_core_xfer_shared_libraries_aix_ftype *core_xfer_shared_libraries_aix);
+
 /* How the core target converts a PTID from a core file to a string. */
 
 extern int gdbarch_core_pid_to_str_p (struct gdbarch *gdbarch);
 
 # core file into buffer READBUF with length LEN.
 M:LONGEST:core_xfer_shared_libraries:gdb_byte *readbuf, ULONGEST offset, LONGEST len:readbuf, offset, len
 
+# Read offset OFFSET of TARGET_OBJECT_LIBRARIES_AIX formatted shared
+# libraries list from core file into buffer READBUF with length LEN.
+M:LONGEST:core_xfer_shared_libraries_aix:gdb_byte *readbuf, ULONGEST offset, LONGEST len:readbuf, offset, len
+
 # How the core target converts a PTID from a core file to a string.
 M:char *:core_pid_to_str:ptid_t ptid:ptid
 
 
 #include "breakpoint.h"
 #include "rs6000-tdep.h"
 #include "ppc-tdep.h"
+#include "rs6000-aix-tdep.h"
 #include "exceptions.h"
 #include "xcoffread.h"
 #include "solib.h"
 #include "solib-aix.h"
+#include "xml-utils.h"
 
 /* If the kernel has to deliver a signal, it pushes a sigcontext
    structure on the stack and then calls the signal handler, passing
   return GDB_OSABI_AIX;
 }
 
+/* A structure encoding the offset and size of a field within
+   a struct.  */
+
+struct field_info
+{
+  int offset;
+  int size;
+};
+
+/* A structure describing the layout of all the fields of interest
+   in AIX's struct ld_info.  Each field in this struct corresponds
+   to the field of the same name in struct ld_info.  */
+
+struct ld_info_desc
+{
+  struct field_info ldinfo_next;
+  struct field_info ldinfo_fd;
+  struct field_info ldinfo_textorg;
+  struct field_info ldinfo_textsize;
+  struct field_info ldinfo_dataorg;
+  struct field_info ldinfo_datasize;
+  struct field_info ldinfo_filename;
+};
+
+/* The following data has been generated by compiling and running
+   the following program on AIX 5.3.  */
+
+#if 0
+    #include <stddef.h>
+    #include <stdio.h>
+    #define __LDINFO_PTRACE32__
+    #define __LDINFO_PTRACE64__
+    #include <sys/ldr.h>
+
+    #define pinfo(type,member)              \
+      {                                         \
+        struct type ldi = {0};                  \
+                                                \
+        printf ("  {%d, %d},\t/* %s */\n",      \
+                offsetof (struct type, member), \
+                sizeof (ldi.member),            \
+                #member);                       \
+      }                                         \
+      while (0)
+
+    int
+    main (void)
+    {
+      printf ("static const struct ld_info_desc ld_info32_desc =\n{\n");
+      pinfo (__ld_info32, ldinfo_next);
+      pinfo (__ld_info32, ldinfo_fd);
+      pinfo (__ld_info32, ldinfo_textorg);
+      pinfo (__ld_info32, ldinfo_textsize);
+      pinfo (__ld_info32, ldinfo_dataorg);
+      pinfo (__ld_info32, ldinfo_datasize);
+      pinfo (__ld_info32, ldinfo_filename);
+      printf ("};\n");
+
+      printf ("\n");
+
+      printf ("static const struct ld_info_desc ld_info64_desc =\n{\n");
+      pinfo (__ld_info64, ldinfo_next);
+      pinfo (__ld_info64, ldinfo_fd);
+      pinfo (__ld_info64, ldinfo_textorg);
+      pinfo (__ld_info64, ldinfo_textsize);
+      pinfo (__ld_info64, ldinfo_dataorg);
+      pinfo (__ld_info64, ldinfo_datasize);
+      pinfo (__ld_info64, ldinfo_filename);
+      printf ("};\n");
+
+      return 0;
+    }
+#endif /* 0 */
+
+/* Layout of the 32bit version of struct ld_info.  */
+
+static const struct ld_info_desc ld_info32_desc =
+{
+  {0, 4},       /* ldinfo_next */
+  {4, 4},       /* ldinfo_fd */
+  {8, 4},       /* ldinfo_textorg */
+  {12, 4},      /* ldinfo_textsize */
+  {16, 4},      /* ldinfo_dataorg */
+  {20, 4},      /* ldinfo_datasize */
+  {24, 2},      /* ldinfo_filename */
+};
+
+/* Layout of the 64bit version of struct ld_info.  */
+
+static const struct ld_info_desc ld_info64_desc =
+{
+  {0, 4},       /* ldinfo_next */
+  {8, 4},       /* ldinfo_fd */
+  {16, 8},      /* ldinfo_textorg */
+  {24, 8},      /* ldinfo_textsize */
+  {32, 8},      /* ldinfo_dataorg */
+  {40, 8},      /* ldinfo_datasize */
+  {48, 2},      /* ldinfo_filename */
+};
+
+/* A structured representation of one entry read from the ld_info
+   binary data provided by the AIX loader.  */
+
+struct ld_info
+{
+  ULONGEST next;
+  int fd;
+  CORE_ADDR textorg;
+  ULONGEST textsize;
+  CORE_ADDR dataorg;
+  ULONGEST datasize;
+  char *filename;
+  char *member_name;
+};
+
+/* Return a struct ld_info object corresponding to the entry at
+   LDI_BUF.
+
+   Note that the filename and member_name strings still point
+   to the data in LDI_BUF.  So LDI_BUF must not be deallocated
+   while the struct ld_info object returned is in use.  */
+
+static struct ld_info
+rs6000_aix_extract_ld_info (struct gdbarch *gdbarch,
+                           const gdb_byte *ldi_buf)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
+  const struct ld_info_desc desc
+    = tdep->wordsize == 8 ? ld_info64_desc : ld_info32_desc;
+  struct ld_info info;
+
+  info.next = extract_unsigned_integer (ldi_buf + desc.ldinfo_next.offset,
+                                       desc.ldinfo_next.size,
+                                       byte_order);
+  info.fd = extract_signed_integer (ldi_buf + desc.ldinfo_fd.offset,
+                                   desc.ldinfo_fd.size,
+                                   byte_order);
+  info.textorg = extract_typed_address (ldi_buf + desc.ldinfo_textorg.offset,
+                                       ptr_type);
+  info.textsize
+    = extract_unsigned_integer (ldi_buf + desc.ldinfo_textsize.offset,
+                               desc.ldinfo_textsize.size,
+                               byte_order);
+  info.dataorg = extract_typed_address (ldi_buf + desc.ldinfo_dataorg.offset,
+                                       ptr_type);
+  info.datasize
+    = extract_unsigned_integer (ldi_buf + desc.ldinfo_datasize.offset,
+                               desc.ldinfo_datasize.size,
+                               byte_order);
+  info.filename = (char *) ldi_buf + desc.ldinfo_filename.offset;
+  info.member_name = info.filename + strlen (info.filename) + 1;
+
+  return info;
+}
+
+/* Append to OBJSTACK an XML string description of the shared library
+   corresponding to LDI, following the TARGET_OBJECT_LIBRARIES_AIX
+   format.  */
+
+static void
+rs6000_aix_shared_library_to_xml (struct ld_info *ldi,
+                                 struct obstack *obstack)
+{
+  char *p;
+
+  obstack_grow_str (obstack, "<library name=\"");
+  p = xml_escape_text (ldi->filename);
+  obstack_grow_str (obstack, p);
+  xfree (p);
+  obstack_grow_str (obstack, "\"");
+
+  if (ldi->member_name[0] != '\0')
+    {
+      obstack_grow_str (obstack, " member=\"");
+      p = xml_escape_text (ldi->member_name);
+      obstack_grow_str (obstack, p);
+      xfree (p);
+      obstack_grow_str (obstack, "\"");
+    }
+
+  obstack_grow_str (obstack, " text_addr=\"");
+  obstack_grow_str (obstack, core_addr_to_string (ldi->textorg));
+  obstack_grow_str (obstack, "\"");
+
+  obstack_grow_str (obstack, " text_size=\"");
+  obstack_grow_str (obstack, pulongest (ldi->textsize));
+  obstack_grow_str (obstack, "\"");
+
+  obstack_grow_str (obstack, " data_addr=\"");
+  obstack_grow_str (obstack, core_addr_to_string (ldi->dataorg));
+  obstack_grow_str (obstack, "\"");
+
+  obstack_grow_str (obstack, " data_size=\"");
+  obstack_grow_str (obstack, pulongest (ldi->datasize));
+  obstack_grow_str (obstack, "\"");
+
+  obstack_grow_str (obstack, "></library>");
+}
+
+/* Convert the ld_info binary data provided by the AIX loader into
+   an XML representation following the TARGET_OBJECT_LIBRARIES_AIX
+   format.
+
+   LDI_BUF is a buffer containing the ld_info data.
+   READBUF, OFFSET and LEN follow the same semantics as target_ops'
+   to_xfer_partial target_ops method.
+
+   If CLOSE_LDINFO_FD is nonzero, then this routine also closes
+   the ldinfo_fd file descriptor.  This is useful when the ldinfo
+   data is obtained via ptrace, as ptrace opens a file descriptor
+   for each and every entry; but we cannot use this descriptor
+   as the consumer of the XML library list might live in a different
+   process.  */
+
+LONGEST
+rs6000_aix_ld_info_to_xml (struct gdbarch *gdbarch, const gdb_byte *ldi_buf,
+                          gdb_byte *readbuf, ULONGEST offset, LONGEST len,
+                          int close_ldinfo_fd)
+{
+  struct obstack obstack;
+  const char *buf;
+  LONGEST len_avail;
+
+  obstack_init (&obstack);
+  obstack_grow_str (&obstack, "<library-list-aix version=\"1.0\">\n");
+
+  while (1)
+    {
+      struct ld_info ldi = rs6000_aix_extract_ld_info (gdbarch, ldi_buf);
+
+      rs6000_aix_shared_library_to_xml (&ldi, &obstack);
+      if (close_ldinfo_fd)
+       close (ldi.fd);
+
+      if (!ldi.next)
+       break;
+      ldi_buf = ldi_buf + ldi.next;
+    }
+
+  obstack_grow_str0 (&obstack, "</library-list-aix>\n");
+
+  buf = obstack_finish (&obstack);
+  len_avail = strlen (buf);
+  if (offset >= len_avail)
+    len= 0;
+  else
+    {
+      if (len > len_avail - offset)
+        len = len_avail - offset;
+      memcpy (readbuf, buf + offset, len);
+    }
+
+  obstack_free (&obstack, NULL);
+  return len;
+}
+
+/* Implement the core_xfer_shared_libraries_aix gdbarch method.  */
+
+static LONGEST
+rs6000_aix_core_xfer_shared_libraries_aix (struct gdbarch *gdbarch,
+                                          gdb_byte *readbuf,
+                                          ULONGEST offset,
+                                          LONGEST len)
+{
+  struct bfd_section *ldinfo_sec;
+  int ldinfo_size;
+  gdb_byte *ldinfo_buf;
+  struct cleanup *cleanup;
+  LONGEST result;
+
+  ldinfo_sec = bfd_get_section_by_name (core_bfd, ".ldinfo");
+  if (ldinfo_sec == NULL)
+    error (_("cannot find .ldinfo section from core file: %s"),
+          bfd_errmsg (bfd_get_error ()));
+  ldinfo_size = bfd_get_section_size (ldinfo_sec);
+
+  ldinfo_buf = xmalloc (ldinfo_size);
+  cleanup = make_cleanup (xfree, ldinfo_buf);
+
+  if (! bfd_get_section_contents (core_bfd, ldinfo_sec,
+                                 ldinfo_buf, 0, ldinfo_size))
+    error (_("unable to read .ldinfo section from core file: %s"),
+         bfd_errmsg (bfd_get_error ()));
+
+  result = rs6000_aix_ld_info_to_xml (gdbarch, ldinfo_buf, readbuf,
+                                     offset, len, 0);
+
+  do_cleanups (cleanup);
+  return result;
+}
+
 static void
 rs6000_aix_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   /* Core file support.  */
   set_gdbarch_regset_from_core_section
     (gdbarch, rs6000_aix_regset_from_core_section);
+  set_gdbarch_core_xfer_shared_libraries_aix
+    (gdbarch, rs6000_aix_core_xfer_shared_libraries_aix);
 
   if (tdep->wordsize == 8)
     tdep->lr_frame_offset = 16;
 
--- /dev/null
+/* Copyright (C) 2013 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 3 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, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef RS6000_AIX_TDEP_H
+#define RS6000_AIX_TDEP_H
+
+extern LONGEST rs6000_aix_ld_info_to_xml (struct gdbarch *gdbarch,
+                                         const gdb_byte *ldi_buf,
+                                         gdb_byte *readbuf,
+                                         ULONGEST offset,
+                                         LONGEST len,
+                                         int close_ldinfo_fd);
+
+#endif /* RS6000_AIX_TDEP_H */
 
 #include "inf-ptrace.h"
 #include "ppc-tdep.h"
 #include "rs6000-tdep.h"
+#include "rs6000-aix-tdep.h"
 #include "exec.h"
 #include "observer.h"
 #include "xcoffread.h"
 #define __LDINFO_PTRACE64__    /* for __ld_info64 */
 #include <sys/ldr.h>
 #include <sys/systemcfg.h>
-#include "xml-utils.h"
 
 /* On AIX4.3+, sys/ldr.h provides different versions of struct ld_info for
    debugging 32-bit and 64-bit processes.  Define a typedef and macros for
 # define ARCH64() (register_size (target_gdbarch (), 0) == 8)
 #endif
 
-/* Union of 32-bit and 64-bit versions of ld_info.  */
-
-typedef union {
-#ifndef ARCH3264
-  struct ld_info l32;
-  struct ld_info l64;
-#else
-  struct __ld_info32 l32;
-  struct __ld_info64 l64;
-#endif
-} LdInfo;
-
-/* If compiling with 32-bit and 64-bit debugging capability (e.g. AIX 4.x),
-   declare and initialize a variable named VAR suitable for use as the arch64
-   parameter to the various LDI_*() macros.  */
-
-#ifndef ARCH3264
-# define ARCH64_DECL(var)
-#else
-# define ARCH64_DECL(var) int var = ARCH64 ()
-#endif
-
-/* Return LDI's FIELD for a 64-bit process if ARCH64 and for a 32-bit process
-   otherwise.  This technique only works for FIELDs with the same data type in
-   32-bit and 64-bit versions of ld_info.  */
-
-#ifndef ARCH3264
-# define LDI_FIELD(ldi, arch64, field) (ldi)->l32.ldinfo_##field
-#else
-# define LDI_FIELD(ldi, arch64, field) \
-  (arch64 ? (ldi)->l64.ldinfo_##field : (ldi)->l32.ldinfo_##field)
-#endif
-
-/* Return various LDI fields for a 64-bit process if ARCH64 and for a 32-bit
-   process otherwise.  */
-
-#define LDI_NEXT(ldi, arch64)          LDI_FIELD(ldi, arch64, next)
-#define LDI_FD(ldi, arch64)            LDI_FIELD(ldi, arch64, fd)
-#define LDI_FILENAME(ldi, arch64)      LDI_FIELD(ldi, arch64, filename)
-
 static void exec_one_dummy_insn (struct regcache *);
 
 static LONGEST rs6000_xfer_shared_libraries
 
    The returned value must be deallocated after use.  */
 
-static LdInfo *
+static gdb_byte *
 rs6000_ptrace_ldinfo (ptid_t ptid)
 {
   const int pid = ptid_get_pid (ptid);
   int ldi_size = 1024;
-  LdInfo *ldi = xmalloc (ldi_size);
+  gdb_byte *ldi = xmalloc (ldi_size);
   int rc = -1;
 
   while (1)
   return ldi;
 }
 
-/* Assuming ABFD refers to a core file, return the LdInfo data
-   stored in that core file.  Raises an error if the data could
-   not be read or extracted.
-
-   The returned value much be deallocated after use.  */
-
-static LdInfo *
-rs6000_core_ldinfo (bfd *abfd)
-{
-  struct bfd_section *ldinfo_sec;
-  int ldinfo_size;
-  gdb_byte *ldinfo_buf;
-  struct cleanup *cleanup;
-
-  ldinfo_sec = bfd_get_section_by_name (abfd, ".ldinfo");
-  if (ldinfo_sec == NULL)
-    error (_("cannot find .ldinfo section from core file: %s"),
-          bfd_errmsg (bfd_get_error ()));
-  ldinfo_size = bfd_get_section_size (ldinfo_sec);
-
-  ldinfo_buf = xmalloc (ldinfo_size);
-  cleanup = make_cleanup (xfree, ldinfo_buf);
-
-  if (! bfd_get_section_contents (abfd, ldinfo_sec,
-                                 ldinfo_buf, 0, ldinfo_size))
-    error (_("unable to read .ldinfo section from core file: %s"),
-          bfd_errmsg (bfd_get_error ()));
-
-  discard_cleanups (cleanup);
-  return (LdInfo *) ldinfo_buf;
-}
-
-/* Append to OBJSTACK an XML string description of the shared library
-   corresponding to LDI, following the TARGET_OBJECT_LIBRARIES_AIX
-   format.  */
-
-static void
-rs6000_xfer_shared_library (LdInfo *ldi, struct obstack *obstack)
-{
-  const int arch64 = ARCH64 ();
-  const char *archive_name = LDI_FILENAME (ldi, arch64);
-  const char *member_name = archive_name + strlen (archive_name) + 1;
-  CORE_ADDR text_addr, data_addr;
-  ULONGEST text_size, data_size;
-  char *p;
-
-  if (arch64)
-    {
-      text_addr = ldi->l64.ldinfo_textorg;
-      text_size = ldi->l64.ldinfo_textsize;
-      data_addr = ldi->l64.ldinfo_dataorg;
-      data_size = ldi->l64.ldinfo_datasize;
-    }
-  else
-    {
-      /* The text and data addresses are defined as pointers.
-        To avoid sign-extending their value in the assignments
-        below, we cast their value to unsigned long first.  */
-      text_addr = (unsigned long) ldi->l32.ldinfo_textorg;
-      text_size = ldi->l32.ldinfo_textsize;
-      data_addr = (unsigned long) ldi->l32.ldinfo_dataorg;
-      data_size = ldi->l32.ldinfo_datasize;
-    }
-
-  obstack_grow_str (obstack, "<library name=\"");
-  p = xml_escape_text (archive_name);
-  obstack_grow_str (obstack, p);
-  xfree (p);
-  obstack_grow_str (obstack, "\"");
-
-  if (member_name[0] != '\0')
-    {
-      obstack_grow_str (obstack, " member=\"");
-      p = xml_escape_text (member_name);
-      obstack_grow_str (obstack, p);
-      xfree (p);
-      obstack_grow_str (obstack, "\"");
-    }
-
-  obstack_grow_str (obstack, " text_addr=\"");
-  obstack_grow_str (obstack, core_addr_to_string (text_addr));
-  obstack_grow_str (obstack, "\"");
-
-  obstack_grow_str (obstack, " text_size=\"");
-  obstack_grow_str (obstack, pulongest (text_size));
-  obstack_grow_str (obstack, "\"");
-
-  obstack_grow_str (obstack, " data_addr=\"");
-  obstack_grow_str (obstack, core_addr_to_string (data_addr));
-  obstack_grow_str (obstack, "\"");
-
-  obstack_grow_str (obstack, " data_size=\"");
-  obstack_grow_str (obstack, pulongest (data_size));
-  obstack_grow_str (obstack, "\"");
-
-  obstack_grow_str (obstack, "></library>");
-}
-
 /* Implement the to_xfer_partial target_ops method for
    TARGET_OBJECT_LIBRARIES_AIX objects.  */
 
    const char *annex, gdb_byte *readbuf, const gdb_byte *writebuf,
    ULONGEST offset, LONGEST len)
 {
-  const int arch64 = ARCH64 ();
-  LdInfo *ldi_data;
-  LdInfo *ldi;
-  struct obstack obstack;
-  const char *buf;
-  LONGEST len_avail;
+  gdb_byte *ldi_buf;
+  ULONGEST result;
+  struct cleanup *cleanup;
+
+  /* This function assumes that it is being run with a live process.
+     Core files are handled via gdbarch.  */
+  gdb_assert (target_has_execution);
 
   if (writebuf)
     return -1;
 
-  /* Get the ldinfo raw data: If debugging a live process, we get it
-     using ptrace.  Otherwise, the info is stored in the .ldinfo
-     section of the core file.  */
-
-  if (target_has_execution)
-    ldi_data = rs6000_ptrace_ldinfo (inferior_ptid);
-  else
-    ldi_data = rs6000_core_ldinfo (core_bfd);
-
-  /* Convert the raw data into an XML representation.  */
-
-  obstack_init (&obstack);
-  obstack_grow_str (&obstack, "<library-list-aix version=\"1.0\">\n");
-
-  ldi = ldi_data;
-  while (1)
-    {
-      /* Close the fd.  We cannot use it, because we cannot assume
-        that the user of this descriptor will be in the same
-        process.  */
-      close (LDI_FD (ldi, arch64));
-
-      rs6000_xfer_shared_library (ldi, &obstack);
-
-      if (!LDI_NEXT (ldi, arch64))
-       break;
-      ldi = (LdInfo *) ((char *) ldi + LDI_NEXT (ldi, arch64));
-    }
-
-  xfree (ldi_data);
-
-  obstack_grow_str0 (&obstack, "</library-list-aix>\n");
-
-  buf = obstack_finish (&obstack);
-  len_avail = strlen (buf);
-  if (offset >= len_avail)
-    len= 0;
-  else
-    {
-      if (len > len_avail - offset)
-        len = len_avail - offset;
-      memcpy (readbuf, buf + offset, len);
-    }
+  ldi_buf = rs6000_ptrace_ldinfo (inferior_ptid);
+  gdb_assert (ldi_buf != NULL);
+  cleanup = make_cleanup (xfree, ldi_buf);
+  result = rs6000_aix_ld_info_to_xml (target_gdbarch (), ldi_buf,
+                                     readbuf, offset, len, 1);
+  xfree (ldi_buf);
 
-  obstack_free (&obstack, NULL);
-  return len;
+  do_cleanups (cleanup);
+  return result;
 }
 
 void _initialize_rs6000_nat (void);