Skip to content

Commit

Permalink
delve: support linux-loong64 native debug
Browse files Browse the repository at this point in the history
LoongArch is a new RISC ISA, which is independently designed by Loongson Technology.

LoongArch includes a reduced 32-bit version (LA32R), a standard 32-bit version (LA32S)
and a 64-bit version (LA64), and loong64 is the 64-bit version of LoongArch.

LoongArch documentation: https://github.com/loongson/LoongArch-Documentation.git
  • Loading branch information
Huang Qiqi committed Dec 3, 2024
1 parent 7b9a379 commit 29ec15f
Show file tree
Hide file tree
Showing 28 changed files with 1,089 additions and 19 deletions.
7 changes: 7 additions & 0 deletions Documentation/backend_test_health.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ Tests skipped by each supported backend:
* 2 not working on linux/386
* linux/386/pie skipped = 1
* 1 broken
* linux/loong64 skipped = 2
* 1 broken - cgo stacktraces
* 1 not working on linux/loong64
* linux/ppc64le skipped = 3
* 1 broken - cgo stacktraces
* 2 not working on linux/ppc64le when -gcflags=-N -l is passed
Expand All @@ -33,6 +36,10 @@ Tests skipped by each supported backend:
* linux/riscv64 skipped = 2
* 1 broken - cgo stacktraces
* 1 not working on linux/riscv64
* loong64 skipped = 7
* 2 broken
* 1 broken - global variable symbolication
* 4 not implemented
* pie skipped = 2
* 2 upstream issue - https://github.com/golang/go/issues/29322
* ppc64le skipped = 12
Expand Down
7 changes: 7 additions & 0 deletions _fixtures/asmnilptr/main_loong64.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include "textflag.h"

TEXT ·asmFunc(SB),0,$0-16
MOVV arg+0(FP), R5
MOVV (R5), R5
MOVV 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 @@ -16,6 +16,8 @@
#endif
#elif __riscv
#define BREAKPOINT asm("ebreak;")
#elif __loongarch__
#define BREAKPOINT asm("break 0;")
#endif

void helloworld_pt2(int x) {
Expand Down
2 changes: 2 additions & 0 deletions _fixtures/testvariablescgo/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#endif
#elif __riscv
#define BREAKPOINT asm("ebreak;")
#elif __loongarch__
#define BREAKPOINT asm("break 0;")
#endif

#define N 100
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20241028140143-9c0d19e65ba0 h1:od0RE4kmouF+x/o4zkTTSvBnGPZ2azGgCUmZdrbnEXM=
golang.org/x/telemetry v0.0.0-20241028140143-9c0d19e65ba0/go.mod h1:8nZWdGp9pq73ZI//QJyckMQab3yq7hoWi7SI0UIusVI=
golang.org/x/telemetry v0.0.0-20241106142447-58a1122356f5 h1:TCDqnvbBsFapViksHcHySl/sW4+rTGNIAoJJesHRuMM=
golang.org/x/telemetry v0.0.0-20241106142447-58a1122356f5/go.mod h1:8nZWdGp9pq73ZI//QJyckMQab3yq7hoWi7SI0UIusVI=
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
Expand Down
87 changes: 87 additions & 0 deletions pkg/dwarf/regnum/loong64.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package regnum

import (
"fmt"
)

// The mapping between hardware registers and DWARF registers, See
// https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html
// https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html

const (
// General-purpose Register
LOONG64_R0 = 0
LOONG64_LR = 1 // ra: address for subroutine
LOONG64_SP = 3 // sp: stack pointer
LOONG64_R22 = 22
LOONG64_FP = LOONG64_R22 // fp: frame pointer
LOONG64_R31 = 31

// Floating-point Register
LOONG64_F0 = 32
LOONG64_F31 = 63

// Floating condition flag register
LOONG64_FCC0 = 64
LOONG64_FCC7 = 71

LOONG64_FCSR = 72

// Extra, not defined in ELF-ABI specification
LOONG64_ERA = 73
LOONG64_BADV = 74

// See golang src/cmd/link/internal/loong64/l.go
LOONG64_PC = LOONG64_ERA // era : exception program counter

_LOONG64_MaxRegNum = LOONG64_BADV
)

func LOONG64ToName(num uint64) string {
switch {
case num <= LOONG64_R31:
return fmt.Sprintf("R%d", num)

case num >= LOONG64_F0 && num <= LOONG64_F31:
return fmt.Sprintf("F%d", num-32)

case num >= LOONG64_FCC0 && num <= LOONG64_FCC7:
return fmt.Sprintf("FCC%d", num-64)

case num == LOONG64_FCSR:
return "FCSR"

case num == LOONG64_ERA:
return "ERA"

case num == LOONG64_BADV:
return "BADV"

default:
return fmt.Sprintf("Unknown%d", num)
}
}

func LOONG64MaxRegNum() uint64 {
return _LOONG64_MaxRegNum
}

var LOONG64NameToDwarf = func() map[string]int {
r := make(map[string]int)
for i := 0; i <= 31; i++ {
r[fmt.Sprintf("r%d", i)] = LOONG64_R0 + i
}
r["era"] = LOONG64_ERA
r["badv"] = LOONG64_BADV

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

for i := 0; i <= 7; i++ {
r[fmt.Sprintf("fcc%d", i)] = LOONG64_FCC0 + i
}
r["fcsr"] = LOONG64_FCSR

return r
}()
5 changes: 4 additions & 1 deletion pkg/proc/bininfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ var (
elf.EM_386: true,
elf.EM_PPC64: true,
elf.EM_RISCV: true,
elf.EM_LOONGARCH: true,
}

supportedWindowsArch = map[_PEMachine]bool{
Expand Down Expand Up @@ -824,6 +825,8 @@ func NewBinaryInfo(goos, goarch string) *BinaryInfo {
r.Arch = PPC64LEArch(goos)
case "riscv64":
r.Arch = RISCV64Arch(goos)
case "loong64":
r.Arch = LOONG64Arch(goos)
}
return r
}
Expand Down Expand Up @@ -1822,7 +1825,7 @@ func (bi *BinaryInfo) setGStructOffsetElf(image *Image, exe *elf.File, wg *sync.

bi.gStructOffset = tlsg.Value + uint64(bi.Arch.PtrSize()*2) + ((tls.Vaddr - uint64(bi.Arch.PtrSize()*2)) & (tls.Align - 1))

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

default:
Expand Down
6 changes: 6 additions & 0 deletions pkg/proc/core/core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,9 @@ func TestCore(t *testing.T) {
if runtime.GOOS != "linux" || runtime.GOARCH == "386" {
t.Skip("unsupported")
}
if runtime.GOOS != "linux" || runtime.GOARCH == "loong64" {
t.Skip("could not read runtime.sigtrampgo context")
}
if runtime.GOOS == "linux" && os.Getenv("CI") == "true" && buildMode == "pie" {
t.Skip("disabled on linux, Github Actions, with PIE buildmode")
}
Expand Down Expand Up @@ -412,6 +415,9 @@ func TestCoreWithEmptyString(t *testing.T) {
if runtime.GOOS != "linux" || runtime.GOARCH == "386" {
t.Skip("unsupported")
}
if runtime.GOOS != "linux" || runtime.GOARCH == "loong64" {
t.Skip("could not read runtime.sigtrampgo context")
}
if runtime.GOOS == "linux" && os.Getenv("CI") == "true" && buildMode == "pie" {
t.Skip("disabled on linux, Github Actions, with PIE buildmode")
}
Expand Down
46 changes: 43 additions & 3 deletions pkg/proc/core/linux_core.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const (
_EM_AARCH64 = 183
_EM_X86_64 = 62
_EM_RISCV = 243
_EM_LOONGARCH = 258
_ARM_FP_HEADER_START = 512
)

Expand All @@ -63,6 +64,9 @@ func linuxThreadsFromNotes(p *process, notes []*note, machineType elf.Machine) p
case _EM_RISCV:
t := note.Desc.(*linuxPrStatusRISCV64)
lastThread = &linuxRISCV64Thread{linutil.RISCV64Registers{Regs: &t.Reg}, t}
case _EM_LOONGARCH:
t := note.Desc.(*linuxPrStatusLOONG64)
lastThread = &linuxLOONG64Thread{linutil.LOONG64Registers{Regs: &t.Reg}, t}
default:
continue
}
Expand All @@ -76,6 +80,8 @@ func linuxThreadsFromNotes(p *process, notes []*note, machineType elf.Machine) p
th.regs.Fpregs = note.Desc.(*linutil.ARM64PtraceFpRegs).Decode()
case *linuxRISCV64Thread:
th.regs.Fpregs = note.Desc.(*linutil.RISCV64PtraceFpRegs).Decode()
case *linuxLOONG64Thread:
th.regs.Fpregs = note.Desc.(*linutil.LOONG64PtraceFpRegs).Decode()
}
case _NT_X86_XSTATE:
if lastThread != nil {
Expand All @@ -89,9 +95,10 @@ func linuxThreadsFromNotes(p *process, notes []*note, machineType elf.Machine) p
}

var supportedLinuxMachines = map[elf.Machine]string{
_EM_X86_64: "amd64",
_EM_AARCH64: "arm64",
_EM_RISCV: "riscv64",
_EM_X86_64: "amd64",
_EM_AARCH64: "arm64",
_EM_RISCV: "riscv64",
_EM_LOONGARCH: "loong64",
}

// readLinuxOrPlatformIndependentCore reads a core file from corePath
Expand Down Expand Up @@ -189,6 +196,11 @@ type linuxRISCV64Thread struct {
t *linuxPrStatusRISCV64
}

type linuxLOONG64Thread struct {
regs linutil.LOONG64Registers
t *linuxPrStatusLOONG64
}

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

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

func (t *linuxAMD64Thread) ThreadID() int {
return int(t.t.Pid)
}
Expand All @@ -222,6 +241,10 @@ func (t *linuxRISCV64Thread) ThreadID() int {
return int(t.t.Pid)
}

func (t *linuxLOONG64Thread) ThreadID() 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 @@ -307,6 +330,8 @@ func readNote(r io.ReadSeeker, machineType elf.Machine) (*note, error) {
note.Desc = &linuxPrStatusARM64{}
case _EM_RISCV:
note.Desc = &linuxPrStatusRISCV64{}
case _EM_LOONGARCH:
note.Desc = &linuxPrStatusLOONG64{}
default:
return nil, errors.New("unsupported machine type")
}
Expand Down Expand Up @@ -350,6 +375,8 @@ func readNote(r io.ReadSeeker, machineType elf.Machine) (*note, error) {
err = readFpregsetNote(note, &linutil.ARM64PtraceFpRegs{}, desc[:_ARM_FP_HEADER_START])
} else if machineType == _EM_RISCV {
err = readFpregsetNote(note, &linutil.RISCV64PtraceFpRegs{}, desc)
} else if machineType == _EM_LOONGARCH {
err = readFpregsetNote(note, &linutil.LOONG64PtraceFpRegs{}, desc)
}
if err != nil {
return nil, err
Expand Down Expand Up @@ -489,6 +516,19 @@ type linuxPrStatusRISCV64 struct {
Fpvalid int32
}

// LinuxPrStatusLOONG64 is a copy of the prstatus kernel struct.
type linuxPrStatusLOONG64 struct {
Siginfo linuxSiginfo
Cursig uint16
_ [2]uint8
Sigpend uint64
Sighold uint64
Pid, Ppid, Pgrp, Sid int32
Utime, Stime, CUtime, CStime linuxCoreTimeval
Reg linutil.LOONG64PtraceRegs
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 @@ -140,6 +140,8 @@ func (t *Target) Dump(out elfwriter.WriteCloserSeeker, flags DumpFlags, state *D
fhdr.Machine = elf.EM_PPC64
case "riscv64":
fhdr.Machine = elf.EM_RISCV
case "loong64":
fhdr.Machine = elf.EM_LOONGARCH
default:
panic("not implemented")
}
Expand Down
Loading

0 comments on commit 29ec15f

Please sign in to comment.