* [PATCH] arc: Determine a branch target of DBNZ correctly
@ 2024-02-14 18:16 Yuriy Kolerov
2024-02-21 13:12 ` Shahab Vahedi
2024-02-21 13:17 ` [PUSHED] " Shahab Vahedi
0 siblings, 2 replies; 3+ messages in thread
From: Yuriy Kolerov @ 2024-02-14 18:16 UTC (permalink / raw)
To: gdb-patches, shahab; +Cc: Yuriy Kolerov
DBNZ instruction was moved from BRANCH class to a separate one - DBNZ.
Thus, it must be processed separately in arc_insn_get_branch_target
to correctly determine an offset for a possible branch.
The testsuite for DBNZ instruction verifies these cases:
1. Check that dbnz does not branch and falls through if its source
register is 0 after decrementing. GDB must successfully break
on the following instruction after stepping over.
2. Check that dbnz branches to the target correctly if its source register
is not 0 after decrementing - GDB must successfully break on the target
instruction if a forward branch is performed after stepping over.
3. The same as point 2 but for a backward branching case.
Signed-off-by: Yuriy Kolerov <kolerov93@gmail.com>
---
gdb/arc-tdep.c | 10 +++
gdb/testsuite/gdb.arch/arc-dbnz.S | 47 ++++++++++++++
gdb/testsuite/gdb.arch/arc-dbnz.exp | 97 +++++++++++++++++++++++++++++
3 files changed, 154 insertions(+)
create mode 100644 gdb/testsuite/gdb.arch/arc-dbnz.S
create mode 100644 gdb/testsuite/gdb.arch/arc-dbnz.exp
diff --git a/gdb/arc-tdep.c b/gdb/arc-tdep.c
index 84e211ce9ad..3c31e009f32 100644
--- a/gdb/arc-tdep.c
+++ b/gdb/arc-tdep.c
@@ -466,6 +466,16 @@ arc_insn_get_branch_target (const struct arc_instruction &insn)
instruction, hence last two bits should be truncated. */
return pcrel_addr + align_down (insn.address, 4);
}
+ /* DBNZ is the only branch instruction that keeps a branch address in
+ the second operand. It must be intercepted and treated differently. */
+ else if (insn.insn_class == DBNZ)
+ {
+ CORE_ADDR pcrel_addr = arc_insn_get_operand_value_signed (insn, 1);
+
+ /* Offset is relative to the 4-byte aligned address of the current
+ instruction, hence last two bits should be truncated. */
+ return pcrel_addr + align_down (insn.address, 4);
+ }
/* B, Bcc, BL, BLcc, LP, LPcc: PC = currentPC + operand. */
else if (insn.insn_class == BRANCH || insn.insn_class == LOOP)
{
diff --git a/gdb/testsuite/gdb.arch/arc-dbnz.S b/gdb/testsuite/gdb.arch/arc-dbnz.S
new file mode 100644
index 00000000000..45e1dfe8305
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/arc-dbnz.S
@@ -0,0 +1,47 @@
+; This testcase is part of GDB, the GNU debugger.
+
+; Copyright 2024 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/>.
+
+ .section .text
+ .align 4
+ .global main
+ .type main, @function
+
+main:
+ mov r0,1
+dbnz1:
+ ; r0 == 0 after decrementing. dbnz doesn't do branch.
+ dbnz r0,@end
+
+ mov r0,5
+dbnz2:
+ ; r0 == 3 after decrementing and delay slot. dbnz does branch.
+ dbnz.d r0,@dbnz3
+ sub r0,r0,1
+
+dbnz4:
+ ; r0 == 1 after decrementing. dbnz does branch.
+ dbnz r0,@end
+
+dbnz3:
+ ; r0 == 2 after decrementing. dbnz does branch.
+ dbnz r0,@dbnz4
+
+end:
+ mov r0,0
+ j [blink]
+
+ .section .note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/gdb.arch/arc-dbnz.exp b/gdb/testsuite/gdb.arch/arc-dbnz.exp
new file mode 100644
index 00000000000..f1fce0e5a7f
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/arc-dbnz.exp
@@ -0,0 +1,97 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2024 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 dbnz instruction. It decrements its source register operand, and if
+# the result is non-zero it branches to the location defined by a signed
+# half-word displacement operand.
+#
+# It's necessary to verify these cases:
+#
+# 1. Check that dbnz does not branch and falls through if its source
+# register is 0 after decrementing. GDB must successfully break
+# on the following instruction after stepping over.
+# 2. Check that dbnz branches to the target correctly if its source register
+# is not 0 after decrementing - GDB must successfully break on the target
+# instruction if a forward branch is performed after stepping over.
+# 3. The same as point 2 but for a backward branching case.
+
+require {istarget "arc*-*-*"}
+
+standard_testfile .S
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile] } {
+ return -1
+}
+
+if ![runto_main] {
+ return 0
+}
+
+gdb_test "break dbnz1" \
+ "Breakpoint $decimal at .*" \
+ "set breakpoint on the 1st dbnz"
+
+gdb_test "break dbnz2" \
+ "Breakpoint $decimal at .*" \
+ "set breakpoint on the 2nd dbnz"
+
+gdb_test "break dbnz3" \
+ "Breakpoint $decimal at .*" \
+ "set breakpoint on the 3rd dbnz"
+
+gdb_test "break dbnz4" \
+ "Breakpoint $decimal at .*" \
+ "set breakpoint on the 4th dbnz"
+
+gdb_test "break end" \
+ "Breakpoint $decimal at .*" \
+ "set breakpoint at the end"
+
+gdb_test "continue" \
+ "Breakpoint $decimal, dbnz1.*dbnz r0,@end" \
+ "continue to the 1st dbnz"
+
+gdb_test "x /i \$pc" \
+ "$hex <.*>:\[ \t\]+dbnz\[ \t\]+r0,24.*" \
+ "stayng on the 1st dbnz instruction"
+
+gdb_test "stepi" \
+ "mov r0,5" \
+ "step over the 1st dbnz, branch is not taken"
+
+gdb_test "stepi" \
+ "Breakpoint $decimal, dbnz2.*dbnz\\.d r0,@dbnz3" \
+ "step over r0 initialization, staying on the 2nd dbnz"
+
+# Linux steps over delay slot after "stepi", but stubs with hardware stepping
+# like nSIM's stub may step right on delay slot. Thus use "continue" instead of
+# "stepi" to make this test work for all platforms.
+gdb_test "continue" \
+ "Breakpoint $decimal, dbnz3.*dbnz r0,@dbnz4" \
+ "step over the 2nd dbnz, branch is taken, staying on the 3rd dbnz"
+
+gdb_test "stepi" \
+ "Breakpoint $decimal, dbnz4.*dbnz r0,@end" \
+ "step over the 3rd dbnz, branch is taken, staying on the 4th dbnz"
+
+gdb_test "stepi" \
+ "Breakpoint $decimal, end.*mov r0,0" \
+ "step over the 4th dbnz, branch is taken, staying on the epilogue"
+
+gdb_test "info register r0" \
+ "r0\[ \t\]+0x1\[ \t\]+1" \
+ "r0 contains 1 after all dbnz instructions"
--
2.39.2
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH] arc: Determine a branch target of DBNZ correctly
2024-02-14 18:16 [PATCH] arc: Determine a branch target of DBNZ correctly Yuriy Kolerov
@ 2024-02-21 13:12 ` Shahab Vahedi
2024-02-21 13:17 ` [PUSHED] " Shahab Vahedi
1 sibling, 0 replies; 3+ messages in thread
From: Shahab Vahedi @ 2024-02-21 13:12 UTC (permalink / raw)
To: gdb-patches; +Cc: Yuriy Kolerov
Yuriy Kolerov <kolerov93@gmail.com> wrote:
> DBNZ instruction was moved from BRANCH class to a separate one - DBNZ.
> Thus, it must be processed separately in arc_insn_get_branch_target
> to correctly determine an offset for a possible branch.
> ...
> Signed-off-by: Yuriy Kolerov <kolerov93@gmail.com>
> ---
> gdb/arc-tdep.c | 10 +++
> gdb/testsuite/gdb.arch/arc-dbnz.S | 47 ++++++++++++++
> gdb/testsuite/gdb.arch/arc-dbnz.exp | 97 +++++++++++++++++++++++++++++
> 3 files changed, 154 insertions(+)
> create mode 100644 gdb/testsuite/gdb.arch/arc-dbnz.S
> create mode 100644 gdb/testsuite/gdb.arch/arc-dbnz.exp
Looks good to me. Thank you for your fix.
Approved-By: Shahab Vahedi <shahab@synopsys.com>
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PUSHED] arc: Determine a branch target of DBNZ correctly
2024-02-14 18:16 [PATCH] arc: Determine a branch target of DBNZ correctly Yuriy Kolerov
2024-02-21 13:12 ` Shahab Vahedi
@ 2024-02-21 13:17 ` Shahab Vahedi
1 sibling, 0 replies; 3+ messages in thread
From: Shahab Vahedi @ 2024-02-21 13:17 UTC (permalink / raw)
To: gdb-patches; +Cc: Yuriy Kolerov
From: Yuriy Kolerov <kolerov93@gmail.com>
DBNZ instruction was moved from BRANCH class to a separate one - DBNZ.
Thus, it must be processed separately in arc_insn_get_branch_target
to correctly determine an offset for a possible branch.
The testsuite for DBNZ instruction verifies these cases:
1. Check that dbnz does not branch and falls through if its source
register is 0 after decrementing. GDB must successfully break
on the following instruction after stepping over.
2. Check that dbnz branches to the target correctly if its source register
is not 0 after decrementing - GDB must successfully break on the target
instruction if a forward branch is performed after stepping over.
3. The same as point 2 but for a backward branching case.
Signed-off-by: Yuriy Kolerov <kolerov93@gmail.com>
---
gdb/arc-tdep.c | 10 +++
gdb/testsuite/gdb.arch/arc-dbnz.S | 47 ++++++++++++++
gdb/testsuite/gdb.arch/arc-dbnz.exp | 97 +++++++++++++++++++++++++++++
3 files changed, 154 insertions(+)
create mode 100644 gdb/testsuite/gdb.arch/arc-dbnz.S
create mode 100644 gdb/testsuite/gdb.arch/arc-dbnz.exp
diff --git a/gdb/arc-tdep.c b/gdb/arc-tdep.c
index 12d8aee949f..7dd43cc239f 100644
--- a/gdb/arc-tdep.c
+++ b/gdb/arc-tdep.c
@@ -466,6 +466,16 @@ arc_insn_get_branch_target (const struct arc_instruction &insn)
instruction, hence last two bits should be truncated. */
return pcrel_addr + align_down (insn.address, 4);
}
+ /* DBNZ is the only branch instruction that keeps a branch address in
+ the second operand. It must be intercepted and treated differently. */
+ else if (insn.insn_class == DBNZ)
+ {
+ CORE_ADDR pcrel_addr = arc_insn_get_operand_value_signed (insn, 1);
+
+ /* Offset is relative to the 4-byte aligned address of the current
+ instruction, hence last two bits should be truncated. */
+ return pcrel_addr + align_down (insn.address, 4);
+ }
/* B, Bcc, BL, BLcc, LP, LPcc: PC = currentPC + operand. */
else if (insn.insn_class == BRANCH || insn.insn_class == LOOP)
{
diff --git a/gdb/testsuite/gdb.arch/arc-dbnz.S b/gdb/testsuite/gdb.arch/arc-dbnz.S
new file mode 100644
index 00000000000..45e1dfe8305
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/arc-dbnz.S
@@ -0,0 +1,47 @@
+; This testcase is part of GDB, the GNU debugger.
+
+; Copyright 2024 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/>.
+
+ .section .text
+ .align 4
+ .global main
+ .type main, @function
+
+main:
+ mov r0,1
+dbnz1:
+ ; r0 == 0 after decrementing. dbnz doesn't do branch.
+ dbnz r0,@end
+
+ mov r0,5
+dbnz2:
+ ; r0 == 3 after decrementing and delay slot. dbnz does branch.
+ dbnz.d r0,@dbnz3
+ sub r0,r0,1
+
+dbnz4:
+ ; r0 == 1 after decrementing. dbnz does branch.
+ dbnz r0,@end
+
+dbnz3:
+ ; r0 == 2 after decrementing. dbnz does branch.
+ dbnz r0,@dbnz4
+
+end:
+ mov r0,0
+ j [blink]
+
+ .section .note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/gdb.arch/arc-dbnz.exp b/gdb/testsuite/gdb.arch/arc-dbnz.exp
new file mode 100644
index 00000000000..f1fce0e5a7f
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/arc-dbnz.exp
@@ -0,0 +1,97 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2024 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 dbnz instruction. It decrements its source register operand, and if
+# the result is non-zero it branches to the location defined by a signed
+# half-word displacement operand.
+#
+# It's necessary to verify these cases:
+#
+# 1. Check that dbnz does not branch and falls through if its source
+# register is 0 after decrementing. GDB must successfully break
+# on the following instruction after stepping over.
+# 2. Check that dbnz branches to the target correctly if its source register
+# is not 0 after decrementing - GDB must successfully break on the target
+# instruction if a forward branch is performed after stepping over.
+# 3. The same as point 2 but for a backward branching case.
+
+require {istarget "arc*-*-*"}
+
+standard_testfile .S
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile] } {
+ return -1
+}
+
+if ![runto_main] {
+ return 0
+}
+
+gdb_test "break dbnz1" \
+ "Breakpoint $decimal at .*" \
+ "set breakpoint on the 1st dbnz"
+
+gdb_test "break dbnz2" \
+ "Breakpoint $decimal at .*" \
+ "set breakpoint on the 2nd dbnz"
+
+gdb_test "break dbnz3" \
+ "Breakpoint $decimal at .*" \
+ "set breakpoint on the 3rd dbnz"
+
+gdb_test "break dbnz4" \
+ "Breakpoint $decimal at .*" \
+ "set breakpoint on the 4th dbnz"
+
+gdb_test "break end" \
+ "Breakpoint $decimal at .*" \
+ "set breakpoint at the end"
+
+gdb_test "continue" \
+ "Breakpoint $decimal, dbnz1.*dbnz r0,@end" \
+ "continue to the 1st dbnz"
+
+gdb_test "x /i \$pc" \
+ "$hex <.*>:\[ \t\]+dbnz\[ \t\]+r0,24.*" \
+ "stayng on the 1st dbnz instruction"
+
+gdb_test "stepi" \
+ "mov r0,5" \
+ "step over the 1st dbnz, branch is not taken"
+
+gdb_test "stepi" \
+ "Breakpoint $decimal, dbnz2.*dbnz\\.d r0,@dbnz3" \
+ "step over r0 initialization, staying on the 2nd dbnz"
+
+# Linux steps over delay slot after "stepi", but stubs with hardware stepping
+# like nSIM's stub may step right on delay slot. Thus use "continue" instead of
+# "stepi" to make this test work for all platforms.
+gdb_test "continue" \
+ "Breakpoint $decimal, dbnz3.*dbnz r0,@dbnz4" \
+ "step over the 2nd dbnz, branch is taken, staying on the 3rd dbnz"
+
+gdb_test "stepi" \
+ "Breakpoint $decimal, dbnz4.*dbnz r0,@end" \
+ "step over the 3rd dbnz, branch is taken, staying on the 4th dbnz"
+
+gdb_test "stepi" \
+ "Breakpoint $decimal, end.*mov r0,0" \
+ "step over the 4th dbnz, branch is taken, staying on the epilogue"
+
+gdb_test "info register r0" \
+ "r0\[ \t\]+0x1\[ \t\]+1" \
+ "r0 contains 1 after all dbnz instructions"
--
2.35.8
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2024-02-21 13:17 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-02-14 18:16 [PATCH] arc: Determine a branch target of DBNZ correctly Yuriy Kolerov
2024-02-21 13:12 ` Shahab Vahedi
2024-02-21 13:17 ` [PUSHED] " Shahab Vahedi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).