package proc import ( "fmt" "strings" "github.com/go-delve/delve/pkg/dwarf/frame" "github.com/go-delve/delve/pkg/dwarf/op" ) // Arch represents a CPU architecture. type Arch struct { Name string // architecture name ptrSize int maxInstructionLength int prologues []opcodeSeq breakpointInstruction []byte altBreakpointInstruction []byte breakInstrMovesPC bool derefTLS bool usesLR bool // architecture uses a link register, also called RA on some architectures PCRegNum uint64 SPRegNum uint64 BPRegNum uint64 ContextRegNum uint64 // register used to pass a closure context when calling a function pointer LRRegNum uint64 // 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 func(asmInst *AsmInstruction, mem []byte, regs *op.DwarfRegisters, memrw MemoryReadWriter, bi *BinaryInfo) error // fixFrameUnwindContext applies architecture specific rules for unwinding a stack frame // on the given arch. 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 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 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 func(uint64, uint64, uint64, uint64, uint64) op.DwarfRegisters // DwarfRegisterToString returns the name and value representation of the // given register, the register value can be nil in which case only the // register name will be returned. DwarfRegisterToString func(int, *op.DwarfRegister) (string, bool, string) // inhibitStepInto returns whether StepBreakpoint can be set at pc. inhibitStepInto func(bi *BinaryInfo, pc uint64) bool RegisterNameToDwarf func(s string) (int, bool) RegnumToString func(uint64) string // debugCallMinStackSize is the minimum stack size for call injection on this architecture. debugCallMinStackSize uint64 // maxRegArgBytes is extra padding for ABI1 call injections, equivalent to // the maximum space occupied by register arguments. maxRegArgBytes int // asmRegisters maps assembly register numbers to dwarf registers. asmRegisters map[int]asmRegister // 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 } type asmRegister struct { dwarfNum uint64 offset uint mask uint64 } const ( mask8 = 0x000000ff mask16 = 0x0000ffff mask32 = 0xffffffff ) // 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 } // BreakpointInstruction is the instruction that will trigger a breakpoint trap for // the given architecture. func (a *Arch) BreakpointInstruction() []byte { return a.breakpointInstruction } // AltBreakpointInstruction returns an alternate encoding for the breakpoint instruction. func (a *Arch) AltBreakpointInstruction() []byte { return a.altBreakpointInstruction } // 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 } // getAsmRegister returns the value of the asm register asmreg using the asmRegisters table of arch. // The interpretation of asmreg is architecture specific and defined by the disassembler. // A mask value of 0 inside asmRegisters is equivalent to ^uint64(0). func (a *Arch) getAsmRegister(regs *op.DwarfRegisters, asmreg int) (uint64, error) { hwreg, ok := a.asmRegisters[asmreg] if !ok { return 0, ErrUnknownRegister } reg := regs.Reg(hwreg.dwarfNum) if reg == nil { return 0, fmt.Errorf("register %#x not found", asmreg) } n := (reg.Uint64Val >> hwreg.offset) if hwreg.mask != 0 { n = n & hwreg.mask } return n, nil } func nameToDwarfFunc(n2d map[string]int) func(string) (int, bool) { return func(name string) (int, bool) { r, ok := n2d[strings.ToLower(name)] return r, ok } } // crosscall2 is defined in $GOROOT/src/runtime/cgo/asm_amd64.s. const ( crosscall2SPOffsetBad = 0x8 crosscall2SPOffsetWindowsAMD64 = 0x118 crosscall2SPOffsetLinuxPPC64LE = 0x158 crosscall2SPOffset = 0x58 )