terminal,api: move PrintStack function (#2537)
Commit 30cdedae6910f5e9af6739845bacfd5b8778e745 introduced a dependency from service/dap to pkg/terminal to call a stack printing function, it's weird to have code that implements the DAP protocol depend on the code for the JSON-RPC client. Move PrintStack to a different package that can be called by both.
This commit is contained in:
parent
1ecdb3be05
commit
29825d41a6
@ -2331,71 +2331,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(t *Term, out io.Writer, stack []api.Stackframe, ind string, offsets bool) {
|
func printStack(t *Term, out io.Writer, stack []api.Stackframe, ind string, offsets bool) {
|
||||||
PrintStack(t.formatPath, out, stack, ind, offsets, func(api.Stackframe) bool { return true })
|
api.PrintStack(t.formatPath, out, stack, ind, offsets, func(api.Stackframe) bool { return true })
|
||||||
}
|
|
||||||
|
|
||||||
func PrintStack(formatPath func(string) string, out io.Writer, stack []api.Stackframe, ind string, offsets bool, include func(api.Stackframe) bool) {
|
|
||||||
if len(stack) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
extranl := offsets
|
|
||||||
for i := range stack {
|
|
||||||
if extranl {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
extranl = extranl || (len(stack[i].Defers) > 0) || (len(stack[i].Arguments) > 0) || (len(stack[i].Locals) > 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
d := digits(len(stack) - 1)
|
|
||||||
fmtstr := "%s%" + strconv.Itoa(d) + "d 0x%016x in %s\n"
|
|
||||||
s := ind + strings.Repeat(" ", d+2+len(ind))
|
|
||||||
|
|
||||||
for i := range stack {
|
|
||||||
if !include(stack[i]) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if stack[i].Err != "" {
|
|
||||||
fmt.Fprintf(out, "%serror: %s\n", s, stack[i].Err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fmt.Fprintf(out, fmtstr, ind, i, stack[i].PC, stack[i].Function.Name())
|
|
||||||
fmt.Fprintf(out, "%sat %s:%d\n", s, formatPath(stack[i].File), stack[i].Line)
|
|
||||||
|
|
||||||
if offsets {
|
|
||||||
fmt.Fprintf(out, "%sframe: %+#x frame pointer %+#x\n", s, stack[i].FrameOffset, stack[i].FramePointerOffset)
|
|
||||||
}
|
|
||||||
|
|
||||||
for j, d := range stack[i].Defers {
|
|
||||||
deferHeader := fmt.Sprintf("%s defer %d: ", s, j+1)
|
|
||||||
s2 := strings.Repeat(" ", len(deferHeader))
|
|
||||||
if d.Unreadable != "" {
|
|
||||||
fmt.Fprintf(out, "%s(unreadable defer: %s)\n", deferHeader, d.Unreadable)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fmt.Fprintf(out, "%s%#016x in %s\n", deferHeader, d.DeferredLoc.PC, d.DeferredLoc.Function.Name())
|
|
||||||
fmt.Fprintf(out, "%sat %s:%d\n", s2, formatPath(d.DeferredLoc.File), d.DeferredLoc.Line)
|
|
||||||
fmt.Fprintf(out, "%sdeferred by %s at %s:%d\n", s2, d.DeferLoc.Function.Name(), formatPath(d.DeferLoc.File), d.DeferLoc.Line)
|
|
||||||
}
|
|
||||||
|
|
||||||
for j := range stack[i].Arguments {
|
|
||||||
fmt.Fprintf(out, "%s %s = %s\n", s, stack[i].Arguments[j].Name, stack[i].Arguments[j].SinglelineString())
|
|
||||||
}
|
|
||||||
for j := range stack[i].Locals {
|
|
||||||
fmt.Fprintf(out, "%s %s = %s\n", s, stack[i].Locals[j].Name, stack[i].Locals[j].SinglelineString())
|
|
||||||
}
|
|
||||||
|
|
||||||
if extranl {
|
|
||||||
fmt.Fprintln(out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(stack) > 0 && !stack[len(stack)-1].Bottom {
|
|
||||||
fmt.Fprintf(out, "%s"+stacktraceTruncatedMessage+"\n", ind)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func printcontext(t *Term, state *api.DebuggerState) {
|
func printcontext(t *Term, state *api.DebuggerState) {
|
||||||
|
@ -943,6 +943,7 @@ func TestOptimizationCheck(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTruncateStacktrace(t *testing.T) {
|
func TestTruncateStacktrace(t *testing.T) {
|
||||||
|
const stacktraceTruncatedMessage = "(truncated)"
|
||||||
withTestTerminal("stacktraceprog", t, func(term *FakeTerminal) {
|
withTestTerminal("stacktraceprog", t, func(term *FakeTerminal) {
|
||||||
term.MustExec("break main.stacktraceme")
|
term.MustExec("break main.stacktraceme")
|
||||||
term.MustExec("continue")
|
term.MustExec("continue")
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -493,3 +494,73 @@ func byteArrayToUInt64(buf []byte, isLittleEndian bool) uint64 {
|
|||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stacktraceTruncatedMessage = "(truncated)"
|
||||||
|
|
||||||
|
func digits(n int) int {
|
||||||
|
if n <= 0 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return int(math.Floor(math.Log10(float64(n)))) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintStack(formatPath func(string) string, out io.Writer, stack []Stackframe, ind string, offsets bool, include func(Stackframe) bool) {
|
||||||
|
if len(stack) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
extranl := offsets
|
||||||
|
for i := range stack {
|
||||||
|
if extranl {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
extranl = extranl || (len(stack[i].Defers) > 0) || (len(stack[i].Arguments) > 0) || (len(stack[i].Locals) > 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
d := digits(len(stack) - 1)
|
||||||
|
fmtstr := "%s%" + strconv.Itoa(d) + "d 0x%016x in %s\n"
|
||||||
|
s := ind + strings.Repeat(" ", d+2+len(ind))
|
||||||
|
|
||||||
|
for i := range stack {
|
||||||
|
if !include(stack[i]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if stack[i].Err != "" {
|
||||||
|
fmt.Fprintf(out, "%serror: %s\n", s, stack[i].Err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintf(out, fmtstr, ind, i, stack[i].PC, stack[i].Function.Name())
|
||||||
|
fmt.Fprintf(out, "%sat %s:%d\n", s, formatPath(stack[i].File), stack[i].Line)
|
||||||
|
|
||||||
|
if offsets {
|
||||||
|
fmt.Fprintf(out, "%sframe: %+#x frame pointer %+#x\n", s, stack[i].FrameOffset, stack[i].FramePointerOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
for j, d := range stack[i].Defers {
|
||||||
|
deferHeader := fmt.Sprintf("%s defer %d: ", s, j+1)
|
||||||
|
s2 := strings.Repeat(" ", len(deferHeader))
|
||||||
|
if d.Unreadable != "" {
|
||||||
|
fmt.Fprintf(out, "%s(unreadable defer: %s)\n", deferHeader, d.Unreadable)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintf(out, "%s%#016x in %s\n", deferHeader, d.DeferredLoc.PC, d.DeferredLoc.Function.Name())
|
||||||
|
fmt.Fprintf(out, "%sat %s:%d\n", s2, formatPath(d.DeferredLoc.File), d.DeferredLoc.Line)
|
||||||
|
fmt.Fprintf(out, "%sdeferred by %s at %s:%d\n", s2, d.DeferLoc.Function.Name(), formatPath(d.DeferLoc.File), d.DeferLoc.Line)
|
||||||
|
}
|
||||||
|
|
||||||
|
for j := range stack[i].Arguments {
|
||||||
|
fmt.Fprintf(out, "%s %s = %s\n", s, stack[i].Arguments[j].Name, stack[i].Arguments[j].SinglelineString())
|
||||||
|
}
|
||||||
|
for j := range stack[i].Locals {
|
||||||
|
fmt.Fprintf(out, "%s %s = %s\n", s, stack[i].Locals[j].Name, stack[i].Locals[j].SinglelineString())
|
||||||
|
}
|
||||||
|
|
||||||
|
if extranl {
|
||||||
|
fmt.Fprintln(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(stack) > 0 && !stack[len(stack)-1].Bottom {
|
||||||
|
fmt.Fprintf(out, "%s"+stacktraceTruncatedMessage+"\n", ind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -32,7 +32,6 @@ import (
|
|||||||
"github.com/go-delve/delve/pkg/locspec"
|
"github.com/go-delve/delve/pkg/locspec"
|
||||||
"github.com/go-delve/delve/pkg/logflags"
|
"github.com/go-delve/delve/pkg/logflags"
|
||||||
"github.com/go-delve/delve/pkg/proc"
|
"github.com/go-delve/delve/pkg/proc"
|
||||||
"github.com/go-delve/delve/pkg/terminal"
|
|
||||||
"github.com/go-delve/delve/service"
|
"github.com/go-delve/delve/service"
|
||||||
"github.com/go-delve/delve/service/api"
|
"github.com/go-delve/delve/service/api"
|
||||||
"github.com/go-delve/delve/service/debugger"
|
"github.com/go-delve/delve/service/debugger"
|
||||||
@ -2475,7 +2474,7 @@ func (s *Server) onExceptionInfoRequest(request *dap.ExceptionInfoRequest) {
|
|||||||
fmt.Fprintln(&buf, "Stack:")
|
fmt.Fprintln(&buf, "Stack:")
|
||||||
userLoc := g.UserCurrent()
|
userLoc := g.UserCurrent()
|
||||||
userFuncPkg := fnPackageName(&userLoc)
|
userFuncPkg := fnPackageName(&userLoc)
|
||||||
terminal.PrintStack(s.toClientPath, &buf, apiFrames, "\t", false, func(s api.Stackframe) bool {
|
api.PrintStack(s.toClientPath, &buf, apiFrames, "\t", false, func(s api.Stackframe) bool {
|
||||||
// Include all stack frames if the stack trace is for a system goroutine,
|
// Include all stack frames if the stack trace is for a system goroutine,
|
||||||
// otherwise, skip runtime stack frames.
|
// otherwise, skip runtime stack frames.
|
||||||
if userFuncPkg == "runtime" {
|
if userFuncPkg == "runtime" {
|
||||||
|
Loading…
Reference in New Issue
Block a user