proc: convert Arch into a struct (#1972)
Replace the interface type Arch with a struct with the same functionality.
This commit is contained in:
parent
85c34e47ee
commit
223e0a57ca
@ -12,23 +12,6 @@ import (
|
|||||||
"github.com/go-delve/delve/pkg/dwarf/op"
|
"github.com/go-delve/delve/pkg/dwarf/op"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AMD64 represents the AMD64 CPU architecture.
|
|
||||||
type AMD64 struct {
|
|
||||||
gStructOffset uint64
|
|
||||||
goos string
|
|
||||||
|
|
||||||
// crosscall2fn is the DIE of crosscall2, a function used by the go runtime
|
|
||||||
// to call C functions. This function in go 1.9 (and previous versions) had
|
|
||||||
// a bad frame descriptor which needs to be fixed to generate good stack
|
|
||||||
// traces.
|
|
||||||
crosscall2fn *Function
|
|
||||||
|
|
||||||
// sigreturnfn is the DIE of runtime.sigreturn, the return trampoline for
|
|
||||||
// the signal handler. See comment in FixFrameUnwindContext for a
|
|
||||||
// description of why this is needed.
|
|
||||||
sigreturnfn *Function
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
amd64DwarfIPRegNum uint64 = 16
|
amd64DwarfIPRegNum uint64 = 16
|
||||||
amd64DwarfSPRegNum uint64 = 7
|
amd64DwarfSPRegNum uint64 = 7
|
||||||
@ -39,51 +22,28 @@ var amd64BreakInstruction = []byte{0xCC}
|
|||||||
|
|
||||||
// AMD64Arch returns an initialized AMD64
|
// AMD64Arch returns an initialized AMD64
|
||||||
// struct.
|
// struct.
|
||||||
func AMD64Arch(goos string) *AMD64 {
|
func AMD64Arch(goos string) *Arch {
|
||||||
return &AMD64{
|
return &Arch{
|
||||||
goos: goos,
|
Name: "amd64",
|
||||||
|
ptrSize: 8,
|
||||||
|
maxInstructionLength: 15,
|
||||||
|
breakpointInstruction: amd64BreakInstruction,
|
||||||
|
breakInstrMovesPC: true,
|
||||||
|
derefTLS: goos == "windows",
|
||||||
|
prologues: prologuesAMD64,
|
||||||
|
fixFrameUnwindContext: amd64FixFrameUnwindContext,
|
||||||
|
switchStack: amd64SwitchStack,
|
||||||
|
regSize: amd64RegSize,
|
||||||
|
RegistersToDwarfRegisters: amd64RegistersToDwarfRegisters,
|
||||||
|
addrAndStackRegsToDwarfRegisters: amd64AddrAndStackRegsToDwarfRegisters,
|
||||||
|
DwarfRegisterToString: amd64DwarfRegisterToString,
|
||||||
|
inhibitStepInto: func(*BinaryInfo, uint64) bool { return false },
|
||||||
|
asmDecode: amd64AsmDecode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PtrSize returns the size of a pointer
|
func amd64FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryInfo) *frame.FrameContext {
|
||||||
// on this architecture.
|
a := bi.Arch
|
||||||
func (a *AMD64) PtrSize() int {
|
|
||||||
return 8
|
|
||||||
}
|
|
||||||
|
|
||||||
// MaxInstructionLength returns the maximum length of an instruction.
|
|
||||||
func (a *AMD64) MaxInstructionLength() int {
|
|
||||||
return 15
|
|
||||||
}
|
|
||||||
|
|
||||||
// BreakpointInstruction returns the Breakpoint
|
|
||||||
// instruction for this architecture.
|
|
||||||
func (a *AMD64) BreakpointInstruction() []byte {
|
|
||||||
return amd64BreakInstruction
|
|
||||||
}
|
|
||||||
|
|
||||||
// BreakInstrMovesPC returns whether the
|
|
||||||
// breakpoint instruction will change the value
|
|
||||||
// of PC after being executed
|
|
||||||
func (a *AMD64) BreakInstrMovesPC() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// BreakpointSize returns the size of the
|
|
||||||
// breakpoint instruction on this architecture.
|
|
||||||
func (a *AMD64) BreakpointSize() int {
|
|
||||||
return len(amd64BreakInstruction)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DerefTLS returns true if the value of regs.TLS()+GStructOffset() is a
|
|
||||||
// pointer to the G struct
|
|
||||||
func (a *AMD64) DerefTLS() bool {
|
|
||||||
return a.goos == "windows"
|
|
||||||
}
|
|
||||||
|
|
||||||
// FixFrameUnwindContext adds default architecture rules to fctxt or returns
|
|
||||||
// the default frame unwind context if fctxt is nil.
|
|
||||||
func (a *AMD64) FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryInfo) *frame.FrameContext {
|
|
||||||
if a.sigreturnfn == nil {
|
if a.sigreturnfn == nil {
|
||||||
a.sigreturnfn = bi.LookupFunc["runtime.sigreturn"]
|
a.sigreturnfn = bi.LookupFunc["runtime.sigreturn"]
|
||||||
}
|
}
|
||||||
@ -138,7 +98,7 @@ func (a *AMD64) FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *
|
|||||||
if a.crosscall2fn != nil && pc >= a.crosscall2fn.Entry && pc < a.crosscall2fn.End {
|
if a.crosscall2fn != nil && pc >= a.crosscall2fn.Entry && pc < a.crosscall2fn.End {
|
||||||
rule := fctxt.CFA
|
rule := fctxt.CFA
|
||||||
if rule.Offset == crosscall2SPOffsetBad {
|
if rule.Offset == crosscall2SPOffsetBad {
|
||||||
switch a.goos {
|
switch bi.GOOS {
|
||||||
case "windows":
|
case "windows":
|
||||||
rule.Offset += crosscall2SPOffsetWindows
|
rule.Offset += crosscall2SPOffsetWindows
|
||||||
default:
|
default:
|
||||||
@ -168,10 +128,7 @@ func (a *AMD64) FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *
|
|||||||
// switch happens.
|
// switch happens.
|
||||||
const amd64cgocallSPOffsetSaveSlot = 0x28
|
const amd64cgocallSPOffsetSaveSlot = 0x28
|
||||||
|
|
||||||
// SwitchStack will use the current frame to determine if it's time to
|
func amd64SwitchStack(it *stackIterator, _ *op.DwarfRegisters) bool {
|
||||||
// switch between the system stack and the goroutine stack or vice versa.
|
|
||||||
// Sets it.atend when the top of the stack is reached.
|
|
||||||
func (a *AMD64) SwitchStack(it *stackIterator, _ *op.DwarfRegisters) bool {
|
|
||||||
if it.frame.Current.Fn == nil {
|
if it.frame.Current.Fn == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -282,12 +239,12 @@ func (a *AMD64) SwitchStack(it *stackIterator, _ *op.DwarfRegisters) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegSize returns the size (in bytes) of register regnum.
|
// amd64RegSize returns the size (in bytes) of register regnum.
|
||||||
// The mapping between hardware registers and DWARF registers is specified
|
// The mapping between hardware registers and DWARF registers is specified
|
||||||
// in the System V ABI AMD64 Architecture Processor Supplement page 57,
|
// in the System V ABI AMD64 Architecture Processor Supplement page 57,
|
||||||
// figure 3.36
|
// figure 3.36
|
||||||
// https://www.uclibc.org/docs/psABI-x86_64.pdf
|
// https://www.uclibc.org/docs/psABI-x86_64.pdf
|
||||||
func (a *AMD64) RegSize(regnum uint64) int {
|
func amd64RegSize(regnum uint64) int {
|
||||||
// XMM registers
|
// XMM registers
|
||||||
if regnum > amd64DwarfIPRegNum && regnum <= 32 {
|
if regnum > amd64DwarfIPRegNum && regnum <= 32 {
|
||||||
return 16
|
return 16
|
||||||
@ -387,9 +344,7 @@ func maxAmd64DwarfRegister() int {
|
|||||||
return max
|
return max
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegistersToDwarfRegisters converts hardware registers to the format used
|
func amd64RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
|
||||||
// by the DWARF expression interpreter.
|
|
||||||
func (a *AMD64) RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
|
|
||||||
dregs := make([]*op.DwarfRegister, maxAmd64DwarfRegister()+1)
|
dregs := make([]*op.DwarfRegister, maxAmd64DwarfRegister()+1)
|
||||||
|
|
||||||
for _, reg := range regs.Slice(true) {
|
for _, reg := range regs.Slice(true) {
|
||||||
@ -408,9 +363,7 @@ func (a *AMD64) RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddrAndStackRegsToDwarfRegisters returns DWARF registers from the passed in
|
func amd64AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
|
||||||
// PC, SP, and BP registers in the format used by the DWARF expression interpreter.
|
|
||||||
func (a *AMD64) AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
|
|
||||||
dregs := make([]*op.DwarfRegister, amd64DwarfIPRegNum+1)
|
dregs := make([]*op.DwarfRegister, amd64DwarfIPRegNum+1)
|
||||||
dregs[amd64DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
|
dregs[amd64DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
|
||||||
dregs[amd64DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
|
dregs[amd64DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
|
||||||
@ -426,8 +379,7 @@ func (a *AMD64) AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DwarfRegisterToString returns the name and value representation of the given register.
|
func amd64DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
|
||||||
func (a *AMD64) DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
|
|
||||||
name, ok := amd64DwarfToName[i]
|
name, ok := amd64DwarfToName[i]
|
||||||
if !ok {
|
if !ok {
|
||||||
name = fmt.Sprintf("unknown%d", i)
|
name = fmt.Sprintf("unknown%d", i)
|
||||||
@ -559,9 +511,3 @@ func formatX87Reg(b []byte) string {
|
|||||||
|
|
||||||
return fmt.Sprintf("%#04x%016x\t%g", exponent, mantissa, f)
|
return fmt.Sprintf("%#04x%016x\t%g", exponent, mantissa, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InhibitStepInto returns whether StepBreakpoint can be set at pc.
|
|
||||||
// Always return false on amd64.
|
|
||||||
func (a *AMD64) InhibitStepInto(bi *BinaryInfo, pc uint64) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|||||||
@ -8,16 +8,10 @@ import (
|
|||||||
"golang.org/x/arch/x86/x86asm"
|
"golang.org/x/arch/x86/x86asm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AsmDecode decodes the assembly instruction starting at mem[0:] into asmInst.
|
func amd64AsmDecode(asmInst *AsmInstruction, mem []byte, regs Registers, memrw MemoryReadWriter, bi *BinaryInfo) error {
|
||||||
// It assumes that the Loc and AtPC fields of asmInst have already been filled.
|
|
||||||
func (a *AMD64) AsmDecode(asmInst *AsmInstruction, mem []byte, regs Registers, memrw MemoryReadWriter, bi *BinaryInfo) error {
|
|
||||||
return x86AsmDecode(asmInst, mem, regs, memrw, bi, 64)
|
return x86AsmDecode(asmInst, mem, regs, memrw, bi, 64)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AMD64) Prologues() []opcodeSeq {
|
|
||||||
return prologuesAMD64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Possible stacksplit prologues are inserted by stacksplit in
|
// Possible stacksplit prologues are inserted by stacksplit in
|
||||||
// $GOROOT/src/cmd/internal/obj/x86/obj6.go.
|
// $GOROOT/src/cmd/internal/obj/x86/obj6.go.
|
||||||
// The stacksplit prologue will always begin with loading curg in CX, this
|
// The stacksplit prologue will always begin with loading curg in CX, this
|
||||||
|
|||||||
110
pkg/proc/arch.go
110
pkg/proc/arch.go
@ -5,47 +5,87 @@ import (
|
|||||||
"github.com/go-delve/delve/pkg/dwarf/op"
|
"github.com/go-delve/delve/pkg/dwarf/op"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Arch defines an interface for representing a
|
// Arch represents a CPU architecture.
|
||||||
// CPU architecture.
|
type Arch struct {
|
||||||
type Arch interface {
|
Name string // architecture name
|
||||||
// PtrSize returns the size of a pointer for the architecture.
|
|
||||||
PtrSize() int
|
ptrSize int
|
||||||
// MaxInstructionLength is the maximum size in bytes of an instruction.
|
maxInstructionLength int
|
||||||
MaxInstructionLength() int
|
prologues []opcodeSeq
|
||||||
// AsmDecode decodes the assembly instruction starting at mem[0:] into asmInst.
|
breakpointInstruction []byte
|
||||||
|
breakInstrMovesPC bool
|
||||||
|
derefTLS bool
|
||||||
|
|
||||||
|
// asmDecode decodes the assembly instruction starting at mem[0:] into asmInst.
|
||||||
// It assumes that the Loc and AtPC fields of asmInst have already been filled.
|
// It assumes that the Loc and AtPC fields of asmInst have already been filled.
|
||||||
AsmDecode(asmInst *AsmInstruction, mem []byte, regs Registers, memrw MemoryReadWriter, bi *BinaryInfo) error
|
asmDecode func(asmInst *AsmInstruction, mem []byte, regs Registers, memrw MemoryReadWriter, bi *BinaryInfo) error
|
||||||
// Prologues returns a list of stack split prologues
|
// fixFrameUnwindContext applies architecture specific rules for unwinding a stack frame
|
||||||
// that are inserted at function entry.
|
|
||||||
Prologues() []opcodeSeq
|
|
||||||
// BreakpointInstruction is the instruction that will trigger a breakpoint trap for
|
|
||||||
// the given architecture.
|
|
||||||
BreakpointInstruction() []byte
|
|
||||||
// BreakInstrMovesPC is true if hitting the breakpoint instruction advances the
|
|
||||||
// instruction counter by the size of the breakpoint instruction.
|
|
||||||
BreakInstrMovesPC() bool
|
|
||||||
// BreakpointSize is the size of the breakpoint instruction for the given architecture.
|
|
||||||
BreakpointSize() int
|
|
||||||
// DerefTLS is true if the G struct stored in the TLS section is a pointer
|
|
||||||
// and the address must be dereferenced to find to actual G struct.
|
|
||||||
DerefTLS() bool
|
|
||||||
// FixFrameUnwindContext applies architecture specific rules for unwinding a stack frame
|
|
||||||
// on the given arch.
|
// on the given arch.
|
||||||
FixFrameUnwindContext(*frame.FrameContext, uint64, *BinaryInfo) *frame.FrameContext
|
fixFrameUnwindContext func(*frame.FrameContext, uint64, *BinaryInfo) *frame.FrameContext
|
||||||
// SwitchStack will use the current frame to determine if it's time to
|
// switchStack will use the current frame to determine if it's time to
|
||||||
// switch between the system stack and the goroutine stack or vice versa.
|
// switch between the system stack and the goroutine stack or vice versa.
|
||||||
SwitchStack(it *stackIterator, callFrameRegs *op.DwarfRegisters) bool
|
switchStack func(it *stackIterator, callFrameRegs *op.DwarfRegisters) bool
|
||||||
// RegSize returns the size (in bytes) of register regnum.
|
// regSize returns the size (in bytes) of register regnum.
|
||||||
RegSize(uint64) int
|
regSize func(uint64) int
|
||||||
// RegistersToDwarfRegisters maps hardware registers to DWARF registers.
|
// RegistersToDwarfRegisters maps hardware registers to DWARF registers.
|
||||||
RegistersToDwarfRegisters(uint64, Registers) op.DwarfRegisters
|
RegistersToDwarfRegisters func(uint64, Registers) op.DwarfRegisters
|
||||||
// AddrAndStackRegsToDwarfRegisters returns DWARF registers from the passed in
|
// addrAndStackRegsToDwarfRegisters returns DWARF registers from the passed in
|
||||||
// PC, SP, and BP registers in the format used by the DWARF expression interpreter.
|
// PC, SP, and BP registers in the format used by the DWARF expression interpreter.
|
||||||
AddrAndStackRegsToDwarfRegisters(uint64, uint64, uint64, uint64, uint64) op.DwarfRegisters
|
addrAndStackRegsToDwarfRegisters func(uint64, uint64, uint64, uint64, uint64) op.DwarfRegisters
|
||||||
// DwarfRegisterToString returns the name and value representation of the given register.
|
// DwarfRegisterToString returns the name and value representation of the given register.
|
||||||
DwarfRegisterToString(int, *op.DwarfRegister) (string, bool, string)
|
DwarfRegisterToString func(int, *op.DwarfRegister) (string, bool, string)
|
||||||
// InhibitStepInto returns whether StepBreakpoint can be set at pc.
|
// inhibitStepInto returns whether StepBreakpoint can be set at pc.
|
||||||
InhibitStepInto(bi *BinaryInfo, pc uint64) bool
|
inhibitStepInto func(bi *BinaryInfo, pc uint64) bool
|
||||||
|
|
||||||
|
// crosscall2fn is the DIE of crosscall2, a function used by the go runtime
|
||||||
|
// to call C functions. This function in go 1.9 (and previous versions) had
|
||||||
|
// a bad frame descriptor which needs to be fixed to generate good stack
|
||||||
|
// traces.
|
||||||
|
crosscall2fn *Function
|
||||||
|
|
||||||
|
// sigreturnfn is the DIE of runtime.sigreturn, the return trampoline for
|
||||||
|
// the signal handler. See comment in FixFrameUnwindContext for a
|
||||||
|
// description of why this is needed.
|
||||||
|
sigreturnfn *Function
|
||||||
|
}
|
||||||
|
|
||||||
|
// PtrSize returns the size of a pointer for the architecture.
|
||||||
|
func (a *Arch) PtrSize() int {
|
||||||
|
return a.ptrSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaxInstructionLength is the maximum size in bytes of an instruction.
|
||||||
|
func (a *Arch) MaxInstructionLength() int {
|
||||||
|
return a.maxInstructionLength
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prologues returns a list of stack split prologues
|
||||||
|
// that are inserted at function entry.
|
||||||
|
func (a *Arch) Prologues() []opcodeSeq {
|
||||||
|
return a.prologues
|
||||||
|
}
|
||||||
|
|
||||||
|
// BreakpointInstruction is the instruction that will trigger a breakpoint trap for
|
||||||
|
// the given architecture.
|
||||||
|
func (a *Arch) BreakpointInstruction() []byte {
|
||||||
|
return a.breakpointInstruction
|
||||||
|
}
|
||||||
|
|
||||||
|
// BreakInstrMovesPC is true if hitting the breakpoint instruction advances the
|
||||||
|
// instruction counter by the size of the breakpoint instruction.
|
||||||
|
func (a *Arch) BreakInstrMovesPC() bool {
|
||||||
|
return a.breakInstrMovesPC
|
||||||
|
}
|
||||||
|
|
||||||
|
// BreakpointSize is the size of the breakpoint instruction for the given architecture.
|
||||||
|
func (a *Arch) BreakpointSize() int {
|
||||||
|
return len(a.breakpointInstruction)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DerefTLS is true if the G struct stored in the TLS section is a pointer
|
||||||
|
// and the address must be dereferenced to find to actual G struct.
|
||||||
|
func (a *Arch) DerefTLS() bool {
|
||||||
|
return a.derefTLS
|
||||||
}
|
}
|
||||||
|
|
||||||
// crosscall2 is defined in $GOROOT/src/runtime/cgo/asm_amd64.s.
|
// crosscall2 is defined in $GOROOT/src/runtime/cgo/asm_amd64.s.
|
||||||
|
|||||||
@ -12,23 +12,6 @@ import (
|
|||||||
"golang.org/x/arch/arm64/arm64asm"
|
"golang.org/x/arch/arm64/arm64asm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ARM64 represents the ARM64 CPU architecture.
|
|
||||||
type ARM64 struct {
|
|
||||||
gStructOffset uint64
|
|
||||||
goos string
|
|
||||||
|
|
||||||
// crosscall2fn is the DIE of crosscall2, a function used by the go runtime
|
|
||||||
// to call C functions. This function in go 1.9 (and previous versions) had
|
|
||||||
// a bad frame descriptor which needs to be fixed to generate good stack
|
|
||||||
// traces.
|
|
||||||
crosscall2fn *Function
|
|
||||||
|
|
||||||
// sigreturnfn is the DIE of runtime.sigreturn, the return trampoline for
|
|
||||||
// the signal handler. See comment in FixFrameUnwindContext for a
|
|
||||||
// description of why this is needed.
|
|
||||||
sigreturnfn *Function
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
arm64DwarfIPRegNum uint64 = 32
|
arm64DwarfIPRegNum uint64 = 32
|
||||||
arm64DwarfSPRegNum uint64 = 31
|
arm64DwarfSPRegNum uint64 = 31
|
||||||
@ -40,50 +23,28 @@ var arm64BreakInstruction = []byte{0x0, 0x0, 0x20, 0xd4}
|
|||||||
|
|
||||||
// ARM64Arch returns an initialized ARM64
|
// ARM64Arch returns an initialized ARM64
|
||||||
// struct.
|
// struct.
|
||||||
func ARM64Arch(goos string) *ARM64 {
|
func ARM64Arch(goos string) *Arch {
|
||||||
return &ARM64{
|
return &Arch{
|
||||||
goos: goos,
|
Name: "arm64",
|
||||||
|
ptrSize: 8,
|
||||||
|
maxInstructionLength: 4,
|
||||||
|
breakpointInstruction: arm64BreakInstruction,
|
||||||
|
breakInstrMovesPC: false,
|
||||||
|
derefTLS: false,
|
||||||
|
prologues: prologuesARM64,
|
||||||
|
fixFrameUnwindContext: arm64FixFrameUnwindContext,
|
||||||
|
switchStack: arm64SwitchStack,
|
||||||
|
regSize: arm64RegSize,
|
||||||
|
RegistersToDwarfRegisters: arm64RegistersToDwarfRegisters,
|
||||||
|
addrAndStackRegsToDwarfRegisters: arm64AddrAndStackRegsToDwarfRegisters,
|
||||||
|
DwarfRegisterToString: arm64DwarfRegisterToString,
|
||||||
|
inhibitStepInto: func(*BinaryInfo, uint64) bool { return false },
|
||||||
|
asmDecode: arm64AsmDecode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PtrSize returns the size of a pointer
|
func arm64FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryInfo) *frame.FrameContext {
|
||||||
// on this architecture.
|
a := bi.Arch
|
||||||
func (a *ARM64) PtrSize() int {
|
|
||||||
return 8
|
|
||||||
}
|
|
||||||
|
|
||||||
// MaxInstructionLength returns the maximum length of an instruction.
|
|
||||||
func (a *ARM64) MaxInstructionLength() int {
|
|
||||||
return 4
|
|
||||||
}
|
|
||||||
|
|
||||||
// BreakpointInstruction returns the Breakpoint
|
|
||||||
// instruction for this architecture.
|
|
||||||
func (a *ARM64) BreakpointInstruction() []byte {
|
|
||||||
return arm64BreakInstruction
|
|
||||||
}
|
|
||||||
|
|
||||||
// BreakInstrMovesPC returns whether the
|
|
||||||
// breakpoint instruction will change the value
|
|
||||||
// of PC after being executed
|
|
||||||
func (a *ARM64) BreakInstrMovesPC() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// BreakpointSize returns the size of the
|
|
||||||
// breakpoint instruction on this architecture.
|
|
||||||
func (a *ARM64) BreakpointSize() int {
|
|
||||||
return len(arm64BreakInstruction)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always return false for now.
|
|
||||||
func (a *ARM64) DerefTLS() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// FixFrameUnwindContext adds default architecture rules to fctxt or returns
|
|
||||||
// the default frame unwind context if fctxt is nil.
|
|
||||||
func (a *ARM64) FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryInfo) *frame.FrameContext {
|
|
||||||
if a.sigreturnfn == nil {
|
if a.sigreturnfn == nil {
|
||||||
a.sigreturnfn = bi.LookupFunc["runtime.sigreturn"]
|
a.sigreturnfn = bi.LookupFunc["runtime.sigreturn"]
|
||||||
}
|
}
|
||||||
@ -138,7 +99,7 @@ func (a *ARM64) FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *
|
|||||||
if a.crosscall2fn != nil && pc >= a.crosscall2fn.Entry && pc < a.crosscall2fn.End {
|
if a.crosscall2fn != nil && pc >= a.crosscall2fn.Entry && pc < a.crosscall2fn.End {
|
||||||
rule := fctxt.CFA
|
rule := fctxt.CFA
|
||||||
if rule.Offset == crosscall2SPOffsetBad {
|
if rule.Offset == crosscall2SPOffsetBad {
|
||||||
switch a.goos {
|
switch bi.GOOS {
|
||||||
case "windows":
|
case "windows":
|
||||||
rule.Offset += crosscall2SPOffsetWindows
|
rule.Offset += crosscall2SPOffsetWindows
|
||||||
default:
|
default:
|
||||||
@ -174,7 +135,7 @@ const arm64cgocallSPOffsetSaveSlot = 0x8
|
|||||||
const prevG0schedSPOffsetSaveSlot = 0x10
|
const prevG0schedSPOffsetSaveSlot = 0x10
|
||||||
const spAlign = 16
|
const spAlign = 16
|
||||||
|
|
||||||
func (a *ARM64) SwitchStack(it *stackIterator, callFrameRegs *op.DwarfRegisters) bool {
|
func arm64SwitchStack(it *stackIterator, callFrameRegs *op.DwarfRegisters) bool {
|
||||||
if it.frame.Current.Fn != nil {
|
if it.frame.Current.Fn != nil {
|
||||||
switch it.frame.Current.Fn.Name {
|
switch it.frame.Current.Fn.Name {
|
||||||
case "runtime.asmcgocall", "runtime.cgocallback_gofunc", "runtime.sigpanic":
|
case "runtime.asmcgocall", "runtime.cgocallback_gofunc", "runtime.sigpanic":
|
||||||
@ -270,7 +231,7 @@ func (a *ARM64) SwitchStack(it *stackIterator, callFrameRegs *op.DwarfRegisters)
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ARM64) RegSize(regnum uint64) int {
|
func arm64RegSize(regnum uint64) int {
|
||||||
// fp registers
|
// fp registers
|
||||||
if regnum >= 64 && regnum <= 95 {
|
if regnum >= 64 && regnum <= 95 {
|
||||||
return 16
|
return 16
|
||||||
@ -361,9 +322,7 @@ func maxArm64DwarfRegister() int {
|
|||||||
return max
|
return max
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegistersToDwarfRegisters converts hardware registers to the format used
|
func arm64RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
|
||||||
// by the DWARF expression interpreter.
|
|
||||||
func (a *ARM64) RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
|
|
||||||
dregs := make([]*op.DwarfRegister, maxArm64DwarfRegister()+1)
|
dregs := make([]*op.DwarfRegister, maxArm64DwarfRegister()+1)
|
||||||
|
|
||||||
dregs[arm64DwarfIPRegNum] = op.DwarfRegisterFromUint64(regs.PC())
|
dregs[arm64DwarfIPRegNum] = op.DwarfRegisterFromUint64(regs.PC())
|
||||||
@ -391,9 +350,7 @@ func (a *ARM64) RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddrAndStackRegsToDwarfRegisters returns DWARF registers from the passed in
|
func arm64AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
|
||||||
// PC, SP, and BP registers in the format used by the DWARF expression interpreter.
|
|
||||||
func (a *ARM64) AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
|
|
||||||
dregs := make([]*op.DwarfRegister, arm64DwarfIPRegNum+1)
|
dregs := make([]*op.DwarfRegister, arm64DwarfIPRegNum+1)
|
||||||
dregs[arm64DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
|
dregs[arm64DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
|
||||||
dregs[arm64DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
|
dregs[arm64DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
|
||||||
@ -411,7 +368,7 @@ func (a *ARM64) AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ARM64) DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
|
func arm64DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
|
||||||
// see arm64DwarfToHardware table for explanation
|
// see arm64DwarfToHardware table for explanation
|
||||||
switch {
|
switch {
|
||||||
case i <= 30:
|
case i <= 30:
|
||||||
@ -465,9 +422,3 @@ func (a *ARM64) DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string
|
|||||||
}
|
}
|
||||||
return name, false, fmt.Sprintf("%#x", reg.Bytes)
|
return name, false, fmt.Sprintf("%#x", reg.Bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InhibitStepInto returns whether StepBreakpoint can be set at pc.
|
|
||||||
// Always return false on arm64.
|
|
||||||
func (a *ARM64) InhibitStepInto(bi *BinaryInfo, pc uint64) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|||||||
@ -8,9 +8,7 @@ import (
|
|||||||
"golang.org/x/arch/arm64/arm64asm"
|
"golang.org/x/arch/arm64/arm64asm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AsmDecode decodes the assembly instruction starting at mem[0:] into asmInst.
|
func arm64AsmDecode(asmInst *AsmInstruction, mem []byte, regs Registers, memrw MemoryReadWriter, bi *BinaryInfo) error {
|
||||||
// It assumes that the Loc and AtPC fields of asmInst have already been filled.
|
|
||||||
func (a *ARM64) AsmDecode(asmInst *AsmInstruction, mem []byte, regs Registers, memrw MemoryReadWriter, bi *BinaryInfo) error {
|
|
||||||
asmInst.Size = 4
|
asmInst.Size = 4
|
||||||
asmInst.Bytes = mem[:asmInst.Size]
|
asmInst.Bytes = mem[:asmInst.Size]
|
||||||
|
|
||||||
@ -35,10 +33,6 @@ func (a *ARM64) AsmDecode(asmInst *AsmInstruction, mem []byte, regs Registers, m
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ARM64) Prologues() []opcodeSeq {
|
|
||||||
return prologuesARM64
|
|
||||||
}
|
|
||||||
|
|
||||||
func resolveCallArgARM64(inst *arm64asm.Inst, instAddr uint64, currentGoroutine bool, regs Registers, mem MemoryReadWriter, bininfo *BinaryInfo) *Location {
|
func resolveCallArgARM64(inst *arm64asm.Inst, instAddr uint64, currentGoroutine bool, regs Registers, mem MemoryReadWriter, bininfo *BinaryInfo) *Location {
|
||||||
if inst.Op != arm64asm.BL && inst.Op != arm64asm.BLR {
|
if inst.Op != arm64asm.BL && inst.Op != arm64asm.BLR {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -43,7 +43,7 @@ const (
|
|||||||
// includes both the executable and also any loaded libraries).
|
// includes both the executable and also any loaded libraries).
|
||||||
type BinaryInfo struct {
|
type BinaryInfo struct {
|
||||||
// Architecture of this binary.
|
// Architecture of this binary.
|
||||||
Arch Arch
|
Arch *Arch
|
||||||
|
|
||||||
// GOOS operating system this binary is executing on.
|
// GOOS operating system this binary is executing on.
|
||||||
GOOS string
|
GOOS string
|
||||||
|
|||||||
@ -313,11 +313,6 @@ func (t *Thread) RestoreRegisters(proc.Registers) error {
|
|||||||
return ErrChangeRegisterCore
|
return ErrChangeRegisterCore
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arch returns the architecture the target is built for and executing on.
|
|
||||||
func (t *Thread) Arch() proc.Arch {
|
|
||||||
return t.p.bi.Arch
|
|
||||||
}
|
|
||||||
|
|
||||||
// BinInfo returns information about the binary.
|
// BinInfo returns information about the binary.
|
||||||
func (t *Thread) BinInfo() *proc.BinaryInfo {
|
func (t *Thread) BinInfo() *proc.BinaryInfo {
|
||||||
return t.p.bi
|
return t.p.bi
|
||||||
|
|||||||
@ -185,7 +185,7 @@ func withCoreFile(t *testing.T, name, args string) *proc.Target {
|
|||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func logRegisters(t *testing.T, regs proc.Registers, arch proc.Arch) {
|
func logRegisters(t *testing.T, regs proc.Registers, arch *proc.Arch) {
|
||||||
dregs := arch.RegistersToDwarfRegisters(0, regs)
|
dregs := arch.RegistersToDwarfRegisters(0, regs)
|
||||||
for i, reg := range dregs.Regs {
|
for i, reg := range dregs.Regs {
|
||||||
if reg == nil {
|
if reg == nil {
|
||||||
|
|||||||
@ -139,7 +139,7 @@ func disassemble(memrw MemoryReadWriter, regs Registers, breakpoints *Breakpoint
|
|||||||
inst.Breakpoint = atbp
|
inst.Breakpoint = atbp
|
||||||
inst.AtPC = (regs != nil) && (curpc == pc)
|
inst.AtPC = (regs != nil) && (curpc == pc)
|
||||||
|
|
||||||
bi.Arch.AsmDecode(&inst, mem, regs, memrw, bi)
|
bi.Arch.asmDecode(&inst, mem, regs, memrw, bi)
|
||||||
|
|
||||||
r = append(r, inst)
|
r = append(r, inst)
|
||||||
|
|
||||||
|
|||||||
@ -1303,11 +1303,6 @@ func (t *Thread) RestoreRegisters(savedRegs proc.Registers) error {
|
|||||||
return t.writeRegisters()
|
return t.writeRegisters()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arch will return the CPU architecture for the target.
|
|
||||||
func (t *Thread) Arch() proc.Arch {
|
|
||||||
return t.p.bi.Arch
|
|
||||||
}
|
|
||||||
|
|
||||||
// BinInfo will return information on the binary being debugged.
|
// BinInfo will return information on the binary being debugged.
|
||||||
func (t *Thread) BinInfo() *proc.BinaryInfo {
|
func (t *Thread) BinInfo() *proc.BinaryInfo {
|
||||||
return t.p.bi
|
return t.p.bi
|
||||||
|
|||||||
@ -8,23 +8,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// I386 represents the Intel386 CPU architecture.
|
|
||||||
type I386 struct {
|
|
||||||
gStructOffset uint64
|
|
||||||
goos string
|
|
||||||
|
|
||||||
// crosscall2fn is the DIE of crosscall2, a function used by the go runtime
|
|
||||||
// to call C functions. This function in go 1.9 (and previous versions) had
|
|
||||||
// a bad frame descriptor which needs to be fixed to generate good stack
|
|
||||||
// traces.
|
|
||||||
crosscall2fn *Function
|
|
||||||
|
|
||||||
// sigreturnfn is the DIE of runtime.sigreturn, the return trampoline for
|
|
||||||
// the signal handler. See comment in FixFrameUnwindContext for a
|
|
||||||
// description of why this is needed.
|
|
||||||
sigreturnfn *Function
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
i386DwarfIPRegNum uint64 = 8
|
i386DwarfIPRegNum uint64 = 8
|
||||||
i386DwarfSPRegNum uint64 = 4
|
i386DwarfSPRegNum uint64 = 4
|
||||||
@ -35,50 +18,28 @@ var i386BreakInstruction = []byte{0xCC}
|
|||||||
|
|
||||||
// I386Arch returns an initialized I386Arch
|
// I386Arch returns an initialized I386Arch
|
||||||
// struct.
|
// struct.
|
||||||
func I386Arch(goos string) *I386 {
|
func I386Arch(goos string) *Arch {
|
||||||
return &I386{
|
return &Arch{
|
||||||
goos: goos,
|
Name: "386",
|
||||||
|
ptrSize: 4,
|
||||||
|
maxInstructionLength: 15,
|
||||||
|
breakpointInstruction: i386BreakInstruction,
|
||||||
|
breakInstrMovesPC: true,
|
||||||
|
derefTLS: false,
|
||||||
|
prologues: prologuesI386,
|
||||||
|
fixFrameUnwindContext: i386FixFrameUnwindContext,
|
||||||
|
switchStack: i386SwitchStack,
|
||||||
|
regSize: i386RegSize,
|
||||||
|
RegistersToDwarfRegisters: i386RegistersToDwarfRegisters,
|
||||||
|
addrAndStackRegsToDwarfRegisters: i386AddrAndStackRegsToDwarfRegisters,
|
||||||
|
DwarfRegisterToString: i386DwarfRegisterToString,
|
||||||
|
inhibitStepInto: i386InhibitStepInto,
|
||||||
|
asmDecode: i386AsmDecode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PtrSize returns the size of a pointer
|
func i386FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryInfo) *frame.FrameContext {
|
||||||
// on this architecture.
|
i := bi.Arch
|
||||||
func (i *I386) PtrSize() int {
|
|
||||||
return 4
|
|
||||||
}
|
|
||||||
|
|
||||||
// MaxInstructionLength returns the maximum length of an instruction.
|
|
||||||
func (i *I386) MaxInstructionLength() int {
|
|
||||||
return 15
|
|
||||||
}
|
|
||||||
|
|
||||||
// BreakpointInstruction returns the Breakpoint
|
|
||||||
// instruction for this architecture.
|
|
||||||
func (i *I386) BreakpointInstruction() []byte {
|
|
||||||
return i386BreakInstruction
|
|
||||||
}
|
|
||||||
|
|
||||||
// BreakInstrMovesPC returns whether the
|
|
||||||
// breakpoint instruction will change the value
|
|
||||||
// of PC after being executed
|
|
||||||
func (i *I386) BreakInstrMovesPC() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// BreakpointSize returns the size of the
|
|
||||||
// breakpoint instruction on this architecture.
|
|
||||||
func (i *I386) BreakpointSize() int {
|
|
||||||
return len(i386BreakInstruction)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO, Not sure, always return false for now. Need to test on windows.
|
|
||||||
func (i *I386) DerefTLS() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// FixFrameUnwindContext adds default architecture rules to fctxt or returns
|
|
||||||
// the default frame unwind context if fctxt is nil.
|
|
||||||
func (i *I386) FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryInfo) *frame.FrameContext {
|
|
||||||
if i.sigreturnfn == nil {
|
if i.sigreturnfn == nil {
|
||||||
i.sigreturnfn = bi.LookupFunc["runtime.sigreturn"]
|
i.sigreturnfn = bi.LookupFunc["runtime.sigreturn"]
|
||||||
}
|
}
|
||||||
@ -153,9 +114,7 @@ func (i *I386) FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *B
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SwitchStack will use the current frame to determine if it's time to
|
// SwitchStack will use the current frame to determine if it's time to
|
||||||
// switch between the system stack and the goroutine stack or vice versa.
|
func i386SwitchStack(it *stackIterator, _ *op.DwarfRegisters) bool {
|
||||||
// Sets it.atend when the top of the stack is reached.
|
|
||||||
func (i *I386) SwitchStack(it *stackIterator, _ *op.DwarfRegisters) bool {
|
|
||||||
if it.frame.Current.Fn == nil {
|
if it.frame.Current.Fn == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -214,7 +173,7 @@ func (i *I386) SwitchStack(it *stackIterator, _ *op.DwarfRegisters) bool {
|
|||||||
// in the System V ABI Intel386 Architecture Processor Supplement page 25,
|
// in the System V ABI Intel386 Architecture Processor Supplement page 25,
|
||||||
// table 2.14
|
// table 2.14
|
||||||
// https://www.uclibc.org/docs/psABI-i386.pdf
|
// https://www.uclibc.org/docs/psABI-i386.pdf
|
||||||
func (i *I386) RegSize(regnum uint64) int {
|
func i386RegSize(regnum uint64) int {
|
||||||
// XMM registers
|
// XMM registers
|
||||||
if regnum >= 21 && regnum <= 36 {
|
if regnum >= 21 && regnum <= 36 {
|
||||||
return 16
|
return 16
|
||||||
@ -293,7 +252,7 @@ func maxI386DwarfRegister() int {
|
|||||||
return max
|
return max
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *I386) RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
|
func i386RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
|
||||||
dregs := make([]*op.DwarfRegister, maxI386DwarfRegister()+1)
|
dregs := make([]*op.DwarfRegister, maxI386DwarfRegister()+1)
|
||||||
|
|
||||||
for _, reg := range regs.Slice(true) {
|
for _, reg := range regs.Slice(true) {
|
||||||
@ -312,9 +271,7 @@ func (i *I386) RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.D
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddrAndStackRegsToDwarfRegisters returns DWARF registers from the passed in
|
func i386AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
|
||||||
// PC, SP, and BP registers in the format used by the DWARF expression interpreter.
|
|
||||||
func (i *I386) AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
|
|
||||||
dregs := make([]*op.DwarfRegister, i386DwarfIPRegNum+1)
|
dregs := make([]*op.DwarfRegister, i386DwarfIPRegNum+1)
|
||||||
dregs[i386DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
|
dregs[i386DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
|
||||||
dregs[i386DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
|
dregs[i386DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
|
||||||
@ -330,7 +287,7 @@ func (i *I386) AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint6
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *I386) DwarfRegisterToString(j int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
|
func i386DwarfRegisterToString(j int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
|
||||||
name, ok := i386DwarfToName[j]
|
name, ok := i386DwarfToName[j]
|
||||||
if !ok {
|
if !ok {
|
||||||
name = fmt.Sprintf("unknown%d", j)
|
name = fmt.Sprintf("unknown%d", j)
|
||||||
@ -356,11 +313,11 @@ func (i *I386) DwarfRegisterToString(j int, reg *op.DwarfRegister) (name string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InhibitStepInto returns whether StepBreakpoint can be set at pc.
|
// i386InhibitStepInto returns whether StepBreakpoint can be set at pc.
|
||||||
// When cgo or pie on 386 linux, compiler will insert more instructions (ex: call __x86.get_pc_thunk.).
|
// When cgo or pie on 386 linux, compiler will insert more instructions (ex: call __x86.get_pc_thunk.).
|
||||||
// StepBreakpoint shouldn't be set on __x86.get_pc_thunk and skip it.
|
// StepBreakpoint shouldn't be set on __x86.get_pc_thunk and skip it.
|
||||||
// See comments on stacksplit in $GOROOT/src/cmd/internal/obj/x86/obj6.go for generated instructions details.
|
// See comments on stacksplit in $GOROOT/src/cmd/internal/obj/x86/obj6.go for generated instructions details.
|
||||||
func (i *I386) InhibitStepInto(bi *BinaryInfo, pc uint64) bool {
|
func i386InhibitStepInto(bi *BinaryInfo, pc uint64) bool {
|
||||||
if bi.SymNames != nil && bi.SymNames[pc] != nil &&
|
if bi.SymNames != nil && bi.SymNames[pc] != nil &&
|
||||||
strings.HasPrefix(bi.SymNames[pc].Name, "__x86.get_pc_thunk.") {
|
strings.HasPrefix(bi.SymNames[pc].Name, "__x86.get_pc_thunk.") {
|
||||||
return true
|
return true
|
||||||
|
|||||||
@ -8,18 +8,10 @@ import (
|
|||||||
"golang.org/x/arch/x86/x86asm"
|
"golang.org/x/arch/x86/x86asm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AsmDecode decodes the assembly instruction starting at mem[0:] into asmInst.
|
func i386AsmDecode(asmInst *AsmInstruction, mem []byte, regs Registers, memrw MemoryReadWriter, bi *BinaryInfo) error {
|
||||||
// It assumes that the Loc and AtPC fields of asmInst have already been filled.
|
|
||||||
func (i *I386) AsmDecode(asmInst *AsmInstruction, mem []byte, regs Registers, memrw MemoryReadWriter, bi *BinaryInfo) error {
|
|
||||||
return x86AsmDecode(asmInst, mem, regs, memrw, bi, 32)
|
return x86AsmDecode(asmInst, mem, regs, memrw, bi, 32)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prologues returns a list of stack split prologues
|
|
||||||
// that are inserted at function entry.
|
|
||||||
func (i *I386) Prologues() []opcodeSeq {
|
|
||||||
return prologuesI386
|
|
||||||
}
|
|
||||||
|
|
||||||
// Possible stacksplit prologues are inserted by stacksplit in
|
// Possible stacksplit prologues are inserted by stacksplit in
|
||||||
// $GOROOT/src/cmd/internal/obj/x86/obj6.go.
|
// $GOROOT/src/cmd/internal/obj/x86/obj6.go.
|
||||||
// If 386 on linux when pie, the stacksplit prologue beigin with `call __x86.get_pc_thunk.` sometime.
|
// If 386 on linux when pie, the stacksplit prologue beigin with `call __x86.get_pc_thunk.` sometime.
|
||||||
|
|||||||
@ -94,12 +94,6 @@ func (t *Thread) Location() (*proc.Location, error) {
|
|||||||
return &proc.Location{PC: pc, File: f, Line: l, Fn: fn}, nil
|
return &proc.Location{PC: pc, File: f, Line: l, Fn: fn}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arch returns the architecture the binary is
|
|
||||||
// compiled for and executing on.
|
|
||||||
func (t *Thread) Arch() proc.Arch {
|
|
||||||
return t.dbp.bi.Arch
|
|
||||||
}
|
|
||||||
|
|
||||||
// BinInfo returns information on the binary.
|
// BinInfo returns information on the binary.
|
||||||
func (t *Thread) BinInfo() *proc.BinaryInfo {
|
func (t *Thread) BinInfo() *proc.BinaryInfo {
|
||||||
return t.dbp.bi
|
return t.dbp.bi
|
||||||
@ -124,7 +118,7 @@ func (t *Thread) SetCurrentBreakpoint(adjustPC bool) error {
|
|||||||
// of PC after being executed we should look for breakpoints
|
// of PC after being executed we should look for breakpoints
|
||||||
// with bp.Addr == PC and there is no need to call SetPC
|
// with bp.Addr == PC and there is no need to call SetPC
|
||||||
// after finding one.
|
// after finding one.
|
||||||
adjustPC = adjustPC && t.Arch().BreakInstrMovesPC()
|
adjustPC = adjustPC && t.BinInfo().Arch.BreakInstrMovesPC()
|
||||||
|
|
||||||
if bp, ok := t.dbp.FindBreakpoint(pc, adjustPC); ok {
|
if bp, ok := t.dbp.FindBreakpoint(pc, adjustPC); ok {
|
||||||
if adjustPC {
|
if adjustPC {
|
||||||
|
|||||||
@ -127,7 +127,7 @@ func (g *G) stackIterator(opts StacktraceOptions) (*stackIterator, error) {
|
|||||||
so := g.variable.bi.PCToImage(g.PC)
|
so := g.variable.bi.PCToImage(g.PC)
|
||||||
return newStackIterator(
|
return newStackIterator(
|
||||||
bi, g.variable.mem,
|
bi, g.variable.mem,
|
||||||
bi.Arch.AddrAndStackRegsToDwarfRegisters(so.StaticBase, g.PC, g.SP, g.BP, g.LR),
|
bi.Arch.addrAndStackRegsToDwarfRegisters(so.StaticBase, g.PC, g.SP, g.BP, g.LR),
|
||||||
g.stackhi, stkbar, g.stkbarPos, g, opts), nil
|
g.stackhi, stkbar, g.stkbarPos, g, opts), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,7 +246,7 @@ func (it *stackIterator) Next() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if it.opts&StacktraceSimple == 0 {
|
if it.opts&StacktraceSimple == 0 {
|
||||||
if it.bi.Arch.SwitchStack(it, &callFrameRegs) {
|
if it.bi.Arch.switchStack(it, &callFrameRegs) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -268,7 +268,7 @@ func (it *stackIterator) switchToGoroutineStack() {
|
|||||||
it.pc = it.g.PC
|
it.pc = it.g.PC
|
||||||
it.regs.Reg(it.regs.SPRegNum).Uint64Val = it.g.SP
|
it.regs.Reg(it.regs.SPRegNum).Uint64Val = it.g.SP
|
||||||
it.regs.AddReg(it.regs.BPRegNum, op.DwarfRegisterFromUint64(it.g.BP))
|
it.regs.AddReg(it.regs.BPRegNum, op.DwarfRegisterFromUint64(it.g.BP))
|
||||||
if _, ok := it.bi.Arch.(*ARM64); ok {
|
if it.bi.Arch.Name == "arm64" {
|
||||||
it.regs.Reg(it.regs.LRRegNum).Uint64Val = it.g.LR
|
it.regs.Reg(it.regs.LRRegNum).Uint64Val = it.g.LR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -414,9 +414,9 @@ func (it *stackIterator) advanceRegs() (callFrameRegs op.DwarfRegisters, ret uin
|
|||||||
fde, err := it.bi.frameEntries.FDEForPC(it.pc)
|
fde, err := it.bi.frameEntries.FDEForPC(it.pc)
|
||||||
var framectx *frame.FrameContext
|
var framectx *frame.FrameContext
|
||||||
if _, nofde := err.(*frame.ErrNoFDEForPC); nofde {
|
if _, nofde := err.(*frame.ErrNoFDEForPC); nofde {
|
||||||
framectx = it.bi.Arch.FixFrameUnwindContext(nil, it.pc, it.bi)
|
framectx = it.bi.Arch.fixFrameUnwindContext(nil, it.pc, it.bi)
|
||||||
} else {
|
} else {
|
||||||
framectx = it.bi.Arch.FixFrameUnwindContext(fde.EstablishFrame(it.pc), it.pc, it.bi)
|
framectx = it.bi.Arch.fixFrameUnwindContext(fde.EstablishFrame(it.pc), it.pc, it.bi)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfareg, err := it.executeFrameRegRule(0, framectx.CFA, 0)
|
cfareg, err := it.executeFrameRegRule(0, framectx.CFA, 0)
|
||||||
@ -455,7 +455,7 @@ func (it *stackIterator) advanceRegs() (callFrameRegs op.DwarfRegisters, ret uin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := it.bi.Arch.(*ARM64); ok {
|
if it.bi.Arch.Name == "arm64" {
|
||||||
if ret == 0 && it.regs.Regs[it.regs.LRRegNum] != nil {
|
if ret == 0 && it.regs.Regs[it.regs.LRRegNum] != nil {
|
||||||
ret = it.regs.Regs[it.regs.LRRegNum].Uint64Val
|
ret = it.regs.Regs[it.regs.LRRegNum].Uint64Val
|
||||||
}
|
}
|
||||||
@ -515,7 +515,7 @@ func (it *stackIterator) executeFrameRegRule(regnum uint64, rule frame.DWRule, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (it *stackIterator) readRegisterAt(regnum uint64, addr uint64) (*op.DwarfRegister, error) {
|
func (it *stackIterator) readRegisterAt(regnum uint64, addr uint64) (*op.DwarfRegister, error) {
|
||||||
buf := make([]byte, it.bi.Arch.RegSize(regnum))
|
buf := make([]byte, it.bi.Arch.regSize(regnum))
|
||||||
_, err := it.mem.ReadMemory(buf, uintptr(addr))
|
_, err := it.mem.ReadMemory(buf, uintptr(addr))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@ -152,8 +152,7 @@ func (t *Target) SupportsFunctionCalls() bool {
|
|||||||
if ok, _ := t.Process.Recorded(); ok {
|
if ok, _ := t.Process.Recorded(); ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
_, ok := t.Process.BinInfo().Arch.(*AMD64)
|
return t.Process.BinInfo().Arch.Name == "amd64"
|
||||||
return ok
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearAllGCache clears the internal Goroutine cache.
|
// ClearAllGCache clears the internal Goroutine cache.
|
||||||
|
|||||||
@ -770,7 +770,7 @@ func setStepIntoBreakpoint(dbp Process, text []AsmInstruction, cond ast.Expr) er
|
|||||||
pc := instr.DestLoc.PC
|
pc := instr.DestLoc.PC
|
||||||
|
|
||||||
// Skip InhibitStepInto functions for different arch.
|
// Skip InhibitStepInto functions for different arch.
|
||||||
if dbp.BinInfo().Arch.InhibitStepInto(dbp.BinInfo(), pc) {
|
if dbp.BinInfo().Arch.inhibitStepInto(dbp.BinInfo(), pc) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,6 @@ type Thread interface {
|
|||||||
|
|
||||||
// RestoreRegisters restores saved registers
|
// RestoreRegisters restores saved registers
|
||||||
RestoreRegisters(Registers) error
|
RestoreRegisters(Registers) error
|
||||||
Arch() Arch
|
|
||||||
BinInfo() *BinaryInfo
|
BinInfo() *BinaryInfo
|
||||||
StepInstruction() error
|
StepInstruction() error
|
||||||
// Blocked returns true if the thread is blocked
|
// Blocked returns true if the thread is blocked
|
||||||
|
|||||||
@ -46,7 +46,7 @@ type runtimeTypeDIE struct {
|
|||||||
kind int64
|
kind int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func pointerTo(typ godwarf.Type, arch Arch) godwarf.Type {
|
func pointerTo(typ godwarf.Type, arch *Arch) godwarf.Type {
|
||||||
return &godwarf.PtrType{
|
return &godwarf.PtrType{
|
||||||
CommonType: godwarf.CommonType{
|
CommonType: godwarf.CommonType{
|
||||||
ByteSize: int64(arch.PtrSize()),
|
ByteSize: int64(arch.PtrSize()),
|
||||||
|
|||||||
@ -432,7 +432,7 @@ func getGVariable(thread Thread) (*Variable, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return newGVariable(thread, uintptr(gaddr), thread.Arch().DerefTLS())
|
return newGVariable(thread, uintptr(gaddr), thread.BinInfo().Arch.DerefTLS())
|
||||||
}
|
}
|
||||||
|
|
||||||
func newGVariable(thread Thread, gaddr uintptr, deref bool) (*Variable, error) {
|
func newGVariable(thread Thread, gaddr uintptr, deref bool) (*Variable, error) {
|
||||||
@ -446,7 +446,7 @@ func newGVariable(thread Thread, gaddr uintptr, deref bool) (*Variable, error) {
|
|||||||
if deref {
|
if deref {
|
||||||
typ = &godwarf.PtrType{
|
typ = &godwarf.PtrType{
|
||||||
CommonType: godwarf.CommonType{
|
CommonType: godwarf.CommonType{
|
||||||
ByteSize: int64(thread.Arch().PtrSize()),
|
ByteSize: int64(thread.BinInfo().Arch.PtrSize()),
|
||||||
Name: "",
|
Name: "",
|
||||||
ReflectKind: reflect.Ptr,
|
ReflectKind: reflect.Ptr,
|
||||||
Offset: 0,
|
Offset: 0,
|
||||||
@ -1305,7 +1305,7 @@ func convertToEface(srcv, dstv *Variable) error {
|
|||||||
return dstv.writeEmptyInterface(typeAddr, srcv)
|
return dstv.writeEmptyInterface(typeAddr, srcv)
|
||||||
}
|
}
|
||||||
|
|
||||||
func readStringInfo(mem MemoryReadWriter, arch Arch, addr uintptr) (uintptr, int64, error) {
|
func readStringInfo(mem MemoryReadWriter, arch *Arch, addr uintptr) (uintptr, int64, error) {
|
||||||
// string data structure is always two ptrs in size. Addr, followed by len
|
// string data structure is always two ptrs in size. Addr, followed by len
|
||||||
// http://research.swtch.com/godata
|
// http://research.swtch.com/godata
|
||||||
|
|
||||||
|
|||||||
@ -329,7 +329,7 @@ func LoadConfigFromProc(cfg *proc.LoadConfig) *LoadConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ConvertRegisters converts proc.Register to api.Register for a slice.
|
// ConvertRegisters converts proc.Register to api.Register for a slice.
|
||||||
func ConvertRegisters(in op.DwarfRegisters, arch proc.Arch, floatingPoint bool) (out []Register) {
|
func ConvertRegisters(in op.DwarfRegisters, arch *proc.Arch, floatingPoint bool) (out []Register) {
|
||||||
out = make([]Register, 0, len(in.Regs))
|
out = make([]Register, 0, len(in.Regs))
|
||||||
for i := range in.Regs {
|
for i := range in.Regs {
|
||||||
reg := in.Reg(uint64(i))
|
reg := in.Reg(uint64(i))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user