From 643d816c8b4348850a8a2a622d73256beea104cd Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Mon, 5 Feb 2024 16:38:41 -0500 Subject: 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 Auto-Submit: Alan Donovan Reviewed-by: Cherry Mui --- src/runtime/traceback.go | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'src/runtime/traceback.go') 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") -- cgit v1.3-5-g9baa