mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 10:47:27 +08:00 
			
		
		
		
	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:
		 Alessandro Arzilli
					Alessandro Arzilli
				
			
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			 GitHub
						GitHub
					
				
			
						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" { | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user