Honour PRIVATE keyword
[deliverable/binutils-gdb.git] / gdb / ppc-linux-tdep.c
index f2d76b8b11b3ebbb60f4f63f226817c2a076639f..84eb742d8e27e2d58fa66fecbef8bd28301cda48 100644 (file)
@@ -188,7 +188,7 @@ ppc_linux_in_sigtramp (CORE_ADDR pc, char *func_name)
   return (pc == handler || pc == handler + 4);
 }
 
-static inline int
+static int
 insn_is_sigreturn (unsigned long pcinsn)
 {
   switch(pcinsn)
@@ -331,7 +331,7 @@ ppc_linux_skip_trampoline_code (CORE_ADDR pc)
   /* This might not work right if we have multiple symbols with the
      same name; the only way to really get it right is to perform
      the same sort of lookup as the dynamic linker. */
-  msymbol = lookup_minimal_symbol_text (symname, NULL, NULL);
+  msymbol = lookup_minimal_symbol_text (symname, NULL);
   if (!msymbol)
     return 0;
 
@@ -402,7 +402,7 @@ ppc_linux_frame_init_saved_regs (struct frame_info *fi)
     {
       CORE_ADDR regs_addr;
       int i;
-      if (get_frame_saved_regs (fi))
+      if (deprecated_get_frame_saved_regs (fi))
        return;
 
       frame_saved_regs_zalloc (fi);
@@ -410,24 +410,24 @@ ppc_linux_frame_init_saved_regs (struct frame_info *fi)
       regs_addr =
        read_memory_integer (get_frame_base (fi)
                             + PPC_LINUX_REGS_PTR_OFFSET, 4);
-      get_frame_saved_regs (fi)[PC_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_NIP;
-      get_frame_saved_regs (fi)[gdbarch_tdep (current_gdbarch)->ppc_ps_regnum] =
+      deprecated_get_frame_saved_regs (fi)[PC_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_NIP;
+      deprecated_get_frame_saved_regs (fi)[gdbarch_tdep (current_gdbarch)->ppc_ps_regnum] =
         regs_addr + 4 * PPC_LINUX_PT_MSR;
-      get_frame_saved_regs (fi)[gdbarch_tdep (current_gdbarch)->ppc_cr_regnum] =
+      deprecated_get_frame_saved_regs (fi)[gdbarch_tdep (current_gdbarch)->ppc_cr_regnum] =
         regs_addr + 4 * PPC_LINUX_PT_CCR;
-      get_frame_saved_regs (fi)[gdbarch_tdep (current_gdbarch)->ppc_lr_regnum] =
+      deprecated_get_frame_saved_regs (fi)[gdbarch_tdep (current_gdbarch)->ppc_lr_regnum] =
         regs_addr + 4 * PPC_LINUX_PT_LNK;
-      get_frame_saved_regs (fi)[gdbarch_tdep (current_gdbarch)->ppc_ctr_regnum] =
+      deprecated_get_frame_saved_regs (fi)[gdbarch_tdep (current_gdbarch)->ppc_ctr_regnum] =
         regs_addr + 4 * PPC_LINUX_PT_CTR;
-      get_frame_saved_regs (fi)[gdbarch_tdep (current_gdbarch)->ppc_xer_regnum] =
+      deprecated_get_frame_saved_regs (fi)[gdbarch_tdep (current_gdbarch)->ppc_xer_regnum] =
         regs_addr + 4 * PPC_LINUX_PT_XER;
-      get_frame_saved_regs (fi)[gdbarch_tdep (current_gdbarch)->ppc_mq_regnum] =
+      deprecated_get_frame_saved_regs (fi)[gdbarch_tdep (current_gdbarch)->ppc_mq_regnum] =
        regs_addr + 4 * PPC_LINUX_PT_MQ;
       for (i = 0; i < 32; i++)
-       get_frame_saved_regs (fi)[gdbarch_tdep (current_gdbarch)->ppc_gp0_regnum + i] =
+       deprecated_get_frame_saved_regs (fi)[gdbarch_tdep (current_gdbarch)->ppc_gp0_regnum + i] =
          regs_addr + 4 * PPC_LINUX_PT_R0 + 4 * i;
       for (i = 0; i < 32; i++)
-       get_frame_saved_regs (fi)[FP0_REGNUM + i] = regs_addr + 4 * PPC_LINUX_PT_FPR0 + 8 * i;
+       deprecated_get_frame_saved_regs (fi)[FP0_REGNUM + i] = regs_addr + 4 * PPC_LINUX_PT_FPR0 + 8 * i;
     }
   else
     rs6000_frame_init_saved_regs (fi);
@@ -591,6 +591,26 @@ ppc_linux_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
   return val;
 }
 
+/* For historic reasons, PPC 32 GNU/Linux follows PowerOpen rather
+   than the 32 bit SYSV R4 ABI structure return convention - all
+   structures, no matter their size, are put in memory.  Vectors,
+   which were added later, do get returned in a register though.  */
+
+static enum return_value_convention
+ppc_linux_return_value (struct gdbarch *gdbarch, struct type *valtype,
+                       struct regcache *regcache, void *readbuf,
+                       const void *writebuf)
+{  
+  if ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+       || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+      && !((TYPE_LENGTH (valtype) == 16 || TYPE_LENGTH (valtype) == 8)
+          && TYPE_VECTOR (valtype)))
+    return RETURN_VALUE_STRUCT_CONVENTION;
+  else
+    return ppc_sysv_abi_return_value (gdbarch, valtype, regcache, readbuf,
+                                     writebuf);
+}
+
 /* 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).
@@ -731,6 +751,16 @@ insn_ds_field (unsigned int insn)
 }
 
 
+/* If DESC is the address of a 64-bit PowerPC GNU/Linux function
+   descriptor, return the descriptor's entry point.  */
+static CORE_ADDR
+ppc64_desc_entry_point (CORE_ADDR desc)
+{
+  /* The first word of the descriptor is the entry point.  */
+  return (CORE_ADDR) read_memory_unsigned_integer (desc, 8);
+}
+
+
 /* Pattern for the standard linkage function.  These are built by
    build_plt_stub in elf64-ppc.c, whose GLINK argument is always
    zero.  */
@@ -770,12 +800,12 @@ static struct insn_pattern ppc64_standard_linkage[] =
   (sizeof (ppc64_standard_linkage) / sizeof (ppc64_standard_linkage[0]))
 
 
-/* Recognize a 64-bit PowerPC Linux linkage function --- what GDB
+/* Recognize a 64-bit PowerPC GNU/Linux linkage function --- what GDB
    calls a "solib trampoline".  */
 static int
 ppc64_in_solib_call_trampoline (CORE_ADDR pc, char *name)
 {
-  /* Detecting solib call trampolines on PPC64 Linux is a pain.
+  /* Detecting solib call trampolines on PPC64 GNU/Linux is a pain.
 
      It's not specifically solib call trampolines that are the issue.
      Any call from one function to another function that uses a
@@ -787,7 +817,7 @@ ppc64_in_solib_call_trampoline (CORE_ADDR pc, char *name)
      also an inter-TOC call, and requires a trampoline --- so "solib
      call trampolines" are just a special case.
 
-     The 64-bit PowerPC Linux ABI calls these call trampolines
+     The 64-bit PowerPC GNU/Linux ABI calls these call trampolines
      "linkage functions".  Since they need to be near the functions
      that call them, they all appear in .text, not in any special
      section.  The .plt section just contains an array of function
@@ -865,7 +895,7 @@ ppc64_standard_linkage_target (CORE_ADDR pc, unsigned int *insn)
        + insn_ds_field (insn[2]));
 
   /* The first word of the descriptor is the entry point.  Return that.  */
-  return (CORE_ADDR) read_memory_unsigned_integer (desc, 8);
+  return ppc64_desc_entry_point (desc);
 }
 
 
@@ -884,6 +914,44 @@ ppc64_skip_trampoline_code (CORE_ADDR pc)
 }
 
 
+/* Support for CONVERT_FROM_FUNC_PTR_ADDR (ARCH, ADDR, TARG) on PPC64
+   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
+   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.  */
+
+/* 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.  */
+
+static CORE_ADDR
+ppc64_linux_convert_from_func_ptr_addr (struct gdbarch *gdbarch,
+                                       CORE_ADDR addr,
+                                       struct target_ops *targ)
+{
+  struct section_table *s = target_section_by_addr (targ, addr);
+
+  /* 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);
+
+  return addr;
+}
+
+
 enum {
   ELF_NGREG = 48,
   ELF_NFPREG = 33,
@@ -972,19 +1040,20 @@ ppc_linux_init_abi (struct gdbarch_info info,
 {
   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)
     {
+      /* Until November 2001, gcc did not comply with the 32 bit SysV
+        R4 ABI requirement that structures less than or equal to 8
+        bytes should be returned in registers.  Instead GCC was using
+        the the AIX/PowerOpen ABI - everything returned in memory
+        (well ignoring vectors that is).  When this was corrected, it
+        wasn't fixed for GNU/Linux native platform.  Use the
+        PowerOpen struct convention.  */
+      set_gdbarch_return_value (gdbarch, ppc_linux_return_value);
+
       /* 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_deprecated_frameless_function_invocation (gdbarch, ppc_linux_frameless_function_invocation);
       set_gdbarch_deprecated_frame_chain (gdbarch, ppc_linux_frame_chain);
       set_gdbarch_deprecated_frame_saved_pc (gdbarch, ppc_linux_frame_saved_pc);
 
@@ -1005,16 +1074,30 @@ ppc_linux_init_abi (struct gdbarch_info info,
   
   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_in_solib_call_trampoline
         (gdbarch, ppc64_in_solib_call_trampoline);
       set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code);
+
+      /* PPC64 malloc's entry-point is called ".malloc".  */
+      set_gdbarch_name_of_malloc (gdbarch, ".malloc");
     }
 }
 
 void
 _initialize_ppc_linux_tdep (void)
 {
-  gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_LINUX,
-                         ppc_linux_init_abi);
+  /* Register for all sub-familes of the POWER/PowerPC: 32-bit and
+     64-bit PowerPC, and the older rs6k.  */
+  gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc, GDB_OSABI_LINUX,
+                         ppc_linux_init_abi);
+  gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc64, GDB_OSABI_LINUX,
+                         ppc_linux_init_abi);
+  gdbarch_register_osabi (bfd_arch_rs6000, bfd_mach_rs6k, GDB_OSABI_LINUX,
+                         ppc_linux_init_abi);
   add_core_fns (&ppc_linux_regset_core_fns);
 }
This page took 0.025923 seconds and 4 git commands to generate.