#include "solib-svr4.h"
#include "arm-tdep.h"
+#include "gdb/sim-arm.h"
#include "elf-bfd.h"
#include "coff/internal.h"
#include "elf/arm.h"
+#include "gdb_assert.h"
+
+static int arm_debug;
+
/* Each OS has a different mechanism for accessing the various
registers stored in the sigcontext structure.
#define MSYMBOL_SIZE(msym) \
((long) MSYMBOL_INFO (msym) & 0x7fffffff)
-/* This table matches the indicees assigned to enum arm_abi.
- Keep them in sync. */
-
-static const char * const arm_abi_names[] =
-{
- "<unknown>",
- "ARM EABI (version 1)",
- "ARM EABI (version 2)",
- "GNU/Linux",
- "NetBSD (a.out)",
- "NetBSD (ELF)",
- "APCS",
- "FreeBSD",
- "Windows CE",
- NULL
-};
-
/* Number of different reg name sets (options). */
static int num_flavor_options;
static CORE_ADDR
arm_addr_bits_remove (CORE_ADDR val)
{
- if (arm_pc_is_thumb (val))
- return (val & (arm_apcs_32 ? 0xfffffffe : 0x03fffffe));
+ if (arm_apcs_32)
+ return (val & (arm_pc_is_thumb (val) ? 0xfffffffe : 0xfffffffc));
else
- return (val & (arm_apcs_32 ? 0xfffffffc : 0x03fffffc));
+ return (val & 0x03fffffc);
}
/* When reading symbols, we need to zap the low bit of the address,
{
unsigned long inst;
CORE_ADDR skip_pc;
- CORE_ADDR func_addr, func_end;
+ CORE_ADDR func_addr, func_end = 0;
char *func_name;
struct symtab_and_line sal;
+ /* If we're in a dummy frame, don't even try to skip the prologue. */
+ if (USE_GENERIC_DUMMY_FRAMES
+ && PC_IN_CALL_DUMMY (pc, 0, 0))
+ return pc;
+
/* See what the symbol table says. */
if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end))
/* Can't find the prologue end in the symbol table, try it the hard way
by disassembling the instructions. */
- skip_pc = pc;
- inst = read_memory_integer (skip_pc, 4);
- /* "mov ip, sp" is no longer a required part of the prologue. */
- if (inst == 0xe1a0c00d) /* mov ip, sp */
- {
- skip_pc += 4;
- inst = read_memory_integer (skip_pc, 4);
- }
- /* Some prologues begin with "str lr, [sp, #-4]!". */
- if (inst == 0xe52de004) /* str lr, [sp, #-4]! */
- {
- skip_pc += 4;
- inst = read_memory_integer (skip_pc, 4);
- }
+ /* Like arm_scan_prologue, stop no later than pc + 64. */
+ if (func_end == 0 || func_end > pc + 64)
+ func_end = pc + 64;
- if ((inst & 0xfffffff0) == 0xe92d0000) /* stmfd sp!,{a1,a2,a3,a4} */
+ for (skip_pc = pc; skip_pc < func_end; skip_pc += 4)
{
- skip_pc += 4;
inst = read_memory_integer (skip_pc, 4);
- }
- if ((inst & 0xfffff800) == 0xe92dd800) /* stmfd sp!,{fp,ip,lr,pc} */
- {
- skip_pc += 4;
- inst = read_memory_integer (skip_pc, 4);
- }
+ /* "mov ip, sp" is no longer a required part of the prologue. */
+ if (inst == 0xe1a0c00d) /* mov ip, sp */
+ continue;
- /* Any insns after this point may float into the code, if it makes
- for better instruction scheduling, so we skip them only if we
- find them, but still consider the function to be frame-ful. */
+ /* Some prologues begin with "str lr, [sp, #-4]!". */
+ if (inst == 0xe52de004) /* str lr, [sp, #-4]! */
+ continue;
- /* We may have either one sfmfd instruction here, or several stfe
- insns, depending on the version of floating point code we
- support. */
- if ((inst & 0xffbf0fff) == 0xec2d0200) /* sfmfd fn, <cnt>, [sp]! */
- {
- skip_pc += 4;
- inst = read_memory_integer (skip_pc, 4);
- }
- else
- {
- while ((inst & 0xffff8fff) == 0xed6d0103) /* stfe fn, [sp, #-12]! */
- {
- skip_pc += 4;
- inst = read_memory_integer (skip_pc, 4);
- }
- }
+ if ((inst & 0xfffffff0) == 0xe92d0000) /* stmfd sp!,{a1,a2,a3,a4} */
+ continue;
- if ((inst & 0xfffff000) == 0xe24cb000) /* sub fp, ip, #nn */
- {
- skip_pc += 4;
- inst = read_memory_integer (skip_pc, 4);
- }
+ if ((inst & 0xfffff800) == 0xe92dd800) /* stmfd sp!,{fp,ip,lr,pc} */
+ continue;
- if ((inst & 0xfffff000) == 0xe24dd000) /* sub sp, sp, #nn */
- {
- skip_pc += 4;
- inst = read_memory_integer (skip_pc, 4);
- }
+ /* Any insns after this point may float into the code, if it makes
+ for better instruction scheduling, so we skip them only if we
+ find them, but still consider the function to be frame-ful. */
- while ((inst & 0xffffcfc0) == 0xe50b0000) /* str r(0123), [r11, #-nn] */
- {
- skip_pc += 4;
- inst = read_memory_integer (skip_pc, 4);
+ /* We may have either one sfmfd instruction here, or several stfe
+ insns, depending on the version of floating point code we
+ support. */
+ if ((inst & 0xffbf0fff) == 0xec2d0200) /* sfmfd fn, <cnt>, [sp]! */
+ continue;
+
+ if ((inst & 0xffff8fff) == 0xed6d0103) /* stfe fn, [sp, #-12]! */
+ continue;
+
+ if ((inst & 0xfffff000) == 0xe24cb000) /* sub fp, ip, #nn */
+ continue;
+
+ if ((inst & 0xfffff000) == 0xe24dd000) /* sub sp, sp, #nn */
+ continue;
+
+ if ((inst & 0xffffc000) == 0xe54b0000 || /* strb r(0123),[r11,#-nn] */
+ (inst & 0xffffc0f0) == 0xe14b00b0 || /* strh r(0123),[r11,#-nn] */
+ (inst & 0xffffc000) == 0xe50b0000) /* str r(0123),[r11,#-nn] */
+ continue;
+
+ if ((inst & 0xffffc000) == 0xe5cd0000 || /* strb r(0123),[sp,#nn] */
+ (inst & 0xffffc0f0) == 0xe1cd00b0 || /* strh r(0123),[sp,#nn] */
+ (inst & 0xffffc000) == 0xe58d0000) /* str r(0123),[sp,#nn] */
+ continue;
+
+ /* Un-recognized instruction; stop scanning. */
+ break;
}
- return skip_pc;
+ return skip_pc; /* End of prologue */
}
/* *INDENT-OFF* */
int findmask = 0;
int i;
+ /* Don't try to scan dummy frames. */
+ if (USE_GENERIC_DUMMY_FRAMES
+ && fi != NULL
+ && PC_IN_CALL_DUMMY (fi->pc, 0, 0))
+ return;
+
if (find_pc_partial_function (fi->pc, NULL, &prologue_start, &prologue_end))
{
struct symtab_and_line sal = find_pc_line (prologue_start, 0);
whether to save LR (R14). */
mask = (insn & 0xff) | ((insn & 0x100) << 6);
- /* Calculate offsets of saved R0-R7 and LR. */
+ /* Calculate offsets of saved R0-R7 and LR. */
for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
if (mask & (1 << regno))
{
else if ((insn & 0xff00) == 0xb000) /* add sp, #simm OR
sub sp, #simm */
{
- if ((findmask & 1) == 0) /* before push? */
+ if ((findmask & 1) == 0) /* before push? */
continue;
else
findmask |= 4; /* add/sub sp found */
Be careful, however, and if it doesn't look like a prologue,
don't try to scan it. If, for instance, a frameless function
begins with stmfd sp!, then we will tell ourselves there is
- a frame, which will confuse stack traceback, as well ad"finish"
+ a frame, which will confuse stack traceback, as well as "finish"
and other operations that rely on a knowledge of the stack
traceback.
[Note further: The "mov ip,sp" only seems to be missing in
frameless functions at optimization level "-O2" or above,
in which case it is often (but not always) replaced by
- "str lr, [sp, #-4]!". - Michael Snyder, 2002-04-23] */
+ "str lr, [sp, #-4]!". - Michael Snyder, 2002-04-23] */
sp_offset = fp_offset = 0;
fi->saved_regs[regno] = sp_offset;
}
}
- else if ((insn & 0xffffcfc0) == 0xe50b0000) /* str rx, [r11, -n] */
+ else if ((insn & 0xffffc000) == 0xe54b0000 || /* strb rx,[r11,#-n] */
+ (insn & 0xffffc0f0) == 0xe14b00b0 || /* strh rx,[r11,#-n] */
+ (insn & 0xffffc000) == 0xe50b0000) /* str rx,[r11,#-n] */
+ {
+ /* No need to add this to saved_regs -- it's just an arg reg. */
+ continue;
+ }
+ else if ((insn & 0xffffc000) == 0xe5cd0000 || /* strb rx,[sp,#n] */
+ (insn & 0xffffc0f0) == 0xe1cd00b0 || /* strh rx,[sp,#n] */
+ (insn & 0xffffc000) == 0xe58d0000) /* str rx,[sp,#n] */
{
/* No need to add this to saved_regs -- it's just an arg reg. */
continue;
}
else if ((insn & 0xf0000000) != 0xe0000000)
break; /* Condition not true, exit early */
- else if ((insn & 0xfe200000) == 0xe8200000) /* ldm? */
+ else if ((insn & 0xfe200000) == 0xe8200000) /* ldm? */
break; /* Don't scan past a block load */
else
/* The optimizer might shove anything into the prologue,
static CORE_ADDR
arm_find_callers_reg (struct frame_info *fi, int regnum)
{
+ /* NOTE: cagney/2002-05-03: This function really shouldn't be
+ needed. Instead the (still being written) register unwind
+ function could be called directly. */
for (; fi; fi = fi->next)
-
-#if 0 /* FIXME: enable this code if we convert to new call dummy scheme. */
- if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
- return generic_read_register_dummy (fi->pc, fi->frame, regnum);
- else
-#endif
- if (fi->saved_regs[regnum] != 0)
- return read_memory_integer (fi->saved_regs[regnum],
- REGISTER_RAW_SIZE (regnum));
+ {
+ if (USE_GENERIC_DUMMY_FRAMES
+ && PC_IN_CALL_DUMMY (fi->pc, 0, 0))
+ {
+ return deprecated_read_register_dummy (fi->pc, fi->frame, regnum);
+ }
+ else if (fi->saved_regs[regnum] != 0)
+ {
+ /* NOTE: cagney/2002-05-03: This would normally need to
+ handle ARM_SP_REGNUM as a special case as, according to
+ the frame.h comments, saved_regs[SP_REGNUM] contains the
+ SP value not its address. It appears that the ARM isn't
+ doing this though. */
+ return read_memory_integer (fi->saved_regs[regnum],
+ REGISTER_RAW_SIZE (regnum));
+ }
+ }
return read_register (regnum);
}
/* Function: frame_chain Given a GDB frame, determine the address of
static CORE_ADDR
arm_frame_chain (struct frame_info *fi)
{
-#if 0 /* FIXME: enable this code if we convert to new call dummy scheme. */
- CORE_ADDR fn_start, callers_pc, fp;
-
- /* Is this a dummy frame? */
- if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
- return fi->frame; /* dummy frame same as caller's frame */
-
- /* Is caller-of-this a dummy frame? */
- callers_pc = FRAME_SAVED_PC (fi); /* find out who called us: */
- fp = arm_find_callers_reg (fi, ARM_FP_REGNUM);
- if (PC_IN_CALL_DUMMY (callers_pc, fp, fp))
- return fp; /* dummy frame's frame may bear no relation to ours */
-
- if (find_pc_partial_function (fi->pc, 0, &fn_start, 0))
- if (fn_start == entry_point_address ())
- return 0; /* in _start fn, don't chain further */
-#endif
- CORE_ADDR caller_pc, fn_start;
+ CORE_ADDR caller_pc;
int framereg = fi->extra_info->framereg;
+ if (USE_GENERIC_DUMMY_FRAMES
+ && PC_IN_CALL_DUMMY (fi->pc, 0, 0))
+ /* A generic call dummy's frame is the same as caller's. */
+ return fi->frame;
+
if (fi->pc < LOWEST_PC)
return 0;
/* If the caller is the startup code, we're at the end of the chain. */
caller_pc = FRAME_SAVED_PC (fi);
- if (find_pc_partial_function (caller_pc, 0, &fn_start, 0))
- if (fn_start == entry_point_address ())
- return 0;
/* If the caller is Thumb and the caller is ARM, or vice versa,
the frame register of the caller is different from ours.
memset (fi->saved_regs, '\000', sizeof fi->saved_regs);
-#if 0 /* FIXME: enable this code if we convert to new call dummy scheme. */
- if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
- {
- /* We need to setup fi->frame here because run_stack_dummy gets
- it wrong by assuming it's always FP. */
- fi->frame = generic_read_register_dummy (fi->pc, fi->frame,
- ARM_SP_REGNUM);
- fi->extra_info->framesize = 0;
- fi->extra_info->frameoffset = 0;
- return;
- }
- else
-#endif
-
/* Compute stack pointer for this frame. We use this value for both
the sigtramp and call dummy cases. */
if (!fi->next)
sp = read_sp();
+ else if (USE_GENERIC_DUMMY_FRAMES
+ && PC_IN_CALL_DUMMY (fi->next->pc, 0, 0))
+ /* For generic dummy frames, pull the value direct from the frame.
+ Having an unwind function to do this would be nice. */
+ sp = deprecated_read_register_dummy (fi->next->pc, fi->next->frame,
+ ARM_SP_REGNUM);
else
sp = (fi->next->frame - fi->next->extra_info->frameoffset
+ fi->next->extra_info->framesize);
fi->extra_info->frameoffset = 0;
}
- else if (PC_IN_CALL_DUMMY (fi->pc, sp, fi->frame))
+ else if (!USE_GENERIC_DUMMY_FRAMES
+ && PC_IN_CALL_DUMMY (fi->pc, sp, fi->frame))
{
CORE_ADDR rp;
CORE_ADDR callers_sp;
callers_sp = read_memory_integer (fi->saved_regs[ARM_SP_REGNUM],
REGISTER_RAW_SIZE (ARM_SP_REGNUM));
- fi->extra_info->framereg = ARM_FP_REGNUM;
+ if (arm_pc_is_thumb (fi->pc))
+ fi->extra_info->framereg = THUMB_FP_REGNUM;
+ else
+ fi->extra_info->framereg = ARM_FP_REGNUM;
fi->extra_info->framesize = callers_sp - sp;
fi->extra_info->frameoffset = fi->frame - sp;
}
if (!fi->next)
/* This is the innermost frame? */
fi->frame = read_register (fi->extra_info->framereg);
+ else if (USE_GENERIC_DUMMY_FRAMES
+ && PC_IN_CALL_DUMMY (fi->next->pc, 0, 0))
+ /* Next inner most frame is a dummy, just grab its frame.
+ Dummy frames always have the same FP as their caller. */
+ fi->frame = fi->next->frame;
else if (fi->extra_info->framereg == ARM_FP_REGNUM
|| fi->extra_info->framereg == THUMB_FP_REGNUM)
{
static CORE_ADDR
arm_frame_saved_pc (struct frame_info *fi)
{
-#if 0 /* FIXME: enable this code if we convert to new call dummy scheme. */
- if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
- return generic_read_register_dummy (fi->pc, fi->frame, ARM_PC_REGNUM);
- else
-#endif
+ /* If a dummy frame, pull the PC out of the frame's register buffer. */
+ if (USE_GENERIC_DUMMY_FRAMES
+ && PC_IN_CALL_DUMMY (fi->pc, 0, 0))
+ return deprecated_read_register_dummy (fi->pc, fi->frame, ARM_PC_REGNUM);
+
if (PC_IN_CALL_DUMMY (fi->pc, fi->frame - fi->extra_info->frameoffset,
fi->frame))
{
arm_init_extra_frame_info (0, fip);
}
+/* Set the return address for a generic dummy frame. ARM uses the
+ entry point. */
+
+static CORE_ADDR
+arm_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
+{
+ write_register (ARM_LR_REGNUM, CALL_DUMMY_ADDRESS ());
+ return sp;
+}
+
/* Push an empty stack frame, to record the current PC, etc. */
static void
arm_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
- char *fp;
- int argnum, argreg, nstack_size;
+ CORE_ADDR fp;
+ int argnum;
+ int argreg;
+ int nstack;
+ int simd_argreg;
+ int second_pass;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
/* Walk through the list of args and determine how large a temporary
stack is required. Need to take care here as structs may be
- passed on the stack, and we have to to push them. */
- nstack_size = -4 * REGISTER_SIZE; /* Some arguments go into A1-A4. */
- if (struct_return) /* The struct address goes in A1. */
- nstack_size += REGISTER_SIZE;
-
- /* Walk through the arguments and add their size to nstack_size. */
- for (argnum = 0; argnum < nargs; argnum++)
- {
- int len;
- struct type *arg_type;
-
- arg_type = check_typedef (VALUE_TYPE (args[argnum]));
- len = TYPE_LENGTH (arg_type);
-
- nstack_size += len;
- }
-
- /* Allocate room on the stack, and initialize our stack frame
- pointer. */
- fp = NULL;
- if (nstack_size > 0)
- {
- sp -= nstack_size;
- fp = (char *) sp;
- }
-
- /* Initialize the integer argument register pointer. */
- argreg = ARM_A1_REGNUM;
-
- /* The struct_return pointer occupies the first parameter passing
- register. */
- if (struct_return)
- write_register (argreg++, struct_addr);
-
- /* Process arguments from left to right. Store as many as allowed
- in the parameter passing registers (A1-A4), and save the rest on
- the temporary stack. */
- for (argnum = 0; argnum < nargs; argnum++)
- {
- int len;
- char *val;
- CORE_ADDR regval;
- enum type_code typecode;
- struct type *arg_type, *target_type;
-
- arg_type = check_typedef (VALUE_TYPE (args[argnum]));
- target_type = TYPE_TARGET_TYPE (arg_type);
- len = TYPE_LENGTH (arg_type);
- typecode = TYPE_CODE (arg_type);
- val = (char *) VALUE_CONTENTS (args[argnum]);
-
-#if 1
- /* I don't know why this code was disable. The only logical use
- for a function pointer is to call that function, so setting
- the mode bit is perfectly fine. FN */
- /* If the argument is a pointer to a function, and it is a Thumb
- function, set the low bit of the pointer. */
- if (TYPE_CODE_PTR == typecode
- && NULL != target_type
- && TYPE_CODE_FUNC == TYPE_CODE (target_type))
+ passed on the stack, and we have to to push them. On the second
+ pass, do the store. */
+ nstack = 0;
+ fp = sp;
+ for (second_pass = 0; second_pass < 2; second_pass++)
+ {
+ /* Compute the FP using the information computed during the
+ first pass. */
+ if (second_pass)
+ fp = sp - nstack;
+
+ simd_argreg = 0;
+ argreg = ARM_A1_REGNUM;
+ nstack = 0;
+
+ /* The struct_return pointer occupies the first parameter
+ passing register. */
+ if (struct_return)
{
- CORE_ADDR regval = extract_address (val, len);
- if (arm_pc_is_thumb (regval))
- store_address (val, len, MAKE_THUMB_ADDR (regval));
+ if (second_pass)
+ {
+ if (arm_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "struct return in %s = 0x%s\n",
+ REGISTER_NAME (argreg),
+ paddr (struct_addr));
+ write_register (argreg, struct_addr);
+ }
+ argreg++;
}
-#endif
- /* Copy the argument to general registers or the stack in
- register-sized pieces. Large arguments are split between
- registers and stack. */
- while (len > 0)
- {
- int partial_len = len < REGISTER_SIZE ? len : REGISTER_SIZE;
- if (argreg <= ARM_LAST_ARG_REGNUM)
+ for (argnum = 0; argnum < nargs; argnum++)
+ {
+ int len;
+ struct type *arg_type;
+ struct type *target_type;
+ enum type_code typecode;
+ char *val;
+
+ arg_type = check_typedef (VALUE_TYPE (args[argnum]));
+ len = TYPE_LENGTH (arg_type);
+ target_type = TYPE_TARGET_TYPE (arg_type);
+ typecode = TYPE_CODE (arg_type);
+ val = VALUE_CONTENTS (args[argnum]);
+
+ /* If the argument is a pointer to a function, and it is a
+ Thumb function, create a LOCAL copy of the value and set
+ the THUMB bit in it. */
+ if (second_pass
+ && TYPE_CODE_PTR == typecode
+ && target_type != NULL
+ && TYPE_CODE_FUNC == TYPE_CODE (target_type))
{
- /* It's an argument being passed in a general register. */
- regval = extract_address (val, partial_len);
- write_register (argreg++, regval);
+ CORE_ADDR regval = extract_address (val, len);
+ if (arm_pc_is_thumb (regval))
+ {
+ val = alloca (len);
+ store_address (val, len, MAKE_THUMB_ADDR (regval));
+ }
}
- else
+
+ /* Copy the argument to general registers or the stack in
+ register-sized pieces. Large arguments are split between
+ registers and stack. */
+ while (len > 0)
{
- /* Push the arguments onto the stack. */
- write_memory ((CORE_ADDR) fp, val, REGISTER_SIZE);
- fp += REGISTER_SIZE;
+ int partial_len = len < REGISTER_SIZE ? len : REGISTER_SIZE;
+
+ if (argreg <= ARM_LAST_ARG_REGNUM)
+ {
+ /* The argument is being passed in a general purpose
+ register. */
+ if (second_pass)
+ {
+ CORE_ADDR regval = extract_address (val,
+ partial_len);
+ if (arm_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "arg %d in %s = 0x%s\n",
+ argnum,
+ REGISTER_NAME (argreg),
+ phex (regval, REGISTER_SIZE));
+ write_register (argreg, regval);
+ }
+ argreg++;
+ }
+ else
+ {
+ if (second_pass)
+ {
+ /* Push the arguments onto the stack. */
+ if (arm_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "arg %d @ 0x%s + %d\n",
+ argnum, paddr (fp), nstack);
+ write_memory (fp + nstack, val, REGISTER_SIZE);
+ }
+ nstack += REGISTER_SIZE;
+ }
+
+ len -= partial_len;
+ val += partial_len;
}
- len -= partial_len;
- val += partial_len;
}
}
- /* Return adjusted stack pointer. */
- return sp;
+ /* Return the botom of the argument list (pointed to by fp). */
+ return fp;
}
/* Pop the current frame. So long as the frame info has been
CORE_ADDR old_SP = (frame->frame - frame->extra_info->frameoffset
+ frame->extra_info->framesize);
+ if (USE_GENERIC_DUMMY_FRAMES
+ && PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
+ {
+ generic_pop_dummy_frame ();
+ flush_cached_frames ();
+ return;
+ }
+
for (regnum = 0; regnum < NUM_REGS; regnum++)
if (frame->saved_regs[regnum] != 0)
write_register (regnum,
/* Print interesting information about the floating point processor
(if present) or emulator. */
static void
-arm_print_float_info (void)
+arm_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
+ struct frame_info *frame, const char *args)
{
register unsigned long status = read_register (ARM_FPS_REGNUM);
int type;
return STATUS_REGISTER_SIZE;
}
+/* Map GDB internal REGNUM onto the Arm simulator register numbers. */
+static int
+arm_register_sim_regno (int regnum)
+{
+ int reg = regnum;
+ gdb_assert (reg >= 0 && reg < NUM_REGS);
+
+ if (reg < NUM_GREGS)
+ return SIM_ARM_R0_REGNUM + reg;
+ reg -= NUM_GREGS;
+
+ if (reg < NUM_FREGS)
+ return SIM_ARM_FP0_REGNUM + reg;
+ reg -= NUM_FREGS;
+
+ if (reg < NUM_SREGS)
+ return SIM_ARM_FPS_REGNUM + reg;
+ reg -= NUM_SREGS;
+
+ internal_error (__FILE__, __LINE__, "Bad REGNUM %d", regnum);
+}
/* NOTE: cagney/2001-08-20: Both convert_from_extended() and
convert_to_extended() use floatformat_arm_ext_littlebyte_bigword.
static void
arm_software_single_step (enum target_signal sig, int insert_bpt)
{
- static int next_pc; /* State between setting and unsetting. */
+ static int next_pc; /* State between setting and unsetting. */
static char break_mem[BREAKPOINT_MAX]; /* Temporary storage for mem@bpt */
if (insert_bpt)
the address in which a function should return its structure value. */
static CORE_ADDR
-arm_extract_struct_value_address (char *regbuf)
+arm_extract_struct_value_address (struct regcache *regcache)
{
- return extract_address (regbuf, REGISTER_RAW_SIZE(ARM_A1_REGNUM));
+ ULONGEST ret;
+
+ regcache_cooked_read_unsigned (regcache, ARM_A1_REGNUM, &ret);
+ return ret;
}
/* Will a function return an aggregate type in memory or in a
case ARM_FLOAT_FPA:
convert_to_extended (valbuf, buf);
- write_register_bytes (REGISTER_BYTE (ARM_F0_REGNUM), buf,
- FP_REGISTER_RAW_SIZE);
+ deprecated_write_register_bytes (REGISTER_BYTE (ARM_F0_REGNUM), buf,
+ FP_REGISTER_RAW_SIZE);
break;
case ARM_FLOAT_SOFT:
case ARM_FLOAT_SOFT_VFP:
- write_register_bytes (ARM_A1_REGNUM, valbuf, TYPE_LENGTH (type));
+ deprecated_write_register_bytes (ARM_A1_REGNUM, valbuf,
+ TYPE_LENGTH (type));
break;
default:
}
}
else
- write_register_bytes (ARM_A1_REGNUM, valbuf, TYPE_LENGTH (type));
+ deprecated_write_register_bytes (ARM_A1_REGNUM, valbuf,
+ TYPE_LENGTH (type));
}
/* Store the address of the place in which to copy the structure the
}
\f
/* Return the ARM register name corresponding to register I. */
-static char *
+static const char *
arm_register_name (int i)
{
return arm_register_names[i];
}
\f
-static void
-process_note_abi_tag_sections (bfd *abfd, asection *sect, void *obj)
+static enum gdb_osabi
+arm_elf_osabi_sniffer (bfd *abfd)
{
- enum arm_abi *os_ident_ptr = obj;
- const char *name;
- unsigned int sectsize;
+ unsigned int elfosabi, eflags;
+ enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
- name = bfd_get_section_name (abfd, sect);
- sectsize = bfd_section_size (abfd, sect);
+ elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
- if (strcmp (name, ".note.ABI-tag") == 0 && sectsize > 0)
+ switch (elfosabi)
{
- unsigned int name_length, data_length, note_type;
- char *note;
-
- /* If the section is larger than this, it's probably not what we are
- looking for. */
- if (sectsize > 128)
- sectsize = 128;
-
- note = alloca (sectsize);
-
- bfd_get_section_contents (abfd, sect, note,
- (file_ptr) 0, (bfd_size_type) sectsize);
-
- name_length = bfd_h_get_32 (abfd, note);
- data_length = bfd_h_get_32 (abfd, note + 4);
- note_type = bfd_h_get_32 (abfd, note + 8);
-
- if (name_length == 4 && data_length == 16 && note_type == 1
- && strcmp (note + 12, "GNU") == 0)
+ case ELFOSABI_NONE:
+ /* When elfosabi is ELFOSABI_NONE (0), then the ELF structures in the
+ file are conforming to the base specification for that machine
+ (there are no OS-specific extensions). In order to determine the
+ real OS in use we must look for OS notes that have been added. */
+ bfd_map_over_sections (abfd,
+ generic_elf_osabi_sniff_abi_tag_sections,
+ &osabi);
+ if (osabi == GDB_OSABI_UNKNOWN)
{
- int os_number = bfd_h_get_32 (abfd, note + 16);
-
- /* The case numbers are from abi-tags in glibc. */
- switch (os_number)
+ /* Existing ARM tools don't set this field, so look at the EI_FLAGS
+ field for more information. */
+ eflags = EF_ARM_EABI_VERSION(elf_elfheader(abfd)->e_flags);
+ switch (eflags)
{
- case 0 :
- *os_ident_ptr = ARM_ABI_LINUX;
+ case EF_ARM_EABI_VER1:
+ osabi = GDB_OSABI_ARM_EABI_V1;
break;
- case 1 :
- internal_error
- (__FILE__, __LINE__,
- "process_note_abi_sections: Hurd objects not supported");
+ case EF_ARM_EABI_VER2:
+ osabi = GDB_OSABI_ARM_EABI_V2;
break;
- case 2 :
- internal_error
- (__FILE__, __LINE__,
- "process_note_abi_sections: Solaris objects not supported");
+ case EF_ARM_EABI_UNKNOWN:
+ /* Assume GNU tools. */
+ osabi = GDB_OSABI_ARM_APCS;
break;
- default :
- internal_error
- (__FILE__, __LINE__,
- "process_note_abi_sections: unknown OS number %d",
- os_number);
- break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ "arm_elf_osabi_sniffer: Unknown ARM EABI "
+ "version 0x%x", eflags);
}
}
- }
- /* NetBSD uses a similar trick. */
- else if (strcmp (name, ".note.netbsd.ident") == 0 && sectsize > 0)
- {
- unsigned int name_length, desc_length, note_type;
- char *note;
-
- /* If the section is larger than this, it's probably not what we are
- looking for. */
- if (sectsize > 128)
- sectsize = 128;
-
- note = alloca (sectsize);
-
- bfd_get_section_contents (abfd, sect, note,
- (file_ptr) 0, (bfd_size_type) sectsize);
-
- name_length = bfd_h_get_32 (abfd, note);
- desc_length = bfd_h_get_32 (abfd, note + 4);
- note_type = bfd_h_get_32 (abfd, note + 8);
-
- if (name_length == 7 && desc_length == 4 && note_type == 1
- && strcmp (note + 12, "NetBSD") == 0)
- /* XXX Should we check the version here?
- Probably not necessary yet. */
- *os_ident_ptr = ARM_ABI_NETBSD_ELF;
- }
-}
-
-/* Return one of the ELFOSABI_ constants for BFDs representing ELF
- executables. If it's not an ELF executable or if the OS/ABI couldn't
- be determined, simply return -1. */
-
-static int
-get_elfosabi (bfd *abfd)
-{
- int elfosabi;
- enum arm_abi arm_abi = ARM_ABI_UNKNOWN;
-
- elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
-
- /* When elfosabi is 0 (ELFOSABI_NONE), this is supposed to indicate
- that we're on a SYSV system. However, GNU/Linux uses a note section
- to record OS/ABI info, but leaves e_ident[EI_OSABI] zero. So we
- have to check the note sections too.
+ break;
- GNU/ARM tools set the EI_OSABI field to ELFOSABI_ARM, so handle that
- as well. */
- if (elfosabi == 0 || elfosabi == ELFOSABI_ARM)
- {
+ case ELFOSABI_ARM:
+ /* GNU tools use this value. Check note sections in this case,
+ as well. */
bfd_map_over_sections (abfd,
- process_note_abi_tag_sections,
- &arm_abi);
- }
-
- if (arm_abi != ARM_ABI_UNKNOWN)
- return arm_abi;
-
- switch (elfosabi)
- {
- case ELFOSABI_NONE:
- /* Existing ARM Tools don't set this field, so look at the EI_FLAGS
- field for more information. */
-
- switch (EF_ARM_EABI_VERSION(elf_elfheader(abfd)->e_flags))
+ generic_elf_osabi_sniff_abi_tag_sections,
+ &osabi);
+ if (osabi == GDB_OSABI_UNKNOWN)
{
- case EF_ARM_EABI_VER1:
- return ARM_ABI_EABI_V1;
-
- case EF_ARM_EABI_VER2:
- return ARM_ABI_EABI_V2;
-
- case EF_ARM_EABI_UNKNOWN:
- /* Assume GNU tools. */
- return ARM_ABI_APCS;
-
- default:
- internal_error (__FILE__, __LINE__,
- "get_elfosabi: Unknown ARM EABI version 0x%lx",
- EF_ARM_EABI_VERSION(elf_elfheader(abfd)->e_flags));
-
+ /* Assume APCS ABI. */
+ osabi = GDB_OSABI_ARM_APCS;
}
break;
- case ELFOSABI_NETBSD:
- return ARM_ABI_NETBSD_ELF;
-
case ELFOSABI_FREEBSD:
- return ARM_ABI_FREEBSD;
-
- case ELFOSABI_LINUX:
- return ARM_ABI_LINUX;
-
- case ELFOSABI_ARM:
- /* Assume GNU tools with the old APCS abi. */
- return ARM_ABI_APCS;
-
- default:
- }
-
- return ARM_ABI_UNKNOWN;
-}
-
-struct arm_abi_handler
-{
- struct arm_abi_handler *next;
- enum arm_abi abi;
- void (*init_abi)(struct gdbarch_info, struct gdbarch *);
-};
-
-struct arm_abi_handler *arm_abi_handler_list = NULL;
+ osabi = GDB_OSABI_FREEBSD_ELF;
+ break;
-void
-arm_gdbarch_register_os_abi (enum arm_abi abi,
- void (*init_abi)(struct gdbarch_info,
- struct gdbarch *))
-{
- struct arm_abi_handler **handler_p;
+ case ELFOSABI_NETBSD:
+ osabi = GDB_OSABI_NETBSD_ELF;
+ break;
- for (handler_p = &arm_abi_handler_list; *handler_p != NULL;
- handler_p = &(*handler_p)->next)
- {
- if ((*handler_p)->abi == abi)
- {
- internal_error
- (__FILE__, __LINE__,
- "arm_gdbarch_register_os_abi: A handler for this ABI variant (%d)"
- " has already been registered", (int)abi);
- /* If user wants to continue, override previous definition. */
- (*handler_p)->init_abi = init_abi;
- return;
- }
+ case ELFOSABI_LINUX:
+ osabi = GDB_OSABI_LINUX;
+ break;
}
- (*handler_p)
- = (struct arm_abi_handler *) xmalloc (sizeof (struct arm_abi_handler));
- (*handler_p)->next = NULL;
- (*handler_p)->abi = abi;
- (*handler_p)->init_abi = init_abi;
+ return osabi;
}
+\f
/* Initialize the current architecture based on INFO. If possible,
re-use an architecture from ARCHES, which is a list of
architectures already created during this debugging session.
{
struct gdbarch_tdep *tdep;
struct gdbarch *gdbarch;
- enum arm_abi arm_abi = ARM_ABI_UNKNOWN;
- struct arm_abi_handler *abi_handler;
+ enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
/* Try to deterimine the ABI of the object we are loading. */
if (info.abfd != NULL)
{
- switch (bfd_get_flavour (info.abfd))
+ osabi = gdbarch_lookup_osabi (info.abfd);
+ if (osabi == GDB_OSABI_UNKNOWN)
{
- case bfd_target_elf_flavour:
- arm_abi = get_elfosabi (info.abfd);
- break;
-
- case bfd_target_aout_flavour:
- if (strcmp (bfd_get_target(info.abfd), "a.out-arm-netbsd") == 0)
- arm_abi = ARM_ABI_NETBSD_AOUT;
- else
- /* Assume it's an old APCS-style ABI. */
- arm_abi = ARM_ABI_APCS;
- break;
+ switch (bfd_get_flavour (info.abfd))
+ {
+ case bfd_target_aout_flavour:
+ /* Assume it's an old APCS-style ABI. */
+ osabi = GDB_OSABI_ARM_APCS;
+ break;
- case bfd_target_coff_flavour:
- /* Assume it's an old APCS-style ABI. */
- /* XXX WinCE? */
- arm_abi = ARM_ABI_APCS;
- break;
+ case bfd_target_coff_flavour:
+ /* Assume it's an old APCS-style ABI. */
+ /* XXX WinCE? */
+ osabi = GDB_OSABI_ARM_APCS;
+ break;
- default:
- /* Not sure what to do here, leave the ABI as unknown. */
- break;
+ default:
+ /* Leave it as "unknown". */
+ }
}
}
{
/* Make sure the ABI selection matches. */
tdep = gdbarch_tdep (arches->gdbarch);
- if (tdep && tdep->arm_abi == arm_abi)
+ if (tdep && tdep->osabi == osabi)
return arches->gdbarch;
}
tdep = xmalloc (sizeof (struct gdbarch_tdep));
gdbarch = gdbarch_alloc (&info, tdep);
- tdep->arm_abi = arm_abi;
- if (arm_abi < ARM_ABI_INVALID)
- tdep->abi_name = arm_abi_names[arm_abi];
- else
- {
- internal_error (__FILE__, __LINE__, "Invalid setting of arm_abi %d",
- (int) arm_abi);
- tdep->abi_name = "<invalid>";
- }
+ tdep->osabi = osabi;
/* This is the way it has always defaulted. */
tdep->fp_model = ARM_FLOAT_FPA;
tdep->lowest_pc = 0x20;
tdep->jb_pc = -1; /* Longjump support not enabled by default. */
+#if OLD_STYLE_ARM_DUMMY_FRAMES
+ /* NOTE: cagney/2002-05-07: Enable the below to restore the old ARM
+ specific (non-generic) dummy frame code. Might be useful if
+ there appears to be a problem with the generic dummy frame
+ mechanism that replaced it. */
set_gdbarch_use_generic_dummy_frames (gdbarch, 0);
/* Call dummy code. */
set_gdbarch_fix_call_dummy (gdbarch, arm_fix_call_dummy);
set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_on_stack);
+#else
+ set_gdbarch_use_generic_dummy_frames (gdbarch, 1);
+ set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
+
+ set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
+ set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0);
- set_gdbarch_get_saved_register (gdbarch, generic_get_saved_register);
+ set_gdbarch_call_dummy_p (gdbarch, 1);
+ set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
+
+ set_gdbarch_call_dummy_words (gdbarch, arm_call_dummy_words);
+ set_gdbarch_sizeof_call_dummy_words (gdbarch, 0);
+ set_gdbarch_call_dummy_start_offset (gdbarch, 0);
+ set_gdbarch_call_dummy_length (gdbarch, 0);
+
+ set_gdbarch_fix_call_dummy (gdbarch, generic_fix_call_dummy);
+ set_gdbarch_pc_in_call_dummy (gdbarch, generic_pc_in_call_dummy);
+
+ set_gdbarch_call_dummy_address (gdbarch, entry_point_address);
+ set_gdbarch_push_return_address (gdbarch, arm_push_return_address);
+#endif
+
+ set_gdbarch_get_saved_register (gdbarch, deprecated_generic_get_saved_register);
set_gdbarch_push_arguments (gdbarch, arm_push_arguments);
set_gdbarch_coerce_float_to_double (gdbarch,
standard_coerce_float_to_double);
set_gdbarch_frame_num_args (gdbarch, arm_frame_num_args);
set_gdbarch_frame_args_skip (gdbarch, 0);
set_gdbarch_frame_init_saved_regs (gdbarch, arm_frame_init_saved_regs);
+#if OLD_STYLE_ARM_DUMMY_FRAMES
+ /* NOTE: cagney/2002-05-07: Enable the below to restore the old ARM
+ specific (non-generic) dummy frame code. Might be useful if
+ there appears to be a problem with the generic dummy frame
+ mechanism that replaced it. */
set_gdbarch_push_dummy_frame (gdbarch, arm_push_dummy_frame);
+#else
+ set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame);
+#endif
set_gdbarch_pop_frame (gdbarch, arm_pop_frame);
/* Address manipulation. */
set_gdbarch_max_register_virtual_size (gdbarch, FP_REGISTER_VIRTUAL_SIZE);
set_gdbarch_register_virtual_type (gdbarch, arm_register_type);
+ /* Internal <-> external register number maps. */
+ set_gdbarch_register_sim_regno (gdbarch, arm_register_sim_regno);
+
/* Integer registers are 4 bytes. */
set_gdbarch_register_size (gdbarch, 4);
set_gdbarch_register_name (gdbarch, arm_register_name);
/* Returning results. */
- set_gdbarch_extract_return_value (gdbarch, arm_extract_return_value);
- set_gdbarch_store_return_value (gdbarch, arm_store_return_value);
+ set_gdbarch_deprecated_extract_return_value (gdbarch, arm_extract_return_value);
+ set_gdbarch_deprecated_store_return_value (gdbarch, arm_store_return_value);
set_gdbarch_store_struct_return (gdbarch, arm_store_struct_return);
set_gdbarch_use_struct_convention (gdbarch, arm_use_struct_convention);
set_gdbarch_extract_struct_value_address (gdbarch,
arm_coff_make_msymbol_special);
/* Hook in the ABI-specific overrides, if they have been registered. */
- if (arm_abi == ARM_ABI_UNKNOWN)
- {
- /* Don't complain about not knowing the ABI variant if we don't
- have an inferior. */
- if (info.abfd)
- fprintf_filtered
- (gdb_stderr, "GDB doesn't recognize the ABI of the inferior. "
- "Attempting to continue with the default ARM settings");
- }
- else
- {
- for (abi_handler = arm_abi_handler_list; abi_handler != NULL;
- abi_handler = abi_handler->next)
- if (abi_handler->abi == arm_abi)
- break;
-
- if (abi_handler)
- abi_handler->init_abi (info, gdbarch);
- else
- {
- /* We assume that if GDB_MULTI_ARCH is less than
- GDB_MULTI_ARCH_TM that an ABI variant can be supported by
- overriding definitions in this file. */
- if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL)
- fprintf_filtered
- (gdb_stderr,
- "A handler for the ABI variant \"%s\" is not built into this "
- "configuration of GDB. "
- "Attempting to continue with the default ARM settings",
- arm_abi_names[arm_abi]);
- }
- }
+ gdbarch_init_osabi (info, gdbarch, osabi);
/* Now we have tuned the configuration, set a few final things,
based on what the OS ABI has told us. */
if (tdep == NULL)
return;
- if (tdep->abi_name != NULL)
- fprintf_unfiltered (file, "arm_dump_tdep: ABI = %s\n", tdep->abi_name);
- else
- internal_error (__FILE__, __LINE__,
- "arm_dump_tdep: illegal setting of tdep->arm_abi (%d)",
- (int) tdep->arm_abi);
+ fprintf_unfiltered (file, "arm_dump_tdep: OS ABI = %s\n",
+ gdbarch_osabi_name (tdep->osabi));
fprintf_unfiltered (file, "arm_dump_tdep: Lowest pc = 0x%lx",
(unsigned long) tdep->lowest_pc);
if (GDB_MULTI_ARCH)
gdbarch_register (bfd_arch_arm, arm_gdbarch_init, arm_dump_tdep);
+ /* Register an ELF OS ABI sniffer for ARM binaries. */
+ gdbarch_register_osabi_sniffer (bfd_arch_arm,
+ bfd_target_elf_flavour,
+ arm_elf_osabi_sniffer);
+
/* Register some ABI variants for embedded systems. */
- arm_gdbarch_register_os_abi (ARM_ABI_EABI_V1, arm_init_abi_eabi_v1);
- arm_gdbarch_register_os_abi (ARM_ABI_EABI_V2, arm_init_abi_eabi_v2);
- arm_gdbarch_register_os_abi (ARM_ABI_APCS, arm_init_abi_apcs);
+ gdbarch_register_osabi (bfd_arch_arm, GDB_OSABI_ARM_EABI_V1,
+ arm_init_abi_eabi_v1);
+ gdbarch_register_osabi (bfd_arch_arm, GDB_OSABI_ARM_EABI_V2,
+ arm_init_abi_eabi_v2);
+ gdbarch_register_osabi (bfd_arch_arm, GDB_OSABI_ARM_APCS,
+ arm_init_abi_apcs);
tm_print_insn = gdb_print_insn_arm;
prologue_cache.saved_regs = NULL;
prologue_cache.extra_info = (struct frame_extra_info *)
xcalloc (1, sizeof (struct frame_extra_info));
+
+ /* Debugging flag. */
+ add_show_from_set (add_set_cmd ("arm", class_maintenance, var_zinteger,
+ &arm_debug, "Set arm debugging.\n\
+When non-zero, arm specific debugging is enabled.", &setdebuglist),
+ &showdebuglist);
}