aboutsummaryrefslogtreecommitdiff
path: root/gdb
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
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')
-rw-r--r--gdb/ChangeLog6
-rw-r--r--gdb/rs6000-tdep.c27
-rw-r--r--gdb/testsuite/ChangeLog13
-rw-r--r--gdb/testsuite/gdb.arch/powerpc-addpcis.exp105
-rw-r--r--gdb/testsuite/gdb.arch/powerpc-addpcis.s35
-rw-r--r--gdb/testsuite/gdb.arch/powerpc-lnia.exp101
-rw-r--r--gdb/testsuite/gdb.arch/powerpc-lnia.s33
7 files changed, 319 insertions, 1 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 4798523..fe52581 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,11 @@
2021-04-12 Will Schmidt <will_schmidt@vnet.ibm.com>
+ PR gdb/27525
+ * gdb/rs6000-tdep.c (ppc_displaced_step_fixup): Update to
+ handle the addpcis/lnia instruction.
+
+2021-04-05 Will Schmidt <will_schmidt@vnet.ibm.com>
+
* MAINTAINERS (Write After Approval): Add myself.
2021-4-12 Carl Love <cel@us.ibm.com>
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;
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index f097a02..2c0233d 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,18 @@
2021-04-12 Will Schmidt <will_schmidt@vnet.ibm.com>
+ PR gdb/27525
+ * gdb/testsuite/gdb.arch/powerpc-addpcis.exp: Testcase harness to
+ exercise single-stepping over subpcis,lnia,addpcis instructions
+ with displacement.
+ * gdb/testsuite/gdb.arch/powerpc-addpcis.s: Testcase with stream
+ of addpcis/lnia/subpcis instructions.
+ * gdb/testsuite/gdb.arch/powerpc-lnia.exp: Testcase harness to
+ exercise single-stepping over lnia instructions with displacement.
+ * gdb/testsuite/gdb.arch/powerpc-lnia.s: Testcase with stream of
+ lnia instructions.
+
+2021-03-31 Will Schmidt <will_schmidt@vnet.ibm.com>
+
* gdb.arch/powerpc-power10.s: New test for instructions.
* gdb.arch/powerpc-power10.exp: Harness to run the test.
diff --git a/gdb/testsuite/gdb.arch/powerpc-addpcis.exp b/gdb/testsuite/gdb.arch/powerpc-addpcis.exp
new file mode 100644
index 0000000..d1bc7f4
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/powerpc-addpcis.exp
@@ -0,0 +1,105 @@
+# Copyright 2021 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+# Test to confirm that gdb is properly single stepping over the
+# displaced addpcis instruction.
+# The addpcis instruction and its extended mnemonics lnia and subpcis
+# apply an immediate shifted value (X || 0x0000) to the current PC/NIA
+# value, and store that value into the instructions target register.
+# When the instruction is displaced, it needs special handling.
+
+# lnia Rx == addpcis Rx,0
+# subcis Rx,value == addpcis Rx,-value
+
+if { ![istarget powerpc*-*] } {
+ verbose "Skipping powerpc addpcis test."
+ return
+}
+
+set retval 0
+
+standard_testfile .s
+
+if { [prepare_for_testing "failed to prepare" $testfile "$srcfile" \
+ {debug quiet}] } {
+ return -1
+}
+
+if ![runto_main] then {
+ return
+}
+
+set check_pc [get_hexadecimal_valueof "\$pc" "default0"]
+set bp1 *$check_pc+4
+set bp2 *$check_pc+12
+set bp3 *$check_pc+16
+gdb_breakpoint $bp1
+gdb_breakpoint $bp2
+gdb_breakpoint $bp3
+
+gdb_test "stepi" "" "set r3 "
+set check_r3 [get_hexadecimal_valueof "\$r3" "default0"]
+gdb_test "stepi" "" "set r4"
+set check_r4 [get_hexadecimal_valueof "\$r4" "default0"]
+gdb_test "stepi" "" "set r5"
+set check_r5 [get_hexadecimal_valueof "\$r5" "default0"]
+gdb_test "stepi" "" "set r6"
+set check_r6 [get_hexadecimal_valueof "\$r6" "default0"]
+gdb_test "stepi" "" "set r7"
+set check_r7 [get_hexadecimal_valueof "\$r7" "default0"]
+gdb_test "stepi" "" "set r8"
+set check_r8 [get_hexadecimal_valueof "\$r8" "default0"]
+gdb_test "stepi" "" "set r9"
+set check_r9 [get_hexadecimal_valueof "\$r9" "default0"]
+
+# R6 will contain the reference value. All other
+# instructions in this test will be storing values
+# relative to what is stored in R6.
+
+# subpcis 3,+0x100 # /* set r3 */
+# subpcis 4,+0x10 # /* set r4 */
+# subpcis 5,+0x1 # /* set r5 */
+# lnia 6 # /* set r6 */
+# addpcis 7,+0x1 # /* set r7 */
+# addpcis 8,+0x10 # /* set r8 */
+# addpcis 9,+0x100 # /* set r9 */
+
+if [expr $check_r3 + 0x1000000 != $check_r6 - 0xc ] {
+ fail "unexpected value r3 + 0x1,000,000 != r6 + 0xc ; r3: $check_r3 r6: $check_r6 "
+}
+if [expr $check_r4 + 0x100000 != $check_r6 - 0x8 ] {
+ fail "unexpected value r4 + 0x100,000 != r6 - 0x8 ; r4: $check_r4 r6: $check_r6 "
+}
+if [expr $check_r5 + 0x10000 != $check_r6 - 0x4 ] {
+ fail "unexpected value r5 + 0x10,000 != r6 , r5: $check_r5 r6: $check_r6 "
+}
+if [expr $check_r6 != $check_r6] {
+ fail "unexpected value r6 != r6 , r6: $check_r6 r6: $check_r6 "
+}
+if [expr $check_r7 - 0x10000 != $check_r6 + 0x4] {
+ fail "unexpected value r7 - 0x10,000 != r6 + 0x4 , r7: $check_r7 r7: $check_r6 "
+}
+if [expr $check_r8 - 0x100000 != $check_r6 + 0x8 ] {
+ fail "unexpected value r8 - 0x100,000 != r6 , r8: $check_r8 r8: $check_r6 "
+}
+if [expr $check_r9 - 0x1000000 != $check_r6 + 0xc ] {
+ fail "unexpected value r9 - 0x1,000,000 != r6 + 0xc , r9: $check_r9 r6: $check_r6 "
+}
+
+gdb_test "info break"
+gdb_test "info register r3 r4 r5 r6 r7 r8 r9"
+gdb_test "disas main"
+
diff --git a/gdb/testsuite/gdb.arch/powerpc-addpcis.s b/gdb/testsuite/gdb.arch/powerpc-addpcis.s
new file mode 100644
index 0000000..8a163a2
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/powerpc-addpcis.s
@@ -0,0 +1,35 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2021 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+
+/* Test to confirm that gdb is properly single stepping over the
+ displaced addpcis instruction. */
+
+.global main
+.type main,function
+# addpcis: the sum of NIA + ( D || 0x0000) is placed in RT.
+main:
+ subpcis 3,+0x100 # /* set r3 */
+ subpcis 4,+0x10 # /* set r4 */
+ subpcis 5,+0x1 # /* set r5 */
+ lnia 6 # /* set r6 */
+ addpcis 7,+0x1 # /* set r7 */
+ addpcis 8,+0x10 # /* set r8 */
+ addpcis 9,+0x100 # /* set r9 */
+ blr
+
+
diff --git a/gdb/testsuite/gdb.arch/powerpc-lnia.exp b/gdb/testsuite/gdb.arch/powerpc-lnia.exp
new file mode 100644
index 0000000..0f56d83
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/powerpc-lnia.exp
@@ -0,0 +1,101 @@
+# Copyright 2021 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Test to see if gdb is properly single stepping over the
+# displaced lnia instruction. This test checks that a series
+# of lnia instructions are loading ascending values as expected.
+
+# lnia is an extended mnemonic for the addpcis instruction, which
+# stores the $NIA plus an immediate value into a register.
+#
+# lnia Rx == addpcis Rx,0 == lnia Rx
+# subcis Rx,value == addpcis Rx,-value
+
+if { ![istarget powerpc*-*] } {
+ verbose "Skipping powerpc lnia test."
+ return
+}
+
+set retval 0
+
+standard_testfile .s
+
+if { [prepare_for_testing "failed to prepare" $testfile "$srcfile" \
+ {debug quiet}] } {
+ return -1
+}
+
+if ![runto_main] then {
+ return
+}
+
+set before_pc 0
+set check_pc [get_hexadecimal_valueof "\$pc" "default0"]
+
+# set some breakpoints on the instructions below main().
+set bp1 *$check_pc+4
+set bp2 *$check_pc+12
+set bp3 *$check_pc+16
+gdb_breakpoint $bp1
+gdb_breakpoint $bp2
+gdb_breakpoint $bp3
+
+# single-step through the lnia instructions, and retrieve the
+# register values as we proceed.
+gdb_test "stepi" "" "set r3"
+set check_r3 [get_hexadecimal_valueof "\$r3" "default0"]
+gdb_test "stepi" "" "set r4"
+set check_r4 [get_hexadecimal_valueof "\$r4" "default0"]
+gdb_test "stepi" "" "set r5"
+set check_r5 [get_hexadecimal_valueof "\$r5" "default0"]
+gdb_test "stepi" "" "set r6"
+set check_r6 [get_hexadecimal_valueof "\$r6" "default0"]
+gdb_test "stepi" "" "set r7"
+set check_r7 [get_hexadecimal_valueof "\$r7" "default0"]
+gdb_test "stepi" "" "set r8"
+set check_r8 [get_hexadecimal_valueof "\$r8" "default0"]
+gdb_test "stepi" "" "set r9"
+set check_r9 [get_hexadecimal_valueof "\$r9" "default0"]
+
+# Ensure that our register values are as expected.
+# Specifically that the values loaded by the lnia instruction
+# reflect the value of the PC as if the instruction was
+# not displaced.
+if [expr $check_r3 + 4 != $check_r4] {
+ fail "unexpected value r3+4 != r4 , r3: $check_r3 r4: $check_r4 "
+}
+if [expr $check_r4 + 4 != $check_r5] {
+ fail "unexpected value r4+4 != r5 , r4: $check_r4 r5: $check_r5 "
+}
+if [expr $check_r5 + 4 != $check_r6] {
+ fail "unexpected value r5+4 != r6 , r5: $check_r5 r6: $check_r6 "
+}
+if [expr $check_r6 + 4 != $check_r7] {
+ fail "unexpected value r6+4 != r7 , r6: $check_r6 r7: $check_r7 "
+}
+if [expr $check_r7 + 4 != $check_r8] {
+ fail "unexpected value r7+4 != r8 , r7: $check_r7 r8: $check_r8 "
+}
+if [expr $check_r8 + 4 != $check_r9] {
+ fail "unexpected value r8+4 != r9 , r8: $check_r8 r9: $check_r9 "
+}
+
+gdb_test "info break"
+gdb_test "info register r3 r4 r5 r6 r7 r8 r9"
+gdb_test "disas main"
+
+# Let the inferior store all vector registers in a buffer, then dump
+# the buffer and check it.
+
diff --git a/gdb/testsuite/gdb.arch/powerpc-lnia.s b/gdb/testsuite/gdb.arch/powerpc-lnia.s
new file mode 100644
index 0000000..56e5745
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/powerpc-lnia.s
@@ -0,0 +1,33 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2021 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Test to confirm that gdb properly handles lnia instructions
+ that load the current PC into a target register when executed
+ from a displaced location. */
+
+.global main
+.type main,function
+main:
+ lnia 3 # /* set r3 */
+ lnia 4 # /* set r4 */
+ lnia 5 # /* set r5 */
+ lnia 6 # /* set r6 */
+ lnia 7 # /* set r7 */
+ lnia 8 # /* set r8 */
+ lnia 9 # /* set r9 */
+ blr
+