Refactor code. Split copy_* routines to mode-dependent part (arm_copy_*) and mode-independent part (copy_*). Define some copy helpers. * arm-tdep.c (THUMB_NOP): New macro. (union instruction_instance): New. (copy_unmodified): Renamed to arm_copy_unmodified. (arm_copy_unmodified): New. (copy_preload, copy_preload_reg, copy_b_bl_blx): Move mode-dependent part and leave mode-independent part. (copy_bx_blx_reg copy_ldr_str_ldrb_strb, copy_alu_reg): Likewise. (copy_block_xfer, copy_copro_load_store): Likewise. (arm_copy_preload, arm_copy_preload_reg, arm_copy_b_bl_blx): Mode-dependent part. (arm_copy_bx_blx_reg, arm_copy_ldr_str_ldrb_strb): Likewise. (arm_copy_alu_reg, arm_copy_block_xfer): Likewise. (copy_undef): Renamed to arm_copy_undef. (arm_copy_undef): New. (copy_unpred): Renamed to arm_copy_unpred. (arm_copy_unpred): New. (arm_copy_alu_shifted_reg): Renamed from copy_alu_shifted_reg. (arm_copy_unmodified_helper, arm_copy_undef_helper): Copy helpers for ARM. (arm_copy_copro_load_store_helper, arm_copy_ldm_with_pc_helper): Likewise. (arm_copy_svc_helper): Likewise. (copy_svc): Delete. (decode_misc_memhint_neon, decode_unconditional): Update callers. (decode_dp_misc, decode_miscellaneous, decode_ld_st_word_ubyte): Likewise. (decode_media, decode_b_bl_ldmstm, decode_ext_reg_ld_st): Likewise. (decode_svc_copro, copy_alu_imm, copy_extra_ld_st): Likewise. (arm_decode_svc_copro): Renamed from decode_svc_copro. Call copy helpers routine. (arm_process_displaced_insn): Update callers to decode_svc_copro. --- gdb/arm-tdep.c | 926 +++++++++++++++++++++++++++++++++----------------------- 1 files changed, 554 insertions(+), 372 deletions(-) diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index d1f5d7b..2d06d8e 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -5105,6 +5105,7 @@ arm_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr) /* NOP instruction (mov r0, r0). */ #define ARM_NOP 0xe1a00000 +#define THUMB_NOP 0x4600 static int displaced_in_arm_mode (struct regcache *regs); @@ -5310,9 +5311,16 @@ insn_references_pc (uint32_t insn, uint32_t bitmask) /* The simplest copy function. Many instructions have the same effect no matter what address they are executed at: in those cases, use this. */ +union instruction_instance +{ + uint32_t _32_bit; + uint16_t _16_bit[2]; +}; + +/* Copy ARM instruction without any modification. */ static int -copy_unmodified (struct gdbarch *gdbarch, uint32_t insn, - const char *iname, struct displaced_step_closure *dsc) +arm_copy_unmodified (uint32_t insn, const char *iname, + struct displaced_step_closure *dsc) { if (debug_displaced) fprintf_unfiltered (gdb_stdlog, "displaced: copying insn %.8lx, " @@ -5336,20 +5344,12 @@ cleanup_preload (struct gdbarch *gdbarch, } static int -copy_preload (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs, +copy_preload (struct gdbarch *gdbarch, unsigned int rn, struct regcache *regs, struct displaced_step_closure *dsc) { - unsigned int rn = bits (insn, 16, 19); ULONGEST rn_val; CORE_ADDR from = dsc->insn_addr; - if (!insn_references_pc (insn, 0x000f0000ul)) - return copy_unmodified (gdbarch, insn, "preload", dsc); - - if (debug_displaced) - fprintf_unfiltered (gdb_stdlog, "displaced: copying preload insn %.8lx\n", - (unsigned long) insn); - /* Preload instructions: {pli/pld} [rn, #+/-imm] @@ -5362,32 +5362,39 @@ copy_preload (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs, dsc->u.preload.immed = 1; - RECORD_ARM_MODE_INSN (0, (insn & 0xfff0ffff)); - dsc->cleanup = &cleanup_preload; return 0; } -/* Preload instructions with register offset. */ - static int -copy_preload_reg (struct gdbarch *gdbarch, uint32_t insn, - struct regcache *regs, - struct displaced_step_closure *dsc) +arm_copy_preload (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs, + struct displaced_step_closure *dsc) { unsigned int rn = bits (insn, 16, 19); - unsigned int rm = bits (insn, 0, 3); - ULONGEST rn_val, rm_val; - CORE_ADDR from = dsc->insn_addr; - if (!insn_references_pc (insn, 0x000f000ful)) - return copy_unmodified (gdbarch, insn, "preload reg", dsc); + if (!insn_references_pc (insn, 0x000f0000ul)) + return arm_copy_unmodified (insn, "preload", dsc); if (debug_displaced) fprintf_unfiltered (gdb_stdlog, "displaced: copying preload insn %.8lx\n", (unsigned long) insn); + RECORD_ARM_MODE_INSN (0, (insn & 0xfff0ffff)); + + return copy_preload (gdbarch, rn, regs, dsc); +} + +/* Preload instructions with register offset. */ + +static int +copy_preload_reg (struct gdbarch *gdbarch, unsigned int rn, unsigned int rm, + struct regcache *regs, + struct displaced_step_closure *dsc) +{ + ULONGEST rn_val, rm_val; + CORE_ADDR from = dsc->insn_addr; + /* Preload register-offset instructions: {pli/pld} [rn, rm {, shift}] @@ -5400,15 +5407,31 @@ copy_preload_reg (struct gdbarch *gdbarch, uint32_t insn, rm_val = displaced_read_reg (regs, from, rm); displaced_write_reg (regs, dsc, 0, rn_val, CANNOT_WRITE_PC); displaced_write_reg (regs, dsc, 1, rm_val, CANNOT_WRITE_PC); - dsc->u.preload.immed = 0; - RECORD_ARM_MODE_INSN (0, ((insn & 0xfff0fff0) | 0x1)); - dsc->cleanup = &cleanup_preload; return 0; } +static int +arm_copy_preload_reg (struct gdbarch *gdbarch, uint32_t insn, + struct regcache *regs, + struct displaced_step_closure *dsc) +{ + unsigned int rn = bits (insn, 16, 19); + unsigned int rm = bits (insn, 0, 3); + + if (!insn_references_pc (insn, 0x000f000ful)) + return arm_copy_unmodified (insn, "preload reg", dsc); + + if (debug_displaced) + fprintf_unfiltered (gdb_stdlog, "displaced: copying preload insn %.8lx\n", + (unsigned long) insn); + + RECORD_ARM_MODE_INSN (0, ((insn & 0xfff0fff0) | 0x1)); + + return copy_preload_reg (gdbarch, rn, rm, regs, dsc); +} /* Copy/cleanup coprocessor load and store instructions. */ @@ -5426,21 +5449,14 @@ cleanup_copro_load_store (struct gdbarch *gdbarch, } static int -copy_copro_load_store (struct gdbarch *gdbarch, uint32_t insn, +copy_copro_load_store (struct gdbarch *gdbarch, unsigned int rn, struct regcache *regs, struct displaced_step_closure *dsc) { - unsigned int rn = bits (insn, 16, 19); + ULONGEST rn_val; CORE_ADDR from = dsc->insn_addr; - if (!insn_references_pc (insn, 0x000f0000ul)) - return copy_unmodified (gdbarch, insn, "copro load/store", dsc); - - if (debug_displaced) - fprintf_unfiltered (gdb_stdlog, "displaced: copying coprocessor " - "load/store insn %.8lx\n", (unsigned long) insn); - /* Coprocessor load/store instructions: {stc/stc2} [, #+/-imm] (and other immediate addressing modes) @@ -5453,11 +5469,6 @@ copy_copro_load_store (struct gdbarch *gdbarch, uint32_t insn, rn_val = displaced_read_reg (regs, from, rn); displaced_write_reg (regs, dsc, 0, rn_val, CANNOT_WRITE_PC); - dsc->u.ldst.writeback = bit (insn, 25); - dsc->u.ldst.rn = rn; - - RECORD_ARM_MODE_INSN (0, (insn & 0xfff0ffff)); - dsc->cleanup = &cleanup_copro_load_store; return 0; @@ -5465,10 +5476,9 @@ copy_copro_load_store (struct gdbarch *gdbarch, uint32_t insn, /* Clean up branch instructions (actually perform the branch, by setting PC). */ - static void cleanup_branch (struct gdbarch *gdbarch, struct regcache *regs, - struct displaced_step_closure *dsc) + struct displaced_step_closure *dsc) { ULONGEST from = dsc->insn_addr; uint32_t status = displaced_read_reg (regs, from, ARM_PS_REGNUM); @@ -5482,29 +5492,25 @@ cleanup_branch (struct gdbarch *gdbarch, struct regcache *regs, if (dsc->u.branch.link) { ULONGEST pc = displaced_read_reg (regs, from, 15); - displaced_write_reg (regs, dsc, 14, pc - 4, CANNOT_WRITE_PC); + + if (displaced_in_arm_mode (regs)) + displaced_write_reg (regs, dsc, 14, pc - 4, CANNOT_WRITE_PC); + else + displaced_write_reg (regs, dsc, 14, (pc - 2) | 1u, + CANNOT_WRITE_PC); } - displaced_write_reg (regs, dsc, 15, dsc->u.branch.dest, write_pc); + displaced_write_reg (regs, dsc, ARM_PC_REGNUM, dsc->u.branch.dest, write_pc); } /* Copy B/BL/BLX instructions with immediate destinations. */ static int -copy_b_bl_blx (struct gdbarch *gdbarch, uint32_t insn, - struct regcache *regs, struct displaced_step_closure *dsc) +copy_b_bl_blx (struct gdbarch *gdbarch, unsigned int cond, int exchange, + int link, long offset, struct regcache *regs, + struct displaced_step_closure *dsc) { - unsigned int cond = bits (insn, 28, 31); - int exchange = (cond == 0xf); - int link = exchange || bit (insn, 24); CORE_ADDR from = dsc->insn_addr; - long offset; - - if (debug_displaced) - fprintf_unfiltered (gdb_stdlog, "displaced: copying %s immediate insn " - "%.8lx\n", (exchange) ? "blx" : (link) ? "bl" : "b", - (unsigned long) insn); - /* Implement "BL