Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

delve: add linux-riscv64 support #3785

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Documentation/backend_test_health.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,19 @@ Tests skipped by each supported backend:
* 1 broken in linux ppc64le
* linux/ppc64le/native/pie skipped = 3
* 3 broken - pie mode
* linux/riscv64 skipped = 2
* 1 broken - cgo stacktraces
* 1 not working on linux/riscv64
* pie skipped = 2
* 2 upstream issue - https://github.com/golang/go/issues/29322
* ppc64le skipped = 12
* 6 broken
* 1 broken - global variable symbolication
* 5 not implemented
* riscv64 skipped = 6
* 2 broken
* 1 broken - global variable symbolication
* 3 not implemented
* windows skipped = 7
* 1 broken
* 2 not working on windows
Expand Down
7 changes: 7 additions & 0 deletions _fixtures/asmnilptr/main_riscv64.s
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions _fixtures/cgostacktest/hello.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#else
#define BREAKPOINT asm("brk 0;")
#endif
#elif __riscv
#define BREAKPOINT asm("ebreak;")
#endif

void helloworld_pt2(int x) {
Expand Down
4 changes: 3 additions & 1 deletion _fixtures/testvariablescgo/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#else
#define BREAKPOINT asm("brk 0;")
#endif
#elif __riscv
#define BREAKPOINT asm("ebreak;")
#endif

#define N 100
Expand All @@ -37,6 +39,6 @@ void testfn(void) {
strcpy(s, s0);

BREAKPOINT;

printf("%s %s %p %p\n", s, longstring, v, v_align_check);
}
2 changes: 1 addition & 1 deletion _scripts/make.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ This option can only be specified if testset is basic or a single package.`)
test.PersistentFlags().StringVarP(&TestBuildMode, "test-build-mode", "m", "", `Runs tests compiling with the specified build mode, one of either:
normal normal buildmode (default)
pie PIE buildmode

This option can only be specified if testset is basic or a single package.`)
test.PersistentFlags().BoolVarP(&TestIncludePIE, "pie", "", true, "Standard testing should include PIE")

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ require (
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
go.starlark.net v0.0.0-20231101134539-556fd59b42f6
golang.org/x/arch v0.6.0
golang.org/x/arch v0.10.1-0.20240910142527-7874f23b9c06
golang.org/x/sys v0.17.0
golang.org/x/tools v0.14.0
gopkg.in/yaml.v3 v3.0.1
Expand Down
92 changes: 92 additions & 0 deletions pkg/dwarf/regnum/riscv64.go
Original file line number Diff line number Diff line change
@@ -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 fmt.Sprintf("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[fmt.Sprintf("pc")] = RISCV64_PC

for i := 0; i <= 31; i++ {
r[fmt.Sprintf("f%d", i)] = RISCV64_F0 + i
}

return r
}()
6 changes: 6 additions & 0 deletions pkg/proc/bininfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ var (
elf.EM_AARCH64: true,
elf.EM_386: true,
elf.EM_PPC64: true,
elf.EM_RISCV: true,
}

supportedWindowsArch = map[_PEMachine]bool{
Expand Down Expand Up @@ -802,6 +803,8 @@ func NewBinaryInfo(goos, goarch string) *BinaryInfo {
r.Arch = ARM64Arch(goos)
case "ppc64le":
r.Arch = PPC64LEArch(goos)
case "riscv64":
r.Arch = RISCV64Arch(goos)
}
return r
}
Expand Down Expand Up @@ -1803,6 +1806,9 @@ func (bi *BinaryInfo) setGStructOffsetElf(image *Image, exe *elf.File, wg *sync.
case elf.EM_PPC64:
_ = getSymbol(image, bi.logger, exe, "runtime.tls_g")

case elf.EM_RISCV:
_ = getSymbol(image, bi.logger, exe, "runtime.tls_g")

default:
// we should never get here
panic("architecture not supported")
Expand Down
54 changes: 54 additions & 0 deletions pkg/proc/core/linux_core.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const _NT_FPREGSET elf.NType = 0x2
const (
_EM_AARCH64 = 183
_EM_X86_64 = 62
_EM_RISCV = 243
_ARM_FP_HEADER_START = 512
)

Expand All @@ -49,6 +50,8 @@ func linuxThreadsFromNotes(p *process, notes []*note, machineType elf.Machine) p
var currentThread proc.Thread
var lastThreadAMD *linuxAMD64Thread
var lastThreadARM *linuxARM64Thread
var lastThreadRISCV *linuxRISCV64Thread

for _, note := range notes {
switch note.Type {
case elf.NT_PRSTATUS:
Expand All @@ -66,12 +69,23 @@ func linuxThreadsFromNotes(p *process, notes []*note, machineType elf.Machine) p
if currentThread == nil {
currentThread = p.Threads[int(t.Pid)]
}
} else if machineType == _EM_RISCV {
t := note.Desc.(*linuxPrStatusRISCV64)
lastThreadRISCV = &linuxRISCV64Thread{linutil.RISCV64Registers{Regs: &t.Reg}, t}
p.Threads[int(t.Pid)] = &thread{lastThreadRISCV, p, proc.CommonThread{}}
if currentThread == nil {
currentThread = p.Threads[int(t.Pid)]
}
}
case _NT_FPREGSET:
if machineType == _EM_AARCH64 {
if lastThreadARM != nil {
lastThreadARM.regs.Fpregs = note.Desc.(*linutil.ARM64PtraceFpRegs).Decode()
}
} else if machineType == _EM_RISCV {
if lastThreadRISCV != nil {
lastThreadRISCV.regs.Fpregs = note.Desc.(*linutil.RISCV64PtraceFpRegs).Decode()
}
}
case _NT_X86_XSTATE:
if machineType == _EM_X86_64 {
Expand Down Expand Up @@ -147,6 +161,8 @@ func readLinuxOrPlatformIndependentCore(corePath, exePath string) (*process, pro
bi = proc.NewBinaryInfo("linux", "amd64")
case _EM_AARCH64:
bi = proc.NewBinaryInfo("linux", "arm64")
case _EM_RISCV:
bi = proc.NewBinaryInfo("linux", "riscv64")
default:
return nil, nil, errors.New("unsupported machine type")
}
Expand Down Expand Up @@ -181,6 +197,11 @@ type linuxARM64Thread struct {
t *linuxPrStatusARM64
}

type linuxRISCV64Thread struct {
regs linutil.RISCV64Registers
t *linuxPrStatusRISCV64
}

func (t *linuxAMD64Thread) registers() (proc.Registers, error) {
var r linutil.AMD64Registers
r.Regs = t.regs.Regs
Expand All @@ -195,6 +216,13 @@ func (t *linuxARM64Thread) registers() (proc.Registers, error) {
return &r, nil
}

func (t *linuxRISCV64Thread) registers() (proc.Registers, error) {
var r linutil.RISCV64Registers
r.Regs = t.regs.Regs
r.Fpregs = t.regs.Fpregs
return &r, nil
}

func (t *linuxAMD64Thread) pid() int {
return int(t.t.Pid)
}
Expand All @@ -203,6 +231,10 @@ func (t *linuxARM64Thread) pid() int {
return int(t.t.Pid)
}

func (t *linuxRISCV64Thread) pid() int {
return int(t.t.Pid)
}

// Note is a note from the PT_NOTE prog.
// Relevant types:
// - NT_FILE: File mapping information, e.g. program text mappings. Desc is a LinuxNTFile.
Expand Down Expand Up @@ -286,6 +318,8 @@ func readNote(r io.ReadSeeker, machineType elf.Machine) (*note, error) {
note.Desc = &linuxPrStatusAMD64{}
case _EM_AARCH64:
note.Desc = &linuxPrStatusARM64{}
case _EM_RISCV:
note.Desc = &linuxPrStatusRISCV64{}
default:
return nil, errors.New("unsupported machine type")
}
Expand Down Expand Up @@ -332,6 +366,13 @@ func readNote(r io.ReadSeeker, machineType elf.Machine) (*note, error) {
return nil, err
}
note.Desc = fpregs
} else if machineType == _EM_RISCV {
fpregs := &linutil.RISCV64PtraceFpRegs{}
rdr := bytes.NewReader(desc)
if err := binary.Read(rdr, binary.LittleEndian, fpregs.Byte()); err != nil {
return nil, err
}
note.Desc = fpregs
}
}
if err := skipPadding(r, 4); err != nil {
Expand Down Expand Up @@ -446,6 +487,19 @@ type linuxPrStatusARM64 struct {
Fpvalid int32
}

// LinuxPrStatusRISCV64 is a copy of the prstatus kernel struct.
type linuxPrStatusRISCV64 struct {
Siginfo linuxSiginfo
Cursig uint16
_ [2]uint8
Sigpend uint64
Sighold uint64
Pid, Ppid, Pgrp, Sid int32
Utime, Stime, CUtime, CStime linuxCoreTimeval
Reg linutil.RISCV64PtraceRegs
Fpvalid int32
}

// LinuxSiginfo is a copy of the
// siginfo kernel struct.
type linuxSiginfo struct {
Expand Down
2 changes: 2 additions & 0 deletions pkg/proc/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ func (t *Target) Dump(out elfwriter.WriteCloserSeeker, flags DumpFlags, state *D
fhdr.Machine = elf.EM_AARCH64
case "ppc64le":
fhdr.Machine = elf.EM_PPC64
case "riscv64":
fhdr.Machine = elf.EM_RISCV
default:
panic("not implemented")
}
Expand Down
Loading