// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: BSD-3-Clause //go:build linux && loong64 package debug // Regs holds the full general-purpose register set of a traced process // (the Linux loong64 user_pt_regs layout). type Regs struct { R0 uint64 // zero R1 uint64 // RA (return address) R2 uint64 // TP (thread pointer) R3 uint64 // SP (stack pointer) R4 uint64 // A0 R5 uint64 // A1 R6 uint64 // A2 R7 uint64 // A3 R8 uint64 // A4 R9 uint64 // A5 R10 uint64 // A6 R11 uint64 // A7 R12 uint64 // T0 R13 uint64 // T1 R14 uint64 // T2 R15 uint64 // T3 R16 uint64 // T4 R17 uint64 // T5 R18 uint64 // T6 R19 uint64 // T7 R20 uint64 // T8 R21 uint64 // FP (frame pointer) R22 uint64 // S0 R23 uint64 // S1 R24 uint64 // S2 R25 uint64 // S3 R26 uint64 // S4 R27 uint64 // S5 R28 uint64 // S6 R29 uint64 // S7 R30 uint64 // S8 R31 uint64 // PC } // GetPC returns the program counter. func (r *Regs) GetPC() uint64 { return r.R31 } // SetPC sets the program counter. func (r *Regs) SetPC(pc uint64) { r.R31 = pc } // GetSP returns the stack pointer. func (r *Regs) GetSP() uint64 { return r.R3 } // RegValue returns the value of the named register, or false if unknown. func (r *Regs) RegValue(name string) (uint64, bool) { switch name { case "r0", "zero": return r.R0, true case "r1", "ra": return r.R1, true case "r2", "tp": return r.R2, true case "r3", "sp": return r.R3, true case "r4", "a0": return r.R4, true case "r5", "a1": return r.R5, true case "r6", "a2": return r.R6, true case "r7", "a3": return r.R7, true case "r8", "a4": return r.R8, true case "r9", "a5": return r.R9, true case "r10", "a6": return r.R10, true case "r11", "a7": return r.R11, true case "r12", "t0": return r.R12, true case "r13", "t1": return r.R13, true case "r14", "t2": return r.R14, true case "r15", "t3": return r.R15, true case "r16", "t4": return r.R16, true case "r17", "t5": return r.R17, true case "r18", "t6": return r.R18, true case "r19", "t7": return r.R19, true case "r20", "t8": return r.R20, true case "r21", "fp": return r.R21, true case "r22", "s0": return r.R22, true case "r23", "s1": return r.R23, true case "r24", "s2": return r.R24, true case "r25", "s3": return r.R25, true case "r26", "s4": return r.R26, true case "r27", "s5": return r.R27, true case "r28", "s6": return r.R28, true case "r29", "s7": return r.R29, true case "r30", "s8": return r.R30, true case "r31", "pc": return r.R31, true default: return 0, false } } // breakpointInsn is the software breakpoint instruction (BRK $0). var breakpointInsn = []byte{0x05, 0x00, 0x2a, 0x00} // break 0 // breakpointPCAdjust is how far PC is past the breakpoint instruction after // a trap: 0, because the kernel delivers the break SIGTRAP with csr_era // still on the break instruction. do_bp passes regs->csr_era straight to // force_sig_fault(SIGTRAP, TRAP_BRKPT, ...) and never adjusts era on the // signal path (arch/loongarch/kernel/traps.c). const breakpointPCAdjust = 0