Add shared library support for FR-V FDPIC ABI.
[platform/upstream/binutils.git] / gdb / frv-tdep.c
index 50a421c..6020b38 100644 (file)
@@ -1,5 +1,5 @@
 /* Target-dependent code for the Fujitsu FR-V, for GDB, the GNU Debugger.
-   Copyright 2002, 2003 Free Software Foundation, Inc.
+   Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -21,7 +21,6 @@
 #include "defs.h"
 #include "gdb_string.h"
 #include "inferior.h"
-#include "symfile.h"           /* for entry_point_address */
 #include "gdbcore.h"
 #include "arch-utils.h"
 #include "regcache.h"
 #include "sim-regno.h"
 #include "gdb/sim-frv.h"
 #include "opcodes/frv-desc.h"  /* for the H_SPR_... enums */
+#include "symtab.h"
+#include "elf-bfd.h"
+#include "elf/frv.h"
+#include "osabi.h"
+#include "frv-tdep.h"
 
 extern void _initialize_frv_tdep (void);
 
@@ -43,9 +47,6 @@ static gdbarch_register_name_ftype frv_register_name;
 static gdbarch_breakpoint_from_pc_ftype frv_breakpoint_from_pc;
 static gdbarch_adjust_breakpoint_address_ftype frv_gdbarch_adjust_breakpoint_address;
 static gdbarch_skip_prologue_ftype frv_skip_prologue;
-static gdbarch_frameless_function_invocation_ftype frv_frameless_function_invocation;
-static gdbarch_deprecated_push_arguments_ftype frv_push_arguments;
-static gdbarch_deprecated_saved_pc_after_call_ftype frv_saved_pc_after_call;
 
 /* Register numbers.  The order in which these appear define the
    remote protocol, so take care in changing them.  */
@@ -72,6 +73,8 @@ enum {
   psr_regnum = 129,
   ccr_regnum = 130,
   cccr_regnum = 131,
+  fdpic_loadmap_exec_regnum = 132,
+  fdpic_loadmap_interp_regnum = 133,
   tbr_regnum = 135,
   brr_regnum = 136,
   dbar0_regnum = 137,
@@ -132,6 +135,9 @@ struct frv_unwind_cache             /* was struct frame_extra_info */
    Fortran.  */
 struct gdbarch_tdep
 {
+  /* Which ABI is in use?  */
+  enum frv_abi frv_abi;
+
   /* How many general-purpose registers does this variant have?  */
   int num_gprs;
 
@@ -150,6 +156,41 @@ struct gdbarch_tdep
 
 #define CURRENT_VARIANT (gdbarch_tdep (current_gdbarch))
 
+/* Return the FR-V ABI associated with GDBARCH.  */
+enum frv_abi
+frv_abi (struct gdbarch *gdbarch)
+{
+  return gdbarch_tdep (gdbarch)->frv_abi;
+}
+
+/* Fetch the interpreter and executable loadmap addresses (for shared
+   library support) for the FDPIC ABI.  Return 0 if successful, -1 if
+   not.  (E.g, -1 will be returned if the ABI isn't the FDPIC ABI.)  */
+int
+frv_fdpic_loadmap_addresses (struct gdbarch *gdbarch, CORE_ADDR *interp_addr,
+                             CORE_ADDR *exec_addr)
+{
+  if (frv_abi (gdbarch) != FRV_ABI_FDPIC)
+    return -1;
+  else
+    {
+      if (interp_addr != NULL)
+       {
+         ULONGEST val;
+         regcache_cooked_read_unsigned (current_regcache,
+                                        fdpic_loadmap_interp_regnum, &val);
+         *interp_addr = val;
+       }
+      if (exec_addr != NULL)
+       {
+         ULONGEST val;
+         regcache_cooked_read_unsigned (current_regcache,
+                                        fdpic_loadmap_exec_regnum, &val);
+         *exec_addr = val;
+       }
+      return 0;
+    }
+}
 
 /* Allocate a new variant structure, and set up default values for all
    the fields.  */
@@ -163,6 +204,7 @@ new_variant (void)
   var = xmalloc (sizeof (*var));
   memset (var, 0, sizeof (*var));
   
+  var->frv_abi = FRV_ABI_EABI;
   var->num_gprs = 64;
   var->num_fprs = 64;
   var->num_hw_watchpoints = 0;
@@ -241,6 +283,13 @@ set_variant_num_fprs (struct gdbarch_tdep *var, int num_fprs)
     }
 }
 
+static void
+set_variant_abi_fdpic (struct gdbarch_tdep *var)
+{
+  var->frv_abi = FRV_ABI_FDPIC;
+  var->register_names[fdpic_loadmap_exec_regnum] = xstrdup ("loadmap_exec");
+  var->register_names[fdpic_loadmap_interp_regnum] = xstrdup ("loadmap_interp");
+}
 
 static const char *
 frv_register_name (int reg)
@@ -417,62 +466,6 @@ is_argument_reg (int reg)
   return (8 <= reg && reg <= 13);
 }
 
-/* Given PC at the function's start address, attempt to find the
-   prologue end using SAL information.  Return zero if the skip fails.
-
-   A non-optimized prologue traditionally has one SAL for the function
-   and a second for the function body.  A single line function has
-   them both pointing at the same line.
-
-   An optimized prologue is similar but the prologue may contain
-   instructions (SALs) from the instruction body.  Need to skip those
-   while not getting into the function body.
-
-   The functions end point and an increasing SAL line are used as
-   indicators of the prologue's endpoint.
-
-   This code is based on the function refine_prologue_limit (versions
-   found in both ia64 and ppc).  */
-
-static CORE_ADDR
-skip_prologue_using_sal (CORE_ADDR func_addr)
-{
-  struct symtab_and_line prologue_sal;
-  CORE_ADDR start_pc;
-  CORE_ADDR end_pc;
-
-  /* Get an initial range for the function.  */
-  find_pc_partial_function (func_addr, NULL, &start_pc, &end_pc);
-  start_pc += FUNCTION_START_OFFSET;
-
-  prologue_sal = find_pc_line (start_pc, 0);
-  if (prologue_sal.line != 0)
-    {
-      while (prologue_sal.end < end_pc)
-       {
-         struct symtab_and_line sal;
-
-         sal = find_pc_line (prologue_sal.end, 0);
-         if (sal.line == 0)
-           break;
-         /* Assume that a consecutive SAL for the same (or larger)
-             line mark the prologue -> body transition.  */
-         if (sal.line >= prologue_sal.line)
-           break;
-         /* The case in which compiler's optimizer/scheduler has
-            moved instructions into the prologue.  We look ahead in
-            the function looking for address ranges whose
-            corresponding line number is less the first one that we
-            found for the function.  This is more conservative then
-            refine_prologue_limit which scans a large number of SALs
-            looking for any in the prologue */
-         prologue_sal = sal;
-       }
-    }
-  return prologue_sal.end;
-}
-
-
 /* Scan an FR-V prologue, starting at PC, until frame->PC.
    If FRAME is non-zero, fill in its saved_regs with appropriate addresses.
    We assume FRAME's saved_regs array has already been allocated and cleared.
@@ -1033,7 +1026,7 @@ frv_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
 static int
 frv_frameless_function_invocation (struct frame_info *frame)
 {
-  return frameless_look_for_prologue (frame);
+  return legacy_frameless_look_for_prologue (frame);
 }
 
 static CORE_ADDR
@@ -1044,6 +1037,45 @@ frv_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
 }
 
 static CORE_ADDR
+find_func_descr (struct gdbarch *gdbarch, CORE_ADDR entry_point)
+{
+  CORE_ADDR descr;
+  char valbuf[4];
+
+  descr = frv_fdpic_find_canonical_descriptor (entry_point);
+
+  if (descr != 0)
+    return descr;
+
+  /* Construct a non-canonical descriptor from space allocated on
+     the stack.  */
+
+  descr = value_as_long (value_allocate_space_in_inferior (8));
+  store_unsigned_integer (valbuf, 4, entry_point);
+  write_memory (descr, valbuf, 4);
+  store_unsigned_integer (valbuf, 4,
+                          frv_fdpic_find_global_pointer (entry_point));
+  write_memory (descr + 4, valbuf, 4);
+  return descr;
+}
+
+static CORE_ADDR
+frv_convert_from_func_ptr_addr (struct gdbarch *gdbarch, CORE_ADDR addr,
+                                struct target_ops *targ)
+{
+  CORE_ADDR entry_point;
+  CORE_ADDR got_address;
+
+  entry_point = get_target_memory_unsigned (targ, addr, 4);
+  got_address = get_target_memory_unsigned (targ, addr + 4, 4);
+
+  if (got_address == frv_fdpic_find_global_pointer (entry_point))
+    return entry_point;
+  else
+    return addr;
+}
+
+static CORE_ADDR
 frv_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,
@@ -1060,6 +1092,7 @@ frv_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
   CORE_ADDR regval;
   int stack_space;
   int stack_offset;
+  enum frv_abi abi = frv_abi (gdbarch);
 
 #if 0
   printf("Push %d args at sp = %x, struct_return=%d (%x)\n",
@@ -1099,6 +1132,22 @@ frv_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
          len = 4;
          val = valbuf;
        }
+      else if (abi == FRV_ABI_FDPIC
+              && len == 4
+               && typecode == TYPE_CODE_PTR
+               && TYPE_CODE (TYPE_TARGET_TYPE (arg_type)) == TYPE_CODE_FUNC)
+       {
+         /* The FDPIC ABI requires function descriptors to be passed instead
+            of entry points.  */
+         store_unsigned_integer
+           (valbuf, 4,
+            find_func_descr (gdbarch,
+                             extract_unsigned_integer (VALUE_CONTENTS (arg),
+                                                       4)));
+         typecode = TYPE_CODE_PTR;
+         len = 4;
+         val = valbuf;
+       }
       else
        {
          val = (char *) VALUE_CONTENTS (arg);
@@ -1136,6 +1185,14 @@ frv_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
      always at BP_ADDR.  */
   regcache_cooked_write_unsigned (regcache, lr_regnum, bp_addr);
 
+  if (abi == FRV_ABI_FDPIC)
+    {
+      /* Set the GOT register for the FDPIC ABI.  */
+      regcache_cooked_write_unsigned
+       (regcache, first_gpr_regnum + 15,
+         frv_fdpic_find_global_pointer (func_addr));
+    }
+
   /* Finally, update the SP register.  */
   regcache_cooked_write_unsigned (regcache, sp_regnum, sp);
 
@@ -1335,6 +1392,7 @@ frv_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
   struct gdbarch *gdbarch;
   struct gdbarch_tdep *var;
+  int elf_flags = 0;
 
   /* Check to see if we've already built an appropriate architecture
      object for this executable.  */
@@ -1364,7 +1422,14 @@ frv_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       /* Never heard of this variant.  */
       return 0;
     }
-  
+
+  /* Extract the ELF flags, if available.  */
+  if (info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+
+  if (elf_flags & EF_FRV_FDPIC)
+    set_variant_abi_fdpic (var);
+
   gdbarch = gdbarch_alloc (&info, var);
 
   set_gdbarch_short_bit (gdbarch, 16);
@@ -1394,15 +1459,14 @@ frv_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_breakpoint_from_pc (gdbarch, frv_breakpoint_from_pc);
   set_gdbarch_adjust_breakpoint_address (gdbarch, frv_gdbarch_adjust_breakpoint_address);
 
-  set_gdbarch_frame_args_skip (gdbarch, 0);
-  set_gdbarch_frameless_function_invocation (gdbarch, frv_frameless_function_invocation);
+  set_gdbarch_deprecated_frameless_function_invocation (gdbarch, frv_frameless_function_invocation);
 
   set_gdbarch_use_struct_convention (gdbarch, always_use_struct_convention);
   set_gdbarch_extract_return_value (gdbarch, frv_extract_return_value);
 
   set_gdbarch_deprecated_store_struct_return (gdbarch, frv_store_struct_return);
   set_gdbarch_store_return_value (gdbarch, frv_store_return_value);
-  set_gdbarch_extract_struct_value_address (gdbarch, frv_extract_struct_value_address);
+  set_gdbarch_deprecated_extract_struct_value_address (gdbarch, frv_extract_struct_value_address);
 
   /* Frame stuff.  */
   set_gdbarch_unwind_pc (gdbarch, frv_unwind_pc);
@@ -1449,6 +1513,9 @@ frv_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     }
 
   set_gdbarch_print_insn (gdbarch, print_insn_frv);
+  if (frv_abi (gdbarch) == FRV_ABI_FDPIC)
+    set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+                                           frv_convert_from_func_ptr_addr);
 
   return gdbarch;
 }