internal/gocore: don't panic if backtrace fails
Backtracing a thread in the core file may fail for various reasons: it
might have C functions, which we don't know how to deal with, or its
stack could be corrupted. Don't crash if that happens, just give up on
backtracing the current thread.
Fixes golang/go#27323
Change-Id: I271032cef1a9a54ef929b602a9846addfd145296
Reviewed-on: https://go-review.googlesource.com/132055
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rhys Hiltner <rhys@justin.tv>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/internal/gocore/module.go b/internal/gocore/module.go
index fe86162..85c3826 100644
--- a/internal/gocore/module.go
+++ b/internal/gocore/module.go
@@ -167,14 +167,14 @@
t.entries = []pcTabEntry{{bytes: 1<<63 - 1, val: -1}}
}
-func (t *pcTab) find(off int64) int64 {
+func (t *pcTab) find(off int64) (int64, error) {
for _, e := range t.entries {
if off < e.bytes {
- return e.val
+ return e.val, nil
}
off -= e.bytes
}
- panic("can't find pctab entry")
+ return 0, fmt.Errorf("can't find pctab entry for offset %#x", off)
}
// readVarint reads a varint from the core file.
diff --git a/internal/gocore/process.go b/internal/gocore/process.go
index d4e368a..05c7c84 100644
--- a/internal/gocore/process.go
+++ b/internal/gocore/process.go
@@ -516,7 +516,11 @@
return g
}
for {
- f := p.readFrame(sp, pc)
+ f, err := p.readFrame(sp, pc)
+ if err != nil {
+ fmt.Printf("warning: giving up on backtrace: %v\n", err)
+ break
+ }
if f.f.name == "runtime.goexit" {
break
}
@@ -553,13 +557,16 @@
return g
}
-func (p *Process) readFrame(sp, pc core.Address) *Frame {
+func (p *Process) readFrame(sp, pc core.Address) (*Frame, error) {
f := p.funcTab.find(pc)
if f == nil {
- panic(fmt.Errorf(" pc not found %x\n", pc))
+ return nil, fmt.Errorf("cannot find func for pc=%#x", pc)
}
off := pc.Sub(f.entry)
- size := f.frameSize.find(off)
+ size, err := f.frameSize.find(off)
+ if err != nil {
+ return nil, fmt.Errorf("cannot read frame size at pc=%#x: %v", pc, err)
+ }
size += p.proc.PtrSize() // TODO: on amd64, the pushed return address
frame := &Frame{f: f, pc: pc, min: sp, max: sp.Add(size)}
@@ -570,7 +577,10 @@
locals := region{p: p, a: f.funcdata[x], typ: p.findType("runtime.stackmap")}
n := locals.Field("n").Int32() // # of bitmaps
nbit := locals.Field("nbit").Int32() // # of bits per bitmap
- idx := f.stackMap.find(off)
+ idx, err := f.stackMap.find(off)
+ if err != nil {
+ return nil, fmt.Errorf("cannot read stack map at pc=%#x: %v", pc, err)
+ }
if idx < 0 {
idx = 0
}
@@ -590,7 +600,10 @@
args := region{p: p, a: f.funcdata[x], typ: p.findType("runtime.stackmap")}
n := args.Field("n").Int32() // # of bitmaps
nbit := args.Field("nbit").Int32() // # of bits per bitmap
- idx := f.stackMap.find(off)
+ idx, err := f.stackMap.find(off)
+ if err != nil {
+ return nil, fmt.Errorf("cannot read stack map at pc=%#x: %v", pc, err)
+ }
if idx < 0 {
idx = 0
}
@@ -607,7 +620,7 @@
}
frame.Live = live
- return frame
+ return frame, nil
}
// A Stats struct is the node of a tree representing the entire memory