Files
delve/pkg/proc/loong64_arch.go
yelvens d2f748f1bd *: add support for linux/loong64 to native backend (#3892)
* delve: support linux-loong64 native debug

LoongArch is a new RISC ISA, which is independently designed by Loongson Technology.

LoongArch includes a reduced 32-bit version (LA32R), a standard 32-bit version (LA32S)
and a 64-bit version (LA64), and loong64 is the 64-bit version of LoongArch.

LoongArch documentation: https://github.com/loongson/LoongArch-Documentation.git

* *: mark loong64 port as experimental

---------

Co-authored-by: Huang Qiqi <huangqiqi@loongson.cn>
2025-01-17 09:41:37 -08:00

159 lines
5.4 KiB
Go

package proc
import (
"encoding/binary"
"fmt"
"strings"
"github.com/go-delve/delve/pkg/dwarf/frame"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/dwarf/regnum"
)
// Break Instruction : 0x002a0000
var loong64BreakInstruction = []byte{0x00, 0x00, 0x2a, 0x00}
// LOONG64Arch returns an initialized LOONG64 struct.
func LOONG64Arch(goos string) *Arch {
return &Arch{
Name: "loong64",
ptrSize: 8,
maxInstructionLength: 4,
breakpointInstruction: loong64BreakInstruction,
breakInstrMovesPC: false,
derefTLS: false,
prologues: nil,
fixFrameUnwindContext: loong64FixFrameUnwindContext,
switchStack: loong64SwitchStack,
regSize: loong64RegSize,
RegistersToDwarfRegisters: loong64RegistersToDwarfRegisters,
addrAndStackRegsToDwarfRegisters: loong64AddrAndStackRegsToDwarfRegisters,
DwarfRegisterToString: loong64DwarfRegisterToString,
inhibitStepInto: func(*BinaryInfo, uint64) bool { return false },
asmDecode: loong64AsmDecode,
usesLR: true,
PCRegNum: regnum.LOONG64_PC,
SPRegNum: regnum.LOONG64_SP,
asmRegisters: loong64AsmRegisters,
RegisterNameToDwarf: nameToDwarfFunc(regnum.LOONG64NameToDwarf),
RegnumToString: regnum.LOONG64ToName,
debugCallMinStackSize: 280,
maxRegArgBytes: 16*8 + 16*8, // 16 int argument registers plus 16 float argument registers
}
}
func loong64FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryInfo) *frame.FrameContext {
a := bi.Arch
if fctxt == nil {
// When there's no frame descriptor entry use BP (the frame pointer) instead
// - return register is [bp + a.PtrSize()] (i.e. [cfa-a.PtrSize()])
// - cfa is bp + a.PtrSize()*2
// - bp is [bp] (i.e. [cfa-a.PtrSize()*2])
// - sp is cfa
return &frame.FrameContext{
RetAddrReg: regnum.LOONG64_LR,
Regs: map[uint64]frame.DWRule{
regnum.LOONG64_LR: {
Rule: frame.RuleOffset,
Offset: int64(-a.PtrSize()),
},
regnum.LOONG64_FP: {
Rule: frame.RuleOffset,
Offset: int64(-2 * a.PtrSize()),
},
regnum.LOONG64_SP: {
Rule: frame.RuleValOffset,
Offset: 0,
},
},
CFA: frame.DWRule{
Rule: frame.RuleCFA,
Reg: regnum.LOONG64_FP,
Offset: int64(2 * a.PtrSize()),
},
}
}
if fctxt.Regs[regnum.LOONG64_LR].Rule == frame.RuleUndefined {
fctxt.Regs[regnum.LOONG64_LR] = frame.DWRule{
Rule: frame.RuleRegister,
Reg: regnum.LOONG64_LR,
Offset: 0,
}
}
return fctxt
}
func loong64SwitchStack(it *stackIterator, callFrameRegs *op.DwarfRegisters) bool {
if it.frame.Current.Fn == nil {
if it.systemstack && it.g != nil && it.top {
it.switchToGoroutineStack()
return true
}
return false
}
switch it.frame.Current.Fn.Name {
case "runtime.goexit", "runtime.rt0_go", "runtime.mcall":
// Look for "top of stack" functions.
it.atend = true
return true
default:
if it.systemstack && it.top && it.g != nil && strings.HasPrefix(it.frame.Current.Fn.Name, "runtime.") && it.frame.Current.Fn.Name != "runtime.throw" && it.frame.Current.Fn.Name != "runtime.fatalthrow" {
// The runtime switches to the system stack in multiple places.
// This usually happens through a call to runtime.systemstack but there
// are functions that switch to the system stack manually (for example
// runtime.morestack).
// Since we are only interested in printing the system stack for cgo
// calls we switch directly to the goroutine stack if we detect that the
// function at the top of the stack is a runtime function.
it.switchToGoroutineStack()
return true
}
}
return false
}
func loong64RegSize(regnum uint64) int {
// All CPU registers are 64bit
return 8
}
func loong64RegistersToDwarfRegisters(staticBase uint64, regs Registers) *op.DwarfRegisters {
dregs := initDwarfRegistersFromSlice(int(regnum.LOONG64MaxRegNum()), regs, regnum.LOONG64NameToDwarf)
dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, regnum.LOONG64_PC, regnum.LOONG64_SP, regnum.LOONG64_FP, regnum.LOONG64_LR)
dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, regnum.LOONG64NameToDwarf))
return dr
}
func loong64AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, int(regnum.LOONG64MaxRegNum()))
dregs[regnum.LOONG64_PC] = op.DwarfRegisterFromUint64(pc)
dregs[regnum.LOONG64_SP] = op.DwarfRegisterFromUint64(sp)
dregs[regnum.LOONG64_FP] = op.DwarfRegisterFromUint64(bp)
dregs[regnum.LOONG64_LR] = op.DwarfRegisterFromUint64(lr)
return *op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, regnum.LOONG64_PC, regnum.LOONG64_SP, regnum.LOONG64_FP, regnum.LOONG64_LR)
}
func loong64DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
name = regnum.LOONG64ToName(uint64(i))
if reg == nil {
return name, false, ""
}
if strings.HasPrefix(name, "FCC") {
return name, true, fmt.Sprintf("%#x", reg.Uint64Val)
} else if strings.HasPrefix(name, "F") {
return name, true, fmt.Sprintf("%#016x", reg.Uint64Val)
} else {
return name, false, fmt.Sprintf("%#016x", reg.Uint64Val)
}
}