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