/* Common target dependent code for GDB on ARM systems.
Copyright (C) 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <ctype.h> /* XXX for isupper () */
static void set_disassembly_style (void);
static void convert_from_extended (const struct floatformat *, const void *,
- void *);
+ void *, int);
static void convert_to_extended (const struct floatformat *, void *,
- const void *);
+ const void *, int);
struct arm_prologue_cache
{
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. */
+ /* The frame base for this frame is just prev_sp - frame size.
+ FRAMESIZE is the distance from the frame pointer to the
+ initial stack pointer. */
int framesize;
- int frameoffset;
/* The register used to hold the frame pointer for this frame. */
int framereg;
{
int regno;
int mask;
- int stop = 0;
+
+ if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
+ break;
/* Bits 0-7 contain a mask for registers R0-R7. Bit 8 says
whether to save LR (R14). */
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;
- }
-
regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
-4);
pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]);
}
-
- if (stop)
- break;
}
else if ((insn & 0xff00) == 0xb000) /* add sp, #simm OR
sub sp, #simm */
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. */
sub fp, ip, #nn @@ nn == 20 or 4 depending on second insn */
static CORE_ADDR
-arm_skip_prologue (CORE_ADDR pc)
+arm_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
unsigned long inst;
CORE_ADDR skip_pc;
/* Check if this is Thumb code. */
if (arm_pc_is_thumb (pc))
- return thumb_analyze_prologue (current_gdbarch, pc, func_end, NULL);
+ return thumb_analyze_prologue (gdbarch, pc, func_end, NULL);
for (skip_pc = pc; skip_pc < func_end; skip_pc += 4)
{
/* *INDENT-ON* */
static void
-thumb_scan_prologue (CORE_ADDR prev_pc, struct arm_prologue_cache *cache)
+thumb_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR prev_pc,
+ struct arm_prologue_cache *cache)
{
CORE_ADDR prologue_start;
CORE_ADDR prologue_end;
prologue_end = min (prologue_end, prev_pc);
- thumb_analyze_prologue (current_gdbarch, prologue_start, prologue_end,
- cache);
+ thumb_analyze_prologue (gdbarch, prologue_start, prologue_end, cache);
}
/* This function decodes an ARM function prologue to determine:
*/
static void
-arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cache)
+arm_scan_prologue (struct frame_info *next_frame,
+ struct arm_prologue_cache *cache)
{
- int regno, sp_offset, fp_offset, ip_offset;
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ int regno;
CORE_ADDR prologue_start, prologue_end, current_pc;
CORE_ADDR prev_pc = frame_pc_unwind (next_frame);
+ pv_t regs[ARM_FPS_REGNUM];
+ struct pv_area *stack;
+ struct cleanup *back_to;
+ CORE_ADDR offset;
/* Assume there is no frame until proven otherwise. */
cache->framereg = ARM_SP_REGNUM;
cache->framesize = 0;
- cache->frameoffset = 0;
/* Check for Thumb prologue. */
if (arm_pc_is_thumb (prev_pc))
{
- thumb_scan_prologue (prev_pc, cache);
+ thumb_scan_prologue (gdbarch, prev_pc, cache);
return;
}
return;
else
{
- prologue_start = ADDR_BITS_REMOVE (return_value) - 8;
+ prologue_start = gdbarch_addr_bits_remove
+ (gdbarch, return_value) - 8;
prologue_end = prologue_start + 64; /* See above. */
}
}
in which case it is often (but not always) replaced by
"str lr, [sp, #-4]!". - Michael Snyder, 2002-04-23] */
- sp_offset = fp_offset = ip_offset = 0;
+ for (regno = 0; regno < ARM_FPS_REGNUM; regno++)
+ regs[regno] = pv_register (regno, 0);
+ stack = make_pv_area (ARM_SP_REGNUM);
+ back_to = make_cleanup_free_pv_area (stack);
+
+ regs[ARM_PC_REGNUM] = pv_unknown ();
for (current_pc = prologue_start;
current_pc < prologue_end;
if (insn == 0xe1a0c00d) /* mov ip, sp */
{
- ip_offset = 0;
+ regs[ARM_IP_REGNUM] = regs[ARM_SP_REGNUM];
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;
+ regs[ARM_IP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], 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;
+ regs[ARM_IP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -imm);
continue;
}
else if (insn == 0xe52de004) /* str lr, [sp, #-4]! */
{
- sp_offset -= 4;
- cache->saved_regs[ARM_LR_REGNUM].addr = sp_offset;
+ if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
+ break;
+ regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -4);
+ pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[ARM_LR_REGNUM]);
continue;
}
else if ((insn & 0xffff0000) == 0xe92d0000)
{
int mask = insn & 0xffff;
+ if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
+ break;
+
/* Calculate offsets of saved registers. */
for (regno = ARM_PC_REGNUM; regno >= 0; regno--)
if (mask & (1 << regno))
{
- sp_offset -= 4;
- cache->saved_regs[regno].addr = sp_offset;
+ regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -4);
+ pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]);
}
}
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 + ip_offset;
- cache->framereg = ARM_FP_REGNUM;
+ regs[ARM_FP_REGNUM] = pv_add_constant (regs[ARM_IP_REGNUM], -imm);
}
else if ((insn & 0xfffff000) == 0xe24dd000) /* sub sp, sp #n */
{
unsigned imm = insn & 0xff; /* immediate value */
unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */
imm = (imm >> rot) | (imm << (32 - rot));
- sp_offset -= imm;
+ regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -imm);
}
else if ((insn & 0xffff7fff) == 0xed6d0103 /* stfe f?, [sp, -#c]! */
- && gdbarch_tdep (current_gdbarch)->have_fpa_registers)
+ && gdbarch_tdep (gdbarch)->have_fpa_registers)
{
- sp_offset -= 12;
+ if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
+ break;
+
+ regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -12);
regno = ARM_F0_REGNUM + ((insn >> 12) & 0x07);
- cache->saved_regs[regno].addr = sp_offset;
+ pv_area_store (stack, regs[ARM_SP_REGNUM], 12, regs[regno]);
}
else if ((insn & 0xffbf0fff) == 0xec2d0200 /* sfmfd f0, 4, [sp!] */
- && gdbarch_tdep (current_gdbarch)->have_fpa_registers)
+ && gdbarch_tdep (gdbarch)->have_fpa_registers)
{
int n_saved_fp_regs;
unsigned int fp_start_reg, fp_bound_reg;
+ if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
+ break;
+
if ((insn & 0x800) == 0x800) /* N0 is set */
{
if ((insn & 0x40000) == 0x40000) /* N1 is set */
fp_bound_reg = fp_start_reg + n_saved_fp_regs;
for (; fp_start_reg < fp_bound_reg; fp_start_reg++)
{
- sp_offset -= 12;
- cache->saved_regs[fp_start_reg++].addr = sp_offset;
+ regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -12);
+ pv_area_store (stack, regs[ARM_SP_REGNUM], 12,
+ regs[fp_start_reg++]);
}
}
else if ((insn & 0xf0000000) != 0xe0000000)
continue;
}
- /* 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]. */
- cache->framesize = -sp_offset;
- if (cache->framereg == ARM_FP_REGNUM)
- cache->frameoffset = fp_offset - sp_offset;
+ /* The frame size is just the distance from the frame register
+ to the original stack pointer. */
+ if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM))
+ {
+ /* Frame pointer is fp. */
+ cache->framereg = ARM_FP_REGNUM;
+ cache->framesize = -regs[ARM_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
- cache->frameoffset = 0;
+ {
+ /* We're just out of luck. We don't know where the frame is. */
+ cache->framereg = -1;
+ cache->framesize = 0;
+ }
+
+ for (regno = 0; regno < ARM_FPS_REGNUM; regno++)
+ if (pv_area_find_reg (stack, gdbarch, regno, &offset))
+ cache->saved_regs[regno].addr = offset;
+
+ do_cleanups (back_to);
}
static struct arm_prologue_cache *
if (unwound_fp == 0)
return cache;
- cache->prev_sp = unwound_fp + cache->framesize - cache->frameoffset;
+ cache->prev_sp = unwound_fp + cache->framesize;
/* Calculate actual addresses of saved registers using offsets
determined by arm_scan_prologue. */
- for (reg = 0; reg < NUM_REGS; reg++)
+ for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (next_frame)); reg++)
if (trad_frame_addr_p (cache->saved_regs, reg))
cache->saved_regs[reg].addr += cache->prev_sp;
/* 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)
+ if (func <= gdbarch_tdep (get_frame_arch (next_frame))->lowest_pc)
return;
/* If we've hit a wall, stop. */
*this_cache = arm_make_prologue_cache (next_frame);
cache = *this_cache;
- return cache->prev_sp + cache->frameoffset - cache->framesize;
+ return cache->prev_sp - cache->framesize;
}
struct frame_base arm_normal_base = {
{
if (arm_debug)
fprintf_unfiltered (gdb_stdlog, "struct return in %s = 0x%s\n",
- REGISTER_NAME (argreg), paddr (struct_addr));
+ gdbarch_register_name (gdbarch, argreg),
+ paddr (struct_addr));
regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
argreg++;
}
registers and stack. */
while (len > 0)
{
- int partial_len = len < DEPRECATED_REGISTER_SIZE ? len : DEPRECATED_REGISTER_SIZE;
+ int partial_len = len < INT_REGISTER_SIZE ? len : INT_REGISTER_SIZE;
if (argreg <= ARM_LAST_ARG_REGNUM)
{
/* The argument is being passed in a general purpose
register. */
CORE_ADDR regval = extract_unsigned_integer (val, partial_len);
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+ regval <<= (INT_REGISTER_SIZE - partial_len) * 8;
if (arm_debug)
fprintf_unfiltered (gdb_stdlog, "arg %d in %s = 0x%s\n",
- argnum, REGISTER_NAME (argreg),
- phex (regval, DEPRECATED_REGISTER_SIZE));
+ argnum,
+ gdbarch_register_name
+ (gdbarch, argreg),
+ phex (regval, INT_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, DEPRECATED_REGISTER_SIZE);
- nstack += DEPRECATED_REGISTER_SIZE;
+ si = push_stack_item (si, val, INT_REGISTER_SIZE);
+ nstack += INT_REGISTER_SIZE;
}
len -= partial_len;
arm_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
struct frame_info *frame, const char *args)
{
- unsigned long status = read_register (ARM_FPS_REGNUM);
+ unsigned long status = get_frame_register_unsigned (frame, ARM_FPS_REGNUM);
int type;
type = (status >> 24) & 127;
number. */
static int
-arm_dwarf_reg_to_regnum (int reg)
+arm_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
{
/* Core integer regs. */
if (reg >= 0 && reg <= 15)
/* Map GDB internal REGNUM onto the Arm simulator register numbers. */
static int
-arm_register_sim_regno (int regnum)
+arm_register_sim_regno (struct gdbarch *gdbarch, int regnum)
{
int reg = regnum;
- gdb_assert (reg >= 0 && reg < NUM_REGS);
+ gdb_assert (reg >= 0 && reg < gdbarch_num_regs (gdbarch));
if (regnum >= ARM_WR0_REGNUM && regnum <= ARM_WR15_REGNUM)
return regnum - ARM_WR0_REGNUM + SIM_ARM_IWMMXT_COP0R0_REGNUM;
static void
convert_from_extended (const struct floatformat *fmt, const void *ptr,
- void *dbl)
+ void *dbl, int endianess)
{
DOUBLEST d;
- if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+
+ if (endianess == BFD_ENDIAN_BIG)
floatformat_to_doublest (&floatformat_arm_ext_big, ptr, &d);
else
floatformat_to_doublest (&floatformat_arm_ext_littlebyte_bigword,
}
static void
-convert_to_extended (const struct floatformat *fmt, void *dbl, const void *ptr)
+convert_to_extended (const struct floatformat *fmt, void *dbl, const void *ptr,
+ int endianess)
{
DOUBLEST d;
+
floatformat_to_doublest (fmt, ptr, &d);
- if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ if (endianess == BFD_ENDIAN_BIG)
floatformat_from_doublest (&floatformat_arm_ext_big, &d, dbl);
else
floatformat_from_doublest (&floatformat_arm_ext_littlebyte_bigword,
#define ARM_PC_32 1
static unsigned long
-shifted_reg_val (unsigned long inst, int carry, unsigned long pc_val,
- unsigned long status_reg)
+shifted_reg_val (struct frame_info *frame, unsigned long inst, int carry,
+ unsigned long pc_val, unsigned long status_reg)
{
unsigned long res, shift;
int rm = bits (inst, 0, 3);
if (bit (inst, 4))
{
int rs = bits (inst, 8, 11);
- shift = (rs == 15 ? pc_val + 8 : read_register (rs)) & 0xFF;
+ shift = (rs == 15 ? pc_val + 8
+ : get_frame_register_unsigned (frame, rs)) & 0xFF;
}
else
shift = bits (inst, 7, 11);
res = (rm == 15
? ((pc_val | (ARM_PC_32 ? 0 : status_reg))
+ (bit (inst, 4) ? 12 : 8))
- : read_register (rm));
+ : get_frame_register_unsigned (frame, rm));
switch (shifttype)
{
}
static CORE_ADDR
-thumb_get_next_pc (CORE_ADDR pc)
+thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
unsigned long pc_val = ((unsigned long) pc) + 4; /* PC after prefetch */
unsigned short inst1 = read_memory_unsigned_integer (pc, 2);
CORE_ADDR nextpc = pc + 2; /* default is next instruction */
/* Fetch the saved PC from the stack. It's stored above
all of the other registers. */
- offset = bitcount (bits (inst1, 0, 7)) * DEPRECATED_REGISTER_SIZE;
- sp = read_register (ARM_SP_REGNUM);
+ offset = bitcount (bits (inst1, 0, 7)) * INT_REGISTER_SIZE;
+ sp = get_frame_register_unsigned (frame, ARM_SP_REGNUM);
nextpc = (CORE_ADDR) read_memory_unsigned_integer (sp + offset, 4);
- nextpc = ADDR_BITS_REMOVE (nextpc);
+ nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
}
else if ((inst1 & 0xf000) == 0xd000) /* conditional branch */
{
- unsigned long status = read_register (ARM_PS_REGNUM);
+ unsigned long status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
unsigned long cond = bits (inst1, 8, 11);
if (cond != 0x0f && condition_true (cond, status)) /* 0x0f = SWI */
nextpc = pc_val + (sbits (inst1, 0, 7) << 1);
if (bits (inst1, 3, 6) == 0x0f)
nextpc = pc_val;
else
- nextpc = read_register (bits (inst1, 3, 6));
+ nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6));
- nextpc = ADDR_BITS_REMOVE (nextpc);
+ nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
}
return nextpc;
}
-static CORE_ADDR
-arm_get_next_pc (CORE_ADDR pc)
+CORE_ADDR
+arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
unsigned long pc_val;
unsigned long this_instr;
unsigned long status;
CORE_ADDR nextpc;
if (arm_pc_is_thumb (pc))
- return thumb_get_next_pc (pc);
+ return thumb_get_next_pc (frame, pc);
pc_val = (unsigned long) pc;
this_instr = read_memory_unsigned_integer (pc, 4);
- status = read_register (ARM_PS_REGNUM);
+ status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
nextpc = (CORE_ADDR) (pc_val + 4); /* Default case */
- if (condition_true (bits (this_instr, 28, 31), status))
+ if (bits (this_instr, 28, 31) == INST_NV)
+ switch (bits (this_instr, 24, 27))
+ {
+ case 0xa:
+ case 0xb:
+ {
+ /* Branch with Link and change to Thumb. */
+ nextpc = BranchDest (pc, this_instr);
+ nextpc |= bit (this_instr, 24) << 1;
+
+ nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
+ if (nextpc == pc)
+ error (_("Infinite loop detected"));
+ break;
+ }
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ /* Coprocessor register transfer. */
+ if (bits (this_instr, 12, 15) == 15)
+ error (_("Invalid update to pc in instruction"));
+ break;
+ }
+ else if (condition_true (bits (this_instr, 28, 31), status))
{
switch (bits (this_instr, 24, 27))
{
|| 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);
+ result = (rn == 15) ? pc_val + 8
+ : get_frame_register_unsigned (frame, rn);
+ nextpc = (CORE_ADDR) gdbarch_addr_bits_remove
+ (gdbarch, result);
if (nextpc == pc)
error (_("Infinite loop detected"));
/* Multiply into PC */
c = (status & FLAG_C) ? 1 : 0;
rn = bits (this_instr, 16, 19);
- operand1 = (rn == 15) ? pc_val + 8 : read_register (rn);
+ operand1 = (rn == 15) ? pc_val + 8
+ : get_frame_register_unsigned (frame, rn);
if (bit (this_instr, 25))
{
& 0xffffffff;
}
else /* operand 2 is a shifted register */
- operand2 = shifted_reg_val (this_instr, c, pc_val, status);
+ operand2 = shifted_reg_val (frame, this_instr, c, pc_val, status);
switch (bits (this_instr, 21, 24))
{
result = ~operand2;
break;
}
- nextpc = (CORE_ADDR) ADDR_BITS_REMOVE (result);
+ nextpc = (CORE_ADDR) gdbarch_addr_bits_remove
+ (gdbarch, result);
if (nextpc == pc)
error (_("Infinite loop detected"));
/* byte write to PC */
rn = bits (this_instr, 16, 19);
- base = (rn == 15) ? pc_val + 8 : read_register (rn);
+ base = (rn == 15) ? pc_val + 8
+ : get_frame_register_unsigned (frame, rn);
if (bit (this_instr, 24))
{
/* pre-indexed */
int c = (status & FLAG_C) ? 1 : 0;
unsigned long offset =
(bit (this_instr, 25)
- ? shifted_reg_val (this_instr, c, pc_val, status)
+ ? shifted_reg_val (frame, this_instr, c, pc_val, status)
: bits (this_instr, 0, 11));
if (bit (this_instr, 23))
nextpc = (CORE_ADDR) read_memory_integer ((CORE_ADDR) base,
4);
- nextpc = ADDR_BITS_REMOVE (nextpc);
+ nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
{
unsigned long rn_val =
- read_register (bits (this_instr, 16, 19));
+ get_frame_register_unsigned (frame,
+ bits (this_instr, 16, 19));
nextpc =
(CORE_ADDR) read_memory_integer ((CORE_ADDR) (rn_val
+ offset),
4);
}
- nextpc = ADDR_BITS_REMOVE (nextpc);
+ nextpc = gdbarch_addr_bits_remove
+ (gdbarch, nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
}
{
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);
+ nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
break;
/* single_step() is called just before we want to resume the inferior,
if we want to single-step it but there is no hardware or kernel
single-step support. We find the target of the coming instruction
- and breakpoint it.
-
- single_step() is also called just after the inferior stops. If we
- had set up a simulated single-step, we undo our damage. */
+ and breakpoint it. */
-static int
-arm_software_single_step (enum target_signal sig, int insert_bpt)
+int
+arm_software_single_step (struct frame_info *frame)
{
/* 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)
- {
- CORE_ADDR next_pc = arm_get_next_pc (read_register (ARM_PC_REGNUM));
-
- insert_single_step_breakpoint (next_pc);
- }
- else
- remove_single_step_breakpoints ();
+ CORE_ADDR next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
+ insert_single_step_breakpoint (next_pc);
return 1;
}
else
info->symbols = NULL;
- if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
return print_insn_big_arm (memaddr, info);
else
return print_insn_little_arm (memaddr, info);
instruction to force a trap. This can be handled by by the
abi-specific code during establishment of the gdbarch vector. */
-
-/* NOTE rearnsha 2002-02-18: for now we allow a non-multi-arch gdb to
- override these definitions. */
-#ifndef ARM_LE_BREAKPOINT
#define ARM_LE_BREAKPOINT {0xFE,0xDE,0xFF,0xE7}
-#endif
-#ifndef ARM_BE_BREAKPOINT
#define ARM_BE_BREAKPOINT {0xE7,0xFF,0xDE,0xFE}
-#endif
-#ifndef THUMB_LE_BREAKPOINT
-#define THUMB_LE_BREAKPOINT {0xfe,0xdf}
-#endif
-#ifndef THUMB_BE_BREAKPOINT
-#define THUMB_BE_BREAKPOINT {0xdf,0xfe}
-#endif
+#define THUMB_LE_BREAKPOINT {0xbe,0xbe}
+#define THUMB_BE_BREAKPOINT {0xbe,0xbe}
static const char arm_default_arm_le_breakpoint[] = ARM_LE_BREAKPOINT;
static const char arm_default_arm_be_breakpoint[] = ARM_BE_BREAKPOINT;
breakpoint should be inserted. */
static const unsigned char *
-arm_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+arm_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
if (arm_pc_is_thumb (*pcptr))
{
arm_extract_return_value (struct type *type, struct regcache *regs,
gdb_byte *valbuf)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regs);
+
if (TYPE_CODE_FLT == TYPE_CODE (type))
{
- switch (gdbarch_tdep (current_gdbarch)->fp_model)
+ switch (gdbarch_tdep (gdbarch)->fp_model)
{
case ARM_FLOAT_FPA:
{
regcache_cooked_read (regs, ARM_F0_REGNUM, tmpbuf);
convert_from_extended (floatformat_from_type (type), tmpbuf,
- valbuf);
+ valbuf, gdbarch_byte_order (gdbarch));
}
break;
/* 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 DEPRECATED_REGISTER_SIZE and the
+ must be less than or equal to INT_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.
/* All aggregate types that won't fit in a register must be returned
in memory. */
- if (TYPE_LENGTH (type) > DEPRECATED_REGISTER_SIZE)
+ if (TYPE_LENGTH (type) > INT_REGISTER_SIZE)
{
return 1;
}
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
- DEPRECATED_REGISTER_SIZE and the offset of each addressable
+ INT_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
arm_store_return_value (struct type *type, struct regcache *regs,
const gdb_byte *valbuf)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regs);
+
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
char buf[MAX_REGISTER_SIZE];
- switch (gdbarch_tdep (current_gdbarch)->fp_model)
+ switch (gdbarch_tdep (gdbarch)->fp_model)
{
case ARM_FLOAT_FPA:
- convert_to_extended (floatformat_from_type (type), buf, valbuf);
+ convert_to_extended (floatformat_from_type (type), buf, valbuf,
+ gdbarch_byte_order (gdbarch));
regcache_cooked_write (regs, ARM_F0_REGNUM, buf);
break;
static int
-arm_get_longjmp_target (CORE_ADDR *pc)
+arm_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
{
CORE_ADDR jb_addr;
char buf[INT_REGISTER_SIZE];
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame));
- jb_addr = read_register (ARM_A1_REGNUM);
+ jb_addr = get_frame_register_unsigned (frame, ARM_A1_REGNUM);
if (target_read_memory (jb_addr + tdep->jb_pc * tdep->jb_elt_size, buf,
INT_REGISTER_SIZE))
return 1;
}
-/* Return non-zero if the PC is inside a thumb call thunk. */
-
-int
-arm_in_call_stub (CORE_ADDR pc, char *name)
-{
- CORE_ADDR start_addr;
-
- /* Find the starting address of the function containing the PC. If
- the caller didn't give us a name, look it up at the same time. */
- if (0 == find_pc_partial_function (pc, name ? NULL : &name,
- &start_addr, NULL))
- return 0;
-
- return strncmp (name, "_call_via_r", 11) == 0;
-}
-
-/* If PC is in a Thumb call or return stub, return the address of the
- target PC, which is in a register. The thunk functions are called
- _called_via_xx, where x is the register name. The possible names
- are r0-r9, sl, fp, ip, sp, and lr. */
+/* Recognize GCC and GNU ld's trampolines. If we are in a trampoline,
+ return the target PC. Otherwise return 0. */
CORE_ADDR
-arm_skip_stub (CORE_ADDR pc)
+arm_skip_stub (struct frame_info *frame, CORE_ADDR pc)
{
char *name;
+ int namelen;
CORE_ADDR start_addr;
/* Find the starting address and name of the function containing the PC. */
if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0)
return 0;
- /* Call thunks always start with "_call_via_". */
+ /* If PC is in a Thumb call or return stub, return the address of the
+ target PC, which is in a register. The thunk functions are called
+ _call_via_xx, where x is the register name. The possible names
+ are r0-r9, sl, fp, ip, sp, and lr. */
if (strncmp (name, "_call_via_", 10) == 0)
{
/* Use the name suffix to determine which register contains the
"r8", "r9", "sl", "fp", "ip", "sp", "lr"
};
int regno;
+ int offset = strlen (name) - 2;
for (regno = 0; regno <= 14; regno++)
- if (strcmp (&name[10], table[regno]) == 0)
- return read_register (regno);
+ if (strcmp (&name[offset], table[regno]) == 0)
+ return get_frame_register_unsigned (frame, regno);
+ }
+
+ /* GNU ld generates __foo_from_arm or __foo_from_thumb for
+ non-interworking calls to foo. We could decode the stubs
+ to find the target but it's easier to use the symbol table. */
+ namelen = strlen (name);
+ if (name[0] == '_' && name[1] == '_'
+ && ((namelen > 2 + strlen ("_from_thumb")
+ && strncmp (name + namelen - strlen ("_from_thumb"), "_from_thumb",
+ strlen ("_from_thumb")) == 0)
+ || (namelen > 2 + strlen ("_from_arm")
+ && strncmp (name + namelen - strlen ("_from_arm"), "_from_arm",
+ strlen ("_from_arm")) == 0)))
+ {
+ char *target_name;
+ int target_len = namelen - 2;
+ struct minimal_symbol *minsym;
+ struct objfile *objfile;
+ struct obj_section *sec;
+
+ if (name[namelen - 1] == 'b')
+ target_len -= strlen ("_from_thumb");
+ else
+ target_len -= strlen ("_from_arm");
+
+ target_name = alloca (target_len + 1);
+ memcpy (target_name, name + 2, target_len);
+ target_name[target_len] = '\0';
+
+ sec = find_pc_section (pc);
+ objfile = (sec == NULL) ? NULL : sec->objfile;
+ minsym = lookup_minimal_symbol (target_name, NULL, objfile);
+ if (minsym != NULL)
+ return SYMBOL_VALUE_ADDRESS (minsym);
+ else
+ return 0;
}
return 0; /* not a stub */
\f
/* Return the ARM register name corresponding to register I. */
static const char *
-arm_register_name (int i)
+arm_register_name (struct gdbarch *gdbarch, int i)
{
if (i >= ARRAY_SIZE (arm_register_names))
/* These registers are only supported on targets which supply
}
static void
-arm_write_pc (CORE_ADDR pc, ptid_t ptid)
+arm_write_pc (struct regcache *regcache, CORE_ADDR pc)
{
- write_register_pid (ARM_PC_REGNUM, pc, ptid);
+ regcache_cooked_write_unsigned (regcache, ARM_PC_REGNUM, pc);
/* If necessary, set the T bit. */
if (arm_apcs_32)
{
- CORE_ADDR val = read_register_pid (ARM_PS_REGNUM, ptid);
+ ULONGEST val;
+ regcache_cooked_read_unsigned (regcache, ARM_PS_REGNUM, &val);
if (arm_pc_is_thumb (pc))
- write_register_pid (ARM_PS_REGNUM, val | 0x20, ptid);
+ regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM, val | 0x20);
else
- write_register_pid (ARM_PS_REGNUM, val & ~(CORE_ADDR) 0x20, ptid);
+ regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM,
+ val & ~(ULONGEST) 0x20);
}
}
}
}
- /* Now that we have inferred any architecture settings that we
- can, try to inherit from the last ARM ABI. */
- if (arches != NULL)
- {
- 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)
+ if (arm_abi != ARM_ABI_AUTO
+ && arm_abi != gdbarch_tdep (best_arch->gdbarch)->arm_abi)
continue;
- if (fp_model != gdbarch_tdep (best_arch->gdbarch)->fp_model)
+ if (fp_model != ARM_FLOAT_AUTO
+ && fp_model != gdbarch_tdep (best_arch->gdbarch)->fp_model)
continue;
/* Found a match. */
/* Advance PC across function entry code. */
set_gdbarch_skip_prologue (gdbarch, arm_skip_prologue);
+ /* Skip trampolines. */
+ set_gdbarch_skip_trampoline_code (gdbarch, arm_skip_stub);
+
/* The stack grows downward. */
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
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_deprecated_register_size (gdbarch, 4);
set_gdbarch_register_name (gdbarch, arm_register_name);
/* Returning results. */
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_software_single_step (gdbarch, arm_software_single_step);
-
/* Disassembly. */
set_gdbarch_print_insn (gdbarch, gdb_print_insn_arm);
/* Now we have tuned the configuration, set a few final things,
based on what the OS ABI has told us. */
+ /* If the ABI is not otherwise marked, assume the old GNU APCS. EABI
+ binaries are always marked. */
+ if (tdep->arm_abi == ARM_ABI_AUTO)
+ tdep->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 (tdep->fp_model == ARM_FLOAT_AUTO)
+ tdep->fp_model = ARM_FLOAT_SOFT_FPA;
+
if (tdep->jb_pc >= 0)
set_gdbarch_get_longjmp_target (gdbarch, arm_get_longjmp_target);
/* Floating point sizes and format. */
set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
- if (fp_model == ARM_FLOAT_SOFT_FPA || fp_model == ARM_FLOAT_FPA)
+ if (tdep->fp_model == ARM_FLOAT_SOFT_FPA || tdep->fp_model == ARM_FLOAT_FPA)
{
set_gdbarch_double_format
(gdbarch, floatformats_ieee_double_littlebyte_bigword);
}
if (tdesc_data)
- tdesc_use_registers (gdbarch, tdesc_data);
+ tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
/* Add standard register aliases. We add aliases even for those
nanes which are used by the current architecture - it's simpler,
}
static void
-arm_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+arm_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
if (tdep == NULL)
return;