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