/* 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
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
This file is part of GDB.
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. */
return lhs->value < rhs->value;
}
-/* 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. */
+/* Search for the mapping symbol covering MEMADDR. If one is found,
+ return its type. Otherwise, return 0. If START is non-NULL,
+ set *START to the location of the mapping symbol. */
-static int
-arm_pc_is_thumb (CORE_ADDR memaddr)
+static char
+arm_find_mapping_symbol (CORE_ADDR memaddr, CORE_ADDR *start)
{
struct obj_section *sec;
- struct minimal_symbol *sym;
-
- /* If bit 0 of the address is set, assume this is a Thumb address. */
- if (IS_THUMB_ADDR (memaddr))
- return 1;
-
- /* If the user wants to override the symbol table, let him. */
- if (strcmp (arm_force_mode_string, "arm") == 0)
- return 0;
- if (strcmp (arm_force_mode_string, "thumb") == 0)
- return 1;
/* If there are mapping symbols, consult them. */
sec = find_pc_section (memaddr);
{
map_sym = VEC_index (arm_mapping_symbol_s, map, idx);
if (map_sym->value == map_key.value)
- return map_sym->type == 't';
+ {
+ if (start)
+ *start = map_sym->value + obj_section_addr (sec);
+ return map_sym->type;
+ }
}
if (idx > 0)
{
map_sym = VEC_index (arm_mapping_symbol_s, map, idx - 1);
- return map_sym->type == 't';
+ if (start)
+ *start = map_sym->value + obj_section_addr (sec);
+ return map_sym->type;
}
}
}
}
+ 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
+arm_pc_is_thumb (CORE_ADDR memaddr)
+{
+ struct obj_section *sec;
+ struct minimal_symbol *sym;
+ char type;
+
+ /* If bit 0 of the address is set, assume this is a Thumb address. */
+ if (IS_THUMB_ADDR (memaddr))
+ return 1;
+
+ /* If the user wants to override the symbol table, let him. */
+ if (strcmp (arm_force_mode_string, "arm") == 0)
+ return 0;
+ if (strcmp (arm_force_mode_string, "thumb") == 0)
+ return 1;
+
+ /* If there are mapping symbols, consult them. */
+ type = arm_find_mapping_symbol (memaddr, NULL);
+ if (type)
+ return type == 't';
+
/* Thumb functions have a "special" bit set in minimal symbols. */
sym = lookup_minimal_symbol_by_pc (memaddr);
if (sym)
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). */
+ 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. */
if (target_has_registers)
- return arm_frame_is_thumb (get_current_frame ());
+ {
+ 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;
+ }
+ }
/* Otherwise we're out of luck; we assume ARM. */
return 0;
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];
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);
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
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);
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. */
{
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
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;
- 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.
+ /* Stores. */
+ if (bit (this_instr, 20) == 0)
+ 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;
+ /* Loads. */
+ if (bits (this_instr, 12, 15) == ARM_PC_REGNUM)
+ 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 0x4:
+ /* Load/store multiple. */
+ if (bit (this_instr, 20) == 1 && bit (this_instr, 15) == 1)
+ return 1;
+ else
+ return 0;
- if (prev_pc < prologue_end)
- prologue_end = prev_pc;
+ case 0x5:
+ /* Branch and branch with link. */
+ return 1;
+
+ case 0x6:
+ case 0x7:
+ /* Coprocessor transfers or SWIs can not affect PC. */
+ return 0;
+
+ 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.
- /* Now search the prologue looking for instructions that set up the
+ 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,
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);
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)
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 */
n_saved_fp_regs = 4;
}
- fp_start_reg = ARM_F0_REGNUM + ((insn >> 12) & 0x7);
- fp_bound_reg = fp_start_reg + n_saved_fp_regs;
- for (; fp_start_reg < fp_bound_reg; fp_start_reg++)
- {
- 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++]);
- }
+ fp_start_reg = ARM_F0_REGNUM + ((insn >> 12) & 0x7);
+ fp_bound_reg = fp_start_reg + n_saved_fp_regs;
+ for (; fp_start_reg < fp_bound_reg; fp_start_reg++)
+ {
+ 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 & 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 (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. */
+ 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)
+ {
+ 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 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. */
- continue;
- }
-
- /* 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
{
- /* We're just out of luck. We don't know where the frame is. */
- cache->framereg = -1;
- cache->framesize = 0;
+ /* 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. */
+ }
}
- for (regno = 0; regno < ARM_FPS_REGNUM; regno++)
- if (pv_area_find_reg (stack, gdbarch, regno, &offset))
- cache->saved_regs[regno].addr = offset;
+ if (prev_pc < prologue_end)
+ prologue_end = prev_pc;
- do_cleanups (back_to);
+ arm_analyze_prologue (gdbarch, prologue_start, prologue_end, cache);
}
static struct arm_prologue_cache *
static struct arm_prologue_cache *
arm_make_stub_cache (struct frame_info *this_frame)
{
- int reg;
struct arm_prologue_cache *cache;
- CORE_ADDR unwound_fp;
cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
addr_in_block = get_frame_address_in_block (this_frame);
if (in_plt_section (addr_in_block, NULL)
+ /* 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)
return 1;
/* Set the return address. For the ARM, the return breakpoint is
always at BP_ADDR. */
- /* XXX Fix for Thumb. */
+ if (arm_pc_is_thumb (bp_addr))
+ bp_addr |= 1;
regcache_cooked_write_unsigned (regcache, ARM_LR_REGNUM, bp_addr);
/* Walk through the list of args and determine how large a temporary
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)
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)
return nbits;
}
+/* Return the size in bytes of the complete Thumb instruction whose
+ first halfword is INST1. */
+
+static int
+thumb_insn_size (unsigned short inst1)
+{
+ if ((inst1 & 0xe000) == 0xe000 && (inst1 & 0x1800) != 0)
+ return 4;
+ else
+ return 2;
+}
+
+static int
+thumb_advance_itstate (unsigned int itstate)
+{
+ /* Preserve IT[7:5], the first three bits of the condition. Shift
+ the upcoming condition flags left by one bit. */
+ itstate = (itstate & 0xe0) | ((itstate << 1) & 0x1f);
+
+ /* If we have finished the IT block, clear the state. */
+ if ((itstate & 0x0f) == 0)
+ itstate = 0;
+
+ return itstate;
+}
+
+/* Find the next PC after the current instruction executes. In some
+ cases we can not statically determine the answer (see the IT state
+ handling in this function); in that case, a breakpoint may be
+ inserted in addition to the returned PC, which will be used to set
+ another breakpoint by our caller. */
+
static CORE_ADDR
-thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
+thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct address_space *aspace = get_frame_address_space (frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
unsigned long pc_val = ((unsigned long) pc) + 4; /* PC after prefetch */
unsigned short inst1;
CORE_ADDR nextpc = pc + 2; /* default is next instruction */
unsigned long offset;
+ ULONGEST status, itstate;
+
+ nextpc = MAKE_THUMB_ADDR (nextpc);
+ pc_val = MAKE_THUMB_ADDR (pc_val);
inst1 = read_memory_unsigned_integer (pc, 2, byte_order_for_code);
+ /* Thumb-2 conditional execution support. There are eight bits in
+ the CPSR which describe conditional execution state. Once
+ reconstructed (they're in a funny order), the low five bits
+ describe the low bit of the condition for each instruction and
+ how many instructions remain. The high three bits describe the
+ base condition. One of the low four bits will be set if an IT
+ block is active. These bits read as zero on earlier
+ processors. */
+ status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
+ itstate = ((status >> 8) & 0xfc) | ((status >> 25) & 0x3);
+
+ /* If-Then handling. On GNU/Linux, where this routine is used, we
+ use an undefined instruction as a breakpoint. Unlike BKPT, IT
+ can disable execution of the undefined instruction. So we might
+ miss the breakpoint if we set it on a skipped conditional
+ instruction. Because conditional instructions can change the
+ flags, affecting the execution of further instructions, we may
+ need to set two breakpoints. */
+
+ if (gdbarch_tdep (gdbarch)->thumb2_breakpoint != NULL)
+ {
+ if ((inst1 & 0xff00) == 0xbf00 && (inst1 & 0x000f) != 0)
+ {
+ /* An IT instruction. Because this instruction does not
+ modify the flags, we can accurately predict the next
+ executed instruction. */
+ itstate = inst1 & 0x00ff;
+ pc += thumb_insn_size (inst1);
+
+ while (itstate != 0 && ! condition_true (itstate >> 4, status))
+ {
+ inst1 = read_memory_unsigned_integer (pc, 2, byte_order_for_code);
+ pc += thumb_insn_size (inst1);
+ itstate = thumb_advance_itstate (itstate);
+ }
+
+ return MAKE_THUMB_ADDR (pc);
+ }
+ else if (itstate != 0)
+ {
+ /* We are in a conditional block. Check the condition. */
+ if (! condition_true (itstate >> 4, status))
+ {
+ /* Advance to the next executed instruction. */
+ pc += thumb_insn_size (inst1);
+ itstate = thumb_advance_itstate (itstate);
+
+ while (itstate != 0 && ! condition_true (itstate >> 4, status))
+ {
+ inst1 = read_memory_unsigned_integer (pc, 2, byte_order_for_code);
+ pc += thumb_insn_size (inst1);
+ itstate = thumb_advance_itstate (itstate);
+ }
+
+ return MAKE_THUMB_ADDR (pc);
+ }
+ else if ((itstate & 0x0f) == 0x08)
+ {
+ /* This is the last instruction of the conditional
+ block, and it is executed. We can handle it normally
+ because the following instruction is not conditional,
+ and we must handle it normally because it is
+ permitted to branch. Fall through. */
+ }
+ else
+ {
+ int cond_negated;
+
+ /* There are conditional instructions after this one.
+ If this instruction modifies the flags, then we can
+ not predict what the next executed instruction will
+ be. Fortunately, this instruction is architecturally
+ forbidden to branch; we know it will fall through.
+ Start by skipping past it. */
+ pc += thumb_insn_size (inst1);
+ itstate = thumb_advance_itstate (itstate);
+
+ /* Set a breakpoint on the following instruction. */
+ gdb_assert ((itstate & 0x0f) != 0);
+ if (insert_bkpt)
+ insert_single_step_breakpoint (gdbarch, aspace, pc);
+ cond_negated = (itstate >> 4) & 1;
+
+ /* Skip all following instructions with the same
+ condition. If there is a later instruction in the IT
+ block with the opposite condition, set the other
+ breakpoint there. If not, then set a breakpoint on
+ the instruction after the IT block. */
+ do
+ {
+ inst1 = read_memory_unsigned_integer (pc, 2, byte_order_for_code);
+ pc += thumb_insn_size (inst1);
+ itstate = thumb_advance_itstate (itstate);
+ }
+ while (itstate != 0 && ((itstate >> 4) & 1) == cond_negated);
+
+ return MAKE_THUMB_ADDR (pc);
+ }
+ }
+ }
+ else if (itstate & 0x0f)
+ {
+ /* We are in a conditional block. Check the condition. */
+ int cond = itstate >> 4;
+
+ if (! condition_true (cond, status))
+ {
+ /* Advance to the next instruction. All the 32-bit
+ instructions share a common prefix. */
+ if ((inst1 & 0xe000) == 0xe000 && (inst1 & 0x1800) != 0)
+ return MAKE_THUMB_ADDR (pc + 4);
+ else
+ return MAKE_THUMB_ADDR (pc + 2);
+ }
+
+ /* Otherwise, handle the instruction normally. */
+ }
+
if ((inst1 & 0xff00) == 0xbd00) /* pop {rlist, pc} */
{
CORE_ADDR sp;
offset = bitcount (bits (inst1, 0, 7)) * INT_REGISTER_SIZE;
sp = get_frame_register_unsigned (frame, ARM_SP_REGNUM);
nextpc = read_memory_unsigned_integer (sp + offset, 4, byte_order);
- nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
- if (nextpc == pc)
- error (_("Infinite loop detected"));
}
else if ((inst1 & 0xf000) == 0xd000) /* conditional branch */
{
- unsigned long status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
unsigned long cond = bits (inst1, 8, 11);
if (cond != 0x0f && condition_true (cond, status)) /* 0x0f = SWI */
nextpc = pc_val + (sbits (inst1, 0, 7) << 1);
{
nextpc = pc_val + (sbits (inst1, 0, 10) << 1);
}
- else if ((inst1 & 0xf800) == 0xf000) /* long branch with link, and blx */
+ else if ((inst1 & 0xe000) == 0xe000) /* 32-bit instruction */
{
unsigned short inst2;
inst2 = read_memory_unsigned_integer (pc + 2, 2, byte_order_for_code);
- offset = (sbits (inst1, 0, 10) << 12) + (bits (inst2, 0, 10) << 1);
- nextpc = pc_val + offset;
- /* For BLX make sure to clear the low bits. */
- if (bits (inst2, 11, 12) == 1)
- nextpc = nextpc & 0xfffffffc;
+
+ /* Default to the next instruction. */
+ nextpc = pc + 4;
+ nextpc = MAKE_THUMB_ADDR (nextpc);
+
+ if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000)
+ {
+ /* Branches and miscellaneous control instructions. */
+
+ if ((inst2 & 0x1000) != 0 || (inst2 & 0xd001) == 0xc000)
+ {
+ /* B, BL, BLX. */
+ int j1, j2, imm1, imm2;
+
+ imm1 = sbits (inst1, 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 = pc_val + offset;
+ /* For BLX make sure to clear the low bits. */
+ if (bit (inst2, 12) == 0)
+ nextpc = nextpc & 0xfffffffc;
+ }
+ else if (inst1 == 0xf3de && (inst2 & 0xff00) == 0x3f00)
+ {
+ /* SUBS PC, LR, #imm8. */
+ nextpc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
+ nextpc -= inst2 & 0x00ff;
+ }
+ else if ((inst2 & 0xd000) == 0x8000 && (inst1 & 0x0380) != 0x0380)
+ {
+ /* Conditional branch. */
+ if (condition_true (bits (inst1, 6, 9), status))
+ {
+ int sign, j1, j2, imm1, imm2;
+
+ sign = sbits (inst1, 10, 10);
+ imm1 = bits (inst1, 0, 5);
+ imm2 = bits (inst2, 0, 10);
+ j1 = bit (inst2, 13);
+ j2 = bit (inst2, 11);
+
+ offset = (sign << 20) + (j2 << 19) + (j1 << 18);
+ offset += (imm1 << 12) + (imm2 << 1);
+
+ nextpc = pc_val + offset;
+ }
+ }
+ }
+ else if ((inst1 & 0xfe50) == 0xe810)
+ {
+ /* Load multiple or RFE. */
+ int rn, offset, load_pc = 1;
+
+ rn = bits (inst1, 0, 3);
+ if (bit (inst1, 7) && !bit (inst1, 8))
+ {
+ /* LDMIA or POP */
+ if (!bit (inst2, 15))
+ load_pc = 0;
+ offset = bitcount (inst2) * 4 - 4;
+ }
+ else if (!bit (inst1, 7) && bit (inst1, 8))
+ {
+ /* LDMDB */
+ if (!bit (inst2, 15))
+ load_pc = 0;
+ offset = -4;
+ }
+ else if (bit (inst1, 7) && bit (inst1, 8))
+ {
+ /* RFEIA */
+ offset = 0;
+ }
+ else if (!bit (inst1, 7) && !bit (inst1, 8))
+ {
+ /* RFEDB */
+ offset = -8;
+ }
+ else
+ load_pc = 0;
+
+ if (load_pc)
+ {
+ CORE_ADDR addr = get_frame_register_unsigned (frame, rn);
+ nextpc = get_frame_memory_unsigned (frame, addr + offset, 4);
+ }
+ }
+ else if ((inst1 & 0xffef) == 0xea4f && (inst2 & 0xfff0) == 0x0f00)
+ {
+ /* MOV PC or MOVS PC. */
+ nextpc = get_frame_register_unsigned (frame, bits (inst2, 0, 3));
+ nextpc = MAKE_THUMB_ADDR (nextpc);
+ }
+ else if ((inst1 & 0xff70) == 0xf850 && (inst2 & 0xf000) == 0xf000)
+ {
+ /* LDR PC. */
+ CORE_ADDR base;
+ int rn, load_pc = 1;
+
+ rn = bits (inst1, 0, 3);
+ base = get_frame_register_unsigned (frame, rn);
+ if (rn == 15)
+ {
+ base = (base + 4) & ~(CORE_ADDR) 0x3;
+ if (bit (inst1, 7))
+ base += bits (inst2, 0, 11);
+ else
+ base -= bits (inst2, 0, 11);
+ }
+ else if (bit (inst1, 7))
+ base += bits (inst2, 0, 11);
+ else if (bit (inst2, 11))
+ {
+ if (bit (inst2, 10))
+ {
+ if (bit (inst2, 9))
+ base += bits (inst2, 0, 7);
+ else
+ base -= bits (inst2, 0, 7);
+ }
+ }
+ else if ((inst2 & 0x0fc0) == 0x0000)
+ {
+ int shift = bits (inst2, 4, 5), rm = bits (inst2, 0, 3);
+ base += get_frame_register_unsigned (frame, rm) << shift;
+ }
+ else
+ /* Reserved. */
+ load_pc = 0;
+
+ if (load_pc)
+ nextpc = get_frame_memory_unsigned (frame, base, 4);
+ }
+ else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000)
+ {
+ /* TBB. */
+ CORE_ADDR tbl_reg, table, offset, length;
+
+ tbl_reg = bits (inst1, 0, 3);
+ if (tbl_reg == 0x0f)
+ table = pc + 4; /* Regcache copy of PC isn't right yet. */
+ else
+ table = get_frame_register_unsigned (frame, tbl_reg);
+
+ offset = get_frame_register_unsigned (frame, bits (inst2, 0, 3));
+ length = 2 * get_frame_memory_unsigned (frame, table + offset, 1);
+ nextpc = pc_val + length;
+ }
+ else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf010)
+ {
+ /* TBH. */
+ CORE_ADDR tbl_reg, table, offset, length;
+
+ tbl_reg = bits (inst1, 0, 3);
+ if (tbl_reg == 0x0f)
+ table = pc + 4; /* Regcache copy of PC isn't right yet. */
+ else
+ table = get_frame_register_unsigned (frame, tbl_reg);
+
+ offset = 2 * get_frame_register_unsigned (frame, bits (inst2, 0, 3));
+ length = 2 * get_frame_memory_unsigned (frame, table + offset, 2);
+ nextpc = pc_val + length;
+ }
}
else if ((inst1 & 0xff00) == 0x4700) /* bx REG, blx REG */
{
nextpc = pc_val;
else
nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6));
-
- nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
- if (nextpc == pc)
- error (_("Infinite loop detected"));
}
-
+ else if ((inst1 & 0xf500) == 0xb100)
+ {
+ /* CBNZ or CBZ. */
+ int imm = (bit (inst1, 9) << 6) + (bits (inst1, 3, 7) << 1);
+ ULONGEST reg = get_frame_register_unsigned (frame, bits (inst1, 0, 2));
+
+ if (bit (inst1, 11) && reg != 0)
+ nextpc = pc_val + imm;
+ else if (!bit (inst1, 11) && reg == 0)
+ nextpc = pc_val + imm;
+ }
return nextpc;
}
-CORE_ADDR
-arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
+/* Get the raw next address. PC is the current program counter, in
+ FRAME. INSERT_BKPT should be TRUE if we want a breakpoint set on
+ the alternative next instruction if there are two options.
+
+ The value returned has the execution state of the next instruction
+ encoded in it. Use IS_THUMB_ADDR () to see whether the instruction is
+ in Thumb-State, and gdbarch_addr_bits_remove () to get the plain memory
+ address.
+*/
+static CORE_ADDR
+arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
CORE_ADDR nextpc;
if (arm_frame_is_thumb (frame))
- return thumb_get_next_pc (frame, pc);
+ return thumb_get_next_pc_raw (frame, pc, insert_bkpt);
pc_val = (unsigned long) pc;
this_instr = read_memory_unsigned_integer (pc, 4, byte_order_for_code);
/* 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"));
+ nextpc = MAKE_THUMB_ADDR (nextpc);
break;
}
case 0xc:
|| bits (this_instr, 4, 27) == 0x12fff3)
{
rn = bits (this_instr, 0, 3);
- result = (rn == 15) ? pc_val + 8
+ nextpc = (rn == 15) ? pc_val + 8
: get_frame_register_unsigned (frame, rn);
- nextpc = (CORE_ADDR) gdbarch_addr_bits_remove
- (gdbarch, result);
-
- if (nextpc == pc)
- error (_("Infinite loop detected"));
-
return nextpc;
}
result = ~operand2;
break;
}
- nextpc = (CORE_ADDR) gdbarch_addr_bits_remove
- (gdbarch, result);
- if (nextpc == pc)
- error (_("Infinite loop detected"));
+ /* In 26-bit APCS the bottom two bits of the result are
+ ignored, and we always end up in ARM state. */
+ if (!arm_apcs_32)
+ nextpc = arm_addr_bits_remove (gdbarch, result);
+ else
+ nextpc = result;
+
break;
}
}
nextpc = (CORE_ADDR) read_memory_integer ((CORE_ADDR) base,
4, byte_order);
-
- nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
-
- if (nextpc == pc)
- error (_("Infinite loop detected"));
}
}
break;
+ offset),
4, byte_order);
}
- nextpc = gdbarch_addr_bits_remove
- (gdbarch, nextpc);
- if (nextpc == pc)
- error (_("Infinite loop detected"));
}
}
break;
case 0xa: /* branch */
{
nextpc = BranchDest (pc, this_instr);
-
- nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
- if (nextpc == pc)
- error (_("Infinite loop detected"));
break;
}
return nextpc;
}
+CORE_ADDR
+arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ CORE_ADDR nextpc =
+ gdbarch_addr_bits_remove (gdbarch,
+ arm_get_next_pc_raw (frame, pc, TRUE));
+ if (nextpc == pc)
+ error (_("Infinite loop detected"));
+ return nextpc;
+}
+
/* single_step() is called just before we want to resume the inferior,
if we want to single-step it but there is no hardware or kernel
single-step support. We find the target of the coming instruction
arm_software_single_step (struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct address_space *aspace = get_frame_address_space (frame);
/* NOTE: This may insert the wrong breakpoint instruction when
single-stepping over a mode-changing instruction, if the
CPSR heuristics are used. */
CORE_ADDR next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
- insert_single_step_breakpoint (gdbarch, next_pc);
+ insert_single_step_breakpoint (gdbarch, aspace, next_pc);
return 1;
}
+/* Given BUF, which is OLD_LEN bytes ending at ENDADDR, expand
+ the buffer to be NEW_LEN bytes ending at ENDADDR. Return
+ NULL if an error occurs. BUF is freed. */
+
+static gdb_byte *
+extend_buffer_earlier (gdb_byte *buf, CORE_ADDR endaddr,
+ int old_len, int new_len)
+{
+ gdb_byte *new_buf, *middle;
+ int bytes_to_read = new_len - old_len;
+
+ new_buf = xmalloc (new_len);
+ memcpy (new_buf + bytes_to_read, buf, old_len);
+ xfree (buf);
+ if (target_read_memory (endaddr - new_len, new_buf, bytes_to_read) != 0)
+ {
+ xfree (new_buf);
+ return NULL;
+ }
+ return new_buf;
+}
+
+/* An IT block is at most the 2-byte IT instruction followed by
+ four 4-byte instructions. The furthest back we must search to
+ find an IT block that affects the current instruction is thus
+ 2 + 3 * 4 == 14 bytes. */
+#define MAX_IT_BLOCK_PREFIX 14
+
+/* Use a quick scan if there are more than this many bytes of
+ code. */
+#define IT_SCAN_THRESHOLD 32
+
+/* Adjust a breakpoint's address to move breakpoints out of IT blocks.
+ A breakpoint in an IT block may not be hit, depending on the
+ condition flags. */
+static CORE_ADDR
+arm_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
+{
+ gdb_byte *buf;
+ char map_type;
+ CORE_ADDR boundary, func_start;
+ int buf_len, buf2_len;
+ enum bfd_endian order = gdbarch_byte_order_for_code (gdbarch);
+ int i, any, last_it, last_it_count;
+
+ /* If we are using BKPT breakpoints, none of this is necessary. */
+ if (gdbarch_tdep (gdbarch)->thumb2_breakpoint == NULL)
+ return bpaddr;
+
+ /* ARM mode does not have this problem. */
+ if (!arm_pc_is_thumb (bpaddr))
+ return bpaddr;
+
+ /* We are setting a breakpoint in Thumb code that could potentially
+ contain an IT block. The first step is to find how much Thumb
+ code there is; we do not need to read outside of known Thumb
+ sequences. */
+ map_type = arm_find_mapping_symbol (bpaddr, &boundary);
+ if (map_type == 0)
+ /* Thumb-2 code must have mapping symbols to have a chance. */
+ return bpaddr;
+
+ bpaddr = gdbarch_addr_bits_remove (gdbarch, bpaddr);
+
+ if (find_pc_partial_function (bpaddr, NULL, &func_start, NULL)
+ && func_start > boundary)
+ boundary = func_start;
+
+ /* Search for a candidate IT instruction. We have to do some fancy
+ footwork to distinguish a real IT instruction from the second
+ half of a 32-bit instruction, but there is no need for that if
+ there's no candidate. */
+ buf_len = min (bpaddr - boundary, MAX_IT_BLOCK_PREFIX);
+ if (buf_len == 0)
+ /* No room for an IT instruction. */
+ return bpaddr;
+
+ buf = xmalloc (buf_len);
+ if (target_read_memory (bpaddr - buf_len, buf, buf_len) != 0)
+ return bpaddr;
+ any = 0;
+ for (i = 0; i < buf_len; i += 2)
+ {
+ unsigned short inst1 = extract_unsigned_integer (&buf[i], 2, order);
+ if ((inst1 & 0xff00) == 0xbf00 && (inst1 & 0x000f) != 0)
+ {
+ any = 1;
+ break;
+ }
+ }
+ if (any == 0)
+ {
+ xfree (buf);
+ return bpaddr;
+ }
+
+ /* OK, the code bytes before this instruction contain at least one
+ halfword which resembles an IT instruction. We know that it's
+ Thumb code, but there are still two possibilities. Either the
+ halfword really is an IT instruction, or it is the second half of
+ a 32-bit Thumb instruction. The only way we can tell is to
+ scan forwards from a known instruction boundary. */
+ if (bpaddr - boundary > IT_SCAN_THRESHOLD)
+ {
+ int definite;
+
+ /* There's a lot of code before this instruction. Start with an
+ optimistic search; it's easy to recognize halfwords that can
+ not be the start of a 32-bit instruction, and use that to
+ lock on to the instruction boundaries. */
+ buf = extend_buffer_earlier (buf, bpaddr, buf_len, IT_SCAN_THRESHOLD);
+ if (buf == NULL)
+ return bpaddr;
+ buf_len = IT_SCAN_THRESHOLD;
+
+ definite = 0;
+ for (i = 0; i < buf_len - sizeof (buf) && ! definite; i += 2)
+ {
+ unsigned short inst1 = extract_unsigned_integer (&buf[i], 2, order);
+ if (thumb_insn_size (inst1) == 2)
+ {
+ definite = 1;
+ break;
+ }
+ }
+
+ /* At this point, if DEFINITE, BUF[I] is the first place we
+ are sure that we know the instruction boundaries, and it is far
+ enough from BPADDR that we could not miss an IT instruction
+ affecting BPADDR. If ! DEFINITE, give up - start from a
+ known boundary. */
+ if (! definite)
+ {
+ buf = extend_buffer_earlier (buf, bpaddr, buf_len, bpaddr - boundary);
+ if (buf == NULL)
+ return bpaddr;
+ buf_len = bpaddr - boundary;
+ i = 0;
+ }
+ }
+ else
+ {
+ buf = extend_buffer_earlier (buf, bpaddr, buf_len, bpaddr - boundary);
+ if (buf == NULL)
+ return bpaddr;
+ buf_len = bpaddr - boundary;
+ i = 0;
+ }
+
+ /* Scan forwards. Find the last IT instruction before BPADDR. */
+ last_it = -1;
+ last_it_count = 0;
+ while (i < buf_len)
+ {
+ unsigned short inst1 = extract_unsigned_integer (&buf[i], 2, order);
+ last_it_count--;
+ if ((inst1 & 0xff00) == 0xbf00 && (inst1 & 0x000f) != 0)
+ {
+ last_it = i;
+ if (inst1 & 0x0001)
+ last_it_count = 4;
+ else if (inst1 & 0x0002)
+ last_it_count = 3;
+ else if (inst1 & 0x0004)
+ last_it_count = 2;
+ else
+ last_it_count = 1;
+ }
+ i += thumb_insn_size (inst1);
+ }
+
+ xfree (buf);
+
+ if (last_it == -1)
+ /* There wasn't really an IT instruction after all. */
+ return bpaddr;
+
+ if (last_it_count < 1)
+ /* It was too far away. */
+ return bpaddr;
+
+ /* This really is a trouble spot. Move the breakpoint to the IT
+ instruction. */
+ return bpaddr - buf_len + last_it;
+}
+
/* ARM displaced stepping support.
Generally ARM displaced stepping works as follows:
matter what address they are executed at: in those cases, use this. */
static int
-copy_unmodified (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, uint32_t insn,
+copy_unmodified (struct gdbarch *gdbarch, uint32_t insn,
const char *iname, struct displaced_step_closure *dsc)
{
if (debug_displaced)
/* Preload instructions with immediate offset. */
static void
-cleanup_preload (struct gdbarch *gdbarch ATTRIBUTE_UNUSED,
+cleanup_preload (struct gdbarch *gdbarch,
struct regcache *regs, struct displaced_step_closure *dsc)
{
displaced_write_reg (regs, dsc, 0, dsc->tmp[0], CANNOT_WRITE_PC);
/* Copy/cleanup coprocessor load and store instructions. */
static void
-cleanup_copro_load_store (struct gdbarch *gdbarch ATTRIBUTE_UNUSED,
+cleanup_copro_load_store (struct gdbarch *gdbarch,
struct regcache *regs,
struct displaced_step_closure *dsc)
{
PC). */
static void
-cleanup_branch (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, struct regcache *regs,
+cleanup_branch (struct gdbarch *gdbarch, struct regcache *regs,
struct displaced_step_closure *dsc)
{
ULONGEST from = dsc->insn_addr;
/* Copy B/BL/BLX instructions with immediate destinations. */
static int
-copy_b_bl_blx (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, uint32_t insn,
+copy_b_bl_blx (struct gdbarch *gdbarch, uint32_t insn,
struct regcache *regs, struct displaced_step_closure *dsc)
{
unsigned int cond = bits (insn, 28, 31);
/* Copy BX/BLX with register-specified destinations. */
static int
-copy_bx_blx_reg (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, uint32_t insn,
+copy_bx_blx_reg (struct gdbarch *gdbarch, uint32_t insn,
struct regcache *regs, struct displaced_step_closure *dsc)
{
unsigned int cond = bits (insn, 28, 31);
/* Copy/cleanup arithmetic/logic instruction with immediate RHS. */
static void
-cleanup_alu_imm (struct gdbarch *gdbarch ATTRIBUTE_UNUSED,
+cleanup_alu_imm (struct gdbarch *gdbarch,
struct regcache *regs, struct displaced_step_closure *dsc)
{
ULONGEST rd_val = displaced_read_reg (regs, dsc->insn_addr, 0);
/* Copy/cleanup arithmetic/logic insns with register RHS. */
static void
-cleanup_alu_reg (struct gdbarch *gdbarch ATTRIBUTE_UNUSED,
+cleanup_alu_reg (struct gdbarch *gdbarch,
struct regcache *regs, struct displaced_step_closure *dsc)
{
ULONGEST rd_val;
/* Cleanup/copy arithmetic/logic insns with shifted register RHS. */
static void
-cleanup_alu_shifted_reg (struct gdbarch *gdbarch ATTRIBUTE_UNUSED,
+cleanup_alu_shifted_reg (struct gdbarch *gdbarch,
struct regcache *regs,
struct displaced_step_closure *dsc)
{
/* Clean up load instructions. */
static void
-cleanup_load (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, struct regcache *regs,
+cleanup_load (struct gdbarch *gdbarch, struct regcache *regs,
struct displaced_step_closure *dsc)
{
ULONGEST rt_val, rt_val2 = 0, rn_val;
/* Clean up store instructions. */
static void
-cleanup_store (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, struct regcache *regs,
+cleanup_store (struct gdbarch *gdbarch, struct regcache *regs,
struct displaced_step_closure *dsc)
{
CORE_ADDR from = dsc->insn_addr;
must undo that here. */
static void
-cleanup_block_load_pc (struct gdbarch *gdbarch ATTRIBUTE_UNUSED,
+cleanup_block_load_pc (struct gdbarch *gdbarch,
struct regcache *regs,
struct displaced_step_closure *dsc)
{
for Linux, where some SVC instructions must be treated specially. */
static void
-cleanup_svc (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, struct regcache *regs,
+cleanup_svc (struct gdbarch *gdbarch, struct regcache *regs,
struct displaced_step_closure *dsc)
{
CORE_ADDR from = dsc->insn_addr;
/* Copy undefined instructions. */
static int
-copy_undef (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, uint32_t insn,
+copy_undef (struct gdbarch *gdbarch, uint32_t insn,
struct displaced_step_closure *dsc)
{
if (debug_displaced)
/* Copy unpredictable instructions. */
static int
-copy_unpred (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, uint32_t insn,
+copy_unpred (struct gdbarch *gdbarch, uint32_t insn,
struct displaced_step_closure *dsc)
{
if (debug_displaced)
arm_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
if (arm_pc_is_thumb (*pcptr))
{
*pcptr = UNMAKE_THUMB_ADDR (*pcptr);
+
+ /* If we have a separate 32-bit breakpoint instruction for Thumb-2,
+ check whether we are replacing a 32-bit instruction. */
+ if (tdep->thumb2_breakpoint != NULL)
+ {
+ gdb_byte buf[2];
+ if (target_read_memory (*pcptr, buf, 2) == 0)
+ {
+ unsigned short inst1;
+ inst1 = extract_unsigned_integer (buf, 2, byte_order_for_code);
+ if ((inst1 & 0xe000) == 0xe000 && (inst1 & 0x1800) != 0)
+ {
+ *lenptr = tdep->thumb2_breakpoint_size;
+ return tdep->thumb2_breakpoint;
+ }
+ }
+ }
+
*lenptr = tdep->thumb_breakpoint_size;
return tdep->thumb_breakpoint;
}
}
}
+static void
+arm_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
+ int *kindptr)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ arm_breakpoint_from_pc (gdbarch, pcptr, kindptr);
+
+ if (arm_pc_is_thumb (*pcptr) && *kindptr == 4)
+ /* The documented magic value for a 32-bit Thumb-2 breakpoint, so
+ that this is not confused with a 32-bit ARM breakpoint. */
+ *kindptr = 3;
+}
+
/* Extract from an array REGBUF containing the (raw) register state a
function return value of type TYPE, and copy that, in virtual
format, into VALBUF. */
/* If PC is in a Thumb call or return stub, return the address of the
target PC, which is in a register. The thunk functions are called
_call_via_xx, where x is the register name. The possible names
- are r0-r9, sl, fp, ip, sp, and lr. */
- if (strncmp (name, "_call_via_", 10) == 0)
+ are r0-r9, sl, fp, ip, sp, and lr. ARM RealView has similar
+ functions, named __ARM_call_via_r[0-7]. */
+ if (strncmp (name, "_call_via_", 10) == 0
+ || strncmp (name, "__ARM_call_via_", strlen ("__ARM_call_via_")) == 0)
{
/* Use the name suffix to determine which register contains the
target PC. */
/* Breakpoint manipulation. */
set_gdbarch_breakpoint_from_pc (gdbarch, arm_breakpoint_from_pc);
+ set_gdbarch_remote_breakpoint_from_pc (gdbarch,
+ arm_remote_breakpoint_from_pc);
/* Information about registers, etc. */
set_gdbarch_deprecated_fp_regnum (gdbarch, ARM_FP_REGNUM); /* ??? */
arm_coff_make_msymbol_special);
set_gdbarch_record_special_symbol (gdbarch, arm_record_special_symbol);
+ /* Thumb-2 IT block support. */
+ set_gdbarch_adjust_breakpoint_address (gdbarch,
+ arm_adjust_breakpoint_address);
+
/* Virtual tables. */
set_gdbarch_vbit_in_delta (gdbarch, 1);