/* 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.
#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);
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;
/* Register numbers. The order in which these appear define the
remote protocol, so take care in changing them. */
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,
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;
#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. */
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;
}
}
+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)
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.
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
}
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,
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",
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);
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);
{
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. */
/* 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);
set_gdbarch_breakpoint_from_pc (gdbarch, frv_breakpoint_from_pc);
set_gdbarch_adjust_breakpoint_address (gdbarch, frv_gdbarch_adjust_breakpoint_address);
- 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_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;
}