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

support linux-loong64 native debug #3685

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
5 changes: 5 additions & 0 deletions Documentation/backend_test_health.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ Tests skipped by each supported backend:
* 1 broken in linux ppc64le
* linux/ppc64le/native/pie skipped = 3
* 3 broken - pie mode
* loong64 skipped = 8
* 1 broken
* 3 broken - cgo stacktraces
* 1 broken - global variable symbolication
* 3 not implemented
* pie skipped = 2
* 2 upstream issue - https://github.com/golang/go/issues/29322
* ppc64le skipped = 11
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 @@ -14,6 +14,8 @@
#else
#define BREAKPOINT asm("brk 0;")
#endif
#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 @@ -12,6 +12,8 @@
#else
#define BREAKPOINT asm("brk 0;")
#endif
#elif __loongarch__
#define BREAKPOINT asm("break 0;")
#endif

#define N 100
Expand Down
5 changes: 4 additions & 1 deletion _scripts/make.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ func NewMakeCommands() *cobra.Command {
envflags = append(envflags, "GOOS="+OS)
}
if len(envflags) > 0 {
executeEnv(envflags, "go", "build", "-ldflags", "-extldflags -static", tagFlags(), buildFlags(), DelveMainPackagePath)
envflags = append(envflags, "-mod=vendor")
}
if len(envflags) > 0 {
executeEnv(envflags, "go", "build", "-mod=vendor", "-ldflags", "-extldflags -static", tagFlags(), buildFlags(), DelveMainPackagePath)
} else {
execute("go", "build", "-ldflags", "-extldflags -static", tagFlags(), buildFlags(), DelveMainPackagePath)
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/dlv/dlv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ func getDlvBinEBPF(t *testing.T) string {

func getDlvBinInternal(t *testing.T, goflags ...string) string {
dlvbin := filepath.Join(t.TempDir(), "dlv.exe")
args := append([]string{"build", "-o", dlvbin}, goflags...)
args := append([]string{"build", "-mod=vendor", "-o", dlvbin}, goflags...)
args = append(args, "github.com/go-delve/delve/cmd/dlv")

out, err := exec.Command("go", args...).CombinedOutput()
Expand Down Expand Up @@ -382,7 +382,7 @@ func TestGeneratedDoc(t *testing.T) {

// Checks gen-usage-docs.go
tempDir := t.TempDir()
cmd := exec.Command("go", "run", "_scripts/gen-usage-docs.go", tempDir)
cmd := exec.Command("go", "run", "-mod=vendor", "_scripts/gen-usage-docs.go", tempDir)
cmd.Dir = projectRoot()
err := cmd.Run()
assertNoError(err, t, "go run _scripts/gen-usage-docs.go")
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 fmt.Sprintf("FCSR")

case num == LOONG64_ERA:
return fmt.Sprintf("ERA")

case num == LOONG64_BADV:
return fmt.Sprintf("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[fmt.Sprintf("era")] = LOONG64_ERA
r[fmt.Sprintf("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
}()
2 changes: 1 addition & 1 deletion pkg/gobuild/gobuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func goBuildArgs(debugname string, pkgs []string, buildflags string, isTest bool

args = append(args, "-o", debugname)
if isTest {
args = append([]string{"-c"}, args...)
args = append([]string{"-c", "-mod=vendor"}, args...)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't force users to only build with -mod=vendor.

}
args = append(args, "-gcflags", "all=-N -l")
if buildflags != "" {
Expand Down
10 changes: 10 additions & 0 deletions pkg/proc/bininfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ var (
elf.EM_AARCH64: true,
elf.EM_386: true,
elf.EM_PPC64: true,
elf.EM_LOONGARCH: true,
}

supportedWindowsArch = map[_PEMachine]bool{
Expand Down Expand Up @@ -689,6 +690,8 @@ func NewBinaryInfo(goos, goarch string) *BinaryInfo {
r.Arch = ARM64Arch(goos)
case "ppc64le":
r.Arch = PPC64LEArch(goos)
case "loong64":
r.Arch = LOONG64Arch(goos)
}
return r
}
Expand Down Expand Up @@ -1742,6 +1745,13 @@ 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_LOONGARCH:
tlsg := getSymbol(image, bi.logger, exe, "runtime.tls_g")
if tlsg == nil || tls == nil {
bi.gStructOffset = 6 * uint64(bi.Arch.PtrSize())
return
}
bi.gStructOffset = tlsg.Value + (tls.Vaddr & (tls.Align - 1))

default:
// we should never get here
Expand Down
57 changes: 57 additions & 0 deletions pkg/proc/core/linux_core.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const _NT_FPREGSET elf.NType = 0x2
const (
_EM_AARCH64 = 183
_EM_X86_64 = 62
_EM_LOONGARCH = 258
_ARM_FP_HEADER_START = 512
)

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

for _, note := range notes {
switch note.Type {
case elf.NT_PRSTATUS:
Expand All @@ -65,12 +68,24 @@ func linuxThreadsFromNotes(p *process, notes []*note, machineType elf.Machine) p
if currentThread == nil {
currentThread = p.Threads[int(t.Pid)]
}

} else if machineType == _EM_LOONGARCH {
t := note.Desc.(*linuxPrStatusLOONG64)
lastThreadLOONG = &linuxLOONG64Thread{linutil.LOONG64Registers{Regs: &t.Reg}, t}
p.Threads[int(t.Pid)] = &thread{lastThreadLOONG, 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_LOONGARCH {
if lastThreadLOONG != nil {
lastThreadLOONG.regs.Fpregs = note.Desc.(*linutil.LOONG64PtraceFpRegs).Decode()
}
}
case _NT_X86_XSTATE:
if machineType == _EM_X86_64 {
Expand Down Expand Up @@ -146,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_LOONGARCH:
bi = proc.NewBinaryInfo("linux", "loong64")
default:
return nil, nil, fmt.Errorf("unsupported machine type")
}
Expand Down Expand Up @@ -202,6 +219,22 @@ func (t *linuxARM64Thread) pid() int {
return int(t.t.Pid)
}

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

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 *linuxLOONG64Thread) 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 @@ -285,6 +318,8 @@ func readNote(r io.ReadSeeker, machineType elf.Machine) (*note, error) {
note.Desc = &linuxPrStatusAMD64{}
case _EM_AARCH64:
note.Desc = &linuxPrStatusARM64{}
case _EM_LOONGARCH:
note.Desc = &linuxPrStatusLOONG64{}
default:
return nil, fmt.Errorf("unsupported machine type")
}
Expand Down Expand Up @@ -332,6 +367,15 @@ func readNote(r io.ReadSeeker, machineType elf.Machine) (*note, error) {
}
note.Desc = fpregs
}

if machineType == _EM_LOONGARCH {
fpregs := &linutil.LOONG64PtraceFpRegs{}
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 {
return nil, fmt.Errorf("aligning after desc: %v", err)
Expand Down Expand Up @@ -446,6 +490,19 @@ type linuxPrStatusARM64 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 @@ -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 "loong64":
fhdr.Machine = elf.EM_LOONGARCH
default:
panic("not implemented")
}
Expand Down
Loading