This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
Patch 3 is about supporting 16-bit Thumb displaced stepping. In this patch, we decode 16-bit instruction, and process them. We also leave a slot for 32-bit Thumb instructions, and put an error there. Test cases are updated accordingly for some PC-related instructions. -- Yao (éå)
gdb/ 2010-12-25 Yao Qi <yao@codesourcery.com> Displaced stepping support for 16-bit Thumb insns. * gdb/arm-tdep.c (THUMB_NOP): New macro. (displaced_read_reg): Support Thumb mode. (thumb_copy_unmodified_16bit): New. (cleanup_branch): Move some code to ... (cleanup_branch_1): ... here. New. Support Thumb mode. (cleanup_cbz_cbnz): New. (copy_b_bl_blx): Move some code to ... (arm_copy_b_bl_blx): ... here. New. (thumb_copy_b): New. (copy_bx_blx_reg): Move some code to ... (arm_copy_bx_blx_reg): ... here. New. (thumb_copy_bx_blx_reg): New. (decode_unconditional): Update caller. (decode_miscellaneous): Likewise. (decode_b_bl_ldmstm): Likewise. (copy_ldr_str_ldrb_strb): Replace magic number with macro. (thumb_decode_dp): New. (thumb_decode_pc_relative): New. (thumb_copy_16bit_ldr_literal): New. (thumb_copy_cbnz_cbz): New. (thumb_process_displaced_16bit_insn): New. (thumb_process_displaced_32bit_insn): New. gdb/testsuite/ 2010-12-25 Yao Qi <yao@codesourcery.com> * gdb.arch/arm-disp-step.S: Test cbnz/cbz, adr and ldr. * gdb.arch/arm-disp-step.exp: Likewise. diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 93c4e50..4d766c9 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -4326,6 +4326,9 @@ 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); /* Helper for register reads for displaced stepping. In particular, this returns the PC as it would be seen by the instruction at its original @@ -4338,10 +4341,15 @@ displaced_read_reg (struct regcache *regs, CORE_ADDR from, int regno) if (regno == 15) { + if (displaced_in_arm_mode (regs)) + from += 8; + else + from += 6; + if (debug_displaced) fprintf_unfiltered (gdb_stdlog, "displaced: read pc value %.8lx\n", - (unsigned long) from + 8); - return (ULONGEST) from + 8; /* Pipeline offset. */ + (unsigned long) from); + return (ULONGEST) from; /* Pipeline offset. */ } else { @@ -4530,6 +4538,21 @@ copy_unmodified (struct gdbarch *gdbarch, uint32_t insn, return 0; } +static int +thumb_copy_unmodified_16bit (struct gdbarch *gdbarch, unsigned int insn, + const char *iname, + struct displaced_step_closure *dsc) +{ + if (debug_displaced) + fprintf_unfiltered (gdb_stdlog, "displaced: copying insn %.4x, " + "opcode/class '%s' unmodified\n", insn, + iname); + + RECORD_MOD_16BIT_INSN (0, insn); + + return 0; +} + /* Preload instructions with immediate offset. */ static void @@ -4668,16 +4691,11 @@ copy_copro_load_store (struct gdbarch *gdbarch, uint32_t insn, return 0; } -/* 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) +cleanup_branch_1 (struct gdbarch *gdbarch, struct regcache *regs, + struct displaced_step_closure *dsc, unsigned int branch_taken) { ULONGEST from = dsc->insn_addr; - uint32_t status = displaced_read_reg (regs, from, ARM_PS_REGNUM); - int branch_taken = condition_true (dsc->u.branch.cond, status); enum pc_write_style write_pc = dsc->u.branch.exchange ? BX_WRITE_PC : BRANCH_WRITE_PC; @@ -4687,29 +4705,45 @@ cleanup_branch (struct gdbarch *gdbarch, struct regcache *regs, if (dsc->u.branch.link) { ULONGEST pc = displaced_read_reg (regs, from, ARM_PC_REGNUM); - displaced_write_reg (regs, dsc, ARM_LR_REGNUM, pc - 4, CANNOT_WRITE_PC); + + if (displaced_in_arm_mode (regs)) + displaced_write_reg (regs, dsc, ARM_LR_REGNUM, pc - 4, CANNOT_WRITE_PC); + else + displaced_write_reg (regs, dsc, ARM_LR_REGNUM, (pc - 2) | 1u, + CANNOT_WRITE_PC); } displaced_write_reg (regs, dsc, ARM_PC_REGNUM, dsc->u.branch.dest, write_pc); } +/* 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) +{ + ULONGEST from = dsc->insn_addr; + uint32_t status = displaced_read_reg (regs, from, ARM_PS_REGNUM); + int branch_taken = condition_true (dsc->u.branch.cond, status); + + cleanup_branch_1 (gdbarch, regs, dsc, branch_taken); +} + +static void +cleanup_cbz_cbnz(struct gdbarch *gdbarch, struct regcache *regs, + struct displaced_step_closure *dsc) +{ + cleanup_branch_1 (gdbarch, regs, dsc, dsc->u.branch.cond); +} + /* 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<cond> <label>" as: Preparation: cond <- instruction condition @@ -4718,6 +4752,40 @@ copy_b_bl_blx (struct gdbarch *gdbarch, uint32_t insn, B<cond> similar, but don't set r14 in cleanup. */ + + dsc->u.branch.cond = cond; + dsc->u.branch.link = link; + dsc->u.branch.exchange = exchange; + + if (arm_pc_is_thumb (gdbarch, from)) + { + /* Plus the size of THUMB_NOP and B/BL/BLX. */ + dsc->u.branch.dest = from + 2 + 4 + offset; + RECORD_MOD_16BIT_INSN (0, THUMB_NOP); + } + else + { + dsc->u.branch.dest = from + 8 + offset; + RECORD_MOD_32BIT_INSN (0, ARM_NOP); + } + + dsc->cleanup = &cleanup_branch; + + return 0; +} +static int +arm_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); + int exchange = (cond == 0xf); + int link = exchange || bit (insn, 24); + long offset; + + if (debug_displaced) + fprintf_unfiltered (gdb_stdlog, "displaced: copying %s immediate insn " + "%.8lx\n", (exchange) ? "blx" : (link) ? "bl" : "b", + (unsigned long) insn); if (exchange) /* For BLX, set bit 0 of the destination. The cleanup_branch function will then arrange the switch into Thumb mode. */ @@ -4728,12 +4796,40 @@ copy_b_bl_blx (struct gdbarch *gdbarch, uint32_t insn, if (bit (offset, 25)) offset = offset | ~0x3ffffff; + return copy_b_bl_blx (gdbarch, cond, exchange, link, offset, regs, dsc); +} + +static int +thumb_copy_b (struct gdbarch *gdbarch, unsigned short insn, + struct displaced_step_closure *dsc) +{ + unsigned int cond = 0; + int offset = 0; + unsigned short bit_12_15 = bits (insn, 12, 15); + CORE_ADDR from = dsc->insn_addr; + + if (bit_12_15 == 0xd) + { + offset = sbits (insn, 0, 7); + cond = bits (insn, 8, 11); + } + else if (bit_12_15 == 0xe) + { + offset = sbits (insn, 0, 10); + cond = INST_AL; + } + + if (debug_displaced) + fprintf_unfiltered (gdb_stdlog, + "displaced: copying b immediate insn %.4x " + "with offset %d\n", insn, offset); + dsc->u.branch.cond = cond; - dsc->u.branch.link = link; - dsc->u.branch.exchange = exchange; - dsc->u.branch.dest = from + 8 + offset; + dsc->u.branch.link = 0; + dsc->u.branch.exchange = 0; + dsc->u.branch.dest = from + 4 + offset; - RECORD_MOD_32BIT_INSN (0, ARM_NOP); + RECORD_MOD_16BIT_INSN (0, THUMB_NOP); dsc->cleanup = &cleanup_branch; @@ -4743,19 +4839,12 @@ copy_b_bl_blx (struct gdbarch *gdbarch, uint32_t insn, /* Copy BX/BLX with register-specified destinations. */ static int -copy_bx_blx_reg (struct gdbarch *gdbarch, uint32_t insn, - struct regcache *regs, struct displaced_step_closure *dsc) +copy_bx_blx_reg (struct gdbarch *gdbarch, unsigned int cond, int link, + unsigned int rm, struct regcache *regs, + struct displaced_step_closure *dsc) { - unsigned int cond = bits (insn, 28, 31); - /* BX: x12xxx1x - BLX: x12xxx3x. */ - int link = bit (insn, 5); - unsigned int rm = bits (insn, 0, 3); CORE_ADDR from = dsc->insn_addr; - - if (debug_displaced) - fprintf_unfiltered (gdb_stdlog, "displaced: copying %s register insn " - "%.8lx\n", (link) ? "blx" : "bx", (unsigned long) insn); + int is_thumb = arm_pc_is_thumb (gdbarch, from); /* Implement {BX,BLX}<cond> <reg>" as: @@ -4767,16 +4856,56 @@ copy_bx_blx_reg (struct gdbarch *gdbarch, uint32_t insn, dsc->u.branch.dest = displaced_read_reg (regs, from, rm); - dsc->u.branch.cond = cond; dsc->u.branch.link = link; dsc->u.branch.exchange = 1; - RECORD_MOD_32BIT_INSN (0, ARM_NOP); + if (is_thumb) + { + /* Always true for thumb. */ + dsc->u.branch.cond = INST_AL; + RECORD_MOD_16BIT_INSN (0, THUMB_NOP); + } + else + { + dsc->u.branch.cond = cond; + RECORD_MOD_32BIT_INSN (0, ARM_NOP); + } dsc->cleanup = &cleanup_branch; return 0; } +static int +arm_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); + /* BX: x12xxx1x + BLX: x12xxx3x. */ + int link = bit (insn, 5); + unsigned int rm = bits (insn, 0, 3); + + if (debug_displaced) + fprintf_unfiltered (gdb_stdlog, "displaced: copying %s register insn " + "%.8lx\n", (link) ? "blx" : "bx", (unsigned long) insn); + + return copy_bx_blx_reg (gdbarch, cond, link, rm, regs, dsc); +} + +static int +thumb_copy_bx_blx_reg (struct gdbarch *gdbarch, uint16_t insn, + struct regcache *regs, + struct displaced_step_closure *dsc) +{ + int link = bit (insn, 7); + unsigned int rm = bits (insn, 3, 6); + + if (debug_displaced) + fprintf_unfiltered (gdb_stdlog, "displaced: copying %s register insn " + "%.4x\n", (link) ? "blx" : "bx", (unsigned short) insn); + + return copy_bx_blx_reg (gdbarch, INST_AL, link, rm, regs, dsc); +} /* Copy/cleanup arithmetic/logic instruction with immediate RHS. */ @@ -5171,7 +5300,7 @@ copy_ldr_str_ldrb_strb (struct gdbarch *gdbarch, uint32_t insn, Otherwise we don't know what value to write for PC, since the offset is architecture-dependent (sometimes PC+8, sometimes PC+12). */ - if (load || rt != 15) + if (load || rt != ARM_PC_REGNUM) { dsc->u.ldst.restore_r4 = 0; @@ -5694,7 +5823,7 @@ decode_unconditional (struct gdbarch *gdbarch, uint32_t insn, return copy_unmodified (gdbarch, insn, "rfe", dsc); case 0x4: case 0x5: case 0x6: case 0x7: - return copy_b_bl_blx (gdbarch, insn, regs, dsc); + return arm_copy_b_bl_blx (gdbarch, insn, regs, dsc); case 0x8: switch ((insn & 0xe00000) >> 21) @@ -5777,7 +5906,7 @@ decode_miscellaneous (struct gdbarch *gdbarch, uint32_t insn, case 0x1: if (op == 0x1) /* bx. */ - return copy_bx_blx_reg (gdbarch, insn, regs, dsc); + return arm_copy_bx_blx_reg (gdbarch, insn, regs, dsc); else if (op == 0x3) return copy_unmodified (gdbarch, insn, "clz", dsc); else @@ -5791,8 +5920,8 @@ decode_miscellaneous (struct gdbarch *gdbarch, uint32_t insn, return copy_undef (gdbarch, insn, dsc); case 0x3: - if (op == 0x1) - return copy_bx_blx_reg (gdbarch, insn, regs, dsc); /* blx register. */ + if (op == 0x1) /* blx register. */ + return arm_copy_bx_blx_reg (gdbarch, insn, regs, dsc); else return copy_undef (gdbarch, insn, dsc); @@ -5955,7 +6084,7 @@ decode_b_bl_ldmstm (struct gdbarch *gdbarch, int32_t insn, struct regcache *regs, struct displaced_step_closure *dsc) { if (bit (insn, 25)) - return copy_b_bl_blx (gdbarch, insn, regs, dsc); + return arm_copy_b_bl_blx (gdbarch, insn, regs, dsc); else return copy_block_xfer (gdbarch, insn, regs, dsc); } @@ -6036,12 +6165,231 @@ decode_svc_copro (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to, return copy_undef (gdbarch, insn, dsc); /* Possibly unreachable. */ } +static int +thumb_decode_dp (struct gdbarch *gdbarch, unsigned short insn, + struct displaced_step_closure *dsc) +{ + /* 16-bit data-processing insns are not related to PC. */ + return thumb_copy_unmodified_16bit (gdbarch, insn,"data-processing", dsc); +} + +static int +thumb_decode_pc_relative (struct gdbarch *gdbarch, unsigned short insn, + struct regcache *regs, + struct displaced_step_closure *dsc) +{ + unsigned int rd = bits (insn, 8, 10); + unsigned int imm8 = bits (insn, 0, 7); + CORE_ADDR from = dsc->insn_addr; + int val; + + /* ADR Rd, #imm8 + + Rewrite as: + + Preparation: Rd <- PC + Insn: ADD Rd, #imm8 + Cleanup: Null. + */ + + + if (debug_displaced) + fprintf_unfiltered (gdb_stdlog, + "displaced: copying thumb adr r%d, #%d insn %.4x\n", + rd, imm8, insn); + + /* Rd <- PC */ + val = displaced_read_reg (regs, from, ARM_PC_REGNUM); + displaced_write_reg (regs, dsc, rd, val, CANNOT_WRITE_PC); + + /* ADDS Rd, #imm8 */ + RECORD_MOD_32BIT_INSN (0, 0x3000 | (rd << 8) | imm8); + + return 0; +} + +static int +thumb_copy_16bit_ldr_literal (struct gdbarch *gdbarch, unsigned short insn1, + struct regcache *regs, + struct displaced_step_closure *dsc) +{ + unsigned int rt = bits (insn1, 8, 7); + unsigned int pc; + int imm8 = sbits (insn1, 0, 7); + CORE_ADDR from = dsc->insn_addr; + + /* LDR Rd, #imm8 + + Rwrite as: + + Preparation: tmp2 <- R2, tmp3 <- R3, R2 <- PC, R3 <- #imm8; + if (Rd is not R0) tmp0 <- R0; + Insn: LDR R0, [R2, R3]; + Cleanup: R2 <- tmp2, R3 <- tmp3, + if (Rd is not R0) Rd <- R0, R0 <- tmp0 */ + + if (debug_displaced) + fprintf_unfiltered (gdb_stdlog, "displaced: copying thumb ldr literal " + "insn %.4x\n", insn1); + + dsc->tmp[0] = displaced_read_reg (regs, from, 0); + dsc->tmp[2] = displaced_read_reg (regs, from, 2); + dsc->tmp[3] = displaced_read_reg (regs, from, 3); + pc = displaced_read_reg (regs, from, ARM_PC_REGNUM); + + displaced_write_reg (regs, dsc, 2, pc, CANNOT_WRITE_PC); + displaced_write_reg (regs, dsc, 3, imm8, CANNOT_WRITE_PC); + + dsc->rd = rt; + dsc->u.ldst.xfersize = 4; + dsc->u.ldst.rn = 0; + dsc->u.ldst.immed = 0; + dsc->u.ldst.writeback = 0; + dsc->u.ldst.restore_r4 = 0; + + RECORD_MOD_16BIT_INSN (0, 0x58d0); /* ldr r0, [r2, r3]*/ + + dsc->cleanup = &cleanup_load; + + return 0; +} + +static int +thumb_copy_cbnz_cbz (struct gdbarch *gdbarch, unsigned short insn1, + struct regcache *regs, + struct displaced_step_closure *dsc) +{ + int non_zero = bit (insn1, 11); + unsigned int imm5 = (bit (insn1, 9) << 6) | (bits (insn1, 3, 7) << 1); + CORE_ADDR from = dsc->insn_addr; + int rn = bits (insn1, 0, 2); + int rn_val = displaced_read_reg (regs, from, rn); + + dsc->u.branch.cond = (rn_val && non_zero) || (!rn_val && !non_zero); + dsc->u.branch.link = 0; + dsc->u.branch.exchange = 0; + + dsc->u.branch.dest = from + 4 + imm5; + + if (debug_displaced) + fprintf_unfiltered (gdb_stdlog, "displaced: copying %s [r%d = 0x%x]" + " insn %.4x to %.8lx\n", non_zero ? "cbnz" : "cbz", + rn, rn_val, insn1, dsc->u.branch.dest); + + RECORD_MOD_16BIT_INSN (0, THUMB_NOP); + + dsc->cleanup = &cleanup_cbz_cbnz; + return 0; +} + +static void +thumb_process_displaced_16bit_insn (struct gdbarch *gdbarch, + unsigned short insn1, CORE_ADDR to, + struct regcache *regs, + struct displaced_step_closure *dsc) +{ + unsigned short op_bit_12_15 = bits (insn1, 12, 15); + unsigned short op_bit_10_11 = bits (insn1, 10, 11); + int err = 0; + + /* 16-bit thumb instructions. */ + switch (op_bit_12_15) + { + /* Shift (imme), add, subtract, move and compare*/ + case 0: case 1: case 2: case 3: + err = thumb_copy_unmodified_16bit (gdbarch, insn1,"", dsc); + break; + case 4: + switch (op_bit_10_11) + { + case 0: /* Data-processing */ + err = thumb_decode_dp (gdbarch, insn1, dsc); + break; + case 1: /* Special data instructions and branch and exchange */ + { + unsigned short op = bits (insn1, 7, 9); + if (op == 6 || op == 7) /* BX or BLX */ + err = thumb_copy_bx_blx_reg (gdbarch, insn1, regs, dsc); + else + err = thumb_copy_unmodified_16bit (gdbarch, insn1, "special data", + dsc); + } + break; + default: /* LDR (literal) */ + err = thumb_copy_16bit_ldr_literal (gdbarch, insn1, regs, dsc); + } + break; + case 5: case 6: case 7: case 8: case 9: /* Load/Store single data item */ + err = thumb_copy_unmodified_16bit (gdbarch, insn1,"ldr/str", dsc); + break; + case 10: + if (op_bit_10_11 < 2) /* Generate PC-relative address */ + err = thumb_decode_pc_relative (gdbarch, insn1, regs, dsc); + else /* Generate SP-relative address */ + err = thumb_copy_unmodified_16bit (gdbarch, insn1,"sp-relative", dsc); + break; + case 11: /* Misc 16-bit instructions */ + { + switch (bits (insn1, 8, 11)) + { + case 1: case 3: case 9: case 11: /* CBNZ, CBZ */ + err = thumb_copy_cbnz_cbz (gdbarch, insn1, regs, dsc); + break; + default: + err = thumb_copy_unmodified_16bit (gdbarch, insn1,"", dsc); + } + } + break; + case 12: + if (op_bit_10_11 < 2) /* Store multiple registers */ + err = thumb_copy_unmodified_16bit (gdbarch, insn1,"stm", dsc); + else /* Load multiple registers */ + err = thumb_copy_unmodified_16bit (gdbarch, insn1,"ldm", dsc); + break; + case 13: /* Conditional branch and supervisor call */ + if (bits (insn1, 9, 11) != 7) /* conditional branch */ + err = thumb_copy_b (gdbarch, insn1, dsc); + else + err = thumb_copy_unmodified_16bit (gdbarch, insn1,"svc", dsc); + break; + case 14: /* Unconditional branch */ + err = thumb_copy_b (gdbarch, insn1, dsc); + break; + default: + internal_error (__FILE__, __LINE__, + _("thumb_process_displaced_insn: Instruction decode error")); + } + + if (err) + internal_error (__FILE__, __LINE__, + _("thumb_process_displaced_insn: Instruction decode error")); +} + +static void +thumb_process_displaced_32bit_insn (struct gdbarch *gdbarch, CORE_ADDR from, + CORE_ADDR to, struct regcache *regs, + struct displaced_step_closure *dsc) +{ + error (_("Displaced stepping is only supported in ARM mode and Thumb 16bit instructions")); +} + static void thumb_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from, CORE_ADDR to, struct regcache *regs, struct displaced_step_closure *dsc) { - error (_("Displaced stepping is only supported in ARM mode")); + enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); + unsigned short insn1 + = read_memory_unsigned_integer (from, 2, byte_order_for_code); + + if (debug_displaced) + fprintf_unfiltered (gdb_stdlog, "displaced: process thumb insn %.4x " + "at %.8lx\n", insn1, (unsigned long) from); + + if ((bits (insn1, 13, 15) == 7) && (bits (insn1, 11, 12))) + thumb_process_displaced_32bit_insn(gdbarch, from, to, regs, dsc); + else + thumb_process_displaced_16bit_insn(gdbarch, insn1, to, regs, dsc); } void diff --git a/gdb/testsuite/gdb.arch/arm-disp-step.S b/gdb/testsuite/gdb.arch/arm-disp-step.S index d748718..2e5b7ba 100644 --- a/gdb/testsuite/gdb.arch/arm-disp-step.S +++ b/gdb/testsuite/gdb.arch/arm-disp-step.S @@ -48,6 +48,26 @@ test_ret_end: bl test_ldm_stm_pc #endif + /* Test ldrX literal in ARM and Thumb-2 */ +#if !defined (__thumb__) + bl test_ldr_literal +#endif + + /* Test ldr literal in Thumb */ +#if defined(__thumb__) + bl test_ldr_literal_16 +#endif + + /* Test cbnz/cbz in Thumb-2 */ +#if defined(__thumb2__) + bl test_cbz_cbnz +#endif + + /* Test adr in Thumb and Thumb-2 */ +#if defined(__thumb) || defined(__thumb2__) + bl test_adr +#endif + /* Return */ mov sp, r7 sub sp, sp, #4 @@ -118,3 +138,75 @@ test_ldm_stm_pc_ret: .word test_ldm_stm_pc_ret .size test_ldm_stm_pc, .-test_ldm_stm_pc #endif + +#if !defined (__thumb__) + .global test_ldr_literal + .type test_ldr_literal, %function +test_ldr_literal: + ldrh r0, [pc] + .global test_ldrsb_literal +test_ldrsb_literal: + ldrsb r0, [pc] + .global test_ldrsh_literal +test_ldrsh_literal: + ldrsh r0, [pc] + .global test_ldr_literal_end +test_ldr_literal_end: + bx lr + .size test_ldr_literal, .-test_ldr_literal +#endif + +#if defined(__thumb__) + .global test_ldr_literal_16 + .code 16 + .thumb_func +test_ldr_literal_16: + ldr r0, .L2 + .global test_ldr_literal_16_end +test_ldr_literal_16_end: + bx lr + .align 2 +.L2: + .word test_ldr_literal_16 + .size test_ldr_literal_16, .-test_ldr_literal_16 +#endif + +#if defined(__thumb2__) + .global test_cbz_cbnz + .code 16 + .thumb_func +test_cbz_cbnz: + movs r0, #0 + .global test_zero_cbnz +test_zero_cbnz: + cbnz r0, .L3 + .global test_zero_cbz +test_zero_cbz: + cbz r0, .L3 +.L3: + movs r0, #1 + .global test_non_zero_cbz +test_non_zero_cbz: + cbz r0, .L4 + .global test_non_zero_cbnz +test_non_zero_cbnz: + cbnz r0, .L4 + nop +.L4: + .global test_cbz_cbnz_end +test_cbz_cbnz_end: + bx lr + .size test_cbz_cbnz, .-test_cbz_cbnz +#endif + +#if defined(__thumb) || defined(__thumb2__) + .global test_adr + .code 16 + .thumb_func +test_adr: + adr r0, #1 + .global test_adr_end +test_adr_end: + bx lr + .size test_adr, .-test_adr +#endif \ No newline at end of file diff --git a/gdb/testsuite/gdb.arch/arm-disp-step.exp b/gdb/testsuite/gdb.arch/arm-disp-step.exp index 826f728..51b7951 100644 --- a/gdb/testsuite/gdb.arch/arm-disp-step.exp +++ b/gdb/testsuite/gdb.arch/arm-disp-step.exp @@ -37,6 +37,22 @@ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list return -1 } +# Try to resume program with displaced stepping. If displaced stepping is +# not supported, turn it off, and continue. + +proc try_continue_with_displaced_step { msg loc } { + gdb_test_no_output "set displaced-stepping on" + gdb_test_multiple "continue" "continue to test_call_end" { + -re ".*$loc.*" { + pass "continue to $msg" + } + -re "Displaced stepping is only supported in.*" { + gdb_test_no_output "set displaced-stepping off" + gdb_test "continue" ".*" + kfail "gdb/NNNN" $msg + } + } +} ######################################### # Test ldm/stm related to PC. @@ -50,7 +66,11 @@ proc test_ldm_stm_pc {} { } -re "Function \"test_ldm_stm_pc\" not defined\..*Make breakpoint pending on future shared library load.*y or .n.. $" { gdb_test "n" "" "Test case is compiled in Thumb mode" - return + return 0 + } + -re "No symbol.*" { + pass "break test_ldm_stm_pc" + return 0 } } @@ -68,10 +88,75 @@ proc test_ldm_stm_pc {} { gdb_continue_to_breakpoint "continue to test_ldm_stm_pc_ret" \ ".*bx lr.*" } + +######################################### +# Test ldrX literal +proc test_ldr_literal {} { + global srcfile + # Try to set breakpoint on test_ldm_stm_pc. If symbol 'test_ldm_stm_pc' + # can't be resolved, test case is compiled in Thumb mode, skip it. + gdb_test_multiple "break *test_ldr_literal" "break test_ldr_literal" { + -re "Breakpoint.*at.* file .*$srcfile, line.*" { + pass "break test_ldr_literal" + } + -re "Function \"test_ldr_literal\" not defined\..*Make breakpoint pending on future shared library load.*y or .n.. $" { + gdb_test "n" "" "Test case is compiled in Thumb mode" + return 0 + } + -re "No symbol.*" { + return 0 + } + } + + gdb_test "break *test_ldrsb_literal" \ + "Breakpoint.*at.* file .*$srcfile, line.*" \ + "break test_ldrsb_literal" + gdb_test "break *test_ldrsh_literal" \ + "Breakpoint.*at.* file .*$srcfile, line.*" \ + "break test_ldrsh_literal" + gdb_test "break *test_ldr_literal_end" \ + "Breakpoint.*at.* file .*$srcfile, line.*" \ + "break test_test_ldr_literal_end" + + gdb_continue_to_breakpoint "continue to test_ldr_literal" \ + ".*ldrh.*r0\,.*\[pc\].*" + gdb_continue_to_breakpoint "continue to test_ldrsb_literal" \ + ".*ldrsb.*r0\,.*\[pc\].*" + gdb_continue_to_breakpoint "continue to test_ldrsh_literal" \ + ".*ldrsh.*r0\,.*\[pc\].*" + gdb_continue_to_breakpoint "continue to test_ldr_literal_ret" \ + ".*bx lr.*" + + gdb_test_multiple "break test_ldr_literal_16" "break test_ldr_literal_16" { + -re "Breakpoint.*at.* file .*$srcfile, line.*" { + pass "break test_ldr_literal" + } + -re "Function \"test_ldr_literal_16\" not defined\..*Make breakpoint pending on future shared library load.*y or .n.. $" { + gdb_test "n" "" "skip" + return 0 + } + } + + gdb_test "break *test_ldr_literal_16_end" \ + "Breakpoint.*at.* file .*$srcfile, line.*" \ + "break test_test_ldr_literal_16_end" + + gdb_continue_to_breakpoint "continue to test_ldr_literal" \ + ".*ldr.*r0\,.*L2.*" + gdb_continue_to_breakpoint "continue to test_ldrsb_literal" \ + ".*bx lr.*" +} + ########################################## # Test call/ret. proc test_call_ret {} { global srcfile + global testfile + + gdb_test "break *test_call" \ + "Breakpoint.*at.* file .*$srcfile, line.*" \ + "break test_call" + gdb_test "break *test_call_end" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_call_end" @@ -82,8 +167,10 @@ proc test_call_ret {} { "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_ret_end" - gdb_continue_to_breakpoint "continue to test_call_end" \ - ".*@ Location test_call_end.*" + try_continue_with_displaced_step "test_call" "bl test_call_subr" + try_continue_with_displaced_step "test_call_end" \ + "@ Location test_call_end" + gdb_continue_to_breakpoint "continue to test_ret" \ ".*bx lr.*" gdb_continue_to_breakpoint "continue to test_ret_end" \ @@ -122,7 +209,66 @@ proc test_ldr_from_pc {} { gdb_continue_to_breakpoint "continue to test_ldr_pc" \ ".*ldr.*r1\,.*\[pc, #0\].*" - gdb_continue_to_breakpoint "continue to Lbranch" \ + gdb_continue_to_breakpoint "continue to test_ldr_pc_ret" \ + ".*bx lr.*" +} + +######################################### + +# Test cbz and cbnz +proc test_cbz_cbnz {} { + global srcfile + + gdb_test_multiple "break *test_zero_cbnz" "break test_zero_cbnz" { + -re "Breakpoint.*at.* file .*$srcfile, line.*" { + pass "break test_ldr_literal" + } + -re "No symbol.*" { + return 0 + } + } + + gdb_test "break *test_zero_cbz" \ + "Breakpoint.*at.* file .*$srcfile, line.*" \ + "break test_zero_cbz" + gdb_test "break *test_non_zero_cbnz" \ + "Breakpoint.*at.* file .*$srcfile, line.*" \ + "break test_non_zero_cbnz" + gdb_test "break *test_non_zero_cbz" \ + "Breakpoint.*at.* file .*$srcfile, line.*" \ + "break test_non_zero_cbz" + + gdb_continue_to_breakpoint "continue to test_zero_cbnz" \ + ".*cbnz.*r0\,.*\.L3.*" + gdb_continue_to_breakpoint "continue to test_zero_cbz" \ + ".*cbz.*r0\,.*\.L3.*" + gdb_continue_to_breakpoint "continue to test_non_zero_cbz" \ + ".*cbz.*r0\,.*\.L4.*" + gdb_continue_to_breakpoint "continue to test_non_zero_cbnz" \ + ".*cbnz.*r0\,.*\.L4.*" +} + +# Test adr + +proc test_adr {} { + global srcfile + + gdb_test_multiple "break *test_adr" "break test_adr" { + -re "Breakpoint.*at.* file .*$srcfile, line.*" { + pass "break test_adr" + } + -re "No symbol.*" { + return 0 + } + } + + gdb_test "break *test_adr_end" \ + "Breakpoint.*at.* file .*$srcfile, line.*" \ + "break test_adr_end" + + gdb_continue_to_breakpoint "continue to test_adr" \ + ".*adr.*r0\,.*#1.*" + gdb_continue_to_breakpoint "continue to test_adr_end" \ ".*bx lr.*" } @@ -143,20 +289,6 @@ if ![runto_main] then { gdb_test_no_output "set displaced-stepping on" gdb_test "show displaced-stepping" ".* displaced stepping .* is on.*" -gdb_test "break *test_call" \ - "Breakpoint.*at.* file .*$srcfile, line.*" \ - "break test_call" - -gdb_test_multiple "continue" "continue to test_call" { - -re ".*bl test_call_subr.*" { - pass "continue to test_call" - } - -re "Displaced stepping is only supported in" { - kfail "gdb/NNNN" $testfile - return - } - } - test_call_ret test_branch @@ -165,6 +297,11 @@ test_ldr_from_pc test_ldm_stm_pc +test_ldr_literal + +test_cbz_cbnz + +test_adr ########################################## # Done, run program to exit.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |