X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Farm-tdep.c;h=ef7e66b36afe34aed3880b86d16b466984481131;hb=849d0ba802323fe05e3039ed5b22957db2c85a67;hp=c8b665ab1737154c419acc927f582817736526bf;hpb=b13c8ab2b93de7fe1adb1ecd307d9078ce299c6e;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index c8b665ab17..ef7e66b36a 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -1,6 +1,6 @@ /* Common target dependent code for GDB on ARM systems. - Copyright (C) 1988-2015 Free Software Foundation, Inc. + Copyright (C) 1988-2018 Free Software Foundation, Inc. This file is part of GDB. @@ -27,9 +27,10 @@ #include "gdbcmd.h" #include "gdbcore.h" #include "dis-asm.h" /* For register styles. */ +#include "disasm.h" #include "regcache.h" #include "reggroups.h" -#include "doublest.h" +#include "target-float.h" #include "value.h" #include "arch-utils.h" #include "osabi.h" @@ -46,6 +47,7 @@ #include "observer.h" #include "arch/arm.h" +#include "arch/arm-get-next-pcs.h" #include "arm-tdep.h" #include "gdb/sim-arm.h" @@ -57,14 +59,19 @@ #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" +#include + +#include "features/arm/arm-with-m.c" +#include "features/arm/arm-with-m-fpa-layout.c" +#include "features/arm/arm-with-m-vfp-d16.c" +#include "features/arm/arm-with-iwmmxt.c" +#include "features/arm/arm-with-vfpv2.c" +#include "features/arm/arm-with-vfpv3.c" +#include "features/arm/arm-with-neon.c" + +#if GDB_SELF_TEST +#include "selftest.h" +#endif static int arm_debug; @@ -142,16 +149,6 @@ static const char *const 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; - /* The standard register names, and all the valid aliases for them. Note that `fp', `sp' and `pc' are not added in this alias list, because they have been added as builtin user registers in @@ -212,6 +209,9 @@ static const char *const arm_register_names[] = "f4", "f5", "f6", "f7", /* 20 21 22 23 */ "fps", "cpsr" }; /* 24 25 */ +/* Holds the current set of options to be passed to the disassembler. */ +static char *arm_disassembler_options; + /* Valid register name styles. */ static const char **valid_disassembly_styles; @@ -220,22 +220,32 @@ static const char *disassembly_style; /* This is used to keep the bfd arch_info in sync with the disassembly style. */ -static void set_disassembly_style_sfunc(char *, int, +static void set_disassembly_style_sfunc (const char *, int, struct cmd_list_element *); -static void set_disassembly_style (void); - -static void convert_from_extended (const struct floatformat *, const void *, - void *, int); -static void convert_to_extended (const struct floatformat *, void *, - const void *, int); +static void show_disassembly_style_sfunc (struct ui_file *, int, + struct cmd_list_element *, + const char *); static enum register_status arm_neon_quad_read (struct gdbarch *gdbarch, - struct regcache *regcache, + readable_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 CORE_ADDR + arm_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self); + + +/* get_next_pcs operations. */ +static struct arm_get_next_pcs_ops arm_get_next_pcs_ops = { + arm_get_next_pcs_read_memory_unsigned_integer, + arm_get_next_pcs_syscall_next_pc, + arm_get_next_pcs_addr_bits_remove, + arm_get_next_pcs_is_thumb, + NULL, +}; + struct arm_prologue_cache { /* The stack pointer at the time this frame was created; i.e. the @@ -281,6 +291,19 @@ arm_psr_thumb_bit (struct gdbarch *gdbarch) return CPSR_T; } +/* Determine if the processor is currently executing in Thumb mode. */ + +int +arm_is_thumb (struct regcache *regcache) +{ + ULONGEST cpsr; + ULONGEST t_bit = arm_psr_thumb_bit (regcache->arch ()); + + cpsr = regcache_raw_get_unsigned (regcache, ARM_PS_REGNUM); + + return (cpsr & t_bit) != 0; +} + /* Determine if FRAME is executing in Thumb mode. */ int @@ -376,8 +399,9 @@ arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr) { struct bound_minimal_symbol sym; char type; - struct displaced_step_closure* dsc - = get_displaced_step_closure_by_addr(memaddr); + arm_displaced_step_closure *dsc + = ((arm_displaced_step_closure * ) + 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. */ @@ -395,10 +419,6 @@ arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr) 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; @@ -437,6 +457,62 @@ arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr) return 0; } +/* Determine if the address specified equals any of these magic return + values, called EXC_RETURN, defined by the ARM v6-M and v7-M + architectures. + + From ARMv6-M Reference Manual B1.5.8 + Table B1-5 Exception return behavior + + EXC_RETURN Return To Return Stack + 0xFFFFFFF1 Handler mode Main + 0xFFFFFFF9 Thread mode Main + 0xFFFFFFFD Thread mode Process + + From ARMv7-M Reference Manual B1.5.8 + Table B1-8 EXC_RETURN definition of exception return behavior, no FP + + EXC_RETURN Return To Return Stack + 0xFFFFFFF1 Handler mode Main + 0xFFFFFFF9 Thread mode Main + 0xFFFFFFFD Thread mode Process + + Table B1-9 EXC_RETURN definition of exception return behavior, with + FP + + EXC_RETURN Return To Return Stack Frame Type + 0xFFFFFFE1 Handler mode Main Extended + 0xFFFFFFE9 Thread mode Main Extended + 0xFFFFFFED Thread mode Process Extended + 0xFFFFFFF1 Handler mode Main Basic + 0xFFFFFFF9 Thread mode Main Basic + 0xFFFFFFFD Thread mode Process Basic + + For more details see "B1.5.8 Exception return behavior" + in both ARMv6-M and ARMv7-M Architecture Reference Manuals. */ + +static int +arm_m_addr_is_magic (CORE_ADDR addr) +{ + switch (addr) + { + /* Values from Tables in B1.5.8 the EXC_RETURN definitions of + the exception return behavior. */ + case 0xffffffe1: + case 0xffffffe9: + case 0xffffffed: + case 0xfffffff1: + case 0xfffffff9: + case 0xfffffffd: + /* Address is magic. */ + return 1; + + default: + /* Address is not magic. */ + return 0; + } +} + /* Remove useless bits from addresses in a running program. */ static CORE_ADDR arm_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR val) @@ -444,7 +520,7 @@ 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) + && arm_m_addr_is_magic (val)) return val; if (arm_apcs_32) @@ -497,9 +573,9 @@ skip_prologue_function (struct gdbarch *gdbarch, CORE_ADDR pc, int is_thumb) implementation (this is hand-written ARM assembler in glibc). */ if (!is_thumb - && read_memory_unsigned_integer (pc, 4, byte_order_for_code) + && read_code_unsigned_integer (pc, 4, byte_order_for_code) == 0xe3e00a0f /* mov r0, #0xffff0fff */ - && read_memory_unsigned_integer (pc + 4, 4, byte_order_for_code) + && read_code_unsigned_integer (pc + 4, 4, byte_order_for_code) == 0xe240f01f) /* sub pc, r0, #31 */ return 1; } @@ -507,15 +583,6 @@ skip_prologue_function (struct gdbarch *gdbarch, CORE_ADDR pc, int is_thumb) 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) (((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 instruction. */ @@ -555,128 +622,6 @@ thumb_expand_immediate (unsigned int imm) return (0x80 | (imm & 0x7f)) << (32 - count); } -/* Return 1 if the 16-bit Thumb instruction INST might change - control flow, 0 otherwise. */ - -static int -thumb_instruction_changes_pc (unsigned short inst) -{ - if ((inst & 0xff00) == 0xbd00) /* pop {rlist, pc} */ - return 1; - - if ((inst & 0xf000) == 0xd000) /* conditional branch */ - return 1; - - if ((inst & 0xf800) == 0xe000) /* unconditional branch */ - return 1; - - if ((inst & 0xff00) == 0x4700) /* bx REG, blx REG */ - return 1; - - if ((inst & 0xff87) == 0x4687) /* mov pc, REG */ - return 1; - - if ((inst & 0xf500) == 0xb100) /* CBNZ or CBZ. */ - return 1; - - return 0; -} - -/* Return 1 if the 32-bit Thumb instruction in INST1 and INST2 - might change control flow, 0 otherwise. */ - -static int -thumb2_instruction_changes_pc (unsigned short inst1, unsigned short inst2) -{ - if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000) - { - /* Branches and miscellaneous control instructions. */ - - if ((inst2 & 0x1000) != 0 || (inst2 & 0xd001) == 0xc000) - { - /* B, BL, BLX. */ - return 1; - } - else if (inst1 == 0xf3de && (inst2 & 0xff00) == 0x3f00) - { - /* SUBS PC, LR, #imm8. */ - return 1; - } - else if ((inst2 & 0xd000) == 0x8000 && (inst1 & 0x0380) != 0x0380) - { - /* Conditional branch. */ - return 1; - } - - return 0; - } - - if ((inst1 & 0xfe50) == 0xe810) - { - /* Load multiple or RFE. */ - - if (bit (inst1, 7) && !bit (inst1, 8)) - { - /* LDMIA or POP */ - if (bit (inst2, 15)) - return 1; - } - else if (!bit (inst1, 7) && bit (inst1, 8)) - { - /* LDMDB */ - if (bit (inst2, 15)) - return 1; - } - else if (bit (inst1, 7) && bit (inst1, 8)) - { - /* RFEIA */ - return 1; - } - else if (!bit (inst1, 7) && !bit (inst1, 8)) - { - /* RFEDB */ - return 1; - } - - return 0; - } - - if ((inst1 & 0xffef) == 0xea4f && (inst2 & 0xfff0) == 0x0f00) - { - /* MOV PC or MOVS PC. */ - return 1; - } - - if ((inst1 & 0xff70) == 0xf850 && (inst2 & 0xf000) == 0xf000) - { - /* LDR PC. */ - if (bits (inst1, 0, 3) == 15) - return 1; - if (bit (inst1, 7)) - return 1; - if (bit (inst2, 11)) - return 1; - if ((inst2 & 0x0fc0) == 0x0000) - return 1; - - return 0; - } - - if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000) - { - /* TBB. */ - return 1; - } - - if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf010) - { - /* TBH. */ - return 1; - } - - return 0; -} - /* Return 1 if the 16-bit Thumb instruction INSN restores SP in epilogue, 0 otherwise. */ @@ -703,28 +648,25 @@ thumb_analyze_prologue (struct gdbarch *gdbarch, enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); int i; pv_t regs[16]; - struct pv_area *stack; - struct cleanup *back_to; CORE_ADDR offset; CORE_ADDR unrecognized_pc = 0; for (i = 0; i < 16; i++) regs[i] = pv_register (i, 0); - stack = make_pv_area (ARM_SP_REGNUM, gdbarch_addr_bit (gdbarch)); - back_to = make_cleanup_free_pv_area (stack); + pv_area stack (ARM_SP_REGNUM, gdbarch_addr_bit (gdbarch)); while (start < limit) { unsigned short insn; - insn = read_memory_unsigned_integer (start, 2, byte_order_for_code); + insn = read_code_unsigned_integer (start, 2, byte_order_for_code); if ((insn & 0xfe00) == 0xb400) /* push { rlist } */ { int regno; int mask; - if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM])) + if (stack.store_would_trash (regs[ARM_SP_REGNUM])) break; /* Bits 0-7 contain a mask for registers R0-R7. Bit 8 says @@ -737,7 +679,7 @@ thumb_analyze_prologue (struct gdbarch *gdbarch, { regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -4); - pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]); + stack.store (regs[ARM_SP_REGNUM], 4, regs[regno]); } } else if ((insn & 0xff80) == 0xb080) /* sub sp, #imm */ @@ -791,10 +733,10 @@ thumb_analyze_prologue (struct gdbarch *gdbarch, offset = (insn & 0xff) << 2; addr = pv_add_constant (regs[ARM_SP_REGNUM], offset); - if (pv_area_store_would_trash (stack, addr)) + if (stack.store_would_trash (addr)) break; - pv_area_store (stack, addr, 4, regs[regno]); + stack.store (addr, 4, regs[regno]); } else if ((insn & 0xf800) == 0x6000) /* str rd, [rn, #off] */ { @@ -805,10 +747,10 @@ thumb_analyze_prologue (struct gdbarch *gdbarch, offset = bits (insn, 6, 10) << 2; addr = pv_add_constant (regs[rn], offset); - if (pv_area_store_would_trash (stack, addr)) + if (stack.store_would_trash (addr)) break; - pv_area_store (stack, addr, 4, regs[rd]); + stack.store (addr, 4, regs[rd]); } else if (((insn & 0xf800) == 0x7000 /* strb Rd, [Rn, #off] */ || (insn & 0xf800) == 0x8000) /* strh Rd, [Rn, #off] */ @@ -848,8 +790,8 @@ thumb_analyze_prologue (struct gdbarch *gdbarch, { unsigned short inst2; - inst2 = read_memory_unsigned_integer (start + 2, 2, - byte_order_for_code); + inst2 = read_code_unsigned_integer (start + 2, 2, + byte_order_for_code); if ((insn & 0xf800) == 0xf000 && (inst2 & 0xe800) == 0xe800) { @@ -884,7 +826,7 @@ thumb_analyze_prologue (struct gdbarch *gdbarch, pv_t addr = regs[bits (insn, 0, 3)]; int regno; - if (pv_area_store_would_trash (stack, addr)) + if (stack.store_would_trash (addr)) break; /* Calculate offsets of saved registers. */ @@ -892,7 +834,7 @@ thumb_analyze_prologue (struct gdbarch *gdbarch, if (inst2 & (1 << regno)) { addr = pv_add_constant (addr, -4); - pv_area_store (stack, addr, 4, regs[regno]); + stack.store (addr, 4, regs[regno]); } if (insn & 0x0020) @@ -913,12 +855,12 @@ thumb_analyze_prologue (struct gdbarch *gdbarch, else addr = pv_add_constant (addr, -offset); - if (pv_area_store_would_trash (stack, addr)) + if (stack.store_would_trash (addr)) break; - pv_area_store (stack, addr, 4, regs[regno1]); - pv_area_store (stack, pv_add_constant (addr, 4), - 4, regs[regno2]); + stack.store (addr, 4, regs[regno1]); + stack.store (pv_add_constant (addr, 4), + 4, regs[regno2]); if (insn & 0x0020) regs[bits (insn, 0, 3)] = addr; @@ -937,10 +879,10 @@ thumb_analyze_prologue (struct gdbarch *gdbarch, else addr = pv_add_constant (addr, -offset); - if (pv_area_store_would_trash (stack, addr)) + if (stack.store_would_trash (addr)) break; - pv_area_store (stack, addr, 4, regs[regno]); + stack.store (addr, 4, regs[regno]); if (inst2 & 0x0100) regs[bits (insn, 0, 3)] = addr; @@ -955,10 +897,10 @@ thumb_analyze_prologue (struct gdbarch *gdbarch, offset = inst2 & 0xfff; addr = pv_add_constant (regs[bits (insn, 0, 3)], offset); - if (pv_area_store_would_trash (stack, addr)) + if (stack.store_would_trash (addr)) break; - pv_area_store (stack, addr, 4, regs[regno]); + stack.store (addr, 4, regs[regno]); } else if ((insn & 0xffd0) == 0xf880 /* str{bh}.w Rt,[Rn,#imm] */ @@ -1141,10 +1083,7 @@ thumb_analyze_prologue (struct gdbarch *gdbarch, unrecognized_pc = start; if (cache == NULL) - { - do_cleanups (back_to); - return unrecognized_pc; - } + return unrecognized_pc; if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM)) { @@ -1166,10 +1105,9 @@ thumb_analyze_prologue (struct gdbarch *gdbarch, } for (i = 0; i < 16; i++) - if (pv_area_find_reg (stack, gdbarch, i, &offset)) + if (stack.find_reg (gdbarch, i, &offset)) cache->saved_regs[i].addr = offset; - do_cleanups (back_to); return unrecognized_pc; } @@ -1192,7 +1130,7 @@ arm_analyze_load_stack_chk_guard(CORE_ADDR pc, struct gdbarch *gdbarch, if (is_thumb) { unsigned short insn1 - = read_memory_unsigned_integer (pc, 2, byte_order_for_code); + = read_code_unsigned_integer (pc, 2, byte_order_for_code); if ((insn1 & 0xf800) == 0x4800) /* ldr Rd, #immed */ { @@ -1205,14 +1143,14 @@ arm_analyze_load_stack_chk_guard(CORE_ADDR pc, struct gdbarch *gdbarch, else if ((insn1 & 0xfbf0) == 0xf240) /* movw Rd, #const */ { unsigned short insn2 - = read_memory_unsigned_integer (pc + 2, 2, byte_order_for_code); + = read_code_unsigned_integer (pc + 2, 2, byte_order_for_code); low = EXTRACT_MOVW_MOVT_IMM_T (insn1, insn2); insn1 - = read_memory_unsigned_integer (pc + 4, 2, byte_order_for_code); + = read_code_unsigned_integer (pc + 4, 2, byte_order_for_code); insn2 - = read_memory_unsigned_integer (pc + 6, 2, byte_order_for_code); + = read_code_unsigned_integer (pc + 6, 2, byte_order_for_code); /* movt Rd, #const */ if ((insn1 & 0xfbc0) == 0xf2c0) @@ -1227,7 +1165,7 @@ arm_analyze_load_stack_chk_guard(CORE_ADDR pc, struct gdbarch *gdbarch, else { unsigned int insn - = read_memory_unsigned_integer (pc, 4, byte_order_for_code); + = read_code_unsigned_integer (pc, 4, byte_order_for_code); if ((insn & 0x0e5f0000) == 0x041f0000) /* ldr Rd, [PC, #immed] */ { @@ -1243,7 +1181,7 @@ arm_analyze_load_stack_chk_guard(CORE_ADDR pc, struct gdbarch *gdbarch, low = EXTRACT_MOVW_MOVT_IMM_A (insn); insn - = read_memory_unsigned_integer (pc + 4, 4, byte_order_for_code); + = read_code_unsigned_integer (pc + 4, 4, byte_order_for_code); if ((insn & 0x0ff00000) == 0x03400000) /* movt Rd, #const */ { @@ -1315,7 +1253,7 @@ arm_skip_stack_protector(CORE_ADDR pc, struct gdbarch *gdbarch) { unsigned int destreg; unsigned short insn - = read_memory_unsigned_integer (pc + offset, 2, byte_order_for_code); + = read_code_unsigned_integer (pc + offset, 2, byte_order_for_code); /* Step 2: ldr Rd, [Rn, #immed], encoding T1. */ if ((insn & 0xf800) != 0x6800) @@ -1324,8 +1262,8 @@ arm_skip_stack_protector(CORE_ADDR pc, struct gdbarch *gdbarch) return pc; destreg = bits (insn, 0, 2); - insn = read_memory_unsigned_integer (pc + offset + 2, 2, - byte_order_for_code); + insn = read_code_unsigned_integer (pc + offset + 2, 2, + byte_order_for_code); /* Step 3: str Rd, [Rn, #immed], encoding T1. */ if ((insn & 0xf800) != 0x6000) return pc; @@ -1336,7 +1274,7 @@ arm_skip_stack_protector(CORE_ADDR pc, struct gdbarch *gdbarch) { unsigned int destreg; unsigned int insn - = read_memory_unsigned_integer (pc + offset, 4, byte_order_for_code); + = read_code_unsigned_integer (pc + offset, 4, byte_order_for_code); /* Step 2: ldr Rd, [Rn, #immed], encoding A1. */ if ((insn & 0x0e500000) != 0x04100000) @@ -1345,7 +1283,7 @@ arm_skip_stack_protector(CORE_ADDR pc, struct gdbarch *gdbarch) return pc; destreg = bits (insn, 12, 15); /* Step 3: str Rd, [Rn, #immed], encoding A1. */ - insn = read_memory_unsigned_integer (pc + offset + 4, + insn = read_code_unsigned_integer (pc + offset + 4, 4, byte_order_for_code); if ((insn & 0x0e500000) != 0x04000000) return pc; @@ -1378,8 +1316,6 @@ arm_skip_stack_protector(CORE_ADDR pc, struct gdbarch *gdbarch) static CORE_ADDR 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 func_addr, limit_pc; /* See if we can determine the end of the prologue via the symbol table. @@ -1499,103 +1435,11 @@ thumb_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR prev_pc, function is. */ return; - prologue_end = min (prologue_end, prev_pc); + prologue_end = std::min (prologue_end, prev_pc); thumb_analyze_prologue (gdbarch, prologue_start, prologue_end, cache); } -/* Return 1 if THIS_INSTR might change control flow, 0 otherwise. */ - -static int -arm_instruction_changes_pc (uint32_t this_instr) -{ - 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; - - /* Otherwise, miscellaneous instructions. */ - - /* BX , BXJ , BLX */ - if (bits (this_instr, 4, 27) == 0x12fff1 - || bits (this_instr, 4, 27) == 0x12fff2 - || bits (this_instr, 4, 27) == 0x12fff3) - return 1; - - /* Other miscellaneous instructions are unpredictable if they - modify PC. */ - return 0; - } - /* Data processing instruction. Fall through. */ - - case 0x1: - if (bits (this_instr, 12, 15) == 15) - return 1; - else - return 0; - - case 0x2: - case 0x3: - /* Media instructions and architecturally undefined instructions. */ - if (bits (this_instr, 25, 27) == 3 && bit (this_instr, 4) == 1) - return 0; - - /* Stores. */ - if (bit (this_instr, 20) == 0) - return 0; - - /* Loads. */ - if (bits (this_instr, 12, 15) == ARM_PC_REGNUM) - return 1; - else - return 0; - - case 0x4: - /* Load/store multiple. */ - if (bit (this_instr, 20) == 1 && bit (this_instr, 15) == 1) - return 1; - else - return 0; - - 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")); - } -} - /* Return 1 if the ARM instruction INSN restores SP in epilogue, 0 otherwise. */ @@ -1635,13 +1479,10 @@ 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; CORE_ADDR unrecognized_pc = 0; /* Search the prologue looking for instructions that set up the @@ -1656,15 +1497,14 @@ arm_analyze_prologue (struct gdbarch *gdbarch, for (regno = 0; regno < ARM_FPS_REGNUM; regno++) regs[regno] = pv_register (regno, 0); - stack = make_pv_area (ARM_SP_REGNUM, gdbarch_addr_bit (gdbarch)); - back_to = make_cleanup_free_pv_area (stack); + pv_area stack (ARM_SP_REGNUM, gdbarch_addr_bit (gdbarch)); for (current_pc = prologue_start; current_pc < prologue_end; current_pc += 4) { unsigned int insn - = read_memory_unsigned_integer (current_pc, 4, byte_order_for_code); + = read_code_unsigned_integer (current_pc, 4, byte_order_for_code); if (insn == 0xe1a0c00d) /* mov ip, sp */ { @@ -1694,11 +1534,11 @@ arm_analyze_prologue (struct gdbarch *gdbarch, else if ((insn & 0xffff0fff) == 0xe52d0004) /* str Rd, [sp, #-4]! */ { - if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM])) + if (stack.store_would_trash (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[bits (insn, 12, 15)]); + stack.store (regs[ARM_SP_REGNUM], 4, + regs[bits (insn, 12, 15)]); continue; } else if ((insn & 0xffff0000) == 0xe92d0000) @@ -1708,7 +1548,7 @@ arm_analyze_prologue (struct gdbarch *gdbarch, { int mask = insn & 0xffff; - if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM])) + if (stack.store_would_trash (regs[ARM_SP_REGNUM])) break; /* Calculate offsets of saved registers. */ @@ -1717,7 +1557,7 @@ arm_analyze_prologue (struct gdbarch *gdbarch, { regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -4); - pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]); + stack.store (regs[ARM_SP_REGNUM], 4, regs[regno]); } } else if ((insn & 0xffff0000) == 0xe54b0000 /* strb rx,[r11,#-n] */ @@ -1759,12 +1599,12 @@ arm_analyze_prologue (struct gdbarch *gdbarch, [sp, -#c]! */ && gdbarch_tdep (gdbarch)->have_fpa_registers) { - if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM])) + if (stack.store_would_trash (regs[ARM_SP_REGNUM])) break; regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -12); regno = ARM_F0_REGNUM + ((insn >> 12) & 0x07); - pv_area_store (stack, regs[ARM_SP_REGNUM], 12, regs[regno]); + stack.store (regs[ARM_SP_REGNUM], 12, regs[regno]); } else if ((insn & 0xffbf0fff) == 0xec2d0200 /* sfmfd f0, 4, [sp!] */ @@ -1773,7 +1613,7 @@ arm_analyze_prologue (struct gdbarch *gdbarch, int n_saved_fp_regs; unsigned int fp_start_reg, fp_bound_reg; - if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM])) + if (stack.store_would_trash (regs[ARM_SP_REGNUM])) break; if ((insn & 0x800) == 0x800) /* N0 is set */ @@ -1796,8 +1636,8 @@ arm_analyze_prologue (struct gdbarch *gdbarch, 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++]); + stack.store (regs[ARM_SP_REGNUM], 12, + regs[fp_start_reg++]); } } else if ((insn & 0xff000000) == 0xeb000000 && cache == NULL) /* bl */ @@ -1877,7 +1717,7 @@ arm_analyze_prologue (struct gdbarch *gdbarch, cache->framesize = framesize; for (regno = 0; regno < ARM_FPS_REGNUM; regno++) - if (pv_area_find_reg (stack, gdbarch, regno, &offset)) + if (stack.find_reg (gdbarch, regno, &offset)) cache->saved_regs[regno].addr = offset; } @@ -1885,7 +1725,6 @@ arm_analyze_prologue (struct gdbarch *gdbarch, fprintf_unfiltered (gdb_stdlog, "Prologue scan stopped at %s\n", paddress (gdbarch, unrecognized_pc)); - do_cleanups (back_to); return unrecognized_pc; } @@ -1895,14 +1734,9 @@ arm_scan_prologue (struct frame_info *this_frame, { 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 prologue_start, prologue_end; 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; @@ -1965,10 +1799,11 @@ arm_scan_prologue (struct frame_info *this_frame, 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; + ULONGEST 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)) + if (!safe_read_memory_unsigned_integer (frame_loc, 4, byte_order, + &return_value)) return; else { @@ -2817,19 +2652,19 @@ arm_exidx_unwind_sniffer (const struct frame_unwind *self, ensure this, so that e.g. pthread cancellation works. */ if (arm_frame_is_thumb (this_frame)) { - LONGEST insn; + ULONGEST insn; - if (safe_read_memory_integer (get_frame_pc (this_frame) - 2, 2, - byte_order_for_code, &insn) + if (safe_read_memory_unsigned_integer (get_frame_pc (this_frame) - 2, + 2, byte_order_for_code, &insn) && (insn & 0xff00) == 0xdf00 /* svc */) exc_valid = 1; } else { - LONGEST insn; + ULONGEST insn; - if (safe_read_memory_integer (get_frame_pc (this_frame) - 4, 4, - byte_order_for_code, &insn) + if (safe_read_memory_unsigned_integer (get_frame_pc (this_frame) - 4, + 4, byte_order_for_code, &insn) && (insn & 0x0f000000) == 0x0f000000 /* svc */) exc_valid = 1; } @@ -2873,6 +2708,108 @@ struct frame_unwind arm_exidx_unwind = { arm_exidx_unwind_sniffer }; +static struct arm_prologue_cache * +arm_make_epilogue_frame_cache (struct frame_info *this_frame) +{ + struct arm_prologue_cache *cache; + int reg; + + cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache); + cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); + + /* Still rely on the offset calculated from prologue. */ + arm_scan_prologue (this_frame, cache); + + /* Since we are in epilogue, the SP has been restored. */ + cache->prev_sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM); + + /* Calculate actual addresses of saved registers using offsets + determined by arm_scan_prologue. */ + for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (this_frame)); reg++) + if (trad_frame_addr_p (cache->saved_regs, reg)) + cache->saved_regs[reg].addr += cache->prev_sp; + + return cache; +} + +/* Implementation of function hook 'this_id' in + 'struct frame_uwnind' for epilogue unwinder. */ + +static void +arm_epilogue_frame_this_id (struct frame_info *this_frame, + void **this_cache, + struct frame_id *this_id) +{ + struct arm_prologue_cache *cache; + CORE_ADDR pc, func; + + if (*this_cache == NULL) + *this_cache = arm_make_epilogue_frame_cache (this_frame); + cache = (struct arm_prologue_cache *) *this_cache; + + /* Use function start address as part of the frame ID. If we cannot + identify the start address (due to missing symbol information), + fall back to just using the current PC. */ + pc = get_frame_pc (this_frame); + func = get_frame_func (this_frame); + if (func == 0) + func = pc; + + (*this_id) = frame_id_build (cache->prev_sp, pc); +} + +/* Implementation of function hook 'prev_register' in + 'struct frame_uwnind' for epilogue unwinder. */ + +static struct value * +arm_epilogue_frame_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + if (*this_cache == NULL) + *this_cache = arm_make_epilogue_frame_cache (this_frame); + + return arm_prologue_prev_register (this_frame, this_cache, regnum); +} + +static int arm_stack_frame_destroyed_p_1 (struct gdbarch *gdbarch, + CORE_ADDR pc); +static int thumb_stack_frame_destroyed_p (struct gdbarch *gdbarch, + CORE_ADDR pc); + +/* Implementation of function hook 'sniffer' in + 'struct frame_uwnind' for epilogue unwinder. */ + +static int +arm_epilogue_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_prologue_cache) +{ + if (frame_relative_level (this_frame) == 0) + { + struct gdbarch *gdbarch = get_frame_arch (this_frame); + CORE_ADDR pc = get_frame_pc (this_frame); + + if (arm_frame_is_thumb (this_frame)) + return thumb_stack_frame_destroyed_p (gdbarch, pc); + else + return arm_stack_frame_destroyed_p_1 (gdbarch, pc); + } + else + return 0; +} + +/* Frame unwinder from epilogue. */ + +static const struct frame_unwind arm_epilogue_frame_unwind = +{ + NORMAL_FRAME, + default_frame_unwind_stop_reason, + arm_epilogue_frame_this_id, + arm_epilogue_frame_prev_register, + NULL, + arm_epilogue_frame_sniffer, +}; + /* Recognize GCC's trampoline for thumb call-indirect. If we are in a trampoline, return the target PC. Otherwise return 0. @@ -3064,7 +3001,6 @@ 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) @@ -3093,14 +3029,8 @@ arm_m_exception_unwind_sniffer (const struct frame_unwind *self, /* 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; + /* Check if exception frame returns to a magic PC value. */ + return arm_m_addr_is_magic (this_pc); } /* Frame unwinder for M-profile exceptions. */ @@ -3329,19 +3259,14 @@ thumb_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc) return found_stack_adjust; } -/* Implement the stack_frame_destroyed_p gdbarch method. */ - static int -arm_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc) +arm_stack_frame_destroyed_p_1 (struct gdbarch *gdbarch, CORE_ADDR pc) { enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); unsigned int insn; int found_return; CORE_ADDR func_start, func_end; - if (arm_pc_is_thumb (gdbarch, pc)) - return thumb_stack_frame_destroyed_p (gdbarch, pc); - if (!find_pc_partial_function (pc, NULL, &func_start, &func_end)) return 0; @@ -3383,6 +3308,16 @@ arm_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc) return 0; } +/* Implement the stack_frame_destroyed_p gdbarch method. */ + +static int +arm_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + if (arm_pc_is_thumb (gdbarch, pc)) + return thumb_stack_frame_destroyed_p (gdbarch, pc); + else + return arm_stack_frame_destroyed_p_1 (gdbarch, pc); +} /* When arguments must be pushed onto the stack, they go on in reverse order. The code below implements a FILO (stack) to do this. */ @@ -3441,13 +3376,24 @@ arm_type_align (struct type *t) case TYPE_CODE_SET: case TYPE_CODE_RANGE: case TYPE_CODE_REF: + case TYPE_CODE_RVALUE_REF: case TYPE_CODE_CHAR: case TYPE_CODE_BOOL: return TYPE_LENGTH (t); case TYPE_CODE_ARRAY: + if (TYPE_VECTOR (t)) + { + /* Use the natural alignment for vector types (the same for + scalar type), but the maximum alignment is 64-bit. */ + if (TYPE_LENGTH (t) > 8) + return 8; + else + return TYPE_LENGTH (t); + } + else + return arm_type_align (TYPE_TARGET_TYPE (t)); case TYPE_CODE_COMPLEX: - /* TODO: What about vector types? */ return arm_type_align (TYPE_TARGET_TYPE (t)); case TYPE_CODE_STRUCT: @@ -3594,21 +3540,44 @@ arm_vfp_cprc_sub_candidate (struct type *t, case TYPE_CODE_ARRAY: { - int count; - unsigned unitlen; - count = arm_vfp_cprc_sub_candidate (TYPE_TARGET_TYPE (t), base_type); - if (count == -1) - return -1; - if (TYPE_LENGTH (t) == 0) + if (TYPE_VECTOR (t)) { - gdb_assert (count == 0); - return 0; + /* A 64-bit or 128-bit containerized vector type are VFP + CPRCs. */ + switch (TYPE_LENGTH (t)) + { + case 8: + if (*base_type == VFP_CPRC_UNKNOWN) + *base_type = VFP_CPRC_VEC64; + return 1; + case 16: + if (*base_type == VFP_CPRC_UNKNOWN) + *base_type = VFP_CPRC_VEC128; + return 1; + default: + return -1; + } + } + else + { + int count; + unsigned unitlen; + + count = arm_vfp_cprc_sub_candidate (TYPE_TARGET_TYPE (t), + base_type); + if (count == -1) + return -1; + if (TYPE_LENGTH (t) == 0) + { + gdb_assert (count == 0); + return 0; + } + else if (count == 0) + return -1; + unitlen = arm_vfp_cprc_unit_length (*base_type); + gdb_assert ((TYPE_LENGTH (t) % unitlen) == 0); + return TYPE_LENGTH (t) / unitlen; } - else if (count == 0) - return -1; - unitlen = arm_vfp_cprc_unit_length (*base_type); - gdb_assert ((TYPE_LENGTH (t) % unitlen) == 0); - return TYPE_LENGTH (t) / unitlen; } break; @@ -3619,8 +3588,11 @@ arm_vfp_cprc_sub_candidate (struct type *t, int i; for (i = 0; i < TYPE_NFIELDS (t); i++) { - int sub_count = arm_vfp_cprc_sub_candidate (TYPE_FIELD_TYPE (t, i), - base_type); + int sub_count = 0; + + if (!field_is_static (&TYPE_FIELD (t, i))) + sub_count = arm_vfp_cprc_sub_candidate (TYPE_FIELD_TYPE (t, i), + base_type); if (sub_count == -1) return -1; count += sub_count; @@ -3892,13 +3864,13 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function, while (len > 0) { int partial_len = len < INT_REGISTER_SIZE ? len : INT_REGISTER_SIZE; + CORE_ADDR regval + = extract_unsigned_integer (val, partial_len, byte_order); if (may_use_core_reg && argreg <= ARM_LAST_ARG_REGNUM) { /* The argument is being passed in a general purpose register. */ - CORE_ADDR regval - = extract_unsigned_integer (val, partial_len, byte_order); if (byte_order == BFD_ENDIAN_BIG) regval <<= (INT_REGISTER_SIZE - partial_len) * 8; if (arm_debug) @@ -3912,11 +3884,16 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function, } else { + gdb_byte buf[INT_REGISTER_SIZE]; + + memset (buf, 0, sizeof (buf)); + store_unsigned_integer (buf, partial_len, byte_order, regval); + /* Push the arguments onto the stack. */ if (arm_debug) fprintf_unfiltered (gdb_stdlog, "arg %d @ sp + %d\n", argnum, nstack); - si = push_stack_item (si, val, INT_REGISTER_SIZE); + si = push_stack_item (si, buf, INT_REGISTER_SIZE); nstack += INT_REGISTER_SIZE; } @@ -4103,1199 +4080,120 @@ arm_register_type (struct gdbarch *gdbarch, int regnum) && TYPE_CODE (t) == TYPE_CODE_FLT && gdbarch_tdep (gdbarch)->have_neon) return arm_neon_double_type (gdbarch); - else - return t; - } - - if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS) - { - if (!gdbarch_tdep (gdbarch)->have_fpa_registers) - return builtin_type (gdbarch)->builtin_void; - - return arm_ext_type (gdbarch); - } - else if (regnum == ARM_SP_REGNUM) - return builtin_type (gdbarch)->builtin_data_ptr; - else if (regnum == ARM_PC_REGNUM) - return builtin_type (gdbarch)->builtin_func_ptr; - else if (regnum >= ARRAY_SIZE (arm_register_names)) - /* These registers are only supported on targets which supply - an XML description. */ - return builtin_type (gdbarch)->builtin_int0; - else - return builtin_type (gdbarch)->builtin_uint32; -} - -/* Map a DWARF register REGNUM onto the appropriate GDB register - number. */ - -static int -arm_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg) -{ - /* Core integer regs. */ - if (reg >= 0 && reg <= 15) - return reg; - - /* Legacy FPA encoding. These were once used in a way which - overlapped with VFP register numbering, so their use is - discouraged, but GDB doesn't support the ARM toolchain - which used them for VFP. */ - if (reg >= 16 && reg <= 23) - return ARM_F0_REGNUM + reg - 16; - - /* New assignments for the FPA registers. */ - if (reg >= 96 && reg <= 103) - return ARM_F0_REGNUM + reg - 96; - - /* WMMX register assignments. */ - if (reg >= 104 && reg <= 111) - return ARM_WCGR0_REGNUM + reg - 104; - - if (reg >= 112 && reg <= 127) - return ARM_WR0_REGNUM + reg - 112; - - if (reg >= 192 && reg <= 199) - return ARM_WC0_REGNUM + reg - 192; - - /* VFP v2 registers. A double precision value is actually - in d1 rather than s2, but the ABI only defines numbering - for the single precision registers. This will "just work" - in GDB for little endian targets (we'll read eight bytes, - starting in s0 and then progressing to s1), but will be - reversed on big endian targets with VFP. This won't - be a problem for the new Neon quad registers; you're supposed - to use DW_OP_piece for those. */ - if (reg >= 64 && reg <= 95) - { - char name_buf[4]; - - xsnprintf (name_buf, sizeof (name_buf), "s%d", reg - 64); - return user_reg_map_name_to_regnum (gdbarch, name_buf, - strlen (name_buf)); - } - - /* VFP v3 / Neon registers. This range is also used for VFP v2 - registers, except that it now describes d0 instead of s0. */ - if (reg >= 256 && reg <= 287) - { - char name_buf[4]; - - xsnprintf (name_buf, sizeof (name_buf), "d%d", reg - 256); - return user_reg_map_name_to_regnum (gdbarch, name_buf, - strlen (name_buf)); - } - - return -1; -} - -/* Map GDB internal REGNUM onto the Arm simulator register numbers. */ -static int -arm_register_sim_regno (struct gdbarch *gdbarch, int regnum) -{ - int reg = regnum; - gdb_assert (reg >= 0 && reg < gdbarch_num_regs (gdbarch)); - - if (regnum >= ARM_WR0_REGNUM && regnum <= ARM_WR15_REGNUM) - return regnum - ARM_WR0_REGNUM + SIM_ARM_IWMMXT_COP0R0_REGNUM; - - if (regnum >= ARM_WC0_REGNUM && regnum <= ARM_WC7_REGNUM) - return regnum - ARM_WC0_REGNUM + SIM_ARM_IWMMXT_COP1R0_REGNUM; - - if (regnum >= ARM_WCGR0_REGNUM && regnum <= ARM_WCGR7_REGNUM) - return regnum - ARM_WCGR0_REGNUM + SIM_ARM_IWMMXT_COP1R8_REGNUM; - - if (reg < NUM_GREGS) - return SIM_ARM_R0_REGNUM + reg; - reg -= NUM_GREGS; - - if (reg < NUM_FREGS) - return SIM_ARM_FP0_REGNUM + reg; - reg -= NUM_FREGS; - - if (reg < NUM_SREGS) - return SIM_ARM_FPS_REGNUM + reg; - reg -= NUM_SREGS; - - internal_error (__FILE__, __LINE__, _("Bad REGNUM %d"), regnum); -} - -/* NOTE: cagney/2001-08-20: Both convert_from_extended() and - convert_to_extended() use floatformat_arm_ext_littlebyte_bigword. - It is thought that this is is the floating-point register format on - little-endian systems. */ - -static void -convert_from_extended (const struct floatformat *fmt, const void *ptr, - void *dbl, int endianess) -{ - DOUBLEST d; - - if (endianess == BFD_ENDIAN_BIG) - floatformat_to_doublest (&floatformat_arm_ext_big, ptr, &d); - else - floatformat_to_doublest (&floatformat_arm_ext_littlebyte_bigword, - ptr, &d); - floatformat_from_doublest (fmt, &d, dbl); -} - -static void -convert_to_extended (const struct floatformat *fmt, void *dbl, const void *ptr, - int endianess) -{ - DOUBLEST d; - - floatformat_to_doublest (fmt, ptr, &d); - if (endianess == BFD_ENDIAN_BIG) - floatformat_from_doublest (&floatformat_arm_ext_big, &d, dbl); - else - floatformat_from_doublest (&floatformat_arm_ext_littlebyte_bigword, - &d, dbl); -} - -static int -condition_true (unsigned long cond, unsigned long status_reg) -{ - if (cond == INST_AL || cond == INST_NV) - return 1; - - switch (cond) - { - case INST_EQ: - return ((status_reg & FLAG_Z) != 0); - case INST_NE: - return ((status_reg & FLAG_Z) == 0); - case INST_CS: - return ((status_reg & FLAG_C) != 0); - case INST_CC: - return ((status_reg & FLAG_C) == 0); - case INST_MI: - return ((status_reg & FLAG_N) != 0); - case INST_PL: - return ((status_reg & FLAG_N) == 0); - case INST_VS: - return ((status_reg & FLAG_V) != 0); - case INST_VC: - return ((status_reg & FLAG_V) == 0); - case INST_HI: - return ((status_reg & (FLAG_C | FLAG_Z)) == FLAG_C); - case INST_LS: - return ((status_reg & (FLAG_C | FLAG_Z)) != FLAG_C); - case INST_GE: - return (((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 0)); - case INST_LT: - return (((status_reg & FLAG_N) == 0) != ((status_reg & FLAG_V) == 0)); - case INST_GT: - return (((status_reg & FLAG_Z) == 0) - && (((status_reg & FLAG_N) == 0) - == ((status_reg & FLAG_V) == 0))); - case INST_LE: - return (((status_reg & FLAG_Z) != 0) - || (((status_reg & FLAG_N) == 0) - != ((status_reg & FLAG_V) == 0))); - } - return 1; -} - -static unsigned long -shifted_reg_val (struct frame_info *frame, unsigned long inst, int carry, - unsigned long pc_val, unsigned long status_reg) -{ - unsigned long res, shift; - int rm = bits (inst, 0, 3); - unsigned long shifttype = bits (inst, 5, 6); - - if (bit (inst, 4)) - { - int rs = bits (inst, 8, 11); - shift = (rs == 15 ? pc_val + 8 - : get_frame_register_unsigned (frame, rs)) & 0xFF; - } - else - shift = bits (inst, 7, 11); - - res = (rm == ARM_PC_REGNUM - ? (pc_val + (bit (inst, 4) ? 12 : 8)) - : get_frame_register_unsigned (frame, rm)); - - switch (shifttype) - { - case 0: /* LSL */ - res = shift >= 32 ? 0 : res << shift; - break; - - case 1: /* LSR */ - res = shift >= 32 ? 0 : res >> shift; - break; - - case 2: /* ASR */ - if (shift >= 32) - shift = 31; - res = ((res & 0x80000000L) - ? ~((~res) >> shift) : res >> shift); - break; - - case 3: /* ROR/RRX */ - shift &= 31; - if (shift == 0) - res = (res >> 1) | (carry ? 0x80000000L : 0); - else - res = (res >> shift) | (res << (32 - shift)); - break; - } - - return res & 0xffffffff; -} - -/* Return number of 1-bits in VAL. */ - -static int -bitcount (unsigned long val) -{ - int nbits; - for (nbits = 0; val != 0; nbits++) - val &= val - 1; /* Delete rightmost 1-bit in val. */ - return nbits; -} - -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_raw (struct frame_info *frame, CORE_ADDR pc) -{ - 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); - arm_insert_single_step_breakpoint (gdbarch, aspace, - MAKE_THUMB_ADDR (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. */ - return MAKE_THUMB_ADDR (pc + thumb_insn_size (inst1)); - - /* Otherwise, handle the instruction normally. */ - } - - if ((inst1 & 0xff00) == 0xbd00) /* pop {rlist, pc} */ - { - CORE_ADDR sp; - - /* Fetch the saved PC from the stack. It's stored above - all of the other registers. */ - 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); - } - else if ((inst1 & 0xf000) == 0xd000) /* conditional branch */ - { - unsigned long cond = bits (inst1, 8, 11); - if (cond == 0x0f) /* 0x0f = SWI */ - { - struct gdbarch_tdep *tdep; - tdep = gdbarch_tdep (gdbarch); - - if (tdep->syscall_next_pc != NULL) - nextpc = tdep->syscall_next_pc (frame); - - } - else if (cond != 0x0f && condition_true (cond, status)) - nextpc = pc_val + (sbits (inst1, 0, 7) << 1); - } - else if ((inst1 & 0xf800) == 0xe000) /* unconditional branch */ - { - nextpc = pc_val + (sbits (inst1, 0, 10) << 1); - } - else if (thumb_insn_size (inst1) == 4) /* 32-bit instruction */ - { - unsigned short inst2; - inst2 = read_memory_unsigned_integer (pc + 2, 2, byte_order_for_code); - - /* 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 == ARM_PC_REGNUM) - { - 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 */ - { - if (bits (inst1, 3, 6) == 0x0f) - nextpc = UNMAKE_THUMB_ADDR (pc_val); - else - nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6)); - } - else if ((inst1 & 0xff87) == 0x4687) /* mov pc, REG */ - { - if (bits (inst1, 3, 6) == 0x0f) - nextpc = pc_val; - else - nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6)); - - nextpc = MAKE_THUMB_ADDR (nextpc); - } - 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; -} - -/* Get the raw next address. PC is the current program counter, in - FRAME, which is assumed to be executing in ARM mode. - - 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) -{ - struct gdbarch *gdbarch = get_frame_arch (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 this_instr; - unsigned long status; - CORE_ADDR nextpc; - - pc_val = (unsigned long) pc; - this_instr = read_memory_unsigned_integer (pc, 4, byte_order_for_code); - - status = get_frame_register_unsigned (frame, ARM_PS_REGNUM); - nextpc = (CORE_ADDR) (pc_val + 4); /* Default case */ - - if (bits (this_instr, 28, 31) == INST_NV) - switch (bits (this_instr, 24, 27)) - { - case 0xa: - case 0xb: - { - /* Branch with Link and change to Thumb. */ - nextpc = BranchDest (pc, this_instr); - nextpc |= bit (this_instr, 24) << 1; - nextpc = MAKE_THUMB_ADDR (nextpc); - break; - } - case 0xc: - case 0xd: - case 0xe: - /* Coprocessor register transfer. */ - if (bits (this_instr, 12, 15) == 15) - error (_("Invalid update to pc in instruction")); - break; - } - else if (condition_true (bits (this_instr, 28, 31), status)) - { - switch (bits (this_instr, 24, 27)) - { - case 0x0: - case 0x1: /* data processing */ - case 0x2: - case 0x3: - { - unsigned long operand1, operand2, result = 0; - unsigned long rn; - int c; - - if (bits (this_instr, 12, 15) != 15) - break; - - if (bits (this_instr, 22, 25) == 0 - && bits (this_instr, 4, 7) == 9) /* multiply */ - error (_("Invalid update to pc in instruction")); - - /* BX , BLX */ - if (bits (this_instr, 4, 27) == 0x12fff1 - || bits (this_instr, 4, 27) == 0x12fff3) - { - rn = bits (this_instr, 0, 3); - nextpc = ((rn == ARM_PC_REGNUM) - ? (pc_val + 8) - : get_frame_register_unsigned (frame, rn)); - - return nextpc; - } - - /* Multiply into PC. */ - c = (status & FLAG_C) ? 1 : 0; - rn = bits (this_instr, 16, 19); - operand1 = ((rn == ARM_PC_REGNUM) - ? (pc_val + 8) - : get_frame_register_unsigned (frame, rn)); - - if (bit (this_instr, 25)) - { - unsigned long immval = bits (this_instr, 0, 7); - unsigned long rotate = 2 * bits (this_instr, 8, 11); - operand2 = ((immval >> rotate) | (immval << (32 - rotate))) - & 0xffffffff; - } - else /* operand 2 is a shifted register. */ - operand2 = shifted_reg_val (frame, this_instr, c, - pc_val, status); - - switch (bits (this_instr, 21, 24)) - { - case 0x0: /*and */ - result = operand1 & operand2; - break; - - case 0x1: /*eor */ - result = operand1 ^ operand2; - break; - - case 0x2: /*sub */ - result = operand1 - operand2; - break; - - case 0x3: /*rsb */ - result = operand2 - operand1; - break; - - case 0x4: /*add */ - result = operand1 + operand2; - break; - - case 0x5: /*adc */ - result = operand1 + operand2 + c; - break; - - case 0x6: /*sbc */ - result = operand1 - operand2 + c; - break; - - case 0x7: /*rsc */ - result = operand2 - operand1 + c; - break; - - case 0x8: - case 0x9: - case 0xa: - case 0xb: /* tst, teq, cmp, cmn */ - result = (unsigned long) nextpc; - break; - - case 0xc: /*orr */ - result = operand1 | operand2; - break; - - case 0xd: /*mov */ - /* Always step into a function. */ - result = operand2; - break; - - case 0xe: /*bic */ - result = operand1 & ~operand2; - break; - - case 0xf: /*mvn */ - result = ~operand2; - break; - } - - /* 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; - } - - case 0x4: - case 0x5: /* data transfer */ - case 0x6: - case 0x7: - if (bits (this_instr, 25, 27) == 0x3 && bit (this_instr, 4) == 1) - { - /* Media instructions and architecturally undefined - instructions. */ - break; - } - - if (bit (this_instr, 20)) - { - /* load */ - if (bits (this_instr, 12, 15) == 15) - { - /* rd == pc */ - unsigned long rn; - unsigned long base; - - if (bit (this_instr, 22)) - error (_("Invalid update to pc in instruction")); - - /* byte write to PC */ - rn = bits (this_instr, 16, 19); - base = ((rn == ARM_PC_REGNUM) - ? (pc_val + 8) - : get_frame_register_unsigned (frame, rn)); - - if (bit (this_instr, 24)) - { - /* pre-indexed */ - int c = (status & FLAG_C) ? 1 : 0; - unsigned long offset = - (bit (this_instr, 25) - ? shifted_reg_val (frame, this_instr, c, pc_val, status) - : bits (this_instr, 0, 11)); - - if (bit (this_instr, 23)) - base += offset; - else - base -= offset; - } - nextpc = - (CORE_ADDR) read_memory_unsigned_integer ((CORE_ADDR) base, - 4, byte_order); - } - } - break; - - case 0x8: - case 0x9: /* block transfer */ - if (bit (this_instr, 20)) - { - /* LDM */ - if (bit (this_instr, 15)) - { - /* loading pc */ - int offset = 0; - unsigned long rn_val - = get_frame_register_unsigned (frame, - bits (this_instr, 16, 19)); - - if (bit (this_instr, 23)) - { - /* up */ - unsigned long reglist = bits (this_instr, 0, 14); - offset = bitcount (reglist) * 4; - if (bit (this_instr, 24)) /* pre */ - offset += 4; - } - else if (bit (this_instr, 24)) - offset = -4; - - nextpc = - (CORE_ADDR) read_memory_unsigned_integer ((CORE_ADDR) - (rn_val + offset), - 4, byte_order); - } - } - break; - - case 0xb: /* branch & link */ - case 0xa: /* branch */ - { - nextpc = BranchDest (pc, this_instr); - break; - } - - case 0xc: - case 0xd: - case 0xe: /* coproc ops */ - break; - case 0xf: /* SWI */ - { - struct gdbarch_tdep *tdep; - tdep = gdbarch_tdep (gdbarch); - - if (tdep->syscall_next_pc != NULL) - nextpc = tdep->syscall_next_pc (frame); - - } - break; - - default: - fprintf_filtered (gdb_stderr, _("Bad bit-field extraction\n")); - return (pc); - } - } - - return nextpc; -} - -/* Determine next PC after current instruction executes. Will call either - arm_get_next_pc_raw or thumb_get_next_pc_raw. Error out if infinite - loop is detected. */ - -CORE_ADDR -arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc) -{ - CORE_ADDR nextpc; - - if (arm_frame_is_thumb (frame)) - nextpc = thumb_get_next_pc_raw (frame, pc); - else - nextpc = arm_get_next_pc_raw (frame, pc); - - return nextpc; -} - -/* Like insert_single_step_breakpoint, but make sure we use a breakpoint - of the appropriate mode (as encoded in the PC value), even if this - differs from what would be expected according to the symbol tables. */ - -void -arm_insert_single_step_breakpoint (struct gdbarch *gdbarch, - struct address_space *aspace, - CORE_ADDR pc) -{ - struct cleanup *old_chain - = make_cleanup_restore_integer (&arm_override_mode); - - arm_override_mode = IS_THUMB_ADDR (pc); - pc = gdbarch_addr_bits_remove (gdbarch, pc); - - insert_single_step_breakpoint (gdbarch, aspace, pc); - - do_cleanups (old_chain); -} - -/* Checks for an atomic sequence of instructions beginning with a LDREX{,B,H,D} - instruction and ending with a STREX{,B,H,D} instruction. If such a sequence - is found, attempt to step through it. A breakpoint is placed at the end of - the sequence. */ - -static int -thumb_deal_with_atomic_sequence_raw (struct frame_info *frame) -{ - struct gdbarch *gdbarch = get_frame_arch (frame); - struct address_space *aspace = get_frame_address_space (frame); - enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); - CORE_ADDR pc = get_frame_pc (frame); - CORE_ADDR breaks[2] = {-1, -1}; - CORE_ADDR loc = pc; - unsigned short insn1, insn2; - int insn_count; - int index; - int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed). */ - const int atomic_sequence_length = 16; /* Instruction sequence length. */ - ULONGEST status, itstate; - - /* We currently do not support atomic sequences within an IT block. */ - status = get_frame_register_unsigned (frame, ARM_PS_REGNUM); - itstate = ((status >> 8) & 0xfc) | ((status >> 25) & 0x3); - if (itstate & 0x0f) - return 0; - - /* Assume all atomic sequences start with a ldrex{,b,h,d} instruction. */ - insn1 = read_memory_unsigned_integer (loc, 2, byte_order_for_code); - loc += 2; - if (thumb_insn_size (insn1) != 4) - return 0; - - insn2 = read_memory_unsigned_integer (loc, 2, byte_order_for_code); - loc += 2; - if (!((insn1 & 0xfff0) == 0xe850 - || ((insn1 & 0xfff0) == 0xe8d0 && (insn2 & 0x00c0) == 0x0040))) - return 0; - - /* Assume that no atomic sequence is longer than "atomic_sequence_length" - instructions. */ - for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count) - { - insn1 = read_memory_unsigned_integer (loc, 2, byte_order_for_code); - loc += 2; - - if (thumb_insn_size (insn1) != 4) - { - /* Assume that there is at most one conditional branch in the - atomic sequence. If a conditional branch is found, put a - breakpoint in its destination address. */ - if ((insn1 & 0xf000) == 0xd000 && bits (insn1, 8, 11) != 0x0f) - { - if (last_breakpoint > 0) - return 0; /* More than one conditional branch found, - fallback to the standard code. */ - - breaks[1] = loc + 2 + (sbits (insn1, 0, 7) << 1); - last_breakpoint++; - } - - /* We do not support atomic sequences that use any *other* - instructions but conditional branches to change the PC. - Fall back to standard code to avoid losing control of - execution. */ - else if (thumb_instruction_changes_pc (insn1)) - return 0; - } - else - { - insn2 = read_memory_unsigned_integer (loc, 2, byte_order_for_code); - loc += 2; - - /* Assume that there is at most one conditional branch in the - atomic sequence. If a conditional branch is found, put a - breakpoint in its destination address. */ - if ((insn1 & 0xf800) == 0xf000 - && (insn2 & 0xd000) == 0x8000 - && (insn1 & 0x0380) != 0x0380) - { - int sign, j1, j2, imm1, imm2; - unsigned int offset; - - sign = sbits (insn1, 10, 10); - imm1 = bits (insn1, 0, 5); - imm2 = bits (insn2, 0, 10); - j1 = bit (insn2, 13); - j2 = bit (insn2, 11); - - offset = (sign << 20) + (j2 << 19) + (j1 << 18); - offset += (imm1 << 12) + (imm2 << 1); - - if (last_breakpoint > 0) - return 0; /* More than one conditional branch found, - fallback to the standard code. */ - - breaks[1] = loc + offset; - last_breakpoint++; - } - - /* We do not support atomic sequences that use any *other* - instructions but conditional branches to change the PC. - Fall back to standard code to avoid losing control of - execution. */ - else if (thumb2_instruction_changes_pc (insn1, insn2)) - return 0; - - /* If we find a strex{,b,h,d}, we're done. */ - if ((insn1 & 0xfff0) == 0xe840 - || ((insn1 & 0xfff0) == 0xe8c0 && (insn2 & 0x00c0) == 0x0040)) - break; - } - } - - /* If we didn't find the strex{,b,h,d}, we cannot handle the sequence. */ - if (insn_count == atomic_sequence_length) - return 0; - - /* Insert a breakpoint right after the end of the atomic sequence. */ - breaks[0] = loc; - - /* Check for duplicated breakpoints. Check also for a breakpoint - placed (branch instruction's destination) anywhere in sequence. */ - if (last_breakpoint - && (breaks[1] == breaks[0] - || (breaks[1] >= pc && breaks[1] < loc))) - last_breakpoint = 0; + else + return t; + } - /* Effectively inserts the breakpoints. */ - for (index = 0; index <= last_breakpoint; index++) - arm_insert_single_step_breakpoint (gdbarch, aspace, - MAKE_THUMB_ADDR (breaks[index])); + if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS) + { + if (!gdbarch_tdep (gdbarch)->have_fpa_registers) + return builtin_type (gdbarch)->builtin_void; - return 1; + return arm_ext_type (gdbarch); + } + else if (regnum == ARM_SP_REGNUM) + return builtin_type (gdbarch)->builtin_data_ptr; + else if (regnum == ARM_PC_REGNUM) + return builtin_type (gdbarch)->builtin_func_ptr; + else if (regnum >= ARRAY_SIZE (arm_register_names)) + /* These registers are only supported on targets which supply + an XML description. */ + return builtin_type (gdbarch)->builtin_int0; + else + return builtin_type (gdbarch)->builtin_uint32; } +/* Map a DWARF register REGNUM onto the appropriate GDB register + number. */ + static int -arm_deal_with_atomic_sequence_raw (struct frame_info *frame) +arm_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg) { - struct gdbarch *gdbarch = get_frame_arch (frame); - struct address_space *aspace = get_frame_address_space (frame); - enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); - CORE_ADDR pc = get_frame_pc (frame); - CORE_ADDR breaks[2] = {-1, -1}; - CORE_ADDR loc = pc; - unsigned int insn; - int insn_count; - int index; - int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed). */ - const int atomic_sequence_length = 16; /* Instruction sequence length. */ - - /* Assume all atomic sequences start with a ldrex{,b,h,d} instruction. - Note that we do not currently support conditionally executed atomic - instructions. */ - insn = read_memory_unsigned_integer (loc, 4, byte_order_for_code); - loc += 4; - if ((insn & 0xff9000f0) != 0xe1900090) - return 0; + /* Core integer regs. */ + if (reg >= 0 && reg <= 15) + return reg; - /* Assume that no atomic sequence is longer than "atomic_sequence_length" - instructions. */ - for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count) - { - insn = read_memory_unsigned_integer (loc, 4, byte_order_for_code); - loc += 4; + /* Legacy FPA encoding. These were once used in a way which + overlapped with VFP register numbering, so their use is + discouraged, but GDB doesn't support the ARM toolchain + which used them for VFP. */ + if (reg >= 16 && reg <= 23) + return ARM_F0_REGNUM + reg - 16; - /* Assume that there is at most one conditional branch in the atomic - sequence. If a conditional branch is found, put a breakpoint in - its destination address. */ - if (bits (insn, 24, 27) == 0xa) - { - if (last_breakpoint > 0) - return 0; /* More than one conditional branch found, fallback - to the standard single-step code. */ + /* New assignments for the FPA registers. */ + if (reg >= 96 && reg <= 103) + return ARM_F0_REGNUM + reg - 96; - breaks[1] = BranchDest (loc - 4, insn); - last_breakpoint++; - } + /* WMMX register assignments. */ + if (reg >= 104 && reg <= 111) + return ARM_WCGR0_REGNUM + reg - 104; - /* We do not support atomic sequences that use any *other* instructions - but conditional branches to change the PC. Fall back to standard - code to avoid losing control of execution. */ - else if (arm_instruction_changes_pc (insn)) - return 0; + if (reg >= 112 && reg <= 127) + return ARM_WR0_REGNUM + reg - 112; - /* If we find a strex{,b,h,d}, we're done. */ - if ((insn & 0xff9000f0) == 0xe1800090) - break; - } + if (reg >= 192 && reg <= 199) + return ARM_WC0_REGNUM + reg - 192; - /* If we didn't find the strex{,b,h,d}, we cannot handle the sequence. */ - if (insn_count == atomic_sequence_length) - return 0; + /* VFP v2 registers. A double precision value is actually + in d1 rather than s2, but the ABI only defines numbering + for the single precision registers. This will "just work" + in GDB for little endian targets (we'll read eight bytes, + starting in s0 and then progressing to s1), but will be + reversed on big endian targets with VFP. This won't + be a problem for the new Neon quad registers; you're supposed + to use DW_OP_piece for those. */ + if (reg >= 64 && reg <= 95) + { + char name_buf[4]; - /* Insert a breakpoint right after the end of the atomic sequence. */ - breaks[0] = loc; + xsnprintf (name_buf, sizeof (name_buf), "s%d", reg - 64); + return user_reg_map_name_to_regnum (gdbarch, name_buf, + strlen (name_buf)); + } - /* Check for duplicated breakpoints. Check also for a breakpoint - placed (branch instruction's destination) anywhere in sequence. */ - if (last_breakpoint - && (breaks[1] == breaks[0] - || (breaks[1] >= pc && breaks[1] < loc))) - last_breakpoint = 0; + /* VFP v3 / Neon registers. This range is also used for VFP v2 + registers, except that it now describes d0 instead of s0. */ + if (reg >= 256 && reg <= 287) + { + char name_buf[4]; - /* Effectively inserts the breakpoints. */ - for (index = 0; index <= last_breakpoint; index++) - arm_insert_single_step_breakpoint (gdbarch, aspace, breaks[index]); + xsnprintf (name_buf, sizeof (name_buf), "d%d", reg - 256); + return user_reg_map_name_to_regnum (gdbarch, name_buf, + strlen (name_buf)); + } - return 1; + return -1; } -int -arm_deal_with_atomic_sequence (struct frame_info *frame) +/* Map GDB internal REGNUM onto the Arm simulator register numbers. */ +static int +arm_register_sim_regno (struct gdbarch *gdbarch, int regnum) { - if (arm_frame_is_thumb (frame)) - return thumb_deal_with_atomic_sequence_raw (frame); - else - return arm_deal_with_atomic_sequence_raw (frame); -} + int reg = regnum; + gdb_assert (reg >= 0 && reg < gdbarch_num_regs (gdbarch)); -/* 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 - and breakpoint it. */ + if (regnum >= ARM_WR0_REGNUM && regnum <= ARM_WR15_REGNUM) + return regnum - ARM_WR0_REGNUM + SIM_ARM_IWMMXT_COP0R0_REGNUM; -int -arm_software_single_step (struct frame_info *frame) -{ - struct gdbarch *gdbarch = get_frame_arch (frame); - struct address_space *aspace = get_frame_address_space (frame); - CORE_ADDR next_pc; + if (regnum >= ARM_WC0_REGNUM && regnum <= ARM_WC7_REGNUM) + return regnum - ARM_WC0_REGNUM + SIM_ARM_IWMMXT_COP1R0_REGNUM; - if (arm_deal_with_atomic_sequence (frame)) - return 1; + if (regnum >= ARM_WCGR0_REGNUM && regnum <= ARM_WCGR7_REGNUM) + return regnum - ARM_WCGR0_REGNUM + SIM_ARM_IWMMXT_COP1R8_REGNUM; - next_pc = arm_get_next_pc (frame, get_frame_pc (frame)); - arm_insert_single_step_breakpoint (gdbarch, aspace, next_pc); + if (reg < NUM_GREGS) + return SIM_ARM_R0_REGNUM + reg; + reg -= NUM_GREGS; - return 1; + if (reg < NUM_FREGS) + return SIM_ARM_FP0_REGNUM + reg; + reg -= NUM_FREGS; + + if (reg < NUM_SREGS) + return SIM_ARM_FPS_REGNUM + reg; + reg -= NUM_SREGS; + + internal_error (__FILE__, __LINE__, _("Bad REGNUM %d"), regnum); } /* Given BUF, which is OLD_LEN bytes ending at ENDADDR, expand @@ -5312,7 +4210,7 @@ extend_buffer_earlier (gdb_byte *buf, CORE_ADDR endaddr, new_buf = (gdb_byte *) 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) + if (target_read_code (endaddr - new_len, new_buf, bytes_to_read) != 0) { xfree (new_buf); return NULL; @@ -5370,13 +4268,13 @@ arm_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr) 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); + buf_len = std::min (bpaddr - boundary, (CORE_ADDR) MAX_IT_BLOCK_PREFIX); if (buf_len == 0) /* No room for an IT instruction. */ return bpaddr; buf = (gdb_byte *) xmalloc (buf_len); - if (target_read_memory (bpaddr - buf_len, buf, buf_len) != 0) + if (target_read_code (bpaddr - buf_len, buf, buf_len) != 0) return bpaddr; any = 0; for (i = 0; i < buf_len; i += 2) @@ -5388,6 +4286,7 @@ arm_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr) break; } } + if (any == 0) { xfree (buf); @@ -5490,13 +4389,12 @@ arm_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr) Generally ARM displaced stepping works as follows: 1. When an instruction is to be single-stepped, it is first decoded by - arm_process_displaced_insn (called from arm_displaced_step_copy_insn). - Depending on the type of instruction, it is then copied to a scratch - location, possibly in a modified form. The copy_* set of functions - performs such modification, as necessary. A breakpoint is placed after - the modified instruction in the scratch space to return control to GDB. - Note in particular that instructions which modify the PC will no longer - do so after modification. + arm_process_displaced_insn. Depending on the type of instruction, it is + then copied to a scratch location, possibly in a modified form. The + copy_* set of functions performs such modification, as necessary. A + breakpoint is placed after the modified instruction in the scratch space + to return control to GDB. Note in particular that instructions which + modify the PC will no longer do so after modification. 2. The instruction is single-stepped, by setting the PC to the scratch location address, and resuming. Control returns to GDB when the @@ -5516,7 +4414,7 @@ arm_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr) location. */ ULONGEST -displaced_read_reg (struct regcache *regs, struct displaced_step_closure *dsc, +displaced_read_reg (struct regcache *regs, arm_displaced_step_closure *dsc, int regno) { ULONGEST ret; @@ -5554,7 +4452,7 @@ static int displaced_in_arm_mode (struct regcache *regs) { ULONGEST ps; - ULONGEST t_bit = arm_psr_thumb_bit (get_regcache_arch (regs)); + ULONGEST t_bit = arm_psr_thumb_bit (regs->arch ()); regcache_cooked_read_unsigned (regs, ARM_PS_REGNUM, &ps); @@ -5564,7 +4462,7 @@ displaced_in_arm_mode (struct regcache *regs) /* Write to the PC as from a branch instruction. */ static void -branch_write_pc (struct regcache *regs, struct displaced_step_closure *dsc, +branch_write_pc (struct regcache *regs, arm_displaced_step_closure *dsc, ULONGEST val) { if (!dsc->is_thumb) @@ -5583,7 +4481,7 @@ static void bx_write_pc (struct regcache *regs, ULONGEST val) { ULONGEST ps; - ULONGEST t_bit = arm_psr_thumb_bit (get_regcache_arch (regs)); + ULONGEST t_bit = arm_psr_thumb_bit (regs->arch ()); regcache_cooked_read_unsigned (regs, ARM_PS_REGNUM, &ps); @@ -5610,7 +4508,7 @@ bx_write_pc (struct regcache *regs, ULONGEST val) /* Write to the PC as if from a load instruction. */ static void -load_write_pc (struct regcache *regs, struct displaced_step_closure *dsc, +load_write_pc (struct regcache *regs, arm_displaced_step_closure *dsc, ULONGEST val) { if (DISPLACED_STEPPING_ARCH_VERSION >= 5) @@ -5622,7 +4520,7 @@ load_write_pc (struct regcache *regs, struct displaced_step_closure *dsc, /* Write to the PC as if from an ALU instruction. */ static void -alu_write_pc (struct regcache *regs, struct displaced_step_closure *dsc, +alu_write_pc (struct regcache *regs, arm_displaced_step_closure *dsc, ULONGEST val) { if (DISPLACED_STEPPING_ARCH_VERSION >= 7 && !dsc->is_thumb) @@ -5636,7 +4534,7 @@ alu_write_pc (struct regcache *regs, struct displaced_step_closure *dsc, this is controlled by the WRITE_PC argument. */ void -displaced_write_reg (struct regcache *regs, struct displaced_step_closure *dsc, +displaced_write_reg (struct regcache *regs, arm_displaced_step_closure *dsc, int regno, ULONGEST val, enum pc_write_style write_pc) { if (regno == ARM_PC_REGNUM) @@ -5720,7 +4618,7 @@ insn_references_pc (uint32_t insn, uint32_t bitmask) static int arm_copy_unmodified (struct gdbarch *gdbarch, uint32_t insn, - const char *iname, struct displaced_step_closure *dsc) + const char *iname, arm_displaced_step_closure *dsc) { if (debug_displaced) fprintf_unfiltered (gdb_stdlog, "displaced: copying insn %.8lx, " @@ -5735,7 +4633,7 @@ arm_copy_unmodified (struct gdbarch *gdbarch, uint32_t insn, static int thumb_copy_unmodified_32bit (struct gdbarch *gdbarch, uint16_t insn1, uint16_t insn2, const char *iname, - struct displaced_step_closure *dsc) + arm_displaced_step_closure *dsc) { if (debug_displaced) fprintf_unfiltered (gdb_stdlog, "displaced: copying insn %.4x %.4x, " @@ -5752,9 +4650,9 @@ thumb_copy_unmodified_32bit (struct gdbarch *gdbarch, uint16_t insn1, /* Copy 16-bit Thumb(Thumb and 16-bit Thumb-2) instruction without any modification. */ static int -thumb_copy_unmodified_16bit (struct gdbarch *gdbarch, unsigned int insn, +thumb_copy_unmodified_16bit (struct gdbarch *gdbarch, uint16_t insn, const char *iname, - struct displaced_step_closure *dsc) + arm_displaced_step_closure *dsc) { if (debug_displaced) fprintf_unfiltered (gdb_stdlog, "displaced: copying insn %.4x, " @@ -5770,7 +4668,7 @@ thumb_copy_unmodified_16bit (struct gdbarch *gdbarch, unsigned int insn, static void cleanup_preload (struct gdbarch *gdbarch, - struct regcache *regs, struct displaced_step_closure *dsc) + struct regcache *regs, arm_displaced_step_closure *dsc) { displaced_write_reg (regs, dsc, 0, dsc->tmp[0], CANNOT_WRITE_PC); if (!dsc->u.preload.immed) @@ -5779,7 +4677,7 @@ cleanup_preload (struct gdbarch *gdbarch, static void install_preload (struct gdbarch *gdbarch, struct regcache *regs, - struct displaced_step_closure *dsc, unsigned int rn) + arm_displaced_step_closure *dsc, unsigned int rn) { ULONGEST rn_val; /* Preload instructions: @@ -5798,7 +4696,7 @@ install_preload (struct gdbarch *gdbarch, struct regcache *regs, static int arm_copy_preload (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs, - struct displaced_step_closure *dsc) + arm_displaced_step_closure *dsc) { unsigned int rn = bits (insn, 16, 19); @@ -5818,7 +4716,7 @@ arm_copy_preload (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs, static int thumb2_copy_preload (struct gdbarch *gdbarch, uint16_t insn1, uint16_t insn2, - struct regcache *regs, struct displaced_step_closure *dsc) + struct regcache *regs, arm_displaced_step_closure *dsc) { unsigned int rn = bits (insn1, 0, 3); unsigned int u_bit = bit (insn1, 7); @@ -5868,7 +4766,7 @@ thumb2_copy_preload (struct gdbarch *gdbarch, uint16_t insn1, uint16_t insn2, static void install_preload_reg(struct gdbarch *gdbarch, struct regcache *regs, - struct displaced_step_closure *dsc, unsigned int rn, + arm_displaced_step_closure *dsc, unsigned int rn, unsigned int rm) { ULONGEST rn_val, rm_val; @@ -5893,7 +4791,7 @@ install_preload_reg(struct gdbarch *gdbarch, struct regcache *regs, static int arm_copy_preload_reg (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs, - struct displaced_step_closure *dsc) + arm_displaced_step_closure *dsc) { unsigned int rn = bits (insn, 16, 19); unsigned int rm = bits (insn, 0, 3); @@ -5917,7 +4815,7 @@ arm_copy_preload_reg (struct gdbarch *gdbarch, uint32_t insn, static void cleanup_copro_load_store (struct gdbarch *gdbarch, struct regcache *regs, - struct displaced_step_closure *dsc) + arm_displaced_step_closure *dsc) { ULONGEST rn_val = displaced_read_reg (regs, dsc, 0); @@ -5929,7 +4827,7 @@ cleanup_copro_load_store (struct gdbarch *gdbarch, static void install_copro_load_store (struct gdbarch *gdbarch, struct regcache *regs, - struct displaced_step_closure *dsc, + arm_displaced_step_closure *dsc, int writeback, unsigned int rn) { ULONGEST rn_val; @@ -5957,7 +4855,7 @@ install_copro_load_store (struct gdbarch *gdbarch, struct regcache *regs, static int arm_copy_copro_load_store (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs, - struct displaced_step_closure *dsc) + arm_displaced_step_closure *dsc) { unsigned int rn = bits (insn, 16, 19); @@ -5978,7 +4876,7 @@ arm_copy_copro_load_store (struct gdbarch *gdbarch, uint32_t insn, static int thumb2_copy_copro_load_store (struct gdbarch *gdbarch, uint16_t insn1, uint16_t insn2, struct regcache *regs, - struct displaced_step_closure *dsc) + arm_displaced_step_closure *dsc) { unsigned int rn = bits (insn1, 0, 3); @@ -6006,7 +4904,7 @@ thumb2_copy_copro_load_store (struct gdbarch *gdbarch, uint16_t insn1, static void cleanup_branch (struct gdbarch *gdbarch, struct regcache *regs, - struct displaced_step_closure *dsc) + arm_displaced_step_closure *dsc) { uint32_t status = displaced_read_reg (regs, dsc, ARM_PS_REGNUM); int branch_taken = condition_true (dsc->u.branch.cond, status); @@ -6037,7 +4935,7 @@ cleanup_branch (struct gdbarch *gdbarch, struct regcache *regs, static void install_b_bl_blx (struct gdbarch *gdbarch, struct regcache *regs, - struct displaced_step_closure *dsc, + arm_displaced_step_closure *dsc, unsigned int cond, int exchange, int link, long offset) { /* Implement "BL