* Makefile.in (ALLDEPFILES): Add alphabsd-tdep.c.
[deliverable/binutils-gdb.git] / gdb / ppc-linux-tdep.c
index 50388faf2ce47679158fbac3763b0b0f336c79a5..f358274140bf7d6afee135fa8b04572484f78e49 100644 (file)
@@ -1,6 +1,7 @@
 /* Target-dependent code for GDB, the GNU debugger.
-   Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
-   Free Software Foundation, Inc.
+
+   Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
+   1997, 2000, 2001, 2002 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "gdbcmd.h"
 #include "symfile.h"
 #include "objfiles.h"
+#include "regcache.h"
+#include "value.h"
+
+#include "solib-svr4.h"
+#include "ppc-tdep.h"
 
 /* The following two instructions are used in the signal trampoline
-   code on linux/ppc */
+   code on GNU/Linux PPC.  */
 #define INSTR_LI_R0_0x7777     0x38007777
 #define INSTR_SC               0x44000002
 
 #define PPC_LINUX_PT_FPR31 (PPC_LINUX_PT_FPR0 + 2*31)
 #define PPC_LINUX_PT_FPSCR (PPC_LINUX_PT_FPR0 + 2*32 + 1)
 
-int ppc_linux_at_sigtramp_return_path (CORE_ADDR pc);
+static int ppc_linux_at_sigtramp_return_path (CORE_ADDR pc);
 
 /* Determine if pc is in a signal trampoline...
 
-   Ha!  That's not what this does at all.  wait_for_inferior in infrun.c
-   calls IN_SIGTRAMP in order to detect entry into a signal trampoline
-   just after delivery of a signal.  But on linux, signal trampolines
-   are used for the return path only.  The kernel sets things up so that
-   the signal handler is called directly.
+   Ha!  That's not what this does at all.  wait_for_inferior in
+   infrun.c calls PC_IN_SIGTRAMP in order to detect entry into a
+   signal trampoline just after delivery of a signal.  But on
+   GNU/Linux, signal trampolines are used for the return path only.
+   The kernel sets things up so that the signal handler is called
+   directly.
 
    If we use in_sigtramp2() in place of in_sigtramp() (see below)
    we'll (often) end up with stop_pc in the trampoline and prev_pc in
@@ -135,11 +142,11 @@ int ppc_linux_at_sigtramp_return_path (CORE_ADDR pc);
    first instruction long after the fact, just in case the observed
    behavior is ever fixed.)
 
-   IN_SIGTRAMP is called from blockframe.c as well in order to set
+   PC_IN_SIGTRAMP is called from blockframe.c as well in order to set
    the signal_handler_caller flag.  Because of our strange definition
-   of in_sigtramp below, we can't rely on signal_handler_caller getting
-   set correctly from within blockframe.c.  This is why we take pains
-   to set it in init_extra_frame_info().  */
+   of in_sigtramp below, we can't rely on signal_handler_caller
+   getting set correctly from within blockframe.c.  This is why we
+   take pains to set it in init_extra_frame_info().  */
 
 int
 ppc_linux_in_sigtramp (CORE_ADDR pc, char *func_name)
@@ -150,7 +157,7 @@ ppc_linux_in_sigtramp (CORE_ADDR pc, char *func_name)
   char buf[4];
   CORE_ADDR handler;
 
-  lr = read_register (LR_REGNUM);
+  lr = read_register (gdbarch_tdep (current_gdbarch)->ppc_lr_regnum);
   if (!ppc_linux_at_sigtramp_return_path (lr))
     return 0;
 
@@ -177,7 +184,7 @@ ppc_linux_in_sigtramp (CORE_ADDR pc, char *func_name)
  * instructions.  It'd be faster though if we could find a way to do this
  * via some simple address comparisons.
  */
-int
+static int
 ppc_linux_at_sigtramp_return_path (CORE_ADDR pc)
 {
   char buf[12];
@@ -308,7 +315,7 @@ ppc_linux_skip_trampoline_code (CORE_ADDR pc)
 /* The rs6000 version of FRAME_SAVED_PC will almost work for us.  The
    signal handler details are different, so we'll handle those here
    and call the rs6000 version to do the rest. */
-unsigned long
+CORE_ADDR
 ppc_linux_frame_saved_pc (struct frame_info *fi)
 {
   if (fi->signal_handler_caller)
@@ -372,14 +379,21 @@ ppc_linux_frame_init_saved_regs (struct frame_info *fi)
       regs_addr =
        read_memory_integer (fi->frame + PPC_LINUX_REGS_PTR_OFFSET, 4);
       fi->saved_regs[PC_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_NIP;
-      fi->saved_regs[PS_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_MSR;
-      fi->saved_regs[CR_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_CCR;
-      fi->saved_regs[LR_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_LNK;
-      fi->saved_regs[CTR_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_CTR;
-      fi->saved_regs[XER_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_XER;
-      fi->saved_regs[MQ_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_MQ;
+      fi->saved_regs[gdbarch_tdep (current_gdbarch)->ppc_ps_regnum] =
+        regs_addr + 4 * PPC_LINUX_PT_MSR;
+      fi->saved_regs[gdbarch_tdep (current_gdbarch)->ppc_cr_regnum] =
+        regs_addr + 4 * PPC_LINUX_PT_CCR;
+      fi->saved_regs[gdbarch_tdep (current_gdbarch)->ppc_lr_regnum] =
+        regs_addr + 4 * PPC_LINUX_PT_LNK;
+      fi->saved_regs[gdbarch_tdep (current_gdbarch)->ppc_ctr_regnum] =
+        regs_addr + 4 * PPC_LINUX_PT_CTR;
+      fi->saved_regs[gdbarch_tdep (current_gdbarch)->ppc_xer_regnum] =
+        regs_addr + 4 * PPC_LINUX_PT_XER;
+      fi->saved_regs[gdbarch_tdep (current_gdbarch)->ppc_mq_regnum] =
+       regs_addr + 4 * PPC_LINUX_PT_MQ;
       for (i = 0; i < 32; i++)
-       fi->saved_regs[GP0_REGNUM + i] = regs_addr + 4 * PPC_LINUX_PT_R0 + 4 * i;
+       fi->saved_regs[gdbarch_tdep (current_gdbarch)->ppc_gp0_regnum + i] =
+         regs_addr + 4 * PPC_LINUX_PT_R0 + 4 * i;
       for (i = 0; i < 32; i++)
        fi->saved_regs[FP0_REGNUM + i] = regs_addr + 4 * PPC_LINUX_PT_FPR0 + 8 * i;
     }
@@ -401,6 +415,32 @@ ppc_linux_frame_chain (struct frame_info *thisframe)
    it may be used generically by ports which use either the SysV ABI or
    the EABI */
 
+/* Until November 2001, gcc was not complying to the SYSV ABI for
+   returning structures less than or equal to 8 bytes in size.  It was
+   returning everything in memory.  When this was corrected, it wasn't
+   fixed for native platforms.  */
+int
+ppc_sysv_abi_broken_use_struct_convention (int gcc_p, struct type *value_type)
+{
+  if (TYPE_LENGTH (value_type) == 16
+      && TYPE_VECTOR (value_type))
+    return 0;
+
+  return generic_use_struct_convention (gcc_p, value_type);
+}
+
+/* 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)
+{
+  if (TYPE_LENGTH (value_type) == 16
+      && TYPE_VECTOR (value_type))
+    return 0;
+
+  return (TYPE_LENGTH (value_type) > 8);
+}
+
 /* round2 rounds x up to the nearest multiple of s assuming that s is a
    power of 2 */
 
@@ -419,20 +459,21 @@ ppc_linux_frame_chain (struct frame_info *thisframe)
    starting from r4. */
 
 CORE_ADDR
-ppc_sysv_abi_push_arguments (nargs, args, sp, struct_return, struct_addr)
-     int nargs;
-     value_ptr *args;
-     CORE_ADDR sp;
-     int struct_return;
-     CORE_ADDR struct_addr;
+ppc_sysv_abi_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
+                            int struct_return, CORE_ADDR struct_addr)
 {
   int argno;
-  int greg, freg;
+  /* Next available general register for non-float, non-vector arguments. */
+  int greg;
+  /* Next available floating point register for float arguments. */
+  int freg;
+  /* Next available vector register for vector arguments. */
+  int vreg;
   int argstkspace;
   int structstkspace;
   int argoffset;
   int structoffset;
-  value_ptr arg;
+  struct value *arg;
   struct type *type;
   int len;
   char old_sp_buf[4];
@@ -440,6 +481,7 @@ ppc_sysv_abi_push_arguments (nargs, args, sp, struct_return, struct_addr)
 
   greg = struct_return ? 4 : 3;
   freg = 1;
+  vreg = 2;
   argstkspace = 0;
   structstkspace = 0;
 
@@ -482,21 +524,38 @@ ppc_sysv_abi_push_arguments (nargs, args, sp, struct_return, struct_addr)
              greg += 2;
            }
        }
-      else
-       {
+      else if (!TYPE_VECTOR (type))
+        {
          if (len > 4
              || TYPE_CODE (type) == TYPE_CODE_STRUCT
              || TYPE_CODE (type) == TYPE_CODE_UNION)
            {
              /* Rounding to the nearest multiple of 8 may not be necessary,
-                but it is safe.  Particularly since we don't know the
-                field types of the structure */
+                but it is safe.  Particularly since we don't know the
+                field types of the structure */
              structstkspace += round2 (len, 8);
            }
          if (greg <= 10)
            greg++;
          else
            argstkspace += 4;
+       }
+      else
+        {
+          if (len == 16
+             && TYPE_CODE (type) == TYPE_CODE_ARRAY
+             && TYPE_VECTOR (type))
+           {
+             if (vreg <= 13)
+               vreg++;
+             else
+               {
+                 /* Vector arguments must be aligned to 16 bytes on
+                     the stack. */
+                 argstkspace += round2 (argstkspace, 16);
+                 argstkspace += 16;
+               }
+           }
        }
     }
 
@@ -522,6 +581,7 @@ ppc_sysv_abi_push_arguments (nargs, args, sp, struct_return, struct_addr)
   structoffset = argoffset + argstkspace;
   freg = 1;
   greg = 3;
+  vreg = 2;
   /* Fill in r3 with the return structure, if any */
   if (struct_return)
     {
@@ -543,7 +603,7 @@ ppc_sysv_abi_push_arguments (nargs, args, sp, struct_return, struct_addr)
            {
              if (len > 8)
                printf_unfiltered (
-                                   "Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno);
+                                  "Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno);
              memcpy (&registers[REGISTER_BYTE (FP0_REGNUM + freg)],
                      VALUE_CONTENTS (arg), len);
              freg++;
@@ -581,7 +641,7 @@ ppc_sysv_abi_push_arguments (nargs, args, sp, struct_return, struct_addr)
              greg += 2;
            }
        }
-      else
+      else if (!TYPE_VECTOR (type))
        {
          char val_buf[4];
          if (len > 4
@@ -599,7 +659,6 @@ ppc_sysv_abi_push_arguments (nargs, args, sp, struct_return, struct_addr)
            }
          if (greg <= 10)
            {
-             *(int *) &registers[REGISTER_BYTE (greg)] = 0;
              memcpy (&registers[REGISTER_BYTE (greg)], val_buf, 4);
              greg++;
            }
@@ -609,6 +668,30 @@ ppc_sysv_abi_push_arguments (nargs, args, sp, struct_return, struct_addr)
              argoffset += 4;
            }
        }
+      else
+       {
+         if (len == 16
+             && TYPE_CODE (type) == TYPE_CODE_ARRAY
+             && TYPE_VECTOR (type))
+           {
+             struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+             char *v_val_buf = alloca (16);
+             memset (v_val_buf, 0, 16);
+             memcpy (v_val_buf, VALUE_CONTENTS (arg), len);
+             if (vreg <= 13)
+               {
+                 memcpy (&registers[REGISTER_BYTE (tdep->ppc_vr0_regnum
+                                                   + vreg)],
+                         v_val_buf, 16);
+                 vreg++;
+               }
+             else
+               {
+                 write_memory (sp + argoffset, v_val_buf, 16);
+                 argoffset += 16;
+               }
+           }
+        }
     }
 
   target_store_registers (-1);
@@ -742,7 +825,7 @@ ppc_sysv_abi_push_arguments (nargs, args, sp, struct_return, struct_addr)
 int
 ppc_linux_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
 {
-  unsigned char *bp;
+  const unsigned char *bp;
   int val;
   int bplen;
   char old_contents[BREAKPOINT_MAX];
@@ -762,3 +845,44 @@ ppc_linux_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
 
   return val;
 }
+
+/* Fetch (and possibly build) an appropriate link_map_offsets
+   structure for GNU/Linux PPC targets using the struct offsets
+   defined in link.h (but without actual reference to that file).
+
+   This makes it possible to access GNU/Linux PPC shared libraries
+   from a GDB that was not built on an GNU/Linux PPC host (for cross
+   debugging).  */
+
+struct link_map_offsets *
+ppc_linux_svr4_fetch_link_map_offsets (void)
+{
+  static struct link_map_offsets lmo;
+  static struct link_map_offsets *lmp = NULL;
+
+  if (lmp == NULL)
+    {
+      lmp = &lmo;
+
+      lmo.r_debug_size = 8;    /* The actual size is 20 bytes, but
+                                  this is all we need.  */
+      lmo.r_map_offset = 4;
+      lmo.r_map_size   = 4;
+
+      lmo.link_map_size = 20;  /* The actual size is 560 bytes, but
+                                  this is all we need.  */
+      lmo.l_addr_offset = 0;
+      lmo.l_addr_size   = 4;
+
+      lmo.l_name_offset = 4;
+      lmo.l_name_size   = 4;
+
+      lmo.l_next_offset = 12;
+      lmo.l_next_size   = 4;
+
+      lmo.l_prev_offset = 16;
+      lmo.l_prev_size   = 4;
+    }
+
+  return lmp;
+}
This page took 0.028992 seconds and 4 git commands to generate.