delve/pkg/proc/riscv64_disasm.go
2024-10-11 12:34:25 -07:00

184 lines
4.3 KiB
Go

package proc
import (
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/dwarf/regnum"
"golang.org/x/arch/riscv64/riscv64asm"
)
func riscv64AsmDecode(asmInst *AsmInstruction, mem []byte, regs *op.DwarfRegisters, memrw MemoryReadWriter, bi *BinaryInfo) error {
inst, err := riscv64asm.Decode(mem)
if err != nil {
asmInst.Inst = (*riscv64ArchInst)(nil)
return err
}
asmInst.Size = inst.Len
asmInst.Bytes = mem[:asmInst.Size]
asmInst.Inst = (*riscv64ArchInst)(&inst)
asmInst.Kind = OtherInstruction
switch inst.Op {
case riscv64asm.JALR:
rd, _ := inst.Args[0].(riscv64asm.Reg)
rs1 := inst.Args[1].(riscv64asm.RegOffset).OfsReg
if rd == riscv64asm.X1 {
asmInst.Kind = CallInstruction
} else if rd == riscv64asm.X0 && rs1 == riscv64asm.X1 {
asmInst.Kind = RetInstruction
} else {
asmInst.Kind = JmpInstruction
}
case riscv64asm.JAL:
rd, _ := inst.Args[0].(riscv64asm.Reg)
if rd == riscv64asm.X1 {
asmInst.Kind = CallInstruction
} else {
asmInst.Kind = JmpInstruction
}
case riscv64asm.BEQ,
riscv64asm.BNE,
riscv64asm.BLT,
riscv64asm.BGE,
riscv64asm.BLTU,
riscv64asm.BGEU:
asmInst.Kind = JmpInstruction
case riscv64asm.EBREAK:
asmInst.Kind = HardBreakInstruction
default:
asmInst.Kind = OtherInstruction
}
asmInst.DestLoc = resolveCallArgRISCV64(&inst, asmInst.Loc.PC, asmInst.AtPC, regs, memrw, bi)
return nil
}
func resolveCallArgRISCV64(inst *riscv64asm.Inst, instAddr uint64, currentGoroutine bool, regs *op.DwarfRegisters, mem MemoryReadWriter, bininfo *BinaryInfo) *Location {
var pc uint64
var err error
switch inst.Op {
// Format: op rs1, rs2, bimm12
// Target: bimm12
case riscv64asm.BEQ,
riscv64asm.BNE,
riscv64asm.BLT,
riscv64asm.BGE,
riscv64asm.BLTU,
riscv64asm.BGEU:
switch arg := inst.Args[2].(type) {
case riscv64asm.Simm:
pc = uint64(int64(instAddr) + int64(arg.Imm))
default:
return nil
}
// Format: op rd, jimm20
// Target: simm20
case riscv64asm.JAL:
switch arg := inst.Args[1].(type) {
case riscv64asm.Simm:
pc = uint64(int64(instAddr) + int64(arg.Imm))
default:
return nil
}
// Format: op rd, rs1, imm12
// Target: rj + offs16
case riscv64asm.JALR:
if !currentGoroutine || regs == nil {
return nil
}
switch arg := inst.Args[1].(type) {
case riscv64asm.RegOffset:
pc, err = bininfo.Arch.getAsmRegister(regs, int(arg.OfsReg))
if err != nil {
return nil
}
pc = uint64(int64(pc) + int64(arg.Ofs.Imm))
}
default:
return nil
}
file, line, fn := bininfo.PCToLine(pc)
if fn == nil {
return &Location{PC: pc}
}
return &Location{PC: pc, File: file, Line: line, Fn: fn}
}
// Possible stacksplit prologues are inserted by stacksplit in
// $GOROOT/src/cmd/internal/obj/riscv/obj.go.
var prologuesRISCV64 []opcodeSeq
func init() {
var tinyStacksplit = opcodeSeq{uint64(riscv64asm.ADDI)}
var smallStacksplit = opcodeSeq{}
var bigStacksplit = opcodeSeq{uint64(riscv64asm.LUI),
uint64(riscv64asm.ADDIW),
uint64(riscv64asm.BLTU),
uint64(riscv64asm.LUI),
uint64(riscv64asm.ADDIW),
uint64(riscv64asm.ADD)}
var unixGetG = opcodeSeq{uint64(riscv64asm.LD)}
var tailPrologues = opcodeSeq{uint64(riscv64asm.BLTU),
uint64(riscv64asm.JAL),
uint64(riscv64asm.JAL)}
prologuesRISCV64 = make([]opcodeSeq, 0, 3)
for _, stacksplit := range []opcodeSeq{tinyStacksplit, smallStacksplit, bigStacksplit} {
prologue := make(opcodeSeq, 0, len(unixGetG)+len(stacksplit)+len(tailPrologues))
prologue = append(prologue, unixGetG...)
prologue = append(prologue, stacksplit...)
prologue = append(prologue, tailPrologues...)
prologuesRISCV64 = append(prologuesRISCV64, prologue)
}
}
type riscv64ArchInst riscv64asm.Inst
func (inst *riscv64ArchInst) Text(flavour AssemblyFlavour, pc uint64, symLookup func(uint64) (string, uint64)) string {
if inst == nil {
return "?"
}
var text string
switch flavour {
case GNUFlavour:
text = riscv64asm.GNUSyntax(riscv64asm.Inst(*inst))
default:
text = riscv64asm.GoSyntax(riscv64asm.Inst(*inst), pc, symLookup, nil)
}
return text
}
func (inst *riscv64ArchInst) OpcodeEquals(op uint64) bool {
if inst == nil {
return false
}
return uint64(inst.Op) == op
}
var riscv64AsmRegisters = func() map[int]asmRegister {
r := make(map[int]asmRegister)
for i := riscv64asm.X0; i <= riscv64asm.X31; i++ {
r[int(i)] = asmRegister{regnum.RISCV64_X0 + uint64(i), 0, 0}
}
return r
}()