+/* 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)
+{
+ obstack_grow_str (obstack, "<library name=\"");
+ std::string p = xml_escape_text (ldi->filename);
+ obstack_grow_str (obstack, p.c_str ());
+ 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.c_str ());
+ 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. */
+
+ULONGEST
+rs6000_aix_ld_info_to_xml (struct gdbarch *gdbarch, const gdb_byte *ldi_buf,
+ gdb_byte *readbuf, ULONGEST offset, ULONGEST len,
+ int close_ldinfo_fd)
+{
+ struct obstack obstack;
+ const char *buf;
+ ULONGEST 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 = (const char *) 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 ULONGEST
+rs6000_aix_core_xfer_shared_libraries_aix (struct gdbarch *gdbarch,
+ gdb_byte *readbuf,
+ ULONGEST offset,
+ ULONGEST len)
+{
+ struct bfd_section *ldinfo_sec;
+ int ldinfo_size;
+
+ 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);
+
+ gdb::byte_vector ldinfo_buf (ldinfo_size);
+
+ if (! bfd_get_section_contents (core_bfd, ldinfo_sec,
+ ldinfo_buf.data (), 0, ldinfo_size))
+ error (_("unable to read .ldinfo section from core file: %s"),
+ bfd_errmsg (bfd_get_error ()));
+
+ return rs6000_aix_ld_info_to_xml (gdbarch, ldinfo_buf.data (), readbuf,
+ offset, len, 0);