aboutsummaryrefslogtreecommitdiff
path: root/gdb/rs6000-tdep.c
diff options
context:
space:
mode:
authorWill Schmidt <will_schmidt@vnet.ibm.com>2021-04-12 13:35:54 -0500
committerWill Schmidt <will_schmidt@vnet.ibm.com>2021-04-12 13:35:54 -0500
commite3d528d7e6a6b863d30aaecf74adf8c78286f84c (patch)
treeec7b64bf5893b1bad1aec556ae7754896a47cdc6 /gdb/rs6000-tdep.c
parent82d9b2804751252a31342ab5a501ef6c96f4548a (diff)
downloadfsf-binutils-gdb-e3d528d7e6a6b863d30aaecf74adf8c78286f84c.zip
fsf-binutils-gdb-e3d528d7e6a6b863d30aaecf74adf8c78286f84c.tar.gz
fsf-binutils-gdb-e3d528d7e6a6b863d30aaecf74adf8c78286f84c.tar.bz2
[PATCH, rs6000, v3][PR gdb/27525] displaced stepping across addpcis/lnia.
This addresses PR gdb/27525. The lnia and other variations of the addpcis instruction write the value of the NIA into a target register. If we are single-stepping across a breakpoint, the instruction is executed from a displaced location, and thusly the written value of the PC/NIA will be incorrect. The changes here will measure the displacement offset, and adjust the target register value to compensate. YYYY-MM-DD Will Schmidt <will_schmidt@vnet.ibm.com> gdb/ChangeLog: * rs6000-tdep.c (ppc_displaced_step_fixup): Update to handle the addpcis/lnia instruction. gdb/testsuite/ChangeLog: * gdb.arch/powerpc-addpcis.exp: Testcase harness to exercise single-stepping over subpcis,lnia,addpcis instructions with displacement. * gdb.arch/powerpc-addpcis.s: Testcase with stream of addpcis/lnia/subpcis instructions. * gdb.arch/powerpc-lnia.exp: Testcase harness to exercise single-stepping over lnia instructions with displacement. * gdb.arch/powerpc-lnia.s: Testcase with stream of lnia instructions.
Diffstat (limited to 'gdb/rs6000-tdep.c')
-rw-r--r--gdb/rs6000-tdep.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index 276b4fa..7a5b4bf 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -863,6 +863,12 @@ typedef BP_MANIPULATION_ENDIAN (little_breakpoint, big_breakpoint)
#define STHCX_INSTRUCTION 0x7c0005ad
#define STQCX_INSTRUCTION 0x7c00016d
+/* Instruction masks for single-stepping of addpcis/lnia. */
+#define ADDPCIS_INSN 0x4c000004
+#define ADDPCIS_INSN_MASK 0xfc00003e
+#define ADDPCIS_TARGET_REGISTER 0x03F00000
+#define ADDPCIS_INSN_REGSHIFT 21
+
/* Check if insn is one of the Load And Reserve instructions used for atomic
sequences. */
#define IS_LOAD_AND_RESERVE_INSN(insn) ((insn & LOAD_AND_RESERVE_MASK) == LWARX_INSTRUCTION \
@@ -941,8 +947,27 @@ ppc_displaced_step_fixup (struct gdbarch *gdbarch,
displaced_debug_printf ("(ppc) fixup (%s, %s)",
paddress (gdbarch, from), paddress (gdbarch, to));
+ /* Handle the addpcis/lnia instruction. */
+ if ((insn & ADDPCIS_INSN_MASK) == ADDPCIS_INSN)
+ {
+ LONGEST displaced_offset;
+ ULONGEST current_val;
+ /* Measure the displacement. */
+ displaced_offset = from - to;
+ /* Identify the target register that was updated by the instruction. */
+ int regnum = (insn & ADDPCIS_TARGET_REGISTER) >> ADDPCIS_INSN_REGSHIFT;
+ /* Read and update the target value. */
+ regcache_cooked_read_unsigned (regs, regnum , &current_val);
+ displaced_debug_printf ("addpcis target regnum %d was 0x%lx now 0x%lx",
+ regnum, current_val, current_val + displaced_offset );
+ regcache_cooked_write_unsigned (regs, regnum,
+ current_val + displaced_offset);
+ /* point the PC back at the non-displaced instruction. */
+ regcache_cooked_write_unsigned (regs, gdbarch_pc_regnum (gdbarch),
+ from + offset);
+ }
/* Handle PC-relative branch instructions. */
- if (opcode == B_INSN || opcode == BC_INSN || opcode == BXL_INSN)
+ else if (opcode == B_INSN || opcode == BC_INSN || opcode == BXL_INSN)
{
ULONGEST current_pc;