* arm-linux-tdep.h (ARM_CPSR_REGNUM): Delete definition.
* arm-tdep.c (arm_frame_is_thumb): New. (arm_pc_is_thumb): Clarify comment. (thumb_analyze_prologue): Remove PC special case. (thumb_scan_prologue): Take a block_addr argument. Use it for find_pc_partial_function. Remove unused variables. (arm_scan_prologue): Use arm_frame_is_thumb. Use the block address for find_pc_partial_function. Remove PC special case. (arm_prologue_prev_register): Add special handling for PC and CPSR. (arm_dwarf2_prev_register, arm_dwarf2_frame_init_reg): New. (arm_get_next_pc): Use arm_frame_is_thumb. (arm_write_pc): Use CPSR_T instead of 0x20. (arm_gdbarch_init): Call dwarf2_frame_set_init_reg. * arm-tdep.h (enum gdb_regnum): Add ARM_CPSR_REGNUM. (CPSR_T): Define. * dwarf2-frame.c (dwarf2_frame_prev_register): Handle DWARF2_FRAME_REG_FN. * dwarf2-frame.h (enum dwarf2_frame_reg_rule): Add DWARF2_FRAME_REG_FN. (struct dwarf2_frame_state_reg): Add FN to loc union. * gdb.arch/thumb-prologue.exp: Do not expect a saved PC.
This commit is contained in:
parent
36d520f5f6
commit
b39cc96258
|
@ -1,3 +1,26 @@
|
|||
2008-05-01 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* arm-linux-tdep.h (ARM_CPSR_REGNUM): Delete definition.
|
||||
* arm-tdep.c (arm_frame_is_thumb): New.
|
||||
(arm_pc_is_thumb): Clarify comment.
|
||||
(thumb_analyze_prologue): Remove PC special case.
|
||||
(thumb_scan_prologue): Take a block_addr argument. Use it for
|
||||
find_pc_partial_function. Remove unused variables.
|
||||
(arm_scan_prologue): Use arm_frame_is_thumb. Use the block address
|
||||
for find_pc_partial_function. Remove PC special case.
|
||||
(arm_prologue_prev_register): Add special handling for PC and CPSR.
|
||||
(arm_dwarf2_prev_register, arm_dwarf2_frame_init_reg): New.
|
||||
(arm_get_next_pc): Use arm_frame_is_thumb.
|
||||
(arm_write_pc): Use CPSR_T instead of 0x20.
|
||||
(arm_gdbarch_init): Call dwarf2_frame_set_init_reg.
|
||||
* arm-tdep.h (enum gdb_regnum): Add ARM_CPSR_REGNUM.
|
||||
(CPSR_T): Define.
|
||||
* dwarf2-frame.c (dwarf2_frame_prev_register): Handle
|
||||
DWARF2_FRAME_REG_FN.
|
||||
* dwarf2-frame.h (enum dwarf2_frame_reg_rule): Add
|
||||
DWARF2_FRAME_REG_FN.
|
||||
(struct dwarf2_frame_state_reg): Add FN to loc union.
|
||||
|
||||
2008-05-01 Nick Roberts <nickrob@snap.net.nz>
|
||||
|
||||
* exec.c (print_section_info): Add missing '\n'.
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
struct regset;
|
||||
struct regcache;
|
||||
|
||||
#define ARM_CPSR_REGNUM 16
|
||||
|
||||
#define ARM_LINUX_SIZEOF_NWFPE (8 * FP_REGISTER_SIZE \
|
||||
+ 2 * INT_REGISTER_SIZE \
|
||||
+ 8 + INT_REGISTER_SIZE)
|
||||
|
|
147
gdb/arm-tdep.c
147
gdb/arm-tdep.c
|
@ -211,8 +211,25 @@ struct arm_prologue_cache
|
|||
|
||||
int arm_apcs_32 = 1;
|
||||
|
||||
/* Determine if FRAME is executing in Thumb mode. */
|
||||
|
||||
static int
|
||||
arm_frame_is_thumb (struct frame_info *frame)
|
||||
{
|
||||
CORE_ADDR cpsr;
|
||||
|
||||
/* Every ARM frame unwinder can unwind the T bit of the CPSR, either
|
||||
directly (from a signal frame or dummy frame) or by interpreting
|
||||
the saved LR (from a prologue or DWARF frame). So consult it and
|
||||
trust the unwinders. */
|
||||
cpsr = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
|
||||
|
||||
return (cpsr & CPSR_T) != 0;
|
||||
}
|
||||
|
||||
/* Determine if the program counter specified in MEMADDR is in a Thumb
|
||||
function. */
|
||||
function. This function should be called for addresses unrelated to
|
||||
any executing frame; otherwise, prefer arm_frame_is_thumb. */
|
||||
|
||||
static int
|
||||
arm_pc_is_thumb (CORE_ADDR memaddr)
|
||||
|
@ -273,14 +290,6 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
|
|||
stack = make_pv_area (ARM_SP_REGNUM);
|
||||
back_to = make_cleanup_free_pv_area (stack);
|
||||
|
||||
/* The call instruction saved PC in LR, and the current PC is not
|
||||
interesting. Due to this file's conventions, we want the value
|
||||
of LR at this function's entry, not at the call site, so we do
|
||||
not record the save of the PC - when the ARM prologue analyzer
|
||||
has also been converted to the pv mechanism, we could record the
|
||||
save here and remove the hack in prev_register. */
|
||||
regs[ARM_PC_REGNUM] = pv_unknown ();
|
||||
|
||||
while (start < limit)
|
||||
{
|
||||
unsigned short insn;
|
||||
|
@ -535,22 +544,14 @@ arm_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
|
|||
|
||||
static void
|
||||
thumb_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR prev_pc,
|
||||
struct arm_prologue_cache *cache)
|
||||
CORE_ADDR block_addr, struct arm_prologue_cache *cache)
|
||||
{
|
||||
CORE_ADDR prologue_start;
|
||||
CORE_ADDR prologue_end;
|
||||
CORE_ADDR current_pc;
|
||||
/* Which register has been copied to register n? */
|
||||
int saved_reg[16];
|
||||
/* findmask:
|
||||
bit 0 - push { rlist }
|
||||
bit 1 - mov r7, sp OR add r7, sp, #imm (setting of r7)
|
||||
bit 2 - sub sp, #simm OR add sp, #simm (adjusting of sp)
|
||||
*/
|
||||
int findmask = 0;
|
||||
int i;
|
||||
|
||||
if (find_pc_partial_function (prev_pc, NULL, &prologue_start, &prologue_end))
|
||||
if (find_pc_partial_function (block_addr, NULL, &prologue_start,
|
||||
&prologue_end))
|
||||
{
|
||||
struct symtab_and_line sal = find_pc_line (prologue_start, 0);
|
||||
|
||||
|
@ -644,6 +645,7 @@ arm_scan_prologue (struct frame_info *this_frame,
|
|||
int regno;
|
||||
CORE_ADDR prologue_start, prologue_end, current_pc;
|
||||
CORE_ADDR prev_pc = get_frame_pc (this_frame);
|
||||
CORE_ADDR block_addr = get_frame_address_in_block (this_frame);
|
||||
pv_t regs[ARM_FPS_REGNUM];
|
||||
struct pv_area *stack;
|
||||
struct cleanup *back_to;
|
||||
|
@ -654,15 +656,16 @@ arm_scan_prologue (struct frame_info *this_frame,
|
|||
cache->framesize = 0;
|
||||
|
||||
/* Check for Thumb prologue. */
|
||||
if (arm_pc_is_thumb (prev_pc))
|
||||
if (arm_frame_is_thumb (this_frame))
|
||||
{
|
||||
thumb_scan_prologue (gdbarch, prev_pc, cache);
|
||||
thumb_scan_prologue (gdbarch, prev_pc, block_addr, 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 (prev_pc, NULL, &prologue_start, &prologue_end))
|
||||
if (find_pc_partial_function (block_addr, 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:
|
||||
|
@ -751,8 +754,6 @@ arm_scan_prologue (struct frame_info *this_frame,
|
|||
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;
|
||||
current_pc += 4)
|
||||
|
@ -985,10 +986,18 @@ arm_prologue_prev_register (struct frame_info *this_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. */
|
||||
instead. The prologue may save PC, but it will point into this
|
||||
frame's prologue, not the next frame's resume location. Also
|
||||
strip the saved T bit. A valid LR may have the low bit set, but
|
||||
a valid PC never does. */
|
||||
if (prev_regnum == ARM_PC_REGNUM)
|
||||
prev_regnum = ARM_LR_REGNUM;
|
||||
{
|
||||
CORE_ADDR lr;
|
||||
|
||||
lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM);
|
||||
return frame_unwind_got_constant (this_frame, prev_regnum,
|
||||
arm_addr_bits_remove (lr));
|
||||
}
|
||||
|
||||
/* SP is generally not saved to the stack, but this frame is
|
||||
identified by the next frame's stack pointer at the time of the call.
|
||||
|
@ -996,6 +1005,27 @@ arm_prologue_prev_register (struct frame_info *this_frame,
|
|||
if (prev_regnum == ARM_SP_REGNUM)
|
||||
return frame_unwind_got_constant (this_frame, prev_regnum, cache->prev_sp);
|
||||
|
||||
/* The CPSR may have been changed by the call instruction and by the
|
||||
called function. The only bit we can reconstruct is the T bit,
|
||||
by checking the low bit of LR as of the call. This is a reliable
|
||||
indicator of Thumb-ness except for some ARM v4T pre-interworking
|
||||
Thumb code, which could get away with a clear low bit as long as
|
||||
the called function did not use bx. Guess that all other
|
||||
bits are unchanged; the condition flags are presumably lost,
|
||||
but the processor status is likely valid. */
|
||||
if (prev_regnum == ARM_PS_REGNUM)
|
||||
{
|
||||
CORE_ADDR lr, cpsr;
|
||||
|
||||
cpsr = get_frame_register_unsigned (this_frame, prev_regnum);
|
||||
lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM);
|
||||
if (IS_THUMB_ADDR (lr))
|
||||
cpsr |= CPSR_T;
|
||||
else
|
||||
cpsr &= ~CPSR_T;
|
||||
return frame_unwind_got_constant (this_frame, prev_regnum, cpsr);
|
||||
}
|
||||
|
||||
return trad_frame_get_prev_register (this_frame, cache->saved_regs,
|
||||
prev_regnum);
|
||||
}
|
||||
|
@ -1113,6 +1143,59 @@ arm_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
|
|||
return frame_unwind_register_unsigned (this_frame, ARM_SP_REGNUM);
|
||||
}
|
||||
|
||||
static struct value *
|
||||
arm_dwarf2_prev_register (struct frame_info *this_frame, void **this_cache,
|
||||
int regnum)
|
||||
{
|
||||
CORE_ADDR lr, cpsr;
|
||||
|
||||
switch (regnum)
|
||||
{
|
||||
case ARM_PC_REGNUM:
|
||||
/* The PC is normally copied from the return column, which
|
||||
describes saves of LR. However, that version may have an
|
||||
extra bit set to indicate Thumb state. The bit is not
|
||||
part of the PC. */
|
||||
lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM);
|
||||
return frame_unwind_got_constant (this_frame, regnum,
|
||||
arm_addr_bits_remove (lr));
|
||||
|
||||
case ARM_PS_REGNUM:
|
||||
/* Reconstruct the T bit; see arm_prologue_prev_register for details. */
|
||||
CORE_ADDR lr, cpsr;
|
||||
|
||||
cpsr = get_frame_register_unsigned (this_frame, prev_regnum);
|
||||
lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM);
|
||||
if (IS_THUMB_ADDR (lr))
|
||||
cpsr |= CPSR_T;
|
||||
else
|
||||
cpsr &= ~CPSR_T;
|
||||
return frame_unwind_got_constant (this_frame, prev_regnum, cpsr);
|
||||
|
||||
default:
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("Unexpected register %d"), regnum);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
arm_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
|
||||
struct dwarf2_frame_state_reg *reg,
|
||||
struct frame_info *this_frame)
|
||||
{
|
||||
switch (regnum)
|
||||
{
|
||||
case ARM_PC_REGNUM:
|
||||
case ARM_PS_REGNUM:
|
||||
reg->how = DWARF2_FRAME_REG_FN;
|
||||
reg->loc.fn = arm_dwarf2_prev_register;
|
||||
break;
|
||||
case ARM_SP_REGNUM:
|
||||
reg->how = DWARF2_FRAME_REG_CFA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* When arguments must be pushed onto the stack, they go on in reverse
|
||||
order. The code below implements a FILO (stack) to do this. */
|
||||
|
||||
|
@ -1694,7 +1777,7 @@ arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
|
|||
unsigned long status;
|
||||
CORE_ADDR nextpc;
|
||||
|
||||
if (arm_pc_is_thumb (pc))
|
||||
if (arm_frame_is_thumb (frame))
|
||||
return thumb_get_next_pc (frame, pc);
|
||||
|
||||
pc_val = (unsigned long) pc;
|
||||
|
@ -2667,10 +2750,10 @@ arm_write_pc (struct regcache *regcache, CORE_ADDR pc)
|
|||
ULONGEST val;
|
||||
regcache_cooked_read_unsigned (regcache, ARM_PS_REGNUM, &val);
|
||||
if (arm_pc_is_thumb (pc))
|
||||
regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM, val | 0x20);
|
||||
regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM, val | CPSR_T);
|
||||
else
|
||||
regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM,
|
||||
val & ~(ULONGEST) 0x20);
|
||||
val & ~(ULONGEST) CPSR_T);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3034,6 +3117,8 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
|
|||
/* Hook in the ABI-specific overrides, if they have been registered. */
|
||||
gdbarch_init_osabi (info, gdbarch);
|
||||
|
||||
dwarf2_frame_set_init_reg (gdbarch, arm_dwarf2_frame_init_reg);
|
||||
|
||||
/* Add some default predicates. */
|
||||
frame_unwind_append_unwinder (gdbarch, &arm_stub_unwind);
|
||||
dwarf2_append_unwinders (gdbarch);
|
||||
|
|
|
@ -38,6 +38,7 @@ enum gdb_regnum {
|
|||
ARM_F7_REGNUM = 23, /* last floating point register */
|
||||
ARM_FPS_REGNUM = 24, /* floating point status register */
|
||||
ARM_PS_REGNUM = 25, /* Contains processor status */
|
||||
ARM_CPSR_REGNUM = ARM_PS_REGNUM,
|
||||
ARM_WR0_REGNUM, /* WMMX data registers. */
|
||||
ARM_WR15_REGNUM = ARM_WR0_REGNUM + 15,
|
||||
ARM_WC0_REGNUM, /* WMMX control registers. */
|
||||
|
@ -107,6 +108,8 @@ enum gdb_regnum {
|
|||
#define FLAG_C 0x20000000
|
||||
#define FLAG_V 0x10000000
|
||||
|
||||
#define CPSR_T 0x20
|
||||
|
||||
/* Type of floating-point code in use by inferior. There are really 3 models
|
||||
that are traditionally supported (plus the endianness issue), but gcc can
|
||||
only generate 2 of those. The third is APCS_FLOAT, where arguments to
|
||||
|
|
|
@ -1139,6 +1139,9 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache,
|
|||
addr += get_frame_register_unsigned (this_frame, regnum);
|
||||
return frame_unwind_got_address (this_frame, regnum, addr);
|
||||
|
||||
case DWARF2_FRAME_REG_FN:
|
||||
return cache->reg[regnum].loc.fn (this_frame, this_cache, regnum);
|
||||
|
||||
default:
|
||||
internal_error (__FILE__, __LINE__, _("Unknown register rule."));
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ enum dwarf2_frame_reg_rule
|
|||
|
||||
/* These aren't defined by the DWARF2 CFI specification, but are
|
||||
used internally by GDB. */
|
||||
DWARF2_FRAME_REG_FN, /* Call a registered function. */
|
||||
DWARF2_FRAME_REG_RA, /* Return Address. */
|
||||
DWARF2_FRAME_REG_RA_OFFSET, /* Return Address with offset. */
|
||||
DWARF2_FRAME_REG_CFA, /* Call Frame Address. */
|
||||
|
@ -71,6 +72,8 @@ struct dwarf2_frame_state_reg
|
|||
LONGEST offset;
|
||||
ULONGEST reg;
|
||||
unsigned char *exp;
|
||||
struct value *(*fn) (struct frame_info *this_frame, void **this_cache,
|
||||
int regnum);
|
||||
} loc;
|
||||
ULONGEST exp_len;
|
||||
enum dwarf2_frame_reg_rule how;
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2007-05-01 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* gdb.arch/thumb-prologue.exp: Do not expect a saved PC.
|
||||
|
||||
2008-05-01 Joel Brobecker <brobecker@adacore.com>
|
||||
|
||||
* gdb.base/info-target.exp: New testcase.
|
||||
|
|
|
@ -57,5 +57,5 @@ gdb_test "backtrace 10" \
|
|||
"backtrace in TPCS"
|
||||
|
||||
gdb_test "info frame" \
|
||||
".*Saved registers:.*r7 at.*r10 at.*r11 at.*lr at.*pc at .*" \
|
||||
".*Saved registers:.*r7 at.*r10 at.*r11 at.*lr at.*" \
|
||||
"saved registers in TPCS"
|
||||
|
|
Loading…
Reference in New Issue