| /* Native support code for PPC AIX, for GDB the GNU debugger. | 
 |  | 
 |    Copyright (C) 2006-2022 Free Software Foundation, Inc. | 
 |  | 
 |    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/>.  */ | 
 |  | 
 | #include "defs.h" | 
 | #include "osabi.h" | 
 | #include "regcache.h" | 
 | #include "regset.h" | 
 | #include "gdbtypes.h" | 
 | #include "gdbcore.h" | 
 | #include "target.h" | 
 | #include "value.h" | 
 | #include "infcall.h" | 
 | #include "objfiles.h" | 
 | #include "breakpoint.h" | 
 | #include "ppc-tdep.h" | 
 | #include "rs6000-aix-tdep.h" | 
 | #include "xcoffread.h" | 
 | #include "solib.h" | 
 | #include "solib-aix.h" | 
 | #include "target-float.h" | 
 | #include "gdbsupport/xml-utils.h" | 
 | #include "trad-frame.h" | 
 | #include "frame-unwind.h" | 
 |  | 
 | /* If the kernel has to deliver a signal, it pushes a sigcontext | 
 |    structure on the stack and then calls the signal handler, passing | 
 |    the address of the sigcontext in an argument register.  Usually | 
 |    the signal handler doesn't save this register, so we have to | 
 |    access the sigcontext structure via an offset from the signal handler | 
 |    frame. | 
 |    The following constants were determined by experimentation on AIX 3.2. | 
 |  | 
 |    sigcontext structure have the mstsave saved under the | 
 |    sc_jmpbuf.jmp_context. STKMIN(minimum stack size) is 56 for 32-bit | 
 |    processes, and iar offset under sc_jmpbuf.jmp_context is 40. | 
 |    ie offsetof(struct sigcontext, sc_jmpbuf.jmp_context.iar). | 
 |    so PC offset in this case is STKMIN+iar offset, which is 96. */ | 
 |  | 
 | #define SIG_FRAME_PC_OFFSET 96 | 
 | #define SIG_FRAME_LR_OFFSET 108 | 
 | /* STKMIN+grp1 offset, which is 56+228=284 */ | 
 | #define SIG_FRAME_FP_OFFSET 284 | 
 |  | 
 | /* 64 bit process. | 
 |    STKMIN64  is 112 and iar offset is 312. So 112+312=424 */ | 
 | #define SIG_FRAME_LR_OFFSET64 424 | 
 | /* STKMIN64+grp1 offset. 112+56=168 */ | 
 | #define SIG_FRAME_FP_OFFSET64 168 | 
 |  | 
 | /* Minimum possible text address in AIX.  */ | 
 | #define AIX_TEXT_SEGMENT_BASE 0x10000000 | 
 |  | 
 | static struct trad_frame_cache * | 
 | aix_sighandle_frame_cache (struct frame_info *this_frame, | 
 | 			   void **this_cache) | 
 | { | 
 |   LONGEST backchain; | 
 |   CORE_ADDR base, base_orig, func; | 
 |   struct gdbarch *gdbarch = get_frame_arch (this_frame); | 
 |   ppc_gdbarch_tdep *tdep = (ppc_gdbarch_tdep *) gdbarch_tdep (gdbarch); | 
 |   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); | 
 |   struct trad_frame_cache *this_trad_cache; | 
 |  | 
 |   if ((*this_cache) != NULL) | 
 |     return (struct trad_frame_cache *) (*this_cache); | 
 |  | 
 |   this_trad_cache = trad_frame_cache_zalloc (this_frame); | 
 |   (*this_cache) = this_trad_cache; | 
 |  | 
 |   base = get_frame_register_unsigned (this_frame, | 
 | 				      gdbarch_sp_regnum (gdbarch)); | 
 |   base_orig = base; | 
 |  | 
 |   if (tdep->wordsize == 4) | 
 |     { | 
 |       func = read_memory_unsigned_integer (base_orig + | 
 | 					   SIG_FRAME_PC_OFFSET + 8, | 
 | 					   tdep->wordsize, byte_order); | 
 |       safe_read_memory_integer (base_orig + SIG_FRAME_FP_OFFSET + 8, | 
 | 				tdep->wordsize, byte_order, &backchain); | 
 |       base = (CORE_ADDR)backchain; | 
 |     } | 
 |   else | 
 |     { | 
 |       func = read_memory_unsigned_integer (base_orig + | 
 | 					   SIG_FRAME_LR_OFFSET64, | 
 | 					   tdep->wordsize, byte_order); | 
 |       safe_read_memory_integer (base_orig + SIG_FRAME_FP_OFFSET64, | 
 | 				tdep->wordsize, byte_order, &backchain); | 
 |       base = (CORE_ADDR)backchain; | 
 |     } | 
 |  | 
 |   trad_frame_set_reg_value (this_trad_cache, gdbarch_pc_regnum (gdbarch), func); | 
 |   trad_frame_set_reg_value (this_trad_cache, gdbarch_sp_regnum (gdbarch), base); | 
 |  | 
 |   if (tdep->wordsize == 4) | 
 |     trad_frame_set_reg_addr (this_trad_cache, tdep->ppc_lr_regnum, | 
 | 			     base_orig + 0x38 + 52 + 8); | 
 |   else | 
 |     trad_frame_set_reg_addr (this_trad_cache, tdep->ppc_lr_regnum, | 
 | 			     base_orig + 0x70 + 320); | 
 |  | 
 |   trad_frame_set_id (this_trad_cache, frame_id_build (base, func)); | 
 |   trad_frame_set_this_base (this_trad_cache, base); | 
 |  | 
 |   return this_trad_cache; | 
 | } | 
 |  | 
 | static void | 
 | aix_sighandle_frame_this_id (struct frame_info *this_frame, | 
 | 			     void **this_prologue_cache, | 
 | 			     struct frame_id *this_id) | 
 | { | 
 |   struct trad_frame_cache *this_trad_cache | 
 |     = aix_sighandle_frame_cache (this_frame, this_prologue_cache); | 
 |   trad_frame_get_id (this_trad_cache, this_id); | 
 | } | 
 |  | 
 | static struct value * | 
 | aix_sighandle_frame_prev_register (struct frame_info *this_frame, | 
 | 				   void **this_prologue_cache, int regnum) | 
 | { | 
 |   struct trad_frame_cache *this_trad_cache | 
 |     = aix_sighandle_frame_cache (this_frame, this_prologue_cache); | 
 |   return trad_frame_get_register (this_trad_cache, this_frame, regnum); | 
 | } | 
 |  | 
 | static int | 
 | aix_sighandle_frame_sniffer (const struct frame_unwind *self, | 
 | 			     struct frame_info *this_frame, | 
 | 			     void **this_prologue_cache) | 
 | { | 
 |   CORE_ADDR pc = get_frame_pc (this_frame); | 
 |   if (pc && pc < AIX_TEXT_SEGMENT_BASE) | 
 |     return 1; | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | /* AIX signal handler frame unwinder */ | 
 |  | 
 | static const struct frame_unwind aix_sighandle_frame_unwind = { | 
 |   "rs6000 aix sighandle", | 
 |   SIGTRAMP_FRAME, | 
 |   default_frame_unwind_stop_reason, | 
 |   aix_sighandle_frame_this_id, | 
 |   aix_sighandle_frame_prev_register, | 
 |   NULL, | 
 |   aix_sighandle_frame_sniffer | 
 | }; | 
 |  | 
 | /* Core file support.  */ | 
 |  | 
 | static struct ppc_reg_offsets rs6000_aix32_reg_offsets = | 
 | { | 
 |   /* General-purpose registers.  */ | 
 |   208, /* r0_offset */ | 
 |   4,  /* gpr_size */ | 
 |   4,  /* xr_size */ | 
 |   24, /* pc_offset */ | 
 |   28, /* ps_offset */ | 
 |   32, /* cr_offset */ | 
 |   36, /* lr_offset */ | 
 |   40, /* ctr_offset */ | 
 |   44, /* xer_offset */ | 
 |   48, /* mq_offset */ | 
 |  | 
 |   /* Floating-point registers.  */ | 
 |   336, /* f0_offset */ | 
 |   56, /* fpscr_offset */ | 
 |   4  /* fpscr_size */ | 
 | }; | 
 |  | 
 | static struct ppc_reg_offsets rs6000_aix64_reg_offsets = | 
 | { | 
 |   /* General-purpose registers.  */ | 
 |   0, /* r0_offset */ | 
 |   8,  /* gpr_size */ | 
 |   4,  /* xr_size */ | 
 |   264, /* pc_offset */ | 
 |   256, /* ps_offset */ | 
 |   288, /* cr_offset */ | 
 |   272, /* lr_offset */ | 
 |   280, /* ctr_offset */ | 
 |   292, /* xer_offset */ | 
 |   -1, /* mq_offset */ | 
 |  | 
 |   /* Floating-point registers.  */ | 
 |   312, /* f0_offset */ | 
 |   296, /* fpscr_offset */ | 
 |   4  /* fpscr_size */ | 
 | }; | 
 |  | 
 |  | 
 | /* Supply register REGNUM in the general-purpose register set REGSET | 
 |    from the buffer specified by GREGS and LEN to register cache | 
 |    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */ | 
 |  | 
 | static void | 
 | rs6000_aix_supply_regset (const struct regset *regset, | 
 | 			  struct regcache *regcache, int regnum, | 
 | 			  const void *gregs, size_t len) | 
 | { | 
 |   ppc_supply_gregset (regset, regcache, regnum, gregs, len); | 
 |   ppc_supply_fpregset (regset, regcache, regnum, gregs, len); | 
 | } | 
 |  | 
 | /* Collect register REGNUM in the general-purpose register set | 
 |    REGSET, from register cache REGCACHE into the buffer specified by | 
 |    GREGS and LEN.  If REGNUM is -1, do this for all registers in | 
 |    REGSET.  */ | 
 |  | 
 | static void | 
 | rs6000_aix_collect_regset (const struct regset *regset, | 
 | 			   const struct regcache *regcache, int regnum, | 
 | 			   void *gregs, size_t len) | 
 | { | 
 |   ppc_collect_gregset (regset, regcache, regnum, gregs, len); | 
 |   ppc_collect_fpregset (regset, regcache, regnum, gregs, len); | 
 | } | 
 |  | 
 | /* AIX register set.  */ | 
 |  | 
 | static const struct regset rs6000_aix32_regset = | 
 | { | 
 |   &rs6000_aix32_reg_offsets, | 
 |   rs6000_aix_supply_regset, | 
 |   rs6000_aix_collect_regset, | 
 | }; | 
 |  | 
 | static const struct regset rs6000_aix64_regset = | 
 | { | 
 |   &rs6000_aix64_reg_offsets, | 
 |   rs6000_aix_supply_regset, | 
 |   rs6000_aix_collect_regset, | 
 | }; | 
 |  | 
 | /* Iterate over core file register note sections.  */ | 
 |  | 
 | static void | 
 | rs6000_aix_iterate_over_regset_sections (struct gdbarch *gdbarch, | 
 | 					 iterate_over_regset_sections_cb *cb, | 
 | 					 void *cb_data, | 
 | 					 const struct regcache *regcache) | 
 | { | 
 |   ppc_gdbarch_tdep *tdep = (ppc_gdbarch_tdep *) gdbarch_tdep (gdbarch); | 
 |   if (tdep->wordsize == 4) | 
 |     cb (".reg", 592, 592, &rs6000_aix32_regset, NULL, cb_data); | 
 |   else | 
 |     cb (".reg", 576, 576, &rs6000_aix64_regset, NULL, cb_data); | 
 | } | 
 |  | 
 |  | 
 | /* Pass the arguments in either registers, or in the stack.  In RS/6000, | 
 |    the first eight words of the argument list (that might be less than | 
 |    eight parameters if some parameters occupy more than one word) are | 
 |    passed in r3..r10 registers.  Float and double parameters are | 
 |    passed in fpr's, in addition to that.  Rest of the parameters if any | 
 |    are passed in user stack.  There might be cases in which half of the | 
 |    parameter is copied into registers, the other half is pushed into | 
 |    stack. | 
 |  | 
 |    Stack must be aligned on 64-bit boundaries when synthesizing | 
 |    function calls. | 
 |  | 
 |    If the function is returning a structure, then the return address is passed | 
 |    in r3, then the first 7 words of the parameters can be passed in registers, | 
 |    starting from r4.  */ | 
 |  | 
 | static CORE_ADDR | 
 | rs6000_push_dummy_call (struct gdbarch *gdbarch, struct value *function, | 
 | 			struct regcache *regcache, CORE_ADDR bp_addr, | 
 | 			int nargs, struct value **args, CORE_ADDR sp, | 
 | 			function_call_return_method return_method, | 
 | 			CORE_ADDR struct_addr) | 
 | { | 
 |   ppc_gdbarch_tdep *tdep = (ppc_gdbarch_tdep *) gdbarch_tdep (gdbarch); | 
 |   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); | 
 |   int ii; | 
 |   int len = 0; | 
 |   int argno;			/* current argument number */ | 
 |   int argbytes;			/* current argument byte */ | 
 |   gdb_byte tmp_buffer[50]; | 
 |   int f_argno = 0;		/* current floating point argno */ | 
 |   int wordsize = tdep->wordsize; | 
 |   CORE_ADDR func_addr = find_function_addr (function, NULL); | 
 |  | 
 |   struct value *arg = 0; | 
 |   struct type *type; | 
 |  | 
 |   ULONGEST saved_sp; | 
 |  | 
 |   /* The calling convention this function implements assumes the | 
 |      processor has floating-point registers.  We shouldn't be using it | 
 |      on PPC variants that lack them.  */ | 
 |   gdb_assert (ppc_floating_point_unit_p (gdbarch)); | 
 |  | 
 |   /* The first eight words of ther arguments are passed in registers. | 
 |      Copy them appropriately.  */ | 
 |   ii = 0; | 
 |  | 
 |   /* If the function is returning a `struct', then the first word | 
 |      (which will be passed in r3) is used for struct return address. | 
 |      In that case we should advance one word and start from r4 | 
 |      register to copy parameters.  */ | 
 |   if (return_method == return_method_struct) | 
 |     { | 
 |       regcache_raw_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3, | 
 | 				   struct_addr); | 
 |       ii++; | 
 |     } | 
 |  | 
 | /* effectively indirect call... gcc does... | 
 |  | 
 |    return_val example( float, int); | 
 |  | 
 |    eabi:  | 
 |    float in fp0, int in r3 | 
 |    offset of stack on overflow 8/16 | 
 |    for varargs, must go by type. | 
 |    power open: | 
 |    float in r3&r4, int in r5 | 
 |    offset of stack on overflow different  | 
 |    both:  | 
 |    return in r3 or f0.  If no float, must study how gcc emulates floats; | 
 |    pay attention to arg promotion. | 
 |    User may have to cast\args to handle promotion correctly  | 
 |    since gdb won't know if prototype supplied or not.  */ | 
 |  | 
 |   for (argno = 0, argbytes = 0; argno < nargs && ii < 8; ++ii) | 
 |     { | 
 |       int reg_size = register_size (gdbarch, ii + 3); | 
 |  | 
 |       arg = args[argno]; | 
 |       type = check_typedef (value_type (arg)); | 
 |       len = TYPE_LENGTH (type); | 
 |  | 
 |       if (type->code () == 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. | 
 |  | 
 | 	     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); | 
 |  | 
 | 	  target_float_convert (value_contents (arg).data (), type, reg_val, | 
 | 				reg_type); | 
 | 	  regcache->cooked_write (fp_regnum, reg_val); | 
 | 	  ++f_argno; | 
 | 	} | 
 |  | 
 |       if (len > reg_size) | 
 | 	{ | 
 |  | 
 | 	  /* Argument takes more than one register.  */ | 
 | 	  while (argbytes < len) | 
 | 	    { | 
 | 	      gdb_byte word[PPC_MAX_REGISTER_SIZE]; | 
 | 	      memset (word, 0, reg_size); | 
 | 	      memcpy (word, | 
 | 		      ((char *) value_contents (arg).data ()) + argbytes, | 
 | 		      (len - argbytes) > reg_size | 
 | 			? reg_size : len - argbytes); | 
 | 	      regcache->cooked_write (tdep->ppc_gp0_regnum + 3 + ii, word); | 
 | 	      ++ii, argbytes += reg_size; | 
 |  | 
 | 	      if (ii >= 8) | 
 | 		goto ran_out_of_registers_for_arguments; | 
 | 	    } | 
 | 	  argbytes = 0; | 
 | 	  --ii; | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* Argument can fit in one register.  No problem.  */ | 
 | 	  gdb_byte word[PPC_MAX_REGISTER_SIZE]; | 
 |  | 
 | 	  memset (word, 0, reg_size); | 
 | 	  memcpy (word, value_contents (arg).data (), len); | 
 | 	  regcache->cooked_write (tdep->ppc_gp0_regnum + 3 +ii, word); | 
 | 	} | 
 |       ++argno; | 
 |     } | 
 |  | 
 | ran_out_of_registers_for_arguments: | 
 |  | 
 |   regcache_cooked_read_unsigned (regcache, | 
 | 				 gdbarch_sp_regnum (gdbarch), | 
 | 				 &saved_sp); | 
 |  | 
 |   /* Location for 8 parameters are always reserved.  */ | 
 |   sp -= wordsize * 8; | 
 |  | 
 |   /* Another six words for back chain, TOC register, link register, etc.  */ | 
 |   sp -= wordsize * 6; | 
 |  | 
 |   /* Stack pointer must be quadword aligned.  */ | 
 |   sp &= -16; | 
 |  | 
 |   /* If there are more arguments, allocate space for them in  | 
 |      the stack, then push them starting from the ninth one.  */ | 
 |  | 
 |   if ((argno < nargs) || argbytes) | 
 |     { | 
 |       int space = 0, jj; | 
 |  | 
 |       if (argbytes) | 
 | 	{ | 
 | 	  space += ((len - argbytes + 3) & -4); | 
 | 	  jj = argno + 1; | 
 | 	} | 
 |       else | 
 | 	jj = argno; | 
 |  | 
 |       for (; jj < nargs; ++jj) | 
 | 	{ | 
 | 	  struct value *val = args[jj]; | 
 | 	  space += ((TYPE_LENGTH (value_type (val))) + 3) & -4; | 
 | 	} | 
 |  | 
 |       /* Add location required for the rest of the parameters.  */ | 
 |       space = (space + 15) & -16; | 
 |       sp -= space; | 
 |  | 
 |       /* This is another instance we need to be concerned about | 
 | 	 securing our stack space.  If we write anything underneath %sp | 
 | 	 (r1), we might conflict with the kernel who thinks he is free | 
 | 	 to use this area.  So, update %sp first before doing anything | 
 | 	 else.  */ | 
 |  | 
 |       regcache_raw_write_signed (regcache, | 
 | 				 gdbarch_sp_regnum (gdbarch), sp); | 
 |  | 
 |       /* If the last argument copied into the registers didn't fit there  | 
 | 	 completely, push the rest of it into stack.  */ | 
 |  | 
 |       if (argbytes) | 
 | 	{ | 
 | 	  write_memory (sp + 24 + (ii * 4), | 
 | 			value_contents (arg).data () + argbytes, | 
 | 			len - argbytes); | 
 | 	  ++argno; | 
 | 	  ii += ((len - argbytes + 3) & -4) / 4; | 
 | 	} | 
 |  | 
 |       /* Push the rest of the arguments into stack.  */ | 
 |       for (; argno < nargs; ++argno) | 
 | 	{ | 
 |  | 
 | 	  arg = args[argno]; | 
 | 	  type = check_typedef (value_type (arg)); | 
 | 	  len = TYPE_LENGTH (type); | 
 |  | 
 |  | 
 | 	  /* Float types should be passed in fpr's, as well as in the | 
 | 	     stack.  */ | 
 | 	  if (type->code () == TYPE_CODE_FLT && f_argno < 13) | 
 | 	    { | 
 |  | 
 | 	      gdb_assert (len <= 8); | 
 |  | 
 | 	      regcache->cooked_write (tdep->ppc_fp0_regnum + 1 + f_argno, | 
 | 				      value_contents (arg).data ()); | 
 | 	      ++f_argno; | 
 | 	    } | 
 |  | 
 | 	  write_memory (sp + 24 + (ii * 4), value_contents (arg).data (), len); | 
 | 	  ii += ((len + 3) & -4) / 4; | 
 | 	} | 
 |     } | 
 |  | 
 |   /* Set the stack pointer.  According to the ABI, the SP is meant to | 
 |      be set _before_ the corresponding stack space is used.  On AIX, | 
 |      this even applies when the target has been completely stopped! | 
 |      Not doing this can lead to conflicts with the kernel which thinks | 
 |      that it still has control over this not-yet-allocated stack | 
 |      region.  */ | 
 |   regcache_raw_write_signed (regcache, gdbarch_sp_regnum (gdbarch), sp); | 
 |  | 
 |   /* Set back chain properly.  */ | 
 |   store_unsigned_integer (tmp_buffer, wordsize, byte_order, saved_sp); | 
 |   write_memory (sp, tmp_buffer, wordsize); | 
 |  | 
 |   /* Point the inferior function call's return address at the dummy's | 
 |      breakpoint.  */ | 
 |   regcache_raw_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr); | 
 |  | 
 |   /* 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; | 
 | } | 
 |  | 
 | static enum return_value_convention | 
 | rs6000_return_value (struct gdbarch *gdbarch, struct value *function, | 
 | 		     struct type *valtype, struct regcache *regcache, | 
 | 		     gdb_byte *readbuf, const gdb_byte *writebuf) | 
 | { | 
 |   ppc_gdbarch_tdep *tdep = (ppc_gdbarch_tdep *) gdbarch_tdep (gdbarch); | 
 |   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); | 
 |  | 
 |   /* The calling convention this function implements assumes the | 
 |      processor has floating-point registers.  We shouldn't be using it | 
 |      on PowerPC variants that lack them.  */ | 
 |   gdb_assert (ppc_floating_point_unit_p (gdbarch)); | 
 |  | 
 |   /* AltiVec extension: Functions that declare a vector data type as a | 
 |      return value place that return value in VR2.  */ | 
 |   if (valtype->code () == TYPE_CODE_ARRAY && valtype->is_vector () | 
 |       && TYPE_LENGTH (valtype) == 16) | 
 |     { | 
 |       if (readbuf) | 
 | 	regcache->cooked_read (tdep->ppc_vr0_regnum + 2, readbuf); | 
 |       if (writebuf) | 
 | 	regcache->cooked_write (tdep->ppc_vr0_regnum + 2, writebuf); | 
 |  | 
 |       return RETURN_VALUE_REGISTER_CONVENTION; | 
 |     } | 
 |  | 
 |   /* If the called subprogram returns an aggregate, there exists an | 
 |      implicit first argument, whose value is the address of a caller- | 
 |      allocated buffer into which the callee is assumed to store its | 
 |      return value.  All explicit parameters are appropriately | 
 |      relabeled.  */ | 
 |   if (valtype->code () == TYPE_CODE_STRUCT | 
 |       || valtype->code () == TYPE_CODE_UNION | 
 |       || valtype->code () == TYPE_CODE_ARRAY) | 
 |     return RETURN_VALUE_STRUCT_CONVENTION; | 
 |  | 
 |   /* Scalar floating-point values are returned in FPR1 for float or | 
 |      double, and in FPR1:FPR2 for quadword precision.  Fortran | 
 |      complex*8 and complex*16 are returned in FPR1:FPR2, and | 
 |      complex*32 is returned in FPR1:FPR4.  */ | 
 |   if (valtype->code () == TYPE_CODE_FLT | 
 |       && (TYPE_LENGTH (valtype) == 4 || TYPE_LENGTH (valtype) == 8)) | 
 |     { | 
 |       struct type *regtype = register_type (gdbarch, tdep->ppc_fp0_regnum); | 
 |       gdb_byte regval[8]; | 
 |  | 
 |       /* FIXME: kettenis/2007-01-01: Add support for quadword | 
 | 	 precision and complex.  */ | 
 |  | 
 |       if (readbuf) | 
 | 	{ | 
 | 	  regcache->cooked_read (tdep->ppc_fp0_regnum + 1, regval); | 
 | 	  target_float_convert (regval, regtype, readbuf, valtype); | 
 | 	} | 
 |       if (writebuf) | 
 | 	{ | 
 | 	  target_float_convert (writebuf, valtype, regval, regtype); | 
 | 	  regcache->cooked_write (tdep->ppc_fp0_regnum + 1, regval); | 
 | 	} | 
 |  | 
 |       return RETURN_VALUE_REGISTER_CONVENTION; | 
 |   } | 
 |  | 
 |   /* Values of the types int, long, short, pointer, and char (length | 
 |      is less than or equal to four bytes), as well as bit values of | 
 |      lengths less than or equal to 32 bits, must be returned right | 
 |      justified in GPR3 with signed values sign extended and unsigned | 
 |      values zero extended, as necessary.  */ | 
 |   if (TYPE_LENGTH (valtype) <= tdep->wordsize) | 
 |     { | 
 |       if (readbuf) | 
 | 	{ | 
 | 	  ULONGEST regval; | 
 |  | 
 | 	  /* For reading we don't have to worry about sign extension.  */ | 
 | 	  regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 3, | 
 | 					 ®val); | 
 | 	  store_unsigned_integer (readbuf, TYPE_LENGTH (valtype), byte_order, | 
 | 				  regval); | 
 | 	} | 
 |       if (writebuf) | 
 | 	{ | 
 | 	  /* For writing, use unpack_long since that should handle any | 
 | 	     required sign extension.  */ | 
 | 	  regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3, | 
 | 					  unpack_long (valtype, writebuf)); | 
 | 	} | 
 |  | 
 |       return RETURN_VALUE_REGISTER_CONVENTION; | 
 |     } | 
 |  | 
 |   /* Eight-byte non-floating-point scalar values must be returned in | 
 |      GPR3:GPR4.  */ | 
 |  | 
 |   if (TYPE_LENGTH (valtype) == 8) | 
 |     { | 
 |       gdb_assert (valtype->code () != TYPE_CODE_FLT); | 
 |       gdb_assert (tdep->wordsize == 4); | 
 |  | 
 |       if (readbuf) | 
 | 	{ | 
 | 	  gdb_byte regval[8]; | 
 |  | 
 | 	  regcache->cooked_read (tdep->ppc_gp0_regnum + 3, regval); | 
 | 	  regcache->cooked_read (tdep->ppc_gp0_regnum + 4, regval + 4); | 
 | 	  memcpy (readbuf, regval, 8); | 
 | 	} | 
 |       if (writebuf) | 
 | 	{ | 
 | 	  regcache->cooked_write (tdep->ppc_gp0_regnum + 3, writebuf); | 
 | 	  regcache->cooked_write (tdep->ppc_gp0_regnum + 4, writebuf + 4); | 
 | 	} | 
 |  | 
 |       return RETURN_VALUE_REGISTER_CONVENTION; | 
 |     } | 
 |  | 
 |   return RETURN_VALUE_STRUCT_CONVENTION; | 
 | } | 
 |  | 
 | /* Support for CONVERT_FROM_FUNC_PTR_ADDR (ARCH, ADDR, TARG). | 
 |  | 
 |    Usually a function pointer's representation is simply the address | 
 |    of the function.  On the RS/6000 however, a function pointer is | 
 |    represented by a pointer to an OPD entry.  This OPD entry contains | 
 |    three words, the first word is the address of the function, the | 
 |    second word is the TOC pointer (r2), and the third word is the | 
 |    static chain value.  Throughout GDB it is currently assumed that a | 
 |    function pointer contains the address of the function, which is not | 
 |    easy to fix.  In addition, the conversion of a function address to | 
 |    a function pointer would require allocation of an OPD entry in the | 
 |    inferior's memory space, with all its drawbacks.  To be able to | 
 |    call C++ virtual methods in the inferior (which are called via | 
 |    function pointers), find_function_addr uses this function to get the | 
 |    function address from a function pointer.  */ | 
 |  | 
 | /* Return real function address if ADDR (a function pointer) is in the data | 
 |    space and is therefore a special function pointer.  */ | 
 |  | 
 | static CORE_ADDR | 
 | rs6000_convert_from_func_ptr_addr (struct gdbarch *gdbarch, | 
 | 				   CORE_ADDR addr, | 
 | 				   struct target_ops *targ) | 
 | { | 
 |   ppc_gdbarch_tdep *tdep = (ppc_gdbarch_tdep *) gdbarch_tdep (gdbarch); | 
 |   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); | 
 |   struct obj_section *s; | 
 |  | 
 |   s = find_pc_section (addr); | 
 |  | 
 |   /* Normally, functions live inside a section that is executable. | 
 |      So, if ADDR points to a non-executable section, then treat it | 
 |      as a function descriptor and return the target address iff | 
 |      the target address itself points to a section that is executable.  */ | 
 |   if (s && (s->the_bfd_section->flags & SEC_CODE) == 0) | 
 |     { | 
 |       CORE_ADDR pc = 0; | 
 |       struct obj_section *pc_section; | 
 |  | 
 |       try | 
 | 	{ | 
 | 	  pc = read_memory_unsigned_integer (addr, tdep->wordsize, byte_order); | 
 | 	} | 
 |       catch (const gdb_exception_error &e) | 
 | 	{ | 
 | 	  /* 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; | 
 | 	} | 
 |  | 
 |       pc_section = find_pc_section (pc); | 
 |  | 
 |       if (pc_section && (pc_section->the_bfd_section->flags & SEC_CODE)) | 
 | 	return pc; | 
 |     } | 
 |  | 
 |   return addr; | 
 | } | 
 |  | 
 |  | 
 | /* Calculate the destination of a branch/jump.  Return -1 if not a branch.  */ | 
 |  | 
 | static CORE_ADDR | 
 | branch_dest (struct regcache *regcache, int opcode, int instr, | 
 | 	     CORE_ADDR pc, CORE_ADDR safety) | 
 | { | 
 |   struct gdbarch *gdbarch = regcache->arch (); | 
 |   ppc_gdbarch_tdep *tdep = (ppc_gdbarch_tdep *) gdbarch_tdep (gdbarch); | 
 |   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); | 
 |   CORE_ADDR dest; | 
 |   int immediate; | 
 |   int absolute; | 
 |   int ext_op; | 
 |  | 
 |   absolute = (int) ((instr >> 1) & 1); | 
 |  | 
 |   switch (opcode) | 
 |     { | 
 |     case 18: | 
 |       immediate = ((instr & ~3) << 6) >> 6;	/* br unconditional */ | 
 |       if (absolute) | 
 | 	dest = immediate; | 
 |       else | 
 | 	dest = pc + immediate; | 
 |       break; | 
 |  | 
 |     case 16: | 
 |       immediate = ((instr & ~3) << 16) >> 16;	/* br conditional */ | 
 |       if (absolute) | 
 | 	dest = immediate; | 
 |       else | 
 | 	dest = pc + immediate; | 
 |       break; | 
 |  | 
 |     case 19: | 
 |       ext_op = (instr >> 1) & 0x3ff; | 
 |  | 
 |       if (ext_op == 16)		/* br conditional register */ | 
 | 	{ | 
 | 	  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) | 
 | 	    { | 
 | 	      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 = 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 = regcache_raw_get_unsigned (regcache, | 
 | 					      tdep->ppc_lr_regnum) & ~3; | 
 | 	} | 
 |       else | 
 | 	return -1; | 
 |       break; | 
 |  | 
 |     default: | 
 |       return -1; | 
 |     } | 
 |   return (dest < AIX_TEXT_SEGMENT_BASE) ? safety : dest; | 
 | } | 
 |  | 
 | /* AIX does not support PT_STEP.  Simulate it.  */ | 
 |  | 
 | static std::vector<CORE_ADDR> | 
 | rs6000_software_single_step (struct regcache *regcache) | 
 | { | 
 |   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 = regcache_read_pc (regcache); | 
 |  | 
 |   insn = read_memory_integer (loc, 4, byte_order); | 
 |  | 
 |   std::vector<CORE_ADDR> 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 (regcache, opcode, insn, loc, breaks[0]); | 
 |  | 
 |   /* Don't put two breakpoints on the same address.  */ | 
 |   if (breaks[1] == breaks[0]) | 
 |     breaks[1] = -1; | 
 |  | 
 |   for (ii = 0; ii < 2; ++ii) | 
 |     { | 
 |       /* ignore invalid breakpoint.  */ | 
 |       if (breaks[ii] == -1) | 
 | 	continue; | 
 |  | 
 |       next_pcs.push_back (breaks[ii]); | 
 |     } | 
 |  | 
 |   errno = 0;			/* FIXME, don't ignore errors!  */ | 
 |   /* What errors?  {read,write}_memory call error().  */ | 
 |   return next_pcs; | 
 | } | 
 |  | 
 | /* 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) | 
 | { | 
 |   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 <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) | 
 | { | 
 |   ppc_gdbarch_tdep *tdep = (ppc_gdbarch_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_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); | 
 | } | 
 |  | 
 | static void | 
 | rs6000_aix_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch) | 
 | { | 
 |   ppc_gdbarch_tdep *tdep = (ppc_gdbarch_tdep *) gdbarch_tdep (gdbarch); | 
 |  | 
 |   /* RS6000/AIX does not support PT_STEP.  Has to be simulated.  */ | 
 |   set_gdbarch_software_single_step (gdbarch, rs6000_software_single_step); | 
 |  | 
 |   /* Displaced stepping is currently not supported in combination with | 
 |      software single-stepping.  These override the values set by | 
 |      rs6000_gdbarch_init.  */ | 
 |   set_gdbarch_displaced_step_copy_insn (gdbarch, NULL); | 
 |   set_gdbarch_displaced_step_fixup (gdbarch, NULL); | 
 |   set_gdbarch_displaced_step_prepare (gdbarch, NULL); | 
 |   set_gdbarch_displaced_step_finish (gdbarch, NULL); | 
 |  | 
 |   set_gdbarch_push_dummy_call (gdbarch, rs6000_push_dummy_call); | 
 |   set_gdbarch_return_value (gdbarch, rs6000_return_value); | 
 |   set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT); | 
 |  | 
 |   /* Handle RS/6000 function pointers (which are really function | 
 |      descriptors).  */ | 
 |   set_gdbarch_convert_from_func_ptr_addr | 
 |     (gdbarch, rs6000_convert_from_func_ptr_addr); | 
 |  | 
 |   /* Core file support.  */ | 
 |   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; | 
 |   else | 
 |     tdep->lr_frame_offset = 8; | 
 |  | 
 |   if (tdep->wordsize == 4) | 
 |     /* PowerOpen / AIX 32 bit.  The saved area or red zone consists of | 
 |        19 4 byte GPRS + 18 8 byte FPRs giving a total of 220 bytes. | 
 |        Problem is, 220 isn't frame (16 byte) aligned.  Round it up to | 
 |        224.  */ | 
 |     set_gdbarch_frame_red_zone_size (gdbarch, 224); | 
 |   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); | 
 |  | 
 |   set_solib_ops (gdbarch, &solib_aix_so_ops); | 
 |   frame_unwind_append_unwinder (gdbarch, &aix_sighandle_frame_unwind); | 
 | } | 
 |  | 
 | void _initialize_rs6000_aix_tdep (); | 
 | void | 
 | _initialize_rs6000_aix_tdep () | 
 | { | 
 |   gdbarch_register_osabi_sniffer (bfd_arch_rs6000, | 
 | 				  bfd_target_xcoff_flavour, | 
 | 				  rs6000_aix_osabi_sniffer); | 
 |   gdbarch_register_osabi_sniffer (bfd_arch_powerpc, | 
 | 				  bfd_target_xcoff_flavour, | 
 | 				  rs6000_aix_osabi_sniffer); | 
 |  | 
 |   gdbarch_register_osabi (bfd_arch_rs6000, 0, GDB_OSABI_AIX, | 
 | 			  rs6000_aix_init_osabi); | 
 |   gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_AIX, | 
 | 			  rs6000_aix_init_osabi); | 
 | } | 
 |  |