github.com/undoio/delve@v1.9.0/pkg/dwarf/op/op.go (about) 1 package op 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "errors" 7 "fmt" 8 "io" 9 10 "github.com/undoio/delve/pkg/dwarf/util" 11 ) 12 13 // Opcode represent a DWARF stack program instruction. 14 // See ./opcodes.go for a full list. 15 type Opcode byte 16 17 //go:generate go run ../../../_scripts/gen-opcodes.go opcodes.table opcodes.go 18 19 type stackfn func(Opcode, *context) error 20 21 type ReadMemoryFunc func([]byte, uint64) (int, error) 22 23 type context struct { 24 buf *bytes.Buffer 25 prog []byte 26 stack []int64 27 pieces []Piece 28 ptrSize int 29 30 DwarfRegisters 31 readMemory ReadMemoryFunc 32 } 33 34 // Piece is a piece of memory stored either at an address or in a register. 35 type Piece struct { 36 Size int 37 Kind PieceKind 38 Val uint64 39 Bytes []byte 40 } 41 42 // PieceKind describes the kind of a piece. 43 type PieceKind uint8 44 45 const ( 46 AddrPiece PieceKind = iota // The piece is stored in memory, Val is the address 47 RegPiece // The piece is stored in a register, Val is the register number 48 ImmPiece // The piece is an immediate value, Val or Bytes is the value 49 ) 50 51 var ( 52 ErrStackUnderflow = errors.New("DWARF stack underflow") 53 ErrStackIndexOutOfBounds = errors.New("DWARF stack index out of bounds") 54 ErrMemoryReadUnavailable = errors.New("memory read unavailable") 55 ) 56 57 const arbitraryExecutionLimitFactor = 10 58 59 // ExecuteStackProgram executes a DWARF location expression and returns 60 // either an address (int64), or a slice of Pieces for location expressions 61 // that don't evaluate to an address (such as register and composite expressions). 62 func ExecuteStackProgram(regs DwarfRegisters, instructions []byte, ptrSize int, readMemory ReadMemoryFunc) (int64, []Piece, error) { 63 ctxt := &context{ 64 buf: bytes.NewBuffer(instructions), 65 prog: instructions, 66 stack: make([]int64, 0, 3), 67 DwarfRegisters: regs, 68 ptrSize: ptrSize, 69 } 70 71 for tick := 0; tick < len(instructions)*arbitraryExecutionLimitFactor; tick++ { 72 opcodeByte, err := ctxt.buf.ReadByte() 73 if err != nil { 74 break 75 } 76 opcode := Opcode(opcodeByte) 77 if opcode == DW_OP_nop { 78 continue 79 } 80 fn, ok := oplut[opcode] 81 if !ok { 82 return 0, nil, fmt.Errorf("invalid instruction %#v", opcode) 83 } 84 85 err = fn(opcode, ctxt) 86 if err != nil { 87 return 0, nil, err 88 } 89 } 90 91 if ctxt.pieces != nil { 92 if len(ctxt.pieces) == 1 && ctxt.pieces[0].Kind == RegPiece { 93 return int64(regs.Uint64Val(ctxt.pieces[0].Val)), ctxt.pieces, nil 94 } 95 return 0, ctxt.pieces, nil 96 } 97 98 if len(ctxt.stack) == 0 { 99 return 0, nil, errors.New("empty OP stack") 100 } 101 102 return ctxt.stack[len(ctxt.stack)-1], nil, nil 103 } 104 105 // PrettyPrint prints the DWARF stack program instructions to `out`. 106 func PrettyPrint(out io.Writer, instructions []byte) { 107 in := bytes.NewBuffer(instructions) 108 109 for { 110 opcode, err := in.ReadByte() 111 if err != nil { 112 break 113 } 114 if name, hasname := opcodeName[Opcode(opcode)]; hasname { 115 io.WriteString(out, name) 116 out.Write([]byte{' '}) 117 } else { 118 fmt.Fprintf(out, "%#x ", opcode) 119 } 120 for _, arg := range opcodeArgs[Opcode(opcode)] { 121 switch arg { 122 case 's': 123 n, _ := util.DecodeSLEB128(in) 124 fmt.Fprintf(out, "%#x ", n) 125 case 'u': 126 n, _ := util.DecodeULEB128(in) 127 fmt.Fprintf(out, "%#x ", n) 128 case '1': 129 var x uint8 130 binary.Read(in, binary.LittleEndian, &x) 131 fmt.Fprintf(out, "%#x ", x) 132 case '2': 133 var x uint16 134 binary.Read(in, binary.LittleEndian, &x) 135 fmt.Fprintf(out, "%#x ", x) 136 case '4': 137 var x uint32 138 binary.Read(in, binary.LittleEndian, &x) 139 fmt.Fprintf(out, "%#x ", x) 140 case '8': 141 var x uint64 142 binary.Read(in, binary.LittleEndian, &x) 143 fmt.Fprintf(out, "%#x ", x) 144 case 'B': 145 sz, _ := util.DecodeULEB128(in) 146 data := make([]byte, sz) 147 sz2, _ := in.Read(data) 148 data = data[:sz2] 149 fmt.Fprintf(out, "%d [%x] ", sz, data) 150 } 151 } 152 } 153 } 154 155 // closeLoc is called by opcodes that can only appear at the end of a 156 // location expression (DW_OP_regN, DW_OP_regx, DW_OP_stack_value...). 157 // It checks that we are at the end of the program or that the following 158 // opcode is DW_OP_piece or DW_OP_bit_piece and processes them. 159 func (ctxt *context) closeLoc(opcode0 Opcode, piece Piece) error { 160 if ctxt.buf.Len() == 0 { 161 ctxt.pieces = append(ctxt.pieces, piece) 162 return nil 163 } 164 165 // DWARF doesn't say what happens to the operand stack at the end of a 166 // location expression, resetting it here. 167 ctxt.stack = ctxt.stack[:0] 168 169 b, err := ctxt.buf.ReadByte() 170 if err != nil { 171 return err 172 } 173 opcode := Opcode(b) 174 175 switch opcode { 176 case DW_OP_piece: 177 sz, _ := util.DecodeULEB128(ctxt.buf) 178 piece.Size = int(sz) 179 ctxt.pieces = append(ctxt.pieces, piece) 180 return nil 181 182 case DW_OP_bit_piece: 183 // not supported 184 return fmt.Errorf("invalid instruction %#v", opcode) 185 default: 186 return fmt.Errorf("invalid instruction %#v after %#v", opcode, opcode0) 187 } 188 } 189 190 func callframecfa(opcode Opcode, ctxt *context) error { 191 if ctxt.CFA == 0 { 192 return errors.New("could not retrieve CFA for current PC") 193 } 194 ctxt.stack = append(ctxt.stack, int64(ctxt.CFA)) 195 return nil 196 } 197 198 func addr(opcode Opcode, ctxt *context) error { 199 buf := ctxt.buf.Next(ctxt.ptrSize) 200 stack, err := util.ReadUintRaw(bytes.NewReader(buf), binary.LittleEndian, ctxt.ptrSize) 201 if err != nil { 202 return err 203 } 204 ctxt.stack = append(ctxt.stack, int64(stack+ctxt.StaticBase)) 205 return nil 206 } 207 208 func plusuconsts(opcode Opcode, ctxt *context) error { 209 slen := len(ctxt.stack) 210 num, _ := util.DecodeULEB128(ctxt.buf) 211 ctxt.stack[slen-1] = ctxt.stack[slen-1] + int64(num) 212 return nil 213 } 214 215 func consts(opcode Opcode, ctxt *context) error { 216 num, _ := util.DecodeSLEB128(ctxt.buf) 217 ctxt.stack = append(ctxt.stack, num) 218 return nil 219 } 220 221 func framebase(opcode Opcode, ctxt *context) error { 222 num, _ := util.DecodeSLEB128(ctxt.buf) 223 ctxt.stack = append(ctxt.stack, ctxt.FrameBase+num) 224 return nil 225 } 226 227 func register(opcode Opcode, ctxt *context) error { 228 var regnum uint64 229 if opcode == DW_OP_regx { 230 regnum, _ = util.DecodeULEB128(ctxt.buf) 231 } else { 232 regnum = uint64(opcode - DW_OP_reg0) 233 } 234 return ctxt.closeLoc(opcode, Piece{Kind: RegPiece, Val: regnum}) 235 } 236 237 func bregister(opcode Opcode, ctxt *context) error { 238 var regnum uint64 239 if opcode == DW_OP_bregx { 240 regnum, _ = util.DecodeULEB128(ctxt.buf) 241 } else { 242 regnum = uint64(opcode - DW_OP_breg0) 243 } 244 offset, _ := util.DecodeSLEB128(ctxt.buf) 245 if ctxt.Reg(regnum) == nil { 246 return fmt.Errorf("register %d not available", regnum) 247 } 248 ctxt.stack = append(ctxt.stack, int64(ctxt.Uint64Val(regnum))+offset) 249 return nil 250 } 251 252 func piece(opcode Opcode, ctxt *context) error { 253 sz, _ := util.DecodeULEB128(ctxt.buf) 254 255 if len(ctxt.stack) == 0 { 256 // nothing on the stack means this piece is unavailable (padding, 257 // optimized away...), see DWARFv4 sec. 2.6.1.3 page 30. 258 ctxt.pieces = append(ctxt.pieces, Piece{Size: int(sz), Kind: ImmPiece, Val: 0}) 259 return nil 260 } 261 262 addr := ctxt.stack[len(ctxt.stack)-1] 263 ctxt.pieces = append(ctxt.pieces, Piece{Size: int(sz), Kind: AddrPiece, Val: uint64(addr)}) 264 ctxt.stack = ctxt.stack[:0] 265 return nil 266 } 267 268 func literal(opcode Opcode, ctxt *context) error { 269 ctxt.stack = append(ctxt.stack, int64(opcode-DW_OP_lit0)) 270 return nil 271 } 272 273 func constnu(opcode Opcode, ctxt *context) error { 274 var ( 275 n uint64 276 err error 277 ) 278 switch opcode { 279 case DW_OP_const1u: 280 var b uint8 281 b, err = ctxt.buf.ReadByte() 282 n = uint64(b) 283 case DW_OP_const2u: 284 n, err = util.ReadUintRaw(ctxt.buf, binary.LittleEndian, 2) 285 case DW_OP_const4u: 286 n, err = util.ReadUintRaw(ctxt.buf, binary.LittleEndian, 4) 287 case DW_OP_const8u: 288 n, err = util.ReadUintRaw(ctxt.buf, binary.LittleEndian, 8) 289 default: 290 panic("internal error") 291 } 292 if err != nil { 293 return err 294 } 295 ctxt.stack = append(ctxt.stack, int64(n)) 296 return nil 297 } 298 299 func constns(opcode Opcode, ctxt *context) error { 300 var ( 301 n uint64 302 err error 303 ) 304 switch opcode { 305 case DW_OP_const1s: 306 var b uint8 307 b, err = ctxt.buf.ReadByte() 308 n = uint64(int64(int8(b))) 309 case DW_OP_const2s: 310 n, err = util.ReadUintRaw(ctxt.buf, binary.LittleEndian, 2) 311 n = uint64(int64(int16(n))) 312 case DW_OP_const4s: 313 n, err = util.ReadUintRaw(ctxt.buf, binary.LittleEndian, 4) 314 n = uint64(int64(int32(n))) 315 case DW_OP_const8s: 316 n, err = util.ReadUintRaw(ctxt.buf, binary.LittleEndian, 8) 317 default: 318 panic("internal error") 319 } 320 if err != nil { 321 return err 322 } 323 ctxt.stack = append(ctxt.stack, int64(n)) 324 return nil 325 } 326 327 func constu(opcode Opcode, ctxt *context) error { 328 num, _ := util.DecodeULEB128(ctxt.buf) 329 ctxt.stack = append(ctxt.stack, int64(num)) 330 return nil 331 } 332 333 func dup(_ Opcode, ctxt *context) error { 334 if len(ctxt.stack) <= 0 { 335 return ErrStackUnderflow 336 } 337 ctxt.stack = append(ctxt.stack, ctxt.stack[len(ctxt.stack)-1]) 338 return nil 339 } 340 341 func drop(_ Opcode, ctxt *context) error { 342 if len(ctxt.stack) <= 0 { 343 return ErrStackUnderflow 344 } 345 ctxt.stack = ctxt.stack[:len(ctxt.stack)-1] 346 return nil 347 } 348 349 func pick(opcode Opcode, ctxt *context) error { 350 var n byte 351 switch opcode { 352 case DW_OP_pick: 353 n, _ = ctxt.buf.ReadByte() 354 case DW_OP_over: 355 n = 1 356 default: 357 panic("internal error") 358 } 359 idx := len(ctxt.stack) - 1 - int(uint8(n)) 360 if idx < 0 || idx >= len(ctxt.stack) { 361 return ErrStackIndexOutOfBounds 362 } 363 ctxt.stack = append(ctxt.stack, ctxt.stack[idx]) 364 return nil 365 } 366 367 func swap(_ Opcode, ctxt *context) error { 368 if len(ctxt.stack) < 2 { 369 return ErrStackUnderflow 370 } 371 ctxt.stack[len(ctxt.stack)-1], ctxt.stack[len(ctxt.stack)-2] = ctxt.stack[len(ctxt.stack)-2], ctxt.stack[len(ctxt.stack)-1] 372 return nil 373 } 374 375 func rot(_ Opcode, ctxt *context) error { 376 if len(ctxt.stack) < 3 { 377 return ErrStackUnderflow 378 } 379 ctxt.stack[len(ctxt.stack)-1], ctxt.stack[len(ctxt.stack)-2], ctxt.stack[len(ctxt.stack)-3] = ctxt.stack[len(ctxt.stack)-2], ctxt.stack[len(ctxt.stack)-3], ctxt.stack[len(ctxt.stack)-1] 380 return nil 381 } 382 383 func unaryop(opcode Opcode, ctxt *context) error { 384 if len(ctxt.stack) < 1 { 385 return ErrStackUnderflow 386 } 387 operand := ctxt.stack[len(ctxt.stack)-1] 388 switch opcode { 389 case DW_OP_abs: 390 if operand < 0 { 391 operand = -operand 392 } 393 case DW_OP_neg: 394 operand = -operand 395 case DW_OP_not: 396 operand = ^operand 397 default: 398 panic("internal error") 399 } 400 ctxt.stack[len(ctxt.stack)-1] = operand 401 return nil 402 } 403 404 func binaryop(opcode Opcode, ctxt *context) error { 405 if len(ctxt.stack) < 2 { 406 return ErrStackUnderflow 407 } 408 second := ctxt.stack[len(ctxt.stack)-2] 409 top := ctxt.stack[len(ctxt.stack)-1] 410 var r int64 411 ctxt.stack = ctxt.stack[:len(ctxt.stack)-2] 412 switch opcode { 413 case DW_OP_and: 414 r = second & top 415 case DW_OP_div: 416 r = second / top 417 case DW_OP_minus: 418 r = second - top 419 case DW_OP_mod: 420 r = second % top 421 case DW_OP_mul: 422 r = second * top 423 case DW_OP_or: 424 r = second | top 425 case DW_OP_plus: 426 r = second + top 427 case DW_OP_shl: 428 r = second << uint64(top) 429 case DW_OP_shr: 430 r = second >> uint64(top) 431 case DW_OP_shra: 432 r = int64(uint64(second) >> uint64(top)) 433 case DW_OP_xor: 434 r = second ^ top 435 case DW_OP_le: 436 r = bool2int(second <= top) 437 case DW_OP_ge: 438 r = bool2int(second >= top) 439 case DW_OP_eq: 440 r = bool2int(second == top) 441 case DW_OP_lt: 442 r = bool2int(second < top) 443 case DW_OP_gt: 444 r = bool2int(second > top) 445 case DW_OP_ne: 446 r = bool2int(second != top) 447 default: 448 panic("internal error") 449 } 450 ctxt.stack = append(ctxt.stack, r) 451 return nil 452 } 453 454 func bool2int(b bool) int64 { 455 if b { 456 return 1 457 } 458 return 0 459 } 460 461 func (ctxt *context) jump(n int16) error { 462 i := len(ctxt.prog) - ctxt.buf.Len() + int(n) 463 if i < 0 { 464 return ErrStackUnderflow 465 } 466 if i >= len(ctxt.prog) { 467 i = len(ctxt.prog) 468 } 469 ctxt.buf = bytes.NewBuffer(ctxt.prog[i:]) 470 return nil 471 } 472 473 func skip(_ Opcode, ctxt *context) error { 474 var n int16 475 binary.Read(ctxt.buf, binary.LittleEndian, &n) 476 return ctxt.jump(n) 477 } 478 479 func bra(_ Opcode, ctxt *context) error { 480 var n int16 481 binary.Read(ctxt.buf, binary.LittleEndian, &n) 482 483 if len(ctxt.stack) < 1 { 484 return ErrStackUnderflow 485 } 486 top := ctxt.stack[len(ctxt.stack)-1] 487 ctxt.stack = ctxt.stack[:len(ctxt.stack)-1] 488 if top != 0 { 489 return ctxt.jump(n) 490 } 491 return nil 492 } 493 494 func stackvalue(_ Opcode, ctxt *context) error { 495 if len(ctxt.stack) < 1 { 496 return ErrStackUnderflow 497 } 498 val := ctxt.stack[len(ctxt.stack)-1] 499 ctxt.stack = ctxt.stack[:len(ctxt.stack)-1] 500 return ctxt.closeLoc(DW_OP_stack_value, Piece{Kind: ImmPiece, Val: uint64(val)}) 501 } 502 503 func implicitvalue(_ Opcode, ctxt *context) error { 504 sz, _ := util.DecodeULEB128(ctxt.buf) 505 block := make([]byte, sz) 506 n, _ := ctxt.buf.Read(block) 507 if uint64(n) != sz { 508 return fmt.Errorf("insufficient bytes read while reading DW_OP_implicit_value's block %d (expected: %d)", n, sz) 509 } 510 return ctxt.closeLoc(DW_OP_implicit_value, Piece{Kind: ImmPiece, Bytes: block, Size: int(sz)}) 511 } 512 513 func deref(op Opcode, ctxt *context) error { 514 if ctxt.readMemory == nil { 515 return ErrMemoryReadUnavailable 516 } 517 518 sz := ctxt.ptrSize 519 if op == DW_OP_deref_size || op == DW_OP_xderef_size { 520 n, err := ctxt.buf.ReadByte() 521 if err != nil { 522 return err 523 } 524 sz = int(n) 525 } 526 527 if len(ctxt.stack) <= 0 { 528 return ErrStackUnderflow 529 } 530 531 addr := ctxt.stack[len(ctxt.stack)-1] 532 ctxt.stack = ctxt.stack[:len(ctxt.stack)-1] 533 534 if op == DW_OP_xderef || op == DW_OP_xderef_size { 535 if len(ctxt.stack) <= 0 { 536 return ErrStackUnderflow 537 } 538 // the second element on the stack is the "address space identifier" which we don't do anything with 539 ctxt.stack = ctxt.stack[:len(ctxt.stack)-1] 540 } 541 542 buf := make([]byte, sz) 543 _, err := ctxt.readMemory(buf, uint64(addr)) 544 if err != nil { 545 return err 546 } 547 548 x, err := util.ReadUintRaw(bytes.NewReader(buf), binary.LittleEndian, sz) 549 if err != nil { 550 return err 551 } 552 553 ctxt.stack = append(ctxt.stack, int64(x)) 554 555 return nil 556 }