diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4b1f21cc91d..087e2041ba2 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +2021-01-27 Matthew Malcomson + + * aarch64-tdep.c (aarch64_displaced_step_others): Account for + BLR and BR instructions. + * arch/aarch64-insn.h (enum aarch64_opcodes): Add BR opcode. + (enum aarch64_masks): New. + 2021-01-26 Tom Tromey * windows-nat.c (DEBUG_EXEC, DEBUG_EVENTS, DEBUG_MEM) diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index d1e15497a46..3ac0564dd9a 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -3099,14 +3099,21 @@ aarch64_displaced_step_others (const uint32_t insn, struct aarch64_displaced_step_data *dsd = (struct aarch64_displaced_step_data *) data; - aarch64_emit_insn (dsd->insn_buf, insn); + uint32_t masked_insn = (insn & CLEAR_Rn_MASK); + if (masked_insn == BLR) + { + /* Emit a BR to the same register and then update LR to the original + address (similar to aarch64_displaced_step_b). */ + aarch64_emit_insn (dsd->insn_buf, insn & 0xffdfffff); + regcache_cooked_write_unsigned (dsd->regs, AARCH64_LR_REGNUM, + data->insn_addr + 4); + } + else + aarch64_emit_insn (dsd->insn_buf, insn); dsd->insn_count = 1; - if ((insn & 0xfffffc1f) == 0xd65f0000) - { - /* RET */ - dsd->dsc->pc_adjust = 0; - } + if (masked_insn == RET || masked_insn == BR || masked_insn == BLR) + dsd->dsc->pc_adjust = 0; else dsd->dsc->pc_adjust = 4; } diff --git a/gdb/arch/aarch64-insn.h b/gdb/arch/aarch64-insn.h index 1e8c5eac940..6f9ec8572b2 100644 --- a/gdb/arch/aarch64-insn.h +++ b/gdb/arch/aarch64-insn.h @@ -61,7 +61,9 @@ enum aarch64_opcodes CBNZ = 0x21000000 | B, TBZ = 0x36000000 | B, TBNZ = 0x37000000 | B, + /* BR 1101 0110 0001 1111 0000 00rr rrr0 0000 */ /* BLR 1101 0110 0011 1111 0000 00rr rrr0 0000 */ + BR = 0xd61f0000, BLR = 0xd63f0000, /* RET 1101 0110 0101 1111 0000 00rr rrr0 0000 */ RET = 0xd65f0000, @@ -128,6 +130,13 @@ enum aarch64_opcodes NOP = (0 << 5) | HINT, }; +/* List of useful masks. */ +enum aarch64_masks +{ + /* Used for masking out an Rn argument from an opcode. */ + CLEAR_Rn_MASK = 0xfffffc1f, +}; + /* Representation of a general purpose register of the form xN or wN. This type is used by emitting functions that take registers as operands. */ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index ec5db0612e0..f20f041878e 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2021-01-27 Matthew Malcomson + + * gdb.arch/insn-reloc.c: Add tests for BR and BLR. + 2021-01-26 Tom de Vries * gdb.threads/killed-outside.exp: Allow regular output. diff --git a/gdb/testsuite/gdb.arch/insn-reloc.c b/gdb/testsuite/gdb.arch/insn-reloc.c index bfbb3161b3a..62f13a92754 100644 --- a/gdb/testsuite/gdb.arch/insn-reloc.c +++ b/gdb/testsuite/gdb.arch/insn-reloc.c @@ -512,6 +512,84 @@ can_relocate_bl (void) : : : "x30"); /* Test that LR is updated correctly. */ } +/* Make sure we can relocate a BR instruction. + + ... Set x0 to target + set_point12: + BR x0 ; jump to target (tracepoint here). + fail() + return + target: + pass() + end + + */ + +static void +can_relocate_br (void) +{ + int ok = 0; + + asm goto (" adr x0, %l0\n" + "set_point12:\n" + " br x0\n" + : + : + : "x0" + : madejump); + + fail (); + return; +madejump: + pass (); +} + +/* Make sure we can relocate a BLR instruction. + + We use two different functions since the test runner expects one breakpoint + per function and we want to test two different things. + For BLR we want to test that the BLR actually jumps to the relevant + function, *and* that it sets the LR register correctly. + + Hence we create one testcase that jumps to `pass` using BLR, and one + testcase that jumps to `pass` if BLR has set the LR correctly. + + -- can_relocate_blr_jumps + ... Set x0 to pass + set_point13: + BLR x0 ; jump to pass (tracepoint here). + + -- can_relocate_blr_sets_lr + ... Set x0 to foo + set_point14: + BLR x0 ; jumps somewhere else (tracepoint here). + BL pass ; ensures the LR was set correctly by the BLR. + + */ + +static void +can_relocate_blr_jumps (void) +{ + int ok = 0; + + /* Test BLR indeed jumps to the target. */ + asm ("set_point13:\n" + " blr %[address]\n" + : : [address] "r" (&pass) : "x30"); +} + +static void +can_relocate_blr_sets_lr (void) +{ + int ok = 0; + + /* Test BLR sets the LR correctly. */ + asm ("set_point14:\n" + " blr %[address]\n" + " bl pass\n" + : : [address] "r" (&foo) : "x30"); +} + #endif /* Functions testing relocations need to be placed here. GDB will read @@ -536,6 +614,9 @@ static testcase_ftype testcases[] = { can_relocate_ldr, can_relocate_bcond_false, can_relocate_bl, + can_relocate_br, + can_relocate_blr_jumps, + can_relocate_blr_sets_lr, #endif };