proc: tolerate memory read errors during stacktrace

When there's a error reading the stack trace the call stack itself
could be corrupted and we should return the partial stacktrace that we
have.

Fixes #868
This commit is contained in:
aarzilli
2017-06-23 13:31:05 +02:00
committed by Derek Parker
parent d4364d0496
commit a7718bd358
5 changed files with 16 additions and 3 deletions

View File

@ -38,6 +38,8 @@ type Stackframe struct {
Ret uint64 Ret uint64
// Address to the memory location containing the return address // Address to the memory location containing the return address
addrret uint64 addrret uint64
// Err is set if an error occoured during stacktrace
Err error
} }
// Stacktrace returns the stack trace for thread. // Stacktrace returns the stack trace for thread.
@ -207,7 +209,7 @@ func (it *stackIterator) newStackframe(pc uint64, cfa int64, retaddr uintptr, fd
f, l, fn := it.bi.PCToLine(pc) f, l, fn := it.bi.PCToLine(pc)
ret, err := readUintRaw(it.mem, retaddr, int64(it.bi.Arch.PtrSize())) ret, err := readUintRaw(it.mem, retaddr, int64(it.bi.Arch.PtrSize()))
if err != nil { if err != nil {
return Stackframe{}, err it.err = err
} }
r := Stackframe{Current: Location{PC: pc, File: f, Line: l, Fn: fn}, CFA: cfa, FDE: fde, Ret: ret, addrret: uint64(retaddr), StackHi: it.stackhi} r := Stackframe{Current: Location{PC: pc, File: f, Line: l, Fn: fn}, CFA: cfa, FDE: fde, Ret: ret, addrret: uint64(retaddr), StackHi: it.stackhi}
if !top { if !top {
@ -231,7 +233,10 @@ func (it *stackIterator) stacktrace(depth int) ([]Stackframe, error) {
} }
} }
if err := it.Err(); err != nil { if err := it.Err(); err != nil {
return nil, err if len(frames) == 0 {
return nil, err
}
frames = append(frames, Stackframe{Err: err})
} }
return frames, nil return frames, nil
} }

View File

@ -1210,6 +1210,10 @@ func printStack(stack []api.Stackframe, ind string) {
s := ind + strings.Repeat(" ", d+2+len(ind)) s := ind + strings.Repeat(" ", d+2+len(ind))
for i := range stack { for i := range stack {
if stack[i].Err != "" {
fmt.Printf("%serror: %s\n", s, stack[i].Err)
continue
}
name := "(nil)" name := "(nil)"
if stack[i].Function != nil { if stack[i].Function != nil {
name = stack[i].Function.Name name = stack[i].Function.Name

View File

@ -216,7 +216,7 @@ func TestExecuteFile(t *testing.T) {
func TestIssue354(t *testing.T) { func TestIssue354(t *testing.T) {
printStack([]api.Stackframe{}, "") printStack([]api.Stackframe{}, "")
printStack([]api.Stackframe{{api.Location{PC: 0, File: "irrelevant.go", Line: 10, Function: nil}, nil, nil, 0}}, "") printStack([]api.Stackframe{{api.Location{PC: 0, File: "irrelevant.go", Line: 10, Function: nil}, nil, nil, 0, nil}}, "")
} }
func TestIssue411(t *testing.T) { func TestIssue411(t *testing.T) {

View File

@ -121,6 +121,7 @@ type Stackframe struct {
Locals []Variable Locals []Variable
Arguments []Variable Arguments []Variable
FrameOffset int64 FrameOffset int64
Err string
} }
func (frame *Stackframe) Var(name string) *Variable { func (frame *Stackframe) Var(name string) *Variable {

View File

@ -857,6 +857,9 @@ func (d *Debugger) convertStacktrace(rawlocs []proc.Stackframe, cfg *proc.LoadCo
Location: api.ConvertLocation(rawlocs[i].Call), Location: api.ConvertLocation(rawlocs[i].Call),
FrameOffset: rawlocs[i].CFA - int64(rawlocs[i].StackHi), FrameOffset: rawlocs[i].CFA - int64(rawlocs[i].StackHi),
} }
if rawlocs[i].Err != nil {
frame.Err = rawlocs[i].Err.Error()
}
if cfg != nil && rawlocs[i].Current.Fn != nil { if cfg != nil && rawlocs[i].Current.Fn != nil {
var err error var err error
scope := proc.FrameToScope(d.target, rawlocs[i]) scope := proc.FrameToScope(d.target, rawlocs[i])