mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 18:57:18 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			252 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			252 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package evalop
 | |
| 
 | |
| import (
 | |
| 	"go/ast"
 | |
| 	"go/constant"
 | |
| 
 | |
| 	"github.com/go-delve/delve/pkg/dwarf/godwarf"
 | |
| )
 | |
| 
 | |
| // Op is a stack machine opcode
 | |
| type Op interface {
 | |
| 	depthCheck() (npop, npush int)
 | |
| }
 | |
| 
 | |
| // PushCurg pushes the current goroutine on the stack.
 | |
| type PushCurg struct {
 | |
| }
 | |
| 
 | |
| func (*PushCurg) depthCheck() (npop, npush int) { return 0, 1 }
 | |
| 
 | |
| // PushFrameoff pushes the frame offset for the current frame on the stack.
 | |
| type PushFrameoff struct {
 | |
| }
 | |
| 
 | |
| func (*PushFrameoff) depthCheck() (npop, npush int) { return 0, 1 }
 | |
| 
 | |
| // PushThreadID pushes the ID of the current thread on the stack.
 | |
| type PushThreadID struct {
 | |
| }
 | |
| 
 | |
| func (*PushThreadID) depthCheck() (npop, npush int) { return 0, 1 }
 | |
| 
 | |
| // PushConst pushes a constant on the stack.
 | |
| type PushConst struct {
 | |
| 	Value constant.Value
 | |
| }
 | |
| 
 | |
| func (*PushConst) depthCheck() (npop, npush int) { return 0, 1 }
 | |
| 
 | |
| // PushLocal pushes the local variable with the given name on the stack.
 | |
| type PushLocal struct {
 | |
| 	Name  string
 | |
| 	Frame int64
 | |
| }
 | |
| 
 | |
| func (*PushLocal) depthCheck() (npop, npush int) { return 0, 1 }
 | |
| 
 | |
| // PushNil pushes an untyped nil on the stack.
 | |
| type PushNil struct {
 | |
| }
 | |
| 
 | |
| func (*PushNil) depthCheck() (npop, npush int) { return 0, 1 }
 | |
| 
 | |
| // PushRegister pushes the CPU register Regnum on the stack.
 | |
| type PushRegister struct {
 | |
| 	Regnum  int
 | |
| 	Regname string
 | |
| }
 | |
| 
 | |
| func (*PushRegister) depthCheck() (npop, npush int) { return 0, 1 }
 | |
| 
 | |
| // PushPackageVar pushes a package variable on the stack.
 | |
| type PushPackageVar struct {
 | |
| 	PkgName, Name string // if PkgName == "" use current function's package
 | |
| }
 | |
| 
 | |
| func (*PushPackageVar) depthCheck() (npop, npush int) { return 0, 1 }
 | |
| 
 | |
| // Select replaces the topmost stack variable v with v.Name.
 | |
| type Select struct {
 | |
| 	Name string
 | |
| }
 | |
| 
 | |
| func (*Select) depthCheck() (npop, npush int) { return 1, 1 }
 | |
| 
 | |
| // TypeAssert replaces the topmost stack variable v with v.(DwarfType).
 | |
| type TypeAssert struct {
 | |
| 	DwarfType godwarf.Type
 | |
| 	Node      *ast.TypeAssertExpr
 | |
| }
 | |
| 
 | |
| func (*TypeAssert) depthCheck() (npop, npush int) { return 1, 1 }
 | |
| 
 | |
| // PointerDeref replaces the topmost stack variable v with *v.
 | |
| type PointerDeref struct {
 | |
| 	Node *ast.StarExpr
 | |
| }
 | |
| 
 | |
| func (*PointerDeref) depthCheck() (npop, npush int) { return 1, 1 }
 | |
| 
 | |
| // Unary applies the given unary operator to the topmost stack variable.
 | |
| type Unary struct {
 | |
| 	Node *ast.UnaryExpr
 | |
| }
 | |
| 
 | |
| func (*Unary) depthCheck() (npop, npush int) { return 1, 1 }
 | |
| 
 | |
| // AddrOf replaces the topmost stack variable v with &v.
 | |
| type AddrOf struct {
 | |
| 	Node *ast.UnaryExpr
 | |
| }
 | |
| 
 | |
| func (*AddrOf) depthCheck() (npop, npush int) { return 1, 1 }
 | |
| 
 | |
| // TypeCast replaces the topmost stack variable v with (DwarfType)(v).
 | |
| type TypeCast struct {
 | |
| 	DwarfType godwarf.Type
 | |
| 	Node      *ast.CallExpr
 | |
| }
 | |
| 
 | |
| func (*TypeCast) depthCheck() (npop, npush int) { return 1, 1 }
 | |
| 
 | |
| // Reslice implements a reslice operation.
 | |
| // If HasHigh is set it pops three variables, low, high and v, and pushes
 | |
| // v[low:high].
 | |
| // Otherwise it pops two variables, low and v, and pushes v[low:].
 | |
| type Reslice struct {
 | |
| 	HasHigh bool
 | |
| 	Node    *ast.SliceExpr
 | |
| }
 | |
| 
 | |
| func (op *Reslice) depthCheck() (npop, npush int) {
 | |
| 	if op.HasHigh {
 | |
| 		return 3, 1
 | |
| 	} else {
 | |
| 		return 2, 1
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Index pops two variables, idx and v, and pushes v[idx].
 | |
| type Index struct {
 | |
| 	Node *ast.IndexExpr
 | |
| }
 | |
| 
 | |
| func (*Index) depthCheck() (npop, npush int) { return 2, 1 }
 | |
| 
 | |
| // Jump looks at the topmost stack variable and if it satisfies the
 | |
| // condition specified by When it jumps to the stack machine instruction at
 | |
| // Target+1.
 | |
| // If Pop is set the topmost stack variable is also popped.
 | |
| type Jump struct {
 | |
| 	When   JumpCond
 | |
| 	Pop    bool
 | |
| 	Target int
 | |
| 	Node   ast.Expr
 | |
| }
 | |
| 
 | |
| func (jmpif *Jump) depthCheck() (npop, npush int) {
 | |
| 	if jmpif.Pop {
 | |
| 		return 1, 0
 | |
| 	}
 | |
| 	return 0, 0
 | |
| }
 | |
| 
 | |
| // JumpCond specifies a condition for the Jump instruction.
 | |
| type JumpCond uint8
 | |
| 
 | |
| const (
 | |
| 	JumpIfFalse JumpCond = iota
 | |
| 	JumpIfTrue
 | |
| )
 | |
| 
 | |
| // Binary pops two variables from the stack, applies the specified binary
 | |
| // operator to them and pushes the result back on the stack.
 | |
| type Binary struct {
 | |
| 	Node *ast.BinaryExpr
 | |
| }
 | |
| 
 | |
| func (*Binary) depthCheck() (npop, npush int) { return 2, 1 }
 | |
| 
 | |
| // BoolToConst pops the topmost variable from the stack, which must be a
 | |
| // boolean variable, and converts it to a constant.
 | |
| type BoolToConst struct {
 | |
| }
 | |
| 
 | |
| func (*BoolToConst) depthCheck() (npop, npush int) { return 1, 1 }
 | |
| 
 | |
| // Pop removes the topmost variable from the stack.
 | |
| type Pop struct {
 | |
| }
 | |
| 
 | |
| func (*Pop) depthCheck() (npop, npush int) { return 1, 0 }
 | |
| 
 | |
| // BuiltinCall pops len(Args) argument from the stack, calls the specified
 | |
| // builtin on them and pushes the result back on the stack.
 | |
| type BuiltinCall struct {
 | |
| 	Name string
 | |
| 	Args []ast.Expr
 | |
| }
 | |
| 
 | |
| func (bc *BuiltinCall) depthCheck() (npop, npush int) {
 | |
| 	return len(bc.Args), 1
 | |
| }
 | |
| 
 | |
| // CallInjectionStart starts call injection by calling
 | |
| // runtime.debugCallVn.
 | |
| type CallInjectionStart struct {
 | |
| 	id      int  // identifier for all the call injection instructions that belong to the same sequence, this only exists to make reading listings easier
 | |
| 	HasFunc bool // target function already pushed on the stack
 | |
| 	Node    *ast.CallExpr
 | |
| }
 | |
| 
 | |
| func (*CallInjectionStart) depthCheck() (npop, npush int) { return 0, 1 }
 | |
| 
 | |
| // CallInjectionSetTarget starts the call injection, after
 | |
| // runtime.debugCallVn set up the stack for us, by copying the entry point
 | |
| // of the function, setting the closure register and copying the receiver.
 | |
| type CallInjectionSetTarget struct {
 | |
| 	id int
 | |
| }
 | |
| 
 | |
| func (*CallInjectionSetTarget) depthCheck() (npop, npush int) { return 1, 0 }
 | |
| 
 | |
| // CallInjectionCopyArg copies one argument for call injection.
 | |
| type CallInjectionCopyArg struct {
 | |
| 	id      int
 | |
| 	ArgNum  int
 | |
| 	ArgExpr ast.Expr
 | |
| }
 | |
| 
 | |
| func (*CallInjectionCopyArg) depthCheck() (npop, npush int) { return 1, 0 }
 | |
| 
 | |
| // CallInjectionComplete resumes target execution so that the injected call can run.
 | |
| type CallInjectionComplete struct {
 | |
| 	id int
 | |
| }
 | |
| 
 | |
| func (*CallInjectionComplete) depthCheck() (npop, npush int) { return 0, 1 }
 | |
| 
 | |
| // CallInjectionAllocString uses the call injection protocol to allocate the
 | |
| // value of a string literal somewhere on the target's memory so that it can
 | |
| // be assigned to a variable (or passed to a function).
 | |
| // There are three phases to CallInjectionAllocString, distinguished by the
 | |
| // Phase field. They must always appear in sequence in the program:
 | |
| //
 | |
| //	CallInjectionAllocString{Phase: 0}
 | |
| //	CallInjectionAllocString{Phase: 1}
 | |
| //	CallInjectionAllocString{Phase: 2}
 | |
| type CallInjectionAllocString struct {
 | |
| 	Phase int
 | |
| }
 | |
| 
 | |
| func (op *CallInjectionAllocString) depthCheck() (npop, npush int) { return 1, 1 }
 | |
| 
 | |
| // SetValue pops to variables from the stack, lhv and rhv, and sets lhv to
 | |
| // rhv.
 | |
| type SetValue struct {
 | |
| 	lhe, Rhe ast.Expr
 | |
| }
 | |
| 
 | |
| func (*SetValue) depthCheck() (npop, npush int) { return 2, 0 }
 | 
