| Index: gdb/rs6000-aix-tdep.c
|
| diff --git a/gdb/rs6000-aix-tdep.c b/gdb/rs6000-aix-tdep.c
|
| index 59cfa73b495685795f817473b2e98ef01936eddb..328200770b4ef15d25d026be66bb4c1ed5e993e5 100644
|
| --- a/gdb/rs6000-aix-tdep.c
|
| +++ b/gdb/rs6000-aix-tdep.c
|
| @@ -1,6 +1,6 @@
|
| /* Native support code for PPC AIX, for GDB the GNU debugger.
|
|
|
| - Copyright (C) 2006-2012 Free Software Foundation, Inc.
|
| + Copyright (C) 2006-2013 Free Software Foundation, Inc.
|
|
|
| Free Software Foundation, Inc.
|
|
|
| @@ -20,7 +20,7 @@
|
| along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
| #include "defs.h"
|
| -#include "gdb_string.h"
|
| +#include <string.h>
|
| #include "gdb_assert.h"
|
| #include "osabi.h"
|
| #include "regcache.h"
|
| @@ -34,13 +34,12 @@
|
| #include "breakpoint.h"
|
| #include "rs6000-tdep.h"
|
| #include "ppc-tdep.h"
|
| +#include "rs6000-aix-tdep.h"
|
| #include "exceptions.h"
|
| -
|
| -/* Hook for determining the TOC address when calling functions in the
|
| - inferior under AIX. The initialization code in rs6000-nat.c sets
|
| - this hook to point to find_toc_address. */
|
| -
|
| -CORE_ADDR (*rs6000_find_toc_address_hook) (CORE_ADDR) = NULL;
|
| +#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
|
| @@ -257,16 +256,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;
|
| }
|
|
|
| @@ -411,13 +415,9 @@ ran_out_of_registers_for_arguments:
|
| breakpoint. */
|
| regcache_raw_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
|
|
|
| - /* Set the TOC register, get the value from the objfile reader
|
| - which, in turn, gets it from the VMAP table. */
|
| - if (rs6000_find_toc_address_hook != NULL)
|
| - {
|
| - CORE_ADDR tocvalue = (*rs6000_find_toc_address_hook) (func_addr);
|
| - regcache_raw_write_signed (regcache, tdep->ppc_toc_regnum, tocvalue);
|
| - }
|
| + /* Set the TOC register value. */
|
| + regcache_raw_write_signed (regcache, tdep->ppc_toc_regnum,
|
| + solib_aix_get_toc_value (func_addr));
|
|
|
| target_store_registers (regcache, -1);
|
| return sp;
|
| @@ -719,14 +719,327 @@ rs6000_software_single_step (struct frame_info *frame)
|
| return 1;
|
| }
|
|
|
| +/* Implement the "auto_wide_charset" gdbarch method for this platform. */
|
| +
|
| +static const char *
|
| +rs6000_aix_auto_wide_charset (void)
|
| +{
|
| + return "UTF-16";
|
| +}
|
| +
|
| +/* Implement an osabi sniffer for RS6000/AIX.
|
| +
|
| + This function assumes that ABFD's flavour is XCOFF. In other words,
|
| + it should be registered as a sniffer for bfd_target_xcoff_flavour
|
| + objfiles only. A failed assertion will be raised if this condition
|
| + is not met. */
|
| +
|
| static enum gdb_osabi
|
| rs6000_aix_osabi_sniffer (bfd *abfd)
|
| {
|
| -
|
| - if (bfd_get_flavour (abfd) == bfd_target_xcoff_flavour);
|
| - return GDB_OSABI_AIX;
|
| + gdb_assert (bfd_get_flavour (abfd) == bfd_target_xcoff_flavour);
|
| +
|
| + /* The only noticeable difference between Lynx178 XCOFF files and
|
| + AIX XCOFF files comes from the fact that there are no shared
|
| + libraries on Lynx178. On AIX, we are betting that an executable
|
| + linked with no shared library will never exist. */
|
| + if (xcoff_get_n_import_files (abfd) <= 0)
|
| + return GDB_OSABI_UNKNOWN;
|
| +
|
| + return GDB_OSABI_AIX;
|
| +}
|
| +
|
| +/* A structure encoding the offset and size of a field within
|
| + a struct. */
|
| +
|
| +struct field_info
|
| +{
|
| + int offset;
|
| + int size;
|
| +};
|
|
|
| - return GDB_OSABI_UNKNOWN;
|
| +/* 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
|
| @@ -756,6 +1069,8 @@ 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;
|
| @@ -770,6 +1085,10 @@ rs6000_aix_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
| set_gdbarch_frame_red_zone_size (gdbarch, 224);
|
| else
|
| set_gdbarch_frame_red_zone_size (gdbarch, 0);
|
| +
|
| + set_gdbarch_auto_wide_charset (gdbarch, rs6000_aix_auto_wide_charset);
|
| +
|
| + set_solib_ops (gdbarch, &solib_aix_so_ops);
|
| }
|
|
|
| /* Provide a prototype to silence -Wmissing-prototypes. */
|
|
|