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 ppc64le support #2963

Merged
merged 2 commits into from
Jul 7, 2023
Merged
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
13 changes: 12 additions & 1 deletion Documentation/backend_test_health.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,22 @@ Tests skipped by each supported backend:
* 4 not implemented
* linux/386/pie skipped = 1
* 1 broken
* linux/ppc64le skipped = 1
* 1 broken - cgo stacktraces
* linux/ppc64le/native skipped = 1
* 1 broken in linux ppc64le
* linux/ppc64le/native/pie skipped = 11
* 11 broken - pie mode
* pie skipped = 2
* 2 upstream issue - https://github.com/golang/go/issues/29322
* ppc64le skipped = 11
* 6 broken
* 1 broken - global variable symbolication
* 4 not implemented
* windows skipped = 4
* 1 broken
* 3 see https://github.com/go-delve/delve/issues/2768
* windows/arm64 skipped = 4
* windows/arm64 skipped = 5
* 3 broken
* 1 broken - cgo stacktraces
* 1 broken - step concurrent
7 changes: 7 additions & 0 deletions _fixtures/asmnilptr/main_ppc64le.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include "textflag.h"

TEXT ·asmFunc(SB),0,$0-16
MOVD arg+0(FP), R5
MOVD (R5), R5
MOVD 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 @@ -6,6 +6,8 @@
#define BREAKPOINT asm("int3;")
#elif __i386__
#define BREAKPOINT asm("int3;")
#elif __PPC64__
#define BREAKPOINT asm("tw 31,0,0;")
#elif __aarch64__
#ifdef WIN32
#define BREAKPOINT asm("brk 0xF000;")
Expand Down
3 changes: 3 additions & 0 deletions _scripts/make.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,9 @@ func tagFlags() string {
if runtime.GOOS == "windows" && runtime.GOARCH == "arm64" {
tags = append(tags, "exp.winarm64")
}
if runtime.GOOS == "linux" && runtime.GOARCH == "ppc64le" {
tags = append(tags, "exp.linuxppc64le")
}
if Tags != nil && len(*Tags) > 0 {
tags = append(tags, *Tags...)
}
Expand Down
8 changes: 8 additions & 0 deletions _scripts/test_linux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,11 @@ else
exit $x
fi

export GOARCH=ppc64le
go run _scripts/make.go --tags exp.linuxppc64le
Copy link
Member

Choose a reason for hiding this comment

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

There's a bunch of test failures in CI, I think this might be what's causing them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it was the TestGeneratedDoc. It should be fix now

Copy link
Member

Choose a reason for hiding this comment

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

You are right: this isn't even running currently in CI because other failures (TestStaticcheck) are causing the script to exit before this is even executed. However I don't think it's going to work. The export GOARCH=ppc64le makes go run produce a ppc64le binary for make.go, which won't run.

I think the way to do this is to do GOARCH=ppc64le go build -tags exp.linuxppc64le github.com/go-delve/delve/cmd/dlv directly.

Copy link
Member

Choose a reason for hiding this comment

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

The tests now pass, this line however is never executed because of the exit above.

x=$?
if [ "$version" = "gotip" ]; then
exit 0
else
exit $x
fi
7 changes: 7 additions & 0 deletions cmd/dlv/dlv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ func getDlvBin(t *testing.T) string {
if runtime.GOOS == "windows" && runtime.GOARCH == "arm64" {
tags = "-tags=exp.winarm64"
}
if runtime.GOOS == "linux" && runtime.GOARCH == "ppc64le" {
tags = "-tags=exp.linuxppc64le"
}
return getDlvBinInternal(t, tags)
}

Expand Down Expand Up @@ -371,6 +374,10 @@ func TestGeneratedDoc(t *testing.T) {
//TODO(qmuntal): investigate further when the Windows ARM64 backend is more stable.
t.Skip("skipping test on Windows in CI")
}
if runtime.GOOS == "linux" && runtime.GOARCH == "ppc64le" {
//TODO(alexsaezm): finish CI integration
t.Skip("skipping test on Linux/PPC64LE in CI")
}
// Checks gen-cli-docs.go
var generatedBuf bytes.Buffer
commands := terminal.DebugCommands(nil)
Expand Down
115 changes: 115 additions & 0 deletions pkg/dwarf/regnum/ppc64le.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package regnum

import "fmt"

// The mapping between hardware registers and DWARF registers is specified
// in the 64-Bit ELF V2 ABI Specification of the Power Architecture in section
// 2.4 DWARF Definition
// https://openpowerfoundation.org/specifications/64bitelfabi/

const (
alexsaezm marked this conversation as resolved.
Show resolved Hide resolved
// General Purpose Registers: from R0 to R31
PPC64LE_FIRST_GPR = 0
PPC64LE_R0 = PPC64LE_FIRST_GPR
PPC64LE_LAST_GPR = 31
// Floating point registers: from F0 to F31
PPC64LE_FIRST_FPR = 32
PPC64LE_F0 = PPC64LE_FIRST_FPR
PPC64LE_LAST_FPR = 63
// Vector (Altivec/VMX) registers: from V0 to V31
PPC64LE_FIRST_VMX = 64
PPC64LE_V0 = PPC64LE_FIRST_VMX
PPC64LE_LAST_VMX = 95
// Vector Scalar (VSX) registers: from VS0 to VS63
PPC64LE_FIRST_VSX = 96
PPC64LE_VS0 = PPC64LE_FIRST_VSX
PPC64LE_LAST_VSX = 160
// Condition Registers: from CR0 to CR7
PPC64LE_CR0 = 0
// Special registers
PPC64LE_SP = 1 // Stack frame pointer: Gpr[1]
PPC64LE_PC = 12 // The documentation refers to this as the CIA (Current Instruction Address)
PPC64LE_LR = 65 // Link register
)

func PPC64LEToName(num uint64) string {
switch {
case num == PPC64LE_SP:
return "SP"
case num == PPC64LE_PC:
return "PC"
case num == PPC64LE_LR:
return "LR"
case isGPR(num):
return fmt.Sprintf("r%d", int(num-PPC64LE_FIRST_GPR))
case isFPR(num):
return fmt.Sprintf("f%d", int(num-PPC64LE_FIRST_FPR))
case isVMX(num):
return fmt.Sprintf("v%d", int(num-PPC64LE_FIRST_VMX))
case isVSX(num):
return fmt.Sprintf("vs%d", int(num-PPC64LE_FIRST_VSX))
default:
return fmt.Sprintf("unknown%d", num)
}
}

// PPC64LEMaxRegNum is 172 registers in total, across 4 categories:
// General Purpose Registers or GPR (32 GPR + 9 special registers)
// Floating Point Registers or FPR (32 FPR + 1 special register)
// Altivec/VMX Registers or VMX (32 VMX + 2 special registers)
// VSX Registers or VSX (64 VSX)
// Documentation: https://lldb.llvm.org/cpp_reference/RegisterContextPOSIX__ppc64le_8cpp_source.html
func PPC64LEMaxRegNum() uint64 {
return 172
}

func isGPR(num uint64) bool {
return num < PPC64LE_LAST_GPR
}

func isFPR(num uint64) bool {
return num >= PPC64LE_FIRST_FPR && num <= PPC64LE_LAST_FPR
}

func isVMX(num uint64) bool {
return num >= PPC64LE_FIRST_VMX && num <= PPC64LE_LAST_VMX
}

func isVSX(num uint64) bool {
return num >= PPC64LE_FIRST_VSX && num <= PPC64LE_LAST_VSX
}

var PPC64LENameToDwarf = func() map[string]int {
r := make(map[string]int)

r["nip"] = PPC64LE_PC
r["sp"] = PPC64LE_SP
r["bp"] = PPC64LE_SP
derekparker marked this conversation as resolved.
Show resolved Hide resolved
r["link"] = PPC64LE_LR

// General Purpose Registers: from R0 to R31
for i := 0; i <= 31; i++ {
r[fmt.Sprintf("r%d", i)] = PPC64LE_R0 + i
}

// Floating point registers: from F0 to F31
for i := 0; i <= 31; i++ {
r[fmt.Sprintf("f%d", i)] = PPC64LE_F0 + i
}

// Vector (Altivec/VMX) registers: from V0 to V31
for i := 0; i <= 31; i++ {
r[fmt.Sprintf("v%d", i)] = PPC64LE_V0 + i
}

// Vector Scalar (VSX) registers: from VS0 to VS63
for i := 0; i <= 63; i++ {
r[fmt.Sprintf("vs%d", i)] = PPC64LE_VS0 + i
}

// Condition Registers: from CR0 to CR7
for i := 0; i <= 7; i++ {
r[fmt.Sprintf("cr%d", i)] = PPC64LE_CR0 + i
}
return r
}()
1 change: 1 addition & 0 deletions pkg/proc/arch.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,5 +151,6 @@ func nameToDwarfFunc(n2d map[string]int) func(string) (int, bool) {
const (
crosscall2SPOffsetBad = 0x8
crosscall2SPOffsetWindowsAMD64 = 0x118
crosscall2SPOffsetLinuxPPC64LE = 0x158
crosscall2SPOffset = 0x58
)
6 changes: 6 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_X86_64: true,
elf.EM_AARCH64: true,
elf.EM_386: true,
elf.EM_PPC64: true,
}

supportedWindowsArch = map[_PEMachine]bool{
Expand Down Expand Up @@ -687,6 +688,8 @@ func NewBinaryInfo(goos, goarch string) *BinaryInfo {
r.Arch = AMD64Arch(goos)
case "arm64":
r.Arch = ARM64Arch(goos)
case "ppc64le":
r.Arch = PPC64LEArch(goos)
}
return r
}
Expand Down Expand Up @@ -1648,6 +1651,9 @@ 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:
aarzilli marked this conversation as resolved.
Show resolved Hide resolved
_ = getSymbol(image, bi.logger, exe, "runtime.tls_g")

default:
// we should never get here
panic("architecture not supported")
Expand Down
2 changes: 2 additions & 0 deletions pkg/proc/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ func (t *Target) Dump(out elfwriter.WriteCloserSeeker, flags DumpFlags, state *D
fhdr.Machine = elf.EM_386
case "arm64":
fhdr.Machine = elf.EM_AARCH64
case "ppc64le":
fhdr.Machine = elf.EM_PPC64
default:
panic("not implemented")
}
Expand Down
Loading