expression.h: New ops OP_NSSTRING, OP_SELECTOR, OP_MSGCALL, and OP_SELF.
[deliverable/binutils-gdb.git] / gdb / ppc-linux-tdep.c
index 7e0a70a33d0782327adefeb6130954257526d014..6adfe297170cf9a64c0552f1d3806caeaeb20ee5 100644 (file)
@@ -106,10 +106,11 @@ 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 GNU/Linux,
-   signal trampolines are used for the return path only.  The kernel
-   sets things up so that the signal handler is called directly.
+   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
@@ -141,11 +142,11 @@ static 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)
@@ -410,228 +411,6 @@ ppc_linux_frame_chain (struct frame_info *thisframe)
     return rs6000_frame_chain (thisframe);
 }
 
-/* FIXME: Move the following to rs6000-tdep.c (or some other file where
-   it may be used generically by ports which use either the SysV ABI or
-   the EABI */
-
-/* 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)
-{
-  return (TYPE_LENGTH (value_type) > 8);
-}
-
-/* round2 rounds x up to the nearest multiple of s assuming that s is a
-   power of 2 */
-
-#undef round2
-#define round2(x,s) ((((long) (x) - 1) & ~(long)((s)-1)) + (s))
-
-/* 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
-   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. 
-
-   If the function is returning a structure, then the return address is passed
-   in r3, then the first 7 words of the parametes can be passed in registers,
-   starting from r4. */
-
-CORE_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;
-  int argstkspace;
-  int structstkspace;
-  int argoffset;
-  int structoffset;
-  struct value *arg;
-  struct type *type;
-  int len;
-  char old_sp_buf[4];
-  CORE_ADDR saved_sp;
-
-  greg = struct_return ? 4 : 3;
-  freg = 1;
-  argstkspace = 0;
-  structstkspace = 0;
-
-  /* Figure out how much new stack space is required for arguments
-     which don't fit in registers.  Unlike the PowerOpen ABI, the
-     SysV ABI doesn't reserve any extra space for parameters which
-     are put in registers. */
-  for (argno = 0; argno < nargs; argno++)
-    {
-      arg = args[argno];
-      type = check_typedef (VALUE_TYPE (arg));
-      len = TYPE_LENGTH (type);
-
-      if (TYPE_CODE (type) == TYPE_CODE_FLT)
-       {
-         if (freg <= 8)
-           freg++;
-         else
-           {
-             /* SysV ABI converts floats to doubles when placed in
-                memory and requires 8 byte alignment */
-             if (argstkspace & 0x4)
-               argstkspace += 4;
-             argstkspace += 8;
-           }
-       }
-      else if (TYPE_CODE (type) == TYPE_CODE_INT && len == 8)  /* long long */
-       {
-         if (greg > 9)
-           {
-             greg = 11;
-             if (argstkspace & 0x4)
-               argstkspace += 4;
-             argstkspace += 8;
-           }
-         else
-           {
-             if ((greg & 1) == 0)
-               greg++;
-             greg += 2;
-           }
-       }
-      else
-       {
-         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 */
-             structstkspace += round2 (len, 8);
-           }
-         if (greg <= 10)
-           greg++;
-         else
-           argstkspace += 4;
-       }
-    }
-
-  /* Get current SP location */
-  saved_sp = read_sp ();
-
-  sp -= argstkspace + structstkspace;
-
-  /* Allocate space for backchain and callee's saved lr */
-  sp -= 8;
-
-  /* Make sure that we maintain 16 byte alignment */
-  sp &= ~0x0f;
-
-  /* Update %sp before proceeding any further */
-  write_register (SP_REGNUM, sp);
-
-  /* write the backchain */
-  store_address (old_sp_buf, 4, saved_sp);
-  write_memory (sp, old_sp_buf, 4);
-
-  argoffset = 8;
-  structoffset = argoffset + argstkspace;
-  freg = 1;
-  greg = 3;
-  /* Fill in r3 with the return structure, if any */
-  if (struct_return)
-    {
-      char val_buf[4];
-      store_address (val_buf, 4, struct_addr);
-      memcpy (&registers[REGISTER_BYTE (greg)], val_buf, 4);
-      greg++;
-    }
-  /* Now fill in the registers and stack... */
-  for (argno = 0; argno < nargs; argno++)
-    {
-      arg = args[argno];
-      type = check_typedef (VALUE_TYPE (arg));
-      len = TYPE_LENGTH (type);
-
-      if (TYPE_CODE (type) == TYPE_CODE_FLT)
-       {
-         if (freg <= 8)
-           {
-             if (len > 8)
-               printf_unfiltered (
-                                   "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++;
-           }
-         else
-           {
-             /* SysV ABI converts floats to doubles when placed in
-                memory and requires 8 byte alignment */
-             /* FIXME: Convert floats to doubles */
-             if (argoffset & 0x4)
-               argoffset += 4;
-             write_memory (sp + argoffset, (char *) VALUE_CONTENTS (arg), len);
-             argoffset += 8;
-           }
-       }
-      else if (TYPE_CODE (type) == TYPE_CODE_INT && len == 8)  /* long long */
-       {
-         if (greg > 9)
-           {
-             greg = 11;
-             if (argoffset & 0x4)
-               argoffset += 4;
-             write_memory (sp + argoffset, (char *) VALUE_CONTENTS (arg), len);
-             argoffset += 8;
-           }
-         else
-           {
-             if ((greg & 1) == 0)
-               greg++;
-
-             memcpy (&registers[REGISTER_BYTE (greg)],
-                     VALUE_CONTENTS (arg), 4);
-             memcpy (&registers[REGISTER_BYTE (greg + 1)],
-                     VALUE_CONTENTS (arg) + 4, 4);
-             greg += 2;
-           }
-       }
-      else
-       {
-         char val_buf[4];
-         if (len > 4
-             || TYPE_CODE (type) == TYPE_CODE_STRUCT
-             || TYPE_CODE (type) == TYPE_CODE_UNION)
-           {
-             write_memory (sp + structoffset, VALUE_CONTENTS (arg), len);
-             store_address (val_buf, 4, sp + structoffset);
-             structoffset += round2 (len, 8);
-           }
-         else
-           {
-             memset (val_buf, 0, 4);
-             memcpy (val_buf, VALUE_CONTENTS (arg), len);
-           }
-         if (greg <= 10)
-           {
-             *(int *) &registers[REGISTER_BYTE (greg)] = 0;
-             memcpy (&registers[REGISTER_BYTE (greg)], val_buf, 4);
-             greg++;
-           }
-         else
-           {
-             write_memory (sp + argoffset, val_buf, 4);
-             argoffset += 4;
-           }
-       }
-    }
-
-  target_store_registers (-1);
-  return sp;
-}
-
 /* ppc_linux_memory_remove_breakpoints attempts to remove a breakpoint
    in much the same fashion as memory_remove_breakpoint in mem-break.c,
    but is careful not to write back the previous contents if the code
@@ -759,7 +538,7 @@ ppc_sysv_abi_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
 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];
@@ -820,3 +599,127 @@ ppc_linux_svr4_fetch_link_map_offsets (void)
 
   return lmp;
 }
+
+enum {
+  ELF_NGREG = 48,
+  ELF_NFPREG = 33,
+  ELF_NVRREG = 33
+};
+
+enum {
+  ELF_GREGSET_SIZE = (ELF_NGREG * 4),
+  ELF_FPREGSET_SIZE = (ELF_NFPREG * 8)
+};
+
+void
+ppc_linux_supply_gregset (char *buf)
+{
+  int regi;
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); 
+
+  for (regi = 0; regi < 32; regi++)
+    supply_register (regi, buf + 4 * regi);
+
+  supply_register (PC_REGNUM, buf + 4 * PPC_LINUX_PT_NIP);
+  supply_register (tdep->ppc_lr_regnum, buf + 4 * PPC_LINUX_PT_LNK);
+  supply_register (tdep->ppc_cr_regnum, buf + 4 * PPC_LINUX_PT_CCR);
+  supply_register (tdep->ppc_xer_regnum, buf + 4 * PPC_LINUX_PT_XER);
+  supply_register (tdep->ppc_ctr_regnum, buf + 4 * PPC_LINUX_PT_CTR);
+  if (tdep->ppc_mq_regnum != -1)
+    supply_register (tdep->ppc_mq_regnum, buf + 4 * PPC_LINUX_PT_MQ);
+  supply_register (tdep->ppc_ps_regnum, buf + 4 * PPC_LINUX_PT_MSR);
+}
+
+void
+ppc_linux_supply_fpregset (char *buf)
+{
+  int regi;
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); 
+
+  for (regi = 0; regi < 32; regi++)
+    supply_register (FP0_REGNUM + regi, buf + 8 * regi);
+
+  /* The FPSCR is stored in the low order word of the last doubleword in the
+     fpregset.  */
+  supply_register (tdep->ppc_fpscr_regnum, buf + 8 * 32 + 4);
+}
+
+/*
+  Use a local version of this function to get the correct types for regsets.
+*/
+
+static void
+fetch_core_registers (char *core_reg_sect,
+                     unsigned core_reg_size,
+                     int which,
+                     CORE_ADDR reg_addr)
+{
+  if (which == 0)
+    {
+      if (core_reg_size == ELF_GREGSET_SIZE)
+       ppc_linux_supply_gregset (core_reg_sect);
+      else
+       warning ("wrong size gregset struct in core file");
+    }
+  else if (which == 2)
+    {
+      if (core_reg_size == ELF_FPREGSET_SIZE)
+       ppc_linux_supply_fpregset (core_reg_sect);
+      else
+       warning ("wrong size fpregset struct in core file");
+    }
+}
+
+/* Register that we are able to handle ELF file formats using standard
+   procfs "regset" structures.  */
+
+static struct core_fns ppc_linux_regset_core_fns =
+{
+  bfd_target_elf_flavour,      /* core_flavour */
+  default_check_format,                /* check_format */
+  default_core_sniffer,                /* core_sniffer */
+  fetch_core_registers,                /* core_read_registers */
+  NULL                         /* next */
+};
+
+static void
+ppc_linux_init_abi (struct gdbarch_info info,
+                    struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* 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.  */
+  set_gdbarch_use_struct_convention (gdbarch,
+                                   ppc_sysv_abi_broken_use_struct_convention);
+
+  if (tdep->wordsize == 4)
+    {
+      /* Note: kevinb/2002-04-12: See note in rs6000_gdbarch_init regarding
+        *_push_arguments().  The same remarks hold for the methods below.  */
+      set_gdbarch_frameless_function_invocation (gdbarch,
+        ppc_linux_frameless_function_invocation);
+      set_gdbarch_frame_chain (gdbarch, ppc_linux_frame_chain);
+      set_gdbarch_frame_saved_pc (gdbarch, ppc_linux_frame_saved_pc);
+
+      set_gdbarch_frame_init_saved_regs (gdbarch,
+                                         ppc_linux_frame_init_saved_regs);
+      set_gdbarch_init_extra_frame_info (gdbarch,
+                                         ppc_linux_init_extra_frame_info);
+
+      set_gdbarch_memory_remove_breakpoint (gdbarch,
+                                            ppc_linux_memory_remove_breakpoint);
+      set_solib_svr4_fetch_link_map_offsets
+        (gdbarch, ppc_linux_svr4_fetch_link_map_offsets);
+    }
+}
+
+void
+_initialize_ppc_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_powerpc, GDB_OSABI_LINUX,
+                         ppc_linux_init_abi);
+  add_core_fns (&ppc_linux_regset_core_fns);
+}
This page took 0.03636 seconds and 4 git commands to generate.