X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Farm-tdep.c;h=8e9552a1e19d06784e5d48e15df064d5e061e196;hb=df25ebbd091aebc132f97ffd6ce9cf7964a57981;hp=a9abf2d0a49dfcf47675dd83e19ffa39e9acff31;hpb=e0634ccfe8718b76b5e77c983a3cebfa7707747a;p=deliverable%2Fbinutils-gdb.git
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index a9abf2d0a4..8e9552a1e1 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -1,8 +1,6 @@
/* 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, 2008, 2009, 2010, 2011
- Free Software Foundation, Inc.
+ Copyright (C) 1988-2015 Free Software Foundation, Inc.
This file is part of GDB.
@@ -19,14 +17,15 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
+#include "defs.h"
+
#include /* XXX for isupper (). */
-#include "defs.h"
#include "frame.h"
#include "inferior.h"
+#include "infrun.h"
#include "gdbcmd.h"
#include "gdbcore.h"
-#include "gdb_string.h"
#include "dis-asm.h" /* For register styles. */
#include "regcache.h"
#include "reggroups.h"
@@ -41,6 +40,7 @@
#include "dwarf2-frame.h"
#include "gdbtypes.h"
#include "prologue-value.h"
+#include "remote.h"
#include "target-descriptions.h"
#include "user-regs.h"
#include "observer.h"
@@ -52,10 +52,18 @@
#include "coff/internal.h"
#include "elf/arm.h"
-#include "gdb_assert.h"
#include "vec.h"
+#include "record.h"
+#include "record-full.h"
+
#include "features/arm-with-m.c"
+#include "features/arm-with-m-fpa-layout.c"
+#include "features/arm-with-m-vfp-d16.c"
+#include "features/arm-with-iwmmxt.c"
+#include "features/arm-with-vfpv2.c"
+#include "features/arm-with-vfpv3.c"
+#include "features/arm-with-neon.c"
static int arm_debug;
@@ -94,7 +102,7 @@ static struct cmd_list_element *showarmcmdlist = NULL;
/* The type of floating-point to use. Keep this in sync with enum
arm_float_model, and the help string in _initialize_arm_tdep. */
-static const char *fp_model_strings[] =
+static const char *const fp_model_strings[] =
{
"auto",
"softfpa",
@@ -109,7 +117,7 @@ static enum arm_float_model arm_fp_model = ARM_FLOAT_AUTO;
static const char *current_fp_model = "auto";
/* The ABI to use. Keep this in sync with arm_abi_kind. */
-static const char *arm_abi_strings[] =
+static const char *const arm_abi_strings[] =
{
"auto",
"APCS",
@@ -122,7 +130,7 @@ static enum arm_abi_kind arm_abi_global = ARM_ABI_AUTO;
static const char *arm_abi_string = "auto";
/* The execution mode to assume. */
-static const char *arm_mode_strings[] =
+static const char *const arm_mode_strings[] =
{
"auto",
"arm",
@@ -133,6 +141,13 @@ static const char *arm_mode_strings[] =
static const char *arm_fallback_mode_string = "auto";
static const char *arm_force_mode_string = "auto";
+/* Internal override of the execution mode. -1 means no override,
+ 0 means override to ARM mode, 1 means override to Thumb mode.
+ The effect is the same as if arm_force_mode has been set by the
+ user (except the internal override has precedence over a user's
+ arm_force_mode override). */
+static int arm_override_mode = -1;
+
/* Number of different reg name sets (options). */
static int num_disassembly_options;
@@ -213,13 +228,15 @@ static void convert_from_extended (const struct floatformat *, const void *,
static void convert_to_extended (const struct floatformat *, void *,
const void *, int);
-static void arm_neon_quad_read (struct gdbarch *gdbarch,
- struct regcache *regcache,
- int regnum, gdb_byte *buf);
+static enum register_status arm_neon_quad_read (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ int regnum, gdb_byte *buf);
static void arm_neon_quad_write (struct gdbarch *gdbarch,
struct regcache *regcache,
int regnum, const gdb_byte *buf);
+static int thumb_insn_size (unsigned short inst1);
+
struct arm_prologue_cache
{
/* The stack pointer at the time this frame was created; i.e. the
@@ -262,7 +279,7 @@ int arm_apcs_32 = 1;
/* Return the bit mask in ARM_PS_REGNUM that indicates Thumb mode. */
-static int
+int
arm_psr_thumb_bit (struct gdbarch *gdbarch)
{
if (gdbarch_tdep (gdbarch)->is_m)
@@ -356,24 +373,38 @@ arm_find_mapping_symbol (CORE_ADDR memaddr, CORE_ADDR *start)
return 0;
}
-static CORE_ADDR arm_get_next_pc_raw (struct frame_info *frame,
- CORE_ADDR pc, int insert_bkpt);
-
/* Determine if the program counter specified in MEMADDR is in a Thumb
function. This function should be called for addresses unrelated to
any executing frame; otherwise, prefer arm_frame_is_thumb. */
-static int
+int
arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr)
{
- struct obj_section *sec;
- struct minimal_symbol *sym;
+ struct bound_minimal_symbol sym;
char type;
+ struct displaced_step_closure* dsc
+ = get_displaced_step_closure_by_addr(memaddr);
+
+ /* If checking the mode of displaced instruction in copy area, the mode
+ should be determined by instruction on the original address. */
+ if (dsc)
+ {
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog,
+ "displaced: check mode of %.8lx instead of %.8lx\n",
+ (unsigned long) dsc->insn_addr,
+ (unsigned long) memaddr);
+ memaddr = dsc->insn_addr;
+ }
/* If bit 0 of the address is set, assume this is a Thumb address. */
if (IS_THUMB_ADDR (memaddr))
return 1;
+ /* Respect internal mode override if active. */
+ if (arm_override_mode != -1)
+ return arm_override_mode;
+
/* If the user wants to override the symbol table, let him. */
if (strcmp (arm_force_mode_string, "arm") == 0)
return 0;
@@ -391,8 +422,8 @@ arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr)
/* Thumb functions have a "special" bit set in minimal symbols. */
sym = lookup_minimal_symbol_by_pc (memaddr);
- if (sym)
- return (MSYMBOL_IS_SPECIAL (sym));
+ if (sym.minsym)
+ return (MSYMBOL_IS_SPECIAL (sym.minsym));
/* If the user wants to override the fallback mode, let them. */
if (strcmp (arm_fallback_mode_string, "arm") == 0)
@@ -404,29 +435,9 @@ arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr)
target, then trust the current value of $cpsr. This lets
"display/i $pc" always show the correct mode (though if there is
a symbol table we will not reach here, so it still may not be
- displayed in the mode it will be executed).
-
- As a further heuristic if we detect that we are doing a single-step we
- see what state executing the current instruction ends up with us being
- in. */
+ displayed in the mode it will be executed). */
if (target_has_registers)
- {
- struct frame_info *current_frame = get_current_frame ();
- CORE_ADDR current_pc = get_frame_pc (current_frame);
- int is_thumb = arm_frame_is_thumb (current_frame);
- CORE_ADDR next_pc;
- if (memaddr == current_pc)
- return is_thumb;
- else
- {
- struct gdbarch *gdbarch = get_frame_arch (current_frame);
- next_pc = arm_get_next_pc_raw (current_frame, current_pc, FALSE);
- if (memaddr == gdbarch_addr_bits_remove (gdbarch, next_pc))
- return IS_THUMB_ADDR (next_pc);
- else
- return is_thumb;
- }
- }
+ return arm_frame_is_thumb (get_current_frame ());
/* Otherwise we're out of luck; we assume ARM. */
return 0;
@@ -436,20 +447,18 @@ arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr)
static CORE_ADDR
arm_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR val)
{
+ /* On M-profile devices, do not strip the low bit from EXC_RETURN
+ (the magic exception return address). */
+ if (gdbarch_tdep (gdbarch)->is_m
+ && (val & 0xfffffff0) == 0xfffffff0)
+ return val;
+
if (arm_apcs_32)
return UNMAKE_THUMB_ADDR (val);
else
return (val & 0x03fffffc);
}
-/* When reading symbols, we need to zap the low bit of the address,
- which may be set to 1 for Thumb functions. */
-static CORE_ADDR
-arm_smash_text_address (struct gdbarch *gdbarch, CORE_ADDR val)
-{
- return val & ~1;
-}
-
/* Return 1 if PC is the start of a compiler helper function which
can be safely ignored during prologue skipping. IS_THUMB is true
if the function is known to be a Thumb function due to the way it
@@ -458,14 +467,14 @@ static int
skip_prologue_function (struct gdbarch *gdbarch, CORE_ADDR pc, int is_thumb)
{
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- struct minimal_symbol *msym;
+ struct bound_minimal_symbol msym;
msym = lookup_minimal_symbol_by_pc (pc);
- if (msym != NULL
- && SYMBOL_VALUE_ADDRESS (msym) == pc
- && SYMBOL_LINKAGE_NAME (msym) != NULL)
+ if (msym.minsym != NULL
+ && BMSYMBOL_VALUE_ADDRESS (msym) == pc
+ && MSYMBOL_LINKAGE_NAME (msym.minsym) != NULL)
{
- const char *name = SYMBOL_LINKAGE_NAME (msym);
+ const char *name = MSYMBOL_LINKAGE_NAME (msym.minsym);
/* The GNU linker's Thumb call stub to foo is named
__foo_from_thumb. */
@@ -511,7 +520,7 @@ skip_prologue_function (struct gdbarch *gdbarch, CORE_ADDR pc, int is_thumb)
#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)))
+ ((CORE_ADDR) (((unsigned long) (addr)) + 8 + (sbits (instr, 0, 23) << 2)))
/* Extract the immediate from instruction movw/movt of encoding T. INSN1 is
the first 16-bit of instruction, and INSN2 is the second 16-bit of
@@ -674,6 +683,17 @@ thumb2_instruction_changes_pc (unsigned short inst1, unsigned short inst2)
return 0;
}
+/* Return 1 if the 16-bit Thumb instruction INSN restores SP in
+ epilogue, 0 otherwise. */
+
+static int
+thumb_instruction_restores_sp (unsigned short insn)
+{
+ return (insn == 0x46bd /* mov sp, r7 */
+ || (insn & 0xff80) == 0xb000 /* add sp, imm */
+ || (insn & 0xfe00) == 0xbc00); /* pop */
+}
+
/* 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.
@@ -726,16 +746,16 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]);
}
}
- else if ((insn & 0xff00) == 0xb000) /* add sp, #simm OR
- sub sp, #simm */
+ else if ((insn & 0xff80) == 0xb080) /* sub sp, #imm */
{
offset = (insn & 0x7f) << 2; /* get scaled offset */
- if (insn & 0x80) /* Check for SUB. */
- regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
- -offset);
- else
- regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
- offset);
+ regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
+ -offset);
+ }
+ else if (thumb_instruction_restores_sp (insn))
+ {
+ /* Don't scan past the epilogue. */
+ break;
}
else if ((insn & 0xf800) == 0xa800) /* add Rd, sp, #imm */
regs[bits (insn, 8, 10)] = pv_add_constant (regs[ARM_SP_REGNUM],
@@ -830,7 +850,7 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
constant = read_memory_unsigned_integer (loc, 4, byte_order);
regs[bits (insn, 8, 10)] = pv_constant (constant);
}
- else if ((insn & 0xe000) == 0xe000)
+ else if (thumb_insn_size (insn) == 4) /* 32-bit Thumb-2 instructions. */
{
unsigned short inst2;
@@ -1061,7 +1081,7 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
unsigned int constant;
CORE_ADDR loc;
- offset = bits (insn, 0, 11);
+ offset = bits (inst2, 0, 11);
if (insn & 0x0080)
loc = start + 4 + offset;
else
@@ -1077,7 +1097,7 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
unsigned int constant;
CORE_ADDR loc;
- offset = bits (insn, 0, 7) << 2;
+ offset = bits (inst2, 0, 7) << 2;
if (insn & 0x0080)
loc = start + 4 + offset;
else
@@ -1144,18 +1164,12 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
cache->framereg = THUMB_FP_REGNUM;
cache->framesize = -regs[THUMB_FP_REGNUM].k;
}
- else if (pv_is_register (regs[ARM_SP_REGNUM], ARM_SP_REGNUM))
+ else
{
/* Try the stack pointer... this is a bit desperate. */
cache->framereg = ARM_SP_REGNUM;
cache->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;
- }
for (i = 0; i < 16; i++)
if (pv_area_find_reg (stack, gdbarch, i, &offset))
@@ -1190,7 +1204,9 @@ arm_analyze_load_stack_chk_guard(CORE_ADDR pc, struct gdbarch *gdbarch,
{
*destreg = bits (insn1, 8, 10);
*offset = 2;
- address = bits (insn1, 0, 7);
+ address = (pc & 0xfffffffc) + 4 + (bits (insn1, 0, 7) << 2);
+ address = read_memory_unsigned_integer (address, 4,
+ byte_order_for_code);
}
else if ((insn1 & 0xfbf0) == 0xf240) /* movw Rd, #const */
{
@@ -1219,9 +1235,12 @@ arm_analyze_load_stack_chk_guard(CORE_ADDR pc, struct gdbarch *gdbarch,
unsigned int insn
= read_memory_unsigned_integer (pc, 4, byte_order_for_code);
- if ((insn & 0x0e5f0000) == 0x041f0000) /* ldr Rd, #immed */
+ if ((insn & 0x0e5f0000) == 0x041f0000) /* ldr Rd, [PC, #immed] */
{
- address = bits (insn, 0, 11);
+ address = bits (insn, 0, 11) + pc + 8;
+ address = read_memory_unsigned_integer (address, 4,
+ byte_order_for_code);
+
*destreg = bits (insn, 12, 15);
*offset = 4;
}
@@ -1279,8 +1298,8 @@ static CORE_ADDR
arm_skip_stack_protector(CORE_ADDR pc, struct gdbarch *gdbarch)
{
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- unsigned int address, basereg;
- struct minimal_symbol *stack_chk_guard;
+ unsigned int basereg;
+ struct bound_minimal_symbol stack_chk_guard;
int offset;
int is_thumb = arm_pc_is_thumb (gdbarch, pc);
CORE_ADDR addr;
@@ -1292,11 +1311,12 @@ arm_skip_stack_protector(CORE_ADDR pc, struct gdbarch *gdbarch)
return pc;
stack_chk_guard = lookup_minimal_symbol_by_pc (addr);
- /* If name of symbol doesn't start with '__stack_chk_guard', this
- instruction sequence is not for stack protector. If symbol is
- removed, we conservatively think this sequence is for stack protector. */
- if (stack_chk_guard
- && strcmp (SYMBOL_LINKAGE_NAME(stack_chk_guard), "__stack_chk_guard"))
+ /* ADDR must correspond to a symbol whose name is __stack_chk_guard.
+ Otherwise, this sequence cannot be for stack protector. */
+ if (stack_chk_guard.minsym == NULL
+ || strncmp (MSYMBOL_LINKAGE_NAME (stack_chk_guard.minsym),
+ "__stack_chk_guard",
+ strlen ("__stack_chk_guard")) != 0)
return pc;
if (is_thumb)
@@ -1368,9 +1388,7 @@ arm_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
unsigned long inst;
- CORE_ADDR skip_pc;
CORE_ADDR func_addr, limit_pc;
- struct symtab_and_line sal;
/* 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
@@ -1379,7 +1397,7 @@ arm_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
CORE_ADDR post_prologue_pc
= skip_prologue_using_sal (gdbarch, func_addr);
- struct symtab *s = find_pc_symtab (func_addr);
+ struct compunit_symtab *cust = find_pc_compunit_symtab (func_addr);
if (post_prologue_pc)
post_prologue_pc
@@ -1393,9 +1411,12 @@ arm_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
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))
+ && (cust == NULL
+ || COMPUNIT_PRODUCER (cust) == NULL
+ || strncmp (COMPUNIT_PRODUCER (cust), "GNU ",
+ sizeof ("GNU ") - 1) == 0
+ || strncmp (COMPUNIT_PRODUCER (cust), "clang ",
+ sizeof ("clang ") - 1) == 0))
return post_prologue_pc;
if (post_prologue_pc != 0)
@@ -1440,65 +1461,8 @@ arm_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
/* Check if this is Thumb code. */
if (arm_pc_is_thumb (gdbarch, pc))
return thumb_analyze_prologue (gdbarch, pc, limit_pc, NULL);
-
- for (skip_pc = pc; skip_pc < limit_pc; skip_pc += 4)
- {
- inst = read_memory_unsigned_integer (skip_pc, 4, byte_order_for_code);
-
- /* "mov ip, sp" is no longer a required part of the prologue. */
- if (inst == 0xe1a0c00d) /* mov ip, sp */
- continue;
-
- if ((inst & 0xfffff000) == 0xe28dc000) /* add ip, sp #n */
- continue;
-
- if ((inst & 0xfffff000) == 0xe24dc000) /* sub ip, sp #n */
- continue;
-
- /* Some prologues begin with "str lr, [sp, #-4]!". */
- if (inst == 0xe52de004) /* str lr, [sp, #-4]! */
- continue;
-
- if ((inst & 0xfffffff0) == 0xe92d0000) /* stmfd sp!,{a1,a2,a3,a4} */
- continue;
-
- if ((inst & 0xfffff800) == 0xe92dd800) /* stmfd sp!,{fp,ip,lr,pc} */
- continue;
-
- /* Any insns after this point may float into the code, if it makes
- for better instruction scheduling, so we skip them only if we
- find them, but still consider the function to be frame-ful. */
-
- /* We may have either one sfmfd instruction here, or several stfe
- insns, depending on the version of floating point code we
- support. */
- if ((inst & 0xffbf0fff) == 0xec2d0200) /* sfmfd fn, , [sp]! */
- continue;
-
- if ((inst & 0xffff8fff) == 0xed6d0103) /* stfe fn, [sp, #-12]! */
- continue;
-
- if ((inst & 0xfffff000) == 0xe24cb000) /* sub fp, ip, #nn */
- continue;
-
- if ((inst & 0xfffff000) == 0xe24dd000) /* sub sp, sp, #nn */
- continue;
-
- if ((inst & 0xffffc000) == 0xe54b0000 /* strb r(0123),[r11,#-nn] */
- || (inst & 0xffffc0f0) == 0xe14b00b0 /* strh r(0123),[r11,#-nn] */
- || (inst & 0xffffc000) == 0xe50b0000) /* str r(0123),[r11,#-nn] */
- continue;
-
- if ((inst & 0xffffc000) == 0xe5cd0000 /* strb r(0123),[sp,#nn] */
- || (inst & 0xffffc0f0) == 0xe1cd00b0 /* strh r(0123),[sp,#nn] */
- || (inst & 0xffffc000) == 0xe58d0000) /* str r(0123),[sp,#nn] */
- continue;
-
- /* Un-recognized instruction; stop scanning. */
- break;
- }
-
- return skip_pc; /* End of prologue. */
+ else
+ return arm_analyze_prologue (gdbarch, pc, limit_pc, NULL);
}
/* *INDENT-OFF* */
@@ -1529,7 +1493,6 @@ thumb_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR prev_pc,
{
CORE_ADDR prologue_start;
CORE_ADDR prologue_end;
- CORE_ADDR current_pc;
if (find_pc_partial_function (block_addr, NULL, &prologue_start,
&prologue_end))
@@ -1643,6 +1606,30 @@ arm_instruction_changes_pc (uint32_t this_instr)
}
}
+/* Return 1 if the ARM instruction INSN restores SP in epilogue, 0
+ otherwise. */
+
+static int
+arm_instruction_restores_sp (unsigned int insn)
+{
+ if (bits (insn, 28, 31) != INST_NV)
+ {
+ if ((insn & 0x0df0f000) == 0x0080d000
+ /* ADD SP (register or immediate). */
+ || (insn & 0x0df0f000) == 0x0040d000
+ /* SUB SP (register or immediate). */
+ || (insn & 0x0ffffff0) == 0x01a0d000
+ /* MOV SP. */
+ || (insn & 0x0fff0000) == 0x08bd0000
+ /* POP (LDMIA). */
+ || (insn & 0x0fff0000) == 0x049d0000)
+ /* POP of a single register. */
+ return 1;
+ }
+
+ return 0;
+}
+
/* 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
@@ -1665,7 +1652,6 @@ arm_analyze_prologue (struct gdbarch *gdbarch,
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
@@ -1841,62 +1827,62 @@ arm_analyze_prologue (struct gdbarch *gdbarch,
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)
+ else if (arm_instruction_restores_sp (insn))
{
- /* Similarly ignore single loads from the stack. */
- if (pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
- continue;
- else
- break;
+ /* Don't scan past the epilogue. */
+ break;
}
+ else if ((insn & 0xfe500000) == 0xe8100000 /* ldm */
+ && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
+ /* Ignore block loads from the stack, potentially copying
+ parameters from memory. */
+ continue;
+ else if ((insn & 0xfc500000) == 0xe4100000
+ && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
+ /* Similarly ignore single loads from the stack. */
+ continue;
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. */
+ /* The optimizer might shove anything into the prologue, if
+ we build up cache (cache != NULL) from scanning prologue,
+ we just skip what we don't recognize and scan further to
+ make cache as complete as possible. However, if we skip
+ prologue, we'll stop immediately on unrecognized
+ instruction. */
unrecognized_pc = current_pc;
- continue;
+ if (cache != NULL)
+ continue;
+ else
+ break;
}
}
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. */
- 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. */
- 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. */
- framereg = -1;
- framesize = 0;
- }
-
if (cache)
{
+ int framereg, framesize;
+
+ /* 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. */
+ framereg = ARM_FP_REGNUM;
+ framesize = -regs[ARM_FP_REGNUM].k;
+ }
+ else
+ {
+ /* Try the stack pointer... this is a bit desperate. */
+ framereg = ARM_SP_REGNUM;
+ framesize = -regs[ARM_SP_REGNUM].k;
+ }
+
cache->framereg = framereg;
cache->framesize = framesize;
@@ -2131,6 +2117,7 @@ arm_prologue_prev_register (struct frame_info *this_frame,
struct frame_unwind arm_prologue_unwind = {
NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
arm_prologue_this_id,
arm_prologue_prev_register,
NULL,
@@ -2211,7 +2198,7 @@ arm_obj_section_from_vma (struct objfile *objfile, bfd_vma vma)
static void
arm_exidx_new_objfile (struct objfile *objfile)
{
- struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+ struct cleanup *cleanups;
struct arm_exidx_data *data;
asection *exidx, *extab;
bfd_vma exidx_vma = 0, extab_vma = 0;
@@ -2222,6 +2209,7 @@ arm_exidx_new_objfile (struct objfile *objfile)
/* If we've already touched this file, do nothing. */
if (!objfile || objfile_data (objfile, arm_exidx_data_key) != NULL)
return;
+ cleanups = make_cleanup (null_cleanup, NULL);
/* Read contents of exception table and index. */
exidx = bfd_get_section_by_name (objfile->obfd, ".ARM.exidx");
@@ -2869,12 +2857,71 @@ arm_exidx_unwind_sniffer (const struct frame_unwind *self,
struct frame_unwind arm_exidx_unwind = {
NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
arm_prologue_this_id,
arm_prologue_prev_register,
NULL,
arm_exidx_unwind_sniffer
};
+/* Recognize GCC's trampoline for thumb call-indirect. If we are in a
+ trampoline, return the target PC. Otherwise return 0.
+
+ void call0a (char c, short s, int i, long l) {}
+
+ int main (void)
+ {
+ (*pointer_to_call0a) (c, s, i, l);
+ }
+
+ Instead of calling a stub library function _call_via_xx (xx is
+ the register name), GCC may inline the trampoline in the object
+ file as below (register r2 has the address of call0a).
+
+ .global main
+ .type main, %function
+ ...
+ bl .L1
+ ...
+ .size main, .-main
+
+ .L1:
+ bx r2
+
+ The trampoline 'bx r2' doesn't belong to main. */
+
+static CORE_ADDR
+arm_skip_bx_reg (struct frame_info *frame, CORE_ADDR pc)
+{
+ /* The heuristics of recognizing such trampoline is that FRAME is
+ executing in Thumb mode and the instruction on PC is 'bx Rm'. */
+ if (arm_frame_is_thumb (frame))
+ {
+ gdb_byte buf[2];
+
+ if (target_read_memory (pc, buf, 2) == 0)
+ {
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ enum bfd_endian byte_order_for_code
+ = gdbarch_byte_order_for_code (gdbarch);
+ uint16_t insn
+ = extract_unsigned_integer (buf, 2, byte_order_for_code);
+
+ if ((insn & 0xff80) == 0x4700) /* bx */
+ {
+ CORE_ADDR dest
+ = get_frame_register_unsigned (frame, bits (insn, 3, 6));
+
+ /* Clear the LSB so that gdb core sets step-resume
+ breakpoint at the right address. */
+ return UNMAKE_THUMB_ADDR (dest);
+ }
+ }
+ }
+
+ return 0;
+}
+
static struct arm_prologue_cache *
arm_make_stub_cache (struct frame_info *this_frame)
{
@@ -2910,13 +2957,20 @@ arm_stub_unwind_sniffer (const struct frame_unwind *self,
void **this_prologue_cache)
{
CORE_ADDR addr_in_block;
- char dummy[4];
+ gdb_byte dummy[4];
+ CORE_ADDR pc, start_addr;
+ const char *name;
addr_in_block = get_frame_address_in_block (this_frame);
- if (in_plt_section (addr_in_block, NULL)
+ pc = get_frame_pc (this_frame);
+ if (in_plt_section (addr_in_block)
/* We also use the stub winder if the target memory is unreadable
to avoid having the prologue unwinder trying to read it. */
- || target_read_memory (get_frame_pc (this_frame), dummy, 4) != 0)
+ || target_read_memory (pc, dummy, 4) != 0)
+ return 1;
+
+ if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0
+ && arm_skip_bx_reg (this_frame, pc) != 0)
return 1;
return 0;
@@ -2924,12 +2978,134 @@ arm_stub_unwind_sniffer (const struct frame_unwind *self,
struct frame_unwind arm_stub_unwind = {
NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
arm_stub_this_id,
arm_prologue_prev_register,
NULL,
arm_stub_unwind_sniffer
};
+/* Put here the code to store, into CACHE->saved_regs, the addresses
+ of the saved registers of frame described by THIS_FRAME. CACHE is
+ returned. */
+
+static struct arm_prologue_cache *
+arm_m_exception_cache (struct frame_info *this_frame)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct arm_prologue_cache *cache;
+ CORE_ADDR unwound_sp;
+ LONGEST xpsr;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+ unwound_sp = get_frame_register_unsigned (this_frame,
+ ARM_SP_REGNUM);
+
+ /* The hardware saves eight 32-bit words, comprising xPSR,
+ ReturnAddress, LR (R14), R12, R3, R2, R1, R0. See details in
+ "B1.5.6 Exception entry behavior" in
+ "ARMv7-M Architecture Reference Manual". */
+ cache->saved_regs[0].addr = unwound_sp;
+ cache->saved_regs[1].addr = unwound_sp + 4;
+ cache->saved_regs[2].addr = unwound_sp + 8;
+ cache->saved_regs[3].addr = unwound_sp + 12;
+ cache->saved_regs[12].addr = unwound_sp + 16;
+ cache->saved_regs[14].addr = unwound_sp + 20;
+ cache->saved_regs[15].addr = unwound_sp + 24;
+ cache->saved_regs[ARM_PS_REGNUM].addr = unwound_sp + 28;
+
+ /* If bit 9 of the saved xPSR is set, then there is a four-byte
+ aligner between the top of the 32-byte stack frame and the
+ previous context's stack pointer. */
+ cache->prev_sp = unwound_sp + 32;
+ if (safe_read_memory_integer (unwound_sp + 28, 4, byte_order, &xpsr)
+ && (xpsr & (1 << 9)) != 0)
+ cache->prev_sp += 4;
+
+ return cache;
+}
+
+/* Implementation of function hook 'this_id' in
+ 'struct frame_uwnind'. */
+
+static void
+arm_m_exception_this_id (struct frame_info *this_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct arm_prologue_cache *cache;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_m_exception_cache (this_frame);
+ cache = *this_cache;
+
+ /* Our frame ID for a stub frame is the current SP and LR. */
+ *this_id = frame_id_build (cache->prev_sp,
+ get_frame_pc (this_frame));
+}
+
+/* Implementation of function hook 'prev_register' in
+ 'struct frame_uwnind'. */
+
+static struct value *
+arm_m_exception_prev_register (struct frame_info *this_frame,
+ void **this_cache,
+ int prev_regnum)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct arm_prologue_cache *cache;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_m_exception_cache (this_frame);
+ cache = *this_cache;
+
+ /* The value was already reconstructed into PREV_SP. */
+ if (prev_regnum == ARM_SP_REGNUM)
+ return frame_unwind_got_constant (this_frame, prev_regnum,
+ cache->prev_sp);
+
+ return trad_frame_get_prev_register (this_frame, cache->saved_regs,
+ prev_regnum);
+}
+
+/* Implementation of function hook 'sniffer' in
+ 'struct frame_uwnind'. */
+
+static int
+arm_m_exception_unwind_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_prologue_cache)
+{
+ CORE_ADDR this_pc = get_frame_pc (this_frame);
+
+ /* No need to check is_m; this sniffer is only registered for
+ M-profile architectures. */
+
+ /* Exception frames return to one of these magic PCs. Other values
+ are not defined as of v7-M. See details in "B1.5.8 Exception
+ return behavior" in "ARMv7-M Architecture Reference Manual". */
+ if (this_pc == 0xfffffff1 || this_pc == 0xfffffff9
+ || this_pc == 0xfffffffd)
+ return 1;
+
+ return 0;
+}
+
+/* Frame unwinder for M-profile exceptions. */
+
+struct frame_unwind arm_m_exception_unwind =
+{
+ SIGTRAMP_FRAME,
+ default_frame_unwind_stop_reason,
+ arm_m_exception_this_id,
+ arm_m_exception_prev_register,
+ NULL,
+ arm_m_exception_unwind_sniffer
+};
+
static CORE_ADDR
arm_normal_frame_base (struct frame_info *this_frame, void **this_cache)
{
@@ -3080,17 +3256,12 @@ thumb_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
found_return = 1;
else if (insn == 0x46f7) /* mov pc, lr */
found_return = 1;
- else if (insn == 0x46bd) /* mov sp, r7 */
- found_stack_adjust = 1;
- else if ((insn & 0xff00) == 0xb000) /* add sp, imm or sub sp, imm */
- found_stack_adjust = 1;
- else if ((insn & 0xfe00) == 0xbc00) /* pop */
- {
- found_stack_adjust = 1;
- if (insn & 0x0100) /* include PC. */
+ else if (thumb_instruction_restores_sp (insn))
+ {
+ if ((insn & 0xff00) == 0xbd00) /* pop */
found_return = 1;
}
- else if ((insn & 0xe000) == 0xe000) /* 32-bit Thumb-2 instruction */
+ else if (thumb_insn_size (insn) == 4) /* 32-bit Thumb-2 instruction */
{
if (target_read_memory (scan_pc, buf, 2))
break;
@@ -3100,20 +3271,18 @@ thumb_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
if (insn == 0xe8bd) /* ldm.w sp!, */
{
- found_stack_adjust = 1;
if (insn2 & 0x8000) /* include PC. */
found_return = 1;
}
else if (insn == 0xf85d /* ldr.w