aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/traceback.go
diff options
context:
space:
mode:
authorAlan Donovan <adonovan@google.com>2024-02-05 16:38:41 -0500
committerAlan Donovan <adonovan@google.com>2024-02-08 21:44:52 +0000
commit643d816c8b4348850a8a2a622d73256beea104cd (patch)
tree31c78b014701c6ea5f275873ce9d20106d7f3508 /src/runtime/traceback.go
parent08370dcd9af8122956fc3ab024889c5357fffd5a (diff)
downloadgo-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.go24
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")