From: "Maciej W. Rozycki" <macro@orcam.me.uk>
To: gdb-patches@sourceware.org
Cc: Jovan Dmitrovic <jovan.dmitrovic@htecgroup.com>,
Djordje Todorovic <Djordje.Todorovic@htecgroup.com>,
Milica Matic <milica.matic@htecgroup.com>,
"Maciej W. Rozycki" <macro@globalfoundries.com>
Subject: [PATCH v2 12/12] MIPS: Fix stepping through instructions branching to own delay slot
Date: Mon, 17 Aug 2026 17:54:25 +0100 (BST) [thread overview]
Message-ID: <alpine.DEB.2.21.2608170042050.14132@angie.orcam.me.uk> (raw)
In-Reply-To: <alpine.DEB.2.21.2608161728490.14132@angie.orcam.me.uk>
From: Maciej W. Rozycki <macro@globalfoundries.com>
Branching to own delay slot is not disallowed in the ISA and works as
expected. Especially for regular conditional branches it might be a
useful way to have the branch delay instruction conditionally executed
once or twice, which in some cases could avoid extra jumping around.
We do not handle this case specially in software stepping, which means
that for a taken branch or a jump a single-stepping breakpoint is placed
in the delay slot. This is also allowed by the ISA, however it causes
the execution of the containing branch to be abandoned and a breakpoint
exception triggered with the PC pointing at the branch. While the BD
bit is also set in the CP0 Cause register indicating the situation, we
do not examine it, following a deliberate design decision.
Consequently single-stepping over such a branch or jump loops forever
and execution progress cannot be made without manual intervention.
Recognize the situation then, and skip over the delay slot when placing
a single-stepping breakpoint, except for jumps that switch the ISA mode
(for which jumping to the delay slot instruction seems of questionable
use, even though valid) and where the delay slot instruction itself is a
branch or jump (which yields unpredictable operation according to the
ISA and is therefore unsupported; actual hardware implementations vary
from triggering the Reserved Instruction exception, through executing
the delay slot branch or jump instruction normally, to ignoring it and
proceeding from the target of the original branch or jump).
Add testcases accordingly, for MIPS I, MIPS II, MIPS16 and microMIPS CPU
branches and jumps, and DSP ASE branches except for 64-bit ones.
Approved-By: Maciej W. Rozycki <macro@orcam.me.uk>
---
New change in v2.
---
gdb/mips-tdep.c | 223 +++++++++++++++-------
gdb/testsuite/gdb.arch/micromips-branch-delay.c | 89 ++++++++
gdb/testsuite/gdb.arch/micromips-branch-delay.exp | 31 +++
gdb/testsuite/gdb.arch/micromips-jals-delay.c | 56 +++++
gdb/testsuite/gdb.arch/micromips-jals-delay.exp | 30 ++
gdb/testsuite/gdb.arch/mips-allow.exp.tcl | 58 +++++
gdb/testsuite/gdb.arch/mips-dsp-branch-delay.c | 62 ++++++
gdb/testsuite/gdb.arch/mips-dsp-branch-delay.exp | 31 +++
gdb/testsuite/gdb.arch/mips-jal-delay.c | 60 +++++
gdb/testsuite/gdb.arch/mips-jal-delay.exp | 27 ++
gdb/testsuite/gdb.arch/mips-jr-delay.c | 64 ++++++
gdb/testsuite/gdb.arch/mips-jr-delay.exp | 23 ++
gdb/testsuite/gdb.arch/mips1-bal-delay.c | 63 ++++++
gdb/testsuite/gdb.arch/mips1-bal-delay.exp | 31 +++
gdb/testsuite/gdb.arch/mips1-branch-delay.c | 67 ++++++
gdb/testsuite/gdb.arch/mips1-branch-delay.exp | 31 +++
gdb/testsuite/gdb.arch/mips2-branch-delay.c | 70 ++++++
gdb/testsuite/gdb.arch/mips2-branch-delay.exp | 31 +++
18 files changed, 980 insertions(+), 67 deletions(-)
gdb-mips-next-pc-bds.diff
Index: binutils-gdb/gdb/mips-tdep.c
===================================================================
--- binutils-gdb.orig/gdb/mips-tdep.c
+++ binutils-gdb/gdb/mips-tdep.c
@@ -1592,6 +1592,7 @@ mips32_bc1_pc (struct gdbarch *gdbarch,
int cnum = (itype_rt (inst) >> 2) & (count - 1);
int tf = itype_rt (inst) & 1;
int mask = (1 << count) - 1;
+ CORE_ADDR pc_adj;
ULONGEST fcs;
int cond;
@@ -1602,8 +1603,9 @@ mips32_bc1_pc (struct gdbarch *gdbarch,
fcs = regcache_raw_get_unsigned (regcache, fcsr);
cond = ((fcs >> 24) & 0xfe) | ((fcs >> 23) & 0x01);
- if (((cond >> cnum) & mask) != mask * !tf)
- pc += mips32_relative_offset (inst);
+ pc_adj = mips32_relative_offset (inst);
+ if (pc_adj && ((cond >> cnum) & mask) != mask * !tf)
+ pc += pc_adj;
else
pc += 4;
@@ -1647,6 +1649,7 @@ mips32_next_pc (struct regcache *regcach
{
struct gdbarch *gdbarch = regcache->arch ();
unsigned long inst;
+ CORE_ADDR pc_adj;
int op;
inst = mips_fetch_instruction (gdbarch, ISA_MIPS, pc, NULL);
op = itype_op (inst);
@@ -1702,10 +1705,12 @@ mips32_next_pc (struct regcache *regcach
if (op == 54 || op == 62)
bit += 32;
- if (((regcache_raw_get_signed (regcache,
- itype_rs (inst)) >> bit) & 1)
- == branch_if)
- pc += mips32_relative_offset (inst) + 4;
+ pc_adj = mips32_relative_offset (inst);
+ if (pc_adj
+ && ((regcache_raw_get_signed (regcache,
+ itype_rs (inst)) >> bit) & 1)
+ == branch_if)
+ pc += pc_adj + 4;
else
pc += 8; /* After the delay slot. */
}
@@ -1724,8 +1729,12 @@ mips32_next_pc (struct regcache *regcach
{
case 8: /* JR */
case 9: /* JALR */
- /* Set PC to that address. */
- pc = regcache_raw_get_signed (regcache, rtype_rs (inst));
+ /* Set PC to that address, avoiding the delay slot. */
+ pc_adj = regcache_raw_get_signed (regcache, rtype_rs (inst));
+ if (pc_adj != pc + 4)
+ pc = pc_adj;
+ else
+ pc += 8;
break;
case 12: /* SYSCALL */
{
@@ -1752,8 +1761,10 @@ mips32_next_pc (struct regcache *regcach
case 2: /* BLTZL */
case 16: /* BLTZAL */
case 18: /* BLTZALL */
- if (regcache_raw_get_signed (regcache, itype_rs (inst)) < 0)
- pc += mips32_relative_offset (inst) + 4;
+ pc_adj = mips32_relative_offset (inst);
+ if (pc_adj
+ && regcache_raw_get_signed (regcache, itype_rs (inst)) < 0)
+ pc += pc_adj + 4;
else
pc += 8; /* After the delay slot. */
break;
@@ -1761,8 +1772,10 @@ mips32_next_pc (struct regcache *regcach
case 3: /* BGEZL */
case 17: /* BGEZAL */
case 19: /* BGEZALL */
- if (regcache_raw_get_signed (regcache, itype_rs (inst)) >= 0)
- pc += mips32_relative_offset (inst) + 4;
+ pc_adj = mips32_relative_offset (inst);
+ if (pc_adj
+ && regcache_raw_get_signed (regcache, itype_rs (inst)) >= 0)
+ pc += pc_adj + 4;
else
pc += 8; /* After the delay slot. */
break;
@@ -1778,9 +1791,11 @@ mips32_next_pc (struct regcache *regcach
/* No way to handle; it'll most likely trap anyway. */
break;
- if ((regcache_raw_get_unsigned (regcache,
- dspctl) & 0x7f) >= pos)
- pc += mips32_relative_offset (inst);
+ pc_adj = mips32_relative_offset (inst);
+ if (pc_adj
+ && (regcache_raw_get_unsigned (regcache,
+ dspctl) & 0x7f) >= pos)
+ pc += pc_adj;
else
pc += 4;
}
@@ -1797,37 +1812,49 @@ mips32_next_pc (struct regcache *regcach
unsigned long reg;
reg = jtype_target (inst) << 2;
/* Upper four bits get never changed... */
- pc = reg + ((pc + 4) & ~(CORE_ADDR) 0x0fffffff);
+ pc_adj = reg + ((pc + 4) & ~(CORE_ADDR) 0x0fffffff);
+ if (pc_adj != pc + 4)
+ pc = pc_adj;
+ else
+ pc += 8;
}
break;
case 4: /* BEQ, BEQL */
equal_branch:
- if (regcache_raw_get_signed (regcache, itype_rs (inst)) ==
- regcache_raw_get_signed (regcache, itype_rt (inst)))
- pc += mips32_relative_offset (inst) + 4;
+ pc_adj = mips32_relative_offset (inst);
+ if (pc_adj
+ && (regcache_raw_get_signed (regcache, itype_rs (inst))
+ == regcache_raw_get_signed (regcache, itype_rt (inst))))
+ pc += pc_adj + 4;
else
pc += 8;
break;
case 5: /* BNE, BNEL */
neq_branch:
- if (regcache_raw_get_signed (regcache, itype_rs (inst)) !=
- regcache_raw_get_signed (regcache, itype_rt (inst)))
- pc += mips32_relative_offset (inst) + 4;
+ pc_adj = mips32_relative_offset (inst);
+ if (pc_adj
+ && (regcache_raw_get_signed (regcache, itype_rs (inst))
+ != regcache_raw_get_signed (regcache, itype_rt (inst))))
+ pc += pc_adj + 4;
else
pc += 8;
break;
case 6: /* BLEZ, BLEZL */
less_equal_branch:
- if (regcache_raw_get_signed (regcache, itype_rs (inst)) <= 0)
- pc += mips32_relative_offset (inst) + 4;
+ pc_adj = mips32_relative_offset (inst);
+ if (pc_adj
+ && regcache_raw_get_signed (regcache, itype_rs (inst)) <= 0)
+ pc += pc_adj + 4;
else
pc += 8;
break;
case 7: /* BGTZ, BGTZL */
default:
greater_branch:
- if (regcache_raw_get_signed (regcache, itype_rs (inst)) > 0)
- pc += mips32_relative_offset (inst) + 4;
+ pc_adj = mips32_relative_offset (inst);
+ if (pc_adj
+ && regcache_raw_get_signed (regcache, itype_rs (inst)) > 0)
+ pc += pc_adj + 4;
else
pc += 8;
break;
@@ -1887,6 +1914,7 @@ micromips_bc1_pc (struct gdbarch *gdbarc
int cnum = b2s3_cc (insn >> 16) & (count - 1);
int tf = b5s5_op (insn >> 16) & 1;
int mask = (1 << count) - 1;
+ CORE_ADDR pc_adj;
ULONGEST fcs;
int cond;
@@ -1897,8 +1925,9 @@ micromips_bc1_pc (struct gdbarch *gdbarc
fcs = regcache_raw_get_unsigned (regcache, fcsr);
cond = ((fcs >> 24) & 0xfe) | ((fcs >> 23) & 0x01);
- if (((cond >> cnum) & mask) != mask * !tf)
- pc += micromips_relative_offset16 (insn);
+ pc_adj = micromips_relative_offset16 (insn);
+ if (pc_adj && ((cond >> cnum) & mask) != mask * !tf)
+ pc += pc_adj;
else
pc += micromips_pc_insn_size (gdbarch, pc);
@@ -1912,6 +1941,7 @@ static CORE_ADDR
micromips_next_pc (struct regcache *regcache, CORE_ADDR pc)
{
struct gdbarch *gdbarch = regcache->arch ();
+ CORE_ADDR pc_adj;
ULONGEST insn;
insn = mips_fetch_instruction (gdbarch, ISA_MICROMIPS, pc, NULL);
@@ -1935,8 +1965,12 @@ micromips_next_pc (struct regcache *regc
case 0x7c: /* JALR.HB: 000000 0001111100 111100 */
case 0x13c: /* JALRS: 000000 0100111100 111100 */
case 0x17c: /* JALRS.HB: 000000 0101111100 111100 */
- pc = regcache_raw_get_signed (regcache,
- b0s5_reg (insn >> 16));
+ pc_adj = regcache_raw_get_signed (regcache,
+ b0s5_reg (insn >> 16));
+ if (pc_adj != pc)
+ pc = pc_adj;
+ else
+ pc += micromips_pc_insn_size (gdbarch, pc);;
break;
case 0x22d: /* SYSCALL: 000000 1000101101 111100 */
{
@@ -1958,9 +1992,11 @@ micromips_next_pc (struct regcache *regc
case 0x00: /* BLTZ: bits 010000 00000 */
case 0x01: /* BLTZAL: bits 010000 00001 */
case 0x11: /* BLTZALS: bits 010000 10001 */
- if (regcache_raw_get_signed (regcache,
- b0s5_reg (insn >> 16)) < 0)
- pc += micromips_relative_offset16 (insn);
+ pc_adj = micromips_relative_offset16 (insn);
+ if (pc_adj
+ && regcache_raw_get_signed (regcache,
+ b0s5_reg (insn >> 16)) < 0)
+ pc += pc_adj;
else
pc += micromips_pc_insn_size (gdbarch, pc);
break;
@@ -1968,17 +2004,21 @@ micromips_next_pc (struct regcache *regc
case 0x02: /* BGEZ: bits 010000 00010 */
case 0x03: /* BGEZAL: bits 010000 00011 */
case 0x13: /* BGEZALS: bits 010000 10011 */
- if (regcache_raw_get_signed (regcache,
- b0s5_reg (insn >> 16)) >= 0)
- pc += micromips_relative_offset16 (insn);
+ pc_adj = micromips_relative_offset16 (insn);
+ if (pc_adj
+ && regcache_raw_get_signed (regcache,
+ b0s5_reg (insn >> 16)) >= 0)
+ pc += pc_adj;
else
pc += micromips_pc_insn_size (gdbarch, pc);
break;
case 0x04: /* BLEZ: bits 010000 00100 */
- if (regcache_raw_get_signed (regcache,
- b0s5_reg (insn >> 16)) <= 0)
- pc += micromips_relative_offset16 (insn);
+ pc_adj = micromips_relative_offset16 (insn);
+ if (pc_adj
+ && regcache_raw_get_signed (regcache,
+ b0s5_reg (insn >> 16)) <= 0)
+ pc += pc_adj;
else
pc += micromips_pc_insn_size (gdbarch, pc);
break;
@@ -1990,9 +2030,11 @@ micromips_next_pc (struct regcache *regc
break;
case 0x06: /* BGTZ: bits 010000 00110 */
- if (regcache_raw_get_signed (regcache,
- b0s5_reg (insn >> 16)) > 0)
- pc += micromips_relative_offset16 (insn);
+ pc_adj = micromips_relative_offset16 (insn);
+ if (pc_adj
+ && regcache_raw_get_signed (regcache,
+ b0s5_reg (insn >> 16)) > 0)
+ pc += pc_adj;
else
pc += micromips_pc_insn_size (gdbarch, pc);
break;
@@ -2020,9 +2062,11 @@ micromips_next_pc (struct regcache *regc
/* No way to handle; it'll most likely trap anyway. */
break;
- if ((regcache_raw_get_unsigned (regcache,
- dspctl) & 0x7f) >= pos)
- pc += micromips_relative_offset16 (insn);
+ pc_adj = micromips_relative_offset16 (insn);
+ if (pc_adj
+ && (regcache_raw_get_unsigned (regcache,
+ dspctl) & 0x7f) >= pos)
+ pc += pc_adj;
else
pc += micromips_pc_insn_size (gdbarch, pc);
}
@@ -2048,21 +2092,29 @@ micromips_next_pc (struct regcache *regc
case 0x1d: /* JALS: bits 011101 */
case 0x35: /* J: bits 110101 */
case 0x3d: /* JAL: bits 111101 */
- pc = ((pc | 0x7fffffe) ^ 0x7fffffe) | (b0s26_imm (insn) << 1);
+ pc_adj = ((pc | 0x7fffffe) ^ 0x7fffffe) | (b0s26_imm (insn) << 1);
+ if (pc_adj != pc)
+ pc = pc_adj;
+ else
+ pc += micromips_pc_insn_size (gdbarch, pc);;
break;
case 0x25: /* BEQ: bits 100101 */
- if (regcache_raw_get_signed (regcache, b0s5_reg (insn >> 16))
- == regcache_raw_get_signed (regcache, b5s5_reg (insn >> 16)))
- pc += micromips_relative_offset16 (insn);
+ pc_adj = micromips_relative_offset16 (insn);
+ if (pc_adj
+ && (regcache_raw_get_signed (regcache, b0s5_reg (insn >> 16))
+ == regcache_raw_get_signed (regcache, b5s5_reg (insn >> 16))))
+ pc += pc_adj;
else
pc += micromips_pc_insn_size (gdbarch, pc);
break;
case 0x2d: /* BNE: bits 101101 */
- if (regcache_raw_get_signed (regcache, b0s5_reg (insn >> 16))
- != regcache_raw_get_signed (regcache, b5s5_reg (insn >> 16)))
- pc += micromips_relative_offset16 (insn);
+ pc_adj = micromips_relative_offset16 (insn);
+ if (pc_adj
+ && (regcache_raw_get_signed (regcache, b0s5_reg (insn >> 16))
+ != regcache_raw_get_signed (regcache, b5s5_reg (insn >> 16))))
+ pc += pc_adj;
else
pc += micromips_pc_insn_size (gdbarch, pc);
break;
@@ -2078,20 +2130,33 @@ micromips_next_pc (struct regcache *regc
switch (micromips_op (insn))
{
case 0x11: /* POOL16C: bits 010001 */
- if ((b5s5_op (insn) & 0x1c) == 0xc)
- /* JR16, JRC, JALR16, JALRS16: 010001 011xx */
- pc = regcache_raw_get_signed (regcache, b0s5_reg (insn));
- else if (b5s5_op (insn) == 0x18)
- /* JRADDIUSP: bits 010001 11000 */
- pc = regcache_raw_get_signed (regcache, MIPS_RA_REGNUM);
+ switch (b5s5_op (insn))
+ {
+ case 0x0c: /* JR16: bits 010001 01100 */
+ case 0x0e: /* JALR16: bits 010001 01110 */
+ case 0x0f: /* JALRS16: bits 010001 01111 */
+ pc_adj = regcache_raw_get_signed (regcache, b0s5_reg (insn));
+ if (pc_adj != pc)
+ pc = pc_adj;
+ else
+ pc += micromips_pc_insn_size (gdbarch, pc);;
+ break;
+ case 0x0d: /* JRC: bits 010001 01101 */
+ pc = regcache_raw_get_signed (regcache, b0s5_reg (insn));
+ break;
+ case 0x18: /* JRADDIUSP: bits 010001 11000 */
+ pc = regcache_raw_get_signed (regcache, MIPS_RA_REGNUM);
+ break;
+ }
break;
case 0x23: /* BEQZ16: bits 100011 */
{
int rs = mips_reg3_to_reg[b7s3_reg (insn)];
- if (regcache_raw_get_signed (regcache, rs) == 0)
- pc += micromips_relative_offset7 (insn);
+ pc_adj = micromips_relative_offset7 (insn);
+ if (pc_adj && regcache_raw_get_signed (regcache, rs) == 0)
+ pc += pc_adj;
else
pc += micromips_pc_insn_size (gdbarch, pc);
}
@@ -2101,15 +2166,20 @@ micromips_next_pc (struct regcache *regc
{
int rs = mips_reg3_to_reg[b7s3_reg (insn)];
- if (regcache_raw_get_signed (regcache, rs) != 0)
- pc += micromips_relative_offset7 (insn);
+ pc_adj = micromips_relative_offset7 (insn);
+ if (pc_adj && regcache_raw_get_signed (regcache, rs) != 0)
+ pc += pc_adj;
else
pc += micromips_pc_insn_size (gdbarch, pc);
}
break;
case 0x33: /* B16: bits 110011 */
- pc += micromips_relative_offset10 (insn);
+ pc_adj = micromips_relative_offset10 (insn);
+ if (pc_adj)
+ pc += pc_adj;
+ else
+ pc += micromips_pc_insn_size (gdbarch, pc);;
break;
}
break;
@@ -2278,12 +2348,25 @@ add_offset_16 (CORE_ADDR pc, int offset)
return pc + (offset << 1) + 2;
}
+/* Return the size in bytes of the MIPS16 instruction at the address PC. */
+
+static int
+mips16_pc_insn_size (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ ULONGEST insn;
+
+ insn = mips_fetch_instruction (gdbarch, ISA_MIPS16, pc, NULL);
+ return mips_insn_size (ISA_MIPS16, insn);
+}
+
static CORE_ADDR
extended_mips16_next_pc (regcache *regcache, CORE_ADDR pc,
unsigned int extension, unsigned int insn)
{
struct gdbarch *gdbarch = regcache->arch ();
int op = (insn >> 11);
+ CORE_ADDR pc_adj;
+
switch (op)
{
case 2: /* Branch */
@@ -2298,11 +2381,13 @@ extended_mips16_next_pc (regcache *regca
{
struct upk_mips16 upk;
unpack_mips16 (gdbarch, pc, extension, insn, jalxtype, &upk);
- pc = ((pc + 4) & (~(CORE_ADDR) 0x0fffffff)) | (upk.offset << 2);
+ pc_adj = ((pc + 4) & (~(CORE_ADDR) 0x0fffffff)) | (upk.offset << 2);
if ((insn >> 10) & 0x01) /* Exchange mode */
- pc = pc & ~0x01; /* Clear low bit, indicate 32 bit mode. */
+ pc = pc_adj & ~0x01; /* Clear low bit, indicate 32 bit mode. */
+ else if ((pc_adj | 0x01) != pc + 4)
+ pc = pc_adj | 0x01;
else
- pc |= 0x01;
+ pc += 4 + mips16_pc_insn_size (gdbarch, pc + 4);
break;
}
case 4: /* beqz */
@@ -2358,7 +2443,11 @@ extended_mips16_next_pc (regcache *regca
reg = mips_reg3_to_reg[upk.regx];
else
reg = 31; /* Function return instruction. */
- pc = regcache_raw_get_signed (regcache, reg);
+ pc_adj = regcache_raw_get_signed (regcache, reg);
+ if ((insn >> 7) & 0x01 || pc_adj != pc + 2)
+ pc = pc_adj;
+ else
+ pc += 2 + mips16_pc_insn_size (gdbarch, pc + 2);
}
else
pc += 2;
Index: binutils-gdb/gdb/testsuite/gdb.arch/micromips-branch-delay.c
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/testsuite/gdb.arch/micromips-branch-delay.c
@@ -0,0 +1,89 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright (C) 2026 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 usefu,
+ 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 single-stepping through microMIPS branch and jump instructions
+ to their delay slot. */
+
+int
+test_micromips_branch_delay (void)
+{
+ /* Make 'err' available to the debugger to track the number of single
+ steps executed. Use `volatile' to prevent the variable from being
+ optimized away. */
+ volatile int err = -1;
+
+ int mone = -1;
+ int zero = 0;
+
+ extern const char jr_one asm("jr_one");
+ extern const char jr_two asm("jr_two");
+ extern const char jr_thr asm("jr_thr");
+ extern const char jr_for asm("jr_for");
+
+ asm volatile (
+ ".macro b_test op, args:vararg\n\t"
+ ".ifb \\args\n\t"
+ "\\op 0f\n\t"
+ ".else\n\t"
+ "\\op \\args, 0f\n\t"
+ ".endif\n\t"
+ "0:\n\t"
+ " nop\n\t"
+ ".endm\n\t"
+
+ ".macro j_test op, reg, label\n\t"
+ "\\op \\reg\n\t"
+ ".globl \\label\n\t"
+ ".type \\label, @function\n"
+ "\\label:\n\t"
+ " nop\n\t"
+ ".endm\n\t"
+
+ ".set push\n\t"
+ ".set noreorder\n\t"
+ ".globl step_start\n\t"
+ ".type step_start, @function\n"
+ "step_start:\n\t" /* Units: steps. */
+ "nop\n\t" /* NOP: 1s */
+ "b_test b16\n\t" /* Taken: 1s */
+ "b_test beqz16, %[zero]\n\t" /* Taken: 1s */
+ "b_test bnez16, %[mone]\n\t" /* Taken: 1s */
+ "b_test bltzals, %[mone]\n\t" /* Taken: 1s */
+ "b_test bgezals, %[zero]\n\t" /* Taken: 1s */
+ "j_test jalr16, %[jr_one], jr_one\n\t" /* Taken: 1s */
+ "j_test jalrs16, %[jr_two], jr_two\n\t" /* Taken: 1s */
+ "j_test jalrs, %[jr_thr], jr_thr\n\t" /* Taken: 1s */
+ "j_test jalrs.hb, %[jr_for], jr_for\n\t" /* Taken: 1s */
+ "nop\n\t" /* NOP: 1s */
+ ".globl step_stop\n\t" /* Total: 11s */
+ ".type step_stop, @function\n"
+ "step_stop:\n\t"
+ ".set pop\n"
+ :
+ : [mone] "r" (mone), [zero] "r" (zero)
+ [jr_one] "r" (&jr_one), [jr_two] "r" (&jr_two),
+ [jr_thr] "r" (&jr_thr), [jr_for] "r" (&jr_for)
+ : "$31");
+
+ return err;
+}
+
+int
+main (void)
+{
+ return test_micromips_branch_delay ();
+}
Index: binutils-gdb/gdb/testsuite/gdb.arch/micromips-branch-delay.exp
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/testsuite/gdb.arch/micromips-branch-delay.exp
@@ -0,0 +1,31 @@
+# Copyright (C) 2026 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 single-stepping through microMIPS branch and jump instructions
+# to their delay slot.
+
+require {istarget "mips*-*-*"}
+
+source $srcdir/$subdir/mips-allow.exp.tcl
+
+require allow_micromips_ase_tests
+
+standard_testfile
+
+set steps 11
+foreach flag {-Wa,-W -mno-mips16 -mmicromips -minterlink-compressed} {
+ lappend compile_flags "additional_flags=$flag"
+}
+source $srcdir/$subdir/mips-stepi.exp.tcl
Index: binutils-gdb/gdb/testsuite/gdb.arch/micromips-jals-delay.c
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/testsuite/gdb.arch/micromips-jals-delay.c
@@ -0,0 +1,56 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright (C) 2026 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 usefu,
+ 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 single-stepping through microMIPS JALS to its delay slot. */
+
+int
+test_micromips_jals (void)
+{
+ /* Make 'err' available to the debugger to track the number of single
+ steps executed. Use `volatile' to prevent the variable from being
+ optimized away. */
+ volatile int err = -1;
+
+ asm volatile (
+ ".macro j_test op\n\t"
+ "\\op 0f\n"
+ "0:\n\t"
+ " nop\n\t"
+ ".endm\n\t"
+
+ ".set push\n\t"
+ ".set noreorder\n\t"
+ ".globl step_start\n\t"
+ ".type step_start, @function\n"
+ "step_start:\n\t" /* Units: steps. */
+ "nop\n\t" /* NOP: 1s */
+ "j_test jals\n\t" /* Taken: 1s */
+ "nop\n\t" /* NOP: 1s */
+ ".globl step_stop\n\t" /* Total: 3s */
+ ".type step_stop, @function\n"
+ "step_stop:\n\t"
+ ".set pop\n"
+ : : : "$31");
+
+ return err;
+}
+
+int
+main (void)
+{
+ return test_micromips_jals ();
+}
Index: binutils-gdb/gdb/testsuite/gdb.arch/micromips-jals-delay.exp
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/testsuite/gdb.arch/micromips-jals-delay.exp
@@ -0,0 +1,30 @@
+# Copyright (C) 2026 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 single-stepping through microMIPS JALS to its delay slot.
+
+require {istarget "mips*-*-*"}
+
+source $srcdir/$subdir/mips-allow.exp.tcl
+
+require allow_micromips_jals_tests
+
+standard_testfile
+
+set steps 3
+foreach flag {-Wa,-W -mno-mips16 -mmicromips -minterlink-compressed} {
+ lappend compile_flags "additional_flags=$flag"
+}
+source $srcdir/$subdir/mips-stepi.exp.tcl
Index: binutils-gdb/gdb/testsuite/gdb.arch/mips-allow.exp.tcl
===================================================================
--- binutils-gdb.orig/gdb/testsuite/gdb.arch/mips-allow.exp.tcl
+++ binutils-gdb/gdb/testsuite/gdb.arch/mips-allow.exp.tcl
@@ -15,6 +15,37 @@
# Feature availability check helpers for MIPS tests.
+# Check for JAL machine instruction support.
+#
+# The regular MIPS and microMIPS JAL assembly instruction is always
+# a macro, however in the non-PIC assembly mode it produces a single
+# machine instruction. In PIC/PIE assembly modes it expands to a PIC
+# call sequence using JALR instead. Make sure an actual JAL machine
+# instruction is produced and no macro expanded.
+#
+# MIPS16 JAL requires its jump target to be 32-bit aligned, so use
+# `.align' to satisfy this constraint.
+proc allow_mips_jal_tests {} {
+ return [allow_target_tests "allow_mips_jal_tests" \
+ "MIPS JAL support" "Segmentation fault" \
+ {
+ int main() {
+ asm volatile (
+ ".set push\n\t"
+ ".set noreorder\n\t"
+ ".set nomacro\n\t"
+ "jal 0f\n\t"
+ " nop\n\t"
+ ".align 2\n"
+ "0:\n\t"
+ ".set pop\n"
+ : : : "$31");
+ return 0;
+ }
+ } \
+ {-Wa,-fatal-warnings}]
+}
+
# Check for MIPS I branch support. These instructions may be absent,
# such as with MIPS16 compilations. Make sure an actual BLTZ machine
# instruction is produced and no macro expanded.
@@ -151,5 +182,32 @@ proc allow_micromips_ase_tests {} {
return 0;
}
} \
+ {-Wa,-fatal-warnings -mno-mips16 -mmicromips -minterlink-compressed}]
+}
+
+# Check for microMIPS JALS machine instruction support.
+#
+# The microMIPS JALS assembly instruction is always a macro, however
+# in the non-PIC assembly mode it produces a single machine instruction.
+# In PIC/PIE assembly modes it expands to a PIC call sequence using
+# JALRS instead. Make sure an actual JALS machine instruction is
+# produced and no macro expanded.
+proc allow_micromips_jals_tests {} {
+ return [allow_target_tests "allow_mips_jals_tests" \
+ "microMIPS JALS support" "Segmentation fault" \
+ {
+ int main() {
+ asm volatile (
+ ".set push\n\t"
+ ".set noreorder\n\t"
+ ".set nomacro\n\t"
+ "jals 0f\n\t"
+ " nop\n\t"
+ "0:\n\t"
+ ".set pop\n"
+ : : : "$31");
+ return 0;
+ }
+ } \
{-Wa,-fatal-warnings -mno-mips16 -mmicromips -minterlink-compressed}]
}
Index: binutils-gdb/gdb/testsuite/gdb.arch/mips-dsp-branch-delay.c
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/testsuite/gdb.arch/mips-dsp-branch-delay.c
@@ -0,0 +1,62 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright (C) 2026 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 usefu,
+ 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 single-stepping through MIPS DSP branch instructions
+ to their delay slot. */
+
+int
+test_mips_dsp_branch_delay (void)
+{
+ /* Make 'err' available to the debugger to track the number of single
+ steps executed. Use `volatile' to prevent the variable from being
+ optimized away. */
+ volatile int err = -1;
+
+ int thr_two = 32;
+
+ asm volatile (
+ ".macro b_test op\n\t"
+ "\\op 0f\n"
+ "0:\n\t"
+ " nop\n\t"
+ ".endm\n\t"
+
+ ".set push\n\t"
+ ".set noreorder\n\t"
+ ".globl step_start\n\t"
+ ".type step_start, @function\n"
+ "step_start:\n\t" /* Units: steps. */
+ "nop\n\t" /* NOP: 1s */
+ "wrdsp %[thr_two], 1\n\t" /* WRDSP: 1s */
+ "b_test bposge32\n\t" /* Taken: 1s */
+ "nop\n\t" /* NOP: 1s */
+ ".globl step_stop\n\t" /* Total: 4s */
+ ".type step_stop, @function\n"
+ "step_stop:\n\t"
+ ".set pop\n"
+ :
+ : [thr_two] "r" (thr_two)
+ : "$dsp_po");
+
+ return err;
+}
+
+int
+main (void)
+{
+ return test_mips_dsp_branch_delay ();
+}
Index: binutils-gdb/gdb/testsuite/gdb.arch/mips-dsp-branch-delay.exp
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/testsuite/gdb.arch/mips-dsp-branch-delay.exp
@@ -0,0 +1,31 @@
+# Copyright (C) 2026 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 single-stepping through MIPS DSP branch instructions
+# to their delay slot.
+
+require {istarget "mips*-*-*"}
+
+source $srcdir/$subdir/mips-allow.exp.tcl
+
+require allow_mips_dsp_ase_tests
+
+standard_testfile
+
+set steps 4
+foreach flag {-mno-mips16 -minterlink-compressed -mdsp} {
+ lappend compile_flags "additional_flags=$flag"
+}
+source $srcdir/$subdir/mips-stepi.exp.tcl
Index: binutils-gdb/gdb/testsuite/gdb.arch/mips-jal-delay.c
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/testsuite/gdb.arch/mips-jal-delay.c
@@ -0,0 +1,60 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright (C) 2026 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 usefu,
+ 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 single-stepping through JAL to its delay slot. */
+
+int
+test_mips_jal (void)
+{
+ /* Make 'err' available to the debugger to track the number of single
+ steps executed. Use `volatile' to prevent the variable from being
+ optimized away. */
+ volatile int err = -1;
+
+ /* MIPS16 JAL requires its jump target to be 32-bit aligned, so use
+ `.align' and two leading NOP instructions to meet this constraint. */
+ asm volatile (
+ ".macro j_test op\n\t"
+ "\\op 0f\n"
+ "0:\n\t"
+ " nop\n\t"
+ ".endm\n\t"
+
+ ".set push\n\t"
+ ".set noreorder\n\t"
+ ".align 2\n\t"
+ ".globl step_start\n\t"
+ ".type step_start, @function\n"
+ "step_start:\n\t" /* Units: steps. */
+ "nop\n\t" /* NOP: 1s */
+ "nop\n\t" /* NOP: 1s */
+ "j_test jal\n\t" /* Taken: 1s */
+ "nop\n\t" /* NOP: 1s */
+ ".globl step_stop\n\t" /* Total: 4s */
+ ".type step_stop, @function\n"
+ "step_stop:\n\t"
+ ".set pop\n"
+ : : : "$31");
+
+ return err;
+}
+
+int
+main (void)
+{
+ return test_mips_jal ();
+}
Index: binutils-gdb/gdb/testsuite/gdb.arch/mips-jal-delay.exp
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/testsuite/gdb.arch/mips-jal-delay.exp
@@ -0,0 +1,27 @@
+# Copyright (C) 2026 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 single-stepping through JAL to its delay slot.
+
+require {istarget "mips*-*-*"}
+
+source $srcdir/$subdir/mips-allow.exp.tcl
+
+require allow_mips_jal_tests
+
+standard_testfile
+
+set steps 4
+source $srcdir/$subdir/mips-stepi.exp.tcl
Index: binutils-gdb/gdb/testsuite/gdb.arch/mips-jr-delay.c
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/testsuite/gdb.arch/mips-jr-delay.c
@@ -0,0 +1,64 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright (C) 2026 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 usefu,
+ 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 single-stepping through JR to its delay slot. */
+
+int
+test_mips_jr (void)
+{
+ /* Make 'err' available to the debugger to track the number of single
+ steps executed. Use `volatile' to prevent the variable from being
+ optimized away. */
+ volatile int err = -1;
+
+ extern const char jr_one asm("jr_one");
+ extern const char jr_two asm("jr_two");
+
+ asm volatile (
+ ".macro j_test op, reg, label\n\t"
+ "\\op \\reg\n\t"
+ ".globl \\label\n\t"
+ ".type \\label, @function\n"
+ "\\label:\n\t"
+ " nop\n\t"
+ ".endm\n\t"
+
+ ".set push\n\t"
+ ".set noreorder\n\t"
+ ".globl step_start\n\t"
+ ".type step_start, @function\n"
+ "step_start:\n\t" /* Units: steps. */
+ "nop\n\t" /* NOP: 1s */
+ "j_test jr, %[jr_one], jr_one\n\t" /* Taken: 1s */
+ "j_test jalr, %[jr_two], jr_two\n\t" /* Taken: 1s */
+ "nop\n\t" /* NOP: 1s */
+ ".globl step_stop\n\t" /* Total: 4s */
+ ".type step_stop, @function\n"
+ "step_stop:\n\t"
+ ".set pop\n"
+ :
+ : [jr_one] "r" (&jr_one), [jr_two] "r" (&jr_two)
+ : "$31");
+
+ return err;
+}
+
+int
+main (void)
+{
+ return test_mips_jr ();
+}
Index: binutils-gdb/gdb/testsuite/gdb.arch/mips-jr-delay.exp
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/testsuite/gdb.arch/mips-jr-delay.exp
@@ -0,0 +1,23 @@
+# Copyright (C) 2026 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 single-stepping through JR to its delay slot.
+
+require {istarget "mips*-*-*"}
+
+standard_testfile
+
+set steps 4
+source $srcdir/$subdir/mips-stepi.exp.tcl
Index: binutils-gdb/gdb/testsuite/gdb.arch/mips1-bal-delay.c
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/testsuite/gdb.arch/mips1-bal-delay.c
@@ -0,0 +1,63 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright (C) 2026 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 usefu,
+ 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 single-stepping through MIPS I branch-and-link instructions
+ to their delay slot. */
+
+int
+test_mips1_bal_delay (void)
+{
+ /* Make 'err' available to the debugger to track the number of single
+ steps executed. Use `volatile' to prevent the variable from being
+ optimized away. */
+ volatile int err = -1;
+
+ int mone = -1;
+ int zero = 0;
+
+ asm volatile (
+ ".macro b_test op, args:vararg\n\t"
+ "\\op \\args, 0f\n"
+ "0:\n\t"
+ " nop\n\t"
+ ".endm\n\t"
+
+ ".set push\n\t"
+ ".set noreorder\n\t"
+ ".globl step_start\n\t"
+ ".type step_start, @function\n"
+ "step_start:\n\t" /* Units: steps. */
+ "nop\n\t" /* NOP: 1s */
+ "b_test bltzal, %[mone]\n\t" /* Taken: 1s */
+ "b_test bgezal, %[zero]\n\t" /* Taken: 1s */
+ "nop\n\t" /* NOP: 1s */
+ ".globl step_stop\n\t" /* Total: 4s */
+ ".type step_stop, @function\n"
+ "step_stop:\n\t"
+ ".set pop\n"
+ :
+ : [mone] "r" (mone), [zero] "r" (zero)
+ : "$31");
+
+ return err;
+}
+
+int
+main (void)
+{
+ return test_mips1_bal_delay ();
+}
Index: binutils-gdb/gdb/testsuite/gdb.arch/mips1-bal-delay.exp
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/testsuite/gdb.arch/mips1-bal-delay.exp
@@ -0,0 +1,31 @@
+# Copyright (C) 2026 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 single-stepping through MIPS I branch-and-link instructions
+# to their delay slot.
+
+require {istarget "mips*-*-*"}
+
+source $srcdir/$subdir/mips-allow.exp.tcl
+
+require allow_mips1_bal_tests
+
+standard_testfile
+
+set steps 4
+foreach flag {-mno-mips16 -minterlink-compressed} {
+ lappend compile_flags "additional_flags=$flag"
+}
+source $srcdir/$subdir/mips-stepi.exp.tcl
Index: binutils-gdb/gdb/testsuite/gdb.arch/mips1-branch-delay.c
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/testsuite/gdb.arch/mips1-branch-delay.c
@@ -0,0 +1,67 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright (C) 2026 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 usefu,
+ 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 single-stepping through MIPS I branch instructions
+ to their delay slot. */
+
+int
+test_mips1_branch_delay (void)
+{
+ /* Make 'err' available to the debugger to track the number of single
+ steps executed. Use `volatile' to prevent the variable from being
+ optimized away. */
+ volatile int err = -1;
+
+ int mone = -1;
+ int zero = 0;
+ int one = 1;
+
+ asm volatile (
+ ".macro b_test op, args:vararg\n\t"
+ "\\op \\args, 0f\n"
+ "0:\n\t"
+ " nop\n\t"
+ ".endm\n\t"
+
+ ".set push\n\t"
+ ".set noreorder\n\t"
+ ".globl step_start\n\t"
+ ".type step_start, @function\n"
+ "step_start:\n\t" /* Units: steps. */
+ "nop\n\t" /* NOP: 1s */
+ "b_test beq, %[zero], %[zero]\n\t" /* Taken: 1s */
+ "b_test bne, %[mone], %[one]\n\t" /* Taken: 1s */
+ "b_test bltz, %[mone]\n\t" /* Taken: 1s */
+ "b_test blez, %[zero]\n\t" /* Taken: 1s */
+ "b_test bgez, %[zero]\n\t" /* Taken: 1s */
+ "b_test bgtz, %[one]\n\t" /* Taken: 1s */
+ "nop\n\t" /* NOP: 1s */
+ ".globl step_stop\n\t" /* Total: 8s */
+ ".type step_stop, @function\n"
+ "step_stop:\n\t"
+ ".set pop\n"
+ :
+ : [mone] "r" (mone), [zero] "r" (zero), [one] "r" (one));
+
+ return err;
+}
+
+int
+main (void)
+{
+ return test_mips1_branch_delay ();
+}
Index: binutils-gdb/gdb/testsuite/gdb.arch/mips1-branch-delay.exp
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/testsuite/gdb.arch/mips1-branch-delay.exp
@@ -0,0 +1,31 @@
+# Copyright (C) 2026 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 single-stepping through MIPS I branch instructions
+# to their delay slot.
+
+require {istarget "mips*-*-*"}
+
+source $srcdir/$subdir/mips-allow.exp.tcl
+
+require allow_mips1_branch_tests
+
+standard_testfile
+
+set steps 8
+foreach flag {-mno-mips16 -minterlink-compressed} {
+ lappend compile_flags "additional_flags=$flag"
+}
+source $srcdir/$subdir/mips-stepi.exp.tcl
Index: binutils-gdb/gdb/testsuite/gdb.arch/mips2-branch-delay.c
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/testsuite/gdb.arch/mips2-branch-delay.c
@@ -0,0 +1,70 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright (C) 2026 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 single-stepping through MIPS II branch instructions
+ to their delay slot. */
+
+int
+test_mips2_branch_delay (void)
+{
+ /* Make 'err' available to the debugger to track the number of single
+ steps executed. Use `volatile' to prevent the variable from being
+ optimized away. */
+ volatile int err = -1;
+
+ int mone = -1;
+ int zero = 0;
+ int one = 1;
+
+ asm volatile (
+ ".macro b_test op, args:vararg\n\t"
+ "\\op \\args, 0f\n"
+ "0:\n\t"
+ " nop\n\t"
+ ".endm\n\t"
+
+ ".set push\n\t"
+ ".set noreorder\n\t"
+ ".globl step_start\n\t"
+ ".type step_start, @function\n"
+ "step_start:\n\t" /* Units: steps. */
+ "nop\n\t" /* NOP: 1s */
+ "b_test beql, %[zero], %[zero]\n\t" /* Taken: 1s */
+ "b_test bnel, %[mone], %[one]\n\t" /* Taken: 1s */
+ "b_test bltzl, %[mone]\n\t" /* Taken: 1s */
+ "b_test blezl, %[zero]\n\t" /* Taken: 1s */
+ "b_test bgezl, %[zero]\n\t" /* Taken: 1s */
+ "b_test bgtzl, %[one]\n\t" /* Taken: 1s */
+ "b_test bltzall, %[mone]\n\t" /* Taken: 1s */
+ "b_test bgezall, %[zero]\n\t" /* Taken: 1s */
+ "nop\n\t" /* NOP: 1s */
+ ".globl step_stop\n\t" /* Total: 10s */
+ ".type step_stop, @function\n"
+ "step_stop:\n\t"
+ ".set pop\n"
+ :
+ : [mone] "r" (mone), [zero] "r" (zero), [one] "r" (one)
+ : "$31");
+
+ return err;
+}
+
+int
+main (void)
+{
+ return test_mips2_branch_delay ();
+}
Index: binutils-gdb/gdb/testsuite/gdb.arch/mips2-branch-delay.exp
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/testsuite/gdb.arch/mips2-branch-delay.exp
@@ -0,0 +1,31 @@
+# Copyright (C) 2026 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 single-stepping through MIPS II branch instructions
+# to their delay slot.
+
+require {istarget "mips*-*-*"}
+
+source $srcdir/$subdir/mips-allow.exp.tcl
+
+require allow_mips2_branch_tests
+
+standard_testfile
+
+set steps 10
+foreach flag {-mno-mips16 -mno-micromips -minterlink-compressed} {
+ lappend compile_flags "additional_flags=$flag"
+}
+source $srcdir/$subdir/mips-stepi.exp.tcl
prev parent reply other threads:[~2026-08-17 16:56 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-17 16:53 [PATCH v2 00/12] MIPS+testsuite: BLEZL stepping fix and associated test infrastructure Maciej W. Rozycki
2026-08-17 16:53 ` [PATCH v2 01/12] testsuite: Factor out target feature test template Maciej W. Rozycki
2026-08-17 16:53 ` [PATCH v2 02/12] PowerPC/testsuite: Reduce feature tests in terms of `allow_target_tests' Maciej W. Rozycki
2026-08-17 16:53 ` [PATCH v2 03/12] MIPS/testsuite: Verify MIPS I CPU branch stepping Maciej W. Rozycki
2026-08-17 16:53 ` [PATCH v2 04/12] MIPS: Correct BLEZL single-stepping Maciej W. Rozycki
2026-08-17 16:53 ` [PATCH v2 05/12] MIPS/testsuite: Verify MIPS II CPU branch stepping Maciej W. Rozycki
2026-08-17 16:53 ` [PATCH v2 06/12] MIPS/testsuite: Verify MIPS DSP ASE " Maciej W. Rozycki
2026-08-17 16:53 ` [PATCH v2 07/12] MIPS/testsuite: Verify MIPS16 " Maciej W. Rozycki
2026-08-17 16:53 ` [PATCH v2 08/12] MIPS/testsuite: Verify microMIPS " Maciej W. Rozycki
2026-08-17 16:54 ` [PATCH v2 09/12] MIPS: Reorder a reference to "BGTZ, BGTZL" in `mips32_next_pc' Maciej W. Rozycki
2026-08-17 16:54 ` [PATCH v2 10/12] MIPS: Correct segment calculation for MIPS16 JAL/X Maciej W. Rozycki
2026-08-17 16:54 ` [PATCH v2 11/12] MIPS: Return correct size from `mips_insn_size' " Maciej W. Rozycki
2026-08-17 16:54 ` Maciej W. Rozycki [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=alpine.DEB.2.21.2608170042050.14132@angie.orcam.me.uk \
--to=macro@orcam.me.uk \
--cc=Djordje.Todorovic@htecgroup.com \
--cc=gdb-patches@sourceware.org \
--cc=jovan.dmitrovic@htecgroup.com \
--cc=macro@globalfoundries.com \
--cc=milica.matic@htecgroup.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