X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Frs6000-aix-tdep.c;h=38c86d4cd85a0c503e9704f8df586167590fc987;hb=e2882c85786571175a0b0bfc3bcd2f14620b1ea3;hp=b4fc931d2b399eb346e0eb6e62fd0c8ccb194e8d;hpb=38a69d0a4d05b7fb52902a3c9bd2360d7191af3b;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/rs6000-aix-tdep.c b/gdb/rs6000-aix-tdep.c index b4fc931d2b..38c86d4cd8 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-2018 Free Software Foundation, Inc. Free Software Foundation, Inc. @@ -20,8 +20,6 @@ along with this program. If not, see . */ #include "defs.h" -#include "gdb_string.h" -#include "gdb_assert.h" #include "osabi.h" #include "regcache.h" #include "regset.h" @@ -34,13 +32,12 @@ #include "breakpoint.h" #include "rs6000-tdep.h" #include "ppc-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 "rs6000-aix-tdep.h" +#include "xcoffread.h" +#include "solib.h" +#include "solib-aix.h" +#include "target-float.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 @@ -136,39 +133,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); } @@ -257,16 +247,20 @@ 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[PPC_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)); + target_float_convert (value_contents (arg), type, reg_val, reg_type); + regcache_cooked_write (regcache, fp_regnum, reg_val); ++f_argno; } @@ -276,7 +270,7 @@ rs6000_push_dummy_call (struct gdbarch *gdbarch, struct value *function, /* Argument takes more than one register. */ while (argbytes < len) { - gdb_byte word[MAX_REGISTER_SIZE]; + gdb_byte word[PPC_MAX_REGISTER_SIZE]; memset (word, 0, reg_size); memcpy (word, ((char *) value_contents (arg)) + argbytes, @@ -296,9 +290,7 @@ rs6000_push_dummy_call (struct gdbarch *gdbarch, struct value *function, else { /* Argument can fit in one register. No problem. */ - int adj = gdbarch_byte_order (gdbarch) - == BFD_ENDIAN_BIG ? reg_size - len : 0; - gdb_byte word[MAX_REGISTER_SIZE]; + gdb_byte word[PPC_MAX_REGISTER_SIZE]; memset (word, 0, reg_size); memcpy (word, value_contents (arg), len); @@ -411,13 +403,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; @@ -475,11 +463,11 @@ rs6000_return_value (struct gdbarch *gdbarch, struct value *function, if (readbuf) { regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, regval); - convert_typed_floating (regval, regtype, readbuf, valtype); + target_float_convert (regval, regtype, readbuf, valtype); } if (writebuf) { - convert_typed_floating (writebuf, valtype, regval, regtype); + target_float_convert (writebuf, valtype, regval, regtype); regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1, regval); } @@ -582,19 +570,20 @@ rs6000_convert_from_func_ptr_addr (struct gdbarch *gdbarch, { CORE_ADDR pc = 0; struct obj_section *pc_section; - volatile struct gdb_exception e; - TRY_CATCH (e, RETURN_MASK_ERROR) + TRY { pc = read_memory_unsigned_integer (addr, tdep->wordsize, byte_order); } - if (e.reason < 0) + CATCH (e, RETURN_MASK_ERROR) { /* An error occured during reading. Probably a memory error due to the section not being loaded yet. This address cannot be a function descriptor. */ return addr; } + END_CATCH + pc_section = find_pc_section (pc); if (pc_section && (pc_section->the_bfd_section->flags & SEC_CODE)) @@ -608,10 +597,10 @@ rs6000_convert_from_func_ptr_addr (struct gdbarch *gdbarch, /* Calculate the destination of a branch/jump. Return -1 if not a branch. */ static CORE_ADDR -branch_dest (struct frame_info *frame, int opcode, int instr, +branch_dest (struct regcache *regcache, int opcode, int instr, CORE_ADDR pc, CORE_ADDR safety) { - struct gdbarch *gdbarch = get_frame_arch (frame); + struct gdbarch *gdbarch = regcache->arch (); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); CORE_ADDR dest; @@ -644,29 +633,33 @@ branch_dest (struct frame_info *frame, int opcode, int instr, if (ext_op == 16) /* br conditional register */ { - dest = get_frame_register_unsigned (frame, tdep->ppc_lr_regnum) & ~3; + dest = regcache_raw_get_unsigned (regcache, tdep->ppc_lr_regnum) & ~3; /* If we are about to return from a signal handler, dest is something like 0x3c90. The current frame is a signal handler caller frame, upon completion of the sigreturn system call execution will return to the saved PC in the frame. */ if (dest < AIX_TEXT_SEGMENT_BASE) - dest = read_memory_unsigned_integer - (get_frame_base (frame) + SIG_FRAME_PC_OFFSET, - tdep->wordsize, byte_order); + { + struct frame_info *frame = get_current_frame (); + + dest = read_memory_unsigned_integer + (get_frame_base (frame) + SIG_FRAME_PC_OFFSET, + tdep->wordsize, byte_order); + } } else if (ext_op == 528) /* br cond to count reg */ { - dest = get_frame_register_unsigned (frame, - tdep->ppc_ctr_regnum) & ~3; + dest = regcache_raw_get_unsigned (regcache, + tdep->ppc_ctr_regnum) & ~3; /* If we are about to execute a system call, dest is something like 0x22fc or 0x3b00. Upon completion the system call will return to the address in the link register. */ if (dest < AIX_TEXT_SEGMENT_BASE) - dest = get_frame_register_unsigned (frame, - tdep->ppc_lr_regnum) & ~3; + dest = regcache_raw_get_unsigned (regcache, + tdep->ppc_lr_regnum) & ~3; } else return -1; @@ -680,27 +673,27 @@ branch_dest (struct frame_info *frame, int opcode, int instr, /* AIX does not support PT_STEP. Simulate it. */ -static int -rs6000_software_single_step (struct frame_info *frame) +static std::vector +rs6000_software_single_step (struct regcache *regcache) { - struct gdbarch *gdbarch = get_frame_arch (frame); - struct address_space *aspace = get_frame_address_space (frame); + struct gdbarch *gdbarch = regcache->arch (); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); int ii, insn; CORE_ADDR loc; CORE_ADDR breaks[2]; int opcode; - loc = get_frame_pc (frame); + loc = regcache_read_pc (regcache); insn = read_memory_integer (loc, 4, byte_order); - if (ppc_deal_with_atomic_sequence (frame)) - return 1; + std::vector next_pcs = ppc_deal_with_atomic_sequence (regcache); + if (!next_pcs.empty ()) + return next_pcs; breaks[0] = loc + PPC_INSN_SIZE; opcode = insn >> 26; - breaks[1] = branch_dest (frame, opcode, insn, loc, breaks[0]); + breaks[1] = branch_dest (regcache, opcode, insn, loc, breaks[0]); /* Don't put two breakpoints on the same address. */ if (breaks[1] == breaks[0]) @@ -711,12 +704,13 @@ rs6000_software_single_step (struct frame_info *frame) /* ignore invalid breakpoint. */ if (breaks[ii] == -1) continue; - insert_single_step_breakpoint (gdbarch, aspace, breaks[ii]); + + next_pcs.push_back (breaks[ii]); } errno = 0; /* FIXME, don't ignore errors! */ /* What errors? {read,write}_memory call error(). */ - return 1; + return next_pcs; } /* Implement the "auto_wide_charset" gdbarch method for this platform. */ @@ -739,9 +733,305 @@ rs6000_aix_osabi_sniffer (bfd *abfd) { 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; +}; + +/* 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 +#include +#define __LDINFO_PTRACE32__ +#define __LDINFO_PTRACE64__ +#include + +#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) +{ + obstack_grow_str (obstack, "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, ">"); +} + +/* 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, "\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, "\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; + 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 = (gdb_byte *) 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) { @@ -754,7 +1044,6 @@ rs6000_aix_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch) software single-stepping. */ set_gdbarch_displaced_step_copy_insn (gdbarch, NULL); set_gdbarch_displaced_step_fixup (gdbarch, NULL); - set_gdbarch_displaced_step_free_closure (gdbarch, NULL); set_gdbarch_displaced_step_location (gdbarch, NULL); set_gdbarch_push_dummy_call (gdbarch, rs6000_push_dummy_call); @@ -767,8 +1056,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; @@ -784,11 +1075,15 @@ rs6000_aix_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch) else set_gdbarch_frame_red_zone_size (gdbarch, 0); + if (tdep->wordsize == 8) + set_gdbarch_wchar_bit (gdbarch, 32); + else + set_gdbarch_wchar_bit (gdbarch, 16); + set_gdbarch_wchar_signed (gdbarch, 0); set_gdbarch_auto_wide_charset (gdbarch, rs6000_aix_auto_wide_charset); -} -/* Provide a prototype to silence -Wmissing-prototypes. */ -extern initialize_file_ftype _initialize_rs6000_aix_tdep; + set_solib_ops (gdbarch, &solib_aix_so_ops); +} void _initialize_rs6000_aix_tdep (void)