public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Shahab Vahedi <list+gdb@vahedi.org>
To: gdb-patches@sourceware.org
Cc: Yuriy Kolerov <kolerov93@gmail.com>
Subject: [PUSHED] arc: Determine a branch target of DBNZ correctly
Date: Wed, 21 Feb 2024 14:17:21 +0100	[thread overview]
Message-ID: <20240221131721.15430-1-list+gdb@vahedi.org> (raw)
In-Reply-To: <20240214181616.36502-1-kolerov93@gmail.com>

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


      parent reply	other threads:[~2024-02-21 13:17 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-02-14 18:16 [PATCH] " Yuriy Kolerov
2024-02-21 13:12 ` Shahab Vahedi
2024-02-21 13:17 ` Shahab Vahedi [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240221131721.15430-1-list+gdb@vahedi.org \
    --to=list+gdb@vahedi.org \
    --cc=gdb-patches@sourceware.org \
    --cc=kolerov93@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).