diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 5e7d0d0b8682af04ce4f01fd999d26c9eb459932..640a3e302f8e2b5fac3575e2f37212d40441d318 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -2974,15 +2974,22 @@ 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); - dsd->insn_count = 1; - - if ((insn & 0xfffffc1f) == 0xd65f0000) + uint32_t masked_insn = (insn & 0xfffffc1f); + if (masked_insn == BLR) { - /* RET */ - dsd->dsc->pc_adjust = 0; + /* 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 (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 6a63ce9c2005acd6fe018a12c640f1be01751d6b..6b8721139f8446d82aecac243501d31137c885a5 100644 --- a/gdb/arch/aarch64-insn.h +++ b/gdb/arch/aarch64-insn.h @@ -40,7 +40,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,