delve: add linux-riscv64 support (#3785)
This commit is contained in:
parent
abc948b0ae
commit
75c41f2b64
3
.teamcity/settings.kts
vendored
3
.teamcity/settings.kts
vendored
@ -53,6 +53,8 @@ val targets = arrayOf(
|
||||
|
||||
"linux/ppc64le/1.23",
|
||||
|
||||
"linux/riscv64/1.23",
|
||||
|
||||
"windows/amd64/1.23",
|
||||
"windows/amd64/tip",
|
||||
|
||||
@ -268,6 +270,7 @@ class TestBuild(val os: String, val arch: String, val version: String, buildId:
|
||||
"386", "amd64" -> equals("teamcity.agent.jvm.os.arch", if (os == "mac") "x86_64" else "amd64")
|
||||
"arm64" -> equals("teamcity.agent.jvm.os.arch", "aarch64")
|
||||
"ppc64le" -> equals("teamcity.agent.jvm.os.arch", "ppc64le")
|
||||
"riscv64" -> equals("teamcity.agent.jvm.os.arch", "riscv64")
|
||||
}
|
||||
when (os) {
|
||||
"linux" -> {
|
||||
|
@ -30,12 +30,19 @@ Tests skipped by each supported backend:
|
||||
* 1 broken in linux ppc64le
|
||||
* linux/ppc64le/native/pie skipped = 3
|
||||
* 3 broken - pie mode
|
||||
* linux/riscv64 skipped = 2
|
||||
* 1 broken - cgo stacktraces
|
||||
* 1 not working on linux/riscv64
|
||||
* pie skipped = 2
|
||||
* 2 upstream issue - https://github.com/golang/go/issues/29322
|
||||
* ppc64le skipped = 12
|
||||
* 6 broken
|
||||
* 1 broken - global variable symbolication
|
||||
* 5 not implemented
|
||||
* riscv64 skipped = 6
|
||||
* 2 broken
|
||||
* 1 broken - global variable symbolication
|
||||
* 3 not implemented
|
||||
* windows skipped = 7
|
||||
* 1 broken
|
||||
* 2 not working on windows
|
||||
|
7
_fixtures/asmnilptr/main_riscv64.s
Normal file
7
_fixtures/asmnilptr/main_riscv64.s
Normal file
@ -0,0 +1,7 @@
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·asmFunc(SB),0,$0-16
|
||||
MOV arg+0(FP), R5
|
||||
MOV (R5), R5
|
||||
MOV R5, ret+8(FP)
|
||||
RET
|
@ -14,6 +14,8 @@
|
||||
#else
|
||||
#define BREAKPOINT asm("brk 0;")
|
||||
#endif
|
||||
#elif __riscv
|
||||
#define BREAKPOINT asm("ebreak;")
|
||||
#endif
|
||||
|
||||
void helloworld_pt2(int x) {
|
||||
|
@ -12,6 +12,8 @@
|
||||
#else
|
||||
#define BREAKPOINT asm("brk 0;")
|
||||
#endif
|
||||
#elif __riscv
|
||||
#define BREAKPOINT asm("ebreak;")
|
||||
#endif
|
||||
|
||||
#define N 100
|
||||
@ -37,6 +39,6 @@ void testfn(void) {
|
||||
strcpy(s, s0);
|
||||
|
||||
BREAKPOINT;
|
||||
|
||||
|
||||
printf("%s %s %p %p\n", s, longstring, v, v_align_check);
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ This option can only be specified if testset is basic or a single package.`)
|
||||
test.PersistentFlags().StringVarP(&TestBuildMode, "test-build-mode", "m", "", `Runs tests compiling with the specified build mode, one of either:
|
||||
normal normal buildmode (default)
|
||||
pie PIE buildmode
|
||||
|
||||
|
||||
This option can only be specified if testset is basic or a single package.`)
|
||||
test.PersistentFlags().BoolVarP(&TestIncludePIE, "pie", "", true, "Standard testing should include PIE")
|
||||
|
||||
|
92
pkg/dwarf/regnum/riscv64.go
Normal file
92
pkg/dwarf/regnum/riscv64.go
Normal file
@ -0,0 +1,92 @@
|
||||
package regnum
|
||||
|
||||
import "fmt"
|
||||
|
||||
// The mapping between hardware registers and DWARF registers, See
|
||||
// https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-dwarf.adoc
|
||||
|
||||
const (
|
||||
// Integer Registers
|
||||
RISCV64_X0 = 0
|
||||
// Link Register
|
||||
RISCV64_LR = 1
|
||||
// Stack Pointer
|
||||
RISCV64_SP = 2
|
||||
RISCV64_GP = 3
|
||||
RISCV64_TP = 4
|
||||
RISCV64_T0 = 5
|
||||
RISCV64_T1 = 6
|
||||
RISCV64_T2 = 7
|
||||
RISCV64_S0 = 8
|
||||
// Frame Pointer
|
||||
RISCV64_FP = RISCV64_S0
|
||||
RISCV64_S1 = 9
|
||||
RISCV64_A0 = 10
|
||||
RISCV64_A1 = 11
|
||||
RISCV64_A2 = 12
|
||||
RISCV64_A3 = 13
|
||||
RISCV64_A4 = 14
|
||||
RISCV64_A5 = 15
|
||||
RISCV64_A6 = 16
|
||||
RISCV64_A7 = 17
|
||||
RISCV64_S2 = 18
|
||||
RISCV64_S3 = 19
|
||||
RISCV64_S4 = 20
|
||||
RISCV64_S5 = 21
|
||||
RISCV64_S6 = 22
|
||||
RISCV64_S7 = 23
|
||||
RISCV64_S8 = 24
|
||||
RISCV64_S9 = 25
|
||||
RISCV64_S10 = 26
|
||||
// G Register
|
||||
RISCV64_S11 = 27
|
||||
RISCV64_T3 = 28
|
||||
RISCV64_T4 = 29
|
||||
RISCV64_T5 = 30
|
||||
RISCV64_T6 = 31
|
||||
|
||||
RISCV64_X31 = RISCV64_T6
|
||||
|
||||
// Floating-point Registers
|
||||
RISCV64_F0 = 32
|
||||
RISCV64_F31 = 63
|
||||
|
||||
// Not defined in DWARF specification
|
||||
RISCV64_PC = 65
|
||||
|
||||
_RISC64_MaxRegNum = RISCV64_PC
|
||||
)
|
||||
|
||||
func RISCV64ToName(num uint64) string {
|
||||
switch {
|
||||
case num <= RISCV64_X31:
|
||||
return fmt.Sprintf("X%d", num)
|
||||
|
||||
case num >= RISCV64_F0 && num <= RISCV64_F31:
|
||||
return fmt.Sprintf("F%d", num)
|
||||
|
||||
case num == RISCV64_PC:
|
||||
return "PC"
|
||||
|
||||
default:
|
||||
return fmt.Sprintf("Unknown%d", num)
|
||||
}
|
||||
}
|
||||
|
||||
func RISCV64MaxRegNum() uint64 {
|
||||
return _RISC64_MaxRegNum
|
||||
}
|
||||
|
||||
var RISCV64NameToDwarf = func() map[string]int {
|
||||
r := make(map[string]int)
|
||||
for i := 0; i <= 31; i++ {
|
||||
r[fmt.Sprintf("x%d", i)] = RISCV64_X0 + i
|
||||
}
|
||||
r["pc"] = RISCV64_PC
|
||||
|
||||
for i := 0; i <= 31; i++ {
|
||||
r[fmt.Sprintf("f%d", i)] = RISCV64_F0 + i
|
||||
}
|
||||
|
||||
return r
|
||||
}()
|
@ -131,6 +131,7 @@ var (
|
||||
elf.EM_AARCH64: true,
|
||||
elf.EM_386: true,
|
||||
elf.EM_PPC64: true,
|
||||
elf.EM_RISCV: true,
|
||||
}
|
||||
|
||||
supportedWindowsArch = map[_PEMachine]bool{
|
||||
@ -814,6 +815,8 @@ func NewBinaryInfo(goos, goarch string) *BinaryInfo {
|
||||
r.Arch = ARM64Arch(goos)
|
||||
case "ppc64le":
|
||||
r.Arch = PPC64LEArch(goos)
|
||||
case "riscv64":
|
||||
r.Arch = RISCV64Arch(goos)
|
||||
}
|
||||
return r
|
||||
}
|
||||
@ -1812,7 +1815,7 @@ func (bi *BinaryInfo) setGStructOffsetElf(image *Image, exe *elf.File, wg *sync.
|
||||
|
||||
bi.gStructOffset = tlsg.Value + uint64(bi.Arch.PtrSize()*2) + ((tls.Vaddr - uint64(bi.Arch.PtrSize()*2)) & (tls.Align - 1))
|
||||
|
||||
case elf.EM_PPC64:
|
||||
case elf.EM_PPC64, elf.EM_RISCV:
|
||||
_ = getSymbol(image, bi.logger, exe, "runtime.tls_g")
|
||||
|
||||
default:
|
||||
|
@ -40,6 +40,7 @@ const _NT_FPREGSET elf.NType = 0x2
|
||||
const (
|
||||
_EM_AARCH64 = 183
|
||||
_EM_X86_64 = 62
|
||||
_EM_RISCV = 243
|
||||
_ARM_FP_HEADER_START = 512
|
||||
)
|
||||
|
||||
@ -49,6 +50,8 @@ func linuxThreadsFromNotes(p *process, notes []*note, machineType elf.Machine) p
|
||||
var currentThread proc.Thread
|
||||
var lastThreadAMD *linuxAMD64Thread
|
||||
var lastThreadARM *linuxARM64Thread
|
||||
var lastThreadRISCV *linuxRISCV64Thread
|
||||
|
||||
for _, note := range notes {
|
||||
switch note.Type {
|
||||
case elf.NT_PRSTATUS:
|
||||
@ -66,12 +69,23 @@ func linuxThreadsFromNotes(p *process, notes []*note, machineType elf.Machine) p
|
||||
if currentThread == nil {
|
||||
currentThread = p.Threads[int(t.Pid)]
|
||||
}
|
||||
} else if machineType == _EM_RISCV {
|
||||
t := note.Desc.(*linuxPrStatusRISCV64)
|
||||
lastThreadRISCV = &linuxRISCV64Thread{linutil.RISCV64Registers{Regs: &t.Reg}, t}
|
||||
p.Threads[int(t.Pid)] = &thread{lastThreadRISCV, p, proc.CommonThread{}}
|
||||
if currentThread == nil {
|
||||
currentThread = p.Threads[int(t.Pid)]
|
||||
}
|
||||
}
|
||||
case _NT_FPREGSET:
|
||||
if machineType == _EM_AARCH64 {
|
||||
if lastThreadARM != nil {
|
||||
lastThreadARM.regs.Fpregs = note.Desc.(*linutil.ARM64PtraceFpRegs).Decode()
|
||||
}
|
||||
} else if machineType == _EM_RISCV {
|
||||
if lastThreadRISCV != nil {
|
||||
lastThreadRISCV.regs.Fpregs = note.Desc.(*linutil.RISCV64PtraceFpRegs).Decode()
|
||||
}
|
||||
}
|
||||
case _NT_X86_XSTATE:
|
||||
if machineType == _EM_X86_64 {
|
||||
@ -147,6 +161,8 @@ func readLinuxOrPlatformIndependentCore(corePath, exePath string) (*process, pro
|
||||
bi = proc.NewBinaryInfo("linux", "amd64")
|
||||
case _EM_AARCH64:
|
||||
bi = proc.NewBinaryInfo("linux", "arm64")
|
||||
case _EM_RISCV:
|
||||
bi = proc.NewBinaryInfo("linux", "riscv64")
|
||||
default:
|
||||
return nil, nil, errors.New("unsupported machine type")
|
||||
}
|
||||
@ -181,6 +197,11 @@ type linuxARM64Thread struct {
|
||||
t *linuxPrStatusARM64
|
||||
}
|
||||
|
||||
type linuxRISCV64Thread struct {
|
||||
regs linutil.RISCV64Registers
|
||||
t *linuxPrStatusRISCV64
|
||||
}
|
||||
|
||||
func (t *linuxAMD64Thread) registers() (proc.Registers, error) {
|
||||
var r linutil.AMD64Registers
|
||||
r.Regs = t.regs.Regs
|
||||
@ -195,6 +216,13 @@ func (t *linuxARM64Thread) registers() (proc.Registers, error) {
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
func (t *linuxRISCV64Thread) registers() (proc.Registers, error) {
|
||||
var r linutil.RISCV64Registers
|
||||
r.Regs = t.regs.Regs
|
||||
r.Fpregs = t.regs.Fpregs
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
func (t *linuxAMD64Thread) pid() int {
|
||||
return int(t.t.Pid)
|
||||
}
|
||||
@ -203,6 +231,10 @@ func (t *linuxARM64Thread) pid() int {
|
||||
return int(t.t.Pid)
|
||||
}
|
||||
|
||||
func (t *linuxRISCV64Thread) pid() int {
|
||||
return int(t.t.Pid)
|
||||
}
|
||||
|
||||
// Note is a note from the PT_NOTE prog.
|
||||
// Relevant types:
|
||||
// - NT_FILE: File mapping information, e.g. program text mappings. Desc is a LinuxNTFile.
|
||||
@ -286,6 +318,8 @@ func readNote(r io.ReadSeeker, machineType elf.Machine) (*note, error) {
|
||||
note.Desc = &linuxPrStatusAMD64{}
|
||||
case _EM_AARCH64:
|
||||
note.Desc = &linuxPrStatusARM64{}
|
||||
case _EM_RISCV:
|
||||
note.Desc = &linuxPrStatusRISCV64{}
|
||||
default:
|
||||
return nil, errors.New("unsupported machine type")
|
||||
}
|
||||
@ -332,6 +366,13 @@ func readNote(r io.ReadSeeker, machineType elf.Machine) (*note, error) {
|
||||
return nil, err
|
||||
}
|
||||
note.Desc = fpregs
|
||||
} else if machineType == _EM_RISCV {
|
||||
fpregs := &linutil.RISCV64PtraceFpRegs{}
|
||||
rdr := bytes.NewReader(desc)
|
||||
if err := binary.Read(rdr, binary.LittleEndian, fpregs.Byte()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
note.Desc = fpregs
|
||||
}
|
||||
}
|
||||
if err := skipPadding(r, 4); err != nil {
|
||||
@ -446,6 +487,19 @@ type linuxPrStatusARM64 struct {
|
||||
Fpvalid int32
|
||||
}
|
||||
|
||||
// LinuxPrStatusRISCV64 is a copy of the prstatus kernel struct.
|
||||
type linuxPrStatusRISCV64 struct {
|
||||
Siginfo linuxSiginfo
|
||||
Cursig uint16
|
||||
_ [2]uint8
|
||||
Sigpend uint64
|
||||
Sighold uint64
|
||||
Pid, Ppid, Pgrp, Sid int32
|
||||
Utime, Stime, CUtime, CStime linuxCoreTimeval
|
||||
Reg linutil.RISCV64PtraceRegs
|
||||
Fpvalid int32
|
||||
}
|
||||
|
||||
// LinuxSiginfo is a copy of the
|
||||
// siginfo kernel struct.
|
||||
type linuxSiginfo struct {
|
||||
|
@ -138,6 +138,8 @@ func (t *Target) Dump(out elfwriter.WriteCloserSeeker, flags DumpFlags, state *D
|
||||
fhdr.Machine = elf.EM_AARCH64
|
||||
case "ppc64le":
|
||||
fhdr.Machine = elf.EM_PPC64
|
||||
case "riscv64":
|
||||
fhdr.Machine = elf.EM_RISCV
|
||||
default:
|
||||
panic("not implemented")
|
||||
}
|
||||
|
386
pkg/proc/linutil/regs_riscv64_arch.go
Normal file
386
pkg/proc/linutil/regs_riscv64_arch.go
Normal file
@ -0,0 +1,386 @@
|
||||
package linutil
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-delve/delve/pkg/dwarf/op"
|
||||
"github.com/go-delve/delve/pkg/dwarf/regnum"
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
"golang.org/x/arch/riscv64/riscv64asm"
|
||||
)
|
||||
|
||||
// RISCV64Registers implements the proc.Registers interface.
|
||||
type RISCV64Registers struct {
|
||||
Regs *RISCV64PtraceRegs // general-purpose registers & pc
|
||||
iscgo bool
|
||||
tp_tls uint64
|
||||
Fpregs []proc.Register // Formatted floating-point registers
|
||||
Fpregset []byte // holding all floating-point register values
|
||||
loadFpRegs func(*RISCV64Registers) error
|
||||
}
|
||||
|
||||
func NewRISCV64Registers(regs *RISCV64PtraceRegs, iscgo bool, tp_tls uint64,
|
||||
loadFpRegs func(*RISCV64Registers) error) *RISCV64Registers {
|
||||
return &RISCV64Registers{
|
||||
Regs: regs,
|
||||
iscgo: iscgo,
|
||||
tp_tls: tp_tls,
|
||||
loadFpRegs: loadFpRegs,
|
||||
}
|
||||
}
|
||||
|
||||
// RISCV64PtraceRegs is the struct used by the linux kernel to return the
|
||||
// general purpose registers for RISC-V CPUs.
|
||||
type RISCV64PtraceRegs struct {
|
||||
Pc uint64
|
||||
Ra uint64
|
||||
Sp uint64
|
||||
Gp uint64
|
||||
Tp uint64
|
||||
T0 uint64
|
||||
T1 uint64
|
||||
T2 uint64
|
||||
S0 uint64
|
||||
S1 uint64
|
||||
A0 uint64
|
||||
A1 uint64
|
||||
A2 uint64
|
||||
A3 uint64
|
||||
A4 uint64
|
||||
A5 uint64
|
||||
A6 uint64
|
||||
A7 uint64
|
||||
S2 uint64
|
||||
S3 uint64
|
||||
S4 uint64
|
||||
S5 uint64
|
||||
S6 uint64
|
||||
S7 uint64
|
||||
S8 uint64
|
||||
S9 uint64
|
||||
S10 uint64
|
||||
S11 uint64
|
||||
T3 uint64
|
||||
T4 uint64
|
||||
T5 uint64
|
||||
T6 uint64
|
||||
}
|
||||
|
||||
// Slice returns the registers as a list of (name, value) pairs.
|
||||
func (r *RISCV64Registers) Slice(floatingPoint bool) ([]proc.Register, error) {
|
||||
var regs64 = []struct {
|
||||
k string
|
||||
v uint64
|
||||
}{
|
||||
{"X1", r.Regs.Ra},
|
||||
{"X2", r.Regs.Sp},
|
||||
{"X3", r.Regs.Gp},
|
||||
{"X4", r.Regs.Tp},
|
||||
{"X5", r.Regs.T0},
|
||||
{"X6", r.Regs.T1},
|
||||
{"X7", r.Regs.T2},
|
||||
{"X8", r.Regs.S0},
|
||||
{"X9", r.Regs.S1},
|
||||
{"X10", r.Regs.A0},
|
||||
{"X11", r.Regs.A1},
|
||||
{"X12", r.Regs.A2},
|
||||
{"X13", r.Regs.A3},
|
||||
{"X14", r.Regs.A4},
|
||||
{"X15", r.Regs.A5},
|
||||
{"X16", r.Regs.A6},
|
||||
{"X17", r.Regs.A7},
|
||||
{"X18", r.Regs.S2},
|
||||
{"X19", r.Regs.S3},
|
||||
{"X20", r.Regs.S4},
|
||||
{"X21", r.Regs.S5},
|
||||
{"X22", r.Regs.S6},
|
||||
{"X23", r.Regs.S7},
|
||||
{"X24", r.Regs.S8},
|
||||
{"X25", r.Regs.S9},
|
||||
{"X26", r.Regs.S10},
|
||||
{"X27", r.Regs.S11},
|
||||
{"X28", r.Regs.T3},
|
||||
{"X29", r.Regs.T4},
|
||||
{"X30", r.Regs.T5},
|
||||
{"X31", r.Regs.T6},
|
||||
{"PC", r.Regs.Pc},
|
||||
}
|
||||
|
||||
out := make([]proc.Register, 0, (len(regs64) + len(r.Fpregs)))
|
||||
for _, reg := range regs64 {
|
||||
out = proc.AppendUint64Register(out, reg.k, reg.v)
|
||||
}
|
||||
|
||||
var floatLoadError error
|
||||
if floatingPoint {
|
||||
if r.loadFpRegs != nil {
|
||||
floatLoadError = r.loadFpRegs(r)
|
||||
r.loadFpRegs = nil
|
||||
}
|
||||
|
||||
out = append(out, r.Fpregs...)
|
||||
}
|
||||
|
||||
return out, floatLoadError
|
||||
}
|
||||
|
||||
// PC returns the value of PC register.
|
||||
func (r *RISCV64Registers) PC() uint64 {
|
||||
// PC Register
|
||||
return r.Regs.Pc
|
||||
}
|
||||
|
||||
// SP returns the value of SP register.
|
||||
func (r *RISCV64Registers) SP() uint64 {
|
||||
// Stack pointer
|
||||
return r.Regs.Sp
|
||||
}
|
||||
|
||||
// BP returns the value of FP register
|
||||
func (r *RISCV64Registers) BP() uint64 {
|
||||
// unused FP register
|
||||
return 0
|
||||
}
|
||||
|
||||
// TLS returns the address of the thread local storage memory segment.
|
||||
func (r *RISCV64Registers) TLS() uint64 {
|
||||
// TODO: calling cgo may overwrite $x27, read it from the kernel
|
||||
if !r.iscgo {
|
||||
return 0
|
||||
}
|
||||
|
||||
return r.tp_tls
|
||||
}
|
||||
|
||||
// GAddr returns the address of the G variable if it is known, 0 and false otherwise.
|
||||
func (r *RISCV64Registers) GAddr() (uint64, bool) {
|
||||
// Defined in $GOROOT/cmd/internal/obj/riscv/cpu.go.
|
||||
return r.Regs.S11, !r.iscgo
|
||||
}
|
||||
|
||||
// LR returns the link register.
|
||||
func (r *RISCV64Registers) LR() uint64 {
|
||||
return r.Regs.Ra
|
||||
}
|
||||
|
||||
// Copy returns a copy of these registers that is guaranteed not to change.
|
||||
func (r *RISCV64Registers) Copy() (proc.Registers, error) {
|
||||
if r.loadFpRegs != nil {
|
||||
err := r.loadFpRegs(r)
|
||||
r.loadFpRegs = nil
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var rr RISCV64Registers
|
||||
rr.Regs = &RISCV64PtraceRegs{}
|
||||
*(rr.Regs) = *(r.Regs)
|
||||
if r.Fpregs != nil {
|
||||
rr.Fpregs = make([]proc.Register, len(r.Fpregs))
|
||||
copy(rr.Fpregs, r.Fpregs)
|
||||
}
|
||||
|
||||
if r.Fpregset != nil {
|
||||
rr.Fpregset = make([]byte, len(r.Fpregset))
|
||||
copy(rr.Fpregset, r.Fpregset)
|
||||
}
|
||||
|
||||
return &rr, nil
|
||||
}
|
||||
|
||||
func (r *RISCV64Registers) GetReg(regNum uint64) (uint64, error) {
|
||||
reg := riscv64asm.Reg(regNum)
|
||||
|
||||
if reg <= riscv64asm.X31 {
|
||||
switch regNum {
|
||||
case regnum.RISCV64_LR:
|
||||
return uint64(r.Regs.Ra), nil
|
||||
case regnum.RISCV64_SP:
|
||||
return uint64(r.Regs.Sp), nil
|
||||
case regnum.RISCV64_GP:
|
||||
return uint64(r.Regs.Gp), nil
|
||||
case regnum.RISCV64_TP:
|
||||
return uint64(r.Regs.Tp), nil
|
||||
case regnum.RISCV64_T0:
|
||||
return uint64(r.Regs.T0), nil
|
||||
case regnum.RISCV64_T1:
|
||||
return uint64(r.Regs.T1), nil
|
||||
case regnum.RISCV64_T2:
|
||||
return uint64(r.Regs.T2), nil
|
||||
case regnum.RISCV64_S0:
|
||||
return uint64(r.Regs.S0), nil
|
||||
case regnum.RISCV64_S1:
|
||||
return uint64(r.Regs.S1), nil
|
||||
case regnum.RISCV64_A0:
|
||||
return uint64(r.Regs.A0), nil
|
||||
case regnum.RISCV64_A1:
|
||||
return uint64(r.Regs.A1), nil
|
||||
case regnum.RISCV64_A2:
|
||||
return uint64(r.Regs.A2), nil
|
||||
case regnum.RISCV64_A3:
|
||||
return uint64(r.Regs.A3), nil
|
||||
case regnum.RISCV64_A4:
|
||||
return uint64(r.Regs.A4), nil
|
||||
case regnum.RISCV64_A5:
|
||||
return uint64(r.Regs.A5), nil
|
||||
case regnum.RISCV64_A6:
|
||||
return uint64(r.Regs.A6), nil
|
||||
case regnum.RISCV64_A7:
|
||||
return uint64(r.Regs.A7), nil
|
||||
case regnum.RISCV64_S2:
|
||||
return uint64(r.Regs.S2), nil
|
||||
case regnum.RISCV64_S3:
|
||||
return uint64(r.Regs.S3), nil
|
||||
case regnum.RISCV64_S4:
|
||||
return uint64(r.Regs.S4), nil
|
||||
case regnum.RISCV64_S5:
|
||||
return uint64(r.Regs.S5), nil
|
||||
case regnum.RISCV64_S6:
|
||||
return uint64(r.Regs.S6), nil
|
||||
case regnum.RISCV64_S7:
|
||||
return uint64(r.Regs.S7), nil
|
||||
case regnum.RISCV64_S8:
|
||||
return uint64(r.Regs.S8), nil
|
||||
case regnum.RISCV64_S9:
|
||||
return uint64(r.Regs.S9), nil
|
||||
case regnum.RISCV64_S10:
|
||||
return uint64(r.Regs.S10), nil
|
||||
case regnum.RISCV64_S11:
|
||||
return uint64(r.Regs.S11), nil
|
||||
case regnum.RISCV64_T3:
|
||||
return uint64(r.Regs.T3), nil
|
||||
case regnum.RISCV64_T4:
|
||||
return uint64(r.Regs.T4), nil
|
||||
case regnum.RISCV64_T5:
|
||||
return uint64(r.Regs.T5), nil
|
||||
case regnum.RISCV64_T6:
|
||||
return uint64(r.Regs.T6), nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, proc.ErrUnknownRegister
|
||||
}
|
||||
|
||||
func (r *RISCV64Registers) SetReg(regNum uint64, reg *op.DwarfRegister) (fpchanged bool, err error) {
|
||||
var p *uint64
|
||||
switch regNum {
|
||||
case regnum.RISCV64_LR:
|
||||
p = &r.Regs.Ra
|
||||
case regnum.RISCV64_SP:
|
||||
p = &r.Regs.Sp
|
||||
case regnum.RISCV64_GP:
|
||||
p = &r.Regs.Gp
|
||||
case regnum.RISCV64_TP:
|
||||
p = &r.Regs.Tp
|
||||
case regnum.RISCV64_T0:
|
||||
p = &r.Regs.T0
|
||||
case regnum.RISCV64_T1:
|
||||
p = &r.Regs.T1
|
||||
case regnum.RISCV64_T2:
|
||||
p = &r.Regs.T2
|
||||
case regnum.RISCV64_S0:
|
||||
p = &r.Regs.S0
|
||||
case regnum.RISCV64_S1:
|
||||
p = &r.Regs.S1
|
||||
case regnum.RISCV64_A0:
|
||||
p = &r.Regs.A0
|
||||
case regnum.RISCV64_A1:
|
||||
p = &r.Regs.A1
|
||||
case regnum.RISCV64_A2:
|
||||
p = &r.Regs.A2
|
||||
case regnum.RISCV64_A3:
|
||||
p = &r.Regs.A3
|
||||
case regnum.RISCV64_A4:
|
||||
p = &r.Regs.A4
|
||||
case regnum.RISCV64_A5:
|
||||
p = &r.Regs.A5
|
||||
case regnum.RISCV64_A6:
|
||||
p = &r.Regs.A6
|
||||
case regnum.RISCV64_A7:
|
||||
p = &r.Regs.A7
|
||||
case regnum.RISCV64_S2:
|
||||
p = &r.Regs.S2
|
||||
case regnum.RISCV64_S3:
|
||||
p = &r.Regs.S3
|
||||
case regnum.RISCV64_S4:
|
||||
p = &r.Regs.S4
|
||||
case regnum.RISCV64_S5:
|
||||
p = &r.Regs.S5
|
||||
case regnum.RISCV64_S6:
|
||||
p = &r.Regs.S6
|
||||
case regnum.RISCV64_S7:
|
||||
p = &r.Regs.S7
|
||||
case regnum.RISCV64_S8:
|
||||
p = &r.Regs.S8
|
||||
case regnum.RISCV64_S9:
|
||||
p = &r.Regs.S9
|
||||
case regnum.RISCV64_S10:
|
||||
p = &r.Regs.S10
|
||||
case regnum.RISCV64_S11:
|
||||
p = &r.Regs.S11
|
||||
case regnum.RISCV64_T3:
|
||||
p = &r.Regs.T3
|
||||
case regnum.RISCV64_T4:
|
||||
p = &r.Regs.T4
|
||||
case regnum.RISCV64_T5:
|
||||
p = &r.Regs.T5
|
||||
case regnum.RISCV64_T6:
|
||||
p = &r.Regs.T6
|
||||
case regnum.RISCV64_PC:
|
||||
p = &r.Regs.Pc
|
||||
}
|
||||
|
||||
if p != nil {
|
||||
*p = reg.Uint64Val
|
||||
return false, nil
|
||||
}
|
||||
|
||||
switch {
|
||||
case regNum >= regnum.RISCV64_F0 && regNum <= regnum.RISCV64_F31:
|
||||
if r.loadFpRegs != nil {
|
||||
err := r.loadFpRegs(r)
|
||||
r.loadFpRegs = nil
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
i := regNum - regnum.RISCV64_F0
|
||||
reg.FillBytes()
|
||||
copy(r.Fpregset[8*i:], reg.Bytes)
|
||||
return true, nil
|
||||
|
||||
default:
|
||||
return false, fmt.Errorf("changing register %d not implemented", regNum)
|
||||
}
|
||||
}
|
||||
|
||||
// RISCV64PtraceFpRegs is refer to the definition of struct __riscv_d_ext_state in the kernel ptrace.h
|
||||
type RISCV64PtraceFpRegs struct {
|
||||
Fregs []byte
|
||||
Fcsr uint32
|
||||
}
|
||||
|
||||
const _RISCV64_FPREGSET_LENGTH = (32 * 8)
|
||||
|
||||
func (fpregs *RISCV64PtraceFpRegs) Decode() (regs []proc.Register) {
|
||||
for i := 0; i < len(fpregs.Fregs); i += 8 {
|
||||
name := fmt.Sprintf("F%d", (i / 8))
|
||||
value := fpregs.Fregs[i : i+8]
|
||||
regs = proc.AppendBytesRegister(regs, name, value)
|
||||
}
|
||||
|
||||
fcsrBytes := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(fcsrBytes, uint32(fpregs.Fcsr))
|
||||
regs = proc.AppendBytesRegister(regs, "FCSR", fcsrBytes)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (fpregs *RISCV64PtraceFpRegs) Byte() []byte {
|
||||
fpregs.Fregs = make([]byte, _RISCV64_FPREGSET_LENGTH)
|
||||
|
||||
return fpregs.Fregs[:]
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
//go:build (linux && 386) || (darwin && arm64) || (windows && arm64) || (linux && ppc64le)
|
||||
//go:build (linux && 386) || (darwin && arm64) || (windows && arm64) || (linux && ppc64le) || (linux && riscv64)
|
||||
|
||||
package native
|
||||
|
||||
|
@ -382,7 +382,7 @@ func (dbp *nativeProcess) initialize(path string, debugInfoDirs []string) (*proc
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if dbp.bi.Arch.Name == "arm64" || dbp.bi.Arch.Name == "ppc64le" {
|
||||
if dbp.bi.Arch.Name == "arm64" || dbp.bi.Arch.Name == "ppc64le" || dbp.bi.Arch.Name == "riscv64" {
|
||||
dbp.iscgo = tgt.IsCgo()
|
||||
}
|
||||
return grp, nil
|
||||
|
@ -1,4 +1,4 @@
|
||||
//go:build (linux && amd64) || (linux && arm64) || (linux && ppc64le)
|
||||
//go:build (linux && amd64) || (linux && arm64) || (linux && ppc64le) || (linux && riscv64)
|
||||
|
||||
package native
|
||||
|
||||
|
144
pkg/proc/native/registers_linux_riscv64.go
Normal file
144
pkg/proc/native/registers_linux_riscv64.go
Normal file
@ -0,0 +1,144 @@
|
||||
package native
|
||||
|
||||
import (
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
sys "golang.org/x/sys/unix"
|
||||
|
||||
"github.com/go-delve/delve/pkg/dwarf/op"
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
"github.com/go-delve/delve/pkg/proc/linutil"
|
||||
)
|
||||
|
||||
// Defined in asm/ptrace.h
|
||||
const (
|
||||
_RISCV64_GREGS_SIZE = 32 * 8
|
||||
_RISCV64_FPREGS_SIZE = (32 * 8) + 4 + 4 // Add 4 bytes to align with 8 due to sys.Iovec uses uint64 as len
|
||||
)
|
||||
|
||||
func ptraceGetGRegs(pid int, regs *linutil.RISCV64PtraceRegs) (err error) {
|
||||
iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(regs)), Len: _RISCV64_GREGS_SIZE}
|
||||
|
||||
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(pid),
|
||||
uintptr(elf.NT_PRSTATUS), uintptr(unsafe.Pointer(&iov)), 0, 0)
|
||||
if err == syscall.Errno(0) {
|
||||
err = nil
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func ptraceSetGRegs(pid int, regs *linutil.RISCV64PtraceRegs) (err error) {
|
||||
iov := sys.Iovec{Base: (*byte)(unsafe.Pointer(regs)), Len: _RISCV64_GREGS_SIZE}
|
||||
|
||||
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETREGSET, uintptr(pid), uintptr(elf.NT_PRSTATUS), uintptr(unsafe.Pointer(&iov)), 0, 0)
|
||||
if err == syscall.Errno(0) {
|
||||
err = nil
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func ptraceGetFpRegset(tid int, fpregs *linutil.RISCV64PtraceFpRegs) (err error) {
|
||||
fprBytes := make([]byte, _RISCV64_FPREGS_SIZE)
|
||||
iov := sys.Iovec{Base: &fprBytes[0], Len: uint64(_RISCV64_FPREGS_SIZE)}
|
||||
|
||||
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(tid), uintptr(elf.NT_FPREGSET), uintptr(unsafe.Pointer(&iov)), 0, 0)
|
||||
if err != syscall.Errno(0) {
|
||||
if err == syscall.ENODEV {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
} else {
|
||||
err = nil
|
||||
}
|
||||
|
||||
fpregs.Fregs = fprBytes[:iov.Len-8]
|
||||
fpregs.Fcsr = binary.LittleEndian.Uint32(fprBytes[iov.Len-8 : iov.Len-4])
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (thread *nativeThread) setPC(pc uint64) error {
|
||||
ir, err := registers(thread)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := ir.(*linutil.RISCV64Registers)
|
||||
r.Regs.Pc = pc
|
||||
thread.dbp.execPtraceFunc(func() { err = ptraceSetGRegs(thread.ID, r.Regs) })
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (thread *nativeThread) setSP(sp uint64) (err error) {
|
||||
var ir proc.Registers
|
||||
|
||||
ir, err = registers(thread)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := ir.(*linutil.RISCV64Registers)
|
||||
r.Regs.Sp = sp
|
||||
thread.dbp.execPtraceFunc(func() { err = ptraceSetGRegs(thread.ID, r.Regs) })
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {
|
||||
ir, err := registers(thread)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r := ir.(*linutil.RISCV64Registers)
|
||||
fpchanged, err := r.SetReg(regNum, reg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
thread.dbp.execPtraceFunc(func() {
|
||||
err = ptraceSetGRegs(thread.ID, r.Regs)
|
||||
if err != syscall.Errno(0) && err != nil {
|
||||
return
|
||||
}
|
||||
if fpchanged && r.Fpregset != nil {
|
||||
iov := sys.Iovec{Base: &r.Fpregset[0], Len: uint64(len(r.Fpregset))}
|
||||
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETREGSET, uintptr(thread.ID), uintptr(elf.NT_FPREGSET), uintptr(unsafe.Pointer(&iov)), 0, 0)
|
||||
}
|
||||
})
|
||||
if err == syscall.Errno(0) {
|
||||
err = nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func registers(thread *nativeThread) (proc.Registers, error) {
|
||||
var (
|
||||
regs linutil.RISCV64PtraceRegs
|
||||
err error
|
||||
)
|
||||
|
||||
thread.dbp.execPtraceFunc(func() { err = ptraceGetGRegs(thread.ID, ®s) })
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tp_tls uint64
|
||||
if thread.dbp.iscgo {
|
||||
tp_tls = regs.Tp
|
||||
}
|
||||
r := linutil.NewRISCV64Registers(®s, thread.dbp.iscgo, tp_tls,
|
||||
func(r *linutil.RISCV64Registers) error {
|
||||
var floatLoadError error
|
||||
r.Fpregs, r.Fpregset, floatLoadError = thread.fpRegisters()
|
||||
return floatLoadError
|
||||
})
|
||||
|
||||
return r, nil
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
//go:build linux && !amd64 && !arm64 && !386 && !(ppc64le && exp.linuxppc64le)
|
||||
//go:build linux && !amd64 && !arm64 && !386 && !(ppc64le && exp.linuxppc64le) && !riscv64
|
||||
|
||||
// This file is used to detect build on unsupported GOOS/GOARCH combinations.
|
||||
|
||||
|
45
pkg/proc/native/threads_hardware_singlestep_linux.go
Normal file
45
pkg/proc/native/threads_hardware_singlestep_linux.go
Normal file
@ -0,0 +1,45 @@
|
||||
//go:build !riscv64
|
||||
|
||||
package native
|
||||
|
||||
import (
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
sys "golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func (procgrp *processGroup) singleStep(t *nativeThread) (err error) {
|
||||
sig := 0
|
||||
for {
|
||||
t.dbp.execPtraceFunc(func() { err = ptraceSingleStep(t.ID, sig) })
|
||||
sig = 0
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
wpid, status, err := t.dbp.waitFast(t.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (status == nil || status.Exited()) && wpid == t.dbp.pid {
|
||||
t.dbp.postExit()
|
||||
rs := 0
|
||||
if status != nil {
|
||||
rs = status.ExitStatus()
|
||||
}
|
||||
return proc.ErrProcessExited{Pid: t.dbp.pid, Status: rs}
|
||||
}
|
||||
if wpid == t.ID {
|
||||
switch s := status.StopSignal(); s {
|
||||
case sys.SIGTRAP:
|
||||
return nil
|
||||
case sys.SIGSTOP:
|
||||
// delayed SIGSTOP, ignore it
|
||||
case sys.SIGILL, sys.SIGBUS, sys.SIGFPE, sys.SIGSEGV, sys.SIGSTKFLT:
|
||||
// propagate signals that can have been caused by the current instruction
|
||||
sig = int(s)
|
||||
default:
|
||||
// delay propagation of all other signals
|
||||
t.os.delayedSignal = int(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,8 +4,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
sys "golang.org/x/sys/unix"
|
||||
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
)
|
||||
|
||||
type waitStatus sys.WaitStatus
|
||||
@ -50,43 +48,6 @@ func (t *nativeThread) resumeWithSig(sig int) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (procgrp *processGroup) singleStep(t *nativeThread) (err error) {
|
||||
sig := 0
|
||||
for {
|
||||
t.dbp.execPtraceFunc(func() { err = ptraceSingleStep(t.ID, sig) })
|
||||
sig = 0
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
wpid, status, err := t.dbp.waitFast(t.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (status == nil || status.Exited()) && wpid == t.dbp.pid {
|
||||
t.dbp.postExit()
|
||||
rs := 0
|
||||
if status != nil {
|
||||
rs = status.ExitStatus()
|
||||
}
|
||||
return proc.ErrProcessExited{Pid: t.dbp.pid, Status: rs}
|
||||
}
|
||||
if wpid == t.ID {
|
||||
switch s := status.StopSignal(); s {
|
||||
case sys.SIGTRAP:
|
||||
return nil
|
||||
case sys.SIGSTOP:
|
||||
// delayed SIGSTOP, ignore it
|
||||
case sys.SIGILL, sys.SIGBUS, sys.SIGFPE, sys.SIGSEGV, sys.SIGSTKFLT:
|
||||
// propagate signals that can have been caused by the current instruction
|
||||
sig = int(s)
|
||||
default:
|
||||
// delay propagation of all other signals
|
||||
t.os.delayedSignal = int(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *nativeThread) WriteMemory(addr uint64, data []byte) (written int, err error) {
|
||||
if ok, err := t.dbp.Valid(); !ok {
|
||||
return 0, err
|
||||
|
294
pkg/proc/native/threads_linux_riscv64.go
Normal file
294
pkg/proc/native/threads_linux_riscv64.go
Normal file
@ -0,0 +1,294 @@
|
||||
package native
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
sys "golang.org/x/sys/unix"
|
||||
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
"github.com/go-delve/delve/pkg/proc/linutil"
|
||||
"golang.org/x/arch/riscv64/riscv64asm"
|
||||
)
|
||||
|
||||
func (thread *nativeThread) fpRegisters() ([]proc.Register, []byte, error) {
|
||||
var err error
|
||||
var riscv64_fpregs linutil.RISCV64PtraceFpRegs
|
||||
|
||||
thread.dbp.execPtraceFunc(func() { err = ptraceGetFpRegset(thread.ID, &riscv64_fpregs) })
|
||||
fpregs := riscv64_fpregs.Decode()
|
||||
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not get floating point registers: %v", err.Error())
|
||||
}
|
||||
|
||||
return fpregs, riscv64_fpregs.Fregs, err
|
||||
}
|
||||
|
||||
func (t *nativeThread) restoreRegisters(savedRegs proc.Registers) error {
|
||||
var restoreRegistersErr error
|
||||
|
||||
sr := savedRegs.(*linutil.RISCV64Registers)
|
||||
t.dbp.execPtraceFunc(func() {
|
||||
restoreRegistersErr = ptraceSetGRegs(t.ID, sr.Regs)
|
||||
if restoreRegistersErr != syscall.Errno(0) {
|
||||
return
|
||||
}
|
||||
|
||||
if sr.Fpregset != nil {
|
||||
iov := sys.Iovec{Base: &sr.Fpregset[0], Len: uint64(len(sr.Fpregset))}
|
||||
_, _, restoreRegistersErr = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_SETREGSET, uintptr(t.ID), uintptr(elf.NT_FPREGSET), uintptr(unsafe.Pointer(&iov)), 0, 0)
|
||||
}
|
||||
})
|
||||
|
||||
if restoreRegistersErr == syscall.Errno(0) {
|
||||
restoreRegistersErr = nil
|
||||
}
|
||||
|
||||
return restoreRegistersErr
|
||||
}
|
||||
|
||||
// resolvePC is used to resolve next PC for current instruction.
|
||||
func (t *nativeThread) resolvePC(savedRegs proc.Registers) ([]uint64, error) {
|
||||
regs := savedRegs.(*linutil.RISCV64Registers)
|
||||
nextInstLen := t.BinInfo().Arch.MaxInstructionLength()
|
||||
nextInstBytes := make([]byte, nextInstLen)
|
||||
var err error
|
||||
|
||||
t.dbp.execPtraceFunc(func() {
|
||||
_, err = sys.PtracePeekData(t.ID, uintptr(regs.PC()), nextInstBytes)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nextPCs := []uint64{regs.PC() + uint64(nextInstLen)}
|
||||
if bytes.Equal(nextInstBytes, t.BinInfo().Arch.AltBreakpointInstruction()) {
|
||||
return nextPCs, nil
|
||||
} else if bytes.Equal(nextInstBytes, t.BinInfo().Arch.BreakpointInstruction()) {
|
||||
nextInstLen = 2
|
||||
nextPCs = []uint64{regs.PC() + uint64(nextInstLen)}
|
||||
return nextPCs, nil
|
||||
}
|
||||
|
||||
nextInst, err := riscv64asm.Decode(nextInstBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if nextInst.Len == 2 {
|
||||
nextInstBytes = nextInstBytes[:2]
|
||||
nextInstLen = 2
|
||||
nextPCs = []uint64{regs.PC() + uint64(nextInstLen)}
|
||||
}
|
||||
|
||||
switch nextInst.Op {
|
||||
case riscv64asm.BEQ, riscv64asm.BNE, riscv64asm.BLT, riscv64asm.BGE, riscv64asm.BLTU, riscv64asm.BGEU:
|
||||
rs1, _ := nextInst.Args[0].(riscv64asm.Reg)
|
||||
rs2, _ := nextInst.Args[1].(riscv64asm.Reg)
|
||||
bimm12, _ := nextInst.Args[2].(riscv64asm.Simm)
|
||||
src1u, _ := regs.GetReg(uint64(rs1))
|
||||
src2u, _ := regs.GetReg(uint64(rs2))
|
||||
src1, src2 := int64(src1u), int64(src2u)
|
||||
|
||||
switch nextInst.Op {
|
||||
case riscv64asm.BEQ:
|
||||
if src1 == src2 && int(bimm12.Imm) != nextInstLen {
|
||||
nextPCs = append(nextPCs, regs.PC()+uint64(bimm12.Imm))
|
||||
}
|
||||
case riscv64asm.BNE:
|
||||
if src1 != src2 && int(bimm12.Imm) != nextInstLen {
|
||||
nextPCs = append(nextPCs, regs.PC()+uint64(bimm12.Imm))
|
||||
}
|
||||
case riscv64asm.BLT:
|
||||
if src1 < src2 && int(bimm12.Imm) != nextInstLen {
|
||||
nextPCs = append(nextPCs, regs.PC()+uint64(bimm12.Imm))
|
||||
}
|
||||
case riscv64asm.BGE:
|
||||
if src1 >= src2 && int(bimm12.Imm) != nextInstLen {
|
||||
nextPCs = append(nextPCs, regs.PC()+uint64(bimm12.Imm))
|
||||
}
|
||||
case riscv64asm.BLTU:
|
||||
if src1u < src2u && int(bimm12.Imm) != nextInstLen {
|
||||
nextPCs = append(nextPCs, regs.PC()+uint64(bimm12.Imm))
|
||||
}
|
||||
case riscv64asm.BGEU:
|
||||
if src1u >= src2u && int(bimm12.Imm) != nextInstLen {
|
||||
nextPCs = append(nextPCs, regs.PC()+uint64(bimm12.Imm))
|
||||
}
|
||||
}
|
||||
|
||||
case riscv64asm.JAL:
|
||||
jimm, _ := nextInst.Args[1].(riscv64asm.Simm)
|
||||
if int(jimm.Imm) != nextInstLen {
|
||||
nextPCs = append(nextPCs, regs.PC()+uint64(jimm.Imm))
|
||||
}
|
||||
|
||||
case riscv64asm.JALR:
|
||||
rd, _ := nextInst.Args[0].(riscv64asm.Reg)
|
||||
rs1_mem := nextInst.Args[1].(riscv64asm.RegOffset)
|
||||
rs1, ofs := rs1_mem.OfsReg, rs1_mem.Ofs
|
||||
src1, _ := regs.GetReg(uint64(rs1))
|
||||
if rd == riscv64asm.X0 && rs1 == riscv64asm.X1 {
|
||||
nextPCs = []uint64{(src1 + uint64(ofs.Imm)) & (^uint64(0x1))}
|
||||
}
|
||||
if (src1+uint64(ofs.Imm))&(^uint64(0x1)) != nextPCs[0] {
|
||||
nextPCs = append(nextPCs, (src1+uint64(ofs.Imm))&(^uint64(0x1)))
|
||||
}
|
||||
|
||||
// We can't put a breakpoint in the middle of a lr/sc atomic sequence, so look for the end of the sequence and put the breakpoint there.
|
||||
// RISC-V Go only use lr.w/d.aq, see comments at the beginning of $GOROOT/src/runtime/internal/atomic/atomic_riscv64.s
|
||||
case riscv64asm.LR_D_AQ, riscv64asm.LR_W_AQ:
|
||||
// Currently, RISC-V Go only use this kind of lr/sc sequence, so only check this pattern.
|
||||
// defined in $GOROOT/src/cmd/compile/internal/riscv64/ssa.go:
|
||||
// LR (Rarg0), Rtmp
|
||||
// BNE Rtmp, Rarg1, 3(PC)
|
||||
// SC Rarg2, (Rarg0), Rtmp
|
||||
// BNE Rtmp, ZERO, -3(PC)
|
||||
curPC := regs.PC() + uint64(nextInstLen)
|
||||
t.dbp.execPtraceFunc(func() {
|
||||
_, err = sys.PtracePeekData(t.ID, uintptr(curPC), nextInstBytes)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nextInst, err = riscv64asm.Decode(nextInstBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if nextInst.Len == 2 {
|
||||
nextInstBytes = nextInstBytes[:2]
|
||||
}
|
||||
if nextInst.Op != riscv64asm.BNE {
|
||||
break
|
||||
}
|
||||
|
||||
curPC += uint64(nextInstLen)
|
||||
t.dbp.execPtraceFunc(func() {
|
||||
_, err = sys.PtracePeekData(t.ID, uintptr(curPC), nextInstBytes)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nextInst, err = riscv64asm.Decode(nextInstBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if nextInst.Len == 2 {
|
||||
nextInstBytes = nextInstBytes[:2]
|
||||
}
|
||||
if nextInst.Op != riscv64asm.SC_D_RL && nextInst.Op != riscv64asm.SC_W_RL {
|
||||
break
|
||||
}
|
||||
|
||||
curPC += uint64(nextInstLen)
|
||||
t.dbp.execPtraceFunc(func() {
|
||||
_, err = sys.PtracePeekData(t.ID, uintptr(regs.PC()+uint64(curPC)), nextInstBytes)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nextInst, err = riscv64asm.Decode(nextInstBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if nextInst.Len == 2 {
|
||||
nextInstBytes = nextInstBytes[:2]
|
||||
}
|
||||
if nextInst.Op != riscv64asm.BNE {
|
||||
break
|
||||
}
|
||||
nextPCs = []uint64{curPC}
|
||||
}
|
||||
|
||||
return nextPCs, nil
|
||||
}
|
||||
|
||||
// RISC-V doesn't have ptrace singlestep support, so use breakpoint to emulate it.
|
||||
func (procgrp *processGroup) singleStep(t *nativeThread) (err error) {
|
||||
regs, err := t.Registers()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nextPCs, err := t.resolvePC(regs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
originalDataSet := make(map[uintptr][]byte)
|
||||
|
||||
// Do in batch, first set breakpoint, then continue.
|
||||
t.dbp.execPtraceFunc(func() {
|
||||
breakpointInstr := t.BinInfo().Arch.BreakpointInstruction()
|
||||
readWriteMem := func(i int, addr uintptr, instr []byte) error {
|
||||
originalData := make([]byte, len(breakpointInstr))
|
||||
_, err = sys.PtracePeekData(t.ID, addr, originalData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = sys.PtracePokeData(t.ID, addr, instr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Everything is ok, store originalData
|
||||
originalDataSet[addr] = originalData
|
||||
return nil
|
||||
}
|
||||
for i, nextPC := range nextPCs {
|
||||
err = readWriteMem(i, uintptr(nextPC), breakpointInstr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
// Make sure we restore before return.
|
||||
defer func() {
|
||||
t.dbp.execPtraceFunc(func() {
|
||||
for addr, originalData := range originalDataSet {
|
||||
if originalData != nil {
|
||||
_, err = sys.PtracePokeData(t.ID, addr, originalData)
|
||||
}
|
||||
}
|
||||
})
|
||||
}()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
sig := 0
|
||||
t.dbp.execPtraceFunc(func() { err = ptraceCont(t.ID, sig) })
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// To be able to catch process exit, we can only use wait instead of waitFast.
|
||||
wpid, status, err := t.dbp.wait(t.ID, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (status == nil || status.Exited()) && wpid == t.dbp.pid {
|
||||
t.dbp.postExit()
|
||||
rs := 0
|
||||
if status != nil {
|
||||
rs = status.ExitStatus()
|
||||
}
|
||||
return proc.ErrProcessExited{Pid: t.dbp.pid, Status: rs}
|
||||
}
|
||||
if wpid == t.ID {
|
||||
sig = 0
|
||||
switch s := status.StopSignal(); s {
|
||||
case sys.SIGTRAP:
|
||||
return nil
|
||||
case sys.SIGSTOP:
|
||||
// delayed SIGSTOP, ignore it
|
||||
case sys.SIGILL, sys.SIGBUS, sys.SIGFPE, sys.SIGSEGV, sys.SIGSTKFLT:
|
||||
// propagate signals that can have been caused by the current instruction
|
||||
sig = int(s)
|
||||
default:
|
||||
// delay propagation of all other signals
|
||||
t.os.delayedSignal = int(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ const (
|
||||
_IMAGE_FILE_MACHINE_POWERPC = 0x1f0
|
||||
_IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1
|
||||
_IMAGE_FILE_MACHINE_R4000 = 0x166
|
||||
_IMAGE_FILE_MACHINE_RISCV64 = 0x5064
|
||||
_IMAGE_FILE_MACHINE_SH3 = 0x1a2
|
||||
_IMAGE_FILE_MACHINE_SH3DSP = 0x1a3
|
||||
_IMAGE_FILE_MACHINE_SH4 = 0x1a6
|
||||
|
@ -2808,6 +2808,7 @@ func TestDebugStripped2(t *testing.T) {
|
||||
skipOn(t, "not working on freebsd", "freebsd")
|
||||
skipOn(t, "not working on linux/386", "linux", "386")
|
||||
skipOn(t, "not working on linux/ppc64le when -gcflags=-N -l is passed", "linux", "ppc64le")
|
||||
skipOn(t, "not working on linux/riscv64", "linux", "riscv64")
|
||||
ver, _ := goversion.Parse(runtime.Version())
|
||||
if ver.IsDevel() {
|
||||
t.Skip("not supported")
|
||||
@ -2955,6 +2956,7 @@ func TestCgoStacktrace(t *testing.T) {
|
||||
skipOn(t, "broken - cgo stacktraces", "386")
|
||||
skipOn(t, "broken - cgo stacktraces", "windows", "arm64")
|
||||
skipOn(t, "broken - cgo stacktraces", "linux", "ppc64le")
|
||||
skipOn(t, "broken - cgo stacktraces", "linux", "riscv64")
|
||||
if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 21) {
|
||||
skipOn(t, "broken - cgo stacktraces", "windows", "arm64")
|
||||
}
|
||||
@ -3343,6 +3345,7 @@ func TestHaltKeepsSteppingBreakpoints(t *testing.T) {
|
||||
func TestDisassembleGlobalVars(t *testing.T) {
|
||||
skipOn(t, "broken - global variable symbolication", "arm64") // On ARM64 symLookup can't look up variables due to how they are loaded, see issue #1778
|
||||
skipOn(t, "broken - global variable symbolication", "ppc64le") // See comment on ARM64 above.
|
||||
skipOn(t, "broken - global variable symbolication", "riscv64")
|
||||
// On 386 linux when pie, the generated code use __x86.get_pc_thunk to ensure position-independent.
|
||||
// Locate global variable by
|
||||
// `CALL __x86.get_pc_thunk.ax(SB) 0xb0f7f
|
||||
@ -3634,6 +3637,7 @@ func TestIssue951(t *testing.T) {
|
||||
|
||||
func TestDWZCompression(t *testing.T) {
|
||||
skipOn(t, "broken", "ppc64le")
|
||||
skipOn(t, "broken", "riscv64")
|
||||
// If dwz is not available in the system, skip this test
|
||||
if _, err := exec.LookPath("dwz"); err != nil {
|
||||
t.Skip("dwz not installed")
|
||||
@ -4196,6 +4200,7 @@ func TestCgoStacktrace2(t *testing.T) {
|
||||
skipOn(t, "broken", "386")
|
||||
skipOn(t, "broken - cgo stacktraces", "darwin", "arm64")
|
||||
skipOn(t, "broken", "ppc64le")
|
||||
skipOn(t, "broken", "riscv64")
|
||||
protest.MustHaveCgo(t)
|
||||
// If a panic happens during cgo execution the stacktrace should show the C
|
||||
// function that caused the problem.
|
||||
@ -4735,6 +4740,7 @@ func TestWatchpointsBasic(t *testing.T) {
|
||||
skipOn(t, "not implemented", "freebsd")
|
||||
skipOn(t, "not implemented", "386")
|
||||
skipOn(t, "not implemented", "ppc64le")
|
||||
skipOn(t, "not implemented", "riscv64")
|
||||
skipOn(t, "see https://github.com/go-delve/delve/issues/2768", "windows")
|
||||
protest.AllowRecording(t)
|
||||
|
||||
@ -4791,6 +4797,7 @@ func TestWatchpointCounts(t *testing.T) {
|
||||
skipOn(t, "not implemented", "386")
|
||||
skipOn(t, "see https://github.com/go-delve/delve/issues/2768", "windows")
|
||||
skipOn(t, "not implemented", "ppc64le")
|
||||
skipOn(t, "not implemented", "riscv64")
|
||||
if _, isTeamCityTest := os.LookupEnv("TEAMCITY_VERSION"); isTeamCityTest {
|
||||
skipOn(t, "CI is running a version of macOS that is too old (11.2)", "darwin", "arm64")
|
||||
}
|
||||
@ -4908,6 +4915,7 @@ func TestWatchpointStack(t *testing.T) {
|
||||
skipOn(t, "not implemented", "freebsd")
|
||||
skipOn(t, "not implemented", "386")
|
||||
skipOn(t, "not implemented", "ppc64le")
|
||||
skipOn(t, "not implemented", "riscv64")
|
||||
skipOn(t, "see https://github.com/go-delve/delve/issues/2768", "windows")
|
||||
if _, isTeamCityTest := os.LookupEnv("TEAMCITY_VERSION"); isTeamCityTest {
|
||||
skipOn(t, "CI is running a version of macOS that is too old (11.2)", "darwin", "arm64")
|
||||
@ -5066,6 +5074,8 @@ func TestNilPtrDerefInBreakInstr(t *testing.T) {
|
||||
asmfile = "main_386.s"
|
||||
case "ppc64le":
|
||||
asmfile = "main_ppc64le.s"
|
||||
case "riscv64":
|
||||
asmfile = "main_riscv64.s"
|
||||
default:
|
||||
t.Fatalf("assembly file for %s not provided", runtime.GOARCH)
|
||||
}
|
||||
|
286
pkg/proc/riscv64_arch.go
Normal file
286
pkg/proc/riscv64_arch.go
Normal file
@ -0,0 +1,286 @@
|
||||
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"
|
||||
)
|
||||
|
||||
// ebreak instruction: 0x00100073
|
||||
var riscv64BreakInstruction = []byte{0x73, 0x00, 0x10, 0x00}
|
||||
|
||||
// c.ebreak instruction: 0x9002
|
||||
var riscv64CompressedBreakInstruction = []byte{0x02, 0x90}
|
||||
|
||||
// RISCV64Arch returns an initialized RISCV64 struct.
|
||||
func RISCV64Arch(goos string) *Arch {
|
||||
return &Arch{
|
||||
Name: "riscv64",
|
||||
ptrSize: 8,
|
||||
maxInstructionLength: 4,
|
||||
breakpointInstruction: riscv64CompressedBreakInstruction,
|
||||
altBreakpointInstruction: riscv64BreakInstruction,
|
||||
breakInstrMovesPC: false,
|
||||
derefTLS: false,
|
||||
prologues: prologuesRISCV64,
|
||||
fixFrameUnwindContext: riscv64FixFrameUnwindContext,
|
||||
switchStack: riscv64SwitchStack,
|
||||
regSize: riscv64RegSize,
|
||||
RegistersToDwarfRegisters: riscv64RegistersToDwarfRegisters,
|
||||
addrAndStackRegsToDwarfRegisters: riscv64AddrAndStackRegsToDwarfRegisters,
|
||||
DwarfRegisterToString: riscv64DwarfRegisterToString,
|
||||
inhibitStepInto: func(*BinaryInfo, uint64) bool { return false },
|
||||
asmDecode: riscv64AsmDecode,
|
||||
usesLR: true,
|
||||
PCRegNum: regnum.RISCV64_PC,
|
||||
SPRegNum: regnum.RISCV64_SP,
|
||||
asmRegisters: riscv64AsmRegisters,
|
||||
RegisterNameToDwarf: nameToDwarfFunc(regnum.RISCV64NameToDwarf),
|
||||
RegnumToString: regnum.RISCV64ToName,
|
||||
debugCallMinStackSize: 288, // TODO
|
||||
maxRegArgBytes: 16*8 + 16*8, // 16 int argument registers plus 16 float argument registers
|
||||
}
|
||||
}
|
||||
|
||||
func riscv64FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryInfo) *frame.FrameContext {
|
||||
a := bi.Arch
|
||||
|
||||
if a.sigreturnfn == nil {
|
||||
a.sigreturnfn = bi.lookupOneFunc("runtime.sigreturn")
|
||||
}
|
||||
|
||||
if (fctxt == nil) || ((a.sigreturnfn != nil) && (pc >= a.sigreturnfn.Entry) && (pc < a.sigreturnfn.End)) {
|
||||
// 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
|
||||
|
||||
// When the signal handler runs it will move the execution to the signal
|
||||
// handling stack (installed using the sigaltstack system call).
|
||||
// This isn't a proper stack switch: the pointer to g in TLS will still
|
||||
// refer to whatever g was executing on that thread before the signal was
|
||||
// received.
|
||||
// Since go did not execute a stack switch the previous value of sp, pc
|
||||
// and bp is not saved inside g.sched, as it normally would.
|
||||
// The only way to recover is to either read sp/pc from the signal context
|
||||
// parameter (the ucontext_t* parameter) or to unconditionally follow the
|
||||
// frame pointer when we get to runtime.sigreturn (which is what we do
|
||||
// here).
|
||||
|
||||
return &frame.FrameContext{
|
||||
RetAddrReg: regnum.RISCV64_PC,
|
||||
Regs: map[uint64]frame.DWRule{
|
||||
regnum.RISCV64_PC: {
|
||||
Rule: frame.RuleOffset,
|
||||
Offset: int64(-a.PtrSize()),
|
||||
},
|
||||
|
||||
regnum.RISCV64_FP: {
|
||||
Rule: frame.RuleOffset,
|
||||
Offset: int64(-2 * a.PtrSize()),
|
||||
},
|
||||
|
||||
regnum.RISCV64_SP: {
|
||||
Rule: frame.RuleValOffset,
|
||||
Offset: 0,
|
||||
},
|
||||
},
|
||||
|
||||
CFA: frame.DWRule{
|
||||
Rule: frame.RuleCFA,
|
||||
Reg: regnum.RISCV64_FP,
|
||||
Offset: int64(2 * a.PtrSize()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if a.crosscall2fn == nil {
|
||||
a.crosscall2fn = bi.lookupOneFunc("crosscall2")
|
||||
}
|
||||
|
||||
if a.crosscall2fn != nil && pc >= a.crosscall2fn.Entry && pc < a.crosscall2fn.End {
|
||||
rule := fctxt.CFA
|
||||
|
||||
if rule.Offset == crosscall2SPOffsetBad {
|
||||
rule.Offset += crosscall2SPOffset
|
||||
}
|
||||
fctxt.CFA = rule
|
||||
}
|
||||
|
||||
// We assume that FP is the frame pointer and we want to keep it updated,
|
||||
// so that we can use it to unwind the stack even when we encounter frames
|
||||
// without descriptor entries.
|
||||
// If there isn't a rule already we emit one.
|
||||
if fctxt.Regs[regnum.RISCV64_FP].Rule == frame.RuleUndefined {
|
||||
fctxt.Regs[regnum.RISCV64_FP] = frame.DWRule{
|
||||
Rule: frame.RuleFramePointer,
|
||||
Reg: regnum.RISCV64_FP,
|
||||
Offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
if fctxt.Regs[regnum.RISCV64_LR].Rule == frame.RuleUndefined {
|
||||
fctxt.Regs[regnum.RISCV64_LR] = frame.DWRule{
|
||||
Rule: frame.RuleRegister,
|
||||
Reg: regnum.RISCV64_LR,
|
||||
Offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
return fctxt
|
||||
}
|
||||
|
||||
const riscv64cgocallSPOffsetSaveSlot = 0x8
|
||||
const riscv64prevG0schedSPOffsetSaveSlot = 0x10
|
||||
|
||||
func riscv64SwitchStack(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.cgocallback_gofunc", "runtime.cgocallback", "runtime.asmcgocall", "crosscall2":
|
||||
// cgostacktrace is broken on riscv64, so do nothing here.
|
||||
|
||||
case "runtime.goexit", "runtime.rt0_go", "runtime.mcall":
|
||||
// Look for "top of stack" functions.
|
||||
it.atend = true
|
||||
return true
|
||||
|
||||
case "runtime.mstart":
|
||||
// Calls to runtime.systemstack will switch to the systemstack then:
|
||||
// 1. alter the goroutine stack so that it looks like systemstack_switch
|
||||
// was called
|
||||
// 2. alter the system stack so that it looks like the bottom-most frame
|
||||
// belongs to runtime.mstart
|
||||
// If we find a runtime.mstart frame on the system stack of a goroutine
|
||||
// parked on runtime.systemstack_switch we assume runtime.systemstack was
|
||||
// called and continue tracing from the parked position.
|
||||
|
||||
if it.top || !it.systemstack || it.g == nil {
|
||||
return false
|
||||
}
|
||||
if fn := it.bi.PCToFunc(it.g.PC); fn == nil || fn.Name != "runtime.systemstack_switch" {
|
||||
return false
|
||||
}
|
||||
|
||||
it.switchToGoroutineStack()
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
fn := it.bi.PCToFunc(it.frame.Ret)
|
||||
if fn == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
switch fn.Name {
|
||||
case "runtime.asmcgocall":
|
||||
if !it.systemstack {
|
||||
return false
|
||||
}
|
||||
|
||||
// This function is called by a goroutine to execute a C function and
|
||||
// switches from the goroutine stack to the system stack.
|
||||
// Since we are unwinding the stack from callee to caller we have to switch
|
||||
// from the system stack to the goroutine stack.
|
||||
off, _ := readIntRaw(it.mem, uint64(callFrameRegs.SP()+riscv64cgocallSPOffsetSaveSlot), int64(it.bi.Arch.PtrSize()))
|
||||
oldsp := callFrameRegs.SP()
|
||||
newsp := uint64(int64(it.stackhi) - off)
|
||||
|
||||
// runtime.asmcgocall can also be called from inside the system stack,
|
||||
// in that case no stack switch actually happens
|
||||
if newsp == oldsp {
|
||||
return false
|
||||
}
|
||||
|
||||
it.systemstack = false
|
||||
callFrameRegs.Reg(callFrameRegs.SPRegNum).Uint64Val = uint64(int64(newsp))
|
||||
|
||||
return false
|
||||
|
||||
case "runtime.cgocallback_gofunc":
|
||||
// For a detailed description of how this works read the long comment at
|
||||
// the start of $GOROOT/src/runtime/cgocall.go and the source code of
|
||||
// runtime.cgocallback_gofunc in $GOROOT/src/runtime/asm_riscv64.s
|
||||
//
|
||||
// When a C functions calls back into go it will eventually call into
|
||||
// runtime.cgocallback_gofunc which is the function that does the stack
|
||||
// switch from the system stack back into the goroutine stack
|
||||
// Since we are going backwards on the stack here we see the transition
|
||||
// as goroutine stack -> system stack.
|
||||
if it.systemstack {
|
||||
return false
|
||||
}
|
||||
|
||||
it.loadG0SchedSP()
|
||||
if it.g0_sched_sp <= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// entering the system stack
|
||||
callFrameRegs.Reg(callFrameRegs.SPRegNum).Uint64Val = it.g0_sched_sp
|
||||
|
||||
// reads the previous value of g0.sched.sp that runtime.cgocallback_gofunc saved on the stack
|
||||
it.g0_sched_sp, _ = readUintRaw(it.mem, uint64(callFrameRegs.SP()+riscv64prevG0schedSPOffsetSaveSlot), int64(it.bi.Arch.PtrSize()))
|
||||
it.systemstack = true
|
||||
return false
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func riscv64RegSize(regnum uint64) int {
|
||||
// All CPU registers are 64bit
|
||||
return 8
|
||||
}
|
||||
|
||||
func riscv64RegistersToDwarfRegisters(staticBase uint64, regs Registers) *op.DwarfRegisters {
|
||||
dregs := initDwarfRegistersFromSlice(int(regnum.RISCV64MaxRegNum()), regs, regnum.RISCV64NameToDwarf)
|
||||
dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, regnum.RISCV64_PC, regnum.RISCV64_SP, regnum.RISCV64_FP, regnum.RISCV64_LR)
|
||||
dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, regnum.RISCV64NameToDwarf))
|
||||
return dr
|
||||
}
|
||||
|
||||
func riscv64AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
|
||||
dregs := make([]*op.DwarfRegister, int(regnum.RISCV64_PC+1))
|
||||
dregs[regnum.RISCV64_PC] = op.DwarfRegisterFromUint64(pc)
|
||||
dregs[regnum.RISCV64_SP] = op.DwarfRegisterFromUint64(sp)
|
||||
dregs[regnum.RISCV64_FP] = op.DwarfRegisterFromUint64(bp)
|
||||
dregs[regnum.RISCV64_LR] = op.DwarfRegisterFromUint64(lr)
|
||||
|
||||
return *op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, regnum.RISCV64_PC, regnum.RISCV64_SP, regnum.RISCV64_FP, regnum.RISCV64_LR)
|
||||
}
|
||||
|
||||
func riscv64DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
|
||||
name = regnum.RISCV64ToName(uint64(i))
|
||||
|
||||
if reg == nil {
|
||||
return name, false, ""
|
||||
}
|
||||
|
||||
if strings.HasPrefix(name, "F") {
|
||||
return name, true, fmt.Sprintf("%#016x", reg.Uint64Val)
|
||||
} else {
|
||||
return name, false, fmt.Sprintf("%#016x", reg.Uint64Val)
|
||||
}
|
||||
}
|
183
pkg/proc/riscv64_disasm.go
Normal file
183
pkg/proc/riscv64_disasm.go
Normal file
@ -0,0 +1,183 @@
|
||||
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
|
||||
}()
|
@ -299,7 +299,7 @@ func (it *stackIterator) switchToGoroutineStack() {
|
||||
it.pc = it.g.PC
|
||||
it.regs.Reg(it.regs.SPRegNum).Uint64Val = it.g.SP
|
||||
it.regs.AddReg(it.regs.BPRegNum, op.DwarfRegisterFromUint64(it.g.BP))
|
||||
if it.bi.Arch.Name == "arm64" || it.bi.Arch.Name == "ppc64le" {
|
||||
if it.bi.Arch.Name == "arm64" || it.bi.Arch.Name == "ppc64le" || it.bi.Arch.Name == "riscv64" {
|
||||
it.regs.Reg(it.regs.LRRegNum).Uint64Val = it.g.LR
|
||||
}
|
||||
}
|
||||
@ -564,7 +564,7 @@ func (it *stackIterator) advanceRegs() (callFrameRegs op.DwarfRegisters, ret uin
|
||||
}
|
||||
}
|
||||
|
||||
if it.bi.Arch.Name == "arm64" || it.bi.Arch.Name == "ppc64le" {
|
||||
if it.bi.Arch.Name == "arm64" || it.bi.Arch.Name == "ppc64le" || it.bi.Arch.Name == "riscv64" {
|
||||
if ret == 0 && it.regs.Reg(it.regs.LRRegNum) != nil {
|
||||
ret = it.regs.Reg(it.regs.LRRegNum).Uint64Val
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"go/constant"
|
||||
"go/token"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/arch/ppc64/ppc64asm"
|
||||
@ -1685,7 +1686,9 @@ func (t *Target) handleHardcodedBreakpoints(grp *TargetGroup, trapthread Thread,
|
||||
stepOverBreak(thread, loc.PC)
|
||||
// In linux-arm64, PtraceSingleStep seems cannot step over BRK instruction
|
||||
// (linux-arm64 feature or kernel bug maybe).
|
||||
if !arch.BreakInstrMovesPC() {
|
||||
// RISC-V use ebreak as hardcoded breakpoint in Go, however we use c.ebreak
|
||||
// in delve to support breakpoints in cgo.
|
||||
if !arch.BreakInstrMovesPC() && runtime.GOARCH != "riscv64" {
|
||||
setPC(thread, loc.PC+uint64(arch.BreakpointSize()))
|
||||
}
|
||||
// Single-step current thread until we exit runtime.breakpoint and
|
||||
|
@ -310,6 +310,9 @@ func MustSupportFunctionCalls(t *testing.T, testBackend string) {
|
||||
if runtime.GOARCH == "386" {
|
||||
t.Skip(fmt.Errorf("%s does not support FunctionCall for now", runtime.GOARCH))
|
||||
}
|
||||
if runtime.GOARCH == "riscv64" {
|
||||
t.Skip(fmt.Errorf("%s does not support FunctionCall for now", runtime.GOARCH))
|
||||
}
|
||||
if runtime.GOARCH == "arm64" {
|
||||
if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 19) || runtime.GOOS == "windows" {
|
||||
t.Skip("this version of Go does not support function calls")
|
||||
@ -382,7 +385,7 @@ func RegabiSupported() bool {
|
||||
// Tracks regabiSupported variable in ParseGOEXPERIMENT internal/buildcfg/exp.go
|
||||
switch {
|
||||
case goversion.VersionAfterOrEqual(runtime.Version(), 1, 18):
|
||||
return runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "ppc64"
|
||||
return runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "riscv64"
|
||||
case goversion.VersionAfterOrEqual(runtime.Version(), 1, 17):
|
||||
return runtime.GOARCH == "amd64" && (runtime.GOOS == "android" || runtime.GOOS == "linux" || runtime.GOOS == "darwin" || runtime.GOOS == "windows")
|
||||
default:
|
||||
|
@ -49,6 +49,9 @@ func TestDebugger_LaunchInvalidFormat(t *testing.T) {
|
||||
if runtime.GOARCH == "ppc64le" && runtime.GOOS == "linux" {
|
||||
t.Setenv("GOARCH", "amd64")
|
||||
}
|
||||
if runtime.GOARCH == "riscv64" && runtime.GOOS == "linux" {
|
||||
t.Setenv("GOARCH", "amd64")
|
||||
}
|
||||
t.Setenv("GOOS", switchOS[runtime.GOOS])
|
||||
exepath := filepath.Join(buildtestdir, debugname)
|
||||
if err := gobuild.GoBuild(debugname, []string{buildtestdir}, fmt.Sprintf("-o %s", exepath)); err != nil {
|
||||
|
@ -34,6 +34,9 @@ func TestDebugger_LaunchNoExecutablePerm(t *testing.T) {
|
||||
if runtime.GOARCH == "ppc64le" && runtime.GOOS == "linux" {
|
||||
t.Setenv("GOARCH", "amd64")
|
||||
}
|
||||
if runtime.GOARCH == "riscv64" && runtime.GOOS == "linux" {
|
||||
t.Setenv("GOARCH", "amd64")
|
||||
}
|
||||
t.Setenv("GOOS", switchOS[runtime.GOOS])
|
||||
exepath := filepath.Join(buildtestdir, debugname)
|
||||
defer os.Remove(exepath)
|
||||
|
116
vendor/golang.org/x/arch/riscv64/riscv64asm/arg.go
generated
vendored
Normal file
116
vendor/golang.org/x/arch/riscv64/riscv64asm/arg.go
generated
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package riscv64asm
|
||||
|
||||
// Naming for Go decoder arguments:
|
||||
//
|
||||
// - arg_rd: a general purpose register rd encoded in rd[11:7] field
|
||||
//
|
||||
// - arg_rs1: a general purpose register rs1 encoded in rs1[19:15] field
|
||||
//
|
||||
// - arg_rs2: a general purpose register rs2 encoded in rs2[24:20] field
|
||||
//
|
||||
// - arg_rs3: a general purpose register rs3 encoded in rs3[31:27] field
|
||||
//
|
||||
// - arg_fd: a floating point register rd encoded in rd[11:7] field
|
||||
//
|
||||
// - arg_fs1: a floating point register rs1 encoded in rs1[19:15] field
|
||||
//
|
||||
// - arg_fs2: a floating point register rs2 encoded in rs2[24:20] field
|
||||
//
|
||||
// - arg_fs3: a floating point register rs3 encoded in rs3[31:27] field
|
||||
//
|
||||
// - arg_csr: a control status register encoded in csr[31:20] field
|
||||
//
|
||||
// - arg_rs1_mem: source register with offset in load commands
|
||||
//
|
||||
// - arg_rs1_store: source register with offset in store commands
|
||||
//
|
||||
// - arg_rs1_amo: source register with offset in atomic commands
|
||||
//
|
||||
// - arg_pred: predecessor memory ordering information encoded in pred[27:24] field
|
||||
// For details, please refer to chapter 2.7 of ISA manual volume 1
|
||||
//
|
||||
// - arg_succ: successor memory ordering information encoded in succ[23:20] field
|
||||
// For details, please refer to chapter 2.7 of ISA manual volume 1
|
||||
//
|
||||
// - arg_zimm: a unsigned immediate encoded in zimm[19:15] field
|
||||
//
|
||||
// - arg_imm12: an I-type immediate encoded in imm12[31:20] field
|
||||
//
|
||||
// - arg_simm12: a S-type immediate encoded in simm12[31:25|11:7] field
|
||||
//
|
||||
// - arg_bimm12: a B-type immediate encoded in bimm12[31:25|11:7] field
|
||||
//
|
||||
// - arg_imm20: an U-type immediate encoded in imm20[31:12] field
|
||||
//
|
||||
// - arg_jimm20: a J-type immediate encoded in jimm20[31:12] field
|
||||
//
|
||||
// - arg_shamt5: a shift amount encoded in shamt5[24:20] field
|
||||
//
|
||||
// - arg_shamt6: a shift amount encoded in shamt6[25:20] field
|
||||
//
|
||||
|
||||
type argType uint16
|
||||
|
||||
const (
|
||||
_ argType = iota
|
||||
arg_rd
|
||||
arg_rs1
|
||||
arg_rs2
|
||||
arg_rs3
|
||||
arg_fd
|
||||
arg_fs1
|
||||
arg_fs2
|
||||
arg_fs3
|
||||
arg_csr
|
||||
|
||||
arg_rs1_amo
|
||||
arg_rs1_mem
|
||||
arg_rs1_store
|
||||
|
||||
arg_pred
|
||||
arg_succ
|
||||
|
||||
arg_zimm
|
||||
arg_imm12
|
||||
arg_simm12
|
||||
arg_bimm12
|
||||
arg_imm20
|
||||
arg_jimm20
|
||||
arg_shamt5
|
||||
arg_shamt6
|
||||
|
||||
// RISC-V Compressed Extension Args
|
||||
arg_rd_p
|
||||
arg_fd_p
|
||||
arg_rs1_p
|
||||
arg_rd_rs1_p
|
||||
arg_fs2_p
|
||||
arg_rs2_p
|
||||
arg_rd_n0
|
||||
arg_rs1_n0
|
||||
arg_rd_rs1_n0
|
||||
arg_c_rs1_n0
|
||||
arg_c_rs2_n0
|
||||
arg_c_fs2
|
||||
arg_c_rs2
|
||||
arg_rd_n2
|
||||
|
||||
arg_c_imm6
|
||||
arg_c_nzimm6
|
||||
arg_c_nzuimm6
|
||||
arg_c_uimm7
|
||||
arg_c_uimm8
|
||||
arg_c_uimm8sp_s
|
||||
arg_c_uimm8sp
|
||||
arg_c_uimm9sp_s
|
||||
arg_c_uimm9sp
|
||||
arg_c_bimm9
|
||||
arg_c_nzimm10
|
||||
arg_c_nzuimm10
|
||||
arg_c_imm12
|
||||
arg_c_nzimm18
|
||||
)
|
577
vendor/golang.org/x/arch/riscv64/riscv64asm/csr_string.go
generated
vendored
Normal file
577
vendor/golang.org/x/arch/riscv64/riscv64asm/csr_string.go
generated
vendored
Normal file
@ -0,0 +1,577 @@
|
||||
// Code generated by "stringer -type=CSR"; DO NOT EDIT.
|
||||
|
||||
package riscv64asm
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[USTATUS-0]
|
||||
_ = x[FFLAGS-1]
|
||||
_ = x[FRM-2]
|
||||
_ = x[FCSR-3]
|
||||
_ = x[UIE-4]
|
||||
_ = x[UTVEC-5]
|
||||
_ = x[UTVT-7]
|
||||
_ = x[VSTART-8]
|
||||
_ = x[VXSAT-9]
|
||||
_ = x[VXRM-10]
|
||||
_ = x[VCSR-15]
|
||||
_ = x[USCRATCH-64]
|
||||
_ = x[UEPC-65]
|
||||
_ = x[UCAUSE-66]
|
||||
_ = x[UTVAL-67]
|
||||
_ = x[UIP-68]
|
||||
_ = x[UNXTI-69]
|
||||
_ = x[UINTSTATUS-70]
|
||||
_ = x[USCRATCHCSW-72]
|
||||
_ = x[USCRATCHCSWL-73]
|
||||
_ = x[SSTATUS-256]
|
||||
_ = x[SEDELEG-258]
|
||||
_ = x[SIDELEG-259]
|
||||
_ = x[SIE-260]
|
||||
_ = x[STVEC-261]
|
||||
_ = x[SCOUNTEREN-262]
|
||||
_ = x[STVT-263]
|
||||
_ = x[SSCRATCH-320]
|
||||
_ = x[SEPC-321]
|
||||
_ = x[SCAUSE-322]
|
||||
_ = x[STVAL-323]
|
||||
_ = x[SIP-324]
|
||||
_ = x[SNXTI-325]
|
||||
_ = x[SINTSTATUS-326]
|
||||
_ = x[SSCRATCHCSW-328]
|
||||
_ = x[SSCRATCHCSWL-329]
|
||||
_ = x[SATP-384]
|
||||
_ = x[VSSTATUS-512]
|
||||
_ = x[VSIE-516]
|
||||
_ = x[VSTVEC-517]
|
||||
_ = x[VSSCRATCH-576]
|
||||
_ = x[VSEPC-577]
|
||||
_ = x[VSCAUSE-578]
|
||||
_ = x[VSTVAL-579]
|
||||
_ = x[VSIP-580]
|
||||
_ = x[VSATP-640]
|
||||
_ = x[MSTATUS-768]
|
||||
_ = x[MISA-769]
|
||||
_ = x[MEDELEG-770]
|
||||
_ = x[MIDELEG-771]
|
||||
_ = x[MIE-772]
|
||||
_ = x[MTVEC-773]
|
||||
_ = x[MCOUNTEREN-774]
|
||||
_ = x[MTVT-775]
|
||||
_ = x[MSTATUSH-784]
|
||||
_ = x[MCOUNTINHIBIT-800]
|
||||
_ = x[MHPMEVENT3-803]
|
||||
_ = x[MHPMEVENT4-804]
|
||||
_ = x[MHPMEVENT5-805]
|
||||
_ = x[MHPMEVENT6-806]
|
||||
_ = x[MHPMEVENT7-807]
|
||||
_ = x[MHPMEVENT8-808]
|
||||
_ = x[MHPMEVENT9-809]
|
||||
_ = x[MHPMEVENT10-810]
|
||||
_ = x[MHPMEVENT11-811]
|
||||
_ = x[MHPMEVENT12-812]
|
||||
_ = x[MHPMEVENT13-813]
|
||||
_ = x[MHPMEVENT14-814]
|
||||
_ = x[MHPMEVENT15-815]
|
||||
_ = x[MHPMEVENT16-816]
|
||||
_ = x[MHPMEVENT17-817]
|
||||
_ = x[MHPMEVENT18-818]
|
||||
_ = x[MHPMEVENT19-819]
|
||||
_ = x[MHPMEVENT20-820]
|
||||
_ = x[MHPMEVENT21-821]
|
||||
_ = x[MHPMEVENT22-822]
|
||||
_ = x[MHPMEVENT23-823]
|
||||
_ = x[MHPMEVENT24-824]
|
||||
_ = x[MHPMEVENT25-825]
|
||||
_ = x[MHPMEVENT26-826]
|
||||
_ = x[MHPMEVENT27-827]
|
||||
_ = x[MHPMEVENT28-828]
|
||||
_ = x[MHPMEVENT29-829]
|
||||
_ = x[MHPMEVENT30-830]
|
||||
_ = x[MHPMEVENT31-831]
|
||||
_ = x[MSCRATCH-832]
|
||||
_ = x[MEPC-833]
|
||||
_ = x[MCAUSE-834]
|
||||
_ = x[MTVAL-835]
|
||||
_ = x[MIP-836]
|
||||
_ = x[MNXTI-837]
|
||||
_ = x[MINTSTATUS-838]
|
||||
_ = x[MSCRATCHCSW-840]
|
||||
_ = x[MSCRATCHCSWL-841]
|
||||
_ = x[MTINST-842]
|
||||
_ = x[MTVAL2-843]
|
||||
_ = x[PMPCFG0-928]
|
||||
_ = x[PMPCFG1-929]
|
||||
_ = x[PMPCFG2-930]
|
||||
_ = x[PMPCFG3-931]
|
||||
_ = x[PMPADDR0-944]
|
||||
_ = x[PMPADDR1-945]
|
||||
_ = x[PMPADDR2-946]
|
||||
_ = x[PMPADDR3-947]
|
||||
_ = x[PMPADDR4-948]
|
||||
_ = x[PMPADDR5-949]
|
||||
_ = x[PMPADDR6-950]
|
||||
_ = x[PMPADDR7-951]
|
||||
_ = x[PMPADDR8-952]
|
||||
_ = x[PMPADDR9-953]
|
||||
_ = x[PMPADDR10-954]
|
||||
_ = x[PMPADDR11-955]
|
||||
_ = x[PMPADDR12-956]
|
||||
_ = x[PMPADDR13-957]
|
||||
_ = x[PMPADDR14-958]
|
||||
_ = x[PMPADDR15-959]
|
||||
_ = x[HSTATUS-1536]
|
||||
_ = x[HEDELEG-1538]
|
||||
_ = x[HIDELEG-1539]
|
||||
_ = x[HIE-1540]
|
||||
_ = x[HTIMEDELTA-1541]
|
||||
_ = x[HCOUNTEREN-1542]
|
||||
_ = x[HGEIE-1543]
|
||||
_ = x[HTIMEDELTAH-1557]
|
||||
_ = x[HTVAL-1603]
|
||||
_ = x[HIP-1604]
|
||||
_ = x[HVIP-1605]
|
||||
_ = x[HTINST-1610]
|
||||
_ = x[HGATP-1664]
|
||||
_ = x[TSELECT-1952]
|
||||
_ = x[TDATA1-1953]
|
||||
_ = x[TDATA2-1954]
|
||||
_ = x[TDATA3-1955]
|
||||
_ = x[TINFO-1956]
|
||||
_ = x[TCONTROL-1957]
|
||||
_ = x[MCONTEXT-1960]
|
||||
_ = x[MNOISE-1961]
|
||||
_ = x[SCONTEXT-1962]
|
||||
_ = x[DCSR-1968]
|
||||
_ = x[DPC-1969]
|
||||
_ = x[DSCRATCH0-1970]
|
||||
_ = x[DSCRATCH1-1971]
|
||||
_ = x[MCYCLE-2816]
|
||||
_ = x[MINSTRET-2818]
|
||||
_ = x[MHPMCOUNTER3-2819]
|
||||
_ = x[MHPMCOUNTER4-2820]
|
||||
_ = x[MHPMCOUNTER5-2821]
|
||||
_ = x[MHPMCOUNTER6-2822]
|
||||
_ = x[MHPMCOUNTER7-2823]
|
||||
_ = x[MHPMCOUNTER8-2824]
|
||||
_ = x[MHPMCOUNTER9-2825]
|
||||
_ = x[MHPMCOUNTER10-2826]
|
||||
_ = x[MHPMCOUNTER11-2827]
|
||||
_ = x[MHPMCOUNTER12-2828]
|
||||
_ = x[MHPMCOUNTER13-2829]
|
||||
_ = x[MHPMCOUNTER14-2830]
|
||||
_ = x[MHPMCOUNTER15-2831]
|
||||
_ = x[MHPMCOUNTER16-2832]
|
||||
_ = x[MHPMCOUNTER17-2833]
|
||||
_ = x[MHPMCOUNTER18-2834]
|
||||
_ = x[MHPMCOUNTER19-2835]
|
||||
_ = x[MHPMCOUNTER20-2836]
|
||||
_ = x[MHPMCOUNTER21-2837]
|
||||
_ = x[MHPMCOUNTER22-2838]
|
||||
_ = x[MHPMCOUNTER23-2839]
|
||||
_ = x[MHPMCOUNTER24-2840]
|
||||
_ = x[MHPMCOUNTER25-2841]
|
||||
_ = x[MHPMCOUNTER26-2842]
|
||||
_ = x[MHPMCOUNTER27-2843]
|
||||
_ = x[MHPMCOUNTER28-2844]
|
||||
_ = x[MHPMCOUNTER29-2845]
|
||||
_ = x[MHPMCOUNTER30-2846]
|
||||
_ = x[MHPMCOUNTER31-2847]
|
||||
_ = x[MCYCLEH-2944]
|
||||
_ = x[MINSTRETH-2946]
|
||||
_ = x[MHPMCOUNTER3H-2947]
|
||||
_ = x[MHPMCOUNTER4H-2948]
|
||||
_ = x[MHPMCOUNTER5H-2949]
|
||||
_ = x[MHPMCOUNTER6H-2950]
|
||||
_ = x[MHPMCOUNTER7H-2951]
|
||||
_ = x[MHPMCOUNTER8H-2952]
|
||||
_ = x[MHPMCOUNTER9H-2953]
|
||||
_ = x[MHPMCOUNTER10H-2954]
|
||||
_ = x[MHPMCOUNTER11H-2955]
|
||||
_ = x[MHPMCOUNTER12H-2956]
|
||||
_ = x[MHPMCOUNTER13H-2957]
|
||||
_ = x[MHPMCOUNTER14H-2958]
|
||||
_ = x[MHPMCOUNTER15H-2959]
|
||||
_ = x[MHPMCOUNTER16H-2960]
|
||||
_ = x[MHPMCOUNTER17H-2961]
|
||||
_ = x[MHPMCOUNTER18H-2962]
|
||||
_ = x[MHPMCOUNTER19H-2963]
|
||||
_ = x[MHPMCOUNTER20H-2964]
|
||||
_ = x[MHPMCOUNTER21H-2965]
|
||||
_ = x[MHPMCOUNTER22H-2966]
|
||||
_ = x[MHPMCOUNTER23H-2967]
|
||||
_ = x[MHPMCOUNTER24H-2968]
|
||||
_ = x[MHPMCOUNTER25H-2969]
|
||||
_ = x[MHPMCOUNTER26H-2970]
|
||||
_ = x[MHPMCOUNTER27H-2971]
|
||||
_ = x[MHPMCOUNTER28H-2972]
|
||||
_ = x[MHPMCOUNTER29H-2973]
|
||||
_ = x[MHPMCOUNTER30H-2974]
|
||||
_ = x[MHPMCOUNTER31H-2975]
|
||||
_ = x[CYCLE-3072]
|
||||
_ = x[TIME-3073]
|
||||
_ = x[INSTRET-3074]
|
||||
_ = x[HPMCOUNTER3-3075]
|
||||
_ = x[HPMCOUNTER4-3076]
|
||||
_ = x[HPMCOUNTER5-3077]
|
||||
_ = x[HPMCOUNTER6-3078]
|
||||
_ = x[HPMCOUNTER7-3079]
|
||||
_ = x[HPMCOUNTER8-3080]
|
||||
_ = x[HPMCOUNTER9-3081]
|
||||
_ = x[HPMCOUNTER10-3082]
|
||||
_ = x[HPMCOUNTER11-3083]
|
||||
_ = x[HPMCOUNTER12-3084]
|
||||
_ = x[HPMCOUNTER13-3085]
|
||||
_ = x[HPMCOUNTER14-3086]
|
||||
_ = x[HPMCOUNTER15-3087]
|
||||
_ = x[HPMCOUNTER16-3088]
|
||||
_ = x[HPMCOUNTER17-3089]
|
||||
_ = x[HPMCOUNTER18-3090]
|
||||
_ = x[HPMCOUNTER19-3091]
|
||||
_ = x[HPMCOUNTER20-3092]
|
||||
_ = x[HPMCOUNTER21-3093]
|
||||
_ = x[HPMCOUNTER22-3094]
|
||||
_ = x[HPMCOUNTER23-3095]
|
||||
_ = x[HPMCOUNTER24-3096]
|
||||
_ = x[HPMCOUNTER25-3097]
|
||||
_ = x[HPMCOUNTER26-3098]
|
||||
_ = x[HPMCOUNTER27-3099]
|
||||
_ = x[HPMCOUNTER28-3100]
|
||||
_ = x[HPMCOUNTER29-3101]
|
||||
_ = x[HPMCOUNTER30-3102]
|
||||
_ = x[HPMCOUNTER31-3103]
|
||||
_ = x[VL-3104]
|
||||
_ = x[VTYPE-3105]
|
||||
_ = x[VLENB-3106]
|
||||
_ = x[CYCLEH-3200]
|
||||
_ = x[TIMEH-3201]
|
||||
_ = x[INSTRETH-3202]
|
||||
_ = x[HPMCOUNTER3H-3203]
|
||||
_ = x[HPMCOUNTER4H-3204]
|
||||
_ = x[HPMCOUNTER5H-3205]
|
||||
_ = x[HPMCOUNTER6H-3206]
|
||||
_ = x[HPMCOUNTER7H-3207]
|
||||
_ = x[HPMCOUNTER8H-3208]
|
||||
_ = x[HPMCOUNTER9H-3209]
|
||||
_ = x[HPMCOUNTER10H-3210]
|
||||
_ = x[HPMCOUNTER11H-3211]
|
||||
_ = x[HPMCOUNTER12H-3212]
|
||||
_ = x[HPMCOUNTER13H-3213]
|
||||
_ = x[HPMCOUNTER14H-3214]
|
||||
_ = x[HPMCOUNTER15H-3215]
|
||||
_ = x[HPMCOUNTER16H-3216]
|
||||
_ = x[HPMCOUNTER17H-3217]
|
||||
_ = x[HPMCOUNTER18H-3218]
|
||||
_ = x[HPMCOUNTER19H-3219]
|
||||
_ = x[HPMCOUNTER20H-3220]
|
||||
_ = x[HPMCOUNTER21H-3221]
|
||||
_ = x[HPMCOUNTER22H-3222]
|
||||
_ = x[HPMCOUNTER23H-3223]
|
||||
_ = x[HPMCOUNTER24H-3224]
|
||||
_ = x[HPMCOUNTER25H-3225]
|
||||
_ = x[HPMCOUNTER26H-3226]
|
||||
_ = x[HPMCOUNTER27H-3227]
|
||||
_ = x[HPMCOUNTER28H-3228]
|
||||
_ = x[HPMCOUNTER29H-3229]
|
||||
_ = x[HPMCOUNTER30H-3230]
|
||||
_ = x[HPMCOUNTER31H-3231]
|
||||
_ = x[HGEIP-3602]
|
||||
_ = x[MVENDORID-3857]
|
||||
_ = x[MARCHID-3858]
|
||||
_ = x[MIMPID-3859]
|
||||
_ = x[MHARTID-3860]
|
||||
_ = x[MENTROPY-3861]
|
||||
}
|
||||
|
||||
const _CSR_name = "USTATUSFFLAGSFRMFCSRUIEUTVECUTVTVSTARTVXSATVXRMVCSRUSCRATCHUEPCUCAUSEUTVALUIPUNXTIUINTSTATUSUSCRATCHCSWUSCRATCHCSWLSSTATUSSEDELEGSIDELEGSIESTVECSCOUNTERENSTVTSSCRATCHSEPCSCAUSESTVALSIPSNXTISINTSTATUSSSCRATCHCSWSSCRATCHCSWLSATPVSSTATUSVSIEVSTVECVSSCRATCHVSEPCVSCAUSEVSTVALVSIPVSATPMSTATUSMISAMEDELEGMIDELEGMIEMTVECMCOUNTERENMTVTMSTATUSHMCOUNTINHIBITMHPMEVENT3MHPMEVENT4MHPMEVENT5MHPMEVENT6MHPMEVENT7MHPMEVENT8MHPMEVENT9MHPMEVENT10MHPMEVENT11MHPMEVENT12MHPMEVENT13MHPMEVENT14MHPMEVENT15MHPMEVENT16MHPMEVENT17MHPMEVENT18MHPMEVENT19MHPMEVENT20MHPMEVENT21MHPMEVENT22MHPMEVENT23MHPMEVENT24MHPMEVENT25MHPMEVENT26MHPMEVENT27MHPMEVENT28MHPMEVENT29MHPMEVENT30MHPMEVENT31MSCRATCHMEPCMCAUSEMTVALMIPMNXTIMINTSTATUSMSCRATCHCSWMSCRATCHCSWLMTINSTMTVAL2PMPCFG0PMPCFG1PMPCFG2PMPCFG3PMPADDR0PMPADDR1PMPADDR2PMPADDR3PMPADDR4PMPADDR5PMPADDR6PMPADDR7PMPADDR8PMPADDR9PMPADDR10PMPADDR11PMPADDR12PMPADDR13PMPADDR14PMPADDR15HSTATUSHEDELEGHIDELEGHIEHTIMEDELTAHCOUNTERENHGEIEHTIMEDELTAHHTVALHIPHVIPHTINSTHGATPTSELECTTDATA1TDATA2TDATA3TINFOTCONTROLMCONTEXTMNOISESCONTEXTDCSRDPCDSCRATCH0DSCRATCH1MCYCLEMINSTRETMHPMCOUNTER3MHPMCOUNTER4MHPMCOUNTER5MHPMCOUNTER6MHPMCOUNTER7MHPMCOUNTER8MHPMCOUNTER9MHPMCOUNTER10MHPMCOUNTER11MHPMCOUNTER12MHPMCOUNTER13MHPMCOUNTER14MHPMCOUNTER15MHPMCOUNTER16MHPMCOUNTER17MHPMCOUNTER18MHPMCOUNTER19MHPMCOUNTER20MHPMCOUNTER21MHPMCOUNTER22MHPMCOUNTER23MHPMCOUNTER24MHPMCOUNTER25MHPMCOUNTER26MHPMCOUNTER27MHPMCOUNTER28MHPMCOUNTER29MHPMCOUNTER30MHPMCOUNTER31MCYCLEHMINSTRETHMHPMCOUNTER3HMHPMCOUNTER4HMHPMCOUNTER5HMHPMCOUNTER6HMHPMCOUNTER7HMHPMCOUNTER8HMHPMCOUNTER9HMHPMCOUNTER10HMHPMCOUNTER11HMHPMCOUNTER12HMHPMCOUNTER13HMHPMCOUNTER14HMHPMCOUNTER15HMHPMCOUNTER16HMHPMCOUNTER17HMHPMCOUNTER18HMHPMCOUNTER19HMHPMCOUNTER20HMHPMCOUNTER21HMHPMCOUNTER22HMHPMCOUNTER23HMHPMCOUNTER24HMHPMCOUNTER25HMHPMCOUNTER26HMHPMCOUNTER27HMHPMCOUNTER28HMHPMCOUNTER29HMHPMCOUNTER30HMHPMCOUNTER31HCYCLETIMEINSTRETHPMCOUNTER3HPMCOUNTER4HPMCOUNTER5HPMCOUNTER6HPMCOUNTER7HPMCOUNTER8HPMCOUNTER9HPMCOUNTER10HPMCOUNTER11HPMCOUNTER12HPMCOUNTER13HPMCOUNTER14HPMCOUNTER15HPMCOUNTER16HPMCOUNTER17HPMCOUNTER18HPMCOUNTER19HPMCOUNTER20HPMCOUNTER21HPMCOUNTER22HPMCOUNTER23HPMCOUNTER24HPMCOUNTER25HPMCOUNTER26HPMCOUNTER27HPMCOUNTER28HPMCOUNTER29HPMCOUNTER30HPMCOUNTER31VLVTYPEVLENBCYCLEHTIMEHINSTRETHHPMCOUNTER3HHPMCOUNTER4HHPMCOUNTER5HHPMCOUNTER6HHPMCOUNTER7HHPMCOUNTER8HHPMCOUNTER9HHPMCOUNTER10HHPMCOUNTER11HHPMCOUNTER12HHPMCOUNTER13HHPMCOUNTER14HHPMCOUNTER15HHPMCOUNTER16HHPMCOUNTER17HHPMCOUNTER18HHPMCOUNTER19HHPMCOUNTER20HHPMCOUNTER21HHPMCOUNTER22HHPMCOUNTER23HHPMCOUNTER24HHPMCOUNTER25HHPMCOUNTER26HHPMCOUNTER27HHPMCOUNTER28HHPMCOUNTER29HHPMCOUNTER30HHPMCOUNTER31HHGEIPMVENDORIDMARCHIDMIMPIDMHARTIDMENTROPY"
|
||||
|
||||
var _CSR_map = map[CSR]string{
|
||||
0: _CSR_name[0:7],
|
||||
1: _CSR_name[7:13],
|
||||
2: _CSR_name[13:16],
|
||||
3: _CSR_name[16:20],
|
||||
4: _CSR_name[20:23],
|
||||
5: _CSR_name[23:28],
|
||||
7: _CSR_name[28:32],
|
||||
8: _CSR_name[32:38],
|
||||
9: _CSR_name[38:43],
|
||||
10: _CSR_name[43:47],
|
||||
15: _CSR_name[47:51],
|
||||
64: _CSR_name[51:59],
|
||||
65: _CSR_name[59:63],
|
||||
66: _CSR_name[63:69],
|
||||
67: _CSR_name[69:74],
|
||||
68: _CSR_name[74:77],
|
||||
69: _CSR_name[77:82],
|
||||
70: _CSR_name[82:92],
|
||||
72: _CSR_name[92:103],
|
||||
73: _CSR_name[103:115],
|
||||
256: _CSR_name[115:122],
|
||||
258: _CSR_name[122:129],
|
||||
259: _CSR_name[129:136],
|
||||
260: _CSR_name[136:139],
|
||||
261: _CSR_name[139:144],
|
||||
262: _CSR_name[144:154],
|
||||
263: _CSR_name[154:158],
|
||||
320: _CSR_name[158:166],
|
||||
321: _CSR_name[166:170],
|
||||
322: _CSR_name[170:176],
|
||||
323: _CSR_name[176:181],
|
||||
324: _CSR_name[181:184],
|
||||
325: _CSR_name[184:189],
|
||||
326: _CSR_name[189:199],
|
||||
328: _CSR_name[199:210],
|
||||
329: _CSR_name[210:222],
|
||||
384: _CSR_name[222:226],
|
||||
512: _CSR_name[226:234],
|
||||
516: _CSR_name[234:238],
|
||||
517: _CSR_name[238:244],
|
||||
576: _CSR_name[244:253],
|
||||
577: _CSR_name[253:258],
|
||||
578: _CSR_name[258:265],
|
||||
579: _CSR_name[265:271],
|
||||
580: _CSR_name[271:275],
|
||||
640: _CSR_name[275:280],
|
||||
768: _CSR_name[280:287],
|
||||
769: _CSR_name[287:291],
|
||||
770: _CSR_name[291:298],
|
||||
771: _CSR_name[298:305],
|
||||
772: _CSR_name[305:308],
|
||||
773: _CSR_name[308:313],
|
||||
774: _CSR_name[313:323],
|
||||
775: _CSR_name[323:327],
|
||||
784: _CSR_name[327:335],
|
||||
800: _CSR_name[335:348],
|
||||
803: _CSR_name[348:358],
|
||||
804: _CSR_name[358:368],
|
||||
805: _CSR_name[368:378],
|
||||
806: _CSR_name[378:388],
|
||||
807: _CSR_name[388:398],
|
||||
808: _CSR_name[398:408],
|
||||
809: _CSR_name[408:418],
|
||||
810: _CSR_name[418:429],
|
||||
811: _CSR_name[429:440],
|
||||
812: _CSR_name[440:451],
|
||||
813: _CSR_name[451:462],
|
||||
814: _CSR_name[462:473],
|
||||
815: _CSR_name[473:484],
|
||||
816: _CSR_name[484:495],
|
||||
817: _CSR_name[495:506],
|
||||
818: _CSR_name[506:517],
|
||||
819: _CSR_name[517:528],
|
||||
820: _CSR_name[528:539],
|
||||
821: _CSR_name[539:550],
|
||||
822: _CSR_name[550:561],
|
||||
823: _CSR_name[561:572],
|
||||
824: _CSR_name[572:583],
|
||||
825: _CSR_name[583:594],
|
||||
826: _CSR_name[594:605],
|
||||
827: _CSR_name[605:616],
|
||||
828: _CSR_name[616:627],
|
||||
829: _CSR_name[627:638],
|
||||
830: _CSR_name[638:649],
|
||||
831: _CSR_name[649:660],
|
||||
832: _CSR_name[660:668],
|
||||
833: _CSR_name[668:672],
|
||||
834: _CSR_name[672:678],
|
||||
835: _CSR_name[678:683],
|
||||
836: _CSR_name[683:686],
|
||||
837: _CSR_name[686:691],
|
||||
838: _CSR_name[691:701],
|
||||
840: _CSR_name[701:712],
|
||||
841: _CSR_name[712:724],
|
||||
842: _CSR_name[724:730],
|
||||
843: _CSR_name[730:736],
|
||||
928: _CSR_name[736:743],
|
||||
929: _CSR_name[743:750],
|
||||
930: _CSR_name[750:757],
|
||||
931: _CSR_name[757:764],
|
||||
944: _CSR_name[764:772],
|
||||
945: _CSR_name[772:780],
|
||||
946: _CSR_name[780:788],
|
||||
947: _CSR_name[788:796],
|
||||
948: _CSR_name[796:804],
|
||||
949: _CSR_name[804:812],
|
||||
950: _CSR_name[812:820],
|
||||
951: _CSR_name[820:828],
|
||||
952: _CSR_name[828:836],
|
||||
953: _CSR_name[836:844],
|
||||
954: _CSR_name[844:853],
|
||||
955: _CSR_name[853:862],
|
||||
956: _CSR_name[862:871],
|
||||
957: _CSR_name[871:880],
|
||||
958: _CSR_name[880:889],
|
||||
959: _CSR_name[889:898],
|
||||
1536: _CSR_name[898:905],
|
||||
1538: _CSR_name[905:912],
|
||||
1539: _CSR_name[912:919],
|
||||
1540: _CSR_name[919:922],
|
||||
1541: _CSR_name[922:932],
|
||||
1542: _CSR_name[932:942],
|
||||
1543: _CSR_name[942:947],
|
||||
1557: _CSR_name[947:958],
|
||||
1603: _CSR_name[958:963],
|
||||
1604: _CSR_name[963:966],
|
||||
1605: _CSR_name[966:970],
|
||||
1610: _CSR_name[970:976],
|
||||
1664: _CSR_name[976:981],
|
||||
1952: _CSR_name[981:988],
|
||||
1953: _CSR_name[988:994],
|
||||
1954: _CSR_name[994:1000],
|
||||
1955: _CSR_name[1000:1006],
|
||||
1956: _CSR_name[1006:1011],
|
||||
1957: _CSR_name[1011:1019],
|
||||
1960: _CSR_name[1019:1027],
|
||||
1961: _CSR_name[1027:1033],
|
||||
1962: _CSR_name[1033:1041],
|
||||
1968: _CSR_name[1041:1045],
|
||||
1969: _CSR_name[1045:1048],
|
||||
1970: _CSR_name[1048:1057],
|
||||
1971: _CSR_name[1057:1066],
|
||||
2816: _CSR_name[1066:1072],
|
||||
2818: _CSR_name[1072:1080],
|
||||
2819: _CSR_name[1080:1092],
|
||||
2820: _CSR_name[1092:1104],
|
||||
2821: _CSR_name[1104:1116],
|
||||
2822: _CSR_name[1116:1128],
|
||||
2823: _CSR_name[1128:1140],
|
||||
2824: _CSR_name[1140:1152],
|
||||
2825: _CSR_name[1152:1164],
|
||||
2826: _CSR_name[1164:1177],
|
||||
2827: _CSR_name[1177:1190],
|
||||
2828: _CSR_name[1190:1203],
|
||||
2829: _CSR_name[1203:1216],
|
||||
2830: _CSR_name[1216:1229],
|
||||
2831: _CSR_name[1229:1242],
|
||||
2832: _CSR_name[1242:1255],
|
||||
2833: _CSR_name[1255:1268],
|
||||
2834: _CSR_name[1268:1281],
|
||||
2835: _CSR_name[1281:1294],
|
||||
2836: _CSR_name[1294:1307],
|
||||
2837: _CSR_name[1307:1320],
|
||||
2838: _CSR_name[1320:1333],
|
||||
2839: _CSR_name[1333:1346],
|
||||
2840: _CSR_name[1346:1359],
|
||||
2841: _CSR_name[1359:1372],
|
||||
2842: _CSR_name[1372:1385],
|
||||
2843: _CSR_name[1385:1398],
|
||||
2844: _CSR_name[1398:1411],
|
||||
2845: _CSR_name[1411:1424],
|
||||
2846: _CSR_name[1424:1437],
|
||||
2847: _CSR_name[1437:1450],
|
||||
2944: _CSR_name[1450:1457],
|
||||
2946: _CSR_name[1457:1466],
|
||||
2947: _CSR_name[1466:1479],
|
||||
2948: _CSR_name[1479:1492],
|
||||
2949: _CSR_name[1492:1505],
|
||||
2950: _CSR_name[1505:1518],
|
||||
2951: _CSR_name[1518:1531],
|
||||
2952: _CSR_name[1531:1544],
|
||||
2953: _CSR_name[1544:1557],
|
||||
2954: _CSR_name[1557:1571],
|
||||
2955: _CSR_name[1571:1585],
|
||||
2956: _CSR_name[1585:1599],
|
||||
2957: _CSR_name[1599:1613],
|
||||
2958: _CSR_name[1613:1627],
|
||||
2959: _CSR_name[1627:1641],
|
||||
2960: _CSR_name[1641:1655],
|
||||
2961: _CSR_name[1655:1669],
|
||||
2962: _CSR_name[1669:1683],
|
||||
2963: _CSR_name[1683:1697],
|
||||
2964: _CSR_name[1697:1711],
|
||||
2965: _CSR_name[1711:1725],
|
||||
2966: _CSR_name[1725:1739],
|
||||
2967: _CSR_name[1739:1753],
|
||||
2968: _CSR_name[1753:1767],
|
||||
2969: _CSR_name[1767:1781],
|
||||
2970: _CSR_name[1781:1795],
|
||||
2971: _CSR_name[1795:1809],
|
||||
2972: _CSR_name[1809:1823],
|
||||
2973: _CSR_name[1823:1837],
|
||||
2974: _CSR_name[1837:1851],
|
||||
2975: _CSR_name[1851:1865],
|
||||
3072: _CSR_name[1865:1870],
|
||||
3073: _CSR_name[1870:1874],
|
||||
3074: _CSR_name[1874:1881],
|
||||
3075: _CSR_name[1881:1892],
|
||||
3076: _CSR_name[1892:1903],
|
||||
3077: _CSR_name[1903:1914],
|
||||
3078: _CSR_name[1914:1925],
|
||||
3079: _CSR_name[1925:1936],
|
||||
3080: _CSR_name[1936:1947],
|
||||
3081: _CSR_name[1947:1958],
|
||||
3082: _CSR_name[1958:1970],
|
||||
3083: _CSR_name[1970:1982],
|
||||
3084: _CSR_name[1982:1994],
|
||||
3085: _CSR_name[1994:2006],
|
||||
3086: _CSR_name[2006:2018],
|
||||
3087: _CSR_name[2018:2030],
|
||||
3088: _CSR_name[2030:2042],
|
||||
3089: _CSR_name[2042:2054],
|
||||
3090: _CSR_name[2054:2066],
|
||||
3091: _CSR_name[2066:2078],
|
||||
3092: _CSR_name[2078:2090],
|
||||
3093: _CSR_name[2090:2102],
|
||||
3094: _CSR_name[2102:2114],
|
||||
3095: _CSR_name[2114:2126],
|
||||
3096: _CSR_name[2126:2138],
|
||||
3097: _CSR_name[2138:2150],
|
||||
3098: _CSR_name[2150:2162],
|
||||
3099: _CSR_name[2162:2174],
|
||||
3100: _CSR_name[2174:2186],
|
||||
3101: _CSR_name[2186:2198],
|
||||
3102: _CSR_name[2198:2210],
|
||||
3103: _CSR_name[2210:2222],
|
||||
3104: _CSR_name[2222:2224],
|
||||
3105: _CSR_name[2224:2229],
|
||||
3106: _CSR_name[2229:2234],
|
||||
3200: _CSR_name[2234:2240],
|
||||
3201: _CSR_name[2240:2245],
|
||||
3202: _CSR_name[2245:2253],
|
||||
3203: _CSR_name[2253:2265],
|
||||
3204: _CSR_name[2265:2277],
|
||||
3205: _CSR_name[2277:2289],
|
||||
3206: _CSR_name[2289:2301],
|
||||
3207: _CSR_name[2301:2313],
|
||||
3208: _CSR_name[2313:2325],
|
||||
3209: _CSR_name[2325:2337],
|
||||
3210: _CSR_name[2337:2350],
|
||||
3211: _CSR_name[2350:2363],
|
||||
3212: _CSR_name[2363:2376],
|
||||
3213: _CSR_name[2376:2389],
|
||||
3214: _CSR_name[2389:2402],
|
||||
3215: _CSR_name[2402:2415],
|
||||
3216: _CSR_name[2415:2428],
|
||||
3217: _CSR_name[2428:2441],
|
||||
3218: _CSR_name[2441:2454],
|
||||
3219: _CSR_name[2454:2467],
|
||||
3220: _CSR_name[2467:2480],
|
||||
3221: _CSR_name[2480:2493],
|
||||
3222: _CSR_name[2493:2506],
|
||||
3223: _CSR_name[2506:2519],
|
||||
3224: _CSR_name[2519:2532],
|
||||
3225: _CSR_name[2532:2545],
|
||||
3226: _CSR_name[2545:2558],
|
||||
3227: _CSR_name[2558:2571],
|
||||
3228: _CSR_name[2571:2584],
|
||||
3229: _CSR_name[2584:2597],
|
||||
3230: _CSR_name[2597:2610],
|
||||
3231: _CSR_name[2610:2623],
|
||||
3602: _CSR_name[2623:2628],
|
||||
3857: _CSR_name[2628:2637],
|
||||
3858: _CSR_name[2637:2644],
|
||||
3859: _CSR_name[2644:2650],
|
||||
3860: _CSR_name[2650:2657],
|
||||
3861: _CSR_name[2657:2665],
|
||||
}
|
||||
|
||||
func (i CSR) String() string {
|
||||
if str, ok := _CSR_map[i]; ok {
|
||||
return str
|
||||
}
|
||||
return "CSR(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
550
vendor/golang.org/x/arch/riscv64/riscv64asm/decode.go
generated
vendored
Normal file
550
vendor/golang.org/x/arch/riscv64/riscv64asm/decode.go
generated
vendored
Normal file
@ -0,0 +1,550 @@
|
||||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package riscv64asm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type argTypeList [6]argType
|
||||
|
||||
// An instFormat describes the format of an instruction encoding.
|
||||
type instFormat struct {
|
||||
mask uint32
|
||||
value uint32
|
||||
op Op
|
||||
// args describe how to decode the instruction arguments.
|
||||
// args is stored as a fixed-size array.
|
||||
// if there are fewer than len(args) arguments, args[i] == 0 marks
|
||||
// the end of the argument list.
|
||||
args argTypeList
|
||||
}
|
||||
|
||||
var (
|
||||
errShort = errors.New("truncated instruction")
|
||||
errUnknown = errors.New("unknown instruction")
|
||||
)
|
||||
|
||||
var decoderCover []bool
|
||||
|
||||
func init() {
|
||||
decoderCover = make([]bool, len(instFormats))
|
||||
}
|
||||
|
||||
// Decode decodes the 4 bytes in src as a single instruction.
|
||||
func Decode(src []byte) (Inst, error) {
|
||||
length := len(src)
|
||||
if length < 2 {
|
||||
return Inst{}, errShort
|
||||
}
|
||||
|
||||
var x uint32
|
||||
// Non-RVC instructions always starts with 0x11
|
||||
// So check whether src[0] & 3 == 3
|
||||
if src[0]&3 == 3 {
|
||||
if length < 4 {
|
||||
return Inst{}, errShort
|
||||
}
|
||||
length = 4
|
||||
x = binary.LittleEndian.Uint32(src)
|
||||
} else {
|
||||
length = 2
|
||||
x = uint32(binary.LittleEndian.Uint16(src))
|
||||
}
|
||||
|
||||
Search:
|
||||
for i, f := range instFormats {
|
||||
if (x & f.mask) != f.value {
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode args.
|
||||
var args Args
|
||||
for j, aop := range f.args {
|
||||
if aop == 0 {
|
||||
break
|
||||
}
|
||||
arg := decodeArg(aop, x, i)
|
||||
if arg == nil && f.op != C_NOP {
|
||||
// Cannot decode argument.
|
||||
continue Search
|
||||
}
|
||||
args[j] = arg
|
||||
}
|
||||
|
||||
if length == 2 {
|
||||
args = convertCompressedIns(&f, args)
|
||||
}
|
||||
|
||||
decoderCover[i] = true
|
||||
inst := Inst{
|
||||
Op: f.op,
|
||||
Args: args,
|
||||
Enc: x,
|
||||
Len: length,
|
||||
}
|
||||
return inst, nil
|
||||
}
|
||||
return Inst{}, errUnknown
|
||||
}
|
||||
|
||||
// decodeArg decodes the arg described by aop from the instruction bits x.
|
||||
// It returns nil if x cannot be decoded according to aop.
|
||||
func decodeArg(aop argType, x uint32, index int) Arg {
|
||||
switch aop {
|
||||
case arg_rd:
|
||||
return X0 + Reg((x>>7)&((1<<5)-1))
|
||||
|
||||
case arg_rs1:
|
||||
return X0 + Reg((x>>15)&((1<<5)-1))
|
||||
|
||||
case arg_rs2:
|
||||
return X0 + Reg((x>>20)&((1<<5)-1))
|
||||
|
||||
case arg_rs3:
|
||||
return X0 + Reg((x>>27)&((1<<5)-1))
|
||||
|
||||
case arg_fd:
|
||||
return F0 + Reg((x>>7)&((1<<5)-1))
|
||||
|
||||
case arg_fs1:
|
||||
return F0 + Reg((x>>15)&((1<<5)-1))
|
||||
|
||||
case arg_fs2:
|
||||
return F0 + Reg((x>>20)&((1<<5)-1))
|
||||
|
||||
case arg_fs3:
|
||||
return F0 + Reg((x>>27)&((1<<5)-1))
|
||||
|
||||
case arg_rs1_amo:
|
||||
return AmoReg{X0 + Reg((x>>15)&((1<<5)-1))}
|
||||
|
||||
case arg_rs1_mem:
|
||||
imm := x >> 20
|
||||
// Sign-extend
|
||||
if imm>>uint32(12-1) == 1 {
|
||||
imm |= 0xfffff << 12
|
||||
}
|
||||
return RegOffset{X0 + Reg((x>>15)&((1<<5)-1)), Simm{int32(imm), true, 12}}
|
||||
|
||||
case arg_rs1_store:
|
||||
imm := (x<<20)>>27 | (x>>25)<<5
|
||||
// Sign-extend
|
||||
if imm>>uint32(12-1) == 1 {
|
||||
imm |= 0xfffff << 12
|
||||
}
|
||||
return RegOffset{X0 + Reg((x>>15)&((1<<5)-1)), Simm{int32(imm), true, 12}}
|
||||
|
||||
case arg_pred:
|
||||
imm := x << 4 >> 28
|
||||
return MemOrder(uint8(imm))
|
||||
|
||||
case arg_succ:
|
||||
imm := x << 8 >> 28
|
||||
return MemOrder(uint8(imm))
|
||||
|
||||
case arg_csr:
|
||||
imm := x >> 20
|
||||
return CSR(imm)
|
||||
|
||||
case arg_zimm:
|
||||
imm := x << 12 >> 27
|
||||
return Uimm{imm, true}
|
||||
|
||||
case arg_shamt5:
|
||||
imm := x << 7 >> 27
|
||||
return Uimm{imm, false}
|
||||
|
||||
case arg_shamt6:
|
||||
imm := x << 6 >> 26
|
||||
return Uimm{imm, false}
|
||||
|
||||
case arg_imm12:
|
||||
imm := x >> 20
|
||||
// Sign-extend
|
||||
if imm>>uint32(12-1) == 1 {
|
||||
imm |= 0xfffff << 12
|
||||
}
|
||||
return Simm{int32(imm), true, 12}
|
||||
|
||||
case arg_imm20:
|
||||
imm := x >> 12
|
||||
return Uimm{imm, false}
|
||||
|
||||
case arg_jimm20:
|
||||
imm := (x>>31)<<20 | (x<<1)>>22<<1 | (x<<11)>>31<<11 | (x<<12)>>24<<12
|
||||
// Sign-extend
|
||||
if imm>>uint32(21-1) == 1 {
|
||||
imm |= 0x7ff << 21
|
||||
}
|
||||
return Simm{int32(imm), true, 21}
|
||||
|
||||
case arg_simm12:
|
||||
imm := (x<<20)>>27 | (x>>25)<<5
|
||||
// Sign-extend
|
||||
if imm>>uint32(12-1) == 1 {
|
||||
imm |= 0xfffff << 12
|
||||
}
|
||||
return Simm{int32(imm), true, 12}
|
||||
|
||||
case arg_bimm12:
|
||||
imm := (x<<20)>>28<<1 | (x<<1)>>26<<5 | (x<<24)>>31<<11 | (x>>31)<<12
|
||||
// Sign-extend
|
||||
if imm>>uint32(13-1) == 1 {
|
||||
imm |= 0x7ffff << 13
|
||||
}
|
||||
return Simm{int32(imm), true, 13}
|
||||
|
||||
case arg_rd_p, arg_rs2_p:
|
||||
return X8 + Reg((x>>2)&((1<<3)-1))
|
||||
|
||||
case arg_fd_p, arg_fs2_p:
|
||||
return F8 + Reg((x>>2)&((1<<3)-1))
|
||||
|
||||
case arg_rs1_p, arg_rd_rs1_p:
|
||||
return X8 + Reg((x>>7)&((1<<3)-1))
|
||||
|
||||
case arg_rd_n0, arg_rs1_n0, arg_rd_rs1_n0, arg_c_rs1_n0:
|
||||
if X0+Reg((x>>7)&((1<<5)-1)) == X0 {
|
||||
return nil
|
||||
}
|
||||
return X0 + Reg((x>>7)&((1<<5)-1))
|
||||
|
||||
case arg_c_rs2_n0:
|
||||
if X0+Reg((x>>2)&((1<<5)-1)) == X0 {
|
||||
return nil
|
||||
}
|
||||
return X0 + Reg((x>>2)&((1<<5)-1))
|
||||
|
||||
case arg_c_fs2:
|
||||
return F0 + Reg((x>>2)&((1<<5)-1))
|
||||
|
||||
case arg_c_rs2:
|
||||
return X0 + Reg((x>>2)&((1<<5)-1))
|
||||
|
||||
case arg_rd_n2:
|
||||
if X0+Reg((x>>7)&((1<<5)-1)) == X0 || X0+Reg((x>>7)&((1<<5)-1)) == X2 {
|
||||
return nil
|
||||
}
|
||||
return X0 + Reg((x>>7)&((1<<5)-1))
|
||||
|
||||
case arg_c_imm6:
|
||||
imm := (x<<25)>>27 | (x<<19)>>31<<5
|
||||
// Sign-extend
|
||||
if imm>>uint32(6-1) == 1 {
|
||||
imm |= 0x3ffffff << 6
|
||||
}
|
||||
return Simm{int32(imm), true, 6}
|
||||
|
||||
case arg_c_nzimm6:
|
||||
imm := (x<<25)>>27 | (x<<19)>>31<<5
|
||||
// Sign-extend
|
||||
if imm>>uint32(6-1) == 1 {
|
||||
imm |= 0x3ffffff << 6
|
||||
}
|
||||
if int32(imm) == 0 {
|
||||
return nil
|
||||
}
|
||||
return Simm{int32(imm), true, 6}
|
||||
|
||||
case arg_c_nzuimm6:
|
||||
imm := (x<<25)>>27 | (x<<19)>>31<<5
|
||||
if int32(imm) == 0 {
|
||||
return nil
|
||||
}
|
||||
return Uimm{imm, false}
|
||||
|
||||
case arg_c_uimm7:
|
||||
imm := (x<<26)>>31<<6 | (x<<25)>>31<<2 | (x<<19)>>29<<3
|
||||
return Uimm{imm, false}
|
||||
|
||||
case arg_c_uimm8:
|
||||
imm := (x<<25)>>30<<6 | (x<<19)>>29<<3
|
||||
return Uimm{imm, false}
|
||||
|
||||
case arg_c_uimm8sp_s:
|
||||
imm := (x<<23)>>30<<6 | (x<<19)>>28<<2
|
||||
return Uimm{imm, false}
|
||||
|
||||
case arg_c_uimm8sp:
|
||||
imm := (x<<25)>>29<<2 | (x<<19)>>31<<5 | (x<<28)>>30<<6
|
||||
return Uimm{imm, false}
|
||||
|
||||
case arg_c_uimm9sp_s:
|
||||
imm := (x<<22)>>29<<6 | (x<<19)>>29<<3
|
||||
return Uimm{imm, false}
|
||||
|
||||
case arg_c_uimm9sp:
|
||||
imm := (x<<25)>>30<<3 | (x<<19)>>31<<5 | (x<<27)>>29<<6
|
||||
return Uimm{imm, false}
|
||||
|
||||
case arg_c_bimm9:
|
||||
imm := (x<<29)>>31<<5 | (x<<27)>>30<<1 | (x<<25)>>30<<6 | (x<<19)>>31<<8 | (x<<20)>>30<<3
|
||||
// Sign-extend
|
||||
if imm>>uint32(9-1) == 1 {
|
||||
imm |= 0x7fffff << 9
|
||||
}
|
||||
return Simm{int32(imm), true, 9}
|
||||
|
||||
case arg_c_nzimm10:
|
||||
imm := (x<<29)>>31<<5 | (x<<27)>>30<<7 | (x<<26)>>31<<6 | (x<<25)>>31<<4 | (x<<19)>>31<<9
|
||||
// Sign-extend
|
||||
if imm>>uint32(10-1) == 1 {
|
||||
imm |= 0x3fffff << 10
|
||||
}
|
||||
if int32(imm) == 0 {
|
||||
return nil
|
||||
}
|
||||
return Simm{int32(imm), true, 10}
|
||||
|
||||
case arg_c_nzuimm10:
|
||||
imm := (x<<26)>>31<<3 | (x<<25)>>31<<2 | (x<<21)>>28<<6 | (x<<19)>>30<<4
|
||||
if int32(imm) == 0 {
|
||||
return nil
|
||||
}
|
||||
return Uimm{imm, false}
|
||||
|
||||
case arg_c_imm12:
|
||||
imm := (x<<29)>>31<<5 | (x<<26)>>28<<1 | (x<<25)>>31<<7 | (x<<24)>>31<<6 | (x<<23)>>31<<10 | (x<<21)>>30<<8 | (x<<20)>>31<<4 | (x<<19)>>31<<11
|
||||
// Sign-extend
|
||||
if imm>>uint32(12-1) == 1 {
|
||||
imm |= 0xfffff << 12
|
||||
}
|
||||
return Simm{int32(imm), true, 12}
|
||||
|
||||
case arg_c_nzimm18:
|
||||
imm := (x<<25)>>27<<12 | (x<<19)>>31<<17
|
||||
// Sign-extend
|
||||
if imm>>uint32(18-1) == 1 {
|
||||
imm |= 0x3fff << 18
|
||||
}
|
||||
if int32(imm) == 0 {
|
||||
return nil
|
||||
}
|
||||
return Simm{int32(imm), true, 18}
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// convertCompressedIns rewrites the RVC Instruction to regular Instructions
|
||||
func convertCompressedIns(f *instFormat, args Args) Args {
|
||||
var newargs Args
|
||||
switch f.op {
|
||||
case C_ADDI4SPN:
|
||||
f.op = ADDI
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = Reg(X2)
|
||||
newargs[2] = Simm{int32(args[1].(Uimm).Imm), true, 12}
|
||||
|
||||
case C_LW:
|
||||
f.op = LW
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = RegOffset{args[1].(Reg), Simm{int32(args[2].(Uimm).Imm), true, 12}}
|
||||
|
||||
case C_SW:
|
||||
f.op = SW
|
||||
newargs[0] = args[1]
|
||||
newargs[1] = RegOffset{args[0].(Reg), Simm{int32(args[2].(Uimm).Imm), true, 12}}
|
||||
|
||||
case C_NOP:
|
||||
f.op = ADDI
|
||||
newargs[0] = X0
|
||||
newargs[1] = X0
|
||||
newargs[2] = Simm{0, true, 12}
|
||||
|
||||
case C_ADDI:
|
||||
f.op = ADDI
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = args[0]
|
||||
newargs[2] = Simm{args[1].(Simm).Imm, true, 12}
|
||||
|
||||
case C_LI:
|
||||
f.op = ADDI
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = Reg(X0)
|
||||
newargs[2] = Simm{args[1].(Simm).Imm, true, 12}
|
||||
|
||||
case C_ADDI16SP:
|
||||
f.op = ADDI
|
||||
newargs[0] = Reg(X2)
|
||||
newargs[1] = Reg(X2)
|
||||
newargs[2] = Simm{args[0].(Simm).Imm, true, 12}
|
||||
|
||||
case C_LUI:
|
||||
f.op = LUI
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = Uimm{uint32(args[1].(Simm).Imm >> 12), false}
|
||||
|
||||
case C_ANDI:
|
||||
f.op = ANDI
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = args[0]
|
||||
newargs[2] = Simm{args[1].(Simm).Imm, true, 12}
|
||||
|
||||
case C_SUB:
|
||||
f.op = SUB
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = args[0]
|
||||
newargs[2] = args[1]
|
||||
|
||||
case C_XOR:
|
||||
f.op = XOR
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = args[0]
|
||||
newargs[2] = args[1]
|
||||
|
||||
case C_OR:
|
||||
f.op = OR
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = args[0]
|
||||
newargs[2] = args[1]
|
||||
|
||||
case C_AND:
|
||||
f.op = AND
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = args[0]
|
||||
newargs[2] = args[1]
|
||||
|
||||
case C_J:
|
||||
f.op = JAL
|
||||
newargs[0] = Reg(X0)
|
||||
newargs[1] = Simm{args[0].(Simm).Imm, true, 21}
|
||||
|
||||
case C_BEQZ:
|
||||
f.op = BEQ
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = Reg(X0)
|
||||
newargs[2] = Simm{args[1].(Simm).Imm, true, 13}
|
||||
|
||||
case C_BNEZ:
|
||||
f.op = BNE
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = Reg(X0)
|
||||
newargs[2] = Simm{args[1].(Simm).Imm, true, 13}
|
||||
|
||||
case C_LWSP:
|
||||
f.op = LW
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = RegOffset{Reg(X2), Simm{int32(args[1].(Uimm).Imm), true, 12}}
|
||||
|
||||
case C_JR:
|
||||
f.op = JALR
|
||||
newargs[0] = Reg(X0)
|
||||
newargs[1] = RegOffset{args[0].(Reg), Simm{0, true, 12}}
|
||||
|
||||
case C_MV:
|
||||
f.op = ADD
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = Reg(X0)
|
||||
newargs[2] = args[1]
|
||||
|
||||
case C_EBREAK:
|
||||
f.op = EBREAK
|
||||
|
||||
case C_JALR:
|
||||
f.op = JALR
|
||||
newargs[0] = Reg(X1)
|
||||
newargs[1] = RegOffset{args[0].(Reg), Simm{0, true, 12}}
|
||||
|
||||
case C_ADD:
|
||||
f.op = ADD
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = args[0]
|
||||
newargs[2] = args[1]
|
||||
|
||||
case C_SWSP:
|
||||
f.op = SW
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = RegOffset{Reg(X2), Simm{int32(args[1].(Uimm).Imm), true, 12}}
|
||||
|
||||
// riscv64 compressed instructions
|
||||
case C_LD:
|
||||
f.op = LD
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = RegOffset{args[1].(Reg), Simm{int32(args[2].(Uimm).Imm), true, 12}}
|
||||
|
||||
case C_SD:
|
||||
f.op = SD
|
||||
newargs[0] = args[1]
|
||||
newargs[1] = RegOffset{args[0].(Reg), Simm{int32(args[2].(Uimm).Imm), true, 12}}
|
||||
|
||||
case C_ADDIW:
|
||||
f.op = ADDIW
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = args[0]
|
||||
newargs[2] = Simm{args[1].(Simm).Imm, true, 12}
|
||||
|
||||
case C_SRLI:
|
||||
f.op = SRLI
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = args[0]
|
||||
newargs[2] = args[1]
|
||||
|
||||
case C_SRAI:
|
||||
f.op = SRAI
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = args[0]
|
||||
newargs[2] = args[1]
|
||||
|
||||
case C_SUBW:
|
||||
f.op = SUBW
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = args[0]
|
||||
newargs[2] = args[1]
|
||||
|
||||
case C_ADDW:
|
||||
f.op = ADDW
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = args[0]
|
||||
newargs[2] = args[1]
|
||||
|
||||
case C_SLLI:
|
||||
f.op = SLLI
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = args[0]
|
||||
newargs[2] = args[1]
|
||||
|
||||
case C_LDSP:
|
||||
f.op = LD
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = RegOffset{Reg(X2), Simm{int32(args[1].(Uimm).Imm), true, 12}}
|
||||
|
||||
case C_SDSP:
|
||||
f.op = SD
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = RegOffset{Reg(X2), Simm{int32(args[1].(Uimm).Imm), true, 12}}
|
||||
|
||||
// riscv double precision floating point compressed instructions
|
||||
case C_FLD:
|
||||
f.op = FLD
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = RegOffset{args[1].(Reg), Simm{int32(args[2].(Uimm).Imm), true, 12}}
|
||||
|
||||
case C_FSD:
|
||||
f.op = FSD
|
||||
newargs[0] = args[1]
|
||||
newargs[1] = RegOffset{args[0].(Reg), Simm{int32(args[2].(Uimm).Imm), true, 12}}
|
||||
|
||||
case C_FLDSP:
|
||||
f.op = FLD
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = RegOffset{Reg(X2), Simm{int32(args[1].(Uimm).Imm), true, 12}}
|
||||
|
||||
case C_FSDSP:
|
||||
f.op = FSD
|
||||
newargs[0] = args[0]
|
||||
newargs[1] = RegOffset{Reg(X2), Simm{int32(args[1].(Uimm).Imm), true, 12}}
|
||||
|
||||
case C_UNIMP:
|
||||
f.op = CSRRW
|
||||
newargs[0] = Reg(X0)
|
||||
newargs[1] = CSR(CYCLE)
|
||||
newargs[2] = Reg(X0)
|
||||
}
|
||||
return newargs
|
||||
}
|
328
vendor/golang.org/x/arch/riscv64/riscv64asm/gnu.go
generated
vendored
Normal file
328
vendor/golang.org/x/arch/riscv64/riscv64asm/gnu.go
generated
vendored
Normal file
@ -0,0 +1,328 @@
|
||||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package riscv64asm
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
|
||||
// This form typically matches the syntax defined in the RISC-V Instruction Set Manual. See
|
||||
// https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMAFDQC/riscv-spec-20191213.pdf
|
||||
func GNUSyntax(inst Inst) string {
|
||||
op := strings.ToLower(inst.Op.String())
|
||||
var args []string
|
||||
for _, a := range inst.Args {
|
||||
if a == nil {
|
||||
break
|
||||
}
|
||||
args = append(args, strings.ToLower(a.String()))
|
||||
}
|
||||
|
||||
switch inst.Op {
|
||||
case ADDI, ADDIW, ANDI, ORI, SLLI, SLLIW, SRAI, SRAIW, SRLI, SRLIW, XORI:
|
||||
if inst.Op == ADDI {
|
||||
if inst.Args[1].(Reg) == X0 && inst.Args[0].(Reg) != X0 {
|
||||
op = "li"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
break
|
||||
}
|
||||
|
||||
if inst.Args[2].(Simm).Imm == 0 {
|
||||
if inst.Args[0].(Reg) == X0 && inst.Args[1].(Reg) == X0 {
|
||||
op = "nop"
|
||||
args = nil
|
||||
} else {
|
||||
op = "mv"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if inst.Op == ADDIW && inst.Args[2].(Simm).Imm == 0 {
|
||||
op = "sext.w"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
if inst.Op == XORI && inst.Args[2].(Simm).String() == "-1" {
|
||||
op = "not"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case ADD:
|
||||
if inst.Args[1].(Reg) == X0 {
|
||||
op = "mv"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case BEQ:
|
||||
if inst.Args[1].(Reg) == X0 {
|
||||
op = "beqz"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case BGE:
|
||||
if inst.Args[1].(Reg) == X0 {
|
||||
op = "bgez"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
} else if inst.Args[0].(Reg) == X0 {
|
||||
op = "blez"
|
||||
args[0], args[1] = args[1], args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case BLT:
|
||||
if inst.Args[1].(Reg) == X0 {
|
||||
op = "bltz"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
} else if inst.Args[0].(Reg) == X0 {
|
||||
op = "bgtz"
|
||||
args[0], args[1] = args[1], args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case BNE:
|
||||
if inst.Args[1].(Reg) == X0 {
|
||||
op = "bnez"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case CSRRC:
|
||||
if inst.Args[0].(Reg) == X0 {
|
||||
op = "csrc"
|
||||
args[0], args[1] = args[1], args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case CSRRCI:
|
||||
if inst.Args[0].(Reg) == X0 {
|
||||
op = "csrci"
|
||||
args[0], args[1] = args[1], args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case CSRRS:
|
||||
if inst.Args[2].(Reg) == X0 {
|
||||
switch inst.Args[1].(CSR) {
|
||||
case FCSR:
|
||||
op = "frcsr"
|
||||
args = args[:len(args)-2]
|
||||
|
||||
case FFLAGS:
|
||||
op = "frflags"
|
||||
args = args[:len(args)-2]
|
||||
|
||||
case FRM:
|
||||
op = "frrm"
|
||||
args = args[:len(args)-2]
|
||||
|
||||
// rdcycleh, rdinstreth and rdtimeh are RV-32 only instructions.
|
||||
// So not included there.
|
||||
case CYCLE:
|
||||
op = "rdcycle"
|
||||
args = args[:len(args)-2]
|
||||
|
||||
case INSTRET:
|
||||
op = "rdinstret"
|
||||
args = args[:len(args)-2]
|
||||
|
||||
case TIME:
|
||||
op = "rdtime"
|
||||
args = args[:len(args)-2]
|
||||
|
||||
default:
|
||||
op = "csrr"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
} else if inst.Args[0].(Reg) == X0 {
|
||||
op = "csrs"
|
||||
args[0], args[1] = args[1], args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case CSRRSI:
|
||||
if inst.Args[0].(Reg) == X0 {
|
||||
op = "csrsi"
|
||||
args[0], args[1] = args[1], args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case CSRRW:
|
||||
switch inst.Args[1].(CSR) {
|
||||
case FCSR:
|
||||
op = "fscsr"
|
||||
if inst.Args[0].(Reg) == X0 {
|
||||
args[0] = args[2]
|
||||
args = args[:len(args)-2]
|
||||
} else {
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case FFLAGS:
|
||||
op = "fsflags"
|
||||
if inst.Args[0].(Reg) == X0 {
|
||||
args[0] = args[2]
|
||||
args = args[:len(args)-2]
|
||||
} else {
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case FRM:
|
||||
op = "fsrm"
|
||||
if inst.Args[0].(Reg) == X0 {
|
||||
args[0] = args[2]
|
||||
args = args[:len(args)-2]
|
||||
} else {
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case CYCLE:
|
||||
if inst.Args[0].(Reg) == X0 && inst.Args[2].(Reg) == X0 {
|
||||
op = "unimp"
|
||||
args = nil
|
||||
}
|
||||
|
||||
default:
|
||||
if inst.Args[0].(Reg) == X0 {
|
||||
op = "csrw"
|
||||
args[0], args[1] = args[1], args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
}
|
||||
|
||||
case CSRRWI:
|
||||
if inst.Args[0].(Reg) == X0 {
|
||||
op = "csrwi"
|
||||
args[0], args[1] = args[1], args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
// When both pred and succ equals to iorw, the GNU objdump will omit them.
|
||||
case FENCE:
|
||||
if inst.Args[0].(MemOrder).String() == "iorw" &&
|
||||
inst.Args[1].(MemOrder).String() == "iorw" {
|
||||
args = nil
|
||||
}
|
||||
|
||||
case FSGNJX_D:
|
||||
if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
|
||||
op = "fabs.d"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case FSGNJX_S:
|
||||
if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
|
||||
op = "fabs.s"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case FSGNJ_D:
|
||||
if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
|
||||
op = "fmv.d"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case FSGNJ_S:
|
||||
if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
|
||||
op = "fmv.s"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case FSGNJN_D:
|
||||
if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
|
||||
op = "fneg.d"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case FSGNJN_S:
|
||||
if inst.Args[1].(Reg) == inst.Args[2].(Reg) {
|
||||
op = "fneg.s"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case JAL:
|
||||
if inst.Args[0].(Reg) == X0 {
|
||||
op = "j"
|
||||
args[0] = args[1]
|
||||
args = args[:len(args)-1]
|
||||
} else if inst.Args[0].(Reg) == X1 {
|
||||
op = "jal"
|
||||
args[0] = args[1]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case JALR:
|
||||
if inst.Args[0].(Reg) == X1 && inst.Args[1].(RegOffset).Ofs.Imm == 0 {
|
||||
args[0] = inst.Args[1].(RegOffset).OfsReg.String()
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
if inst.Args[0].(Reg) == X0 {
|
||||
if inst.Args[1].(RegOffset).OfsReg == X1 && inst.Args[1].(RegOffset).Ofs.Imm == 0 {
|
||||
op = "ret"
|
||||
args = nil
|
||||
} else if inst.Args[1].(RegOffset).Ofs.Imm == 0 {
|
||||
op = "jr"
|
||||
args[0] = inst.Args[1].(RegOffset).OfsReg.String()
|
||||
args = args[:len(args)-1]
|
||||
} else {
|
||||
op = "jr"
|
||||
args[0] = inst.Args[1].(RegOffset).String()
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
}
|
||||
|
||||
case SLTIU:
|
||||
if inst.Args[2].(Simm).String() == "1" {
|
||||
op = "seqz"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case SLT:
|
||||
if inst.Args[1].(Reg) == X0 {
|
||||
op = "sgtz"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
} else if inst.Args[2].(Reg) == X0 {
|
||||
op = "sltz"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case SLTU:
|
||||
if inst.Args[1].(Reg) == X0 {
|
||||
op = "snez"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case SUB:
|
||||
if inst.Args[1].(Reg) == X0 {
|
||||
op = "neg"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case SUBW:
|
||||
if inst.Args[1].(Reg) == X0 {
|
||||
op = "negw"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
}
|
||||
|
||||
if args != nil {
|
||||
op += " " + strings.Join(args, ",")
|
||||
}
|
||||
return op
|
||||
}
|
495
vendor/golang.org/x/arch/riscv64/riscv64asm/inst.go
generated
vendored
Normal file
495
vendor/golang.org/x/arch/riscv64/riscv64asm/inst.go
generated
vendored
Normal file
@ -0,0 +1,495 @@
|
||||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package riscv64asm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// An Op is a RISC-V opcode.
|
||||
type Op uint16
|
||||
|
||||
// NOTE: The actual Op values are defined in tables.go.
|
||||
func (op Op) String() string {
|
||||
if op >= Op(len(opstr)) || opstr[op] == "" {
|
||||
return fmt.Sprintf("Op(%d)", op)
|
||||
}
|
||||
|
||||
return opstr[op]
|
||||
}
|
||||
|
||||
// An Arg is a single instruction argument.
|
||||
type Arg interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
// An Args holds the instruction arguments.
|
||||
// If an instruction has fewer than 6 arguments,
|
||||
// the final elements in the array are nil.
|
||||
type Args [6]Arg
|
||||
|
||||
// An Inst is a single instruction.
|
||||
type Inst struct {
|
||||
Op Op // Opcode mnemonic.
|
||||
Enc uint32 // Raw encoding bits.
|
||||
Args Args // Instruction arguments, in RISC-V mamual order.
|
||||
Len int // Length of encoded instruction in bytes
|
||||
}
|
||||
|
||||
func (i Inst) String() string {
|
||||
var args []string
|
||||
for _, arg := range i.Args {
|
||||
if arg == nil {
|
||||
break
|
||||
}
|
||||
args = append(args, arg.String())
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
return i.Op.String()
|
||||
}
|
||||
return i.Op.String() + " " + strings.Join(args, ",")
|
||||
}
|
||||
|
||||
// A Reg is a single register.
|
||||
// The zero value denotes X0, not the absence of a register.
|
||||
type Reg uint16
|
||||
|
||||
const (
|
||||
// General-purpose register
|
||||
X0 Reg = iota
|
||||
X1
|
||||
X2
|
||||
X3
|
||||
X4
|
||||
X5
|
||||
X6
|
||||
X7
|
||||
X8
|
||||
X9
|
||||
X10
|
||||
X11
|
||||
X12
|
||||
X13
|
||||
X14
|
||||
X15
|
||||
X16
|
||||
X17
|
||||
X18
|
||||
X19
|
||||
X20
|
||||
X21
|
||||
X22
|
||||
X23
|
||||
X24
|
||||
X25
|
||||
X26
|
||||
X27
|
||||
X28
|
||||
X29
|
||||
X30
|
||||
X31
|
||||
|
||||
//Float point register
|
||||
F0
|
||||
F1
|
||||
F2
|
||||
F3
|
||||
F4
|
||||
F5
|
||||
F6
|
||||
F7
|
||||
F8
|
||||
F9
|
||||
F10
|
||||
F11
|
||||
F12
|
||||
F13
|
||||
F14
|
||||
F15
|
||||
F16
|
||||
F17
|
||||
F18
|
||||
F19
|
||||
F20
|
||||
F21
|
||||
F22
|
||||
F23
|
||||
F24
|
||||
F25
|
||||
F26
|
||||
F27
|
||||
F28
|
||||
F29
|
||||
F30
|
||||
F31
|
||||
)
|
||||
|
||||
func (r Reg) String() string {
|
||||
switch {
|
||||
case r >= X0 && r <= X31:
|
||||
return fmt.Sprintf("x%d", r)
|
||||
|
||||
case r >= F0 && r <= F31:
|
||||
return fmt.Sprintf("f%d", r-F0)
|
||||
|
||||
default:
|
||||
return fmt.Sprintf("Unknown(%d)", r)
|
||||
}
|
||||
}
|
||||
|
||||
// A CSR is a single control and status register.
|
||||
// Use stringer to generate CSR match table.
|
||||
//
|
||||
//go:generate stringer -type=CSR
|
||||
type CSR uint16
|
||||
|
||||
const (
|
||||
// Control status register
|
||||
USTATUS CSR = 0x0000
|
||||
FFLAGS CSR = 0x0001
|
||||
FRM CSR = 0x0002
|
||||
FCSR CSR = 0x0003
|
||||
UIE CSR = 0x0004
|
||||
UTVEC CSR = 0x0005
|
||||
UTVT CSR = 0x0007
|
||||
VSTART CSR = 0x0008
|
||||
VXSAT CSR = 0x0009
|
||||
VXRM CSR = 0x000a
|
||||
VCSR CSR = 0x000f
|
||||
USCRATCH CSR = 0x0040
|
||||
UEPC CSR = 0x0041
|
||||
UCAUSE CSR = 0x0042
|
||||
UTVAL CSR = 0x0043
|
||||
UIP CSR = 0x0044
|
||||
UNXTI CSR = 0x0045
|
||||
UINTSTATUS CSR = 0x0046
|
||||
USCRATCHCSW CSR = 0x0048
|
||||
USCRATCHCSWL CSR = 0x0049
|
||||
SSTATUS CSR = 0x0100
|
||||
SEDELEG CSR = 0x0102
|
||||
SIDELEG CSR = 0x0103
|
||||
SIE CSR = 0x0104
|
||||
STVEC CSR = 0x0105
|
||||
SCOUNTEREN CSR = 0x0106
|
||||
STVT CSR = 0x0107
|
||||
SSCRATCH CSR = 0x0140
|
||||
SEPC CSR = 0x0141
|
||||
SCAUSE CSR = 0x0142
|
||||
STVAL CSR = 0x0143
|
||||
SIP CSR = 0x0144
|
||||
SNXTI CSR = 0x0145
|
||||
SINTSTATUS CSR = 0x0146
|
||||
SSCRATCHCSW CSR = 0x0148
|
||||
SSCRATCHCSWL CSR = 0x0149
|
||||
SATP CSR = 0x0180
|
||||
VSSTATUS CSR = 0x0200
|
||||
VSIE CSR = 0x0204
|
||||
VSTVEC CSR = 0x0205
|
||||
VSSCRATCH CSR = 0x0240
|
||||
VSEPC CSR = 0x0241
|
||||
VSCAUSE CSR = 0x0242
|
||||
VSTVAL CSR = 0x0243
|
||||
VSIP CSR = 0x0244
|
||||
VSATP CSR = 0x0280
|
||||
MSTATUS CSR = 0x0300
|
||||
MISA CSR = 0x0301
|
||||
MEDELEG CSR = 0x0302
|
||||
MIDELEG CSR = 0x0303
|
||||
MIE CSR = 0x0304
|
||||
MTVEC CSR = 0x0305
|
||||
MCOUNTEREN CSR = 0x0306
|
||||
MTVT CSR = 0x0307
|
||||
MSTATUSH CSR = 0x0310
|
||||
MCOUNTINHIBIT CSR = 0x0320
|
||||
MHPMEVENT3 CSR = 0x0323
|
||||
MHPMEVENT4 CSR = 0x0324
|
||||
MHPMEVENT5 CSR = 0x0325
|
||||
MHPMEVENT6 CSR = 0x0326
|
||||
MHPMEVENT7 CSR = 0x0327
|
||||
MHPMEVENT8 CSR = 0x0328
|
||||
MHPMEVENT9 CSR = 0x0329
|
||||
MHPMEVENT10 CSR = 0x032a
|
||||
MHPMEVENT11 CSR = 0x032b
|
||||
MHPMEVENT12 CSR = 0x032c
|
||||
MHPMEVENT13 CSR = 0x032d
|
||||
MHPMEVENT14 CSR = 0x032e
|
||||
MHPMEVENT15 CSR = 0x032f
|
||||
MHPMEVENT16 CSR = 0x0330
|
||||
MHPMEVENT17 CSR = 0x0331
|
||||
MHPMEVENT18 CSR = 0x0332
|
||||
MHPMEVENT19 CSR = 0x0333
|
||||
MHPMEVENT20 CSR = 0x0334
|
||||
MHPMEVENT21 CSR = 0x0335
|
||||
MHPMEVENT22 CSR = 0x0336
|
||||
MHPMEVENT23 CSR = 0x0337
|
||||
MHPMEVENT24 CSR = 0x0338
|
||||
MHPMEVENT25 CSR = 0x0339
|
||||
MHPMEVENT26 CSR = 0x033a
|
||||
MHPMEVENT27 CSR = 0x033b
|
||||
MHPMEVENT28 CSR = 0x033c
|
||||
MHPMEVENT29 CSR = 0x033d
|
||||
MHPMEVENT30 CSR = 0x033e
|
||||
MHPMEVENT31 CSR = 0x033f
|
||||
MSCRATCH CSR = 0x0340
|
||||
MEPC CSR = 0x0341
|
||||
MCAUSE CSR = 0x0342
|
||||
MTVAL CSR = 0x0343
|
||||
MIP CSR = 0x0344
|
||||
MNXTI CSR = 0x0345
|
||||
MINTSTATUS CSR = 0x0346
|
||||
MSCRATCHCSW CSR = 0x0348
|
||||
MSCRATCHCSWL CSR = 0x0349
|
||||
MTINST CSR = 0x034a
|
||||
MTVAL2 CSR = 0x034b
|
||||
PMPCFG0 CSR = 0x03a0
|
||||
PMPCFG1 CSR = 0x03a1
|
||||
PMPCFG2 CSR = 0x03a2
|
||||
PMPCFG3 CSR = 0x03a3
|
||||
PMPADDR0 CSR = 0x03b0
|
||||
PMPADDR1 CSR = 0x03b1
|
||||
PMPADDR2 CSR = 0x03b2
|
||||
PMPADDR3 CSR = 0x03b3
|
||||
PMPADDR4 CSR = 0x03b4
|
||||
PMPADDR5 CSR = 0x03b5
|
||||
PMPADDR6 CSR = 0x03b6
|
||||
PMPADDR7 CSR = 0x03b7
|
||||
PMPADDR8 CSR = 0x03b8
|
||||
PMPADDR9 CSR = 0x03b9
|
||||
PMPADDR10 CSR = 0x03ba
|
||||
PMPADDR11 CSR = 0x03bb
|
||||
PMPADDR12 CSR = 0x03bc
|
||||
PMPADDR13 CSR = 0x03bd
|
||||
PMPADDR14 CSR = 0x03be
|
||||
PMPADDR15 CSR = 0x03bf
|
||||
HSTATUS CSR = 0x0600
|
||||
HEDELEG CSR = 0x0602
|
||||
HIDELEG CSR = 0x0603
|
||||
HIE CSR = 0x0604
|
||||
HTIMEDELTA CSR = 0x0605
|
||||
HCOUNTEREN CSR = 0x0606
|
||||
HGEIE CSR = 0x0607
|
||||
HTIMEDELTAH CSR = 0x0615
|
||||
HTVAL CSR = 0x0643
|
||||
HIP CSR = 0x0644
|
||||
HVIP CSR = 0x0645
|
||||
HTINST CSR = 0x064a
|
||||
HGATP CSR = 0x0680
|
||||
TSELECT CSR = 0x07a0
|
||||
TDATA1 CSR = 0x07a1
|
||||
TDATA2 CSR = 0x07a2
|
||||
TDATA3 CSR = 0x07a3
|
||||
TINFO CSR = 0x07a4
|
||||
TCONTROL CSR = 0x07a5
|
||||
MCONTEXT CSR = 0x07a8
|
||||
MNOISE CSR = 0x07a9
|
||||
SCONTEXT CSR = 0x07aa
|
||||
DCSR CSR = 0x07b0
|
||||
DPC CSR = 0x07b1
|
||||
DSCRATCH0 CSR = 0x07b2
|
||||
DSCRATCH1 CSR = 0x07b3
|
||||
MCYCLE CSR = 0x0b00
|
||||
MINSTRET CSR = 0x0b02
|
||||
MHPMCOUNTER3 CSR = 0x0b03
|
||||
MHPMCOUNTER4 CSR = 0x0b04
|
||||
MHPMCOUNTER5 CSR = 0x0b05
|
||||
MHPMCOUNTER6 CSR = 0x0b06
|
||||
MHPMCOUNTER7 CSR = 0x0b07
|
||||
MHPMCOUNTER8 CSR = 0x0b08
|
||||
MHPMCOUNTER9 CSR = 0x0b09
|
||||
MHPMCOUNTER10 CSR = 0x0b0a
|
||||
MHPMCOUNTER11 CSR = 0x0b0b
|
||||
MHPMCOUNTER12 CSR = 0x0b0c
|
||||
MHPMCOUNTER13 CSR = 0x0b0d
|
||||
MHPMCOUNTER14 CSR = 0x0b0e
|
||||
MHPMCOUNTER15 CSR = 0x0b0f
|
||||
MHPMCOUNTER16 CSR = 0x0b10
|
||||
MHPMCOUNTER17 CSR = 0x0b11
|
||||
MHPMCOUNTER18 CSR = 0x0b12
|
||||
MHPMCOUNTER19 CSR = 0x0b13
|
||||
MHPMCOUNTER20 CSR = 0x0b14
|
||||
MHPMCOUNTER21 CSR = 0x0b15
|
||||
MHPMCOUNTER22 CSR = 0x0b16
|
||||
MHPMCOUNTER23 CSR = 0x0b17
|
||||
MHPMCOUNTER24 CSR = 0x0b18
|
||||
MHPMCOUNTER25 CSR = 0x0b19
|
||||
MHPMCOUNTER26 CSR = 0x0b1a
|
||||
MHPMCOUNTER27 CSR = 0x0b1b
|
||||
MHPMCOUNTER28 CSR = 0x0b1c
|
||||
MHPMCOUNTER29 CSR = 0x0b1d
|
||||
MHPMCOUNTER30 CSR = 0x0b1e
|
||||
MHPMCOUNTER31 CSR = 0x0b1f
|
||||
MCYCLEH CSR = 0x0b80
|
||||
MINSTRETH CSR = 0x0b82
|
||||
MHPMCOUNTER3H CSR = 0x0b83
|
||||
MHPMCOUNTER4H CSR = 0x0b84
|
||||
MHPMCOUNTER5H CSR = 0x0b85
|
||||
MHPMCOUNTER6H CSR = 0x0b86
|
||||
MHPMCOUNTER7H CSR = 0x0b87
|
||||
MHPMCOUNTER8H CSR = 0x0b88
|
||||
MHPMCOUNTER9H CSR = 0x0b89
|
||||
MHPMCOUNTER10H CSR = 0x0b8a
|
||||
MHPMCOUNTER11H CSR = 0x0b8b
|
||||
MHPMCOUNTER12H CSR = 0x0b8c
|
||||
MHPMCOUNTER13H CSR = 0x0b8d
|
||||
MHPMCOUNTER14H CSR = 0x0b8e
|
||||
MHPMCOUNTER15H CSR = 0x0b8f
|
||||
MHPMCOUNTER16H CSR = 0x0b90
|
||||
MHPMCOUNTER17H CSR = 0x0b91
|
||||
MHPMCOUNTER18H CSR = 0x0b92
|
||||
MHPMCOUNTER19H CSR = 0x0b93
|
||||
MHPMCOUNTER20H CSR = 0x0b94
|
||||
MHPMCOUNTER21H CSR = 0x0b95
|
||||
MHPMCOUNTER22H CSR = 0x0b96
|
||||
MHPMCOUNTER23H CSR = 0x0b97
|
||||
MHPMCOUNTER24H CSR = 0x0b98
|
||||
MHPMCOUNTER25H CSR = 0x0b99
|
||||
MHPMCOUNTER26H CSR = 0x0b9a
|
||||
MHPMCOUNTER27H CSR = 0x0b9b
|
||||
MHPMCOUNTER28H CSR = 0x0b9c
|
||||
MHPMCOUNTER29H CSR = 0x0b9d
|
||||
MHPMCOUNTER30H CSR = 0x0b9e
|
||||
MHPMCOUNTER31H CSR = 0x0b9f
|
||||
CYCLE CSR = 0x0c00
|
||||
TIME CSR = 0x0c01
|
||||
INSTRET CSR = 0x0c02
|
||||
HPMCOUNTER3 CSR = 0x0c03
|
||||
HPMCOUNTER4 CSR = 0x0c04
|
||||
HPMCOUNTER5 CSR = 0x0c05
|
||||
HPMCOUNTER6 CSR = 0x0c06
|
||||
HPMCOUNTER7 CSR = 0x0c07
|
||||
HPMCOUNTER8 CSR = 0x0c08
|
||||
HPMCOUNTER9 CSR = 0x0c09
|
||||
HPMCOUNTER10 CSR = 0x0c0a
|
||||
HPMCOUNTER11 CSR = 0x0c0b
|
||||
HPMCOUNTER12 CSR = 0x0c0c
|
||||
HPMCOUNTER13 CSR = 0x0c0d
|
||||
HPMCOUNTER14 CSR = 0x0c0e
|
||||
HPMCOUNTER15 CSR = 0x0c0f
|
||||
HPMCOUNTER16 CSR = 0x0c10
|
||||
HPMCOUNTER17 CSR = 0x0c11
|
||||
HPMCOUNTER18 CSR = 0x0c12
|
||||
HPMCOUNTER19 CSR = 0x0c13
|
||||
HPMCOUNTER20 CSR = 0x0c14
|
||||
HPMCOUNTER21 CSR = 0x0c15
|
||||
HPMCOUNTER22 CSR = 0x0c16
|
||||
HPMCOUNTER23 CSR = 0x0c17
|
||||
HPMCOUNTER24 CSR = 0x0c18
|
||||
HPMCOUNTER25 CSR = 0x0c19
|
||||
HPMCOUNTER26 CSR = 0x0c1a
|
||||
HPMCOUNTER27 CSR = 0x0c1b
|
||||
HPMCOUNTER28 CSR = 0x0c1c
|
||||
HPMCOUNTER29 CSR = 0x0c1d
|
||||
HPMCOUNTER30 CSR = 0x0c1e
|
||||
HPMCOUNTER31 CSR = 0x0c1f
|
||||
VL CSR = 0x0c20
|
||||
VTYPE CSR = 0x0c21
|
||||
VLENB CSR = 0x0c22
|
||||
CYCLEH CSR = 0x0c80
|
||||
TIMEH CSR = 0x0c81
|
||||
INSTRETH CSR = 0x0c82
|
||||
HPMCOUNTER3H CSR = 0x0c83
|
||||
HPMCOUNTER4H CSR = 0x0c84
|
||||
HPMCOUNTER5H CSR = 0x0c85
|
||||
HPMCOUNTER6H CSR = 0x0c86
|
||||
HPMCOUNTER7H CSR = 0x0c87
|
||||
HPMCOUNTER8H CSR = 0x0c88
|
||||
HPMCOUNTER9H CSR = 0x0c89
|
||||
HPMCOUNTER10H CSR = 0x0c8a
|
||||
HPMCOUNTER11H CSR = 0x0c8b
|
||||
HPMCOUNTER12H CSR = 0x0c8c
|
||||
HPMCOUNTER13H CSR = 0x0c8d
|
||||
HPMCOUNTER14H CSR = 0x0c8e
|
||||
HPMCOUNTER15H CSR = 0x0c8f
|
||||
HPMCOUNTER16H CSR = 0x0c90
|
||||
HPMCOUNTER17H CSR = 0x0c91
|
||||
HPMCOUNTER18H CSR = 0x0c92
|
||||
HPMCOUNTER19H CSR = 0x0c93
|
||||
HPMCOUNTER20H CSR = 0x0c94
|
||||
HPMCOUNTER21H CSR = 0x0c95
|
||||
HPMCOUNTER22H CSR = 0x0c96
|
||||
HPMCOUNTER23H CSR = 0x0c97
|
||||
HPMCOUNTER24H CSR = 0x0c98
|
||||
HPMCOUNTER25H CSR = 0x0c99
|
||||
HPMCOUNTER26H CSR = 0x0c9a
|
||||
HPMCOUNTER27H CSR = 0x0c9b
|
||||
HPMCOUNTER28H CSR = 0x0c9c
|
||||
HPMCOUNTER29H CSR = 0x0c9d
|
||||
HPMCOUNTER30H CSR = 0x0c9e
|
||||
HPMCOUNTER31H CSR = 0x0c9f
|
||||
HGEIP CSR = 0x0e12
|
||||
MVENDORID CSR = 0x0f11
|
||||
MARCHID CSR = 0x0f12
|
||||
MIMPID CSR = 0x0f13
|
||||
MHARTID CSR = 0x0f14
|
||||
MENTROPY CSR = 0x0f15
|
||||
)
|
||||
|
||||
// An Uimm is an unsigned immediate number
|
||||
type Uimm struct {
|
||||
Imm uint32 // 32-bit unsigned integer
|
||||
Decimal bool // Print format of the immediate, either decimal or hexadecimal
|
||||
}
|
||||
|
||||
func (ui Uimm) String() string {
|
||||
if ui.Decimal {
|
||||
return fmt.Sprintf("%d", ui.Imm)
|
||||
}
|
||||
return fmt.Sprintf("%#x", ui.Imm)
|
||||
}
|
||||
|
||||
// A Simm is a signed immediate number
|
||||
type Simm struct {
|
||||
Imm int32 // 32-bit signed integer
|
||||
Decimal bool // Print format of the immediate, either decimal or hexadecimal
|
||||
Width uint8 // Actual width of the Simm
|
||||
}
|
||||
|
||||
func (si Simm) String() string {
|
||||
if si.Decimal {
|
||||
return fmt.Sprintf("%d", si.Imm)
|
||||
}
|
||||
return fmt.Sprintf("%#x", si.Imm)
|
||||
}
|
||||
|
||||
// An AmoReg is an atomic address register used in AMO instructions
|
||||
type AmoReg struct {
|
||||
reg Reg // Avoid promoted String method
|
||||
}
|
||||
|
||||
func (amoReg AmoReg) String() string {
|
||||
return fmt.Sprintf("(%s)", amoReg.reg)
|
||||
}
|
||||
|
||||
// A RegOffset is a register with offset value
|
||||
type RegOffset struct {
|
||||
OfsReg Reg
|
||||
Ofs Simm
|
||||
}
|
||||
|
||||
func (regofs RegOffset) String() string {
|
||||
return fmt.Sprintf("%s(%s)", regofs.Ofs, regofs.OfsReg)
|
||||
}
|
||||
|
||||
// A MemOrder is a memory order hint in fence instruction
|
||||
type MemOrder uint8
|
||||
|
||||
func (memOrder MemOrder) String() string {
|
||||
var str string
|
||||
if memOrder<<7>>7 == 1 {
|
||||
str += "i"
|
||||
}
|
||||
if memOrder>>1<<7>>7 == 1 {
|
||||
str += "o"
|
||||
}
|
||||
if memOrder>>2<<7>>7 == 1 {
|
||||
str += "r"
|
||||
}
|
||||
if memOrder>>3<<7>>7 == 1 {
|
||||
str += "w"
|
||||
}
|
||||
return str
|
||||
}
|
377
vendor/golang.org/x/arch/riscv64/riscv64asm/plan9x.go
generated
vendored
Normal file
377
vendor/golang.org/x/arch/riscv64/riscv64asm/plan9x.go
generated
vendored
Normal file
@ -0,0 +1,377 @@
|
||||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package riscv64asm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GoSyntax returns the Go assembler syntax for the instruction.
|
||||
// The syntax was originally defined by Plan 9.
|
||||
// The pc is the program counter of the instruction, used for
|
||||
// expanding PC-relative addresses into absolute ones.
|
||||
// The symname function queries the symbol table for the program
|
||||
// being disassembled. Given a target address it returns the name
|
||||
// and base address of the symbol containing the target, if any;
|
||||
// otherwise it returns "", 0.
|
||||
// The reader text should read from the text segment using text addresses
|
||||
// as offsets; it is used to display pc-relative loads as constant loads.
|
||||
func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text io.ReaderAt) string {
|
||||
if symname == nil {
|
||||
symname = func(uint64) (string, uint64) { return "", 0 }
|
||||
}
|
||||
|
||||
var args []string
|
||||
for _, a := range inst.Args {
|
||||
if a == nil {
|
||||
break
|
||||
}
|
||||
args = append(args, plan9Arg(&inst, pc, symname, a))
|
||||
}
|
||||
|
||||
op := inst.Op.String()
|
||||
|
||||
switch inst.Op {
|
||||
|
||||
case AMOADD_D, AMOADD_D_AQ, AMOADD_D_RL, AMOADD_D_AQRL, AMOADD_W, AMOADD_W_AQ,
|
||||
AMOADD_W_RL, AMOADD_W_AQRL, AMOAND_D, AMOAND_D_AQ, AMOAND_D_RL, AMOAND_D_AQRL,
|
||||
AMOAND_W, AMOAND_W_AQ, AMOAND_W_RL, AMOAND_W_AQRL, AMOMAXU_D, AMOMAXU_D_AQ,
|
||||
AMOMAXU_D_RL, AMOMAXU_D_AQRL, AMOMAXU_W, AMOMAXU_W_AQ, AMOMAXU_W_RL, AMOMAXU_W_AQRL,
|
||||
AMOMAX_D, AMOMAX_D_AQ, AMOMAX_D_RL, AMOMAX_D_AQRL, AMOMAX_W, AMOMAX_W_AQ, AMOMAX_W_RL,
|
||||
AMOMAX_W_AQRL, AMOMINU_D, AMOMINU_D_AQ, AMOMINU_D_RL, AMOMINU_D_AQRL, AMOMINU_W,
|
||||
AMOMINU_W_AQ, AMOMINU_W_RL, AMOMINU_W_AQRL, AMOMIN_D, AMOMIN_D_AQ, AMOMIN_D_RL,
|
||||
AMOMIN_D_AQRL, AMOMIN_W, AMOMIN_W_AQ, AMOMIN_W_RL, AMOMIN_W_AQRL, AMOOR_D, AMOOR_D_AQ,
|
||||
AMOOR_D_RL, AMOOR_D_AQRL, AMOOR_W, AMOOR_W_AQ, AMOOR_W_RL, AMOOR_W_AQRL, AMOSWAP_D,
|
||||
AMOSWAP_D_AQ, AMOSWAP_D_RL, AMOSWAP_D_AQRL, AMOSWAP_W, AMOSWAP_W_AQ, AMOSWAP_W_RL,
|
||||
AMOSWAP_W_AQRL, AMOXOR_D, AMOXOR_D_AQ, AMOXOR_D_RL, AMOXOR_D_AQRL, AMOXOR_W,
|
||||
AMOXOR_W_AQ, AMOXOR_W_RL, AMOXOR_W_AQRL, SC_D, SC_D_AQ, SC_D_RL, SC_D_AQRL,
|
||||
SC_W, SC_W_AQ, SC_W_RL, SC_W_AQRL:
|
||||
// Atomic instructions have special operand order.
|
||||
args[2], args[1] = args[1], args[2]
|
||||
|
||||
case ADDI:
|
||||
if inst.Args[2].(Simm).Imm == 0 {
|
||||
op = "MOV"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case ADDIW:
|
||||
if inst.Args[2].(Simm).Imm == 0 {
|
||||
op = "MOVW"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case ANDI:
|
||||
if inst.Args[2].(Simm).Imm == 255 {
|
||||
op = "MOVBU"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case BEQ:
|
||||
if inst.Args[1].(Reg) == X0 {
|
||||
op = "BEQZ"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
|
||||
args[i], args[j] = args[j], args[i]
|
||||
}
|
||||
|
||||
case BGE:
|
||||
if inst.Args[1].(Reg) == X0 {
|
||||
op = "BGEZ"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
|
||||
args[i], args[j] = args[j], args[i]
|
||||
}
|
||||
|
||||
case BLT:
|
||||
if inst.Args[1].(Reg) == X0 {
|
||||
op = "BLTZ"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
|
||||
args[i], args[j] = args[j], args[i]
|
||||
}
|
||||
|
||||
case BNE:
|
||||
if inst.Args[1].(Reg) == X0 {
|
||||
op = "BNEZ"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
|
||||
args[i], args[j] = args[j], args[i]
|
||||
}
|
||||
|
||||
case BLTU, BGEU:
|
||||
for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
|
||||
args[i], args[j] = args[j], args[i]
|
||||
}
|
||||
|
||||
case CSRRW:
|
||||
switch inst.Args[1].(CSR) {
|
||||
case FCSR:
|
||||
op = "FSCSR"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
case FFLAGS:
|
||||
op = "FSFLAGS"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
case FRM:
|
||||
op = "FSRM"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
case CYCLE:
|
||||
if inst.Args[0].(Reg) == X0 && inst.Args[2].(Reg) == X0 {
|
||||
op = "UNIMP"
|
||||
args = nil
|
||||
}
|
||||
}
|
||||
|
||||
case CSRRS:
|
||||
if inst.Args[2].(Reg) == X0 {
|
||||
switch inst.Args[1].(CSR) {
|
||||
case FCSR:
|
||||
op = "FRCSR"
|
||||
args = args[:len(args)-2]
|
||||
case FFLAGS:
|
||||
op = "FRFLAGS"
|
||||
args = args[:len(args)-2]
|
||||
case FRM:
|
||||
op = "FRRM"
|
||||
args = args[:len(args)-2]
|
||||
case CYCLE:
|
||||
op = "RDCYCLE"
|
||||
args = args[:len(args)-2]
|
||||
case CYCLEH:
|
||||
op = "RDCYCLEH"
|
||||
args = args[:len(args)-2]
|
||||
case INSTRET:
|
||||
op = "RDINSTRET"
|
||||
args = args[:len(args)-2]
|
||||
case INSTRETH:
|
||||
op = "RDINSTRETH"
|
||||
args = args[:len(args)-2]
|
||||
case TIME:
|
||||
op = "RDTIME"
|
||||
args = args[:len(args)-2]
|
||||
case TIMEH:
|
||||
op = "RDTIMEH"
|
||||
args = args[:len(args)-2]
|
||||
}
|
||||
}
|
||||
|
||||
// Fence instruction in plan9 doesn't have any operands.
|
||||
case FENCE:
|
||||
args = nil
|
||||
|
||||
case FMADD_D, FMADD_H, FMADD_Q, FMADD_S, FMSUB_D, FMSUB_H,
|
||||
FMSUB_Q, FMSUB_S, FNMADD_D, FNMADD_H, FNMADD_Q, FNMADD_S,
|
||||
FNMSUB_D, FNMSUB_H, FNMSUB_Q, FNMSUB_S:
|
||||
args[1], args[3] = args[3], args[1]
|
||||
|
||||
case FSGNJ_S:
|
||||
if inst.Args[2] == inst.Args[1] {
|
||||
op = "MOVF"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case FSGNJ_D:
|
||||
if inst.Args[2] == inst.Args[1] {
|
||||
op = "MOVD"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case FSGNJX_S:
|
||||
if inst.Args[2] == inst.Args[1] {
|
||||
op = "FABSS"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case FSGNJX_D:
|
||||
if inst.Args[2] == inst.Args[1] {
|
||||
op = "FABSD"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case FSGNJN_S:
|
||||
if inst.Args[2] == inst.Args[1] {
|
||||
op = "FNEGS"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case FSGNJN_D:
|
||||
if inst.Args[2] == inst.Args[1] {
|
||||
op = "FNESD"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case LD, SD:
|
||||
op = "MOV"
|
||||
if inst.Op == SD {
|
||||
args[0], args[1] = args[1], args[0]
|
||||
}
|
||||
|
||||
case LB, SB:
|
||||
op = "MOVB"
|
||||
if inst.Op == SB {
|
||||
args[0], args[1] = args[1], args[0]
|
||||
}
|
||||
|
||||
case LH, SH:
|
||||
op = "MOVH"
|
||||
if inst.Op == SH {
|
||||
args[0], args[1] = args[1], args[0]
|
||||
}
|
||||
|
||||
case LW, SW:
|
||||
op = "MOVW"
|
||||
if inst.Op == SW {
|
||||
args[0], args[1] = args[1], args[0]
|
||||
}
|
||||
|
||||
case LBU:
|
||||
op = "MOVBU"
|
||||
|
||||
case LHU:
|
||||
op = "MOVHU"
|
||||
|
||||
case LWU:
|
||||
op = "MOVWU"
|
||||
|
||||
case FLW, FSW:
|
||||
op = "MOVF"
|
||||
if inst.Op == FLW {
|
||||
args[0], args[1] = args[1], args[0]
|
||||
}
|
||||
|
||||
case FLD, FSD:
|
||||
op = "MOVD"
|
||||
if inst.Op == FLD {
|
||||
args[0], args[1] = args[1], args[0]
|
||||
}
|
||||
|
||||
case SUB:
|
||||
if inst.Args[1].(Reg) == X0 {
|
||||
op = "NEG"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case XORI:
|
||||
if inst.Args[2].(Simm).String() == "-1" {
|
||||
op = "NOT"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case SLTIU:
|
||||
if inst.Args[2].(Simm).Imm == 1 {
|
||||
op = "SEQZ"
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case SLTU:
|
||||
if inst.Args[1].(Reg) == X0 {
|
||||
op = "SNEZ"
|
||||
args[1] = args[2]
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
case JAL:
|
||||
if inst.Args[0].(Reg) == X0 {
|
||||
op = "JMP"
|
||||
args[0] = args[1]
|
||||
args = args[:len(args)-1]
|
||||
} else if inst.Args[0].(Reg) == X1 {
|
||||
op = "CALL"
|
||||
args[0] = args[1]
|
||||
args = args[:len(args)-1]
|
||||
} else {
|
||||
args[0], args[1] = args[1], args[0]
|
||||
}
|
||||
|
||||
case JALR:
|
||||
if inst.Args[0].(Reg) == X0 {
|
||||
if inst.Args[1].(RegOffset).OfsReg == X1 && inst.Args[1].(RegOffset).Ofs.Imm == 0 {
|
||||
op = "RET"
|
||||
args = nil
|
||||
break
|
||||
}
|
||||
op = "JMP"
|
||||
args[0] = args[1]
|
||||
args = args[:len(args)-1]
|
||||
} else if inst.Args[0].(Reg) == X1 {
|
||||
op = "CALL"
|
||||
args[0] = args[1]
|
||||
args = args[:len(args)-1]
|
||||
} else {
|
||||
args[0], args[1] = args[1], args[0]
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse args, placing dest last.
|
||||
for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
|
||||
args[i], args[j] = args[j], args[i]
|
||||
}
|
||||
|
||||
// Change to plan9 opcode format
|
||||
// Atomic instructions do not have reorder suffix, so remove them
|
||||
op = strings.Replace(op, ".AQRL", "", -1)
|
||||
op = strings.Replace(op, ".AQ", "", -1)
|
||||
op = strings.Replace(op, ".RL", "", -1)
|
||||
op = strings.Replace(op, ".", "", -1)
|
||||
|
||||
if args != nil {
|
||||
op += " " + strings.Join(args, ", ")
|
||||
}
|
||||
|
||||
return op
|
||||
}
|
||||
|
||||
func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
|
||||
switch a := arg.(type) {
|
||||
case Uimm:
|
||||
return fmt.Sprintf("$%d", uint32(a.Imm))
|
||||
|
||||
case Simm:
|
||||
imm, _ := strconv.Atoi(a.String())
|
||||
if a.Width == 13 || a.Width == 21 {
|
||||
addr := int64(pc) + int64(imm)
|
||||
if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base {
|
||||
return fmt.Sprintf("%s(SB)", s)
|
||||
}
|
||||
return fmt.Sprintf("%d(PC)", imm/4)
|
||||
}
|
||||
return fmt.Sprintf("$%d", int32(imm))
|
||||
|
||||
case Reg:
|
||||
if a <= 31 {
|
||||
return fmt.Sprintf("X%d", a)
|
||||
} else {
|
||||
return fmt.Sprintf("F%d", a-32)
|
||||
}
|
||||
|
||||
case RegOffset:
|
||||
if a.Ofs.Imm == 0 {
|
||||
return fmt.Sprintf("(X%d)", a.OfsReg)
|
||||
} else {
|
||||
return fmt.Sprintf("%s(X%d)", a.Ofs.String(), a.OfsReg)
|
||||
}
|
||||
|
||||
case AmoReg:
|
||||
return fmt.Sprintf("(X%d)", a.reg)
|
||||
|
||||
default:
|
||||
return strings.ToUpper(arg.String())
|
||||
}
|
||||
}
|
1474
vendor/golang.org/x/arch/riscv64/riscv64asm/tables.go
generated
vendored
Normal file
1474
vendor/golang.org/x/arch/riscv64/riscv64asm/tables.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
@ -76,6 +76,7 @@ go.starlark.net/syntax
|
||||
## explicit; go 1.18
|
||||
golang.org/x/arch/arm64/arm64asm
|
||||
golang.org/x/arch/loong64/loong64asm
|
||||
golang.org/x/arch/riscv64/riscv64asm
|
||||
golang.org/x/arch/ppc64/ppc64asm
|
||||
golang.org/x/arch/x86/x86asm
|
||||
# golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2
|
||||
|
Loading…
Reference in New Issue
Block a user