Skip to content

Commit

Permalink
WIP: Add ppc64le support
Browse files Browse the repository at this point in the history
  • Loading branch information
alexsaezm committed Jun 3, 2022
1 parent f37ced6 commit 46de2b4
Show file tree
Hide file tree
Showing 14 changed files with 796 additions and 7 deletions.
73 changes: 73 additions & 0 deletions pkg/dwarf/regnum/ppc64le.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package regnum

import "fmt"

const (
PPC64LE_R0 = 0 // General Purpose Registers: from R0 to R31
PPC64LE_F0 = 0 // Floating point registers: from F0 to F31
PPC64LE_V0 = 0 // Vector (Altivec/VMX) registers: from V0 to V31
PPC64LE_VS0 = 0 // Vector Scalar (VSX) registers: from VS0 to VS63
PPC64LE_CR0 = 0 // Condition Registers: from CR0 to CR7
PPC64LE_SP = 1 // Stack frame pointer: Gpr[1]
PPC64LE_PC = 12 // The documentation refers to this as the CIA (Current Instruction Address)
PPC64LE_BP = 30 // TODO(alexsaezm) No idea where the BP is
PPC64LE_LR = 65 // TODO(alexsaezm) What is this?
)

// PPC64LEToName TODO(alexsaezm) Verify why I have this method, do I need it?
func PPC64LEToName(num uint64) string {
switch {
case num <= 31:
return fmt.Sprintf("R%d", num)
case num <= 62:
return fmt.Sprintf("F%d", num)
case num == PPC64LE_SP:
return "SP"
case num == PPC64LE_PC:
return "PC"
case num >= PPC64LE_V0 && num <= 108:
return fmt.Sprintf("V%d", num-64)
default:
return fmt.Sprintf("unknown%d", num)
}
}

func PPC64LEMaxRegNum() uint64 {
// TODO(alexsaezm) What is this thing?
return 65
}

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

r["nip"] = PPC64LE_PC
r["sp"] = PPC64LE_SP
r["bp"] = PPC64LE_BP
r["lr"] = 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
}()
7 changes: 7 additions & 0 deletions pkg/proc/bininfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,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 @@ -646,6 +647,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 @@ -1451,6 +1454,10 @@ 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:
// TODO(alexsaezm) Complete this
_ = getSymbol(image, bi.logger, exe, "runtime.tls_g")

default:
// we should never get here
panic("architecture not supported")
Expand Down
171 changes: 171 additions & 0 deletions pkg/proc/linutil/regs_ppc64le_arch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package linutil

import (
"fmt"
"github.com/go-delve/delve/pkg/proc"
)

// PPC64LERegisters implements the proc.Registers interface for the native/linux
// backend and core/linux backends, on PPC64LE.
type PPC64LERegisters struct {
Regs *PPC64LEPtraceRegs
Fpregs []proc.Register //Formatted floating point registers
Fpregset []byte //holding all floating point register values
loadFpRegs func(*PPC64LERegisters) error
}

func NewPPC64LERegisters(regs *PPC64LEPtraceRegs, loadFpRegs func(*PPC64LERegisters) error) *PPC64LERegisters {
return &PPC64LERegisters{Regs: regs, loadFpRegs: loadFpRegs}
}

// PPC64LEPtraceRegs is the struct used by the linux kernel to return the
// general purpose registers for PPC64LE CPUs.
// TODO(alexsaezm) Remove the next line:
// Copied from src/syscall/ztypes_linux_ppc64le.go#L518-L532
type PPC64LEPtraceRegs struct {
Gpr [32]uint64 // 32 general-purpose registers, each 64 bits wide
Nip uint64
Msr uint64
Orig_gpr3 uint64
Ctr uint64
Link uint64
Xer uint64
Ccr uint64
Softe uint64
Trap uint64
Dar uint64
Dsisr uint64
Result uint64
//SP uint64 // SP pointer r[1]
//TOC uint64 // TOC pointer -- r[2]
//TLS uint64 // Thread pointer -- r[13]
//BP uint64 // Base pointer -- r[30] // TODO(alexsaezm) Check this
//LR uint64 // Link register -> TODO(alexsaezm) LLDB dwarf_lr_ppc64le = 65
//CTR uint64 // Loop count register // TODO(alexsaezm) LLDB dwarf_ctr_ppc64le = 66
//XER uint64 // Fixed point exception register // TODO(alexsaezm) LLDB dwarf_xer_ppc64le = 76
}

func (regs PPC64LEPtraceRegs) String() string {
gprs := "\n"
for i, r := range regs.Gpr {
gprs += fmt.Sprintf("\t\t - gpr[%d]: %d\n", i, r)
}
return fmt.Sprintf("Registers:\n"+
"\t - Gpr: %s"+
"\t - Nip: %d\n"+
"\t - Msr: %d\n"+
"\t - Orig_gpr3: %d\n"+
"\t - Ctr: %d\n"+
"\t - Link: %d\n"+
"\t - Xer: %d\n"+
"\t - Ccr: %d\n"+
"\t - Softe: %d\n"+
"\t - Trap: %d\n"+
"\t - Dar: %d\n"+
"\t - Dsisr: %d\n"+
"\t - Result: %d\n", gprs, regs.Nip, regs.Msr, regs.Orig_gpr3, regs.Ctr, regs.Link, regs.Xer, regs.Ccr, regs.Softe, regs.Trap, regs.Dar, regs.Dsisr, regs.Result)
}

// PC returns the value of the NIP register
// Also called the IAR/Instruction Address Register or NIP/Next Instruction Pointer
func (r *PPC64LERegisters) PC() uint64 {
return r.Regs.Nip
}

// SP returns the value of Stack frame pointer stored in Gpr[1].
func (r *PPC64LERegisters) SP() uint64 {
return r.Regs.Gpr[1]
}

func (r *PPC64LERegisters) BP() uint64 {
return r.Regs.Gpr[30]
}

// TLS returns the value of the thread pointer stored in Gpr[13]
func (r *PPC64LERegisters) TLS() uint64 {
return r.Regs.Gpr[13]
}

// GAddr returns the address of the G variable
func (r *PPC64LERegisters) GAddr() (uint64, bool) {
return r.Regs.Gpr[30], true
}

// Slice returns the registers as a list of (name, value) pairs.
func (r *PPC64LERegisters) Slice(floatingPoint bool) ([]proc.Register, error) {
var regs = []struct {
k string
v uint64
}{
{"R0", r.Regs.Gpr[0]},
{"R1", r.Regs.Gpr[1]},
{"R2", r.Regs.Gpr[2]},
{"R3", r.Regs.Gpr[3]},
{"R4", r.Regs.Gpr[4]},
{"R5", r.Regs.Gpr[5]},
{"R6", r.Regs.Gpr[6]},
{"R7", r.Regs.Gpr[7]},
{"R8", r.Regs.Gpr[8]},
{"R9", r.Regs.Gpr[9]},
{"R10", r.Regs.Gpr[10]},
{"R11", r.Regs.Gpr[11]},
{"R12", r.Regs.Gpr[12]},
{"R13", r.Regs.Gpr[13]},
{"R14", r.Regs.Gpr[14]},
{"R15", r.Regs.Gpr[15]},
{"R16", r.Regs.Gpr[16]},
{"R17", r.Regs.Gpr[17]},
{"R18", r.Regs.Gpr[18]},
{"R19", r.Regs.Gpr[19]},
{"R20", r.Regs.Gpr[20]},
{"R21", r.Regs.Gpr[21]},
{"R22", r.Regs.Gpr[22]},
{"R23", r.Regs.Gpr[23]},
{"R24", r.Regs.Gpr[24]},
{"R25", r.Regs.Gpr[25]},
{"R26", r.Regs.Gpr[26]},
{"R27", r.Regs.Gpr[27]},
{"R28", r.Regs.Gpr[28]},
{"R29", r.Regs.Gpr[29]},
{"R30", r.Regs.Gpr[30]},
{"R31", r.Regs.Gpr[31]},
{"NIP", r.Regs.Nip},
//{"SP", r.Regs.SP},
//{"TOC", r.Regs.TOC},
//{"TLS", r.Regs.TLS},
//{"BR", r.Regs.BP},
//{"LR", r.Regs.LR},
//{"CTR", r.Regs.CTR},
}
out := make([]proc.Register, 0, len(regs)+len(r.Fpregs))
for _, reg := range regs {
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
}

// Copy returns a copy of these registers that is guaranteed not to change.
func (r *PPC64LERegisters) Copy() (proc.Registers, error) {
//TODO implement me
panic("implement me: Copy")
}

type PPC64LEPtraceFpRegs struct {
// TODO(alexsaezm) Not quite sure about this, review in the future
Fp []byte
}

func (fpregs *PPC64LEPtraceFpRegs) Decode() (regs []proc.Register) {
for i := 0; i < len(fpregs.Fp); i += 16 {
regs = proc.AppendBytesRegister(regs, fmt.Sprintf("V%d", i/16), fpregs.Fp[i:i+16])
}
return
}
23 changes: 23 additions & 0 deletions pkg/proc/native/hwbreak_ppc64le.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package native

import (
"github.com/go-delve/delve/pkg/proc"
)

func (thread *nativeThread) findHardwareBreakpoint() (*proc.Breakpoint, error) {
// TODO(alexsaezm) Implement this method
panic("Unimplemented findHardwareBreakpoint method in threads_linux_ppc64le.go")
return nil, nil
}

func (thread *nativeThread) writeHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error {
// TODO(alexsaezm) Implement this method
panic("Unimplemented writeHardwareBreakpoint method in threads_linux_ppc64le.go")
return nil
}

func (thread *nativeThread) clearHardwareBreakpoint(addr uint64, wtype proc.WatchType, idx uint8) error {
// TODO(alexsaezm) Implement this method
panic("Unimplemented clearHardwareBreakpoint method in threads_linux_ppc64le.go")
return nil
}
2 changes: 2 additions & 0 deletions pkg/proc/native/proc.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ func (dbp *nativeProcess) initialize(path string, debugInfoDirs []string) (*proc
// look like the breakpoint was hit twice when it was "logically" only
// executed once.
// See: https://go-review.googlesource.com/c/go/+/208126
// TODO(alexsaezm) Verify if I need to disable it for ppc64le too
DisableAsyncPreempt: runtime.GOOS == "windows" || runtime.GOOS == "freebsd" || (runtime.GOOS == "linux" && runtime.GOARCH == "arm64"),

StopReason: stopReason,
Expand All @@ -259,6 +260,7 @@ func (dbp *nativeProcess) initialize(path string, debugInfoDirs []string) (*proc
if err != nil {
return nil, err
}
// TODO(alexsaezm) Verify if I need to run IsCgo for ppc64le too
if dbp.bi.Arch.Name == "arm64" {
dbp.iscgo = tgt.IsCgo()
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/proc/native/proc_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,9 +414,9 @@ func (dbp *nativeProcess) trapWaitInternal(pid int, options trapWaitOptions) (*n
// Sometimes we get an unknown thread, ignore it?
continue
}
if (halt && status.StopSignal() == sys.SIGSTOP) || (status.StopSignal() == sys.SIGTRAP) {
if (halt && status.StopSignal() == sys.SIGSTOP) || (status.StopSignal() == sys.SIGTRAP) || (status.StopSignal() == sys.SIGSEGV) {
th.os.running = false
if status.StopSignal() == sys.SIGTRAP {
if status.StopSignal() == sys.SIGTRAP || status.StopSignal() == sys.SIGSEGV {
th.os.setbp = true
}
return th, nil
Expand Down
4 changes: 2 additions & 2 deletions pkg/proc/native/ptrace_linux_64bit.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build (linux && amd64) || (linux && arm64)
// +build linux,amd64 linux,arm64
//go:build (linux && amd64) || (linux && arm64) || (linux && ppc64le)
// +build linux,amd64 linux,arm64 linux,ppc64le

package native

Expand Down
Loading

0 comments on commit 46de2b4

Please sign in to comment.