github.com/undoio/delve@v1.9.0/pkg/proc/stack.go (about) 1 package proc 2 3 import ( 4 "debug/dwarf" 5 "errors" 6 "fmt" 7 "go/constant" 8 "reflect" 9 10 "github.com/undoio/delve/pkg/dwarf/frame" 11 "github.com/undoio/delve/pkg/dwarf/op" 12 "github.com/undoio/delve/pkg/dwarf/reader" 13 ) 14 15 // This code is partly adapted from runtime.gentraceback in 16 // $GOROOT/src/runtime/traceback.go 17 18 // Stackframe represents a frame in a system stack. 19 // 20 // Each stack frame has two locations Current and Call. 21 // 22 // For the topmost stackframe Current and Call are the same location. 23 // 24 // For stackframes after the first Current is the location corresponding to 25 // the return address and Call is the location of the CALL instruction that 26 // was last executed on the frame. Note however that Call.PC is always equal 27 // to Current.PC, because finding the correct value for Call.PC would 28 // require disassembling each function in the stacktrace. 29 // 30 // For synthetic stackframes generated for inlined function calls Current.Fn 31 // is the function containing the inlining and Call.Fn in the inlined 32 // function. 33 type Stackframe struct { 34 Current, Call Location 35 36 // Frame registers. 37 Regs op.DwarfRegisters 38 // High address of the stack. 39 stackHi uint64 40 // Return address for this stack frame (as read from the stack frame itself). 41 Ret uint64 42 // Address to the memory location containing the return address 43 addrret uint64 44 // Err is set if an error occurred during stacktrace 45 Err error 46 // SystemStack is true if this frame belongs to a system stack. 47 SystemStack bool 48 // Inlined is true if this frame is actually an inlined call. 49 Inlined bool 50 // Bottom is true if this is the bottom of the stack 51 Bottom bool 52 53 // lastpc is a memory address guaranteed to belong to the last instruction 54 // executed in this stack frame. 55 // For the topmost stack frame this will be the same as Current.PC and 56 // Call.PC, for other stack frames it will usually be Current.PC-1, but 57 // could be different when inlined calls are involved in the stacktrace. 58 // Note that this address isn't guaranteed to belong to the start of an 59 // instruction and, for this reason, should not be propagated outside of 60 // pkg/proc. 61 // Use this value to determine active lexical scopes for the stackframe. 62 lastpc uint64 63 64 // TopmostDefer is the defer that would be at the top of the stack when a 65 // panic unwind would get to this call frame, in other words it's the first 66 // deferred function that will be called if the runtime unwinds past this 67 // call frame. 68 TopmostDefer *Defer 69 70 // Defers is the list of functions deferred by this stack frame (so far). 71 Defers []*Defer 72 } 73 74 // FrameOffset returns the address of the stack frame, absolute for system 75 // stack frames or as an offset from stackhi for goroutine stacks (a 76 // negative value). 77 func (frame *Stackframe) FrameOffset() int64 { 78 if frame.SystemStack { 79 return frame.Regs.CFA 80 } 81 return frame.Regs.CFA - int64(frame.stackHi) 82 } 83 84 // FramePointerOffset returns the value of the frame pointer, absolute for 85 // system stack frames or as an offset from stackhi for goroutine stacks (a 86 // negative value). 87 func (frame *Stackframe) FramePointerOffset() int64 { 88 if frame.SystemStack { 89 return int64(frame.Regs.BP()) 90 } 91 return int64(frame.Regs.BP()) - int64(frame.stackHi) 92 } 93 94 // ThreadStacktrace returns the stack trace for thread. 95 // Note the locations in the array are return addresses not call addresses. 96 func ThreadStacktrace(thread Thread, depth int) ([]Stackframe, error) { 97 g, _ := GetG(thread) 98 if g == nil { 99 regs, err := thread.Registers() 100 if err != nil { 101 return nil, err 102 } 103 so := thread.BinInfo().PCToImage(regs.PC()) 104 dwarfRegs := *(thread.BinInfo().Arch.RegistersToDwarfRegisters(so.StaticBase, regs)) 105 dwarfRegs.ChangeFunc = thread.SetReg 106 it := newStackIterator(thread.BinInfo(), thread.ProcessMemory(), dwarfRegs, 0, nil, 0) 107 return it.stacktrace(depth) 108 } 109 return g.Stacktrace(depth, 0) 110 } 111 112 func (g *G) stackIterator(opts StacktraceOptions) (*stackIterator, error) { 113 bi := g.variable.bi 114 if g.Thread != nil { 115 regs, err := g.Thread.Registers() 116 if err != nil { 117 return nil, err 118 } 119 so := bi.PCToImage(regs.PC()) 120 dwarfRegs := *(bi.Arch.RegistersToDwarfRegisters(so.StaticBase, regs)) 121 dwarfRegs.ChangeFunc = g.Thread.SetReg 122 return newStackIterator( 123 bi, g.variable.mem, 124 dwarfRegs, 125 g.stack.hi, g, opts), nil 126 } 127 so := g.variable.bi.PCToImage(g.PC) 128 return newStackIterator( 129 bi, g.variable.mem, 130 bi.Arch.addrAndStackRegsToDwarfRegisters(so.StaticBase, g.PC, g.SP, g.BP, g.LR), 131 g.stack.hi, g, opts), nil 132 } 133 134 type StacktraceOptions uint16 135 136 const ( 137 // StacktraceReadDefers requests a stacktrace decorated with deferred calls 138 // for each frame. 139 StacktraceReadDefers StacktraceOptions = 1 << iota 140 141 // StacktraceSimple requests a stacktrace where no stack switches will be 142 // attempted. 143 StacktraceSimple 144 145 // StacktraceG requests a stacktrace starting with the register 146 // values saved in the runtime.g structure. 147 StacktraceG 148 ) 149 150 // Stacktrace returns the stack trace for a goroutine. 151 // Note the locations in the array are return addresses not call addresses. 152 func (g *G) Stacktrace(depth int, opts StacktraceOptions) ([]Stackframe, error) { 153 it, err := g.stackIterator(opts) 154 if err != nil { 155 return nil, err 156 } 157 frames, err := it.stacktrace(depth) 158 if err != nil { 159 return nil, err 160 } 161 if opts&StacktraceReadDefers != 0 { 162 g.readDefers(frames) 163 } 164 return frames, nil 165 } 166 167 // NullAddrError is an error for a null address. 168 type NullAddrError struct{} 169 170 func (n NullAddrError) Error() string { 171 return "NULL address" 172 } 173 174 // stackIterator holds information 175 // required to iterate and walk the program 176 // stack. 177 type stackIterator struct { 178 pc uint64 179 top bool 180 atend bool 181 frame Stackframe 182 bi *BinaryInfo 183 mem MemoryReadWriter 184 err error 185 186 stackhi uint64 187 systemstack bool 188 189 // regs is the register set for the current frame 190 regs op.DwarfRegisters 191 192 g *G // the goroutine being stacktraced, nil if we are stacktracing a goroutine-less thread 193 g0_sched_sp uint64 // value of g0.sched.sp (see comments around its use) 194 g0_sched_sp_loaded bool // g0_sched_sp was loaded from g0 195 196 opts StacktraceOptions 197 } 198 199 func newStackIterator(bi *BinaryInfo, mem MemoryReadWriter, regs op.DwarfRegisters, stackhi uint64, g *G, opts StacktraceOptions) *stackIterator { 200 systemstack := true 201 if g != nil { 202 systemstack = g.SystemStack 203 } 204 return &stackIterator{pc: regs.PC(), regs: regs, top: true, bi: bi, mem: mem, err: nil, atend: false, stackhi: stackhi, systemstack: systemstack, g: g, opts: opts} 205 } 206 207 // Next points the iterator to the next stack frame. 208 func (it *stackIterator) Next() bool { 209 if it.err != nil || it.atend { 210 return false 211 } 212 213 callFrameRegs, ret, retaddr := it.advanceRegs() 214 it.frame = it.newStackframe(ret, retaddr) 215 216 if it.opts&StacktraceSimple == 0 { 217 if it.bi.Arch.switchStack(it, &callFrameRegs) { 218 return true 219 } 220 } 221 222 if it.frame.Ret <= 0 { 223 it.atend = true 224 return true 225 } 226 227 it.top = false 228 it.pc = it.frame.Ret 229 it.regs = callFrameRegs 230 return true 231 } 232 233 func (it *stackIterator) switchToGoroutineStack() { 234 it.systemstack = false 235 it.top = false 236 it.pc = it.g.PC 237 it.regs.Reg(it.regs.SPRegNum).Uint64Val = it.g.SP 238 it.regs.AddReg(it.regs.BPRegNum, op.DwarfRegisterFromUint64(it.g.BP)) 239 if it.bi.Arch.Name == "arm64" { 240 it.regs.Reg(it.regs.LRRegNum).Uint64Val = it.g.LR 241 } 242 } 243 244 // Frame returns the frame the iterator is pointing at. 245 func (it *stackIterator) Frame() Stackframe { 246 it.frame.Bottom = it.atend 247 return it.frame 248 } 249 250 // Err returns the error encountered during stack iteration. 251 func (it *stackIterator) Err() error { 252 return it.err 253 } 254 255 // frameBase calculates the frame base pseudo-register for DWARF for fn and 256 // the current frame. 257 func (it *stackIterator) frameBase(fn *Function) int64 { 258 dwarfTree, err := fn.cu.image.getDwarfTree(fn.offset) 259 if err != nil { 260 return 0 261 } 262 fb, _, _, _ := it.bi.Location(dwarfTree.Entry, dwarf.AttrFrameBase, it.pc, it.regs, it.mem) 263 return fb 264 } 265 266 func (it *stackIterator) newStackframe(ret, retaddr uint64) Stackframe { 267 if retaddr == 0 { 268 it.err = NullAddrError{} 269 return Stackframe{} 270 } 271 f, l, fn := it.bi.PCToLine(it.pc) 272 if fn == nil { 273 f = "?" 274 l = -1 275 } else { 276 it.regs.FrameBase = it.frameBase(fn) 277 } 278 r := Stackframe{Current: Location{PC: it.pc, File: f, Line: l, Fn: fn}, Regs: it.regs, Ret: ret, addrret: retaddr, stackHi: it.stackhi, SystemStack: it.systemstack, lastpc: it.pc} 279 if r.Regs.Reg(it.regs.PCRegNum) == nil { 280 r.Regs.AddReg(it.regs.PCRegNum, op.DwarfRegisterFromUint64(it.pc)) 281 } 282 r.Call = r.Current 283 if !it.top && r.Current.Fn != nil && it.pc != r.Current.Fn.Entry { 284 // if the return address is the entry point of the function that 285 // contains it then this is some kind of fake return frame (for example 286 // runtime.sigreturn) that didn't actually call the current frame, 287 // attempting to get the location of the CALL instruction would just 288 // obfuscate what's going on, since there is no CALL instruction. 289 switch r.Current.Fn.Name { 290 case "runtime.mstart", "runtime.systemstack_switch": 291 // these frames are inserted by runtime.systemstack and there is no CALL 292 // instruction to look for at pc - 1 293 default: 294 r.lastpc = it.pc - 1 295 r.Call.File, r.Call.Line = r.Current.Fn.cu.lineInfo.PCToLine(r.Current.Fn.Entry, it.pc-1) 296 } 297 } 298 return r 299 } 300 301 func (it *stackIterator) stacktrace(depth int) ([]Stackframe, error) { 302 if depth < 0 { 303 return nil, errors.New("negative maximum stack depth") 304 } 305 if it.opts&StacktraceG != 0 && it.g != nil { 306 it.switchToGoroutineStack() 307 it.top = true 308 } 309 frames := make([]Stackframe, 0, depth+1) 310 for it.Next() { 311 frames = it.appendInlineCalls(frames, it.Frame()) 312 if len(frames) >= depth+1 { 313 break 314 } 315 } 316 if err := it.Err(); err != nil { 317 if len(frames) == 0 { 318 return nil, err 319 } 320 frames = append(frames, Stackframe{Err: err}) 321 } 322 return frames, nil 323 } 324 325 func (it *stackIterator) appendInlineCalls(frames []Stackframe, frame Stackframe) []Stackframe { 326 if frame.Call.Fn == nil { 327 return append(frames, frame) 328 } 329 if frame.Call.Fn.cu.lineInfo == nil { 330 return append(frames, frame) 331 } 332 333 callpc := frame.Call.PC 334 if len(frames) > 0 { 335 callpc-- 336 } 337 338 dwarfTree, err := frame.Call.Fn.cu.image.getDwarfTree(frame.Call.Fn.offset) 339 if err != nil { 340 return append(frames, frame) 341 } 342 343 for _, entry := range reader.InlineStack(dwarfTree, callpc) { 344 fnname, okname := entry.Val(dwarf.AttrName).(string) 345 fileidx, okfileidx := entry.Val(dwarf.AttrCallFile).(int64) 346 line, okline := entry.Val(dwarf.AttrCallLine).(int64) 347 348 if !okname || !okfileidx || !okline { 349 break 350 } 351 var e *dwarf.Entry 352 filepath, fileErr := frame.Current.Fn.cu.filePath(int(fileidx), e) 353 if fileErr != nil { 354 break 355 } 356 357 inlfn := &Function{Name: fnname, Entry: frame.Call.Fn.Entry, End: frame.Call.Fn.End, offset: entry.Offset, cu: frame.Call.Fn.cu} 358 frames = append(frames, Stackframe{ 359 Current: frame.Current, 360 Call: Location{ 361 frame.Call.PC, 362 frame.Call.File, 363 frame.Call.Line, 364 inlfn, 365 }, 366 Regs: frame.Regs, 367 stackHi: frame.stackHi, 368 Ret: frame.Ret, 369 addrret: frame.addrret, 370 Err: frame.Err, 371 SystemStack: frame.SystemStack, 372 Inlined: true, 373 lastpc: frame.lastpc, 374 }) 375 376 frame.Call.File = filepath 377 frame.Call.Line = int(line) 378 } 379 380 return append(frames, frame) 381 } 382 383 // advanceRegs calculates the DwarfRegisters for a next stack frame 384 // (corresponding to it.pc). 385 // 386 // The computation uses the registers for the current stack frame (it.regs) and 387 // the corresponding Frame Descriptor Entry (FDE) retrieved from the DWARF info. 388 // 389 // The new set of registers is returned. it.regs is not updated, except for 390 // it.regs.CFA; the caller has to eventually switch it.regs when the iterator 391 // advances to the next frame. 392 func (it *stackIterator) advanceRegs() (callFrameRegs op.DwarfRegisters, ret uint64, retaddr uint64) { 393 fde, err := it.bi.frameEntries.FDEForPC(it.pc) 394 var framectx *frame.FrameContext 395 if _, nofde := err.(*frame.ErrNoFDEForPC); nofde { 396 framectx = it.bi.Arch.fixFrameUnwindContext(nil, it.pc, it.bi) 397 } else { 398 framectx = it.bi.Arch.fixFrameUnwindContext(fde.EstablishFrame(it.pc), it.pc, it.bi) 399 } 400 401 cfareg, err := it.executeFrameRegRule(0, framectx.CFA, 0) 402 if cfareg == nil { 403 it.err = fmt.Errorf("CFA becomes undefined at PC %#x: %v", it.pc, err) 404 return op.DwarfRegisters{}, 0, 0 405 } 406 it.regs.CFA = int64(cfareg.Uint64Val) 407 408 callimage := it.bi.PCToImage(it.pc) 409 410 callFrameRegs = op.DwarfRegisters{StaticBase: callimage.StaticBase, ByteOrder: it.regs.ByteOrder, PCRegNum: it.regs.PCRegNum, SPRegNum: it.regs.SPRegNum, BPRegNum: it.regs.BPRegNum, LRRegNum: it.regs.LRRegNum} 411 412 // According to the standard the compiler should be responsible for emitting 413 // rules for the RSP register so that it can then be used to calculate CFA, 414 // however neither Go nor GCC do this. 415 // In the following line we copy GDB's behaviour by assuming this is 416 // implicit. 417 // See also the comment in dwarf2_frame_default_init in 418 // $GDB_SOURCE/dwarf2-frame.c 419 callFrameRegs.AddReg(callFrameRegs.SPRegNum, cfareg) 420 421 for i, regRule := range framectx.Regs { 422 reg, err := it.executeFrameRegRule(i, regRule, it.regs.CFA) 423 callFrameRegs.AddReg(i, reg) 424 if i == framectx.RetAddrReg { 425 if reg == nil { 426 if err == nil { 427 //lint:ignore ST1005 backwards compatibility 428 err = fmt.Errorf("Undefined return address at %#x", it.pc) 429 } 430 it.err = err 431 } else { 432 ret = reg.Uint64Val 433 } 434 retaddr = uint64(it.regs.CFA + regRule.Offset) 435 } 436 } 437 438 if it.bi.Arch.Name == "arm64" { 439 if ret == 0 && it.regs.Reg(it.regs.LRRegNum) != nil { 440 ret = it.regs.Reg(it.regs.LRRegNum).Uint64Val 441 } 442 } 443 444 return callFrameRegs, ret, retaddr 445 } 446 447 func (it *stackIterator) executeFrameRegRule(regnum uint64, rule frame.DWRule, cfa int64) (*op.DwarfRegister, error) { 448 switch rule.Rule { 449 default: 450 fallthrough 451 case frame.RuleUndefined: 452 return nil, nil 453 case frame.RuleSameVal: 454 if it.regs.Reg(regnum) == nil { 455 return nil, nil 456 } 457 reg := *it.regs.Reg(regnum) 458 return ®, nil 459 case frame.RuleOffset: 460 return it.readRegisterAt(regnum, uint64(cfa+rule.Offset)) 461 case frame.RuleValOffset: 462 return op.DwarfRegisterFromUint64(uint64(cfa + rule.Offset)), nil 463 case frame.RuleRegister: 464 return it.regs.Reg(rule.Reg), nil 465 case frame.RuleExpression: 466 v, _, err := op.ExecuteStackProgram(it.regs, rule.Expression, it.bi.Arch.PtrSize(), it.mem.ReadMemory) 467 if err != nil { 468 return nil, err 469 } 470 return it.readRegisterAt(regnum, uint64(v)) 471 case frame.RuleValExpression: 472 v, _, err := op.ExecuteStackProgram(it.regs, rule.Expression, it.bi.Arch.PtrSize(), it.mem.ReadMemory) 473 if err != nil { 474 return nil, err 475 } 476 return op.DwarfRegisterFromUint64(uint64(v)), nil 477 case frame.RuleArchitectural: 478 return nil, errors.New("architectural frame rules are unsupported") 479 case frame.RuleCFA: 480 if it.regs.Reg(rule.Reg) == nil { 481 return nil, nil 482 } 483 return op.DwarfRegisterFromUint64(uint64(int64(it.regs.Uint64Val(rule.Reg)) + rule.Offset)), nil 484 case frame.RuleFramePointer: 485 curReg := it.regs.Reg(rule.Reg) 486 if curReg == nil { 487 return nil, nil 488 } 489 if curReg.Uint64Val <= uint64(cfa) { 490 return it.readRegisterAt(regnum, curReg.Uint64Val) 491 } 492 newReg := *curReg 493 return &newReg, nil 494 } 495 } 496 497 func (it *stackIterator) readRegisterAt(regnum uint64, addr uint64) (*op.DwarfRegister, error) { 498 buf := make([]byte, it.bi.Arch.regSize(regnum)) 499 _, err := it.mem.ReadMemory(buf, addr) 500 if err != nil { 501 return nil, err 502 } 503 return op.DwarfRegisterFromBytes(buf), nil 504 } 505 506 func (it *stackIterator) loadG0SchedSP() { 507 if it.g0_sched_sp_loaded { 508 return 509 } 510 it.g0_sched_sp_loaded = true 511 if it.g != nil { 512 mvar, _ := it.g.variable.structMember("m") 513 if mvar != nil { 514 g0var, _ := mvar.structMember("g0") 515 if g0var != nil { 516 g0, _ := g0var.parseG() 517 if g0 != nil { 518 it.g0_sched_sp = g0.SP 519 } 520 } 521 } 522 } 523 } 524 525 // Defer represents one deferred call 526 type Defer struct { 527 DwrapPC uint64 // PC of the deferred function or, in Go 1.17+ a wrapper to it 528 DeferPC uint64 // PC address of instruction that added this defer 529 SP uint64 // Value of SP register when this function was deferred (this field gets adjusted when the stack is moved to match the new stack space) 530 link *Defer // Next deferred function 531 argSz int64 // Always 0 in Go >=1.17 532 533 variable *Variable 534 Unreadable error 535 } 536 537 // readDefers decorates the frames with the function deferred at each stack frame. 538 func (g *G) readDefers(frames []Stackframe) { 539 curdefer := g.Defer() 540 i := 0 541 542 // scan simultaneously frames and the curdefer linked list, assigning 543 // defers to their associated frames. 544 for { 545 if curdefer == nil || i >= len(frames) { 546 return 547 } 548 if curdefer.Unreadable != nil { 549 // Current defer is unreadable, stick it into the first available frame 550 // (so that it can be reported to the user) and exit 551 frames[i].Defers = append(frames[i].Defers, curdefer) 552 return 553 } 554 if frames[i].Err != nil { 555 return 556 } 557 558 if frames[i].TopmostDefer == nil { 559 frames[i].TopmostDefer = curdefer 560 } 561 562 if frames[i].SystemStack || curdefer.SP >= uint64(frames[i].Regs.CFA) { 563 // frames[i].Regs.CFA is the value that SP had before the function of 564 // frames[i] was called. 565 // This means that when curdefer.SP == frames[i].Regs.CFA then curdefer 566 // was added by the previous frame. 567 // 568 // curdefer.SP < frames[i].Regs.CFA means curdefer was added by a 569 // function further down the stack. 570 // 571 // SystemStack frames live on a different physical stack and can't be 572 // compared with deferred frames. 573 i++ 574 } else { 575 frames[i].Defers = append(frames[i].Defers, curdefer) 576 curdefer = curdefer.Next() 577 } 578 } 579 } 580 581 func (d *Defer) load() { 582 v := d.variable // +rtype _defer 583 v.loadValue(LoadConfig{false, 1, 0, 0, -1, 0}) 584 if v.Unreadable != nil { 585 d.Unreadable = v.Unreadable 586 return 587 } 588 589 fnvar := v.fieldVariable("fn") 590 if fnvar.Kind == reflect.Func { 591 // In Go 1.18, fn is a func(). 592 d.DwrapPC = fnvar.Base 593 } else if val := fnvar.maybeDereference(); val.Addr != 0 { 594 // In Go <1.18, fn is a *funcval. 595 fnvar = fnvar.loadFieldNamed("fn") 596 if fnvar.Unreadable == nil { 597 d.DwrapPC, _ = constant.Uint64Val(fnvar.Value) 598 } 599 } 600 601 d.DeferPC, _ = constant.Uint64Val(v.fieldVariable("pc").Value) // +rtype uintptr 602 d.SP, _ = constant.Uint64Val(v.fieldVariable("sp").Value) // +rtype uintptr 603 sizVar := v.fieldVariable("siz") // +rtype -opt int32 604 if sizVar != nil { 605 // In Go <1.18, siz stores the number of bytes of 606 // defer arguments following the defer record. In Go 607 // 1.18, the defer record doesn't store arguments, so 608 // we leave this 0. 609 d.argSz, _ = constant.Int64Val(sizVar.Value) 610 } 611 612 linkvar := v.fieldVariable("link").maybeDereference() // +rtype *_defer 613 if linkvar.Addr != 0 { 614 d.link = &Defer{variable: linkvar} 615 } 616 } 617 618 // errSPDecreased is used when (*Defer).Next detects a corrupted linked 619 // list, specifically when after followin a link pointer the value of SP 620 // decreases rather than increasing or staying the same (the defer list is a 621 // FIFO list, nodes further down the list have been added by function calls 622 // further down the call stack and therefore the SP should always increase). 623 var errSPDecreased = errors.New("corrupted defer list: SP decreased") 624 625 // Next returns the next defer in the linked list 626 func (d *Defer) Next() *Defer { 627 if d.link == nil { 628 return nil 629 } 630 d.link.load() 631 if d.link.SP < d.SP { 632 d.link.Unreadable = errSPDecreased 633 } 634 return d.link 635 } 636 637 // EvalScope returns an EvalScope relative to the argument frame of this deferred call. 638 // The argument frame of a deferred call is stored in memory immediately 639 // after the deferred header. 640 func (d *Defer) EvalScope(t *Target, thread Thread) (*EvalScope, error) { 641 scope, err := GoroutineScope(t, thread) 642 if err != nil { 643 return nil, fmt.Errorf("could not get scope: %v", err) 644 } 645 646 bi := thread.BinInfo() 647 scope.PC = d.DwrapPC 648 scope.File, scope.Line, scope.Fn = bi.PCToLine(d.DwrapPC) 649 650 if scope.Fn == nil { 651 return nil, fmt.Errorf("could not find function at %#x", d.DwrapPC) 652 } 653 654 // The arguments are stored immediately after the defer header struct, i.e. 655 // addr+sizeof(_defer). 656 657 if !bi.Arch.usesLR { 658 // On architectures that don't have a link register CFA is always the address of the first 659 // argument, that's what we use for the value of CFA. 660 // For SP we use CFA minus the size of one pointer because that would be 661 // the space occupied by pushing the return address on the stack during the 662 // CALL. 663 scope.Regs.CFA = (int64(d.variable.Addr) + d.variable.RealType.Common().ByteSize) 664 scope.Regs.Reg(scope.Regs.SPRegNum).Uint64Val = uint64(scope.Regs.CFA - int64(bi.Arch.PtrSize())) 665 } else { 666 // On architectures that have a link register CFA and SP have the same 667 // value but the address of the first argument is at CFA+ptrSize so we set 668 // CFA to the start of the argument frame minus one pointer size. 669 scope.Regs.CFA = int64(d.variable.Addr) + d.variable.RealType.Common().ByteSize - int64(bi.Arch.PtrSize()) 670 scope.Regs.Reg(scope.Regs.SPRegNum).Uint64Val = uint64(scope.Regs.CFA) 671 } 672 673 rdr := scope.Fn.cu.image.dwarfReader 674 rdr.Seek(scope.Fn.offset) 675 e, err := rdr.Next() 676 if err != nil { 677 return nil, fmt.Errorf("could not read DWARF function entry: %v", err) 678 } 679 scope.Regs.FrameBase, _, _, _ = bi.Location(e, dwarf.AttrFrameBase, scope.PC, scope.Regs, scope.Mem) 680 scope.Mem = cacheMemory(scope.Mem, uint64(scope.Regs.CFA), int(d.argSz)) 681 682 return scope, nil 683 } 684 685 // DeferredFunc returns the deferred function, on Go 1.17 and later unwraps 686 // any defer wrapper. 687 func (d *Defer) DeferredFunc(p *Target) (file string, line int, fn *Function) { 688 bi := p.BinInfo() 689 fn = bi.PCToFunc(d.DwrapPC) 690 fn = p.dwrapUnwrap(fn) 691 if fn == nil { 692 return "", 0, nil 693 } 694 file, line = fn.cu.lineInfo.PCToLine(fn.Entry, fn.Entry) 695 return file, line, fn 696 }