delve: add linux-riscv64 support (#3785)

This commit is contained in:
lrzlin 2024-10-12 03:34:25 +08:00 committed by GitHub
parent abc948b0ae
commit 75c41f2b64
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
36 changed files with 5462 additions and 50 deletions

@ -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

@ -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")

@ -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")
}

@ -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

@ -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, &regs) })
if err != nil {
return nil, err
}
var tp_tls uint64
if thread.dbp.iscgo {
tp_tls = regs.Tp
}
r := linutil.NewRISCV64Registers(&regs, 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.

@ -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

@ -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

@ -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

@ -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

@ -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
)

@ -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

@ -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

@ -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

@ -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

@ -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

File diff suppressed because it is too large Load Diff

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