Update copyright year printed by gdb, gdbserver and gdbreplay.
[deliverable/binutils-gdb.git] / gdb / rs6000-aix-tdep.c
index 0992213f97e3a5fd412e0a705a7f32780ba1755d..372f1ead15378014be9fab62d1f9ee5843e5ba4c 100644 (file)
@@ -1,6 +1,6 @@
 /* Native support code for PPC AIX, for GDB the GNU debugger.
 
-   Copyright (C) 2006-2013 Free Software Foundation, Inc.
+   Copyright (C) 2006-2014 Free Software Foundation, Inc.
 
    Free Software Foundation, Inc.
 
@@ -20,8 +20,6 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
-#include "gdb_string.h"
-#include "gdb_assert.h"
 #include "osabi.h"
 #include "regcache.h"
 #include "regset.h"
 #include "breakpoint.h"
 #include "rs6000-tdep.h"
 #include "ppc-tdep.h"
-#include "exceptions.h"
+#include "rs6000-aix-tdep.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
@@ -133,39 +132,32 @@ rs6000_aix_collect_regset (const struct regset *regset,
 
 /* AIX register set.  */
 
-static struct regset rs6000_aix32_regset =
+static const struct regset rs6000_aix32_regset =
 {
   &rs6000_aix32_reg_offsets,
   rs6000_aix_supply_regset,
   rs6000_aix_collect_regset,
 };
 
-static struct regset rs6000_aix64_regset =
+static const struct regset rs6000_aix64_regset =
 {
   &rs6000_aix64_reg_offsets,
   rs6000_aix_supply_regset,
   rs6000_aix_collect_regset,
 };
 
-/* Return the appropriate register set for the core section identified
-   by SECT_NAME and SECT_SIZE.  */
+/* Iterate over core file register note sections.  */
 
-static const struct regset *
-rs6000_aix_regset_from_core_section (struct gdbarch *gdbarch,
-                                    const char *sect_name, size_t sect_size)
+static void
+rs6000_aix_iterate_over_regset_sections (struct gdbarch *gdbarch,
+                                        iterate_over_regset_sections_cb *cb,
+                                        void *cb_data,
+                                        const struct regcache *regcache)
 {
   if (gdbarch_tdep (gdbarch)->wordsize == 4)
-    {
-      if (strcmp (sect_name, ".reg") == 0 && sect_size >= 592)
-        return &rs6000_aix32_regset;
-    }
+    cb (".reg", 592, &rs6000_aix32_regset, NULL, cb_data);
   else
-    {
-      if (strcmp (sect_name, ".reg") == 0 && sect_size >= 576)
-        return &rs6000_aix64_regset;
-    }
-
-  return NULL;
+    cb (".reg", 576, &rs6000_aix64_regset, NULL, cb_data);
 }
 
 
@@ -254,16 +246,21 @@ rs6000_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
       if (TYPE_CODE (type) == TYPE_CODE_FLT)
        {
-
          /* Floating point arguments are passed in fpr's, as well as gpr's.
             There are 13 fpr's reserved for passing parameters.  At this point
-            there is no way we would run out of them.  */
+            there is no way we would run out of them.
+
+            Always store the floating point value using the register's
+            floating-point format.  */
+         const int fp_regnum = tdep->ppc_fp0_regnum + 1 + f_argno;
+         gdb_byte reg_val[MAX_REGISTER_SIZE];
+         struct type *reg_type = register_type (gdbarch, fp_regnum);
 
          gdb_assert (len <= 8);
 
-         regcache_cooked_write (regcache,
-                                tdep->ppc_fp0_regnum + 1 + f_argno,
-                                value_contents (arg));
+         convert_typed_floating (value_contents (arg), type,
+                                 reg_val, reg_type);
+         regcache_cooked_write (regcache, fp_regnum, reg_val);
          ++f_argno;
        }
 
@@ -742,6 +739,299 @@ rs6000_aix_osabi_sniffer (bfd *abfd)
   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.  */
+
+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 = 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;
+  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)
 {
@@ -767,8 +1057,10 @@ rs6000_aix_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
     (gdbarch, rs6000_convert_from_func_ptr_addr);
 
   /* Core file support.  */
-  set_gdbarch_regset_from_core_section
-    (gdbarch, rs6000_aix_regset_from_core_section);
+  set_gdbarch_iterate_over_regset_sections
+    (gdbarch, rs6000_aix_iterate_over_regset_sections);
+  set_gdbarch_core_xfer_shared_libraries_aix
+    (gdbarch, rs6000_aix_core_xfer_shared_libraries_aix);
 
   if (tdep->wordsize == 8)
     tdep->lr_frame_offset = 16;
This page took 0.026908 seconds and 4 git commands to generate.