155 lines
3.4 KiB
Go
155 lines
3.4 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}
|
|
}
|
|
|
|
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
|
|
}()
|