gitlab.com/Raven-IO/raven-delve@v1.22.4/pkg/proc/evalop/ops.go (about) 1 package evalop 2 3 import ( 4 "go/ast" 5 "go/constant" 6 7 "gitlab.com/Raven-IO/raven-delve/pkg/dwarf/godwarf" 8 ) 9 10 // Op is a stack machine opcode 11 type Op interface { 12 depthCheck() (npop, npush int) 13 } 14 15 // PushCurg pushes the current goroutine on the stack. 16 type PushCurg struct { 17 } 18 19 func (*PushCurg) depthCheck() (npop, npush int) { return 0, 1 } 20 21 // PushFrameoff pushes the frame offset for the current frame on the stack. 22 type PushFrameoff struct { 23 } 24 25 func (*PushFrameoff) depthCheck() (npop, npush int) { return 0, 1 } 26 27 // PushThreadID pushes the ID of the current thread on the stack. 28 type PushThreadID struct { 29 } 30 31 func (*PushThreadID) depthCheck() (npop, npush int) { return 0, 1 } 32 33 // PushConst pushes a constant on the stack. 34 type PushConst struct { 35 Value constant.Value 36 } 37 38 func (*PushConst) depthCheck() (npop, npush int) { return 0, 1 } 39 40 // PushLocal pushes the local variable with the given name on the stack. 41 type PushLocal struct { 42 Name string 43 Frame int64 44 } 45 46 func (*PushLocal) depthCheck() (npop, npush int) { return 0, 1 } 47 48 // PushNil pushes an untyped nil on the stack. 49 type PushNil struct { 50 } 51 52 func (*PushNil) depthCheck() (npop, npush int) { return 0, 1 } 53 54 // PushRegister pushes the CPU register Regnum on the stack. 55 type PushRegister struct { 56 Regnum int 57 Regname string 58 } 59 60 func (*PushRegister) depthCheck() (npop, npush int) { return 0, 1 } 61 62 // PushPackageVar pushes a package variable on the stack. 63 type PushPackageVar struct { 64 PkgName, Name string // if PkgName == "" use current function's package 65 } 66 67 func (*PushPackageVar) depthCheck() (npop, npush int) { return 0, 1 } 68 69 // PushLen pushes the length of the variable at the top of the stack into 70 // the stack. 71 type PushLen struct { 72 } 73 74 func (*PushLen) depthCheck() (npop, npush int) { return 1, 2 } 75 76 // Select replaces the topmost stack variable v with v.Name. 77 type Select struct { 78 Name string 79 } 80 81 func (*Select) depthCheck() (npop, npush int) { return 1, 1 } 82 83 // TypeAssert replaces the topmost stack variable v with v.(DwarfType). 84 type TypeAssert struct { 85 DwarfType godwarf.Type 86 Node *ast.TypeAssertExpr 87 } 88 89 func (*TypeAssert) depthCheck() (npop, npush int) { return 1, 1 } 90 91 // PointerDeref replaces the topmost stack variable v with *v. 92 type PointerDeref struct { 93 Node *ast.StarExpr 94 } 95 96 func (*PointerDeref) depthCheck() (npop, npush int) { return 1, 1 } 97 98 // Unary applies the given unary operator to the topmost stack variable. 99 type Unary struct { 100 Node *ast.UnaryExpr 101 } 102 103 func (*Unary) depthCheck() (npop, npush int) { return 1, 1 } 104 105 // AddrOf replaces the topmost stack variable v with &v. 106 type AddrOf struct { 107 Node *ast.UnaryExpr 108 } 109 110 func (*AddrOf) depthCheck() (npop, npush int) { return 1, 1 } 111 112 // TypeCast replaces the topmost stack variable v with (DwarfType)(v). 113 type TypeCast struct { 114 DwarfType godwarf.Type 115 Node *ast.CallExpr 116 } 117 118 func (*TypeCast) depthCheck() (npop, npush int) { return 1, 1 } 119 120 // Reslice implements a reslice operation. 121 // If HasHigh is set it pops three variables, low, high and v, and pushes 122 // v[low:high]. 123 // Otherwise it pops two variables, low and v, and pushes v[low:]. 124 // If TrustLen is set when the variable resulting from the reslice is loaded it will be fully loaded. 125 type Reslice struct { 126 HasHigh bool 127 TrustLen bool 128 Node *ast.SliceExpr 129 } 130 131 func (op *Reslice) depthCheck() (npop, npush int) { 132 if op.HasHigh { 133 return 3, 1 134 } else { 135 return 2, 1 136 } 137 } 138 139 // Index pops two variables, idx and v, and pushes v[idx]. 140 type Index struct { 141 Node *ast.IndexExpr 142 } 143 144 func (*Index) depthCheck() (npop, npush int) { return 2, 1 } 145 146 // Jump looks at the topmost stack variable and if it satisfies the 147 // condition specified by When it jumps to the stack machine instruction at 148 // Target+1. 149 // If Pop is set the topmost stack variable is also popped. 150 type Jump struct { 151 When JumpCond 152 Pop bool 153 Target int 154 Node ast.Expr 155 } 156 157 func (jmpif *Jump) depthCheck() (npop, npush int) { 158 if jmpif.Pop { 159 return 1, 0 160 } 161 return 0, 0 162 } 163 164 // JumpCond specifies a condition for the Jump instruction. 165 type JumpCond uint8 166 167 const ( 168 JumpIfFalse JumpCond = iota 169 JumpIfTrue 170 JumpIfAllocStringChecksFail 171 ) 172 173 // Binary pops two variables from the stack, applies the specified binary 174 // operator to them and pushes the result back on the stack. 175 type Binary struct { 176 Node *ast.BinaryExpr 177 } 178 179 func (*Binary) depthCheck() (npop, npush int) { return 2, 1 } 180 181 // BoolToConst pops the topmost variable from the stack, which must be a 182 // boolean variable, and converts it to a constant. 183 type BoolToConst struct { 184 } 185 186 func (*BoolToConst) depthCheck() (npop, npush int) { return 1, 1 } 187 188 // Pop removes the topmost variable from the stack. 189 type Pop struct { 190 } 191 192 func (*Pop) depthCheck() (npop, npush int) { return 1, 0 } 193 194 // BuiltinCall pops len(Args) argument from the stack, calls the specified 195 // builtin on them and pushes the result back on the stack. 196 type BuiltinCall struct { 197 Name string 198 Args []ast.Expr 199 } 200 201 func (bc *BuiltinCall) depthCheck() (npop, npush int) { 202 return len(bc.Args), 1 203 } 204 205 // CallInjectionStart starts call injection by calling 206 // runtime.debugCallVn. 207 type CallInjectionStart struct { 208 id int // identifier for all the call injection instructions that belong to the same sequence, this only exists to make reading listings easier 209 HasFunc bool // target function already pushed on the stack 210 Node *ast.CallExpr 211 } 212 213 func (*CallInjectionStart) depthCheck() (npop, npush int) { return 0, 1 } 214 215 // CallInjectionSetTarget starts the call injection, after 216 // runtime.debugCallVn set up the stack for us, by copying the entry point 217 // of the function, setting the closure register and copying the receiver. 218 type CallInjectionSetTarget struct { 219 id int 220 } 221 222 func (*CallInjectionSetTarget) depthCheck() (npop, npush int) { return 1, 0 } 223 224 // CallInjectionCopyArg copies one argument for call injection. 225 type CallInjectionCopyArg struct { 226 id int 227 ArgNum int 228 ArgExpr ast.Expr 229 } 230 231 func (*CallInjectionCopyArg) depthCheck() (npop, npush int) { return 1, 0 } 232 233 // CallInjectionComplete resumes target execution so that the injected call can run. 234 type CallInjectionComplete struct { 235 id int 236 } 237 238 func (*CallInjectionComplete) depthCheck() (npop, npush int) { return 0, 1 } 239 240 // CallInjectionStartSpecial starts call injection for a function with a 241 // name and arguments known at compile time. 242 type CallInjectionStartSpecial struct { 243 id int 244 FnName string 245 ArgAst []ast.Expr 246 } 247 248 func (*CallInjectionStartSpecial) depthCheck() (npop, npush int) { return 0, 1 } 249 250 // ConvertAllocToString pops two variables from the stack, a constant string 251 // and the return value of runtime.mallocgc (mallocv), copies the contents 252 // of the string at the address in mallocv and pushes on the stack a new 253 // string value that uses the backing storage of mallocv. 254 type ConvertAllocToString struct { 255 } 256 257 func (*ConvertAllocToString) depthCheck() (npop, npush int) { return 2, 1 } 258 259 // SetValue pops to variables from the stack, lhv and rhv, and sets lhv to 260 // rhv. 261 type SetValue struct { 262 lhe, Rhe ast.Expr 263 } 264 265 func (*SetValue) depthCheck() (npop, npush int) { return 2, 0 }