Skip to content

Commit 781fd39

Browse files
committed
runtime: use inlining tables to generate accurate tracebacks
The code in https://play.golang.org/p/aYQPrTtzoK now produces the following stack trace: goroutine 1 [running]: main.(*point).negate(...) /tmp/go/main.go:8 main.main() /tmp/go/main.go:14 +0x23 Previously the stack trace missed the inlined call: goroutine 1 [running]: main.main() /tmp/go/main.go:14 +0x23 Fixes #10152. Updates #19348. Change-Id: Ib43c67012f53da0ef1a1e69bcafb65b57d9cecb2 Reviewed-on: https://go-review.googlesource.com/37233 Run-TryBot: David Lazar <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Austin Clements <[email protected]>
1 parent 1c6ef9a commit 781fd39

File tree

3 files changed

+69
-1
lines changed

3 files changed

+69
-1
lines changed

src/runtime/crash_test.go

+28
Original file line numberDiff line numberDiff line change
@@ -538,3 +538,31 @@ func TestConcurrentMapIterateWrite(t *testing.T) {
538538
t.Fatalf("output does not start with %q:\n%s", want, output)
539539
}
540540
}
541+
542+
type point struct {
543+
x, y *int
544+
}
545+
546+
func (p *point) negate() {
547+
*p.x = *p.x * -1
548+
*p.y = *p.y * -1
549+
}
550+
551+
// Test for issue #10152.
552+
func TestPanicInlined(t *testing.T) {
553+
defer func() {
554+
r := recover()
555+
if r == nil {
556+
t.Fatalf("recover failed")
557+
}
558+
buf := make([]byte, 2048)
559+
n := runtime.Stack(buf, false)
560+
buf = buf[:n]
561+
if !bytes.Contains(buf, []byte("(*point).negate(")) {
562+
t.Fatalf("expecting stack trace to contain call to (*point).negate()")
563+
}
564+
}()
565+
566+
pt := new(point)
567+
pt.negate()
568+
}

src/runtime/symtab.go

+25
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,23 @@ func funcname(f *_func) string {
604604
return gostringnocopy(cfuncname(f))
605605
}
606606

607+
func funcnameFromNameoff(f *_func, nameoff int32) string {
608+
datap := findmoduledatap(f.entry) // inefficient
609+
if datap == nil {
610+
return ""
611+
}
612+
cstr := &datap.pclntable[nameoff]
613+
return gostringnocopy(cstr)
614+
}
615+
616+
func funcfile(f *_func, fileno int32) string {
617+
datap := findmoduledatap(f.entry) // inefficient
618+
if datap == nil {
619+
return "?"
620+
}
621+
return gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
622+
}
623+
607624
func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32) {
608625
datap := findmoduledatap(f.entry) // inefficient
609626
if datap == nil {
@@ -699,3 +716,11 @@ func stackmapdata(stkmap *stackmap, n int32) bitvector {
699716
}
700717
return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+7)/8))))}
701718
}
719+
720+
// inlinedCall is the encoding of entries in the FUNCDATA_InlTree table.
721+
type inlinedCall struct {
722+
parent int32 // index of parent in the inltree, or < 0
723+
file int32 // fileno index into filetab
724+
line int32 // line number of the call site
725+
func_ int32 // offset into pclntab for name of called function
726+
}

src/runtime/traceback.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
332332
}
333333
}
334334
if printing {
335+
// assume skip=0 for printing
335336
if (flags&_TraceRuntimeFrames) != 0 || showframe(f, gp, nprint == 0) {
336337
// Print during crash.
337338
// main(0x1, 0x2, 0x3)
@@ -341,6 +342,21 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
341342
if (n > 0 || flags&_TraceTrap == 0) && frame.pc > f.entry && !waspanic {
342343
tracepc--
343344
}
345+
file, line := funcline(f, tracepc)
346+
inldata := funcdata(f, _FUNCDATA_InlTree)
347+
if inldata != nil {
348+
inltree := (*[1 << 20]inlinedCall)(inldata)
349+
ix := pcdatavalue(f, _PCDATA_InlTreeIndex, tracepc, nil)
350+
for ix != -1 {
351+
name := funcnameFromNameoff(f, inltree[ix].func_)
352+
print(name, "(...)\n")
353+
print("\t", file, ":", line, "\n")
354+
355+
file = funcfile(f, inltree[ix].file)
356+
line = inltree[ix].line
357+
ix = inltree[ix].parent
358+
}
359+
}
344360
name := funcname(f)
345361
if name == "runtime.gopanic" {
346362
name = "panic"
@@ -358,7 +374,6 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
358374
print(hex(argp[i]))
359375
}
360376
print(")\n")
361-
file, line := funcline(f, tracepc)
362377
print("\t", file, ":", line)
363378
if frame.pc > f.entry {
364379
print(" +", hex(frame.pc-f.entry))

0 commit comments

Comments
 (0)