proc,service,terminal: information about stack trace truncation
Add a flag to Stackframe that indicates where the stack frame is the bottom-most frame of the stack. This allows clients to know whether the stack trace terminated normally or if it was truncated because the maximum depth was reached. Add a truncation message to the 'stack' command.
This commit is contained in:
parent
b8e80746e5
commit
ac74944d53
@ -47,6 +47,8 @@ type Stackframe struct {
|
|||||||
SystemStack bool
|
SystemStack bool
|
||||||
// Inlined is true if this frame is actually an inlined call.
|
// Inlined is true if this frame is actually an inlined call.
|
||||||
Inlined bool
|
Inlined bool
|
||||||
|
// Bottom is true if this is the bottom of the stack
|
||||||
|
Bottom bool
|
||||||
|
|
||||||
// lastpc is a memory address guaranteed to belong to the last instruction
|
// lastpc is a memory address guaranteed to belong to the last instruction
|
||||||
// executed in this stack frame.
|
// executed in this stack frame.
|
||||||
@ -339,6 +341,7 @@ func (it *stackIterator) switchStack() bool {
|
|||||||
|
|
||||||
// Frame returns the frame the iterator is pointing at.
|
// Frame returns the frame the iterator is pointing at.
|
||||||
func (it *stackIterator) Frame() Stackframe {
|
func (it *stackIterator) Frame() Stackframe {
|
||||||
|
it.frame.Bottom = it.atend
|
||||||
return it.frame
|
return it.frame
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1530,6 +1530,8 @@ func digits(n int) int {
|
|||||||
return int(math.Floor(math.Log10(float64(n)))) + 1
|
return int(math.Floor(math.Log10(float64(n)))) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stacktraceTruncatedMessage = "(truncated)"
|
||||||
|
|
||||||
func printStack(stack []api.Stackframe, ind string, offsets bool) {
|
func printStack(stack []api.Stackframe, ind string, offsets bool) {
|
||||||
if len(stack) == 0 {
|
if len(stack) == 0 {
|
||||||
return
|
return
|
||||||
@ -1582,6 +1584,10 @@ func printStack(stack []api.Stackframe, ind string, offsets bool) {
|
|||||||
fmt.Println()
|
fmt.Println()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(stack) > 0 && !stack[len(stack)-1].Bottom {
|
||||||
|
fmt.Printf("%s"+stacktraceTruncatedMessage+"\n", ind)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func printcontext(t *Term, state *api.DebuggerState) error {
|
func printcontext(t *Term, state *api.DebuggerState) error {
|
||||||
|
@ -224,7 +224,7 @@ func TestExecuteFile(t *testing.T) {
|
|||||||
|
|
||||||
func TestIssue354(t *testing.T) {
|
func TestIssue354(t *testing.T) {
|
||||||
printStack([]api.Stackframe{}, "", false)
|
printStack([]api.Stackframe{}, "", false)
|
||||||
printStack([]api.Stackframe{{api.Location{PC: 0, File: "irrelevant.go", Line: 10, Function: nil}, nil, nil, 0, 0, nil, ""}}, "", false)
|
printStack([]api.Stackframe{{api.Location{PC: 0, File: "irrelevant.go", Line: 10, Function: nil}, nil, nil, 0, 0, nil, true, ""}}, "", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIssue411(t *testing.T) {
|
func TestIssue411(t *testing.T) {
|
||||||
@ -827,3 +827,20 @@ func TestOptimizationCheck(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTruncateStacktrace(t *testing.T) {
|
||||||
|
withTestTerminal("stacktraceprog", t, func(term *FakeTerminal) {
|
||||||
|
term.MustExec("break main.stacktraceme")
|
||||||
|
term.MustExec("continue")
|
||||||
|
out1 := term.MustExec("stack")
|
||||||
|
t.Logf("untruncated output %q", out1)
|
||||||
|
if strings.Contains(out1, stacktraceTruncatedMessage) {
|
||||||
|
t.Fatalf("stacktrace was truncated")
|
||||||
|
}
|
||||||
|
out2 := term.MustExec("stack 1")
|
||||||
|
t.Logf("truncated output %q", out2)
|
||||||
|
if !strings.Contains(out2, stacktraceTruncatedMessage) {
|
||||||
|
t.Fatalf("stacktrace was not truncated")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -131,6 +131,8 @@ type Stackframe struct {
|
|||||||
|
|
||||||
Defers []Defer
|
Defers []Defer
|
||||||
|
|
||||||
|
Bottom bool `json:"Bottom,omitempty"` // Bottom is true if this is the bottom frame of the stack
|
||||||
|
|
||||||
Err string
|
Err string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -932,6 +932,8 @@ func (d *Debugger) convertStacktrace(rawlocs []proc.Stackframe, cfg *proc.LoadCo
|
|||||||
FramePointerOffset: rawlocs[i].FramePointerOffset(),
|
FramePointerOffset: rawlocs[i].FramePointerOffset(),
|
||||||
|
|
||||||
Defers: d.convertDefers(rawlocs[i].Defers),
|
Defers: d.convertDefers(rawlocs[i].Defers),
|
||||||
|
|
||||||
|
Bottom: rawlocs[i].Bottom,
|
||||||
}
|
}
|
||||||
if rawlocs[i].Err != nil {
|
if rawlocs[i].Err != nil {
|
||||||
frame.Err = rawlocs[i].Err.Error()
|
frame.Err = rawlocs[i].Err.Error()
|
||||||
|
@ -172,11 +172,11 @@ func (s *RPCServer) Stacktrace(arg StacktraceIn, out *StacktraceOut) error {
|
|||||||
if cfg == nil && arg.Full {
|
if cfg == nil && arg.Full {
|
||||||
cfg = &api.LoadConfig{true, 1, 64, 64, -1}
|
cfg = &api.LoadConfig{true, 1, 64, 64, -1}
|
||||||
}
|
}
|
||||||
locs, err := s.debugger.Stacktrace(arg.Id, arg.Depth, arg.Defers, api.LoadConfigToProc(cfg))
|
var err error
|
||||||
|
out.Locations, err = s.debugger.Stacktrace(arg.Id, arg.Depth, arg.Defers, api.LoadConfigToProc(cfg))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
out.Locations = locs
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user