2015-06-12 19:49:23 +00:00
|
|
|
package proc
|
2015-04-29 17:07:27 +00:00
|
|
|
|
2017-10-05 07:26:19 +00:00
|
|
|
import (
|
2021-04-28 17:00:26 +00:00
|
|
|
"fmt"
|
2021-05-04 19:56:17 +00:00
|
|
|
"strings"
|
2021-04-28 17:00:26 +00:00
|
|
|
|
2019-01-04 18:39:25 +00:00
|
|
|
"github.com/go-delve/delve/pkg/dwarf/frame"
|
|
|
|
"github.com/go-delve/delve/pkg/dwarf/op"
|
2017-10-05 07:26:19 +00:00
|
|
|
)
|
|
|
|
|
2020-03-30 18:03:29 +00:00
|
|
|
// Arch represents a CPU architecture.
|
|
|
|
type Arch struct {
|
|
|
|
Name string // architecture name
|
|
|
|
|
2020-11-03 18:28:37 +00:00
|
|
|
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
|
2021-03-04 18:28:28 +00:00
|
|
|
PCRegNum uint64
|
|
|
|
SPRegNum uint64
|
|
|
|
BPRegNum uint64
|
|
|
|
ContextRegNum uint64 // register used to pass a closure context when calling a function pointer
|
2022-05-03 17:46:24 +00:00
|
|
|
LRRegNum uint64
|
2020-03-30 18:03:29 +00:00
|
|
|
|
|
|
|
// asmDecode decodes the assembly instruction starting at mem[0:] into asmInst.
|
2020-03-28 17:39:32 +00:00
|
|
|
// It assumes that the Loc and AtPC fields of asmInst have already been filled.
|
2021-04-28 17:00:26 +00:00
|
|
|
asmDecode func(asmInst *AsmInstruction, mem []byte, regs *op.DwarfRegisters, memrw MemoryReadWriter, bi *BinaryInfo) error
|
2020-03-30 18:03:29 +00:00
|
|
|
// fixFrameUnwindContext applies architecture specific rules for unwinding a stack frame
|
2020-03-28 17:39:32 +00:00
|
|
|
// on the given arch.
|
2020-03-30 18:03:29 +00:00
|
|
|
fixFrameUnwindContext func(*frame.FrameContext, uint64, *BinaryInfo) *frame.FrameContext
|
|
|
|
// switchStack will use the current frame to determine if it's time to
|
2020-03-28 17:39:32 +00:00
|
|
|
// switch between the system stack and the goroutine stack or vice versa.
|
2020-03-30 18:03:29 +00:00
|
|
|
switchStack func(it *stackIterator, callFrameRegs *op.DwarfRegisters) bool
|
|
|
|
// regSize returns the size (in bytes) of register regnum.
|
|
|
|
regSize func(uint64) int
|
2020-03-28 17:39:32 +00:00
|
|
|
// RegistersToDwarfRegisters maps hardware registers to DWARF registers.
|
2021-04-28 17:00:26 +00:00
|
|
|
RegistersToDwarfRegisters func(uint64, Registers) *op.DwarfRegisters
|
2020-03-30 18:03:29 +00:00
|
|
|
// addrAndStackRegsToDwarfRegisters returns DWARF registers from the passed in
|
2020-03-28 17:39:32 +00:00
|
|
|
// PC, SP, and BP registers in the format used by the DWARF expression interpreter.
|
2020-03-30 18:03:29 +00:00
|
|
|
addrAndStackRegsToDwarfRegisters func(uint64, uint64, uint64, uint64, uint64) op.DwarfRegisters
|
2021-03-04 18:28:28 +00:00
|
|
|
// 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.
|
2020-03-30 18:03:29 +00:00
|
|
|
DwarfRegisterToString func(int, *op.DwarfRegister) (string, bool, string)
|
|
|
|
// inhibitStepInto returns whether StepBreakpoint can be set at pc.
|
2021-05-04 19:56:17 +00:00
|
|
|
inhibitStepInto func(bi *BinaryInfo, pc uint64) bool
|
|
|
|
RegisterNameToDwarf func(s string) (int, bool)
|
2022-07-15 12:56:00 +00:00
|
|
|
RegnumToString func(uint64) string
|
2022-05-03 17:46:24 +00:00
|
|
|
// 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
|
2023-11-20 18:43:15 +00:00
|
|
|
// argumentRegs are function call injection registers for runtimeOptimizedWorkaround
|
|
|
|
argumentRegs []int
|
2020-03-30 18:03:29 +00:00
|
|
|
|
2021-04-28 17:00:26 +00:00
|
|
|
// asmRegisters maps assembly register numbers to dwarf registers.
|
|
|
|
asmRegisters map[int]asmRegister
|
|
|
|
|
2020-03-30 18:03:29 +00:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2021-04-28 17:00:26 +00:00
|
|
|
type asmRegister struct {
|
|
|
|
dwarfNum uint64
|
|
|
|
offset uint
|
|
|
|
mask uint64
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
mask8 = 0x000000ff
|
|
|
|
mask16 = 0x0000ffff
|
|
|
|
mask32 = 0xffffffff
|
|
|
|
)
|
|
|
|
|
2020-03-30 18:03:29 +00:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2020-11-03 18:28:37 +00:00
|
|
|
// AltBreakpointInstruction returns an alternate encoding for the breakpoint instruction.
|
|
|
|
func (a *Arch) AltBreakpointInstruction() []byte {
|
|
|
|
return a.altBreakpointInstruction
|
|
|
|
}
|
|
|
|
|
2020-03-30 18:03:29 +00:00
|
|
|
// 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
|
2015-04-29 17:07:27 +00:00
|
|
|
}
|
|
|
|
|
2021-04-28 17:00:26 +00:00
|
|
|
// 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).
|
2023-08-17 21:24:43 +00:00
|
|
|
func (a *Arch) getAsmRegister(regs *op.DwarfRegisters, asmreg int) (uint64, error) {
|
|
|
|
hwreg, ok := a.asmRegisters[asmreg]
|
2021-04-28 17:00:26 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-05-04 19:56:17 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-10 16:34:40 +00:00
|
|
|
// crosscall2 is defined in $GOROOT/src/runtime/cgo/asm_amd64.s.
|
2017-09-01 13:34:13 +00:00
|
|
|
const (
|
2022-09-21 20:39:44 +00:00
|
|
|
crosscall2SPOffsetBad = 0x8
|
|
|
|
crosscall2SPOffsetWindowsAMD64 = 0x118
|
2023-07-07 16:30:38 +00:00
|
|
|
crosscall2SPOffsetLinuxPPC64LE = 0x158
|
2022-09-21 20:39:44 +00:00
|
|
|
crosscall2SPOffset = 0x58
|
2017-09-01 13:34:13 +00:00
|
|
|
)
|