* ppc-linux-nat.c (right_fill_reg): Delete.
[deliverable/binutils-gdb.git] / gdb / ppc-linux-tdep.c
index 5cf0f236cf8a138783e7fff04f430e911b55649d..324cef74c2a83a421ccad6b4592d74a9594e3f9e 100644 (file)
@@ -8,7 +8,7 @@
 
    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
 
    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 2 of the License, or
+   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,
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -17,9 +17,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    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, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "frame.h"
 
 #include "defs.h"
 #include "frame.h"
 #include "frame-unwind.h"
 #include "tramp-frame.h"
 
 #include "frame-unwind.h"
 #include "tramp-frame.h"
 
-/* From <asm/ptrace.h>, values for PT_NIP, PT_R1, and PT_LNK */
-#define PPC_LINUX_PT_R0                0
-#define PPC_LINUX_PT_R1                1
-#define PPC_LINUX_PT_R2                2
-#define PPC_LINUX_PT_R3                3
-#define PPC_LINUX_PT_R4                4
-#define PPC_LINUX_PT_R5                5
-#define PPC_LINUX_PT_R6                6
-#define PPC_LINUX_PT_R7                7
-#define PPC_LINUX_PT_R8                8
-#define PPC_LINUX_PT_R9                9
-#define PPC_LINUX_PT_R10       10
-#define PPC_LINUX_PT_R11       11
-#define PPC_LINUX_PT_R12       12
-#define PPC_LINUX_PT_R13       13
-#define PPC_LINUX_PT_R14       14
-#define PPC_LINUX_PT_R15       15
-#define PPC_LINUX_PT_R16       16
-#define PPC_LINUX_PT_R17       17
-#define PPC_LINUX_PT_R18       18
-#define PPC_LINUX_PT_R19       19
-#define PPC_LINUX_PT_R20       20
-#define PPC_LINUX_PT_R21       21
-#define PPC_LINUX_PT_R22       22
-#define PPC_LINUX_PT_R23       23
-#define PPC_LINUX_PT_R24       24
-#define PPC_LINUX_PT_R25       25
-#define PPC_LINUX_PT_R26       26
-#define PPC_LINUX_PT_R27       27
-#define PPC_LINUX_PT_R28       28
-#define PPC_LINUX_PT_R29       29
-#define PPC_LINUX_PT_R30       30
-#define PPC_LINUX_PT_R31       31
-#define PPC_LINUX_PT_NIP       32
-#define PPC_LINUX_PT_MSR       33
-#define PPC_LINUX_PT_CTR       35
-#define PPC_LINUX_PT_LNK       36
-#define PPC_LINUX_PT_XER       37
-#define PPC_LINUX_PT_CCR       38
-#define PPC_LINUX_PT_MQ                39
-#define PPC_LINUX_PT_FPR0      48      /* each FP reg occupies 2 slots in this space */
-#define PPC_LINUX_PT_FPR31 (PPC_LINUX_PT_FPR0 + 2*31)
-#define PPC_LINUX_PT_FPSCR (PPC_LINUX_PT_FPR0 + 2*32 + 1)
-
-
 static CORE_ADDR
 ppc_linux_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
 {
 static CORE_ADDR
 ppc_linux_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
 {
@@ -591,136 +544,173 @@ ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
 }
 
 
 }
 
 
-/* Support for CONVERT_FROM_FUNC_PTR_ADDR (ARCH, ADDR, TARG) on PPC64
+/* Support for convert_from_func_ptr_addr (ARCH, ADDR, TARG) on PPC
    GNU/Linux.
 
    Usually a function pointer's representation is simply the address
    GNU/Linux.
 
    Usually a function pointer's representation is simply the address
-   of the function. On GNU/Linux on the 64-bit PowerPC however, a
-   function pointer is represented by a pointer to a TOC entry. This
-   TOC 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
+   of the function.  On GNU/Linux on the PowerPC however, a function
+   pointer may be a pointer to a function descriptor.
+
+   For PPC64, a function descriptor is a TOC entry, in a data section,
+   which 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.
+
+   For PPC32, there are two kinds of function pointers: non-secure and
+   secure.  Non-secure function pointers point directly to the
+   function in a code section and thus need no translation.  Secure
+   ones (from GCC's -msecure-plt option) are in a data section and
+   contain one word: the address of the function.
+
+   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 a TOC 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
    conversion of a function address to a function pointer would
    require allocation of a TOC 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.  */
+   from a function pointer.
 
 
-/* If ADDR points at what is clearly a function descriptor, transform
-   it into the address of the corresponding function.  Be
-   conservative, otherwize GDB will do the transformation on any
-   random addresses such as occures when there is no symbol table.  */
+   If ADDR points at what is clearly a function descriptor, transform
+   it into the address of the corresponding function, if needed.  Be
+   conservative, otherwise GDB will do the transformation on any
+   random addresses such as occur when there is no symbol table.  */
 
 static CORE_ADDR
 
 static CORE_ADDR
-ppc64_linux_convert_from_func_ptr_addr (struct gdbarch *gdbarch,
-                                       CORE_ADDR addr,
-                                       struct target_ops *targ)
+ppc_linux_convert_from_func_ptr_addr (struct gdbarch *gdbarch,
+                                     CORE_ADDR addr,
+                                     struct target_ops *targ)
 {
 {
+  struct gdbarch_tdep *tdep;
   struct section_table *s = target_section_by_addr (targ, addr);
   struct section_table *s = target_section_by_addr (targ, addr);
+  char *sect_name = NULL;
+
+  if (!s)
+    return addr;
+
+  tdep = gdbarch_tdep (gdbarch);
+
+  switch (tdep->wordsize)
+    {
+      case 4:
+       sect_name = ".plt";
+       break;
+      case 8:
+       sect_name = ".opd";
+       break;
+      default:
+       internal_error (__FILE__, __LINE__,
+                       _("failed internal consistency check"));
+    }
 
   /* Check if ADDR points to a function descriptor.  */
 
   /* Check if ADDR points to a function descriptor.  */
-  if (s && strcmp (s->the_bfd_section->name, ".opd") == 0)
-    return get_target_memory_unsigned (targ, addr, 8);
+
+  /* NOTE: this depends on the coincidence that the address of a functions
+     entry point is contained in the first word of its function descriptor
+     for both PPC-64 and for PPC-32 with secure PLTs.  */
+  if ((strcmp (s->the_bfd_section->name, sect_name) == 0)
+      && s->the_bfd_section->flags & SEC_DATA)
+    return get_target_memory_unsigned (targ, addr, tdep->wordsize);
 
   return addr;
 }
 
 
   return addr;
 }
 
+/* This wrapper clears areas in the linux gregset not written by
+   ppc_collect_gregset.  */
+
 static void
 static void
-right_supply_register (struct regcache *regcache, int wordsize, int regnum,
-                      const bfd_byte *buf)
+ppc_linux_collect_gregset (const struct regset *regset,
+                          const struct regcache *regcache,
+                          int regnum, void *gregs, size_t len)
 {
 {
-  regcache_raw_supply (regcache, regnum,
-                      (buf + wordsize - register_size (current_gdbarch, regnum)));
+  if (regnum == -1)
+    memset (gregs, 0, len);
+  ppc_collect_gregset (regset, regcache, regnum, gregs, len);
 }
 
 }
 
-/* Extract the register values found in the WORDSIZED ABI GREGSET,
-   storing their values in REGCACHE.  Note that some are left-aligned,
-   while others are right aligned.  */
-
-void
-ppc_linux_supply_gregset (struct regcache *regcache,
-                         int regnum, const void *gregs, size_t size,
-                         int wordsize)
-{
-  int regi;
-  struct gdbarch *regcache_arch = get_regcache_arch (regcache); 
-  struct gdbarch_tdep *regcache_tdep = gdbarch_tdep (regcache_arch);
-  const bfd_byte *buf = gregs;
-
-  for (regi = 0; regi < ppc_num_gprs; regi++)
-    right_supply_register (regcache, wordsize,
-                           regcache_tdep->ppc_gp0_regnum + regi,
-                           buf + wordsize * regi);
-
-  right_supply_register (regcache, wordsize, gdbarch_pc_regnum (regcache_arch),
-                        buf + wordsize * PPC_LINUX_PT_NIP);
-  right_supply_register (regcache, wordsize, regcache_tdep->ppc_lr_regnum,
-                        buf + wordsize * PPC_LINUX_PT_LNK);
-  regcache_raw_supply (regcache, regcache_tdep->ppc_cr_regnum,
-                      buf + wordsize * PPC_LINUX_PT_CCR);
-  regcache_raw_supply (regcache, regcache_tdep->ppc_xer_regnum,
-                      buf + wordsize * PPC_LINUX_PT_XER);
-  regcache_raw_supply (regcache, regcache_tdep->ppc_ctr_regnum,
-                      buf + wordsize * PPC_LINUX_PT_CTR);
-  if (regcache_tdep->ppc_mq_regnum != -1)
-    right_supply_register (regcache, wordsize, regcache_tdep->ppc_mq_regnum,
-                          buf + wordsize * PPC_LINUX_PT_MQ);
-  right_supply_register (regcache, wordsize, regcache_tdep->ppc_ps_regnum,
-                        buf + wordsize * PPC_LINUX_PT_MSR);
-}
+/* Regset descriptions.  */
+static const struct ppc_reg_offsets ppc32_linux_reg_offsets =
+  {
+    /* General-purpose registers.  */
+    /* .r0_offset = */ 0,
+    /* .gpr_size = */ 4,
+    /* .xr_size = */ 4,
+    /* .pc_offset = */ 128,
+    /* .ps_offset = */ 132,
+    /* .cr_offset = */ 152,
+    /* .lr_offset = */ 144,
+    /* .ctr_offset = */ 140,
+    /* .xer_offset = */ 148,
+    /* .mq_offset = */ 156,
+
+    /* Floating-point registers.  */
+    /* .f0_offset = */ 0,
+    /* .fpscr_offset = */ 256,
+    /* .fpscr_size = */ 8,
+
+    /* AltiVec registers.  */
+    /* .vr0_offset = */ 0,
+    /* .vrsave_offset = */ 512,
+    /* .vscr_offset = */ 512 + 12
+  };
 
 
-static void
-ppc32_linux_supply_gregset (const struct regset *regset,
-                           struct regcache *regcache,
-                           int regnum, const void *gregs, size_t size)
-{
-  ppc_linux_supply_gregset (regcache, regnum, gregs, size, 4);
-}
+static const struct ppc_reg_offsets ppc64_linux_reg_offsets =
+  {
+    /* General-purpose registers.  */
+    /* .r0_offset = */ 0,
+    /* .gpr_size = */ 8,
+    /* .xr_size = */ 8,
+    /* .pc_offset = */ 256,
+    /* .ps_offset = */ 264,
+    /* .cr_offset = */ 304,
+    /* .lr_offset = */ 288,
+    /* .ctr_offset = */ 280,
+    /* .xer_offset = */ 296,
+    /* .mq_offset = */ 312,
+
+    /* Floating-point registers.  */
+    /* .f0_offset = */ 0,
+    /* .fpscr_offset = */ 256,
+    /* .fpscr_size = */ 8,
+
+    /* AltiVec registers.  */
+    /* .vr0_offset = */ 0,
+    /* .vrsave_offset = */ 528,
+    /* .vscr_offset = */ 512 + 12
+  };
 
 
-static struct regset ppc32_linux_gregset = {
-  NULL, ppc32_linux_supply_gregset
+static const struct regset ppc32_linux_gregset = {
+  &ppc32_linux_reg_offsets,
+  ppc_supply_gregset,
+  ppc_linux_collect_gregset,
+  NULL
 };
 
 };
 
-static void
-ppc64_linux_supply_gregset (const struct regset *regset,
-                           struct regcache * regcache,
-                           int regnum, const void *gregs, size_t size)
-{
-  ppc_linux_supply_gregset (regcache, regnum, gregs, size, 8);
-}
+static const struct regset ppc64_linux_gregset = {
+  &ppc64_linux_reg_offsets,
+  ppc_supply_gregset,
+  ppc_linux_collect_gregset,
+  NULL
+};
 
 
-static struct regset ppc64_linux_gregset = {
-  NULL, ppc64_linux_supply_gregset
+static const struct regset ppc32_linux_fpregset = {
+  &ppc32_linux_reg_offsets,
+  ppc_supply_fpregset,
+  ppc_collect_fpregset,
+  NULL
 };
 
 };
 
-void
-ppc_linux_supply_fpregset (const struct regset *regset,
-                          struct regcache * regcache,
-                          int regnum, const void *fpset, size_t size)
+const struct regset *
+ppc_linux_gregset (int wordsize)
 {
 {
-  int regi;
-  struct gdbarch *regcache_arch = get_regcache_arch (regcache); 
-  struct gdbarch_tdep *regcache_tdep = gdbarch_tdep (regcache_arch);
-  const bfd_byte *buf = fpset;
-
-  if (! ppc_floating_point_unit_p (regcache_arch))
-    return;
-
-  for (regi = 0; regi < ppc_num_fprs; regi++)
-    regcache_raw_supply (regcache, 
-                         regcache_tdep->ppc_fp0_regnum + regi,
-                         buf + 8 * regi);
-
-  /* The FPSCR is stored in the low order word of the last
-     doubleword in the fpregset.  */
-  regcache_raw_supply (regcache, regcache_tdep->ppc_fpscr_regnum,
-                       buf + 8 * 32 + 4);
+  return wordsize == 8 ? &ppc64_linux_gregset : &ppc32_linux_gregset;
 }
 
 }
 
-static struct regset ppc_linux_fpregset = { NULL, ppc_linux_supply_fpregset };
+const struct regset *
+ppc_linux_fpregset (void)
+{
+  return &ppc32_linux_fpregset;
+}
 
 static const struct regset *
 ppc_linux_regset_from_core_section (struct gdbarch *core_arch,
 
 static const struct regset *
 ppc_linux_regset_from_core_section (struct gdbarch *core_arch,
@@ -735,7 +725,7 @@ ppc_linux_regset_from_core_section (struct gdbarch *core_arch,
        return &ppc64_linux_gregset;
     }
   if (strcmp (sect_name, ".reg2") == 0)
        return &ppc64_linux_gregset;
     }
   if (strcmp (sect_name, ".reg2") == 0)
-    return &ppc_linux_fpregset;
+    return &ppc32_linux_fpregset;
   return NULL;
 }
 
   return NULL;
 }
 
@@ -907,6 +897,11 @@ ppc_linux_init_abi (struct gdbarch_info info,
   /* NOTE: cagney/2005-01-25: True for both 32- and 64-bit.  */
   set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
 
   /* NOTE: cagney/2005-01-25: True for both 32- and 64-bit.  */
   set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
 
+  /* Handle PPC GNU/Linux 64-bit function pointers (which are really
+     function descriptors) and 32-bit secure PLT entries.  */
+  set_gdbarch_convert_from_func_ptr_addr
+    (gdbarch, ppc_linux_convert_from_func_ptr_addr);
+
   if (tdep->wordsize == 4)
     {
       /* Until November 2001, gcc did not comply with the 32 bit SysV
   if (tdep->wordsize == 4)
     {
       /* Until November 2001, gcc did not comply with the 32 bit SysV
@@ -934,13 +929,8 @@ ppc_linux_init_abi (struct gdbarch_info info,
   
   if (tdep->wordsize == 8)
     {
   
   if (tdep->wordsize == 8)
     {
-      /* Handle PPC64 GNU/Linux function pointers (which are really
-         function descriptors).  */
-      set_gdbarch_convert_from_func_ptr_addr
-        (gdbarch, ppc64_linux_convert_from_func_ptr_addr);
-      set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code);
-
       /* Shared library handling.  */
       /* Shared library handling.  */
+      set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code);
       set_solib_svr4_fetch_link_map_offsets
         (gdbarch, svr4_lp64_fetch_link_map_offsets);
 
       set_solib_svr4_fetch_link_map_offsets
         (gdbarch, svr4_lp64_fetch_link_map_offsets);
 
This page took 0.027739 seconds and 4 git commands to generate.