[PATCH] RISC-V: Add software single step support for cm.popret[z]
Kito Cheng
kito.cheng@gmail.com
Thu May 15 09:18:35 GMT 2025
this should be send to gdb-patches@sourceware.org rather than
binutils@sourceware.org
On Thu, May 15, 2025 at 5:17 PM Songhe Zhu <zhusonghe@eswincomputing.com> wrote:
>
> From: zhusonghe <zhusonghe@eswincomputing.com>
>
> The Linux GDB build configures gdbarch_software_single_step_p() = 1,
> indicating that software single-stepping is enabled while hardware
> single-stepping is disabled. According to the RISC-V Zc Specification v1.0.4-3,
> instructions like cm.popret[z] require precise control flow handling.
> When single-stepping through these instructions, the Program Counter (PC)
> must be explicitly updated to maintain correct execution flow.
>
> Passing riscv-gnu-toolchain regressions.
>
> Signed-off-by: Songhe Zhu <zhusonghe@eswincomputing.com>
> Co-Authored by: Fei Gao <gaofei@eswincomputing.com>
>
> gdb/ChangeLog:
>
> * riscv-tdep.c (ROUND_UP): New.
> (zcmp_base_adj): Compute stack_adj_base.
> (zcmp_rlist_regcounts): Through reg_list, compute reg counts.
> (class riscv_insn): Add support for cm.popret[z] opcodes.
> (riscv_insn::decode): Ditto.
> (riscv_next_pc): Add support cm.popret[z] function.
> ---
> gdb/riscv-tdep.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 54 insertions(+)
>
> diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
> index 8998a297315..fa9fef44723 100644
> --- a/gdb/riscv-tdep.c
> +++ b/gdb/riscv-tdep.c
> @@ -66,6 +66,9 @@
> /* The biggest alignment that the target supports. */
> #define BIGGEST_ALIGNMENT 16
>
> +/* This macro rounds x up to the y boundary. */
> +#define ROUND_UP(x,y) (((x) + (y) - 1) & ~((y) - 1))
> +
> /* Define a series of is_XXX_insn functions to check if the value INSN
> is an instance of instruction XXX. */
> #define DECLARE_INSN(INSN_NAME, INSN_MATCH, INSN_MASK) \
> @@ -774,6 +777,20 @@ show_riscv_debug_variable (struct ui_file *file, int from_tty,
> c->name, value);
> }
>
> +
> +static int
> +zcmp_base_adj (int word_bytes, int regcounts)
> +{
> + return ROUND_UP(word_bytes * regcounts, 16);
> +}
> +
> + /* According to zcmp rlist field caculate register counts. */
> +static int
> +zcmp_rlist_regcounts (int rlist)
> +{
> + return (rlist == 15 ? rlist - 2 : rlist - 3);
> +}
> +
> /* See riscv-tdep.h. */
>
> int
> @@ -1593,6 +1610,8 @@ class riscv_insn
> BGE,
> BLTU,
> BGEU,
> + CM_POPRET,
> + CM_POPRETZ,
> /* These are needed for stepping over atomic sequences. */
> SLTI,
> SLTIU,
> @@ -1691,6 +1710,12 @@ class riscv_insn
> return ((opcode >> offset) & 0x7) + 8;
> }
>
> + /* Extract 4 bit rlist field at OFFSET from instruction OPCODE. */
> + int decode_rlist (unsigned long opcode, int offset)
> + {
> + return (opcode >> offset) & 0xF;
> + }
> +
> /* Helper for DECODE, decode 32-bit R-type instruction. */
> void decode_r_type_insn (enum opcode opcode, ULONGEST ival)
> {
> @@ -1822,6 +1847,13 @@ class riscv_insn
> m_rs2 = decode_register_index_short (ival, OP_SH_CRS2S);
> }
>
> + void decode_zcmp_type_insn (enum opcode opcode, ULONGEST ival)
> + {
> + m_opcode = opcode;
> + m_rs1 = decode_rlist (ival, OP_SH_REG_LIST);
> + m_imm.s = EXTRACT_ZCMP_SPIMM (ival);
> + }
> +
> /* The length of the instruction in bytes. Should be 2 or 4. */
> int m_length;
>
> @@ -2091,6 +2123,10 @@ riscv_insn::decode (struct gdbarch *gdbarch, CORE_ADDR pc)
> decode_ci_type_insn (LD, ival, RISCV_SP_REGNUM);
> else if (is_c_lwsp_insn (ival))
> decode_ci_type_insn (LW, ival, RISCV_SP_REGNUM);
> + else if (is_cm_popret_insn (ival))
> + decode_zcmp_type_insn (CM_POPRET, ival);
> + else if (is_cm_popretz_insn (ival))
> + decode_zcmp_type_insn (CM_POPRETZ, ival);
> else
> /* None of the other fields of INSN are valid in this case. */
> m_opcode = OTHER;
> @@ -4523,6 +4559,24 @@ riscv_next_pc (struct regcache *regcache, CORE_ADDR pc)
> if (tdep->syscall_next_pc != nullptr)
> next_pc = tdep->syscall_next_pc (get_current_frame ());
> }
> + else if ((insn.opcode () == riscv_insn::CM_POPRET)
> + || (insn.opcode () == riscv_insn::CM_POPRETZ))
> + {
> + LONGEST sp;
> + gdb_byte buf[8];
> + int isa_xlen = riscv_isa_xlen (gdbarch);
> + int regcounts = zcmp_rlist_regcounts (insn.rs1 ());
> + int stack_adj_base = zcmp_base_adj (isa_xlen, regcounts);
> + int stack_adj = stack_adj_base + insn.imm_signed ();
> + regcache->cooked_read (RISCV_SP_REGNUM, &sp);
> + enum bfd_endian byte_order = gdbarch_byte_order_for_code (gdbarch);
> + CORE_ADDR ra_addr = sp + stack_adj - isa_xlen * regcounts;
> + int status = target_read_memory (ra_addr, buf, isa_xlen);
> + if (status)
> + memory_error (TARGET_XFER_E_IO, ra_addr);
> + ULONGEST ra_value = extract_unsigned_integer (buf, isa_xlen, byte_order);
> + next_pc = (ra_value) & ~(CORE_ADDR) 0x1;
> + }
>
> return next_pc;
> }
> --
> 2.17.1
>
More information about the Binutils
mailing list