2004-04-17 Randolph Chung <tausq@debian.org>
[deliverable/binutils-gdb.git] / gdb / ppc-sysv-tdep.c
index 82c58daf29ed9135450954952b37dd293e5a97b0..60cf986bd72e660fdd143af663452c93cedd581c 100644 (file)
@@ -1,7 +1,7 @@
 /* Target-dependent code for PowerPC systems using the SVR4 ABI
    for GDB, the GNU debugger.
 
-   Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "regcache.h"
 #include "value.h"
 #include "gdb_string.h"
-
+#include "gdb_assert.h"
 #include "ppc-tdep.h"
+#include "target.h"
+#include "objfiles.h"
 
 /* Pass the arguments in either registers, or in the stack. Using the
    ppc sysv ABI, the first eight words of the argument list (that might
@@ -305,16 +307,527 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
   return sp;
 }
 
-/* Structures 8 bytes or less long are returned in the r3 & r4
-   registers, according to the SYSV ABI. */
-int
-ppc_sysv_abi_use_struct_convention (int gcc_p, struct type *value_type)
+/* Handle the return-value conventions specified by the SysV 32-bit
+   PowerPC ABI (including all the supplements):
+
+   no floating-point: floating-point values returned using 32-bit
+   general-purpose registers.
+
+   Altivec: 128-bit vectors returned using vector registers.
+
+   e500: 64-bit vectors returned using the full full 64 bit EV
+   register, floating-point values returned using 32-bit
+   general-purpose registers.
+
+   GCC (broken): Small struct values right (instead of left) aligned
+   when returned in general-purpose registers.  */
+
+static enum return_value_convention
+do_ppc_sysv_return_value (struct gdbarch *gdbarch, struct type *type,
+                         struct regcache *regcache, void *readbuf,
+                         const void *writebuf, int broken_gcc)
 {
-  if ((TYPE_LENGTH (value_type) == 16 || TYPE_LENGTH (value_type) == 8)
-      && TYPE_VECTOR (value_type))
-    return 0;
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  gdb_assert (tdep->wordsize == 4);
+  if (TYPE_CODE (type) == TYPE_CODE_FLT
+      && TYPE_LENGTH (type) <= 8
+      && ppc_floating_point_unit_p (gdbarch))
+    {
+      if (readbuf)
+       {
+         /* Floats and doubles stored in "f1".  Convert the value to
+            the required type.  */
+         char regval[MAX_REGISTER_SIZE];
+         struct type *regtype = register_type (gdbarch, FP0_REGNUM + 1);
+         regcache_cooked_read (regcache, FP0_REGNUM + 1, regval);
+         convert_typed_floating (regval, regtype, readbuf, type);
+       }
+      if (writebuf)
+       {
+         /* Floats and doubles stored in "f1".  Convert the value to
+            the register's "double" type.  */
+         char regval[MAX_REGISTER_SIZE];
+         struct type *regtype = register_type (gdbarch, FP0_REGNUM);
+         convert_typed_floating (writebuf, type, regval, regtype);
+         regcache_cooked_write (regcache, FP0_REGNUM + 1, regval);
+       }
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  if ((TYPE_CODE (type) == TYPE_CODE_INT && TYPE_LENGTH (type) == 8)
+      || (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8))
+    {
+      if (readbuf)
+       {
+         /* A long long, or a double stored in the 32 bit r3/r4.  */
+         regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3,
+                               (bfd_byte *) readbuf + 0);
+         regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
+                               (bfd_byte *) readbuf + 4);
+       }
+      if (writebuf)
+       {
+         /* A long long, or a double stored in the 32 bit r3/r4.  */
+         regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3,
+                                (const bfd_byte *) writebuf + 0);
+         regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
+                                (const bfd_byte *) writebuf + 4);
+       }
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  if (TYPE_CODE (type) == TYPE_CODE_INT
+      && TYPE_LENGTH (type) <= tdep->wordsize)
+    {
+      if (readbuf)
+       {
+         /* Some sort of integer stored in r3.  Since TYPE isn't
+            bigger than the register, sign extension isn't a problem
+            - just do everything unsigned.  */
+         ULONGEST regval;
+         regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
+                                        &regval);
+         store_unsigned_integer (readbuf, TYPE_LENGTH (type), regval);
+       }
+      if (writebuf)
+       {
+         /* Some sort of integer stored in r3.  Use unpack_long since
+            that should handle any required sign extension.  */
+         regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
+                                         unpack_long (type, writebuf));
+       }
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  if (TYPE_LENGTH (type) == 16
+      && TYPE_CODE (type) == TYPE_CODE_ARRAY
+      && TYPE_VECTOR (type) && tdep->ppc_vr0_regnum >= 0)
+    {
+      if (readbuf)
+       {
+         /* Altivec places the return value in "v2".  */
+         regcache_cooked_read (regcache, tdep->ppc_vr0_regnum + 2, readbuf);
+       }
+      if (writebuf)
+       {
+         /* Altivec places the return value in "v2".  */
+         regcache_cooked_write (regcache, tdep->ppc_vr0_regnum + 2, writebuf);
+       }
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  if (TYPE_LENGTH (type) == 8
+      && TYPE_CODE (type) == TYPE_CODE_ARRAY
+      && TYPE_VECTOR (type) && tdep->ppc_ev0_regnum >= 0)
+    {
+      /* The e500 ABI places return values for the 64-bit DSP types
+        (__ev64_opaque__) in r3.  However, in GDB-speak, ev3
+        corresponds to the entire r3 value for e500, whereas GDB's r3
+        only corresponds to the least significant 32-bits.  So place
+        the 64-bit DSP type's value in ev3.  */
+      if (readbuf)
+       regcache_cooked_read (regcache, tdep->ppc_ev0_regnum + 3, readbuf);
+      if (writebuf)
+       regcache_cooked_write (regcache, tdep->ppc_ev0_regnum + 3, writebuf);
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  if (broken_gcc && TYPE_LENGTH (type) <= 8)
+    {
+      if (readbuf)
+       {
+         /* GCC screwed up.  The last register isn't "left" aligned.
+            Need to extract the least significant part of each
+            register and then store that.  */
+         /* Transfer any full words.  */
+         int word = 0;
+         while (1)
+           {
+             ULONGEST reg;
+             int len = TYPE_LENGTH (type) - word * tdep->wordsize;
+             if (len <= 0)
+               break;
+             if (len > tdep->wordsize)
+               len = tdep->wordsize;
+             regcache_cooked_read_unsigned (regcache,
+                                            tdep->ppc_gp0_regnum + 3 + word,
+                                            &reg);
+             store_unsigned_integer (((bfd_byte *) readbuf
+                                      + word * tdep->wordsize), len, reg);
+             word++;
+           }
+       }
+      if (writebuf)
+       {
+         /* GCC screwed up.  The last register isn't "left" aligned.
+            Need to extract the least significant part of each
+            register and then store that.  */
+         /* Transfer any full words.  */
+         int word = 0;
+         while (1)
+           {
+             ULONGEST reg;
+             int len = TYPE_LENGTH (type) - word * tdep->wordsize;
+             if (len <= 0)
+               break;
+             if (len > tdep->wordsize)
+               len = tdep->wordsize;
+             reg = extract_unsigned_integer (((const bfd_byte *) writebuf
+                                              + word * tdep->wordsize), len);
+             regcache_cooked_write_unsigned (regcache,
+                                             tdep->ppc_gp0_regnum + 3 + word,
+                                             reg);
+             word++;
+           }
+       }
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  if (TYPE_LENGTH (type) <= 8)
+    {
+      if (readbuf)
+       {
+         /* This matches SVr4 PPC, it does not match GCC.  */
+         /* The value is right-padded to 8 bytes and then loaded, as
+            two "words", into r3/r4.  */
+         char regvals[MAX_REGISTER_SIZE * 2];
+         regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3,
+                               regvals + 0 * tdep->wordsize);
+         if (TYPE_LENGTH (type) > tdep->wordsize)
+           regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4,
+                                 regvals + 1 * tdep->wordsize);
+         memcpy (readbuf, regvals, TYPE_LENGTH (type));
+       }
+      if (writebuf)
+       {
+         /* This matches SVr4 PPC, it does not match GCC.  */
+         /* The value is padded out to 8 bytes and then loaded, as
+            two "words" into r3/r4.  */
+         char regvals[MAX_REGISTER_SIZE * 2];
+         memset (regvals, 0, sizeof regvals);
+         memcpy (regvals, writebuf, TYPE_LENGTH (type));
+         regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3,
+                                regvals + 0 * tdep->wordsize);
+         if (TYPE_LENGTH (type) > tdep->wordsize)
+           regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
+                                  regvals + 1 * tdep->wordsize);
+       }
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  return RETURN_VALUE_STRUCT_CONVENTION;
+}
+
+enum return_value_convention
+ppc_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *valtype,
+                          struct regcache *regcache, void *readbuf,
+                          const void *writebuf)
+{
+  return do_ppc_sysv_return_value (gdbarch, valtype, regcache, readbuf,
+                                  writebuf, 0);
+}
 
-  return (TYPE_LENGTH (value_type) > 8);
+enum return_value_convention
+ppc_sysv_abi_broken_return_value (struct gdbarch *gdbarch,
+                                 struct type *valtype,
+                                 struct regcache *regcache,
+                                 void *readbuf, const void *writebuf)
+{
+  return do_ppc_sysv_return_value (gdbarch, valtype, regcache, readbuf,
+                                  writebuf, 1);
+}
+
+/* Pass the arguments in either registers, or in the stack. Using the
+   ppc 64 bit SysV ABI.
+
+   This implements a dumbed down version of the ABI.  It always writes
+   values to memory, GPR and FPR, even when not necessary.  Doing this
+   greatly simplifies the logic. */
+
+CORE_ADDR
+ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+                               struct regcache *regcache, CORE_ADDR bp_addr,
+                               int nargs, struct value **args, CORE_ADDR sp,
+                               int struct_return, CORE_ADDR struct_addr)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  /* By this stage in the proceedings, SP has been decremented by "red
+     zone size" + "struct return size".  Fetch the stack-pointer from
+     before this and use that as the BACK_CHAIN.  */
+  const CORE_ADDR back_chain = read_sp ();
+  /* See for-loop comment below.  */
+  int write_pass;
+  /* Size of the Altivec's vector parameter region, the final value is
+     computed in the for-loop below.  */
+  LONGEST vparam_size = 0;
+  /* Size of the general parameter region, the final value is computed
+     in the for-loop below.  */
+  LONGEST gparam_size = 0;
+  /* Kevin writes ... I don't mind seeing tdep->wordsize used in the
+     calls to align_up(), align_down(), etc.  because this makes it
+     easier to reuse this code (in a copy/paste sense) in the future,
+     but it is a 64-bit ABI and asserting that the wordsize is 8 bytes
+     at some point makes it easier to verify that this function is
+     correct without having to do a non-local analysis to figure out
+     the possible values of tdep->wordsize.  */
+  gdb_assert (tdep->wordsize == 8);
+
+  /* Go through the argument list twice.
+
+     Pass 1: Compute the function call's stack space and register
+     requirements.
+
+     Pass 2: Replay the same computation but this time also write the
+     values out to the target.  */
+
+  for (write_pass = 0; write_pass < 2; write_pass++)
+    {
+      int argno;
+      /* Next available floating point register for float and double
+         arguments.  */
+      int freg = 1;
+      /* Next available general register for non-vector (but possibly
+         float) arguments.  */
+      int greg = 3;
+      /* Next available vector register for vector arguments.  */
+      int vreg = 2;
+      /* The address, at which the next general purpose parameter
+         (integer, struct, float, ...) should be saved.  */
+      CORE_ADDR gparam;
+      /* Address, at which the next Altivec vector parameter should be
+         saved.  */
+      CORE_ADDR vparam;
+
+      if (!write_pass)
+       {
+         /* During the first pass, GPARAM and VPARAM are more like
+            offsets (start address zero) than addresses.  That way
+            the accumulate the total stack space each region
+            requires.  */
+         gparam = 0;
+         vparam = 0;
+       }
+      else
+       {
+         /* Decrement the stack pointer making space for the Altivec
+            and general on-stack parameters.  Set vparam and gparam
+            to their corresponding regions.  */
+         vparam = align_down (sp - vparam_size, 16);
+         gparam = align_down (vparam - gparam_size, 16);
+         /* Add in space for the TOC, link editor double word,
+            compiler double word, LR save area, CR save area.  */
+         sp = align_down (gparam - 48, 16);
+       }
+
+      /* If the function is returning a `struct', then there is an
+         extra hidden parameter (which will be passed in r3)
+         containing the address of that struct..  In that case we
+         should advance one word and start from r4 register to copy
+         parameters.  This also consumes one on-stack parameter slot.  */
+      if (struct_return)
+       {
+         if (write_pass)
+           regcache_cooked_write_signed (regcache,
+                                         tdep->ppc_gp0_regnum + greg,
+                                         struct_addr);
+         greg++;
+         gparam = align_up (gparam + tdep->wordsize, tdep->wordsize);
+       }
+
+      for (argno = 0; argno < nargs; argno++)
+       {
+         struct value *arg = args[argno];
+         struct type *type = check_typedef (VALUE_TYPE (arg));
+         char *val = VALUE_CONTENTS (arg);
+         if (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) <= 8)
+           {
+             /* Floats and Doubles go in f1 .. f13.  They also
+                consume a left aligned GREG,, and can end up in
+                memory.  */
+             if (write_pass)
+               {
+                 if (ppc_floating_point_unit_p (current_gdbarch)
+                     && freg <= 13)
+                   {
+                     char regval[MAX_REGISTER_SIZE];
+                     struct type *regtype = register_type (gdbarch,
+                                                           FP0_REGNUM);
+                     convert_typed_floating (val, type, regval, regtype);
+                     regcache_cooked_write (regcache, FP0_REGNUM + freg,
+                                            regval);
+                   }
+                 if (greg <= 10)
+                   {
+                     /* The ABI states "Single precision floating
+                        point values are mapped to the first word in
+                        a single doubleword" and "... floating point
+                        values mapped to the first eight doublewords
+                        of the parameter save area are also passed in
+                        general registers").
+
+                        This code interprets that to mean: store it,
+                        left aligned, in the general register.  */
+                     char regval[MAX_REGISTER_SIZE];
+                     memset (regval, 0, sizeof regval);
+                     memcpy (regval, val, TYPE_LENGTH (type));
+                     regcache_cooked_write (regcache,
+                                            tdep->ppc_gp0_regnum + greg,
+                                            regval);
+                   }
+                 write_memory (gparam, val, TYPE_LENGTH (type));
+               }
+             /* Always consume parameter stack space.  */
+             freg++;
+             greg++;
+             gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+           }
+         else if (TYPE_LENGTH (type) == 16 && TYPE_VECTOR (type)
+                  && TYPE_CODE (type) == TYPE_CODE_ARRAY
+                  && tdep->ppc_vr0_regnum >= 0)
+           {
+             /* In the Altivec ABI, vectors go in the vector
+                registers v2 .. v13, or when that runs out, a vector
+                annex which goes above all the normal parameters.
+                NOTE: cagney/2003-09-21: This is a guess based on the
+                PowerOpen Altivec ABI.  */
+             if (vreg <= 13)
+               {
+                 if (write_pass)
+                   regcache_cooked_write (regcache,
+                                          tdep->ppc_vr0_regnum + vreg, val);
+                 vreg++;
+               }
+             else
+               {
+                 if (write_pass)
+                   write_memory (vparam, val, TYPE_LENGTH (type));
+                 vparam = align_up (vparam + TYPE_LENGTH (type), 16);
+               }
+           }
+         else if ((TYPE_CODE (type) == TYPE_CODE_INT
+                   || TYPE_CODE (type) == TYPE_CODE_ENUM)
+                  && TYPE_LENGTH (type) <= 8)
+           {
+             /* Scalars get sign[un]extended and go in gpr3 .. gpr10.
+                They can also end up in memory.  */
+             if (write_pass)
+               {
+                 /* Sign extend the value, then store it unsigned.  */
+                 ULONGEST word = unpack_long (type, val);
+                 if (greg <= 10)
+                   regcache_cooked_write_unsigned (regcache,
+                                                   tdep->ppc_gp0_regnum +
+                                                   greg, word);
+                 write_memory_unsigned_integer (gparam, tdep->wordsize,
+                                                word);
+               }
+             greg++;
+             gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+           }
+         else
+           {
+             int byte;
+             for (byte = 0; byte < TYPE_LENGTH (type);
+                  byte += tdep->wordsize)
+               {
+                 if (write_pass && greg <= 10)
+                   {
+                     char regval[MAX_REGISTER_SIZE];
+                     int len = TYPE_LENGTH (type) - byte;
+                     if (len > tdep->wordsize)
+                       len = tdep->wordsize;
+                     memset (regval, 0, sizeof regval);
+                     /* WARNING: cagney/2003-09-21: As best I can
+                        tell, the ABI specifies that the value should
+                        be left aligned.  Unfortunately, GCC doesn't
+                        do this - it instead right aligns even sized
+                        values and puts odd sized values on the
+                        stack.  Work around that by putting both a
+                        left and right aligned value into the
+                        register (hopefully no one notices :-^).
+                        Arrrgh!  */
+                     /* Left aligned (8 byte values such as pointers
+                        fill the buffer).  */
+                     memcpy (regval, val + byte, len);
+                     /* Right aligned (but only if even).  */
+                     if (len == 1 || len == 2 || len == 4)
+                       memcpy (regval + tdep->wordsize - len,
+                               val + byte, len);
+                     regcache_cooked_write (regcache, greg, regval);
+                   }
+                 greg++;
+               }
+             if (write_pass)
+               /* WARNING: cagney/2003-09-21: Strictly speaking, this
+                  isn't necessary, unfortunately, GCC appears to get
+                  "struct convention" parameter passing wrong putting
+                  odd sized structures in memory instead of in a
+                  register.  Work around this by always writing the
+                  value to memory.  Fortunately, doing this
+                  simplifies the code.  */
+               write_memory (gparam, val, TYPE_LENGTH (type));
+             /* Always consume parameter stack space.  */
+             gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+           }
+       }
+
+      if (!write_pass)
+       {
+         /* Save the true region sizes ready for the second pass.  */
+         vparam_size = vparam;
+         /* Make certain that the general parameter save area is at
+            least the minimum 8 registers (or doublewords) in size.  */
+         if (greg < 8)
+           gparam_size = 8 * tdep->wordsize;
+         else
+           gparam_size = gparam;
+       }
+    }
+
+  /* Update %sp.   */
+  regcache_cooked_write_signed (regcache, SP_REGNUM, sp);
+
+  /* Write the backchain (it occupies WORDSIZED bytes).  */
+  write_memory_signed_integer (sp, tdep->wordsize, back_chain);
+
+  /* Point the inferior function call's return address at the dummy's
+     breakpoint.  */
+  regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
+
+  /* Find a value for the TOC register.  Every symbol should have both
+     ".FN" and "FN" in the minimal symbol table.  "FN" points at the
+     FN's descriptor, while ".FN" points at the entry point (which
+     matches FUNC_ADDR).  Need to reverse from FUNC_ADDR back to the
+     FN's descriptor address (while at the same time being careful to
+     find "FN" in the same object file as ".FN").  */
+  {
+    /* Find the minimal symbol that corresponds to FUNC_ADDR (should
+       have the name ".FN").  */
+    struct minimal_symbol *dot_fn = lookup_minimal_symbol_by_pc (func_addr);
+    if (dot_fn != NULL && SYMBOL_LINKAGE_NAME (dot_fn)[0] == '.')
+      {
+       /* Get the section that contains FUNC_ADR.  Need this for the
+           "objfile" that it contains.  */
+       struct obj_section *dot_fn_section = find_pc_section (func_addr);
+       if (dot_fn_section != NULL && dot_fn_section->objfile != NULL)
+         {
+           /* Now find the corresponding "FN" (dropping ".") minimal
+              symbol's address.  Only look for the minimal symbol in
+              ".FN"'s object file - avoids problems when two object
+              files (i.e., shared libraries) contain a minimal symbol
+              with the same name.  */
+           struct minimal_symbol *fn =
+             lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (dot_fn) + 1, NULL,
+                                    dot_fn_section->objfile);
+           if (fn != NULL)
+             {
+               /* Got the address of that descriptor.  The TOC is the
+                  second double word.  */
+               CORE_ADDR toc =
+                 read_memory_unsigned_integer (SYMBOL_VALUE_ADDRESS (fn)
+                                               + tdep->wordsize,
+                                               tdep->wordsize);
+               regcache_cooked_write_unsigned (regcache,
+                                               tdep->ppc_gp0_regnum + 2, toc);
+             }
+         }
+      }
+  }
+
+  return sp;
 }
 
 
@@ -324,65 +837,50 @@ ppc_sysv_abi_use_struct_convention (int gcc_p, struct type *value_type)
    0 if the return-value is instead stored on the stack (a.k.a.,
    struct return convention).
 
-   For a return-value stored in a register: when INVAL is non-NULL,
+   For a return-value stored in a register: when WRITEBUF is non-NULL,
    copy the buffer to the corresponding register return-value location
-   location; when OUTVAL is non-NULL, fill the buffer from the
+   location; when READBUF is non-NULL, fill the buffer from the
    corresponding register return-value location.  */
-
-/* Potential ways that a function can return a value of a given type.  */
 enum return_value_convention
+ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *valtype,
+                            struct regcache *regcache, void *readbuf,
+                            const void *writebuf)
 {
-  /* Where the return value has been squeezed into one or more
-     registers.  */
-  RETURN_VALUE_REGISTER_CONVENTION,
-  /* Commonly known as the "struct return convention".  The caller
-     passes an additional hidden first parameter to the caller.  That
-     parameter contains the address at which the value being returned
-     should be stored.  While typically, and historically, used for
-     large structs, this is convention is applied to values of many
-     different types.  */
-  RETURN_VALUE_STRUCT_CONVENTION
-};
-
-static enum return_value_convention
-ppc64_sysv_abi_return_value (struct type *valtype, struct regcache *regcache,
-                            const void *inval, void *outval)
-{
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   /* Floats and doubles in F1.  */
   if (TYPE_CODE (valtype) == TYPE_CODE_FLT && TYPE_LENGTH (valtype) <= 8)
     {
       char regval[MAX_REGISTER_SIZE];
-      struct type *regtype = register_type (current_gdbarch, FP0_REGNUM);
-      if (inval != NULL)
+      struct type *regtype = register_type (gdbarch, FP0_REGNUM);
+      if (writebuf != NULL)
        {
-         convert_typed_floating (inval, valtype, regval, regtype);
+         convert_typed_floating (writebuf, valtype, regval, regtype);
          regcache_cooked_write (regcache, FP0_REGNUM + 1, regval);
        }
-      if (outval != NULL)
+      if (readbuf != NULL)
        {
          regcache_cooked_read (regcache, FP0_REGNUM + 1, regval);
-         convert_typed_floating (regval, regtype, outval, valtype);
+         convert_typed_floating (regval, regtype, readbuf, valtype);
        }
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
   if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 8)
     {
       /* Integers in r3.  */
-      if (inval != NULL)
+      if (writebuf != NULL)
        {
          /* Be careful to sign extend the value.  */
          regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
-                                         unpack_long (valtype, inval));
+                                         unpack_long (valtype, writebuf));
        }
-      if (outval != NULL)
+      if (readbuf != NULL)
        {
          /* Extract the integer from r3.  Since this is truncating the
             value, there isn't a sign extension problem.  */
          ULONGEST regval;
          regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
                                         &regval);
-         store_unsigned_integer (outval, TYPE_LENGTH (valtype), regval);
+         store_unsigned_integer (readbuf, TYPE_LENGTH (valtype), regval);
        }
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
@@ -390,10 +888,10 @@ ppc64_sysv_abi_return_value (struct type *valtype, struct regcache *regcache,
   if (TYPE_CODE (valtype) == TYPE_CODE_PTR)
     {
       /* All pointers live in r3.  */
-      if (inval != NULL)
-       regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3, inval);
-      if (outval != NULL)
-       regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, outval);
+      if (writebuf != NULL)
+       regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3, writebuf);
+      if (readbuf != NULL)
+       regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, readbuf);
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
   if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
@@ -402,14 +900,14 @@ ppc64_sysv_abi_return_value (struct type *valtype, struct regcache *regcache,
       && TYPE_LENGTH (TYPE_TARGET_TYPE (valtype)) == 1)
     {
       /* Small character arrays are returned, right justified, in r3.  */
-      int offset = (register_size (current_gdbarch, tdep->ppc_gp0_regnum + 3)
+      int offset = (register_size (gdbarch, tdep->ppc_gp0_regnum + 3)
                    - TYPE_LENGTH (valtype));
-      if (inval != NULL)
+      if (writebuf != NULL)
        regcache_cooked_write_part (regcache, tdep->ppc_gp0_regnum + 3,
-                                   offset, TYPE_LENGTH (valtype), inval);
-      if (outval != NULL)
+                                   offset, TYPE_LENGTH (valtype), writebuf);
+      if (readbuf != NULL)
        regcache_cooked_read_part (regcache, tdep->ppc_gp0_regnum + 3,
-                                  offset, TYPE_LENGTH (valtype), outval);
+                                  offset, TYPE_LENGTH (valtype), readbuf);
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
   /* Big floating point values get stored in adjacent floating
@@ -417,17 +915,17 @@ ppc64_sysv_abi_return_value (struct type *valtype, struct regcache *regcache,
   if (TYPE_CODE (valtype) == TYPE_CODE_FLT
       && (TYPE_LENGTH (valtype) == 16 || TYPE_LENGTH (valtype) == 32))
     {
-      if (inval || outval != NULL)
+      if (writebuf || readbuf != NULL)
        {
          int i;
          for (i = 0; i < TYPE_LENGTH (valtype) / 8; i++)
            {
-             if (inval != NULL)
+             if (writebuf != NULL)
                regcache_cooked_write (regcache, FP0_REGNUM + 1 + i,
-                                      (const bfd_byte *) inval + i * 8);
-             if (outval != NULL)
+                                      (const bfd_byte *) writebuf + i * 8);
+             if (readbuf != NULL)
                regcache_cooked_read (regcache, FP0_REGNUM + 1 + i,
-                                     (bfd_byte *) outval + i * 8);
+                                     (bfd_byte *) readbuf + i * 8);
            }
        }
       return RETURN_VALUE_REGISTER_CONVENTION;
@@ -444,19 +942,19 @@ ppc64_sysv_abi_return_value (struct type *valtype, struct regcache *regcache,
              char regval[MAX_REGISTER_SIZE];
              struct type *regtype =
                register_type (current_gdbarch, FP0_REGNUM);
-             if (inval != NULL)
+             if (writebuf != NULL)
                {
-                 convert_typed_floating ((const bfd_byte *) inval +
+                 convert_typed_floating ((const bfd_byte *) writebuf +
                                          i * (TYPE_LENGTH (valtype) / 2),
                                          valtype, regval, regtype);
                  regcache_cooked_write (regcache, FP0_REGNUM + 1 + i,
                                         regval);
                }
-             if (outval != NULL)
+             if (readbuf != NULL)
                {
                  regcache_cooked_read (regcache, FP0_REGNUM + 1 + i, regval);
                  convert_typed_floating (regval, regtype,
-                                         (bfd_byte *) outval +
+                                         (bfd_byte *) readbuf +
                                          i * (TYPE_LENGTH (valtype) / 2),
                                          valtype);
                }
@@ -472,12 +970,12 @@ ppc64_sysv_abi_return_value (struct type *valtype, struct regcache *regcache,
          int i;
          for (i = 0; i < 4; i++)
            {
-             if (inval != NULL)
+             if (writebuf != NULL)
                regcache_cooked_write (regcache, FP0_REGNUM + 1 + i,
-                                      (const bfd_byte *) inval + i * 8);
-             if (outval != NULL)
+                                      (const bfd_byte *) writebuf + i * 8);
+             if (readbuf != NULL)
                regcache_cooked_read (regcache, FP0_REGNUM + 1 + i,
-                                     (bfd_byte *) outval + i * 8);
+                                     (bfd_byte *) readbuf + i * 8);
            }
        }
       return RETURN_VALUE_REGISTER_CONVENTION;
@@ -485,27 +983,20 @@ ppc64_sysv_abi_return_value (struct type *valtype, struct regcache *regcache,
   return RETURN_VALUE_STRUCT_CONVENTION;
 }
 
-int
-ppc64_sysv_abi_use_struct_convention (int gcc_p, struct type *value_type)
-{
-  return (ppc64_sysv_abi_return_value (value_type, NULL, NULL, NULL)
-         == RETURN_VALUE_STRUCT_CONVENTION);
-}
-
-void
-ppc64_sysv_abi_extract_return_value (struct type *valtype,
-                                    struct regcache *regbuf, void *valbuf)
-{
-  if (ppc64_sysv_abi_return_value (valtype, regbuf, NULL, valbuf)
-      != RETURN_VALUE_REGISTER_CONVENTION)
-    error ("Function return value unknown");
-}
-
-void
-ppc64_sysv_abi_store_return_value (struct type *valtype,
-                                  struct regcache *regbuf,
-                                  const void *valbuf)
+CORE_ADDR
+ppc64_sysv_abi_adjust_breakpoint_address (struct gdbarch *gdbarch,
+                                         CORE_ADDR bpaddr)
 {
-  if (!ppc64_sysv_abi_return_value (valtype, regbuf, valbuf, NULL))
-    error ("Function return value location unknown");
+  /* PPC64 SYSV specifies that the minimal-symbol "FN" should point at
+     a function-descriptor while the corresponding minimal-symbol
+     ".FN" should point at the entry point.  Consequently, a command
+     like "break FN" applied to an object file with only minimal
+     symbols, will insert the breakpoint into the descriptor at "FN"
+     and not the function at ".FN".  Avoid this confusion by adjusting
+     any attempt to set a descriptor breakpoint into a corresponding
+     function breakpoint.  Note that GDB warns the user when this
+     adjustment is applied - that's ok as otherwise the user will have
+     no way of knowing why their breakpoint at "FN" resulted in the
+     program stopping at ".FN".  */
+  return gdbarch_convert_from_func_ptr_addr (gdbarch, bpaddr, &current_target);
 }
This page took 0.03955 seconds and 4 git commands to generate.