/* 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.
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. */
*/
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))
else
{
prologue_start = gdbarch_addr_bits_remove
- (current_gdbarch, return_value) - 8;
+ (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 < gdbarch_num_regs (current_gdbarch); 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",
- gdbarch_register_name (current_gdbarch, argreg),
+ gdbarch_register_name (gdbarch, argreg),
paddr (struct_addr));
regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
argreg++;
/* The argument is being passed in a general purpose
register. */
CORE_ADDR regval = extract_unsigned_integer (val, partial_len);
- if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+ 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,
gdbarch_register_name
- (current_gdbarch, argreg),
+ (gdbarch, argreg),
phex (regval, INT_REGISTER_SIZE));
regcache_cooked_write_unsigned (regcache, argreg, regval);
argreg++;
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 < gdbarch_num_regs (current_gdbarch));
+ 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 CORE_ADDR
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 */
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 = gdbarch_addr_bits_remove (current_gdbarch, nextpc);
+ nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
}
else
nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6));
- nextpc = gdbarch_addr_bits_remove (current_gdbarch, nextpc);
+ nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
}
return nextpc;
}
-static CORE_ADDR
+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;
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))
{
result = (rn == 15) ? pc_val + 8
: get_frame_register_unsigned (frame, rn);
nextpc = (CORE_ADDR) gdbarch_addr_bits_remove
- (current_gdbarch, result);
+ (gdbarch, result);
if (nextpc == pc)
error (_("Infinite loop detected"));
break;
}
nextpc = (CORE_ADDR) gdbarch_addr_bits_remove
- (current_gdbarch, result);
+ (gdbarch, result);
if (nextpc == pc)
error (_("Infinite loop detected"));
nextpc = (CORE_ADDR) read_memory_integer ((CORE_ADDR) base,
4);
- nextpc = gdbarch_addr_bits_remove (current_gdbarch, nextpc);
+ nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
4);
}
nextpc = gdbarch_addr_bits_remove
- (current_gdbarch, nextpc);
+ (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 = gdbarch_addr_bits_remove (current_gdbarch, nextpc);
+ nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
if (nextpc == pc)
error (_("Infinite loop detected"));
break;
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))
{
{
if (TYPE_CODE_FLT == TYPE_CODE (type))
{
- switch (gdbarch_tdep (current_gdbarch)->fp_model)
+ switch (gdbarch_tdep (get_regcache_arch (regs))->fp_model)
{
case ARM_FLOAT_FPA:
{
{
char buf[MAX_REGISTER_SIZE];
- switch (gdbarch_tdep (current_gdbarch)->fp_model)
+ switch (gdbarch_tdep (get_regcache_arch (regs))->fp_model)
{
case ARM_FLOAT_FPA:
\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
}
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;