/* Common target dependent code for GDB on ARM systems.
- Copyright 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+ Copyright (C) 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1998, 1999, 2000,
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GDB.
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., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#include <ctype.h> /* XXX for isupper () */
#include "frame-unwind.h"
#include "frame-base.h"
#include "trad-frame.h"
+#include "objfiles.h"
+#include "dwarf2-frame.h"
+#include "gdbtypes.h"
+#include "prologue-value.h"
+#include "target-descriptions.h"
+#include "user-regs.h"
#include "arm-tdep.h"
#include "gdb/sim-arm.h"
static int arm_debug;
-/* Each OS has a different mechanism for accessing the various
- registers stored in the sigcontext structure.
-
- SIGCONTEXT_REGISTER_ADDRESS should be defined to the name (or
- function pointer) which may be used to determine the addresses
- of the various saved registers in the sigcontext structure.
-
- For the ARM target, there are three parameters to this function.
- The first is the pc value of the frame under consideration, the
- second the stack pointer of this frame, and the last is the
- register number to fetch.
-
- If the tm.h file does not define this macro, then it's assumed that
- no mechanism is needed and we define SIGCONTEXT_REGISTER_ADDRESS to
- be 0.
-
- When it comes time to multi-arching this code, see the identically
- named machinery in ia64-tdep.c for an example of how it could be
- done. It should not be necessary to modify the code below where
- this macro is used. */
-
-#ifdef SIGCONTEXT_REGISTER_ADDRESS
-#ifndef SIGCONTEXT_REGISTER_ADDRESS_P
-#define SIGCONTEXT_REGISTER_ADDRESS_P() 1
-#endif
-#else
-#define SIGCONTEXT_REGISTER_ADDRESS(SP,PC,REG) 0
-#define SIGCONTEXT_REGISTER_ADDRESS_P() 0
-#endif
-
/* Macros for setting and testing a bit in a minimal symbol that marks
it as Thumb function. The MSB of the minimal symbol's "info" field
is used for this purpose.
"softfpa",
"fpa",
"softvfp",
- "vfp"
+ "vfp",
+ NULL
};
/* A variable that can be configured by the user. */
static enum arm_float_model arm_fp_model = ARM_FLOAT_AUTO;
static const char *current_fp_model = "auto";
+/* The ABI to use. Keep this in sync with arm_abi_kind. */
+static const char *arm_abi_strings[] =
+{
+ "auto",
+ "APCS",
+ "AAPCS",
+ NULL
+};
+
+/* A variable that can be configured by the user. */
+static enum arm_abi_kind arm_abi_global = ARM_ABI_AUTO;
+static const char *arm_abi_string = "auto";
+
/* Number of different reg name sets (options). */
static int num_disassembly_options;
-/* We have more registers than the disassembler as gdb can print the value
- of special registers as well.
- The general register names are overwritten by whatever is being used by
- the disassembler at the moment. We also adjust the case of cpsr and fps. */
+/* The standard register names, and all the valid aliases for them. */
+static const struct
+{
+ const char *name;
+ int regnum;
+} arm_register_aliases[] = {
+ /* Basic register numbers. */
+ { "r0", 0 },
+ { "r1", 1 },
+ { "r2", 2 },
+ { "r3", 3 },
+ { "r4", 4 },
+ { "r5", 5 },
+ { "r6", 6 },
+ { "r7", 7 },
+ { "r8", 8 },
+ { "r9", 9 },
+ { "r10", 10 },
+ { "r11", 11 },
+ { "r12", 12 },
+ { "r13", 13 },
+ { "r14", 14 },
+ { "r15", 15 },
+ /* Synonyms (argument and variable registers). */
+ { "a1", 0 },
+ { "a2", 1 },
+ { "a3", 2 },
+ { "a4", 3 },
+ { "v1", 4 },
+ { "v2", 5 },
+ { "v3", 6 },
+ { "v4", 7 },
+ { "v5", 8 },
+ { "v6", 9 },
+ { "v7", 10 },
+ { "v8", 11 },
+ /* Other platform-specific names for r9. */
+ { "sb", 9 },
+ { "tr", 9 },
+ /* Special names. */
+ { "ip", 12 },
+ { "sp", 13 },
+ { "lr", 14 },
+ { "pc", 15 },
+ /* Names used by GCC (not listed in the ARM EABI). */
+ { "sl", 10 },
+ { "fp", 11 },
+ /* A special name from the older ATPCS. */
+ { "wr", 7 },
+};
-/* Initial value: Register names used in ARM's ISA documentation. */
-static char * arm_register_name_strings[] =
+static const char *const arm_register_names[] =
{"r0", "r1", "r2", "r3", /* 0 1 2 3 */
"r4", "r5", "r6", "r7", /* 4 5 6 7 */
"r8", "r9", "r10", "r11", /* 8 9 10 11 */
"f0", "f1", "f2", "f3", /* 16 17 18 19 */
"f4", "f5", "f6", "f7", /* 20 21 22 23 */
"fps", "cpsr" }; /* 24 25 */
-static char **arm_register_names = arm_register_name_strings;
/* Valid register name styles. */
static const char **valid_disassembly_styles;
/* Disassembly style to use. Default to "std" register names. */
static const char *disassembly_style;
-/* Index to that option in the opcodes table. */
-static int current_option;
/* This is used to keep the bfd arch_info in sync with the disassembly
style. */
int arm_apcs_32 = 1;
-/* Flag set by arm_fix_call_dummy that tells whether the target
- function is a Thumb function. This flag is checked by
- arm_push_arguments. FIXME: Change the PUSH_ARGUMENTS macro (and
- its use in valops.c) to pass the function address as an additional
- parameter. */
-
-static int target_is_thumb;
-
-/* Flag set by arm_fix_call_dummy that tells whether the calling
- function is a Thumb function. This flag is checked by
- arm_pc_is_thumb and arm_call_dummy_breakpoint_offset. */
-
-static int caller_is_thumb;
-
/* Determine if the program counter specified in MEMADDR is in a Thumb
function. */
}
}
-/* Determine if the program counter specified in MEMADDR is in a call
- dummy being called from a Thumb function. */
-
-int
-arm_pc_is_thumb_dummy (CORE_ADDR memaddr)
-{
- CORE_ADDR sp = read_sp ();
-
- /* FIXME: Until we switch for the new call dummy macros, this heuristic
- is the best we can do. We are trying to determine if the pc is on
- the stack, which (hopefully) will only happen in a call dummy.
- We hope the current stack pointer is not so far alway from the dummy
- frame location (true if we have not pushed large data structures or
- gone too many levels deep) and that our 1024 is not enough to consider
- code regions as part of the stack (true for most practical purposes). */
- if (DEPRECATED_PC_IN_CALL_DUMMY (memaddr, sp, sp + 1024))
- return caller_is_thumb;
- else
- return 0;
-}
-
/* Remove useless bits from addresses in a running program. */
static CORE_ADDR
arm_addr_bits_remove (CORE_ADDR val)
return val & ~1;
}
-/* Immediately after a function call, return the saved pc. Can't
- always go through the frames for this because on some machines the
- new frame is not set up until the new function executes some
- instructions. */
+/* Analyze a Thumb prologue, looking for a recognizable stack frame
+ and frame pointer. Scan until we encounter a store that could
+ clobber the stack frame unexpectedly, or an unknown instruction. */
static CORE_ADDR
-arm_saved_pc_after_call (struct frame_info *frame)
+thumb_analyze_prologue (struct gdbarch *gdbarch,
+ CORE_ADDR start, CORE_ADDR limit,
+ struct arm_prologue_cache *cache)
{
- return ADDR_BITS_REMOVE (read_register (ARM_LR_REGNUM));
-}
-
-/* Determine whether the function invocation represented by FI has a
- frame on the stack associated with it. If it does return zero,
- otherwise return 1. */
-
-static int
-arm_frameless_function_invocation (struct frame_info *fi)
-{
- CORE_ADDR func_start, after_prologue;
- int frameless;
-
- /* Sometimes we have functions that do a little setup (like saving the
- vN registers with the stmdb instruction, but DO NOT set up a frame.
- The symbol table will report this as a prologue. However, it is
- important not to try to parse these partial frames as frames, or we
- will get really confused.
-
- So I will demand 3 instructions between the start & end of the
- prologue before I call it a real prologue, i.e. at least
- mov ip, sp,
- stmdb sp!, {}
- sub sp, ip, #4. */
+ int i;
+ pv_t regs[16];
+ struct pv_area *stack;
+ struct cleanup *back_to;
+ CORE_ADDR offset;
- func_start = (get_frame_func (fi) + FUNCTION_START_OFFSET);
- after_prologue = SKIP_PROLOGUE (func_start);
+ for (i = 0; i < 16; i++)
+ regs[i] = pv_register (i, 0);
+ stack = make_pv_area (ARM_SP_REGNUM);
+ back_to = make_cleanup_free_pv_area (stack);
+
+ /* The call instruction saved PC in LR, and the current PC is not
+ interesting. Due to this file's conventions, we want the value
+ of LR at this function's entry, not at the call site, so we do
+ not record the save of the PC - when the ARM prologue analyzer
+ has also been converted to the pv mechanism, we could record the
+ save here and remove the hack in prev_register. */
+ regs[ARM_PC_REGNUM] = pv_unknown ();
+
+ while (start < limit)
+ {
+ unsigned short insn;
- /* There are some frameless functions whose first two instructions
- follow the standard APCS form, in which case after_prologue will
- be func_start + 8. */
+ insn = read_memory_unsigned_integer (start, 2);
- frameless = (after_prologue < func_start + 12);
- return frameless;
-}
+ if ((insn & 0xfe00) == 0xb400) /* push { rlist } */
+ {
+ int regno;
+ int mask;
+ int stop = 0;
-/* A typical Thumb prologue looks like this:
- push {r7, lr}
- add sp, sp, #-28
- add r7, sp, #12
- Sometimes the latter instruction may be replaced by:
- mov r7, sp
-
- or like this:
- push {r7, lr}
- mov r7, sp
- sub sp, #12
-
- or, on tpcs, like this:
- sub sp,#16
- push {r7, lr}
- (many instructions)
- mov r7, sp
- sub sp, #12
-
- There is always one instruction of three classes:
- 1 - push
- 2 - setting of r7
- 3 - adjusting of sp
-
- When we have found at least one of each class we are done with the prolog.
- Note that the "sub sp, #NN" before the push does not count.
- */
+ /* Bits 0-7 contain a mask for registers R0-R7. Bit 8 says
+ whether to save LR (R14). */
+ mask = (insn & 0xff) | ((insn & 0x100) << 6);
-static CORE_ADDR
-thumb_skip_prologue (CORE_ADDR pc, CORE_ADDR func_end)
-{
- CORE_ADDR current_pc;
- /* findmask:
- bit 0 - push { rlist }
- bit 1 - mov r7, sp OR add r7, sp, #imm (setting of r7)
- bit 2 - sub sp, #simm OR add sp, #simm (adjusting of sp)
- */
- int findmask = 0;
+ /* Calculate offsets of saved R0-R7 and LR. */
+ for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
+ if (mask & (1 << regno))
+ {
+ if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
+ {
+ stop = 1;
+ break;
+ }
- for (current_pc = pc;
- current_pc + 2 < func_end && current_pc < pc + 40;
- current_pc += 2)
- {
- unsigned short insn = read_memory_unsigned_integer (current_pc, 2);
+ regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
+ -4);
+ pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]);
+ }
- if ((insn & 0xfe00) == 0xb400) /* push { rlist } */
- {
- findmask |= 1; /* push found */
+ if (stop)
+ break;
}
else if ((insn & 0xff00) == 0xb000) /* add sp, #simm OR
sub sp, #simm */
{
- if ((findmask & 1) == 0) /* before push ? */
- continue;
+ offset = (insn & 0x7f) << 2; /* get scaled offset */
+ if (insn & 0x80) /* Check for SUB. */
+ regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
+ -offset);
else
- findmask |= 4; /* add/sub sp found */
+ regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
+ offset);
}
else if ((insn & 0xff00) == 0xaf00) /* add r7, sp, #imm */
+ regs[THUMB_FP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
+ (insn & 0xff) << 2);
+ else if ((insn & 0xff00) == 0x4600) /* mov hi, lo or mov lo, hi */
{
- findmask |= 2; /* setting of r7 found */
+ int dst_reg = (insn & 0x7) + ((insn & 0x80) >> 4);
+ int src_reg = (insn & 0x78) >> 3;
+ regs[dst_reg] = regs[src_reg];
}
- else if (insn == 0x466f) /* mov r7, sp */
+ else if ((insn & 0xf800) == 0x9000) /* str rd, [sp, #off] */
{
- findmask |= 2; /* setting of r7 found */
+ /* Handle stores to the stack. Normally pushes are used,
+ but with GCC -mtpcs-frame, there may be other stores
+ in the prologue to create the frame. */
+ int regno = (insn >> 8) & 0x7;
+ pv_t addr;
+
+ offset = (insn & 0xff) << 2;
+ addr = pv_add_constant (regs[ARM_SP_REGNUM], offset);
+
+ if (pv_area_store_would_trash (stack, addr))
+ break;
+
+ pv_area_store (stack, addr, 4, regs[regno]);
}
- else if (findmask == (4+2+1))
+ else
{
- /* We have found one of each type of prologue instruction */
+ /* We don't know what this instruction is. We're finished
+ scanning. NOTE: Recognizing more safe-to-ignore
+ instructions here will improve support for optimized
+ code. */
break;
}
- else
- /* Something in the prolog that we don't care about or some
- instruction from outside the prolog scheduled here for
- optimization. */
- continue;
+
+ start += 2;
+ }
+
+ if (cache == NULL)
+ {
+ do_cleanups (back_to);
+ return start;
+ }
+
+ /* frameoffset is unused for this unwinder. */
+ cache->frameoffset = 0;
+
+ if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM))
+ {
+ /* Frame pointer is fp. Frame size is constant. */
+ cache->framereg = ARM_FP_REGNUM;
+ cache->framesize = -regs[ARM_FP_REGNUM].k;
+ }
+ else if (pv_is_register (regs[THUMB_FP_REGNUM], ARM_SP_REGNUM))
+ {
+ /* Frame pointer is r7. Frame size is constant. */
+ cache->framereg = THUMB_FP_REGNUM;
+ cache->framesize = -regs[THUMB_FP_REGNUM].k;
}
+ else if (pv_is_register (regs[ARM_SP_REGNUM], ARM_SP_REGNUM))
+ {
+ /* Try the stack pointer... this is a bit desperate. */
+ cache->framereg = ARM_SP_REGNUM;
+ cache->framesize = -regs[ARM_SP_REGNUM].k;
+ }
+ else
+ {
+ /* We're just out of luck. We don't know where the frame is. */
+ cache->framereg = -1;
+ cache->framesize = 0;
+ }
+
+ for (i = 0; i < 16; i++)
+ if (pv_area_find_reg (stack, gdbarch, i, &offset))
+ cache->saved_regs[i].addr = offset;
- return current_pc;
+ do_cleanups (back_to);
+ return start;
}
/* Advance the PC across any function entry prologue instructions to
struct symtab_and_line sal;
/* If we're in a dummy frame, don't even try to skip the prologue. */
- if (DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0))
+ if (deprecated_pc_in_call_dummy (pc))
return pc;
/* See what the symbol table says. */
}
}
- /* Check if this is Thumb code. */
- if (arm_pc_is_thumb (pc))
- return thumb_skip_prologue (pc, func_end);
-
/* Can't find the prologue end in the symbol table, try it the hard way
by disassembling the instructions. */
if (func_end == 0 || func_end > pc + 64)
func_end = pc + 64;
+ /* Check if this is Thumb code. */
+ if (arm_pc_is_thumb (pc))
+ return thumb_analyze_prologue (current_gdbarch, pc, func_end, NULL);
+
for (skip_pc = pc; skip_pc < func_end; skip_pc += 4)
{
- inst = read_memory_integer (skip_pc, 4);
+ inst = read_memory_unsigned_integer (skip_pc, 4);
/* "mov ip, sp" is no longer a required part of the prologue. */
if (inst == 0xe1a0c00d) /* mov ip, sp */
prologue_end = sal.end; /* (probably means no prologue) */
}
else
- /* We're in the boondocks: allow for
- 16 pushes, an add, and "mv fp,sp". */
- prologue_end = prologue_start + 40;
+ /* We're in the boondocks: we have no idea where the start of the
+ function is. */
+ return;
prologue_end = min (prologue_end, prev_pc);
- /* Initialize the saved register map. When register H is copied to
- register L, we will put H in saved_reg[L]. */
- for (i = 0; i < 16; i++)
- saved_reg[i] = i;
-
- /* Search the prologue looking for instructions that set up the
- frame pointer, adjust the stack pointer, and save registers.
- Do this until all basic prolog instructions are found. */
-
- cache->framesize = 0;
- for (current_pc = prologue_start;
- (current_pc < prologue_end) && ((findmask & 7) != 7);
- current_pc += 2)
- {
- unsigned short insn;
- int regno;
- int offset;
-
- insn = read_memory_unsigned_integer (current_pc, 2);
-
- if ((insn & 0xfe00) == 0xb400) /* push { rlist } */
- {
- int mask;
- findmask |= 1; /* push found */
- /* Bits 0-7 contain a mask for registers R0-R7. Bit 8 says
- whether to save LR (R14). */
- mask = (insn & 0xff) | ((insn & 0x100) << 6);
-
- /* Calculate offsets of saved R0-R7 and LR. */
- for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
- if (mask & (1 << regno))
- {
- cache->framesize += 4;
- cache->saved_regs[saved_reg[regno]].addr = -cache->framesize;
- /* Reset saved register map. */
- saved_reg[regno] = regno;
- }
- }
- else if ((insn & 0xff00) == 0xb000) /* add sp, #simm OR
- sub sp, #simm */
- {
- if ((findmask & 1) == 0) /* before push? */
- continue;
- else
- findmask |= 4; /* add/sub sp found */
-
- offset = (insn & 0x7f) << 2; /* get scaled offset */
- if (insn & 0x80) /* is it signed? (==subtracting) */
- {
- cache->frameoffset += offset;
- offset = -offset;
- }
- cache->framesize -= offset;
- }
- else if ((insn & 0xff00) == 0xaf00) /* add r7, sp, #imm */
- {
- findmask |= 2; /* setting of r7 found */
- cache->framereg = THUMB_FP_REGNUM;
- /* get scaled offset */
- cache->frameoffset = (insn & 0xff) << 2;
- }
- else if (insn == 0x466f) /* mov r7, sp */
- {
- findmask |= 2; /* setting of r7 found */
- cache->framereg = THUMB_FP_REGNUM;
- cache->frameoffset = 0;
- saved_reg[THUMB_FP_REGNUM] = ARM_SP_REGNUM;
- }
- else if ((insn & 0xffc0) == 0x4640) /* mov r0-r7, r8-r15 */
- {
- int lo_reg = insn & 7; /* dest. register (r0-r7) */
- int hi_reg = ((insn >> 3) & 7) + 8; /* source register (r8-15) */
- saved_reg[lo_reg] = hi_reg; /* remember hi reg was saved */
- }
- else
- /* Something in the prolog that we don't care about or some
- instruction from outside the prolog scheduled here for
- optimization. */
- continue;
- }
+ thumb_analyze_prologue (current_gdbarch, prologue_start, prologue_end,
+ cache);
}
/* This function decodes an ARM function prologue to determine:
imm = (imm >> rot) | (imm << (32 - rot));
sp_offset -= imm;
}
- else if ((insn & 0xffff7fff) == 0xed6d0103) /* stfe f?, [sp, -#c]! */
+ else if ((insn & 0xffff7fff) == 0xed6d0103 /* stfe f?, [sp, -#c]! */
+ && gdbarch_tdep (current_gdbarch)->have_fpa_registers)
{
sp_offset -= 12;
regno = ARM_F0_REGNUM + ((insn >> 12) & 0x07);
cache->saved_regs[regno].addr = sp_offset;
}
- else if ((insn & 0xffbf0fff) == 0xec2d0200) /* sfmfd f0, 4, [sp!] */
+ else if ((insn & 0xffbf0fff) == 0xec2d0200 /* sfmfd f0, 4, [sp!] */
+ && gdbarch_tdep (current_gdbarch)->have_fpa_registers)
{
int n_saved_fp_regs;
unsigned int fp_start_reg, fp_bound_reg;
struct arm_prologue_cache *cache;
CORE_ADDR unwound_fp;
- cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache));
+ cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
arm_scan_prologue (next_frame, cache);
*this_cache = arm_make_prologue_cache (next_frame);
cache = *this_cache;
- func = frame_func_unwind (next_frame);
+ func = frame_func_unwind (next_frame, NORMAL_FRAME);
/* This is meant to halt the backtrace at "_start". Make sure we
don't halt it at a generic dummy frame. */
return;
id = frame_id_build (cache->prev_sp, func);
-
- /* Check that we're not going round in circles with the same frame
- ID (but avoid applying the test to sentinel frames which do go
- round in circles). */
- if (frame_relative_level (next_frame) >= 0
- && get_frame_type (next_frame) == NORMAL_FRAME
- && frame_id_eq (get_frame_id (next_frame), id))
- return;
-
*this_id = id;
}
enum lval_type *lvalp,
CORE_ADDR *addrp,
int *realnump,
- void *valuep)
+ gdb_byte *valuep)
{
struct arm_prologue_cache *cache;
return;
}
- trad_frame_prev_register (next_frame, cache->saved_regs, prev_regnum,
- optimized, lvalp, addrp, realnump, valuep);
+ trad_frame_get_prev_register (next_frame, cache->saved_regs, prev_regnum,
+ optimized, lvalp, addrp, realnump, valuep);
}
struct frame_unwind arm_prologue_unwind = {
return &arm_prologue_unwind;
}
-static CORE_ADDR
-arm_normal_frame_base (struct frame_info *next_frame, void **this_cache)
-{
- struct arm_prologue_cache *cache;
-
- if (*this_cache == NULL)
- *this_cache = arm_make_prologue_cache (next_frame);
- cache = *this_cache;
-
- return cache->prev_sp + cache->frameoffset - cache->framesize;
-}
-
-struct frame_base arm_normal_base = {
- &arm_prologue_unwind,
- arm_normal_frame_base,
- arm_normal_frame_base,
- arm_normal_frame_base
-};
-
static struct arm_prologue_cache *
-arm_make_sigtramp_cache (struct frame_info *next_frame)
+arm_make_stub_cache (struct frame_info *next_frame)
{
- struct arm_prologue_cache *cache;
int reg;
+ struct arm_prologue_cache *cache;
+ CORE_ADDR unwound_fp;
- cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache));
-
- cache->prev_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
-
+ cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
- for (reg = 0; reg < NUM_REGS; reg++)
- cache->saved_regs[reg].addr
- = SIGCONTEXT_REGISTER_ADDRESS (cache->prev_sp,
- frame_pc_unwind (next_frame), reg);
-
- /* FIXME: What about thumb mode? */
- cache->framereg = ARM_SP_REGNUM;
- cache->prev_sp
- = read_memory_integer (cache->saved_regs[cache->framereg].addr,
- register_size (current_gdbarch, cache->framereg));
+ cache->prev_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
return cache;
}
-static void
-arm_sigtramp_this_id (struct frame_info *next_frame,
- void **this_cache,
- struct frame_id *this_id)
-{
- struct arm_prologue_cache *cache;
-
- if (*this_cache == NULL)
- *this_cache = arm_make_sigtramp_cache (next_frame);
- cache = *this_cache;
-
- /* FIXME drow/2003-07-07: This isn't right if we single-step within
- the sigtramp frame; the PC should be the beginning of the trampoline. */
- *this_id = frame_id_build (cache->prev_sp, frame_pc_unwind (next_frame));
-}
+/* Our frame ID for a stub frame is the current SP and LR. */
static void
-arm_sigtramp_prev_register (struct frame_info *next_frame,
- void **this_cache,
- int prev_regnum,
- int *optimized,
- enum lval_type *lvalp,
- CORE_ADDR *addrp,
- int *realnump,
- void *valuep)
+arm_stub_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
{
struct arm_prologue_cache *cache;
if (*this_cache == NULL)
- *this_cache = arm_make_sigtramp_cache (next_frame);
+ *this_cache = arm_make_stub_cache (next_frame);
cache = *this_cache;
- trad_frame_prev_register (next_frame, cache->saved_regs, prev_regnum,
- optimized, lvalp, addrp, realnump, valuep);
+ *this_id = frame_id_build (cache->prev_sp,
+ frame_pc_unwind (next_frame));
}
-struct frame_unwind arm_sigtramp_unwind = {
- SIGTRAMP_FRAME,
- arm_sigtramp_this_id,
- arm_sigtramp_prev_register
+struct frame_unwind arm_stub_unwind = {
+ NORMAL_FRAME,
+ arm_stub_this_id,
+ arm_prologue_prev_register
};
static const struct frame_unwind *
-arm_sigtramp_unwind_sniffer (struct frame_info *next_frame)
+arm_stub_unwind_sniffer (struct frame_info *next_frame)
{
- /* Note: If an ARM DEPRECATED_PC_IN_SIGTRAMP method ever needs to
- compare against the name of the function, the code below will
- have to be changed to first fetch the name of the function and
- then pass this name to DEPRECATED_PC_IN_SIGTRAMP. */
+ CORE_ADDR addr_in_block;
+ char dummy[4];
- if (SIGCONTEXT_REGISTER_ADDRESS_P ()
- && DEPRECATED_PC_IN_SIGTRAMP (frame_pc_unwind (next_frame), (char *) 0))
- return &arm_sigtramp_unwind;
+ addr_in_block = frame_unwind_address_in_block (next_frame, NORMAL_FRAME);
+ if (in_plt_section (addr_in_block, NULL)
+ || target_read_memory (frame_pc_unwind (next_frame), dummy, 4) != 0)
+ return &arm_stub_unwind;
return NULL;
}
+static CORE_ADDR
+arm_normal_frame_base (struct frame_info *next_frame, void **this_cache)
+{
+ struct arm_prologue_cache *cache;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_make_prologue_cache (next_frame);
+ cache = *this_cache;
+
+ return cache->prev_sp + cache->frameoffset - cache->framesize;
+}
+
+struct frame_base arm_normal_base = {
+ &arm_prologue_unwind,
+ arm_normal_frame_base,
+ arm_normal_frame_base,
+ arm_normal_frame_base
+};
+
/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
dummy frame. The frame ID's base needs to match the TOS value
saved by save_dummy_frame_tos() and returned from
{
CORE_ADDR pc;
pc = frame_unwind_register_unsigned (this_frame, ARM_PC_REGNUM);
- return IS_THUMB_ADDR (pc) ? UNMAKE_THUMB_ADDR (pc) : pc;
+ return arm_addr_bits_remove (pc);
}
static CORE_ADDR
return frame_unwind_register_unsigned (this_frame, ARM_SP_REGNUM);
}
-/* DEPRECATED_CALL_DUMMY_WORDS:
- This sequence of words is the instructions
-
- mov lr,pc
- mov pc,r4
- illegal
-
- Note this is 12 bytes. */
-
-static LONGEST arm_call_dummy_words[] =
-{
- 0xe1a0e00f, 0xe1a0f004, 0xe7ffdefe
-};
-
/* When arguments must be pushed onto the stack, they go on in reverse
order. The code below implements a FILO (stack) to do this. */
return si;
}
+
+/* Return the alignment (in bytes) of the given type. */
+
+static int
+arm_type_align (struct type *t)
+{
+ int n;
+ int align;
+ int falign;
+
+ t = check_typedef (t);
+ switch (TYPE_CODE (t))
+ {
+ default:
+ /* Should never happen. */
+ internal_error (__FILE__, __LINE__, _("unknown type alignment"));
+ return 4;
+
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_INT:
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_SET:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_BITSTRING:
+ case TYPE_CODE_REF:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_BOOL:
+ return TYPE_LENGTH (t);
+
+ case TYPE_CODE_ARRAY:
+ case TYPE_CODE_COMPLEX:
+ /* TODO: What about vector types? */
+ return arm_type_align (TYPE_TARGET_TYPE (t));
+
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ align = 1;
+ for (n = 0; n < TYPE_NFIELDS (t); n++)
+ {
+ falign = arm_type_align (TYPE_FIELD_TYPE (t, n));
+ if (falign > align)
+ align = falign;
+ }
+ return align;
+ }
+}
+
/* We currently only support passing parameters in integer registers. This
conforms with GCC's default model. Several other variants exist and
we should probably support some of them based on the selected ABI. */
static CORE_ADDR
-arm_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
struct value **args, CORE_ADDR sp, int struct_return,
CORE_ADDR struct_addr)
argreg = ARM_A1_REGNUM;
nstack = 0;
- /* Some platforms require a double-word aligned stack. Make sure sp
- is correctly aligned before we start. We always do this even if
- it isn't really needed -- it can never hurt things. */
- sp &= ~(CORE_ADDR)(2 * DEPRECATED_REGISTER_SIZE - 1);
-
/* The struct_return pointer occupies the first parameter
passing register. */
if (struct_return)
struct type *arg_type;
struct type *target_type;
enum type_code typecode;
- char *val;
+ bfd_byte *val;
+ int align;
- arg_type = check_typedef (VALUE_TYPE (args[argnum]));
+ 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]);
+ val = value_contents_writeable (args[argnum]);
+
+ align = arm_type_align (arg_type);
+ /* Round alignment up to a whole number of words. */
+ align = (align + INT_REGISTER_SIZE - 1) & ~(INT_REGISTER_SIZE - 1);
+ /* Different ABIs have different maximum alignments. */
+ if (gdbarch_tdep (gdbarch)->arm_abi == ARM_ABI_APCS)
+ {
+ /* The APCS ABI only requires word alignment. */
+ align = INT_REGISTER_SIZE;
+ }
+ else
+ {
+ /* The AAPCS requires at most doubleword alignment. */
+ if (align > INT_REGISTER_SIZE * 2)
+ align = INT_REGISTER_SIZE * 2;
+ }
+
+ /* Push stack padding for dowubleword alignment. */
+ if (nstack & (align - 1))
+ {
+ si = push_stack_item (si, val, INT_REGISTER_SIZE);
+ nstack += INT_REGISTER_SIZE;
+ }
+
+ /* Doubleword aligned quantities must go in even register pairs. */
+ if (argreg <= ARM_LAST_ARG_REGNUM
+ && align > INT_REGISTER_SIZE
+ && argreg & 1)
+ argreg++;
/* If the argument is a pointer to a function, and it is a
Thumb function, create a LOCAL copy of the value and set
return sp;
}
+
+/* Always align the frame to an 8-byte boundary. This is required on
+ some platforms and harmless on the rest. */
+
+static CORE_ADDR
+arm_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
+{
+ /* Align the stack to eight bytes. */
+ return sp & ~ (CORE_ADDR) 7;
+}
+
static void
print_fpu_flags (int flags)
{
int type;
type = (status >> 24) & 127;
- printf ("%s FPU type %d\n",
- (status & (1 << 31)) ? "Hardware" : "Software",
- type);
- fputs ("mask: ", stdout);
+ if (status & (1 << 31))
+ printf (_("Hardware FPU type %d\n"), type);
+ else
+ printf (_("Software FPU type %d\n"), type);
+ /* i18n: [floating point unit] mask */
+ fputs (_("mask: "), stdout);
print_fpu_flags (status >> 16);
- fputs ("flags: ", stdout);
+ /* i18n: [floating point unit] flags */
+ fputs (_("flags: "), stdout);
print_fpu_flags (status);
}
arm_register_type (struct gdbarch *gdbarch, int regnum)
{
if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS)
- {
- if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
- return builtin_type_arm_ext_big;
- else
- return builtin_type_arm_ext_littlebyte_bigword;
- }
+ return builtin_type_arm_ext;
+ else if (regnum == ARM_SP_REGNUM)
+ return builtin_type_void_data_ptr;
+ else if (regnum == ARM_PC_REGNUM)
+ return builtin_type_void_func_ptr;
+ else if (regnum >= ARRAY_SIZE (arm_register_names))
+ /* These registers are only supported on targets which supply
+ an XML description. */
+ return builtin_type_int0;
else
- return builtin_type_int32;
+ return builtin_type_uint32;
}
-/* Index within `registers' of the first byte of the space for
- register N. */
+/* Map a DWARF register REGNUM onto the appropriate GDB register
+ number. */
static int
-arm_register_byte (int regnum)
+arm_dwarf_reg_to_regnum (int reg)
{
- if (regnum < ARM_F0_REGNUM)
- return regnum * INT_REGISTER_SIZE;
- else if (regnum < ARM_PS_REGNUM)
- return (NUM_GREGS * INT_REGISTER_SIZE
- + (regnum - ARM_F0_REGNUM) * FP_REGISTER_SIZE);
- else
- return (NUM_GREGS * INT_REGISTER_SIZE
- + NUM_FREGS * FP_REGISTER_SIZE
- + (regnum - ARM_FPS_REGNUM) * STATUS_REGISTER_SIZE);
+ /* Core integer regs. */
+ if (reg >= 0 && reg <= 15)
+ return reg;
+
+ /* Legacy FPA encoding. These were once used in a way which
+ overlapped with VFP register numbering, so their use is
+ discouraged, but GDB doesn't support the ARM toolchain
+ which used them for VFP. */
+ if (reg >= 16 && reg <= 23)
+ return ARM_F0_REGNUM + reg - 16;
+
+ /* New assignments for the FPA registers. */
+ if (reg >= 96 && reg <= 103)
+ return ARM_F0_REGNUM + reg - 96;
+
+ /* WMMX register assignments. */
+ if (reg >= 104 && reg <= 111)
+ return ARM_WCGR0_REGNUM + reg - 104;
+
+ if (reg >= 112 && reg <= 127)
+ return ARM_WR0_REGNUM + reg - 112;
+
+ if (reg >= 192 && reg <= 199)
+ return ARM_WC0_REGNUM + reg - 192;
+
+ return -1;
}
/* Map GDB internal REGNUM onto the Arm simulator register numbers. */
int reg = regnum;
gdb_assert (reg >= 0 && reg < NUM_REGS);
+ if (regnum >= ARM_WR0_REGNUM && regnum <= ARM_WR15_REGNUM)
+ return regnum - ARM_WR0_REGNUM + SIM_ARM_IWMMXT_COP0R0_REGNUM;
+
+ if (regnum >= ARM_WC0_REGNUM && regnum <= ARM_WC7_REGNUM)
+ return regnum - ARM_WC0_REGNUM + SIM_ARM_IWMMXT_COP1R0_REGNUM;
+
+ if (regnum >= ARM_WCGR0_REGNUM && regnum <= ARM_WCGR7_REGNUM)
+ return regnum - ARM_WCGR0_REGNUM + SIM_ARM_IWMMXT_COP1R8_REGNUM;
+
if (reg < NUM_GREGS)
return SIM_ARM_R0_REGNUM + reg;
reg -= NUM_GREGS;
return SIM_ARM_FPS_REGNUM + reg;
reg -= NUM_SREGS;
- internal_error (__FILE__, __LINE__, "Bad REGNUM %d", regnum);
+ internal_error (__FILE__, __LINE__, _("Bad REGNUM %d"), regnum);
}
/* NOTE: cagney/2001-08-20: Both convert_from_extended() and
thumb_get_next_pc (CORE_ADDR pc)
{
unsigned long pc_val = ((unsigned long) pc) + 4; /* PC after prefetch */
- unsigned short inst1 = read_memory_integer (pc, 2);
+ unsigned short inst1 = read_memory_unsigned_integer (pc, 2);
CORE_ADDR nextpc = pc + 2; /* default is next instruction */
unsigned long offset;
all of the other registers. */
offset = bitcount (bits (inst1, 0, 7)) * DEPRECATED_REGISTER_SIZE;
sp = read_register (ARM_SP_REGNUM);
- nextpc = (CORE_ADDR) read_memory_integer (sp + offset, 4);
+ nextpc = (CORE_ADDR) read_memory_unsigned_integer (sp + offset, 4);
nextpc = ADDR_BITS_REMOVE (nextpc);
if (nextpc == pc)
- error ("Infinite loop detected");
+ error (_("Infinite loop detected"));
}
else if ((inst1 & 0xf000) == 0xd000) /* conditional branch */
{
}
else if ((inst1 & 0xf800) == 0xf000) /* long branch with link, and blx */
{
- unsigned short inst2 = read_memory_integer (pc + 2, 2);
+ unsigned short inst2 = read_memory_unsigned_integer (pc + 2, 2);
offset = (sbits (inst1, 0, 10) << 12) + (bits (inst2, 0, 10) << 1);
nextpc = pc_val + offset;
/* For BLX make sure to clear the low bits. */
nextpc = ADDR_BITS_REMOVE (nextpc);
if (nextpc == pc)
- error ("Infinite loop detected");
+ error (_("Infinite loop detected"));
}
return nextpc;
return thumb_get_next_pc (pc);
pc_val = (unsigned long) pc;
- this_instr = read_memory_integer (pc, 4);
+ this_instr = read_memory_unsigned_integer (pc, 4);
status = read_register (ARM_PS_REGNUM);
nextpc = (CORE_ADDR) (pc_val + 4); /* Default case */
if (bits (this_instr, 22, 25) == 0
&& bits (this_instr, 4, 7) == 9) /* multiply */
- error ("Illegal update to pc in instruction");
+ error (_("Invalid update to pc in instruction"));
/* BX <reg>, BLX <reg> */
- if (bits (this_instr, 4, 28) == 0x12fff1
- || bits (this_instr, 4, 28) == 0x12fff3)
+ if (bits (this_instr, 4, 27) == 0x12fff1
+ || bits (this_instr, 4, 27) == 0x12fff3)
{
rn = bits (this_instr, 0, 3);
result = (rn == 15) ? pc_val + 8 : read_register (rn);
nextpc = (CORE_ADDR) ADDR_BITS_REMOVE (result);
if (nextpc == pc)
- error ("Infinite loop detected");
+ error (_("Infinite loop detected"));
return nextpc;
}
nextpc = (CORE_ADDR) ADDR_BITS_REMOVE (result);
if (nextpc == pc)
- error ("Infinite loop detected");
+ error (_("Infinite loop detected"));
break;
}
unsigned long base;
if (bit (this_instr, 22))
- error ("Illegal update to pc in instruction");
+ error (_("Invalid update to pc in instruction"));
/* byte write to PC */
rn = bits (this_instr, 16, 19);
nextpc = ADDR_BITS_REMOVE (nextpc);
if (nextpc == pc)
- error ("Infinite loop detected");
+ error (_("Infinite loop detected"));
}
}
break;
}
nextpc = ADDR_BITS_REMOVE (nextpc);
if (nextpc == pc)
- error ("Infinite loop detected");
+ error (_("Infinite loop detected"));
}
}
break;
nextpc = ADDR_BITS_REMOVE (nextpc);
if (nextpc == pc)
- error ("Infinite loop detected");
+ error (_("Infinite loop detected"));
break;
}
break;
default:
- fprintf_filtered (gdb_stderr, "Bad bit-field extraction\n");
+ fprintf_filtered (gdb_stderr, _("Bad bit-field extraction\n"));
return (pc);
}
}
static void
arm_software_single_step (enum target_signal sig, int insert_bpt)
{
- static int next_pc; /* State between setting and unsetting. */
- static char break_mem[BREAKPOINT_MAX]; /* Temporary storage for mem@bpt */
+ /* NOTE: This may insert the wrong breakpoint instruction when
+ single-stepping over a mode-changing instruction, if the
+ CPSR heuristics are used. */
if (insert_bpt)
{
- next_pc = arm_get_next_pc (read_register (ARM_PC_REGNUM));
- target_insert_breakpoint (next_pc, break_mem);
+ CORE_ADDR next_pc = arm_get_next_pc (read_register (ARM_PC_REGNUM));
+
+ insert_single_step_breakpoint (next_pc);
}
else
- target_remove_breakpoint (next_pc, break_mem);
+ remove_single_step_breakpoints ();
}
#include "bfd-in2.h"
necessary) to point to the actual memory location where the
breakpoint should be inserted. */
-/* XXX ??? from old tm-arm.h: if we're using RDP, then we're inserting
- breakpoints and storing their handles instread of what was in
- memory. It is nice that this is the same size as a handle -
- otherwise remote-rdp will have to change. */
-
static const unsigned char *
arm_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
- if (arm_pc_is_thumb (*pcptr) || arm_pc_is_thumb_dummy (*pcptr))
+ if (arm_pc_is_thumb (*pcptr))
{
*pcptr = UNMAKE_THUMB_ADDR (*pcptr);
*lenptr = tdep->thumb_breakpoint_size;
format, into VALBUF. */
static void
-arm_extract_return_value (struct type *type,
- struct regcache *regs,
- void *dst)
+arm_extract_return_value (struct type *type, struct regcache *regs,
+ gdb_byte *valbuf)
{
- bfd_byte *valbuf = dst;
-
if (TYPE_CODE_FLT == TYPE_CODE (type))
{
- switch (arm_get_fp_model (current_gdbarch))
+ switch (gdbarch_tdep (current_gdbarch)->fp_model)
{
case ARM_FLOAT_FPA:
{
default:
internal_error
(__FILE__, __LINE__,
- "arm_extract_return_value: Floating point model not supported");
+ _("arm_extract_return_value: Floating point model not supported"));
break;
}
}
}
}
-/* Extract from an array REGBUF containing the (raw) register state
- the address in which a function should return its structure value. */
-
-static CORE_ADDR
-arm_extract_struct_value_address (struct regcache *regcache)
-{
- 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
register? Return 0 if an aggregate type can be returned in a
register, 1 if it must be returned in memory. */
static int
-arm_use_struct_convention (int gcc_p, struct type *type)
+arm_return_in_memory (struct gdbarch *gdbarch, struct type *type)
{
int nRc;
enum type_code code;
return 1;
}
+ /* The AAPCS says all aggregates not larger than a word are returned
+ in a register. */
+ if (gdbarch_tdep (gdbarch)->arm_abi != ARM_ABI_APCS)
+ return 0;
+
/* The only aggregate types that can be returned in a register are
structs and unions. Arrays must be returned in memory. */
code = TYPE_CODE (type);
static void
arm_store_return_value (struct type *type, struct regcache *regs,
- const void *src)
+ const gdb_byte *valbuf)
{
- const bfd_byte *valbuf = src;
-
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
char buf[MAX_REGISTER_SIZE];
- switch (arm_get_fp_model (current_gdbarch))
+ switch (gdbarch_tdep (current_gdbarch)->fp_model)
{
case ARM_FLOAT_FPA:
default:
internal_error
(__FILE__, __LINE__,
- "arm_store_return_value: Floating point model not supported");
+ _("arm_store_return_value: Floating point model not supported"));
break;
}
}
}
}
+
+/* Handle function return values. */
+
+static enum return_value_convention
+arm_return_value (struct gdbarch *gdbarch, struct type *valtype,
+ struct regcache *regcache, gdb_byte *readbuf,
+ const gdb_byte *writebuf)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+ || TYPE_CODE (valtype) == TYPE_CODE_UNION
+ || TYPE_CODE (valtype) == TYPE_CODE_ARRAY)
+ {
+ if (tdep->struct_return == pcc_struct_return
+ || arm_return_in_memory (gdbarch, valtype))
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ }
+
+ if (writebuf)
+ arm_store_return_value (valtype, regcache, writebuf);
+
+ if (readbuf)
+ arm_extract_return_value (valtype, regcache, readbuf);
+
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+
static int
arm_get_longjmp_target (CORE_ADDR *pc)
{
static void
set_arm_command (char *args, int from_tty)
{
- printf_unfiltered ("\"set arm\" must be followed by an apporpriate subcommand.\n");
+ printf_unfiltered (_("\
+\"set arm\" must be followed by an apporpriate subcommand.\n"));
help_list (setarmcmdlist, "set arm ", all_commands, gdb_stdout);
}
cmd_show_list (showarmcmdlist, from_tty, "");
}
-enum arm_float_model
-arm_get_fp_model (struct gdbarch *gdbarch)
+static void
+arm_update_current_architecture (void)
{
- if (arm_fp_model == ARM_FLOAT_AUTO)
- return gdbarch_tdep (gdbarch)->fp_model;
+ struct gdbarch_info info;
- return arm_fp_model;
-}
+ /* If the current architecture is not ARM, we have nothing to do. */
+ if (gdbarch_bfd_arch_info (current_gdbarch)->arch != bfd_arch_arm)
+ return;
-static void
-arm_set_fp (struct gdbarch *gdbarch)
-{
- enum arm_float_model fp_model = arm_get_fp_model (gdbarch);
+ /* Update the architecture. */
+ gdbarch_info_init (&info);
- if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE
- && (fp_model == ARM_FLOAT_SOFT_FPA || fp_model == ARM_FLOAT_FPA))
- {
- set_gdbarch_double_format (gdbarch,
- &floatformat_ieee_double_littlebyte_bigword);
- set_gdbarch_long_double_format
- (gdbarch, &floatformat_ieee_double_littlebyte_bigword);
- }
- else
- {
- set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_little);
- set_gdbarch_long_double_format (gdbarch,
- &floatformat_ieee_double_little);
- }
+ if (!gdbarch_update_p (info))
+ internal_error (__FILE__, __LINE__, "could not update architecture");
}
static void
}
if (fp_model == ARM_FLOAT_LAST)
- internal_error (__FILE__, __LINE__, "Invalid fp model accepted: %s.",
+ internal_error (__FILE__, __LINE__, _("Invalid fp model accepted: %s."),
current_fp_model);
- if (gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
- arm_set_fp (current_gdbarch);
+ arm_update_current_architecture ();
+}
+
+static void
+show_fp_model (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (arm_fp_model == ARM_FLOAT_AUTO
+ && gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
+ fprintf_filtered (file, _("\
+The current ARM floating point model is \"auto\" (currently \"%s\").\n"),
+ fp_model_strings[tdep->fp_model]);
+ else
+ fprintf_filtered (file, _("\
+The current ARM floating point model is \"%s\".\n"),
+ fp_model_strings[arm_fp_model]);
+}
+
+static void
+arm_set_abi (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ enum arm_abi_kind arm_abi;
+
+ for (arm_abi = ARM_ABI_AUTO; arm_abi != ARM_ABI_LAST; arm_abi++)
+ if (strcmp (arm_abi_string, arm_abi_strings[arm_abi]) == 0)
+ {
+ arm_abi_global = arm_abi;
+ break;
+ }
+
+ if (arm_abi == ARM_ABI_LAST)
+ internal_error (__FILE__, __LINE__, _("Invalid ABI accepted: %s."),
+ arm_abi_string);
+
+ arm_update_current_architecture ();
}
static void
-show_fp_model (char *args, int from_tty,
- struct cmd_list_element *c)
+arm_show_abi (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
- if (arm_fp_model == ARM_FLOAT_AUTO
+ if (arm_abi_global == ARM_ABI_AUTO
&& gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
- printf_filtered (" - the default for the current ABI is \"%s\".\n",
- fp_model_strings[tdep->fp_model]);
+ fprintf_filtered (file, _("\
+The current ARM ABI is \"auto\" (currently \"%s\").\n"),
+ arm_abi_strings[tdep->arm_abi]);
+ else
+ fprintf_filtered (file, _("The current ARM ABI is \"%s\".\n"),
+ arm_abi_string);
}
/* If the user changes the register disassembly style used for info
static const char *
arm_register_name (int i)
{
+ if (i >= ARRAY_SIZE (arm_register_names))
+ /* These registers are only supported on targets which supply
+ an XML description. */
+ return "";
+
return arm_register_names[i];
}
static void
set_disassembly_style (void)
{
- const char *setname, *setdesc, **regnames;
- int numregs, j;
-
- /* Find the style that the user wants in the opcodes table. */
- int current = 0;
- numregs = get_arm_regnames (current, &setname, &setdesc, ®names);
- while ((disassembly_style != setname)
- && (current < num_disassembly_options))
- get_arm_regnames (++current, &setname, &setdesc, ®names);
- current_option = current;
-
- /* Fill our copy. */
- for (j = 0; j < numregs; j++)
- arm_register_names[j] = (char *) regnames[j];
+ int current;
- /* Adjust case. */
- if (isupper (*regnames[ARM_PC_REGNUM]))
- {
- arm_register_names[ARM_FPS_REGNUM] = "FPS";
- arm_register_names[ARM_PS_REGNUM] = "CPSR";
- }
- else
- {
- arm_register_names[ARM_FPS_REGNUM] = "fps";
- arm_register_names[ARM_PS_REGNUM] = "cpsr";
- }
+ /* Find the style that the user wants. */
+ for (current = 0; current < num_disassembly_options; current++)
+ if (disassembly_style == valid_disassembly_styles[current])
+ break;
+ gdb_assert (current < num_disassembly_options);
/* Synchronize the disassembler. */
set_arm_regname_option (current);
}
-/* arm_othernames implements the "othernames" command. This is deprecated
- by the "set arm disassembly" command. */
-
-static void
-arm_othernames (char *names, int n)
-{
- /* Circle through the various flavors. */
- current_option = (current_option + 1) % num_disassembly_options;
-
- disassembly_style = valid_disassembly_styles[current_option];
- set_disassembly_style ();
-}
-
/* Test whether the coff symbol specific value corresponds to a Thumb
function. */
write_register_pid (ARM_PS_REGNUM, val & ~(CORE_ADDR) 0x20, ptid);
}
}
+
+static struct value *
+value_of_arm_user_reg (struct frame_info *frame, const void *baton)
+{
+ const int *reg_p = baton;
+ return value_of_register (*reg_p, frame);
+}
\f
static enum gdb_osabi
arm_elf_osabi_sniffer (bfd *abfd)
{
- unsigned int elfosabi, eflags;
+ unsigned int elfosabi;
enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
- switch (elfosabi)
- {
- 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)
- {
- /* 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 EF_ARM_EABI_VER1:
- osabi = GDB_OSABI_ARM_EABI_V1;
- break;
-
- case EF_ARM_EABI_VER2:
- osabi = GDB_OSABI_ARM_EABI_V2;
- break;
-
- case EF_ARM_EABI_UNKNOWN:
- /* Assume GNU tools. */
- osabi = GDB_OSABI_ARM_APCS;
- break;
-
- default:
- internal_error (__FILE__, __LINE__,
- "arm_elf_osabi_sniffer: Unknown ARM EABI "
- "version 0x%x", eflags);
- }
- }
- break;
-
- case ELFOSABI_ARM:
- /* GNU tools use this value. Check note sections in this case,
- as well. */
- bfd_map_over_sections (abfd,
- generic_elf_osabi_sniff_abi_tag_sections,
- &osabi);
- if (osabi == GDB_OSABI_UNKNOWN)
- {
- /* Assume APCS ABI. */
- osabi = GDB_OSABI_ARM_APCS;
- }
- break;
-
- case ELFOSABI_FREEBSD:
- osabi = GDB_OSABI_FREEBSD_ELF;
- break;
-
- case ELFOSABI_NETBSD:
- osabi = GDB_OSABI_NETBSD_ELF;
- break;
-
- case ELFOSABI_LINUX:
- osabi = GDB_OSABI_LINUX;
- break;
- }
+ if (elfosabi == ELFOSABI_ARM)
+ /* GNU tools use this value. Check note sections in this case,
+ as well. */
+ bfd_map_over_sections (abfd,
+ generic_elf_osabi_sniff_abi_tag_sections,
+ &osabi);
+ /* Anything else will be handled by the generic ELF sniffer. */
return osabi;
}
{
struct gdbarch_tdep *tdep;
struct gdbarch *gdbarch;
+ struct gdbarch_list *best_arch;
+ enum arm_abi_kind arm_abi = arm_abi_global;
+ enum arm_float_model fp_model = arm_fp_model;
+ struct tdesc_arch_data *tdesc_data = NULL;
+ int i;
+ int have_fpa_registers = 1;
- /* Try to deterimine the ABI of the object we are loading. */
+ /* Check any target description for validity. */
+ if (tdesc_has_registers (info.target_desc))
+ {
+ /* For most registers we require GDB's default names; but also allow
+ the numeric names for sp / lr / pc, as a convenience. */
+ static const char *const arm_sp_names[] = { "r13", "sp", NULL };
+ static const char *const arm_lr_names[] = { "r14", "lr", NULL };
+ static const char *const arm_pc_names[] = { "r15", "pc", NULL };
+
+ const struct tdesc_feature *feature;
+ int i, valid_p;
+
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.arm.core");
+ if (feature == NULL)
+ return NULL;
+
+ tdesc_data = tdesc_data_alloc ();
+
+ valid_p = 1;
+ for (i = 0; i < ARM_SP_REGNUM; i++)
+ valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
+ arm_register_names[i]);
+ valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
+ ARM_SP_REGNUM,
+ arm_sp_names);
+ valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
+ ARM_LR_REGNUM,
+ arm_lr_names);
+ valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
+ ARM_PC_REGNUM,
+ arm_pc_names);
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ ARM_PS_REGNUM, "cpsr");
+
+ if (!valid_p)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.arm.fpa");
+ if (feature != NULL)
+ {
+ valid_p = 1;
+ for (i = ARM_F0_REGNUM; i <= ARM_FPS_REGNUM; i++)
+ valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
+ arm_register_names[i]);
+ if (!valid_p)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+ }
+ else
+ have_fpa_registers = 0;
- if (info.abfd != NULL && info.osabi == GDB_OSABI_UNKNOWN)
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.xscale.iwmmxt");
+ if (feature != NULL)
+ {
+ static const char *const iwmmxt_names[] = {
+ "wR0", "wR1", "wR2", "wR3", "wR4", "wR5", "wR6", "wR7",
+ "wR8", "wR9", "wR10", "wR11", "wR12", "wR13", "wR14", "wR15",
+ "wCID", "wCon", "wCSSF", "wCASF", "", "", "", "",
+ "wCGR0", "wCGR1", "wCGR2", "wCGR3", "", "", "", "",
+ };
+
+ valid_p = 1;
+ for (i = ARM_WR0_REGNUM; i <= ARM_WR15_REGNUM; i++)
+ valid_p
+ &= tdesc_numbered_register (feature, tdesc_data, i,
+ iwmmxt_names[i - ARM_WR0_REGNUM]);
+
+ /* Check for the control registers, but do not fail if they
+ are missing. */
+ for (i = ARM_WC0_REGNUM; i <= ARM_WCASF_REGNUM; i++)
+ tdesc_numbered_register (feature, tdesc_data, i,
+ iwmmxt_names[i - ARM_WR0_REGNUM]);
+
+ for (i = ARM_WCGR0_REGNUM; i <= ARM_WCGR3_REGNUM; i++)
+ valid_p
+ &= tdesc_numbered_register (feature, tdesc_data, i,
+ iwmmxt_names[i - ARM_WR0_REGNUM]);
+
+ if (!valid_p)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+ }
+ }
+
+ /* If we have an object to base this architecture on, try to determine
+ its ABI. */
+
+ if (arm_abi == ARM_ABI_AUTO && info.abfd != NULL)
{
+ int ei_osabi, e_flags;
+
switch (bfd_get_flavour (info.abfd))
{
case bfd_target_aout_flavour:
/* Assume it's an old APCS-style ABI. */
- info.osabi = GDB_OSABI_ARM_APCS;
+ arm_abi = ARM_ABI_APCS;
break;
case bfd_target_coff_flavour:
/* Assume it's an old APCS-style ABI. */
/* XXX WinCE? */
- info.osabi = GDB_OSABI_ARM_APCS;
+ arm_abi = ARM_ABI_APCS;
+ break;
+
+ case bfd_target_elf_flavour:
+ ei_osabi = elf_elfheader (info.abfd)->e_ident[EI_OSABI];
+ e_flags = elf_elfheader (info.abfd)->e_flags;
+
+ if (ei_osabi == ELFOSABI_ARM)
+ {
+ /* GNU tools used to use this value, but do not for EABI
+ objects. There's nowhere to tag an EABI version
+ anyway, so assume APCS. */
+ arm_abi = ARM_ABI_APCS;
+ }
+ else if (ei_osabi == ELFOSABI_NONE)
+ {
+ int eabi_ver = EF_ARM_EABI_VERSION (e_flags);
+
+ switch (eabi_ver)
+ {
+ case EF_ARM_EABI_UNKNOWN:
+ /* Assume GNU tools. */
+ arm_abi = ARM_ABI_APCS;
+ break;
+
+ case EF_ARM_EABI_VER4:
+ case EF_ARM_EABI_VER5:
+ arm_abi = ARM_ABI_AAPCS;
+ /* EABI binaries default to VFP float ordering. */
+ if (fp_model == ARM_FLOAT_AUTO)
+ fp_model = ARM_FLOAT_SOFT_VFP;
+ break;
+
+ default:
+ /* Leave it as "auto". */
+ warning (_("unknown ARM EABI version 0x%x"), eabi_ver);
+ break;
+ }
+ }
+
+ if (fp_model == ARM_FLOAT_AUTO)
+ {
+ int e_flags = elf_elfheader (info.abfd)->e_flags;
+
+ switch (e_flags & (EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT))
+ {
+ case 0:
+ /* Leave it as "auto". Strictly speaking this case
+ means FPA, but almost nobody uses that now, and
+ many toolchains fail to set the appropriate bits
+ for the floating-point model they use. */
+ break;
+ case EF_ARM_SOFT_FLOAT:
+ fp_model = ARM_FLOAT_SOFT_FPA;
+ break;
+ case EF_ARM_VFP_FLOAT:
+ fp_model = ARM_FLOAT_VFP;
+ break;
+ case EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT:
+ fp_model = ARM_FLOAT_SOFT_VFP;
+ break;
+ }
+ }
break;
default:
- /* Leave it as "unknown". */
+ /* Leave it as "auto". */
break;
}
}
- /* If there is already a candidate, use it. */
- arches = gdbarch_list_lookup_by_info (arches, &info);
+ /* Now that we have inferred any architecture settings that we
+ can, try to inherit from the last ARM ABI. */
if (arches != NULL)
- return arches->gdbarch;
+ {
+ if (arm_abi == ARM_ABI_AUTO)
+ arm_abi = gdbarch_tdep (arches->gdbarch)->arm_abi;
+
+ if (fp_model == ARM_FLOAT_AUTO)
+ fp_model = gdbarch_tdep (arches->gdbarch)->fp_model;
+ }
+ else
+ {
+ /* There was no prior ARM architecture; fill in default values. */
+
+ if (arm_abi == ARM_ABI_AUTO)
+ arm_abi = ARM_ABI_APCS;
+
+ /* We used to default to FPA for generic ARM, but almost nobody
+ uses that now, and we now provide a way for the user to force
+ the model. So default to the most useful variant. */
+ if (fp_model == ARM_FLOAT_AUTO)
+ fp_model = ARM_FLOAT_SOFT_FPA;
+ }
+
+ /* If there is already a candidate, use it. */
+ for (best_arch = gdbarch_list_lookup_by_info (arches, &info);
+ best_arch != NULL;
+ best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
+ {
+ if (arm_abi != gdbarch_tdep (best_arch->gdbarch)->arm_abi)
+ continue;
- tdep = xmalloc (sizeof (struct gdbarch_tdep));
+ if (fp_model != gdbarch_tdep (best_arch->gdbarch)->fp_model)
+ continue;
+
+ /* Found a match. */
+ break;
+ }
+
+ if (best_arch != NULL)
+ {
+ if (tdesc_data != NULL)
+ tdesc_data_cleanup (tdesc_data);
+ return best_arch->gdbarch;
+ }
+
+ tdep = xcalloc (1, sizeof (struct gdbarch_tdep));
gdbarch = gdbarch_alloc (&info, tdep);
- /* We used to default to FPA for generic ARM, but almost nobody uses that
- now, and we now provide a way for the user to force the model. So
- default to the most useful variant. */
- tdep->fp_model = ARM_FLOAT_SOFT_FPA;
+ /* Record additional information about the architecture we are defining.
+ These are gdbarch discriminators, like the OSABI. */
+ tdep->arm_abi = arm_abi;
+ tdep->fp_model = fp_model;
+ tdep->have_fpa_registers = have_fpa_registers;
/* Breakpoints. */
switch (info.byte_order)
default:
internal_error (__FILE__, __LINE__,
- "arm_gdbarch_init: bad byte order for float format");
+ _("arm_gdbarch_init: bad byte order for float format"));
}
/* On ARM targets char defaults to unsigned. */
tdep->lowest_pc = 0x20;
tdep->jb_pc = -1; /* Longjump support not enabled by default. */
- set_gdbarch_deprecated_call_dummy_words (gdbarch, arm_call_dummy_words);
- set_gdbarch_deprecated_sizeof_call_dummy_words (gdbarch, 0);
+ /* The default, for both APCS and AAPCS, is to return small
+ structures in registers. */
+ tdep->struct_return = reg_struct_return;
set_gdbarch_push_dummy_call (gdbarch, arm_push_dummy_call);
+ set_gdbarch_frame_align (gdbarch, arm_frame_align);
set_gdbarch_write_pc (gdbarch, arm_write_pc);
set_gdbarch_unwind_pc (gdbarch, arm_unwind_pc);
set_gdbarch_unwind_sp (gdbarch, arm_unwind_sp);
- set_gdbarch_deprecated_frameless_function_invocation (gdbarch, arm_frameless_function_invocation);
-
frame_base_set_default (gdbarch, &arm_normal_base);
/* Address manipulation. */
/* Advance PC across function entry code. */
set_gdbarch_skip_prologue (gdbarch, arm_skip_prologue);
- /* Get the PC when a frame might not be available. */
- set_gdbarch_deprecated_saved_pc_after_call (gdbarch, arm_saved_pc_after_call);
-
/* The stack grows downward. */
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_breakpoint_from_pc (gdbarch, arm_breakpoint_from_pc);
/* Information about registers, etc. */
- set_gdbarch_print_float_info (gdbarch, arm_print_float_info);
set_gdbarch_deprecated_fp_regnum (gdbarch, ARM_FP_REGNUM); /* ??? */
set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM);
set_gdbarch_pc_regnum (gdbarch, ARM_PC_REGNUM);
- set_gdbarch_deprecated_register_byte (gdbarch, arm_register_byte);
- set_gdbarch_deprecated_register_bytes (gdbarch,
- (NUM_GREGS * INT_REGISTER_SIZE
- + NUM_FREGS * FP_REGISTER_SIZE
- + NUM_SREGS * STATUS_REGISTER_SIZE));
- set_gdbarch_num_regs (gdbarch, NUM_GREGS + NUM_FREGS + NUM_SREGS);
+ set_gdbarch_num_regs (gdbarch, ARM_NUM_REGS);
set_gdbarch_register_type (gdbarch, arm_register_type);
+ /* This "info float" is FPA-specific. Use the generic version if we
+ do not have FPA. */
+ if (gdbarch_tdep (gdbarch)->have_fpa_registers)
+ set_gdbarch_print_float_info (gdbarch, arm_print_float_info);
+
/* Internal <-> external register number maps. */
+ set_gdbarch_dwarf_reg_to_regnum (gdbarch, arm_dwarf_reg_to_regnum);
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, arm_dwarf_reg_to_regnum);
set_gdbarch_register_sim_regno (gdbarch, arm_register_sim_regno);
/* Integer registers are 4 bytes. */
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_use_struct_convention (gdbarch, arm_use_struct_convention);
- set_gdbarch_deprecated_extract_struct_value_address (gdbarch, arm_extract_struct_value_address);
+ set_gdbarch_return_value (gdbarch, arm_return_value);
/* Single stepping. */
/* XXX For an RDI target we should ask the target if it can single-step. */
set_gdbarch_coff_make_msymbol_special (gdbarch,
arm_coff_make_msymbol_special);
+ /* Virtual tables. */
+ set_gdbarch_vbit_in_delta (gdbarch, 1);
+
/* Hook in the ABI-specific overrides, if they have been registered. */
gdbarch_init_osabi (info, gdbarch);
/* Add some default predicates. */
- frame_unwind_append_sniffer (gdbarch, arm_sigtramp_unwind_sniffer);
+ frame_unwind_append_sniffer (gdbarch, arm_stub_unwind_sniffer);
+ frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
frame_unwind_append_sniffer (gdbarch, arm_prologue_unwind_sniffer);
/* Now we have tuned the configuration, set a few final things,
set_gdbarch_get_longjmp_target (gdbarch, arm_get_longjmp_target);
/* Floating point sizes and format. */
- switch (info.byte_order)
+ set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+ if (fp_model == ARM_FLOAT_SOFT_FPA || fp_model == ARM_FLOAT_FPA)
{
- case BFD_ENDIAN_BIG:
- set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_big);
- set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_big);
- set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big);
-
- break;
+ set_gdbarch_double_format
+ (gdbarch, floatformats_ieee_double_littlebyte_bigword);
+ set_gdbarch_long_double_format
+ (gdbarch, floatformats_ieee_double_littlebyte_bigword);
+ }
+ else
+ {
+ set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+ set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+ }
- case BFD_ENDIAN_LITTLE:
- set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little);
- arm_set_fp (gdbarch);
- break;
+ if (tdesc_data)
+ tdesc_use_registers (gdbarch, tdesc_data);
- default:
- internal_error (__FILE__, __LINE__,
- "arm_gdbarch_init: bad byte order for float format");
- }
+ /* Add standard register aliases. We add aliases even for those
+ nanes which are used by the current architecture - it's simpler,
+ and does no harm, since nothing ever lists user registers. */
+ for (i = 0; i < ARRAY_SIZE (arm_register_aliases); i++)
+ user_reg_add (gdbarch, arm_register_aliases[i].name,
+ value_of_arm_user_reg, &arm_register_aliases[i].regnum);
return gdbarch;
}
if (tdep == NULL)
return;
- fprintf_unfiltered (file, "arm_dump_tdep: Lowest pc = 0x%lx",
+ fprintf_unfiltered (file, _("arm_dump_tdep: Lowest pc = 0x%lx"),
(unsigned long) tdep->lowest_pc);
}
-static void
-arm_init_abi_eabi_v1 (struct gdbarch_info info,
- struct gdbarch *gdbarch)
-{
- /* Place-holder. */
-}
-
-static void
-arm_init_abi_eabi_v2 (struct gdbarch_info info,
- struct gdbarch *gdbarch)
-{
- /* Place-holder. */
-}
-
-static void
-arm_init_abi_apcs (struct gdbarch_info info,
- struct gdbarch *gdbarch)
-{
- /* Place-holder. */
-}
-
extern initialize_file_ftype _initialize_arm_tdep; /* -Wmissing-prototypes */
void
struct cmd_list_element *new_set, *new_show;
const char *setname;
const char *setdesc;
- const char **regnames;
+ const char *const *regnames;
int numregs, i, j;
static char *helptext;
+ char regdesc[1024], *rdptr = regdesc;
+ size_t rest = sizeof (regdesc);
gdbarch_register (bfd_arch_arm, arm_gdbarch_init, arm_dump_tdep);
bfd_target_elf_flavour,
arm_elf_osabi_sniffer);
- /* Register some ABI variants for embedded systems. */
- gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_ARM_EABI_V1,
- arm_init_abi_eabi_v1);
- gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_ARM_EABI_V2,
- arm_init_abi_eabi_v2);
- gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_ARM_APCS,
- arm_init_abi_apcs);
-
/* Get the number of possible sets of register names defined in opcodes. */
num_disassembly_options = get_arm_regname_num_options ();
/* Add root prefix command for all "set arm"/"show arm" commands. */
add_prefix_cmd ("arm", no_class, set_arm_command,
- "Various ARM-specific commands.",
+ _("Various ARM-specific commands."),
&setarmcmdlist, "set arm ", 0, &setlist);
add_prefix_cmd ("arm", no_class, show_arm_command,
- "Various ARM-specific commands.",
+ _("Various ARM-specific commands."),
&showarmcmdlist, "show arm ", 0, &showlist);
/* Sync the opcode insn printer with our register viewer. */
parse_arm_disassembler_option ("reg-names-std");
- /* Begin creating the help text. */
- stb = mem_fileopen ();
- fprintf_unfiltered (stb, "Set the disassembly style.\n"
- "The valid values are:\n");
-
- /* Initialize the array that will be passed to add_set_enum_cmd(). */
+ /* Initialize the array that will be passed to
+ add_setshow_enum_cmd(). */
valid_disassembly_styles
= xmalloc ((num_disassembly_options + 1) * sizeof (char *));
for (i = 0; i < num_disassembly_options; i++)
{
numregs = get_arm_regnames (i, &setname, &setdesc, ®names);
valid_disassembly_styles[i] = setname;
- fprintf_unfiltered (stb, "%s - %s\n", setname,
- setdesc);
- /* Copy the default names (if found) and synchronize disassembler. */
+ length = snprintf (rdptr, rest, "%s - %s\n", setname, setdesc);
+ rdptr += length;
+ rest -= length;
+ /* When we find the default names, tell the disassembler to use
+ them. */
if (!strcmp (setname, "std"))
{
disassembly_style = setname;
- current_option = i;
- for (j = 0; j < numregs; j++)
- arm_register_names[j] = (char *) regnames[j];
set_arm_regname_option (i);
}
}
/* Mark the end of valid options. */
valid_disassembly_styles[num_disassembly_options] = NULL;
- /* Finish the creation of the help text. */
- fprintf_unfiltered (stb, "The default is \"std\".");
+ /* Create the help text. */
+ stb = mem_fileopen ();
+ fprintf_unfiltered (stb, "%s%s%s",
+ _("The valid values are:\n"),
+ regdesc,
+ _("The default is \"std\"."));
helptext = ui_file_xstrdup (stb, &length);
ui_file_delete (stb);
- /* Add the deprecated disassembly-flavor command. */
- new_set = add_set_enum_cmd ("disassembly-flavor", no_class,
- valid_disassembly_styles,
- &disassembly_style,
- helptext,
- &setlist);
- set_cmd_sfunc (new_set, set_disassembly_style_sfunc);
- deprecate_cmd (new_set, "set arm disassembly");
- deprecate_cmd (add_show_from_set (new_set, &showlist),
- "show arm disassembly");
-
- /* And now add the new interface. */
- new_set = add_set_enum_cmd ("disassembler", no_class,
- valid_disassembly_styles, &disassembly_style,
- helptext, &setarmcmdlist);
-
- set_cmd_sfunc (new_set, set_disassembly_style_sfunc);
- add_show_from_set (new_set, &showarmcmdlist);
-
- add_setshow_cmd_full ("apcs32", no_class,
- var_boolean, (char *) &arm_apcs_32,
- "Set usage of ARM 32-bit mode.",
- "Show usage of ARM 32-bit mode.",
- NULL, NULL,
- &setlist, &showlist, &new_set, &new_show);
- deprecate_cmd (new_set, "set arm apcs32");
- deprecate_cmd (new_show, "show arm apcs32");
+ add_setshow_enum_cmd("disassembler", no_class,
+ valid_disassembly_styles, &disassembly_style,
+ _("Set the disassembly style."),
+ _("Show the disassembly style."),
+ helptext,
+ set_disassembly_style_sfunc,
+ NULL, /* FIXME: i18n: The disassembly style is \"%s\". */
+ &setarmcmdlist, &showarmcmdlist);
add_setshow_boolean_cmd ("apcs32", no_class, &arm_apcs_32,
- "Set usage of ARM 32-bit mode. "
- "When off, a 26-bit PC will be used.",
- "Show usage of ARM 32-bit mode. "
- "When off, a 26-bit PC will be used.",
- NULL, NULL,
+ _("Set usage of ARM 32-bit mode."),
+ _("Show usage of ARM 32-bit mode."),
+ _("When off, a 26-bit PC will be used."),
+ NULL,
+ NULL, /* FIXME: i18n: Usage of ARM 32-bit mode is %s. */
&setarmcmdlist, &showarmcmdlist);
/* Add a command to allow the user to force the FPU model. */
- new_set = add_set_enum_cmd
- ("fpu", no_class, fp_model_strings, ¤t_fp_model,
- "Set the floating point type.\n"
- "auto - Determine the FP typefrom the OS-ABI.\n"
- "softfpa - Software FP, mixed-endian doubles on little-endian ARMs.\n"
- "fpa - FPA co-processor (GCC compiled).\n"
- "softvfp - Software FP with pure-endian doubles.\n"
- "vfp - VFP co-processor.",
- &setarmcmdlist);
- set_cmd_sfunc (new_set, set_fp_model_sfunc);
- set_cmd_sfunc (add_show_from_set (new_set, &showarmcmdlist), show_fp_model);
-
- /* Add the deprecated "othernames" command. */
- deprecate_cmd (add_com ("othernames", class_obscure, arm_othernames,
- "Switch to the next set of register names."),
- "set arm disassembly");
+ add_setshow_enum_cmd ("fpu", no_class, fp_model_strings, ¤t_fp_model,
+ _("Set the floating point type."),
+ _("Show the floating point type."),
+ _("auto - Determine the FP typefrom the OS-ABI.\n\
+softfpa - Software FP, mixed-endian doubles on little-endian ARMs.\n\
+fpa - FPA co-processor (GCC compiled).\n\
+softvfp - Software FP with pure-endian doubles.\n\
+vfp - VFP co-processor."),
+ set_fp_model_sfunc, show_fp_model,
+ &setarmcmdlist, &showarmcmdlist);
+
+ /* Add a command to allow the user to force the ABI. */
+ add_setshow_enum_cmd ("abi", class_support, arm_abi_strings, &arm_abi_string,
+ _("Set the ABI."),
+ _("Show the ABI."),
+ NULL, arm_set_abi, arm_show_abi,
+ &setarmcmdlist, &showarmcmdlist);
/* Debugging flag. */
add_setshow_boolean_cmd ("arm", class_maintenance, &arm_debug,
- "Set ARM debugging. "
- "When on, arm-specific debugging is enabled.",
- "Show ARM debugging. "
- "When on, arm-specific debugging is enabled.",
- NULL, NULL,
+ _("Set ARM debugging."),
+ _("Show ARM debugging."),
+ _("When on, arm-specific debugging is enabled."),
+ NULL,
+ NULL, /* FIXME: i18n: "ARM debugging is %s. */
&setdebuglist, &showdebuglist);
}