未验证 提交 223e0a57 编写于 作者: A Alessandro Arzilli 提交者: GitHub

proc: convert Arch into a struct (#1972)

Replace the interface type Arch with a struct with the same
functionality.
上级 85c34e47
......@@ -12,23 +12,6 @@ import (
"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 (
amd64DwarfIPRegNum uint64 = 16
amd64DwarfSPRegNum uint64 = 7
......@@ -39,51 +22,28 @@ var amd64BreakInstruction = []byte{0xCC}
// AMD64Arch returns an initialized AMD64
// struct.
func AMD64Arch(goos string) *AMD64 {
return &AMD64{
goos: goos,
func AMD64Arch(goos string) *Arch {
return &Arch{
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
// on this architecture.
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 {
func amd64FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryInfo) *frame.FrameContext {
a := bi.Arch
if a.sigreturnfn == nil {
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 {
rule := fctxt.CFA
if rule.Offset == crosscall2SPOffsetBad {
switch a.goos {
switch bi.GOOS {
case "windows":
rule.Offset += crosscall2SPOffsetWindows
default:
......@@ -168,10 +128,7 @@ func (a *AMD64) FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *
// switch happens.
const amd64cgocallSPOffsetSaveSlot = 0x28
// 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.
// Sets it.atend when the top of the stack is reached.
func (a *AMD64) SwitchStack(it *stackIterator, _ *op.DwarfRegisters) bool {
func amd64SwitchStack(it *stackIterator, _ *op.DwarfRegisters) bool {
if it.frame.Current.Fn == nil {
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
// in the System V ABI AMD64 Architecture Processor Supplement page 57,
// figure 3.36
// https://www.uclibc.org/docs/psABI-x86_64.pdf
func (a *AMD64) RegSize(regnum uint64) int {
func amd64RegSize(regnum uint64) int {
// XMM registers
if regnum > amd64DwarfIPRegNum && regnum <= 32 {
return 16
......@@ -387,9 +344,7 @@ func maxAmd64DwarfRegister() int {
return max
}
// RegistersToDwarfRegisters converts hardware registers to the format used
// by the DWARF expression interpreter.
func (a *AMD64) RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
func amd64RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, maxAmd64DwarfRegister()+1)
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
// 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 {
func amd64AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, amd64DwarfIPRegNum+1)
dregs[amd64DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
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 (a *AMD64) DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
func amd64DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
name, ok := amd64DwarfToName[i]
if !ok {
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)
}
// 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"
)
// 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.
func (a *AMD64) AsmDecode(asmInst *AsmInstruction, mem []byte, regs Registers, memrw MemoryReadWriter, bi *BinaryInfo) error {
func amd64AsmDecode(asmInst *AsmInstruction, mem []byte, regs Registers, memrw MemoryReadWriter, bi *BinaryInfo) error {
return x86AsmDecode(asmInst, mem, regs, memrw, bi, 64)
}
func (a *AMD64) Prologues() []opcodeSeq {
return prologuesAMD64
}
// Possible stacksplit prologues are inserted by stacksplit in
// $GOROOT/src/cmd/internal/obj/x86/obj6.go.
// The stacksplit prologue will always begin with loading curg in CX, this
......
......@@ -5,47 +5,87 @@ import (
"github.com/go-delve/delve/pkg/dwarf/op"
)
// Arch defines an interface for representing a
// CPU architecture.
type Arch interface {
// PtrSize returns the size of a pointer for the architecture.
PtrSize() int
// MaxInstructionLength is the maximum size in bytes of an instruction.
MaxInstructionLength() int
// AsmDecode decodes the assembly instruction starting at mem[0:] into asmInst.
// Arch represents a CPU architecture.
type Arch struct {
Name string // architecture name
ptrSize int
maxInstructionLength int
prologues []opcodeSeq
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.
AsmDecode(asmInst *AsmInstruction, mem []byte, regs Registers, memrw MemoryReadWriter, bi *BinaryInfo) error
// Prologues returns a list of stack split prologues
// 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
asmDecode func(asmInst *AsmInstruction, mem []byte, regs Registers, memrw MemoryReadWriter, bi *BinaryInfo) error
// fixFrameUnwindContext applies architecture specific rules for unwinding a stack frame
// on the given arch.
FixFrameUnwindContext(*frame.FrameContext, uint64, *BinaryInfo) *frame.FrameContext
// SwitchStack will use the current frame to determine if it's time to
fixFrameUnwindContext func(*frame.FrameContext, uint64, *BinaryInfo) *frame.FrameContext
// 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.
SwitchStack(it *stackIterator, callFrameRegs *op.DwarfRegisters) bool
// RegSize returns the size (in bytes) of register regnum.
RegSize(uint64) int
switchStack func(it *stackIterator, callFrameRegs *op.DwarfRegisters) bool
// regSize returns the size (in bytes) of register regnum.
regSize func(uint64) int
// RegistersToDwarfRegisters maps hardware registers to DWARF registers.
RegistersToDwarfRegisters(uint64, Registers) op.DwarfRegisters
// AddrAndStackRegsToDwarfRegisters returns DWARF registers from the passed in
RegistersToDwarfRegisters func(uint64, Registers) op.DwarfRegisters
// addrAndStackRegsToDwarfRegisters returns DWARF registers from the passed in
// 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(int, *op.DwarfRegister) (string, bool, string)
// InhibitStepInto returns whether StepBreakpoint can be set at pc.
InhibitStepInto(bi *BinaryInfo, pc uint64) bool
DwarfRegisterToString func(int, *op.DwarfRegister) (string, bool, string)
// inhibitStepInto returns whether StepBreakpoint can be set at pc.
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.
......
......@@ -12,23 +12,6 @@ import (
"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 (
arm64DwarfIPRegNum uint64 = 32
arm64DwarfSPRegNum uint64 = 31
......@@ -40,50 +23,28 @@ var arm64BreakInstruction = []byte{0x0, 0x0, 0x20, 0xd4}
// ARM64Arch returns an initialized ARM64
// struct.
func ARM64Arch(goos string) *ARM64 {
return &ARM64{
goos: goos,
func ARM64Arch(goos string) *Arch {
return &Arch{
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
// on this architecture.
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 {
func arm64FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryInfo) *frame.FrameContext {
a := bi.Arch
if a.sigreturnfn == nil {
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 {
rule := fctxt.CFA
if rule.Offset == crosscall2SPOffsetBad {
switch a.goos {
switch bi.GOOS {
case "windows":
rule.Offset += crosscall2SPOffsetWindows
default:
......@@ -174,7 +135,7 @@ const arm64cgocallSPOffsetSaveSlot = 0x8
const prevG0schedSPOffsetSaveSlot = 0x10
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 {
switch it.frame.Current.Fn.Name {
case "runtime.asmcgocall", "runtime.cgocallback_gofunc", "runtime.sigpanic":
......@@ -270,7 +231,7 @@ func (a *ARM64) SwitchStack(it *stackIterator, callFrameRegs *op.DwarfRegisters)
return false
}
func (a *ARM64) RegSize(regnum uint64) int {
func arm64RegSize(regnum uint64) int {
// fp registers
if regnum >= 64 && regnum <= 95 {
return 16
......@@ -361,9 +322,7 @@ func maxArm64DwarfRegister() int {
return max
}
// RegistersToDwarfRegisters converts hardware registers to the format used
// by the DWARF expression interpreter.
func (a *ARM64) RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
func arm64RegistersToDwarfRegisters(staticBase uint64, regs Registers) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, maxArm64DwarfRegister()+1)
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
// 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 {
func arm64AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, arm64DwarfIPRegNum+1)
dregs[arm64DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
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
switch {
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)
}
// 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"
)
// 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.
func (a *ARM64) AsmDecode(asmInst *AsmInstruction, mem []byte, regs Registers, memrw MemoryReadWriter, bi *BinaryInfo) error {
func arm64AsmDecode(asmInst *AsmInstruction, mem []byte, regs Registers, memrw MemoryReadWriter, bi *BinaryInfo) error {
asmInst.Size = 4
asmInst.Bytes = mem[:asmInst.Size]
......@@ -35,10 +33,6 @@ func (a *ARM64) AsmDecode(asmInst *AsmInstruction, mem []byte, regs Registers, m
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 {
if inst.Op != arm64asm.BL && inst.Op != arm64asm.BLR {
return nil
......
......@@ -43,7 +43,7 @@ const (
// includes both the executable and also any loaded libraries).
type BinaryInfo struct {
// Architecture of this binary.
Arch Arch
Arch *Arch
// GOOS operating system this binary is executing on.
GOOS string
......
......@@ -313,11 +313,6 @@ func (t *Thread) RestoreRegisters(proc.Registers) error {
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.
func (t *Thread) BinInfo() *proc.BinaryInfo {
return t.p.bi
......
......@@ -185,7 +185,7 @@ func withCoreFile(t *testing.T, name, args string) *proc.Target {
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)
for i, reg := range dregs.Regs {
if reg == nil {
......
......@@ -139,7 +139,7 @@ func disassemble(memrw MemoryReadWriter, regs Registers, breakpoints *Breakpoint
inst.Breakpoint = atbp
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)
......
......@@ -1303,11 +1303,6 @@ func (t *Thread) RestoreRegisters(savedRegs proc.Registers) error {
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.
func (t *Thread) BinInfo() *proc.BinaryInfo {
return t.p.bi
......
......@@ -8,23 +8,6 @@ import (
"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 (
i386DwarfIPRegNum uint64 = 8
i386DwarfSPRegNum uint64 = 4
......@@ -35,50 +18,28 @@ var i386BreakInstruction = []byte{0xCC}
// I386Arch returns an initialized I386Arch
// struct.
func I386Arch(goos string) *I386 {
return &I386{
goos: goos,
func I386Arch(goos string) *Arch {
return &Arch{
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
// on this architecture.
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 {
func i386FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryInfo) *frame.FrameContext {
i := bi.Arch
if i.sigreturnfn == nil {
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
// switch between the system stack and the goroutine stack or vice versa.
// Sets it.atend when the top of the stack is reached.
func (i *I386) SwitchStack(it *stackIterator, _ *op.DwarfRegisters) bool {
func i386SwitchStack(it *stackIterator, _ *op.DwarfRegisters) bool {
if it.frame.Current.Fn == nil {
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,
// table 2.14
// https://www.uclibc.org/docs/psABI-i386.pdf
func (i *I386) RegSize(regnum uint64) int {
func i386RegSize(regnum uint64) int {
// XMM registers
if regnum >= 21 && regnum <= 36 {
return 16
......@@ -293,7 +252,7 @@ func maxI386DwarfRegister() int {
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)
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
// 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 {
func i386AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
dregs := make([]*op.DwarfRegister, i386DwarfIPRegNum+1)
dregs[i386DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc)
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]
if !ok {
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.).
// 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.
func (i *I386) InhibitStepInto(bi *BinaryInfo, pc uint64) bool {
func i386InhibitStepInto(bi *BinaryInfo, pc uint64) bool {
if bi.SymNames != nil && bi.SymNames[pc] != nil &&
strings.HasPrefix(bi.SymNames[pc].Name, "__x86.get_pc_thunk.") {
return true
......
......@@ -8,18 +8,10 @@ import (
"golang.org/x/arch/x86/x86asm"
)
// 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.
func (i *I386) AsmDecode(asmInst *AsmInstruction, mem []byte, regs Registers, memrw MemoryReadWriter, bi *BinaryInfo) error {
func i386AsmDecode(asmInst *AsmInstruction, mem []byte, regs Registers, memrw MemoryReadWriter, bi *BinaryInfo) error {
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
// $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.
......
......@@ -94,12 +94,6 @@ func (t *Thread) Location() (*proc.Location, error) {
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.
func (t *Thread) BinInfo() *proc.BinaryInfo {
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
// with bp.Addr == PC and there is no need to call SetPC
// after finding one.
adjustPC = adjustPC && t.Arch().BreakInstrMovesPC()
adjustPC = adjustPC && t.BinInfo().Arch.BreakInstrMovesPC()
if bp, ok := t.dbp.FindBreakpoint(pc, adjustPC); ok {
if adjustPC {
......
......@@ -127,7 +127,7 @@ func (g *G) stackIterator(opts StacktraceOptions) (*stackIterator, error) {
so := g.variable.bi.PCToImage(g.PC)
return newStackIterator(
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
}
......@@ -246,7 +246,7 @@ func (it *stackIterator) Next() bool {
}
if it.opts&StacktraceSimple == 0 {
if it.bi.Arch.SwitchStack(it, &callFrameRegs) {
if it.bi.Arch.switchStack(it, &callFrameRegs) {
return true
}
}
......@@ -268,7 +268,7 @@ func (it *stackIterator) switchToGoroutineStack() {
it.pc = it.g.PC
it.regs.Reg(it.regs.SPRegNum).Uint64Val = it.g.SP
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
}
}
......@@ -414,9 +414,9 @@ func (it *stackIterator) advanceRegs() (callFrameRegs op.DwarfRegisters, ret uin
fde, err := it.bi.frameEntries.FDEForPC(it.pc)
var framectx *frame.FrameContext
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 {
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)
......@@ -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 {
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) {
buf := make([]byte, it.bi.Arch.RegSize(regnum))
buf := make([]byte, it.bi.Arch.regSize(regnum))
_, err := it.mem.ReadMemory(buf, uintptr(addr))
if err != nil {
return nil, err
......
......@@ -152,8 +152,7 @@ func (t *Target) SupportsFunctionCalls() bool {
if ok, _ := t.Process.Recorded(); ok {
return false
}
_, ok := t.Process.BinInfo().Arch.(*AMD64)
return ok
return t.Process.BinInfo().Arch.Name == "amd64"
}
// ClearAllGCache clears the internal Goroutine cache.
......
......@@ -770,7 +770,7 @@ func setStepIntoBreakpoint(dbp Process, text []AsmInstruction, cond ast.Expr) er
pc := instr.DestLoc.PC
// Skip InhibitStepInto functions for different arch.
if dbp.BinInfo().Arch.InhibitStepInto(dbp.BinInfo(), pc) {
if dbp.BinInfo().Arch.inhibitStepInto(dbp.BinInfo(), pc) {
return nil
}
......
......@@ -23,7 +23,6 @@ type Thread interface {
// RestoreRegisters restores saved registers
RestoreRegisters(Registers) error
Arch() Arch
BinInfo() *BinaryInfo
StepInstruction() error
// Blocked returns true if the thread is blocked
......
......@@ -46,7 +46,7 @@ type runtimeTypeDIE struct {
kind int64
}
func pointerTo(typ godwarf.Type, arch Arch) godwarf.Type {
func pointerTo(typ godwarf.Type, arch *Arch) godwarf.Type {
return &godwarf.PtrType{
CommonType: godwarf.CommonType{
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) {
......@@ -446,7 +446,7 @@ func newGVariable(thread Thread, gaddr uintptr, deref bool) (*Variable, error) {
if deref {
typ = &godwarf.PtrType{
CommonType: godwarf.CommonType{
ByteSize: int64(thread.Arch().PtrSize()),
ByteSize: int64(thread.BinInfo().Arch.PtrSize()),
Name: "",
ReflectKind: reflect.Ptr,
Offset: 0,
......@@ -1305,7 +1305,7 @@ func convertToEface(srcv, dstv *Variable) error {
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
// 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.
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))
for i := range in.Regs {
reg := in.Reg(uint64(i))
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册