/* Common target dependent code for GDB on ARM systems.
- Copyright 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1998, 1999, 2000,
- 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ Copyright 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1998, 1999,
+ 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GDB.
#include "inferior.h"
#include "gdbcmd.h"
#include "gdbcore.h"
-#include "symfile.h"
#include "gdb_string.h"
#include "dis-asm.h" /* For register styles. */
#include "regcache.h"
#include "doublest.h"
#include "value.h"
#include "arch-utils.h"
-#include "solib-svr4.h"
#include "osabi.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "trad-frame.h"
+#include "objfiles.h"
+#include "dwarf2-frame.h"
#include "arm-tdep.h"
#include "gdb/sim-arm.h"
/* 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. This field is already being used to store
- the symbol size, so the assumption is that the symbol size cannot
- exceed 2^31.
+ is used for this purpose.
MSYMBOL_SET_SPECIAL Actually sets the "special" bit.
- MSYMBOL_IS_SPECIAL Tests the "special" bit in a minimal symbol.
- MSYMBOL_SIZE Returns the size of the minimal symbol,
- i.e. the "info" field with the "special" bit
- masked out. */
+ MSYMBOL_IS_SPECIAL Tests the "special" bit in a minimal symbol. */
#define MSYMBOL_SET_SPECIAL(msym) \
MSYMBOL_INFO (msym) = (char *) (((long) MSYMBOL_INFO (msym)) \
#define MSYMBOL_IS_SPECIAL(msym) \
(((long) MSYMBOL_INFO (msym) & 0x80000000) != 0)
-#define MSYMBOL_SIZE(msym) \
- ((long) MSYMBOL_INFO (msym) & 0x7fffffff)
-
/* The list of available "set arm ..." and "show arm ..." commands. */
static struct cmd_list_element *setarmcmdlist = NULL;
static struct cmd_list_element *showarmcmdlist = NULL;
"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;
static void convert_to_extended (const struct floatformat *, void *,
const void *);
-/* Define other aspects of the stack frame. We keep the offsets of
- all saved registers, 'cause we need 'em a lot! We also keep the
- current size of the stack frame, and the offset of the frame
- pointer from the stack pointer (for frameless functions, and when
- we're still in the prologue of a function with a frame). */
-
-struct frame_extra_info
+struct arm_prologue_cache
{
+ /* The stack pointer at the time this frame was created; i.e. the
+ caller's stack pointer when this function was called. It is used
+ to identify this frame. */
+ CORE_ADDR prev_sp;
+
+ /* The frame base for this frame is just prev_sp + frame offset -
+ frame size. FRAMESIZE is the size of this stack frame, and
+ FRAMEOFFSET if the initial offset from the stack pointer (this
+ frame's stack pointer, not PREV_SP) to the frame base. */
+
int framesize;
int frameoffset;
+
+ /* The register used to hold the frame pointer for this frame. */
int framereg;
+
+ /* Saved register offsets. */
+ struct trad_frame_saved_reg *saved_regs;
};
/* Addresses for calling Thumb functions have the bit 0 set.
#define MAKE_THUMB_ADDR(addr) ((addr) | 1)
#define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1)
-static int
-arm_frame_chain_valid (CORE_ADDR chain, struct frame_info *thisframe)
-{
- return (DEPRECATED_FRAME_SAVED_PC (thisframe) >= LOWEST_PC);
-}
-
/* Set to true if the 32-bit mode is in use. */
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 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. */
-
- func_start = (get_frame_func (fi)) + FUNCTION_START_OFFSET);
- after_prologue = SKIP_PROLOGUE (func_start);
-
- /* There are some frameless functions whose first two instructions
- follow the standard APCS form, in which case after_prologue will
- be func_start + 8. */
-
- frameless = (after_prologue < func_start + 12);
- return frameless;
-}
-
-/* The address of the arguments in the frame. */
-static CORE_ADDR
-arm_frame_args_address (struct frame_info *fi)
-{
- return get_frame_base (fi);
-}
-
-/* The address of the local variables in the frame. */
-static CORE_ADDR
-arm_frame_locals_address (struct frame_info *fi)
-{
- return get_frame_base (fi);
-}
-
-/* The number of arguments being passed in the frame. */
-static int
-arm_frame_num_args (struct frame_info *fi)
-{
- /* We have no way of knowing. */
- return -1;
-}
-
/* A typical Thumb prologue looks like this:
push {r7, lr}
add sp, sp, #-28
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. */
struct symbol *sym;
/* Found a function. */
- sym = lookup_symbol (func_name, NULL, VAR_NAMESPACE, NULL, NULL);
+ sym = lookup_symbol (func_name, NULL, VAR_DOMAIN, NULL, NULL);
if (sym && SYMBOL_LANGUAGE (sym) != language_asm)
{
/* Don't use this trick for assembly source files. */
if (inst == 0xe1a0c00d) /* mov ip, sp */
continue;
+ if ((inst & 0xfffff000) == 0xe28dc000) /* add ip, sp #n */
+ continue;
+
+ if ((inst & 0xfffff000) == 0xe24dc000) /* sub ip, sp #n */
+ continue;
+
/* Some prologues begin with "str lr, [sp, #-4]!". */
if (inst == 0xe52de004) /* str lr, [sp, #-4]! */
continue;
2) which registers are saved on it
3) the offsets of saved regs
4) the offset from the stack pointer to the frame pointer
- This information is stored in the "extra" fields of the frame_info.
A typical Thumb function prologue would create this stack frame
(offsets relative to FP)
/* *INDENT-ON* */
static void
-thumb_scan_prologue (struct frame_info *fi)
+thumb_scan_prologue (CORE_ADDR prev_pc, struct arm_prologue_cache *cache)
{
CORE_ADDR prologue_start;
CORE_ADDR prologue_end;
int findmask = 0;
int i;
- /* Don't try to scan dummy frames. */
- if (fi != NULL
- && DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi), 0, 0))
- return;
-
- if (find_pc_partial_function (get_frame_pc (fi), NULL, &prologue_start, &prologue_end))
+ if (find_pc_partial_function (prev_pc, NULL, &prologue_start, &prologue_end))
{
struct symtab_and_line sal = find_pc_line (prologue_start, 0);
if (sal.line == 0) /* no line info, use current PC */
- prologue_end = get_frame_pc (fi);
+ prologue_end = prev_pc;
else if (sal.end < prologue_end) /* next line begins after fn end */
prologue_end = sal.end; /* (probably means no prologue) */
}
16 pushes, an add, and "mv fp,sp". */
prologue_end = prologue_start + 40;
- prologue_end = min (prologue_end, get_frame_pc (fi));
+ 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]. */
frame pointer, adjust the stack pointer, and save registers.
Do this until all basic prolog instructions are found. */
- get_frame_extra_info (fi)->framesize = 0;
+ cache->framesize = 0;
for (current_pc = prologue_start;
(current_pc < prologue_end) && ((findmask & 7) != 7);
current_pc += 2)
for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
if (mask & (1 << regno))
{
- get_frame_extra_info (fi)->framesize += 4;
- get_frame_saved_regs (fi)[saved_reg[regno]] =
- -(get_frame_extra_info (fi)->framesize);
+ cache->framesize += 4;
+ cache->saved_regs[saved_reg[regno]].addr = -cache->framesize;
/* Reset saved register map. */
saved_reg[regno] = regno;
}
offset = (insn & 0x7f) << 2; /* get scaled offset */
if (insn & 0x80) /* is it signed? (==subtracting) */
{
- get_frame_extra_info (fi)->frameoffset += offset;
+ cache->frameoffset += offset;
offset = -offset;
}
- get_frame_extra_info (fi)->framesize -= offset;
+ cache->framesize -= offset;
}
else if ((insn & 0xff00) == 0xaf00) /* add r7, sp, #imm */
{
findmask |= 2; /* setting of r7 found */
- get_frame_extra_info (fi)->framereg = THUMB_FP_REGNUM;
+ cache->framereg = THUMB_FP_REGNUM;
/* get scaled offset */
- get_frame_extra_info (fi)->frameoffset = (insn & 0xff) << 2;
+ cache->frameoffset = (insn & 0xff) << 2;
}
else if (insn == 0x466f) /* mov r7, sp */
{
findmask |= 2; /* setting of r7 found */
- get_frame_extra_info (fi)->framereg = THUMB_FP_REGNUM;
- get_frame_extra_info (fi)->frameoffset = 0;
+ 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 */
*/
static void
-arm_scan_prologue (struct frame_info *fi)
+arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cache)
{
- int regno, sp_offset, fp_offset;
- LONGEST return_value;
+ int regno, sp_offset, fp_offset, ip_offset;
CORE_ADDR prologue_start, prologue_end, current_pc;
+ CORE_ADDR prev_pc = frame_pc_unwind (next_frame);
/* Assume there is no frame until proven otherwise. */
- get_frame_extra_info (fi)->framereg = ARM_SP_REGNUM;
- get_frame_extra_info (fi)->framesize = 0;
- get_frame_extra_info (fi)->frameoffset = 0;
+ cache->framereg = ARM_SP_REGNUM;
+ cache->framesize = 0;
+ cache->frameoffset = 0;
/* Check for Thumb prologue. */
- if (arm_pc_is_thumb (get_frame_pc (fi)))
+ if (arm_pc_is_thumb (prev_pc))
{
- thumb_scan_prologue (fi);
+ thumb_scan_prologue (prev_pc, cache);
return;
}
/* Find the function prologue. If we can't find the function in
the symbol table, peek in the stack frame to find the PC. */
- if (find_pc_partial_function (get_frame_pc (fi), NULL, &prologue_start, &prologue_end))
+ if (find_pc_partial_function (prev_pc, NULL, &prologue_start, &prologue_end))
{
/* One way to find the end of the prologue (which works well
for unoptimized code) is to do the following:
struct symtab_and_line sal = find_pc_line (prologue_start, 0);
if (sal.line == 0)
- prologue_end = get_frame_pc (fi);
+ prologue_end = prev_pc;
else if (sal.end < prologue_end)
prologue_end = sal.end;
}
else
{
- /* Get address of the stmfd in the prologue of the callee;
- the saved PC is the address of the stmfd + 8. */
- if (!safe_read_memory_integer (get_frame_base (fi), 4, &return_value))
+ /* We have no symbol information. Our only option is to assume this
+ function has a standard stack frame and the normal frame register.
+ Then, we can find the value of our frame pointer on entrance to
+ the callee (or at the present moment if this is the innermost frame).
+ The value stored there should be the address of the stmfd + 8. */
+ CORE_ADDR frame_loc;
+ LONGEST return_value;
+
+ frame_loc = frame_unwind_register_unsigned (next_frame, ARM_FP_REGNUM);
+ if (!safe_read_memory_integer (frame_loc, 4, &return_value))
return;
else
{
}
}
+ if (prev_pc < prologue_end)
+ prologue_end = prev_pc;
+
/* Now search the prologue looking for instructions that set up the
frame pointer, adjust the stack pointer, and save registers.
in which case it is often (but not always) replaced by
"str lr, [sp, #-4]!". - Michael Snyder, 2002-04-23] */
- sp_offset = fp_offset = 0;
+ sp_offset = fp_offset = ip_offset = 0;
for (current_pc = prologue_start;
current_pc < prologue_end;
if (insn == 0xe1a0c00d) /* mov ip, sp */
{
+ ip_offset = 0;
+ continue;
+ }
+ else if ((insn & 0xfffff000) == 0xe28dc000) /* add ip, sp #n */
+ {
+ unsigned imm = insn & 0xff; /* immediate value */
+ unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */
+ imm = (imm >> rot) | (imm << (32 - rot));
+ ip_offset = imm;
+ continue;
+ }
+ else if ((insn & 0xfffff000) == 0xe24dc000) /* sub ip, sp #n */
+ {
+ unsigned imm = insn & 0xff; /* immediate value */
+ unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */
+ imm = (imm >> rot) | (imm << (32 - rot));
+ ip_offset = -imm;
continue;
}
else if (insn == 0xe52de004) /* str lr, [sp, #-4]! */
{
- /* Function is frameless: extra_info defaults OK? */
+ sp_offset -= 4;
+ cache->saved_regs[ARM_LR_REGNUM].addr = sp_offset;
continue;
}
else if ((insn & 0xffff0000) == 0xe92d0000)
if (mask & (1 << regno))
{
sp_offset -= 4;
- get_frame_saved_regs (fi)[regno] = sp_offset;
+ cache->saved_regs[regno].addr = sp_offset;
}
}
else if ((insn & 0xffffc000) == 0xe54b0000 || /* strb rx,[r11,#-n] */
unsigned imm = insn & 0xff; /* immediate value */
unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */
imm = (imm >> rot) | (imm << (32 - rot));
- fp_offset = -imm;
- get_frame_extra_info (fi)->framereg = ARM_FP_REGNUM;
+ fp_offset = -imm + ip_offset;
+ cache->framereg = ARM_FP_REGNUM;
}
else if ((insn & 0xfffff000) == 0xe24dd000) /* sub sp, sp #n */
{
{
sp_offset -= 12;
regno = ARM_F0_REGNUM + ((insn >> 12) & 0x07);
- get_frame_saved_regs (fi)[regno] = sp_offset;
+ cache->saved_regs[regno].addr = sp_offset;
}
else if ((insn & 0xffbf0fff) == 0xec2d0200) /* sfmfd f0, 4, [sp!] */
{
for (; fp_start_reg < fp_bound_reg; fp_start_reg++)
{
sp_offset -= 12;
- get_frame_saved_regs (fi)[fp_start_reg++] = sp_offset;
+ cache->saved_regs[fp_start_reg++].addr = sp_offset;
}
}
else if ((insn & 0xf0000000) != 0xe0000000)
/* The frame size is just the negative of the offset (from the
original SP) of the last thing thing we pushed on the stack.
The frame offset is [new FP] - [new SP]. */
- get_frame_extra_info (fi)->framesize = -sp_offset;
- if (get_frame_extra_info (fi)->framereg == ARM_FP_REGNUM)
- get_frame_extra_info (fi)->frameoffset = fp_offset - sp_offset;
+ cache->framesize = -sp_offset;
+ if (cache->framereg == ARM_FP_REGNUM)
+ cache->frameoffset = fp_offset - sp_offset;
else
- get_frame_extra_info (fi)->frameoffset = 0;
+ cache->frameoffset = 0;
}
-/* Find REGNUM on the stack. Otherwise, it's in an active register.
- One thing we might want to do here is to check REGNUM against the
- clobber mask, and somehow flag it as invalid if it isn't saved on
- the stack somewhere. This would provide a graceful failure mode
- when trying to get the value of caller-saves registers for an inner
- frame. */
-
-static CORE_ADDR
-arm_find_callers_reg (struct frame_info *fi, int regnum)
+static struct arm_prologue_cache *
+arm_make_prologue_cache (struct frame_info *next_frame)
{
- /* 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 = get_next_frame (fi))
- {
- if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi), 0, 0))
- {
- return deprecated_read_register_dummy (get_frame_pc (fi),
- get_frame_base (fi), regnum);
- }
- else if (get_frame_saved_regs (fi)[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 (get_frame_saved_regs (fi)[regnum],
- REGISTER_RAW_SIZE (regnum));
- }
- }
- return read_register (regnum);
-}
-/* Function: frame_chain Given a GDB frame, determine the address of
- the calling function's frame. This will be used to create a new
- GDB frame struct, and then DEPRECATED_INIT_EXTRA_FRAME_INFO and
- DEPRECATED_INIT_FRAME_PC will be called for the new frame. For
- ARM, we save the frame size when we initialize the frame_info. */
+ int reg;
+ struct arm_prologue_cache *cache;
+ CORE_ADDR unwound_fp;
-static CORE_ADDR
-arm_frame_chain (struct frame_info *fi)
-{
- CORE_ADDR caller_pc;
- int framereg = get_frame_extra_info (fi)->framereg;
+ cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache));
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
- if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi), 0, 0))
- /* A generic call dummy's frame is the same as caller's. */
- return get_frame_base (fi);
+ arm_scan_prologue (next_frame, cache);
- if (get_frame_pc (fi) < LOWEST_PC)
- return 0;
+ unwound_fp = frame_unwind_register_unsigned (next_frame, cache->framereg);
+ if (unwound_fp == 0)
+ return cache;
- /* If the caller is the startup code, we're at the end of the chain. */
- caller_pc = DEPRECATED_FRAME_SAVED_PC (fi);
+ cache->prev_sp = unwound_fp + cache->framesize - cache->frameoffset;
- /* If the caller is Thumb and the caller is ARM, or vice versa,
- the frame register of the caller is different from ours.
- So we must scan the prologue of the caller to determine its
- frame register number. */
- /* XXX Fixme, we should try to do this without creating a temporary
- caller_fi. */
- if (arm_pc_is_thumb (caller_pc) != arm_pc_is_thumb (get_frame_pc (fi)))
- {
- struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
- struct frame_info *caller_fi =
- deprecated_frame_xmalloc_with_cleanup (SIZEOF_FRAME_SAVED_REGS,
- sizeof (struct frame_extra_info));
-
- /* Now, scan the prologue and obtain the frame register. */
- deprecated_update_frame_pc_hack (caller_fi, caller_pc);
- arm_scan_prologue (caller_fi);
- framereg = get_frame_extra_info (caller_fi)->framereg;
-
- /* Deallocate the storage associated with the temporary frame
- created above. */
- do_cleanups (old_chain);
- }
+ /* Calculate actual addresses of saved registers using offsets
+ determined by arm_scan_prologue. */
+ for (reg = 0; reg < NUM_REGS; reg++)
+ if (trad_frame_addr_p (cache->saved_regs, reg))
+ cache->saved_regs[reg].addr += cache->prev_sp;
- /* If the caller used a frame register, return its value.
- Otherwise, return the caller's stack pointer. */
- if (framereg == ARM_FP_REGNUM || framereg == THUMB_FP_REGNUM)
- return arm_find_callers_reg (fi, framereg);
- else
- return get_frame_base (fi) + get_frame_extra_info (fi)->framesize;
+ return cache;
}
-/* This function actually figures out the frame address for a given pc
- and sp. This is tricky because we sometimes don't use an explicit
- frame pointer, and the previous stack pointer isn't necessarily
- recorded on the stack. The only reliable way to get this info is
- to examine the prologue. FROMLEAF is a little confusing, it means
- this is the next frame up the chain AFTER a frameless function. If
- this is true, then the frame value for this frame is still in the
- fp register. */
+/* Our frame ID for a normal frame is the current function's starting PC
+ and the caller's SP when we were called. */
static void
-arm_init_extra_frame_info (int fromleaf, struct frame_info *fi)
+arm_prologue_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
{
- int reg;
- CORE_ADDR sp;
+ struct arm_prologue_cache *cache;
+ struct frame_id id;
+ CORE_ADDR func;
- if (get_frame_saved_regs (fi) == NULL)
- frame_saved_regs_zalloc (fi);
+ if (*this_cache == NULL)
+ *this_cache = arm_make_prologue_cache (next_frame);
+ cache = *this_cache;
- frame_extra_info_zalloc (fi, sizeof (struct frame_extra_info));
+ func = frame_func_unwind (next_frame);
- get_frame_extra_info (fi)->framesize = 0;
- get_frame_extra_info (fi)->frameoffset = 0;
- get_frame_extra_info (fi)->framereg = 0;
+ /* This is meant to halt the backtrace at "_start". Make sure we
+ don't halt it at a generic dummy frame. */
+ if (func <= LOWEST_PC)
+ return;
- if (get_next_frame (fi))
- deprecated_update_frame_pc_hack (fi, DEPRECATED_FRAME_SAVED_PC (get_next_frame (fi)));
+ /* If we've hit a wall, stop. */
+ if (cache->prev_sp == 0)
+ return;
- memset (get_frame_saved_regs (fi), '\000', sizeof get_frame_saved_regs (fi));
+ id = frame_id_build (cache->prev_sp, func);
+ *this_id = id;
+}
- /* Compute stack pointer for this frame. We use this value for both
- the sigtramp and call dummy cases. */
- if (!get_next_frame (fi))
- sp = read_sp();
- else if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (get_next_frame (fi)), 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 (get_frame_pc (get_next_frame (fi)),
- get_frame_base (get_next_frame (fi)),
- ARM_SP_REGNUM);
- else
- sp = (get_frame_base (get_next_frame (fi))
- - get_frame_extra_info (get_next_frame (fi))->frameoffset
- + get_frame_extra_info (get_next_frame (fi))->framesize);
-
- /* Determine whether or not we're in a sigtramp frame.
- Unfortunately, it isn't sufficient to test (get_frame_type (fi)
- == SIGTRAMP_FRAME) because this value is sometimes set after
- invoking DEPRECATED_INIT_EXTRA_FRAME_INFO. So we test *both*
- (get_frame_type (fi) == SIGTRAMP_FRAME) and PC_IN_SIGTRAMP to
- determine if we need to use the sigcontext addresses for the
- saved registers.
-
- Note: If an ARM 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 PC_IN_SIGTRAMP. */
-
- /* FIXME: cagney/2002-11-18: This problem will go away once
- frame.c:get_prev_frame() is modified to set the frame's type
- before calling functions like this. */
-
- if (SIGCONTEXT_REGISTER_ADDRESS_P ()
- && ((get_frame_type (fi) == SIGTRAMP_FRAME) || PC_IN_SIGTRAMP (get_frame_pc (fi), (char *)0)))
+static void
+arm_prologue_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int prev_regnum,
+ int *optimized,
+ enum lval_type *lvalp,
+ CORE_ADDR *addrp,
+ int *realnump,
+ gdb_byte *valuep)
+{
+ struct arm_prologue_cache *cache;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_make_prologue_cache (next_frame);
+ cache = *this_cache;
+
+ /* If we are asked to unwind the PC, then we need to return the LR
+ instead. The saved value of PC points into this frame's
+ prologue, not the next frame's resume location. */
+ if (prev_regnum == ARM_PC_REGNUM)
+ prev_regnum = ARM_LR_REGNUM;
+
+ /* SP is generally not saved to the stack, but this frame is
+ identified by NEXT_FRAME's stack pointer at the time of the call.
+ The value was already reconstructed into PREV_SP. */
+ if (prev_regnum == ARM_SP_REGNUM)
{
- for (reg = 0; reg < NUM_REGS; reg++)
- get_frame_saved_regs (fi)[reg] = SIGCONTEXT_REGISTER_ADDRESS (sp, get_frame_pc (fi), reg);
-
- /* FIXME: What about thumb mode? */
- get_frame_extra_info (fi)->framereg = ARM_SP_REGNUM;
- deprecated_update_frame_base_hack (fi, read_memory_integer (get_frame_saved_regs (fi)[get_frame_extra_info (fi)->framereg], REGISTER_RAW_SIZE (get_frame_extra_info (fi)->framereg)));
- get_frame_extra_info (fi)->framesize = 0;
- get_frame_extra_info (fi)->frameoffset = 0;
-
+ *lvalp = not_lval;
+ if (valuep)
+ store_unsigned_integer (valuep, 4, cache->prev_sp);
+ return;
}
- else
- {
- arm_scan_prologue (fi);
-
- if (!get_next_frame (fi))
- /* This is the innermost frame? */
- deprecated_update_frame_base_hack (fi, read_register (get_frame_extra_info (fi)->framereg));
- else if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (get_next_frame (fi)), 0, 0))
- /* Next inner most frame is a dummy, just grab its frame.
- Dummy frames always have the same FP as their caller. */
- deprecated_update_frame_base_hack (fi, get_frame_base (get_next_frame (fi)));
- else if (get_frame_extra_info (fi)->framereg == ARM_FP_REGNUM
- || get_frame_extra_info (fi)->framereg == THUMB_FP_REGNUM)
- {
- /* not the innermost frame */
- /* If we have an FP, the callee saved it. */
- if (get_frame_saved_regs (get_next_frame (fi))[get_frame_extra_info (fi)->framereg] != 0)
- deprecated_update_frame_base_hack (fi, read_memory_integer (get_frame_saved_regs (get_next_frame (fi))[get_frame_extra_info (fi)->framereg], 4));
- else if (fromleaf)
- /* If we were called by a frameless fn. then our frame is
- still in the frame pointer register on the board... */
- deprecated_update_frame_base_hack (fi, read_fp ());
- }
- /* Calculate actual addresses of saved registers using offsets
- determined by arm_scan_prologue. */
- for (reg = 0; reg < NUM_REGS; reg++)
- if (get_frame_saved_regs (fi)[reg] != 0)
- get_frame_saved_regs (fi)[reg]
- += (get_frame_base (fi)
- + get_frame_extra_info (fi)->framesize
- - get_frame_extra_info (fi)->frameoffset);
- }
+ trad_frame_get_prev_register (next_frame, cache->saved_regs, prev_regnum,
+ optimized, lvalp, addrp, realnump, valuep);
}
+struct frame_unwind arm_prologue_unwind = {
+ NORMAL_FRAME,
+ arm_prologue_this_id,
+ arm_prologue_prev_register
+};
-/* Find the caller of this frame. We do this by seeing if ARM_LR_REGNUM
- is saved in the stack anywhere, otherwise we get it from the
- registers.
-
- The old definition of this function was a macro:
- #define FRAME_SAVED_PC(FRAME) \
- ADDR_BITS_REMOVE (read_memory_integer ((FRAME)->frame - 4, 4)) */
+static const struct frame_unwind *
+arm_prologue_unwind_sniffer (struct frame_info *next_frame)
+{
+ return &arm_prologue_unwind;
+}
-static CORE_ADDR
-arm_frame_saved_pc (struct frame_info *fi)
+static struct arm_prologue_cache *
+arm_make_stub_cache (struct frame_info *next_frame)
{
- /* If a dummy frame, pull the PC out of the frame's register buffer. */
- if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi), 0, 0))
- return deprecated_read_register_dummy (get_frame_pc (fi),
- get_frame_base (fi), ARM_PC_REGNUM);
+ int reg;
+ struct arm_prologue_cache *cache;
+ CORE_ADDR unwound_fp;
- if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi),
- (get_frame_base (fi)
- - get_frame_extra_info (fi)->frameoffset),
- get_frame_base (fi)))
- {
- return read_memory_integer (get_frame_saved_regs (fi)[ARM_PC_REGNUM],
- REGISTER_RAW_SIZE (ARM_PC_REGNUM));
- }
- else
- {
- CORE_ADDR pc = arm_find_callers_reg (fi, ARM_LR_REGNUM);
- return IS_THUMB_ADDR (pc) ? UNMAKE_THUMB_ADDR (pc) : pc;
- }
-}
+ cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache));
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
-/* Return the frame address. On ARM, it is R11; on Thumb it is R7.
- Examine the Program Status Register to decide which state we're in. */
+ cache->prev_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
-static CORE_ADDR
-arm_read_fp (void)
-{
- if (read_register (ARM_PS_REGNUM) & 0x20) /* Bit 5 is Thumb state bit */
- return read_register (THUMB_FP_REGNUM); /* R7 if Thumb */
- else
- return read_register (ARM_FP_REGNUM); /* R11 if ARM */
+ return cache;
}
-/* Store into a struct frame_saved_regs the addresses of the saved
- registers of frame described by FRAME_INFO. This includes special
- registers such as PC and FP saved in special ways in the stack
- frame. SP is even more special: the address we return for it IS
- the sp for the next frame. */
+/* Our frame ID for a stub frame is the current SP and LR. */
static void
-arm_frame_init_saved_regs (struct frame_info *fip)
+arm_stub_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
{
+ struct arm_prologue_cache *cache;
- if (get_frame_saved_regs (fip))
- return;
-
- arm_init_extra_frame_info (0, fip);
-}
-
-/* Set the return address for a generic dummy frame. ARM uses the
- entry point. */
+ if (*this_cache == NULL)
+ *this_cache = arm_make_stub_cache (next_frame);
+ cache = *this_cache;
-static CORE_ADDR
-arm_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
-{
- write_register (ARM_LR_REGNUM, CALL_DUMMY_ADDRESS ());
- return sp;
+ *this_id = frame_id_build (cache->prev_sp,
+ frame_pc_unwind (next_frame));
}
-/* Push an empty stack frame, to record the current PC, etc. */
+struct frame_unwind arm_stub_unwind = {
+ NORMAL_FRAME,
+ arm_stub_this_id,
+ arm_prologue_prev_register
+};
-static void
-arm_push_dummy_frame (void)
+static const struct frame_unwind *
+arm_stub_unwind_sniffer (struct frame_info *next_frame)
{
- CORE_ADDR old_sp = read_register (ARM_SP_REGNUM);
- CORE_ADDR sp = old_sp;
- CORE_ADDR fp, prologue_start;
- int regnum;
+ char dummy[4];
- /* Push the two dummy prologue instructions in reverse order,
- so that they'll be in the correct low-to-high order in memory. */
- /* sub fp, ip, #4 */
- sp = push_word (sp, 0xe24cb004);
- /* stmdb sp!, {r0-r10, fp, ip, lr, pc} */
- prologue_start = sp = push_word (sp, 0xe92ddfff);
+ if (in_plt_section (frame_unwind_address_in_block (next_frame), NULL)
+ || target_read_memory (frame_pc_unwind (next_frame), dummy, 4) != 0)
+ return &arm_stub_unwind;
- /* Push a pointer to the dummy prologue + 12, because when stm
- instruction stores the PC, it stores the address of the stm
- instruction itself plus 12. */
- fp = sp = push_word (sp, prologue_start + 12);
+ return NULL;
+}
- /* Push the processor status. */
- sp = push_word (sp, read_register (ARM_PS_REGNUM));
+static CORE_ADDR
+arm_normal_frame_base (struct frame_info *next_frame, void **this_cache)
+{
+ struct arm_prologue_cache *cache;
- /* Push all 16 registers starting with r15. */
- for (regnum = ARM_PC_REGNUM; regnum >= 0; regnum--)
- sp = push_word (sp, read_register (regnum));
+ if (*this_cache == NULL)
+ *this_cache = arm_make_prologue_cache (next_frame);
+ cache = *this_cache;
- /* Update fp (for both Thumb and ARM) and sp. */
- write_register (ARM_FP_REGNUM, fp);
- write_register (THUMB_FP_REGNUM, fp);
- write_register (ARM_SP_REGNUM, sp);
+ return cache->prev_sp + cache->frameoffset - cache->framesize;
}
-/* CALL_DUMMY_WORDS:
- This sequence of words is the instructions
+struct frame_base arm_normal_base = {
+ &arm_prologue_unwind,
+ arm_normal_frame_base,
+ arm_normal_frame_base,
+ arm_normal_frame_base
+};
- mov lr,pc
- mov pc,r4
- illegal
+static struct arm_prologue_cache *
+arm_make_sigtramp_cache (struct frame_info *next_frame)
+{
+ struct arm_prologue_cache *cache;
+ int reg;
- Note this is 12 bytes. */
+ cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache));
-static LONGEST arm_call_dummy_words[] =
-{
- 0xe1a0e00f, 0xe1a0f004, 0xe7ffdefe
-};
+ cache->prev_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
-/* Adjust the call_dummy_breakpoint_offset for the bp_call_dummy
- breakpoint to the proper address in the call dummy, so that
- `finish' after a stop in a call dummy works.
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
- FIXME rearnsha 2002-02018: Tweeking current_gdbarch is not an
- optimal solution, but the call to arm_fix_call_dummy is immediately
- followed by a call to run_stack_dummy, which is the only function
- where call_dummy_breakpoint_offset is actually used. */
+ 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));
-static void
-arm_set_call_dummy_breakpoint_offset (void)
-{
- if (caller_is_thumb)
- set_gdbarch_call_dummy_breakpoint_offset (current_gdbarch, 4);
- else
- set_gdbarch_call_dummy_breakpoint_offset (current_gdbarch, 8);
+ return cache;
}
-/* Fix up the call dummy, based on whether the processor is currently
- in Thumb or ARM mode, and whether the target function is Thumb or
- ARM. There are three different situations requiring three
- different dummies:
+static void
+arm_sigtramp_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct arm_prologue_cache *cache;
- * ARM calling ARM: uses the call dummy in tm-arm.h, which has already
- been copied into the dummy parameter to this function.
- * ARM calling Thumb: uses the call dummy in tm-arm.h, but with the
- "mov pc,r4" instruction patched to be a "bx r4" instead.
- * Thumb calling anything: uses the Thumb dummy defined below, which
- works for calling both ARM and Thumb functions.
+ if (*this_cache == NULL)
+ *this_cache = arm_make_sigtramp_cache (next_frame);
+ cache = *this_cache;
- All three call dummies expect to receive the target function
- address in R4, with the low bit set if it's a Thumb function. */
+ /* 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));
+}
static void
-arm_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
- struct value **args, struct type *type, int gcc_p)
-{
- static short thumb_dummy[4] =
- {
- 0xf000, 0xf801, /* bl label */
- 0xdf18, /* swi 24 */
- 0x4720, /* label: bx r4 */
- };
- static unsigned long arm_bx_r4 = 0xe12fff14; /* bx r4 instruction */
-
- /* Set flag indicating whether the current PC is in a Thumb function. */
- caller_is_thumb = arm_pc_is_thumb (read_pc ());
- arm_set_call_dummy_breakpoint_offset ();
-
- /* If the target function is Thumb, set the low bit of the function
- address. And if the CPU is currently in ARM mode, patch the
- second instruction of call dummy to use a BX instruction to
- switch to Thumb mode. */
- target_is_thumb = arm_pc_is_thumb (fun);
- if (target_is_thumb)
- {
- fun |= 1;
- if (!caller_is_thumb)
- store_unsigned_integer (dummy + 4, sizeof (arm_bx_r4), arm_bx_r4);
- }
+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,
+ gdb_byte *valuep)
+{
+ struct arm_prologue_cache *cache;
- /* If the CPU is currently in Thumb mode, use the Thumb call dummy
- instead of the ARM one that's already been copied. This will
- work for both Thumb and ARM target functions. */
- if (caller_is_thumb)
- {
- int i;
- char *p = dummy;
- int len = sizeof (thumb_dummy) / sizeof (thumb_dummy[0]);
+ if (*this_cache == NULL)
+ *this_cache = arm_make_sigtramp_cache (next_frame);
+ cache = *this_cache;
- for (i = 0; i < len; i++)
- {
- store_unsigned_integer (p, sizeof (thumb_dummy[0]), thumb_dummy[i]);
- p += sizeof (thumb_dummy[0]);
- }
- }
-
- /* Put the target address in r4; the call dummy will copy this to
- the PC. */
- write_register (4, fun);
+ trad_frame_get_prev_register (next_frame, cache->saved_regs, prev_regnum,
+ optimized, lvalp, addrp, realnump, valuep);
}
-/* Pop the current frame. So long as the frame info has been
- initialized properly (see arm_init_extra_frame_info), this code
- works for dummy frames as well as regular frames. I.e, there's no
- need to have a special case for dummy frames. */
-static void
-arm_pop_frame (void)
+struct frame_unwind arm_sigtramp_unwind = {
+ SIGTRAMP_FRAME,
+ arm_sigtramp_this_id,
+ arm_sigtramp_prev_register
+};
+
+static const struct frame_unwind *
+arm_sigtramp_unwind_sniffer (struct frame_info *next_frame)
{
- int regnum;
- struct frame_info *frame = get_current_frame ();
- CORE_ADDR old_SP = (get_frame_base (frame)
- - get_frame_extra_info (frame)->frameoffset
- + get_frame_extra_info (frame)->framesize);
+ if (SIGCONTEXT_REGISTER_ADDRESS_P ()
+ && legacy_pc_in_sigtramp (frame_pc_unwind (next_frame), (char *) 0))
+ return &arm_sigtramp_unwind;
- if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (frame),
- get_frame_base (frame),
- get_frame_base (frame)))
- {
- generic_pop_dummy_frame ();
- flush_cached_frames ();
- return;
- }
+ return NULL;
+}
- for (regnum = 0; regnum < NUM_REGS; regnum++)
- if (get_frame_saved_regs (frame)[regnum] != 0)
- write_register (regnum,
- read_memory_integer (get_frame_saved_regs (frame)[regnum],
- REGISTER_RAW_SIZE (regnum)));
+/* 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
+ arm_push_dummy_call, and the PC needs to match the dummy frame's
+ breakpoint. */
+
+static struct frame_id
+arm_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_id_build (frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM),
+ frame_pc_unwind (next_frame));
+}
- write_register (ARM_PC_REGNUM, DEPRECATED_FRAME_SAVED_PC (frame));
- write_register (ARM_SP_REGNUM, old_SP);
+/* Given THIS_FRAME, find the previous frame's resume PC (which will
+ be used to construct the previous frame's ID, after looking up the
+ containing function). */
- flush_cached_frames ();
+static CORE_ADDR
+arm_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+ CORE_ADDR pc;
+ pc = frame_unwind_register_unsigned (this_frame, ARM_PC_REGNUM);
+ return IS_THUMB_ADDR (pc) ? UNMAKE_THUMB_ADDR (pc) : pc;
+}
+
+static CORE_ADDR
+arm_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+ return frame_unwind_register_unsigned (this_frame, ARM_SP_REGNUM);
}
/* When arguments must be pushed onto the stack, they go on in reverse
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, struct regcache *regcache,
- CORE_ADDR dummy_addr, int nargs, struct value **args,
- CORE_ADDR sp, int struct_return, CORE_ADDR struct_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)
{
int argnum;
int argreg;
int nstack;
struct stack_item *si = NULL;
- /* Set the return address. For the ARM, the return breakpoint is always
- at DUMMY_ADDR. */
+ /* Set the return address. For the ARM, the return breakpoint is
+ always at BP_ADDR. */
/* XXX Fix for Thumb. */
- regcache_cooked_write_unsigned (regcache, ARM_LR_REGNUM, dummy_addr);
+ regcache_cooked_write_unsigned (regcache, ARM_LR_REGNUM, bp_addr);
/* Walk through the list of args and determine how large a temporary
stack is required. Need to take care here as structs may be
/* 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 * REGISTER_SIZE - 1);
+ sp &= ~(CORE_ADDR)(2 * DEPRECATED_REGISTER_SIZE - 1);
/* The struct_return pointer occupies the first parameter
passing register. */
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
&& target_type != NULL
&& TYPE_CODE_FUNC == TYPE_CODE (target_type))
{
- CORE_ADDR regval = extract_address (val, len);
+ CORE_ADDR regval = extract_unsigned_integer (val, len);
if (arm_pc_is_thumb (regval))
{
val = alloca (len);
- store_address (val, len, MAKE_THUMB_ADDR (regval));
+ store_unsigned_integer (val, len, MAKE_THUMB_ADDR (regval));
}
}
registers and stack. */
while (len > 0)
{
- int partial_len = len < REGISTER_SIZE ? len : REGISTER_SIZE;
+ int partial_len = len < DEPRECATED_REGISTER_SIZE ? len : DEPRECATED_REGISTER_SIZE;
if (argreg <= ARM_LAST_ARG_REGNUM)
{
/* The argument is being passed in a general purpose
register. */
- CORE_ADDR regval = extract_address (val, partial_len);
+ CORE_ADDR regval = extract_unsigned_integer (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));
+ phex (regval, DEPRECATED_REGISTER_SIZE));
regcache_cooked_write_unsigned (regcache, argreg, regval);
argreg++;
}
if (arm_debug)
fprintf_unfiltered (gdb_stdlog, "arg %d @ sp + %d\n",
argnum, nstack);
- si = push_stack_item (si, val, REGISTER_SIZE);
- nstack += REGISTER_SIZE;
+ si = push_stack_item (si, val, DEPRECATED_REGISTER_SIZE);
+ nstack += DEPRECATED_REGISTER_SIZE;
}
len -= partial_len;
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);
+ unsigned long status = read_register (ARM_FPS_REGNUM);
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);
}
register N. */
static struct type *
-arm_register_type (int regnum)
+arm_register_type (struct gdbarch *gdbarch, int regnum)
{
if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS)
{
arm_register_byte (int regnum)
{
if (regnum < ARM_F0_REGNUM)
- return regnum * INT_REGISTER_RAW_SIZE;
+ return regnum * INT_REGISTER_SIZE;
else if (regnum < ARM_PS_REGNUM)
- return (NUM_GREGS * INT_REGISTER_RAW_SIZE
- + (regnum - ARM_F0_REGNUM) * FP_REGISTER_RAW_SIZE);
+ return (NUM_GREGS * INT_REGISTER_SIZE
+ + (regnum - ARM_F0_REGNUM) * FP_REGISTER_SIZE);
else
- return (NUM_GREGS * INT_REGISTER_RAW_SIZE
- + NUM_FREGS * FP_REGISTER_RAW_SIZE
+ return (NUM_GREGS * INT_REGISTER_SIZE
+ + NUM_FREGS * FP_REGISTER_SIZE
+ (regnum - ARM_FPS_REGNUM) * STATUS_REGISTER_SIZE);
}
-/* Number of bytes of storage in the actual machine representation for
- register N. All registers are 4 bytes, except fp0 - fp7, which are
- 12 bytes in length. */
-
-static int
-arm_register_raw_size (int regnum)
-{
- if (regnum < ARM_F0_REGNUM)
- return INT_REGISTER_RAW_SIZE;
- else if (regnum < ARM_FPS_REGNUM)
- return FP_REGISTER_RAW_SIZE;
- else
- return STATUS_REGISTER_SIZE;
-}
-
-/* Number of bytes of storage in a program's representation
- for register N. */
-static int
-arm_register_virtual_size (int regnum)
-{
- if (regnum < ARM_F0_REGNUM)
- return INT_REGISTER_VIRTUAL_SIZE;
- else if (regnum < ARM_FPS_REGNUM)
- return FP_REGISTER_VIRTUAL_SIZE;
- else
- return STATUS_REGISTER_SIZE;
-}
-
/* Map GDB internal REGNUM onto the Arm simulator register numbers. */
static int
arm_register_sim_regno (int regnum)
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
/* Fetch the saved PC from the stack. It's stored above
all of the other registers. */
- offset = bitcount (bits (inst1, 0, 7)) * REGISTER_SIZE;
+ 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 = ADDR_BITS_REMOVE (nextpc);
if (nextpc == pc)
- error ("Infinite loop detected");
+ error (_("Infinite loop detected"));
}
else if ((inst1 & 0xf000) == 0xd000) /* conditional branch */
{
{
nextpc = pc_val + (sbits (inst1, 0, 10) << 1);
}
- else if ((inst1 & 0xf800) == 0xf000) /* long branch with link */
+ else if ((inst1 & 0xf800) == 0xf000) /* long branch with link, and blx */
{
unsigned short inst2 = read_memory_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. */
+ if (bits (inst2, 11, 12) == 1)
+ nextpc = nextpc & 0xfffffffc;
+ }
+ else if ((inst1 & 0xff00) == 0x4700) /* bx REG, blx REG */
+ {
+ if (bits (inst1, 3, 6) == 0x0f)
+ nextpc = pc_val;
+ else
+ nextpc = read_register (bits (inst1, 3, 6));
+
+ nextpc = ADDR_BITS_REMOVE (nextpc);
+ if (nextpc == pc)
+ error (_("Infinite loop detected"));
}
return nextpc;
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)
+ {
+ 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"));
+
+ return nextpc;
+ }
/* Multiply into PC */
c = (status & FLAG_C) ? 1 : 0;
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 = BranchDest (pc, this_instr);
+ /* BLX */
+ if (bits (this_instr, 28, 31) == INST_NV)
+ nextpc |= bit (this_instr, 24) << 1;
+
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);
}
}
{
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:
{
/* The value is in register F0 in internal format. We need to
extract the raw value and then convert it to the desired
internal type. */
- bfd_byte tmpbuf[FP_REGISTER_RAW_SIZE];
+ bfd_byte tmpbuf[FP_REGISTER_SIZE];
regcache_cooked_read (regs, ARM_F0_REGNUM, tmpbuf);
convert_from_extended (floatformat_from_type (type), tmpbuf,
regcache_cooked_read (regs, ARM_A1_REGNUM, valbuf);
if (TYPE_LENGTH (type) > 4)
regcache_cooked_read (regs, ARM_A1_REGNUM + 1,
- valbuf + INT_REGISTER_RAW_SIZE);
+ valbuf + INT_REGISTER_SIZE);
break;
default:
internal_error
(__FILE__, __LINE__,
- "arm_extract_return_value: Floating point model not supported");
+ _("arm_extract_return_value: Floating point model not supported"));
break;
}
}
anything special for small big-endian values. */
regcache_cooked_read_unsigned (regs, regno++, &tmp);
store_unsigned_integer (valbuf,
- (len > INT_REGISTER_RAW_SIZE
- ? INT_REGISTER_RAW_SIZE : len),
+ (len > INT_REGISTER_SIZE
+ ? INT_REGISTER_SIZE : len),
tmp);
- len -= INT_REGISTER_RAW_SIZE;
- valbuf += INT_REGISTER_RAW_SIZE;
+ len -= INT_REGISTER_SIZE;
+ valbuf += INT_REGISTER_SIZE;
}
}
else
registers with 32-bit load instruction(s). */
int len = TYPE_LENGTH (type);
int regno = ARM_A1_REGNUM;
- bfd_byte tmpbuf[INT_REGISTER_RAW_SIZE];
+ bfd_byte tmpbuf[INT_REGISTER_SIZE];
while (len > 0)
{
regcache_cooked_read (regs, regno++, tmpbuf);
memcpy (valbuf, tmpbuf,
- len > INT_REGISTER_RAW_SIZE ? INT_REGISTER_RAW_SIZE : len);
- len -= INT_REGISTER_RAW_SIZE;
- valbuf += INT_REGISTER_RAW_SIZE;
+ len > INT_REGISTER_SIZE ? INT_REGISTER_SIZE : len);
+ len -= INT_REGISTER_SIZE;
+ valbuf += INT_REGISTER_SIZE;
}
}
}
-/* 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;
- register enum type_code code;
+ enum type_code code;
+
+ CHECK_TYPEDEF (type);
/* In the ARM ABI, "integer" like aggregate types are returned in
registers. For an aggregate type to be integer like, its size
- must be less than or equal to REGISTER_SIZE and the offset of
- each addressable subfield must be zero. Note that bit fields are
- not addressable, and all addressable subfields of unions always
- start at offset zero.
+ must be less than or equal to DEPRECATED_REGISTER_SIZE and the
+ offset of each addressable subfield must be zero. Note that bit
+ fields are not addressable, and all addressable subfields of
+ unions always start at offset zero.
This function is based on the behaviour of GCC 2.95.1.
See: gcc/arm.c: arm_return_in_memory() for details.
/* All aggregate types that won't fit in a register must be returned
in memory. */
- if (TYPE_LENGTH (type) > REGISTER_SIZE)
+ if (TYPE_LENGTH (type) > DEPRECATED_REGISTER_SIZE)
{
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);
int i;
/* Need to check if this struct/union is "integer" like. For
this to be true, its size must be less than or equal to
- REGISTER_SIZE and the offset of each addressable subfield
- must be zero. Note that bit fields are not addressable, and
- unions always start at offset zero. If any of the subfields
- is a floating point type, the struct/union cannot be an
- integer type. */
+ DEPRECATED_REGISTER_SIZE and the offset of each addressable
+ subfield must be zero. Note that bit fields are not
+ addressable, and unions always start at offset zero. If any
+ of the subfields is a floating point type, the struct/union
+ cannot be an integer type. */
/* For each field in the object, check:
1) Is it FP? --> yes, nRc = 1;
for (i = 0; i < TYPE_NFIELDS (type); i++)
{
enum type_code field_type_code;
- field_type_code = TYPE_CODE (TYPE_FIELD_TYPE (type, i));
+ field_type_code = TYPE_CODE (check_typedef (TYPE_FIELD_TYPE (type, i)));
/* Is it a floating point type field? */
if (field_type_code == TYPE_CODE_FLT)
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[ARM_MAX_REGISTER_RAW_SIZE];
+ char buf[MAX_REGISTER_SIZE];
- switch (arm_get_fp_model (current_gdbarch))
+ switch (gdbarch_tdep (current_gdbarch)->fp_model)
{
case ARM_FLOAT_FPA:
regcache_cooked_write (regs, ARM_A1_REGNUM, valbuf);
if (TYPE_LENGTH (type) > 4)
regcache_cooked_write (regs, ARM_A1_REGNUM + 1,
- valbuf + INT_REGISTER_RAW_SIZE);
+ valbuf + INT_REGISTER_SIZE);
break;
default:
internal_error
(__FILE__, __LINE__,
- "arm_store_return_value: Floating point model not supported");
+ _("arm_store_return_value: Floating point model not supported"));
break;
}
}
{
/* Values of one word or less are zero/sign-extended and
returned in r0. */
- bfd_byte tmpbuf[INT_REGISTER_RAW_SIZE];
+ bfd_byte tmpbuf[INT_REGISTER_SIZE];
LONGEST val = unpack_long (type, valbuf);
- store_signed_integer (tmpbuf, INT_REGISTER_RAW_SIZE, val);
+ store_signed_integer (tmpbuf, INT_REGISTER_SIZE, val);
regcache_cooked_write (regs, ARM_A1_REGNUM, tmpbuf);
}
else
while (len > 0)
{
regcache_cooked_write (regs, regno++, valbuf);
- len -= INT_REGISTER_RAW_SIZE;
- valbuf += INT_REGISTER_RAW_SIZE;
+ len -= INT_REGISTER_SIZE;
+ valbuf += INT_REGISTER_SIZE;
}
}
}
registers with 32-bit load instruction(s). */
int len = TYPE_LENGTH (type);
int regno = ARM_A1_REGNUM;
- bfd_byte tmpbuf[INT_REGISTER_RAW_SIZE];
+ bfd_byte tmpbuf[INT_REGISTER_SIZE];
while (len > 0)
{
memcpy (tmpbuf, valbuf,
- len > INT_REGISTER_RAW_SIZE ? INT_REGISTER_RAW_SIZE : len);
+ len > INT_REGISTER_SIZE ? INT_REGISTER_SIZE : len);
regcache_cooked_write (regs, regno++, tmpbuf);
- len -= INT_REGISTER_RAW_SIZE;
- valbuf += INT_REGISTER_RAW_SIZE;
+ len -= INT_REGISTER_SIZE;
+ valbuf += INT_REGISTER_SIZE;
}
}
}
+
+/* Handle function return values. */
+
+static enum return_value_convention
+arm_return_value (struct gdbarch *gdbarch, struct type *valtype,
+ struct regcache *regcache, void *readbuf,
+ const void *writebuf)
+{
+ if (TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+ || TYPE_CODE (valtype) == TYPE_CODE_UNION
+ || TYPE_CODE (valtype) == TYPE_CODE_ARRAY)
+ {
+ if (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)
{
CORE_ADDR jb_addr;
- char buf[INT_REGISTER_RAW_SIZE];
+ char buf[INT_REGISTER_SIZE];
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
jb_addr = read_register (ARM_A1_REGNUM);
if (target_read_memory (jb_addr + tdep->jb_pc * tdep->jb_elt_size, buf,
- INT_REGISTER_RAW_SIZE))
+ INT_REGISTER_SIZE))
return 0;
- *pc = extract_address (buf, INT_REGISTER_RAW_SIZE);
+ *pc = extract_unsigned_integer (buf, INT_REGISTER_SIZE);
return 1;
}
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 (char *args, int from_tty,
- struct cmd_list_element *c)
+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
+ if (arm_fp_model == ARM_FLOAT_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 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
+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_abi_global == ARM_ABI_AUTO
+ && gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
+ 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 void
set_disassembly_style (void)
{
- const char *setname, *setdesc, **regnames;
+ const char *setname, *setdesc, *const *regnames;
int numregs, j;
/* Find the style that the user wants in the opcodes table. */
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 ();
-}
-
-/* Fetch, and possibly build, an appropriate link_map_offsets structure
- for ARM linux targets using the struct offsets defined in <link.h>.
- Note, however, that link.h is not actually referred to in this file.
- Instead, the relevant structs offsets were obtained from examining
- link.h. (We can't refer to link.h from this file because the host
- system won't necessarily have it, or if it does, the structs which
- it defines will refer to the host system, not the target). */
-
-struct link_map_offsets *
-arm_linux_svr4_fetch_link_map_offsets (void)
-{
- static struct link_map_offsets lmo;
- static struct link_map_offsets *lmp = 0;
-
- if (lmp == 0)
- {
- lmp = &lmo;
-
- lmo.r_debug_size = 8; /* Actual size is 20, but this is all we
- need. */
-
- lmo.r_map_offset = 4;
- lmo.r_map_size = 4;
-
- lmo.link_map_size = 20; /* Actual size is 552, but this is all we
- need. */
-
- lmo.l_addr_offset = 0;
- lmo.l_addr_size = 4;
-
- lmo.l_name_offset = 4;
- lmo.l_name_size = 4;
-
- lmo.l_next_offset = 12;
- lmo.l_next_size = 4;
-
- lmo.l_prev_offset = 16;
- lmo.l_prev_size = 4;
- }
-
- return lmp;
-}
-
/* Test whether the coff symbol specific value corresponds to a Thumb
function. */
MSYMBOL_SET_SPECIAL (msym);
}
+static void
+arm_write_pc (CORE_ADDR pc, ptid_t ptid)
+{
+ write_register_pid (ARM_PC_REGNUM, pc, ptid);
+
+ /* If necessary, set the T bit. */
+ if (arm_apcs_32)
+ {
+ CORE_ADDR val = read_register_pid (ARM_PS_REGNUM, ptid);
+ if (arm_pc_is_thumb (pc))
+ write_register_pid (ARM_PS_REGNUM, val | 0x20, ptid);
+ else
+ write_register_pid (ARM_PS_REGNUM, val & ~(CORE_ADDR) 0x20, ptid);
+ }
+}
\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;
- /* Try to deterimine the ABI of the object we are loading. */
+ /* If we have an object to base this architecture on, try to determine
+ its ABI. */
- if (info.abfd != NULL && info.osabi == GDB_OSABI_UNKNOWN)
+ if (arm_abi == ARM_ABI_AUTO && info.abfd != NULL)
{
+ int ei_osabi;
+
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];
+ 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 e_flags, eabi_ver;
+
+ e_flags = elf_elfheader (info.abfd)->e_flags;
+ 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:
+ 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:
+ warning (_("unknown ARM EABI version 0x%x"), eabi_ver);
+ arm_abi = ARM_ABI_APCS;
+ 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;
- tdep = xmalloc (sizeof (struct gdbarch_tdep));
- gdbarch = gdbarch_alloc (&info, tdep);
+ 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. */
- /* NOTE: cagney/2002-12-06: This can be deleted when this arch is
- ready to unwind the PC first (see frame.c:get_prev_frame()). */
- set_gdbarch_deprecated_init_frame_pc (gdbarch, init_frame_pc_default);
+ 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. */
- tdep->fp_model = ARM_FLOAT_SOFT_FPA;
+ /* 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;
+
+ if (fp_model != gdbarch_tdep (best_arch->gdbarch)->fp_model)
+ continue;
+
+ /* Found a match. */
+ break;
+ }
+
+ if (best_arch != NULL)
+ return best_arch->gdbarch;
+
+ tdep = xcalloc (1, sizeof (struct gdbarch_tdep));
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ /* 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;
/* 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_call_dummy_words (gdbarch, arm_call_dummy_words);
- set_gdbarch_sizeof_call_dummy_words (gdbarch, 0);
-
set_gdbarch_push_dummy_call (gdbarch, arm_push_dummy_call);
+ set_gdbarch_write_pc (gdbarch, arm_write_pc);
+
/* Frame handling. */
- set_gdbarch_deprecated_frame_chain_valid (gdbarch, arm_frame_chain_valid);
- set_gdbarch_deprecated_init_extra_frame_info (gdbarch, arm_init_extra_frame_info);
- set_gdbarch_read_fp (gdbarch, arm_read_fp);
- set_gdbarch_deprecated_frame_chain (gdbarch, arm_frame_chain);
- set_gdbarch_frameless_function_invocation
- (gdbarch, arm_frameless_function_invocation);
- set_gdbarch_deprecated_frame_saved_pc (gdbarch, arm_frame_saved_pc);
- set_gdbarch_frame_args_address (gdbarch, arm_frame_args_address);
- set_gdbarch_frame_locals_address (gdbarch, arm_frame_locals_address);
- set_gdbarch_frame_num_args (gdbarch, arm_frame_num_args);
- set_gdbarch_frame_args_skip (gdbarch, 0);
- set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, arm_frame_init_saved_regs);
- set_gdbarch_deprecated_pop_frame (gdbarch, arm_pop_frame);
+ set_gdbarch_unwind_dummy_id (gdbarch, arm_unwind_dummy_id);
+ set_gdbarch_unwind_pc (gdbarch, arm_unwind_pc);
+ set_gdbarch_unwind_sp (gdbarch, arm_unwind_sp);
+
+ frame_base_set_default (gdbarch, &arm_normal_base);
/* Address manipulation. */
set_gdbarch_smash_text_address (gdbarch, arm_smash_text_address);
set_gdbarch_addr_bits_remove (gdbarch, arm_addr_bits_remove);
- /* Offset from address of function to start of its code. */
- set_gdbarch_function_start_offset (gdbarch, 0);
-
/* 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_saved_pc_after_call (gdbarch, arm_saved_pc_after_call);
+ 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);
/* Breakpoint manipulation. */
set_gdbarch_breakpoint_from_pc (gdbarch, arm_breakpoint_from_pc);
- set_gdbarch_decr_pc_after_break (gdbarch, 0);
/* Information about registers, etc. */
set_gdbarch_print_float_info (gdbarch, arm_print_float_info);
- set_gdbarch_fp_regnum (gdbarch, ARM_FP_REGNUM); /* ??? */
+ 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_register_byte (gdbarch, arm_register_byte);
- set_gdbarch_register_bytes (gdbarch,
- (NUM_GREGS * INT_REGISTER_RAW_SIZE
- + NUM_FREGS * FP_REGISTER_RAW_SIZE
- + NUM_SREGS * STATUS_REGISTER_SIZE));
+ set_gdbarch_deprecated_register_byte (gdbarch, arm_register_byte);
set_gdbarch_num_regs (gdbarch, NUM_GREGS + NUM_FREGS + NUM_SREGS);
- set_gdbarch_register_raw_size (gdbarch, arm_register_raw_size);
- set_gdbarch_register_virtual_size (gdbarch, arm_register_virtual_size);
- set_gdbarch_deprecated_max_register_raw_size (gdbarch, FP_REGISTER_RAW_SIZE);
- set_gdbarch_deprecated_max_register_virtual_size (gdbarch, FP_REGISTER_VIRTUAL_SIZE);
- set_gdbarch_register_virtual_type (gdbarch, arm_register_type);
+ set_gdbarch_register_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_deprecated_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_use_struct_convention (gdbarch, arm_use_struct_convention);
- set_gdbarch_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. */
/* 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_stub_unwind_sniffer);
+ frame_unwind_append_sniffer (gdbarch, arm_sigtramp_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,
based on what the OS ABI has told us. */
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;
case BFD_ENDIAN_LITTLE:
set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little);
- arm_set_fp (gdbarch);
+ if (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);
+ }
break;
default:
internal_error (__FILE__, __LINE__,
- "arm_gdbarch_init: bad byte order for float format");
+ _("arm_gdbarch_init: bad byte order for float format"));
}
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
_initialize_arm_tdep (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);
- if (GDB_MULTI_ARCH)
- gdbarch_register (bfd_arch_arm, arm_gdbarch_init, arm_dump_tdep);
+ 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. */
- 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);
+ length = snprintf (rdptr, rest, "%s - %s\n", setname, setdesc);
+ rdptr += length;
+ rest -= length;
/* Copy the default names (if found) and synchronize disassembler. */
if (!strcmp (setname, "std"))
{
/* 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);
}