// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: BSD-3-Clause //go:build linux && riscv64 package debug // Regs holds the full general-purpose register set of a traced process // (the Linux riscv64 user_regs_struct layout). type Regs struct { PC uint64 Ra uint64 // x1 (return address) Sp uint64 // x2 Gp uint64 // x3 Tp uint64 // x4 T0 uint64 // x5 T1 uint64 // x6 T2 uint64 // x7 S0 uint64 // x8 (frame pointer) S1 uint64 // x9 A0 uint64 // x10 A1 uint64 // x11 A2 uint64 // x12 A3 uint64 // x13 A4 uint64 // x14 A5 uint64 // x15 A6 uint64 // x16 A7 uint64 // x17 S2 uint64 // x18 S3 uint64 // x19 S4 uint64 // x20 S5 uint64 // x21 S6 uint64 // x22 S7 uint64 // x23 S8 uint64 // x24 S9 uint64 // x25 S10 uint64 // x26 S11 uint64 // x27 T3 uint64 // x28 T4 uint64 // x29 T5 uint64 // x30 T6 uint64 // x31 } // GetPC returns the program counter. func (r *Regs) GetPC() uint64 { return r.PC } // SetPC sets the program counter. func (r *Regs) SetPC(pc uint64) { r.PC = pc } // GetSP returns the stack pointer. func (r *Regs) GetSP() uint64 { return r.Sp } // RegValue returns the value of the named register, or false if unknown. func (r *Regs) RegValue(name string) (uint64, bool) { switch name { case "pc": return r.PC, true case "ra", "x1": return r.Ra, true case "sp", "x2": return r.Sp, true case "gp", "x3": return r.Gp, true case "tp", "x4": return r.Tp, true case "t0", "x5": return r.T0, true case "t1", "x6": return r.T1, true case "t2", "x7": return r.T2, true case "s0", "fp", "x8": return r.S0, true case "s1", "x9": return r.S1, true case "a0", "x10": return r.A0, true case "a1", "x11": return r.A1, true case "a2", "x12": return r.A2, true case "a3", "x13": return r.A3, true case "a4", "x14": return r.A4, true case "a5", "x15": return r.A5, true case "a6", "x16": return r.A6, true case "a7", "x17": return r.A7, true case "s2", "x18": return r.S2, true case "s3", "x19": return r.S3, true case "s4", "x20": return r.S4, true case "s5", "x21": return r.S5, true case "s6", "x22": return r.S6, true case "s7", "x23": return r.S7, true case "s8", "x24": return r.S8, true case "s9", "x25": return r.S9, true case "s10", "x26": return r.S10, true case "s11", "x27": return r.S11, true case "t3", "x28": return r.T3, true case "t4", "x29": return r.T4, true case "t5", "x30": return r.T5, true case "t6", "x31": return r.T6, true default: return 0, false } } // breakpointInsn is the software breakpoint instruction (EBREAK). var breakpointInsn = []byte{0x73, 0x00, 0x10, 0x00} // ebreak // breakpointPCAdjust is how far PC is past the breakpoint instruction after // a trap: 0, because the kernel delivers the EBREAK SIGTRAP with sepc still // on the ebreak. handle_break passes regs->epc straight to // force_sig_fault(SIGTRAP, TRAP_BRKPT, ...) and only the kernel-internal // WARN/CFI paths advance epc (arch/riscv/kernel/traps.c). const breakpointPCAdjust = 0