github.com/undoio/delve@v1.9.0/pkg/proc/arch.go (about)

     1  package proc
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/undoio/delve/pkg/dwarf/frame"
     8  	"github.com/undoio/delve/pkg/dwarf/op"
     9  )
    10  
    11  // Arch represents a CPU architecture.
    12  type Arch struct {
    13  	Name string // architecture name
    14  
    15  	ptrSize                  int
    16  	maxInstructionLength     int
    17  	prologues                []opcodeSeq
    18  	breakpointInstruction    []byte
    19  	altBreakpointInstruction []byte
    20  	breakInstrMovesPC        bool
    21  	derefTLS                 bool
    22  	usesLR                   bool // architecture uses a link register, also called RA on some architectures
    23  	PCRegNum                 uint64
    24  	SPRegNum                 uint64
    25  	BPRegNum                 uint64
    26  	ContextRegNum            uint64 // register used to pass a closure context when calling a function pointer
    27  	LRRegNum                 uint64
    28  
    29  	// asmDecode decodes the assembly instruction starting at mem[0:] into asmInst.
    30  	// It assumes that the Loc and AtPC fields of asmInst have already been filled.
    31  	asmDecode func(asmInst *AsmInstruction, mem []byte, regs *op.DwarfRegisters, memrw MemoryReadWriter, bi *BinaryInfo) error
    32  	// fixFrameUnwindContext applies architecture specific rules for unwinding a stack frame
    33  	// on the given arch.
    34  	fixFrameUnwindContext func(*frame.FrameContext, uint64, *BinaryInfo) *frame.FrameContext
    35  	// switchStack will use the current frame to determine if it's time to
    36  	// switch between the system stack and the goroutine stack or vice versa.
    37  	switchStack func(it *stackIterator, callFrameRegs *op.DwarfRegisters) bool
    38  	// regSize returns the size (in bytes) of register regnum.
    39  	regSize func(uint64) int
    40  	// RegistersToDwarfRegisters maps hardware registers to DWARF registers.
    41  	RegistersToDwarfRegisters func(uint64, Registers) *op.DwarfRegisters
    42  	// addrAndStackRegsToDwarfRegisters returns DWARF registers from the passed in
    43  	// PC, SP, and BP registers in the format used by the DWARF expression interpreter.
    44  	addrAndStackRegsToDwarfRegisters func(uint64, uint64, uint64, uint64, uint64) op.DwarfRegisters
    45  	// DwarfRegisterToString returns the name and value representation of the
    46  	// given register, the register value can be nil in which case only the
    47  	// register name will be returned.
    48  	DwarfRegisterToString func(int, *op.DwarfRegister) (string, bool, string)
    49  	// inhibitStepInto returns whether StepBreakpoint can be set at pc.
    50  	inhibitStepInto     func(bi *BinaryInfo, pc uint64) bool
    51  	RegisterNameToDwarf func(s string) (int, bool)
    52  	// debugCallMinStackSize is the minimum stack size for call injection on this architecture.
    53  	debugCallMinStackSize uint64
    54  	// maxRegArgBytes is extra padding for ABI1 call injections, equivalent to
    55  	// the maximum space occupied by register arguments.
    56  	maxRegArgBytes int
    57  
    58  	// asmRegisters maps assembly register numbers to dwarf registers.
    59  	asmRegisters map[int]asmRegister
    60  
    61  	// crosscall2fn is the DIE of crosscall2, a function used by the go runtime
    62  	// to call C functions. This function in go 1.9 (and previous versions) had
    63  	// a bad frame descriptor which needs to be fixed to generate good stack
    64  	// traces.
    65  	crosscall2fn *Function
    66  
    67  	// sigreturnfn is the DIE of runtime.sigreturn, the return trampoline for
    68  	// the signal handler. See comment in FixFrameUnwindContext for a
    69  	// description of why this is needed.
    70  	sigreturnfn *Function
    71  }
    72  
    73  type asmRegister struct {
    74  	dwarfNum uint64
    75  	offset   uint
    76  	mask     uint64
    77  }
    78  
    79  const (
    80  	mask8  = 0x000000ff
    81  	mask16 = 0x0000ffff
    82  	mask32 = 0xffffffff
    83  )
    84  
    85  // PtrSize returns the size of a pointer for the architecture.
    86  func (a *Arch) PtrSize() int {
    87  	return a.ptrSize
    88  }
    89  
    90  // MaxInstructionLength is the maximum size in bytes of an instruction.
    91  func (a *Arch) MaxInstructionLength() int {
    92  	return a.maxInstructionLength
    93  }
    94  
    95  // BreakpointInstruction is the instruction that will trigger a breakpoint trap for
    96  // the given architecture.
    97  func (a *Arch) BreakpointInstruction() []byte {
    98  	return a.breakpointInstruction
    99  }
   100  
   101  // AltBreakpointInstruction returns an alternate encoding for the breakpoint instruction.
   102  func (a *Arch) AltBreakpointInstruction() []byte {
   103  	return a.altBreakpointInstruction
   104  }
   105  
   106  // BreakInstrMovesPC is true if hitting the breakpoint instruction advances the
   107  // instruction counter by the size of the breakpoint instruction.
   108  func (a *Arch) BreakInstrMovesPC() bool {
   109  	return a.breakInstrMovesPC
   110  }
   111  
   112  // BreakpointSize is the size of the breakpoint instruction for the given architecture.
   113  func (a *Arch) BreakpointSize() int {
   114  	return len(a.breakpointInstruction)
   115  }
   116  
   117  // DerefTLS is true if the G struct stored in the TLS section is a pointer
   118  // and the address must be dereferenced to find to actual G struct.
   119  func (a *Arch) DerefTLS() bool {
   120  	return a.derefTLS
   121  }
   122  
   123  // getAsmRegister returns the value of the asm register asmreg using the asmRegisters table of arch.
   124  // The interpretation of asmreg is architecture specific and defined by the disassembler.
   125  // A mask value of 0 inside asmRegisters is equivalent to ^uint64(0).
   126  func (arch *Arch) getAsmRegister(regs *op.DwarfRegisters, asmreg int) (uint64, error) {
   127  	hwreg, ok := arch.asmRegisters[asmreg]
   128  	if !ok {
   129  		return 0, ErrUnknownRegister
   130  	}
   131  	reg := regs.Reg(hwreg.dwarfNum)
   132  	if reg == nil {
   133  		return 0, fmt.Errorf("register %#x not found", asmreg)
   134  	}
   135  	n := (reg.Uint64Val >> hwreg.offset)
   136  	if hwreg.mask != 0 {
   137  		n = n & hwreg.mask
   138  	}
   139  	return n, nil
   140  }
   141  
   142  func nameToDwarfFunc(n2d map[string]int) func(string) (int, bool) {
   143  	return func(name string) (int, bool) {
   144  		r, ok := n2d[strings.ToLower(name)]
   145  		return r, ok
   146  	}
   147  }
   148  
   149  // crosscall2 is defined in $GOROOT/src/runtime/cgo/asm_amd64.s.
   150  const (
   151  	crosscall2SPOffsetBad        = 0x8
   152  	crosscall2SPOffsetWindows    = 0x118
   153  	crosscall2SPOffsetNonWindows = 0x58
   154  )