aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/rs6000-tdep.c65
-rw-r--r--gdb/testsuite/gdb.arch/powerpc-trap.exp72
-rw-r--r--gdb/testsuite/gdb.arch/powerpc-trap.s31
-rw-r--r--gdb/testsuite/gdb.arch/powerpc64-trap.s33
4 files changed, 201 insertions, 0 deletions
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index 43880fa..ce98dc2 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -6247,6 +6247,69 @@ UNKNOWN_OP:
return 0;
}
+/* Used for matching tw, twi, td and tdi instructions for POWER. */
+
+static constexpr uint32_t TX_INSN_MASK = 0xFC0007FF;
+static constexpr uint32_t TW_INSN = 0x7C000008;
+static constexpr uint32_t TD_INSN = 0x7C000088;
+
+static constexpr uint32_t TXI_INSN_MASK = 0xFC000000;
+static constexpr uint32_t TWI_INSN = 0x0C000000;
+static constexpr uint32_t TDI_INSN = 0x08000000;
+
+static inline bool
+is_tw_insn (uint32_t insn)
+{
+ return (insn & TX_INSN_MASK) == TW_INSN;
+}
+
+static inline bool
+is_twi_insn (uint32_t insn)
+{
+ return (insn & TXI_INSN_MASK) == TWI_INSN;
+}
+
+static inline bool
+is_td_insn (uint32_t insn)
+{
+ return (insn & TX_INSN_MASK) == TD_INSN;
+}
+
+static inline bool
+is_tdi_insn (uint32_t insn)
+{
+ return (insn & TXI_INSN_MASK) == TDI_INSN;
+}
+
+/* Implementation of gdbarch_program_breakpoint_here_p for POWER. */
+
+static bool
+rs6000_program_breakpoint_here_p (gdbarch *gdbarch, CORE_ADDR address)
+{
+ gdb_byte target_mem[PPC_INSN_SIZE];
+
+ /* Enable the automatic memory restoration from breakpoints while
+ we read the memory. Otherwise we may find temporary breakpoints, ones
+ inserted by GDB, and flag them as permanent breakpoints. */
+ scoped_restore restore_memory
+ = make_scoped_restore_show_memory_breakpoints (0);
+
+ if (target_read_memory (address, target_mem, PPC_INSN_SIZE) == 0)
+ {
+ uint32_t insn = (uint32_t) extract_unsigned_integer
+ (target_mem, PPC_INSN_SIZE, gdbarch_byte_order_for_code (gdbarch));
+
+ /* Check if INSN is a TW, TWI, TD or TDI instruction. There
+ are multiple choices of such instructions with different registers
+ and / or immediate values but they all cause a break. */
+ if (is_tw_insn (insn) || is_twi_insn (insn) || is_td_insn (insn)
+ || is_tdi_insn (insn))
+ return true;
+ }
+
+ return false;
+}
+
/* Initialize the current architecture based on INFO. If possible, re-use an
architecture from ARCHES, which is a list of architectures already created
during this debugging session.
@@ -7109,6 +7172,8 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
rs6000_breakpoint::kind_from_pc);
set_gdbarch_sw_breakpoint_from_kind (gdbarch,
rs6000_breakpoint::bp_from_kind);
+ set_gdbarch_program_breakpoint_here_p (gdbarch,
+ rs6000_program_breakpoint_here_p);
/* The value of symbols of type N_SO and N_FUN maybe null when
it shouldn't be. */
diff --git a/gdb/testsuite/gdb.arch/powerpc-trap.exp b/gdb/testsuite/gdb.arch/powerpc-trap.exp
new file mode 100644
index 0000000..57a683d
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/powerpc-trap.exp
@@ -0,0 +1,72 @@
+# 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/>.
+#
+# This file is part of the gdb testsuite.
+
+# Test if GDB stops at various trap instructions inserted into
+# the code.
+
+if { [istarget powerpc-*] } {
+ standard_testfile powerpc-trap.s
+ # Number of expected SIGTRAPs to get. This needs to be kept in sync
+ # with the source file powerpc-trap.s.
+ set expected_traps 3
+} elseif {[istarget powerpc64*] } {
+ standard_testfile powerpc64-trap.s
+ # Number of expected SIGTRAPs to get. This needs to be kept in sync
+ # with the source file powerpc64-trap.s.
+ set expected_traps 5
+} else {
+ verbose "Skipping ${gdb_test_file_name}."
+ return
+}
+
+if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile}]} {
+ return -1
+}
+
+if {![runto_main]} {
+ untested "could not run to main"
+ return -1
+}
+
+set keep_going 1
+set count 0
+
+while {$keep_going} {
+ set keep_going 0
+
+ # Continue to next program breakpoint instruction.
+ gdb_test_multiple "continue" "trap instruction $count causes SIGTRAP" {
+ -re "Program received signal SIGTRAP, Trace/breakpoint trap.*$gdb_prompt $" {
+ pass $gdb_test_name
+
+ # Advance PC to next instruction
+ gdb_test "set \$pc = \$pc + 4" "" "advance past trap instruction $count"
+
+ incr count
+ if {$count < $expected_traps} {
+ set keep_going 1
+ }
+ }
+ }
+}
+
+# Verify we stopped at the expected number of SIGTRAP's.
+gdb_assert {$count == $expected_traps} "all trap instructions triggered"
+
+# One last continue to reach the end of the test, to make sure we don't get
+# another SIGTRAP.
+gdb_test "continue" "exited normally.*" "continue to end"
diff --git a/gdb/testsuite/gdb.arch/powerpc-trap.s b/gdb/testsuite/gdb.arch/powerpc-trap.s
new file mode 100644
index 0000000..b03176f
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/powerpc-trap.s
@@ -0,0 +1,31 @@
+/* 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/>. */
+
+/* To test if GDB stops at various trap instructions inserted into
+ the code. */
+
+.global main
+.type main,function
+main:
+ ori 0, 0, 0
+ trap
+ tw 12, 2, 2
+ twi 31, 3, 3
+ ori 0, 0, 0
+ li 3, 0
+ blr
+
diff --git a/gdb/testsuite/gdb.arch/powerpc64-trap.s b/gdb/testsuite/gdb.arch/powerpc64-trap.s
new file mode 100644
index 0000000..2272b42
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/powerpc64-trap.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/>. */
+
+/* To test if GDB stops at various trap instructions inserted into
+ the code. */
+
+.global main
+.type main,function
+main:
+ ori 0, 0, 0
+ trap
+ tw 12, 2, 2
+ twi 31, 3, 3
+ td 12, 2, 2
+ tdi 31, 3, 3
+ ori 0, 0, 0
+ li 3, 0
+ blr
+