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 | ||||
| } | ||||
|  | ||||
| const stacktraceTruncatedMessage = "(truncated)" | ||||
|  | ||||
| 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 }) | ||||
| } | ||||
|  | ||||
| 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) | ||||
| 	} | ||||
| 	api.PrintStack(t.formatPath, out, stack, ind, offsets, func(api.Stackframe) bool { return true }) | ||||
| } | ||||
|  | ||||
| func printcontext(t *Term, state *api.DebuggerState) { | ||||
|  | ||||
| @ -943,6 +943,7 @@ func TestOptimizationCheck(t *testing.T) { | ||||
| } | ||||
|  | ||||
| func TestTruncateStacktrace(t *testing.T) { | ||||
| 	const stacktraceTruncatedMessage = "(truncated)" | ||||
| 	withTestTerminal("stacktraceprog", t, func(term *FakeTerminal) { | ||||
| 		term.MustExec("break main.stacktraceme") | ||||
| 		term.MustExec("continue") | ||||
|  | ||||
| @ -4,6 +4,7 @@ import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"math" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| @ -493,3 +494,73 @@ func byteArrayToUInt64(buf []byte, isLittleEndian bool) uint64 { | ||||
| 	} | ||||
| 	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/logflags" | ||||
| 	"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/api" | ||||
| 	"github.com/go-delve/delve/service/debugger" | ||||
| @ -2475,7 +2474,7 @@ func (s *Server) onExceptionInfoRequest(request *dap.ExceptionInfoRequest) { | ||||
| 			fmt.Fprintln(&buf, "Stack:") | ||||
| 			userLoc := g.UserCurrent() | ||||
| 			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, | ||||
| 				// otherwise, skip runtime stack frames. | ||||
| 				if userFuncPkg == "runtime" { | ||||
|  | ||||
		Reference in New Issue
	
	Block a user