diff options
| author | Alan Donovan <adonovan@google.com> | 2024-02-05 16:38:41 -0500 |
|---|---|---|
| committer | Alan Donovan <adonovan@google.com> | 2024-02-08 21:44:52 +0000 |
| commit | 643d816c8b4348850a8a2a622d73256beea104cd (patch) | |
| tree | 31c78b014701c6ea5f275873ce9d20106d7f3508 /src/runtime/traceback.go | |
| parent | 08370dcd9af8122956fc3ab024889c5357fffd5a (diff) | |
| download | go-643d816c8b4348850a8a2a622d73256beea104cd.tar.xz | |
runtime: traceback: include pc=0x%x for inline frames
Crash monitoring tools may parse the PC values and feed them
to CallersFrames, which does not run the inline unwinder, since
Callers already did so. So, the GOTRACEBACK=system output
must also include PC values even for inlined frames.
(The actual values are just marker NOP instructions,
but that isn't important.)
This CL also includes a test that the PC values can be
parsed out of the crash report and fed to CallersFrames
to yield a sensible result. (The logic is a distillation
of the x/telemetry crashmonitor.)
The previously printed PCs were in fact slightly wrong
for frames containing inlined calls: instead of the
virtual CALL instruction (a NOP) to the first
inlined call, it would display the PC of the
CALL in the innermost inlined function.
Change-Id: I64a06771fc191ba16c1383b8139b714f4f299703
Reviewed-on: https://go-review.googlesource.com/c/go/+/561635
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Alan Donovan <adonovan@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Diffstat (limited to 'src/runtime/traceback.go')
| -rw-r--r-- | src/runtime/traceback.go | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 1c75c447d2..61027ea89a 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -993,12 +993,24 @@ func traceback2(u *unwinder, showRuntime bool, skip, max int) (n, lastN int) { } print(")\n") print("\t", file, ":", line) - if !iu.isInlined(uf) { - if u.frame.pc > f.entry() { - print(" +", hex(u.frame.pc-f.entry())) - } - if gp.m != nil && gp.m.throwing >= throwTypeRuntime && gp == gp.m.curg || level >= 2 { - print(" fp=", hex(u.frame.fp), " sp=", hex(u.frame.sp), " pc=", hex(u.frame.pc)) + // The contract between Callers and CallersFrames uses + // return addresses, which are +1 relative to the CALL + // instruction. Follow that convention. + pc := uf.pc + 1 + if !iu.isInlined(uf) && pc > f.entry() { + // Func-relative PCs make no sense for inlined + // frames because there is no actual entry. + print(" +", hex(pc-f.entry())) + } + if gp.m != nil && gp.m.throwing >= throwTypeRuntime && gp == gp.m.curg || level >= 2 { + if !iu.isInlined(uf) { + // The stack information makes no sense for inline frames. + print(" fp=", hex(u.frame.fp), " sp=", hex(u.frame.sp), " pc=", hex(pc)) + } else { + // The PC for an inlined frame is a special marker NOP, + // but crash monitoring tools may still parse the PCs + // and feed them to CallersFrames. + print(" pc=", hex(pc)) } } print("\n") |
