This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[commit] Improve ARM prologue analysis
- From: Daniel Jacobowitz <dan at codesourcery dot com>
- To: gdb-patches at sourceware dot org
- Date: Wed, 24 Mar 2010 16:36:00 -0400
- Subject: [commit] Improve ARM prologue analysis
This patch contains a collection of improvements to the ARM prologue
analyzers.
These improvements were motivated by testing GDB with RealView. One
cause of failures is that GDB stops on the opening brace of the
function, or skips the first actual line of the function. GDB
relies on the GCC extension of always emitting a second line note at
the end of the prologue; I am not aware of a non-GCC compiler that
does this. This is particularly problematic if the prologue is empty.
Then there's no prologue line note at all, and we skip into the
function.
The fix I chose was to check the producer, and for non-GNU objects
where we can not rely on the line note, check using the prologue
skipper instead. If the prologue skipper considers every instruction
in the first line of the function to be valid for a prologue, then we
skip the whole line. The same approach could be applied to GNU
objects by dropping the producer check; but it's not necessary to do
so.
The comments in the patch should explain all the various new things I
checked for. There's a lot of new instructions, especially on Thumb
where stack adjustment can involve the constant pool. For
unprototyped functions with float arguments, there are calls to a
library function to convert the passed doubles to floats. And
other than those calls, we never skip over a branch.
Tested on arm-eabi, with no regressions for either GCC or RealView,
ARM or Thumb or Thumb-2. Checked in.
--
Daniel Jacobowitz
CodeSourcery
2010-03-24 Daniel Jacobowitz <dan@codesourcery.com>
* arm-tdep.c (skip_prologue_function): New function.
(submask, bit, bits, sbits, BranchDest): Move higher in the file.
(thumb_analyze_prologue): Document return value. Recognize more
Thumb instructions, skippable calls, and some Thumb-2 instructions.
Add debug output.
(arm_skip_prologue): Remove call dummy check. Check the prologue
for non-GNU compilers.
(arm_instruction_changes_pc): New function.
(arm_analyze_prologue): New function, broken out from
arm_scan_prologue. Recognize more ARM instructions and skippable
calls. Update comments. Handle NULL cache. Return the address
of the first unrecognized instruction. Do not skip past other
instructions which change control flow. Add debug output.
(arm_scan_prologue): Use arm_analyze_prologue.
(ARM_PC_32): Delete.
(shifted_reg_val): Simplify ARM_PC_32 check.
---
gdb/arm-tdep.c | 735 +++++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 529 insertions(+), 206 deletions(-)
Index: gdb-mainline/gdb/arm-tdep.c
===================================================================
--- gdb-mainline.orig/gdb/arm-tdep.c 2010-03-13 20:35:55.000000000 -0800
+++ gdb-mainline/gdb/arm-tdep.c 2010-03-13 21:33:52.000000000 -0800
@@ -235,6 +235,11 @@ struct arm_prologue_cache
struct trad_frame_saved_reg *saved_regs;
};
+static CORE_ADDR arm_analyze_prologue (struct gdbarch *gdbarch,
+ CORE_ADDR prologue_start,
+ CORE_ADDR prologue_end,
+ struct arm_prologue_cache *cache);
+
/* Architecture version for displaced stepping. This effects the behaviour of
certain instructions, and really should not be hard-wired. */
@@ -424,15 +429,59 @@ arm_smash_text_address (struct gdbarch *
return val & ~1;
}
+/* Return 1 if PC is the start of a compiler helper function which
+ can be safely ignored during prologue skipping. */
+static int
+skip_prologue_function (CORE_ADDR pc)
+{
+ struct minimal_symbol *msym;
+ const char *name;
+
+ msym = lookup_minimal_symbol_by_pc (pc);
+ if (msym == NULL || SYMBOL_VALUE_ADDRESS (msym) != pc)
+ return 0;
+
+ name = SYMBOL_LINKAGE_NAME (msym);
+ if (name == NULL)
+ return 0;
+
+ /* The GNU linker's Thumb call stub to foo is named
+ __foo_from_thumb. */
+ if (strstr (name, "_from_thumb") != NULL)
+ name += 2;
+
+ /* On soft-float targets, __truncdfsf2 is called to convert promoted
+ arguments to their argument types in non-prototyped
+ functions. */
+ if (strncmp (name, "__truncdfsf2", strlen ("__truncdfsf2")) == 0)
+ return 1;
+ if (strncmp (name, "__aeabi_d2f", strlen ("__aeabi_d2f")) == 0)
+ return 1;
+
+ return 0;
+}
+
+/* Support routines for instruction parsing. */
+#define submask(x) ((1L << ((x) + 1)) - 1)
+#define bit(obj,st) (((obj) >> (st)) & 1)
+#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st)))
+#define sbits(obj,st,fn) \
+ ((long) (bits(obj,st,fn) | ((long) bit(obj,fn) * ~ submask (fn - st))))
+#define BranchDest(addr,instr) \
+ ((CORE_ADDR) (((long) (addr)) + 8 + (sbits (instr, 0, 23) << 2)))
+
/* Analyze a Thumb prologue, looking for a recognizable stack frame
and frame pointer. Scan until we encounter a store that could
- clobber the stack frame unexpectedly, or an unknown instruction. */
+ clobber the stack frame unexpectedly, or an unknown instruction.
+ Return the last address which is definitely safe to skip for an
+ initial breakpoint. */
static CORE_ADDR
thumb_analyze_prologue (struct gdbarch *gdbarch,
CORE_ADDR start, CORE_ADDR limit,
struct arm_prologue_cache *cache)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
int i;
pv_t regs[16];
@@ -483,9 +532,29 @@ thumb_analyze_prologue (struct gdbarch *
regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
offset);
}
- else if ((insn & 0xff00) == 0xaf00) /* add r7, sp, #imm */
- regs[THUMB_FP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
- (insn & 0xff) << 2);
+ else if ((insn & 0xf800) == 0xa800) /* add Rd, sp, #imm */
+ regs[bits (insn, 8, 10)] = pv_add_constant (regs[ARM_SP_REGNUM],
+ (insn & 0xff) << 2);
+ else if ((insn & 0xfe00) == 0x1c00 /* add Rd, Rn, #imm */
+ && pv_is_register (regs[bits (insn, 3, 5)], ARM_SP_REGNUM))
+ regs[bits (insn, 0, 2)] = pv_add_constant (regs[bits (insn, 3, 5)],
+ bits (insn, 6, 8));
+ else if ((insn & 0xf800) == 0x3000 /* add Rd, #imm */
+ && pv_is_register (regs[bits (insn, 8, 10)], ARM_SP_REGNUM))
+ regs[bits (insn, 8, 10)] = pv_add_constant (regs[bits (insn, 8, 10)],
+ bits (insn, 0, 7));
+ else if ((insn & 0xfe00) == 0x1800 /* add Rd, Rn, Rm */
+ && pv_is_register (regs[bits (insn, 6, 8)], ARM_SP_REGNUM)
+ && pv_is_constant (regs[bits (insn, 3, 5)]))
+ regs[bits (insn, 0, 2)] = pv_add (regs[bits (insn, 3, 5)],
+ regs[bits (insn, 6, 8)]);
+ else if ((insn & 0xff00) == 0x4400 /* add Rd, Rm */
+ && pv_is_constant (regs[bits (insn, 3, 6)]))
+ {
+ int rd = (bit (insn, 7) << 3) + bits (insn, 0, 2);
+ int rm = bits (insn, 3, 6);
+ regs[rd] = pv_add (regs[rd], regs[rm]);
+ }
else if ((insn & 0xff00) == 0x4600) /* mov hi, lo or mov lo, hi */
{
int dst_reg = (insn & 0x7) + ((insn & 0x80) >> 4);
@@ -508,6 +577,131 @@ thumb_analyze_prologue (struct gdbarch *
pv_area_store (stack, addr, 4, regs[regno]);
}
+ else if ((insn & 0xf800) == 0x6000) /* str rd, [rn, #off] */
+ {
+ int rd = bits (insn, 0, 2);
+ int rn = bits (insn, 3, 5);
+ pv_t addr;
+
+ offset = bits (insn, 6, 10) << 2;
+ addr = pv_add_constant (regs[rn], offset);
+
+ if (pv_area_store_would_trash (stack, addr))
+ break;
+
+ pv_area_store (stack, addr, 4, regs[rd]);
+ }
+ else if (((insn & 0xf800) == 0x7000 /* strb Rd, [Rn, #off] */
+ || (insn & 0xf800) == 0x8000) /* strh Rd, [Rn, #off] */
+ && pv_is_register (regs[bits (insn, 3, 5)], ARM_SP_REGNUM))
+ /* Ignore stores of argument registers to the stack. */
+ ;
+ else if ((insn & 0xf800) == 0xc800 /* ldmia Rn!, { registers } */
+ && pv_is_register (regs[bits (insn, 8, 10)], ARM_SP_REGNUM))
+ /* Ignore block loads from the stack, potentially copying
+ parameters from memory. */
+ ;
+ else if ((insn & 0xf800) == 0x9800 /* ldr Rd, [Rn, #immed] */
+ || ((insn & 0xf800) == 0x6800 /* ldr Rd, [sp, #immed] */
+ && pv_is_register (regs[bits (insn, 3, 5)], ARM_SP_REGNUM)))
+ /* Similarly ignore single loads from the stack. */
+ ;
+ else if ((insn & 0xffc0) == 0x0000 /* lsls Rd, Rm, #0 */
+ || (insn & 0xffc0) == 0x1c00) /* add Rd, Rn, #0 */
+ /* Skip register copies, i.e. saves to another register
+ instead of the stack. */
+ ;
+ else if ((insn & 0xf800) == 0x2000) /* movs Rd, #imm */
+ /* Recognize constant loads; even with small stacks these are necessary
+ on Thumb. */
+ regs[bits (insn, 8, 10)] = pv_constant (bits (insn, 0, 7));
+ else if ((insn & 0xf800) == 0x4800) /* ldr Rd, [pc, #imm] */
+ {
+ /* Constant pool loads, for the same reason. */
+ unsigned int constant;
+ CORE_ADDR loc;
+
+ loc = start + 4 + bits (insn, 0, 7) * 4;
+ constant = read_memory_unsigned_integer (loc, 4, byte_order);
+ regs[bits (insn, 8, 10)] = pv_constant (constant);
+ }
+ else if ((insn & 0xe000) == 0xe000 && cache == NULL)
+ {
+ /* Only recognize 32-bit instructions for prologue skipping. */
+ unsigned short inst2;
+
+ inst2 = read_memory_unsigned_integer (start + 2, 2,
+ byte_order_for_code);
+
+ if ((insn & 0xf800) == 0xf000 && (inst2 & 0xe800) == 0xe800)
+ {
+ /* BL, BLX. Allow some special function calls when
+ skipping the prologue; GCC generates these before
+ storing arguments to the stack. */
+ CORE_ADDR nextpc;
+ int j1, j2, imm1, imm2;
+
+ imm1 = sbits (insn, 0, 10);
+ imm2 = bits (inst2, 0, 10);
+ j1 = bit (inst2, 13);
+ j2 = bit (inst2, 11);
+
+ offset = ((imm1 << 12) + (imm2 << 1));
+ offset ^= ((!j2) << 22) | ((!j1) << 23);
+
+ nextpc = start + 4 + offset;
+ /* For BLX make sure to clear the low bits. */
+ if (bit (inst2, 12) == 0)
+ nextpc = nextpc & 0xfffffffc;
+
+ if (!skip_prologue_function (nextpc))
+ break;
+ }
+ else if ((insn & 0xfe50) == 0xe800 /* stm{db,ia} Rn[!], { registers } */
+ && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+ ;
+ else if ((insn & 0xfe50) == 0xe840 /* strd Rt, Rt2, [Rn, #imm] */
+ && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+ ;
+ else if ((insn & 0xffd0) == 0xe890 /* ldmia Rn[!], { registers } */
+ && (inst2 & 0x8000) == 0x0000
+ && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+ ;
+ else if ((insn & 0xfbf0) == 0xf100 /* add.w Rd, Rn, #imm */
+ && (inst2 & 0x8000) == 0x0000)
+ /* Since we only recognize this for prologue skipping, do not bother
+ to compute the constant. */
+ regs[bits (inst2, 8, 11)] = regs[bits (insn, 0, 3)];
+ else if ((insn & 0xfbf0) == 0xf1a0 /* sub.w Rd, Rn, #imm12 */
+ && (inst2 & 0x8000) == 0x0000)
+ /* Since we only recognize this for prologue skipping, do not bother
+ to compute the constant. */
+ regs[bits (inst2, 8, 11)] = regs[bits (insn, 0, 3)];
+ else if ((insn & 0xfbf0) == 0xf2a0 /* sub.w Rd, Rn, #imm8 */
+ && (inst2 & 0x8000) == 0x0000)
+ /* Since we only recognize this for prologue skipping, do not bother
+ to compute the constant. */
+ regs[bits (inst2, 8, 11)] = regs[bits (insn, 0, 3)];
+ else if ((insn & 0xff50) == 0xf850 /* ldr.w Rd, [Rn, #imm]{!} */
+ && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+ ;
+ else if ((insn & 0xff50) == 0xe950 /* ldrd Rt, Rt2, [Rn, #imm]{!} */
+ && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+ ;
+ else if ((insn & 0xff50) == 0xf800 /* strb.w or strh.w */
+ && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+ ;
+ else
+ {
+ /* We don't know what this instruction is. We're finished
+ scanning. NOTE: Recognizing more safe-to-ignore
+ instructions here will improve support for optimized
+ code. */
+ break;
+ }
+
+ start += 2;
+ }
else
{
/* We don't know what this instruction is. We're finished
@@ -520,6 +714,10 @@ thumb_analyze_prologue (struct gdbarch *
start += 2;
}
+ if (arm_debug)
+ fprintf_unfiltered (gdb_stdlog, "Prologue scan stopped at %s\n",
+ paddress (gdbarch, start));
+
if (cache == NULL)
{
do_cleanups (back_to);
@@ -583,10 +781,6 @@ arm_skip_prologue (struct gdbarch *gdbar
CORE_ADDR func_addr, limit_pc;
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 (gdbarch, pc))
- return pc;
-
/* See if we can determine the end of the prologue via the symbol table.
If so, then return either PC, or the PC after the prologue, whichever
is greater. */
@@ -594,8 +788,45 @@ arm_skip_prologue (struct gdbarch *gdbar
{
CORE_ADDR post_prologue_pc
= skip_prologue_using_sal (gdbarch, func_addr);
+ struct symtab *s = find_pc_symtab (func_addr);
+
+ /* GCC always emits a line note before the prologue and another
+ one after, even if the two are at the same address or on the
+ same line. Take advantage of this so that we do not need to
+ know every instruction that might appear in the prologue. We
+ will have producer information for most binaries; if it is
+ missing (e.g. for -gstabs), assuming the GNU tools. */
+ if (post_prologue_pc
+ && (s == NULL
+ || s->producer == NULL
+ || strncmp (s->producer, "GNU ", sizeof ("GNU ") - 1) == 0))
+ return post_prologue_pc;
+
if (post_prologue_pc != 0)
- return max (pc, post_prologue_pc);
+ {
+ CORE_ADDR analyzed_limit;
+
+ /* For non-GCC compilers, make sure the entire line is an
+ acceptable prologue; GDB will round this function's
+ return value up to the end of the following line so we
+ can not skip just part of a line (and we do not want to).
+
+ RealView does not treat the prologue specially, but does
+ associate prologue code with the opening brace; so this
+ lets us skip the first line if we think it is the opening
+ brace. */
+ if (arm_pc_is_thumb (func_addr))
+ analyzed_limit = thumb_analyze_prologue (gdbarch, func_addr,
+ post_prologue_pc, NULL);
+ else
+ analyzed_limit = arm_analyze_prologue (gdbarch, func_addr,
+ post_prologue_pc, NULL);
+
+ if (analyzed_limit != post_prologue_pc)
+ return func_addr;
+
+ return post_prologue_pc;
+ }
}
/* Can't determine prologue from the symbol table, need to examine
@@ -724,167 +955,124 @@ thumb_scan_prologue (struct gdbarch *gdb
thumb_analyze_prologue (gdbarch, prologue_start, prologue_end, cache);
}
-/* This function decodes an ARM function prologue to determine:
- 1) the size of the stack frame
- 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.
-
- There are two basic forms for the ARM prologue. The fixed argument
- function call will look like:
-
- mov ip, sp
- stmfd sp!, {fp, ip, lr, pc}
- sub fp, ip, #4
- [sub sp, sp, #4]
-
- Which would create this stack frame (offsets relative to FP):
- IP -> 4 (caller's stack)
- FP -> 0 PC (points to address of stmfd instruction + 8 in callee)
- -4 LR (return address in caller)
- -8 IP (copy of caller's SP)
- -12 FP (caller's FP)
- SP -> -28 Local variables
-
- The frame size would thus be 32 bytes, and the frame offset would be
- 28 bytes. The stmfd call can also save any of the vN registers it
- plans to use, which increases the frame size accordingly.
-
- Note: The stored PC is 8 off of the STMFD instruction that stored it
- because the ARM Store instructions always store PC + 8 when you read
- the PC register.
-
- A variable argument function call will look like:
-
- mov ip, sp
- stmfd sp!, {a1, a2, a3, a4}
- stmfd sp!, {fp, ip, lr, pc}
- sub fp, ip, #20
-
- Which would create this stack frame (offsets relative to FP):
- IP -> 20 (caller's stack)
- 16 A4
- 12 A3
- 8 A2
- 4 A1
- FP -> 0 PC (points to address of stmfd instruction + 8 in callee)
- -4 LR (return address in caller)
- -8 IP (copy of caller's SP)
- -12 FP (caller's FP)
- SP -> -28 Local variables
-
- The frame size would thus be 48 bytes, and the frame offset would be
- 28 bytes.
-
- There is another potential complication, which is that the optimizer
- will try to separate the store of fp in the "stmfd" instruction from
- the "sub fp, ip, #NN" instruction. Almost anything can be there, so
- we just key on the stmfd, and then scan for the "sub fp, ip, #NN"...
-
- Also, note, the original version of the ARM toolchain claimed that there
- should be an
-
- instruction at the end of the prologue. I have never seen GCC produce
- this, and the ARM docs don't mention it. We still test for it below in
- case it happens...
-
- */
+/* Return 1 if THIS_INSTR might change control flow, 0 otherwise. */
-static void
-arm_scan_prologue (struct frame_info *this_frame,
- struct arm_prologue_cache *cache)
+static int
+arm_instruction_changes_pc (uint32_t this_instr)
{
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- 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;
- CORE_ADDR offset;
+ if (bits (this_instr, 28, 31) == INST_NV)
+ /* Unconditional instructions. */
+ switch (bits (this_instr, 24, 27))
+ {
+ case 0xa:
+ case 0xb:
+ /* Branch with Link and change to Thumb. */
+ return 1;
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ /* Coprocessor register transfer. */
+ if (bits (this_instr, 12, 15) == 15)
+ error (_("Invalid update to pc in instruction"));
+ return 0;
+ default:
+ return 0;
+ }
+ else
+ switch (bits (this_instr, 25, 27))
+ {
+ case 0x0:
+ if (bits (this_instr, 23, 24) == 2 && bit (this_instr, 20) == 0)
+ {
+ /* Multiplies and extra load/stores. */
+ if (bit (this_instr, 4) == 1 && bit (this_instr, 7) == 1)
+ /* Neither multiplies nor extension load/stores are allowed
+ to modify PC. */
+ return 0;
- /* Assume there is no frame until proven otherwise. */
- cache->framereg = ARM_SP_REGNUM;
- cache->framesize = 0;
+ /* Otherwise, miscellaneous instructions. */
- /* Check for Thumb prologue. */
- if (arm_frame_is_thumb (this_frame))
- {
- thumb_scan_prologue (gdbarch, prev_pc, block_addr, cache);
- return;
- }
+ /* BX <reg>, BXJ <reg>, BLX <reg> */
+ if (bits (this_instr, 4, 27) == 0x12fff1
+ || bits (this_instr, 4, 27) == 0x12fff2
+ || bits (this_instr, 4, 27) == 0x12fff3)
+ return 1;
- /* 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 (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:
+ /* Other miscellaneous instructions are unpredictable if they
+ modify PC. */
+ return 0;
+ }
+ /* Data processing instruction. Fall through. */
- struct symtab_and_line sal = find_pc_line (prologue_start, 0);
+ case 0x1:
+ if (bits (this_instr, 12, 15) == 15)
+ return 1;
+ else
+ return 0;
- if (sal.line == 0)
- prologue_end = prev_pc;
- else if (sal.end < prologue_end)
- prologue_end = sal.end;
+ case 0x2:
+ case 0x3:
+ /* Media instructions and architecturally undefined instructions. */
+ if (bits (this_instr, 25, 27) == 3 && bit (this_instr, 4) == 1)
+ return 0;
+
+ /* Stores. */
+ if (bit (this_instr, 20) == 0)
+ return 0;
- This mechanism is very accurate so long as the optimizer
- doesn't move any instructions from the function body into the
- prologue. If this happens, sal.end will be the last
- instruction in the first hunk of prologue code just before
- the first instruction that the scheduler has moved from
- the body to the prologue.
+ /* Loads. */
+ if (bits (this_instr, 12, 15) == ARM_PC_REGNUM)
+ return 1;
+ else
+ return 0;
- In order to make sure that we scan all of the prologue
- instructions, we use a slightly less accurate mechanism which
- may scan more than necessary. To help compensate for this
- lack of accuracy, the prologue scanning loop below contains
- several clauses which'll cause the loop to terminate early if
- an implausible prologue instruction is encountered.
-
- The expression
-
- prologue_start + 64
-
- is a suitable endpoint since it accounts for the largest
- possible prologue plus up to five instructions inserted by
- the scheduler. */
-
- if (prologue_end > prologue_start + 64)
- {
- prologue_end = prologue_start + 64; /* See above. */
- }
- }
- else
- {
- /* 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;
+ case 0x4:
+ /* Load/store multiple. */
+ if (bit (this_instr, 20) == 1 && bit (this_instr, 15) == 1)
+ return 1;
+ else
+ return 0;
- frame_loc = get_frame_register_unsigned (this_frame, ARM_FP_REGNUM);
- if (!safe_read_memory_integer (frame_loc, 4, byte_order, &return_value))
- return;
- else
- {
- prologue_start = gdbarch_addr_bits_remove
- (gdbarch, return_value) - 8;
- prologue_end = prologue_start + 64; /* See above. */
- }
- }
+ case 0x5:
+ /* Branch and branch with link. */
+ return 1;
- if (prev_pc < prologue_end)
- prologue_end = prev_pc;
+ case 0x6:
+ case 0x7:
+ /* Coprocessor transfers or SWIs can not affect PC. */
+ return 0;
- /* Now search the prologue looking for instructions that set up the
+ default:
+ internal_error (__FILE__, __LINE__, "bad value in switch");
+ }
+}
+
+/* Analyze an ARM mode prologue starting at PROLOGUE_START and
+ continuing no further than PROLOGUE_END. If CACHE is non-NULL,
+ fill it in. Return the first address not recognized as a prologue
+ instruction.
+
+ We recognize all the instructions typically found in ARM prologues,
+ plus harmless instructions which can be skipped (either for analysis
+ purposes, or a more restrictive set that can be skipped when finding
+ the end of the prologue). */
+
+static CORE_ADDR
+arm_analyze_prologue (struct gdbarch *gdbarch,
+ CORE_ADDR prologue_start, CORE_ADDR prologue_end,
+ struct arm_prologue_cache *cache)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+ int regno;
+ CORE_ADDR offset, current_pc;
+ pv_t regs[ARM_FPS_REGNUM];
+ struct pv_area *stack;
+ struct cleanup *back_to;
+ int framereg, framesize;
+ CORE_ADDR unrecognized_pc = 0;
+
+ /* Search the prologue looking for instructions that set up the
frame pointer, adjust the stack pointer, and save registers.
Be careful, however, and if it doesn't look like a prologue,
@@ -892,18 +1080,7 @@ arm_scan_prologue (struct frame_info *th
begins with stmfd sp!, then we will tell ourselves there is
a frame, which will confuse stack traceback, as well as "finish"
and other operations that rely on a knowledge of the stack
- traceback.
-
- In the APCS, the prologue should start with "mov ip, sp" so
- if we don't see this as the first insn, we will stop.
-
- [Note: This doesn't seem to be true any longer, so it's now an
- optional part of the prologue. - Kevin Buettner, 2001-11-20]
-
- [Note further: The "mov ip,sp" only seems to be missing in
- frameless functions at optimization level "-O2" or above,
- in which case it is often (but not always) replaced by
- "str lr, [sp, #-4]!". - Michael Snyder, 2002-04-23] */
+ traceback. */
for (regno = 0; regno < ARM_FPS_REGNUM; regno++)
regs[regno] = pv_register (regno, 0);
@@ -922,28 +1099,33 @@ arm_scan_prologue (struct frame_info *th
regs[ARM_IP_REGNUM] = regs[ARM_SP_REGNUM];
continue;
}
- else if ((insn & 0xfffff000) == 0xe28dc000) /* add ip, sp #n */
+ else if ((insn & 0xfff00000) == 0xe2800000 /* add Rd, Rn, #n */
+ && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
{
unsigned imm = insn & 0xff; /* immediate value */
unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */
+ int rd = bits (insn, 12, 15);
imm = (imm >> rot) | (imm << (32 - rot));
- regs[ARM_IP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], imm);
+ regs[rd] = pv_add_constant (regs[bits (insn, 16, 19)], imm);
continue;
}
- else if ((insn & 0xfffff000) == 0xe24dc000) /* sub ip, sp #n */
+ else if ((insn & 0xfff00000) == 0xe2400000 /* sub Rd, Rn, #n */
+ && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
{
unsigned imm = insn & 0xff; /* immediate value */
unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */
+ int rd = bits (insn, 12, 15);
imm = (imm >> rot) | (imm << (32 - rot));
- regs[ARM_IP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -imm);
+ regs[rd] = pv_add_constant (regs[bits (insn, 16, 19)], -imm);
continue;
}
- else if (insn == 0xe52de004) /* str lr, [sp, #-4]! */
+ else if ((insn & 0xffff0fff) == 0xe52d0004) /* str Rd, [sp, #-4]! */
{
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]);
+ pv_area_store (stack, regs[ARM_SP_REGNUM], 4,
+ regs[bits (insn, 12, 15)]);
continue;
}
else if ((insn & 0xffff0000) == 0xe92d0000)
@@ -964,20 +1146,26 @@ arm_scan_prologue (struct frame_info *th
pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]);
}
}
- else if ((insn & 0xffffc000) == 0xe54b0000 /* strb rx,[r11,#-n] */
- || (insn & 0xffffc0f0) == 0xe14b00b0 /* strh rx,[r11,#-n] */
+ else if ((insn & 0xffff0000) == 0xe54b0000 /* strb rx,[r11,#-n] */
+ || (insn & 0xffff00f0) == 0xe14b00b0 /* strh rx,[r11,#-n] */
|| (insn & 0xffffc000) == 0xe50b0000) /* str rx,[r11,#-n] */
{
/* No need to add this to saved_regs -- it's just an arg reg. */
continue;
}
- else if ((insn & 0xffffc000) == 0xe5cd0000 /* strb rx,[sp,#n] */
- || (insn & 0xffffc0f0) == 0xe1cd00b0 /* strh rx,[sp,#n] */
+ else if ((insn & 0xffff0000) == 0xe5cd0000 /* strb rx,[sp,#n] */
+ || (insn & 0xffff00f0) == 0xe1cd00b0 /* strh rx,[sp,#n] */
|| (insn & 0xffffc000) == 0xe58d0000) /* str rx,[sp,#n] */
{
/* No need to add this to saved_regs -- it's just an arg reg. */
continue;
}
+ else if ((insn & 0xfff00000) == 0xe8800000 /* stm Rn, { registers } */
+ && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
+ {
+ /* No need to add this to saved_regs -- it's just arg regs. */
+ continue;
+ }
else if ((insn & 0xfffff000) == 0xe24cb000) /* sub fp, ip #n */
{
unsigned imm = insn & 0xff; /* immediate value */
@@ -1035,42 +1223,188 @@ arm_scan_prologue (struct frame_info *th
regs[fp_start_reg++]);
}
}
+ else if ((insn & 0xff000000) == 0xeb000000 && cache == NULL) /* bl */
+ {
+ /* Allow some special function calls when skipping the
+ prologue; GCC generates these before storing arguments to
+ the stack. */
+ CORE_ADDR dest = BranchDest (current_pc, insn);
+
+ if (skip_prologue_function (dest))
+ continue;
+ else
+ break;
+ }
else if ((insn & 0xf0000000) != 0xe0000000)
break; /* Condition not true, exit early */
- else if ((insn & 0xfe200000) == 0xe8200000) /* ldm? */
- break; /* Don't scan past a block load */
- else
- /* The optimizer might shove anything into the prologue,
- so we just skip what we don't recognize. */
+ else if (arm_instruction_changes_pc (insn))
+ /* Don't scan past anything that might change control flow. */
+ break;
+ else if ((insn & 0xfe500000) == 0xe8100000) /* ldm */
+ {
+ /* Ignore block loads from the stack, potentially copying
+ parameters from memory. */
+ if (pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
+ continue;
+ else
+ break;
+ }
+ else if ((insn & 0xfc500000) == 0xe4100000)
+ {
+ /* Similarly ignore single loads from the stack. */
+ if (pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
+ continue;
+ else
+ break;
+ }
+ else if ((insn & 0xffff0ff0) == 0xe1a00000)
+ /* MOV Rd, Rm. Skip register copies, i.e. saves to another
+ register instead of the stack. */
continue;
+ else
+ {
+ /* The optimizer might shove anything into the prologue,
+ so we just skip what we don't recognize. */
+ unrecognized_pc = current_pc;
+ continue;
+ }
}
+ if (unrecognized_pc == 0)
+ unrecognized_pc = current_pc;
+
/* 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;
+ framereg = ARM_FP_REGNUM;
+ 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;
+ framereg = ARM_SP_REGNUM;
+ framesize = -regs[ARM_SP_REGNUM].k;
}
else
{
/* We're just out of luck. We don't know where the frame is. */
- cache->framereg = -1;
- cache->framesize = 0;
+ framereg = -1;
+ 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;
+ if (cache)
+ {
+ cache->framereg = framereg;
+ cache->framesize = framesize;
+
+ for (regno = 0; regno < ARM_FPS_REGNUM; regno++)
+ if (pv_area_find_reg (stack, gdbarch, regno, &offset))
+ cache->saved_regs[regno].addr = offset;
+ }
+
+ if (arm_debug)
+ fprintf_unfiltered (gdb_stdlog, "Prologue scan stopped at %s\n",
+ paddress (gdbarch, unrecognized_pc));
do_cleanups (back_to);
+ return unrecognized_pc;
+}
+
+static void
+arm_scan_prologue (struct frame_info *this_frame,
+ struct arm_prologue_cache *cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ 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;
+ CORE_ADDR offset;
+
+ /* Assume there is no frame until proven otherwise. */
+ cache->framereg = ARM_SP_REGNUM;
+ cache->framesize = 0;
+
+ /* Check for Thumb prologue. */
+ if (arm_frame_is_thumb (this_frame))
+ {
+ 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 (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:
+
+ struct symtab_and_line sal = find_pc_line (prologue_start, 0);
+
+ if (sal.line == 0)
+ prologue_end = prev_pc;
+ else if (sal.end < prologue_end)
+ prologue_end = sal.end;
+
+ This mechanism is very accurate so long as the optimizer
+ doesn't move any instructions from the function body into the
+ prologue. If this happens, sal.end will be the last
+ instruction in the first hunk of prologue code just before
+ the first instruction that the scheduler has moved from
+ the body to the prologue.
+
+ In order to make sure that we scan all of the prologue
+ instructions, we use a slightly less accurate mechanism which
+ may scan more than necessary. To help compensate for this
+ lack of accuracy, the prologue scanning loop below contains
+ several clauses which'll cause the loop to terminate early if
+ an implausible prologue instruction is encountered.
+
+ The expression
+
+ prologue_start + 64
+
+ is a suitable endpoint since it accounts for the largest
+ possible prologue plus up to five instructions inserted by
+ the scheduler. */
+
+ if (prologue_end > prologue_start + 64)
+ {
+ prologue_end = prologue_start + 64; /* See above. */
+ }
+ }
+ else
+ {
+ /* 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 = get_frame_register_unsigned (this_frame, ARM_FP_REGNUM);
+ if (!safe_read_memory_integer (frame_loc, 4, byte_order, &return_value))
+ return;
+ else
+ {
+ prologue_start = gdbarch_addr_bits_remove
+ (gdbarch, return_value) - 8;
+ prologue_end = prologue_start + 64; /* See above. */
+ }
+ }
+
+ if (prev_pc < prologue_end)
+ prologue_end = prev_pc;
+
+ arm_analyze_prologue (gdbarch, prologue_start, prologue_end, cache);
}
static struct arm_prologue_cache *
@@ -2231,16 +2565,6 @@ condition_true (unsigned long cond, unsi
return 1;
}
-/* Support routines for single stepping. Calculate the next PC value. */
-#define submask(x) ((1L << ((x) + 1)) - 1)
-#define bit(obj,st) (((obj) >> (st)) & 1)
-#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st)))
-#define sbits(obj,st,fn) \
- ((long) (bits(obj,st,fn) | ((long) bit(obj,fn) * ~ submask (fn - st))))
-#define BranchDest(addr,instr) \
- ((CORE_ADDR) (((long) (addr)) + 8 + (sbits (instr, 0, 23) << 2)))
-#define ARM_PC_32 1
-
static unsigned long
shifted_reg_val (struct frame_info *frame, unsigned long inst, int carry,
unsigned long pc_val, unsigned long status_reg)
@@ -2259,8 +2583,7 @@ shifted_reg_val (struct frame_info *fram
shift = bits (inst, 7, 11);
res = (rm == 15
- ? ((pc_val | (ARM_PC_32 ? 0 : status_reg))
- + (bit (inst, 4) ? 12 : 8))
+ ? (pc_val + (bit (inst, 4) ? 12 : 8))
: get_frame_register_unsigned (frame, rm));
switch (shifttype)