diff --git a/cmd/dlv/cmds/commands.go b/cmd/dlv/cmds/commands.go index 04c7df0e..5125d191 100644 --- a/cmd/dlv/cmds/commands.go +++ b/cmd/dlv/cmds/commands.go @@ -14,6 +14,7 @@ import ( "github.com/derekparker/delve/pkg/config" "github.com/derekparker/delve/pkg/goversion" + "github.com/derekparker/delve/pkg/logflags" "github.com/derekparker/delve/pkg/terminal" "github.com/derekparker/delve/pkg/version" "github.com/derekparker/delve/service" @@ -25,7 +26,7 @@ import ( var ( // Log is whether to log debug statements. - Log bool + Log string // Headless is whether to run without terminal. Headless bool // APIVersion is the requested API version while running headless @@ -85,7 +86,11 @@ func New(docCall bool) *cobra.Command { } RootCommand.PersistentFlags().StringVarP(&Addr, "listen", "l", "localhost:0", "Debugging server listen address.") - RootCommand.PersistentFlags().BoolVarP(&Log, "log", "", false, "Enable debugging server logging.") + RootCommand.PersistentFlags().StringVarP(&Log, "log", "", "false", `Comma separated list of components that should produce debug output, possible values: + debugger Log debugger commands + gdbwire Log connection to gdbserial backend + lldbout Copy output from debugserver/lldb to standard output +`) RootCommand.PersistentFlags().BoolVarP(&Headless, "headless", "", false, "Run debug server only, in headless mode.") RootCommand.PersistentFlags().BoolVarP(&AcceptMulti, "accept-multiclient", "", false, "Allows a headless server to accept multiple client connections. Note that the server API is not reentrant and clients will have to coordinate.") RootCommand.PersistentFlags().IntVar(&APIVersion, "api-version", 1, "Selects API version when headless.") @@ -304,6 +309,7 @@ func debugCmd(cmd *cobra.Command, args []string) { func traceCmd(cmd *cobra.Command, args []string) { status := func() int { + logflags.Setup(Log) debugname, err := filepath.Abs(cmd.Flag("output").Value.String()) if err != nil { @@ -348,7 +354,7 @@ func traceCmd(cmd *cobra.Command, args []string) { APIVersion: 2, WorkingDir: WorkingDir, Backend: Backend, - }, Log) + }, logflags.Debugger()) if err := server.Run(); err != nil { fmt.Fprintln(os.Stderr, err) return 1 @@ -455,6 +461,8 @@ const ( ) func execute(attachPid int, processArgs []string, conf *config.Config, coreFile string, kind executeKind) int { + logflags.Setup(Log) + // Make a TCP listener listener, err := net.Listen("tcp", Addr) if err != nil { @@ -488,7 +496,7 @@ func execute(attachPid int, processArgs []string, conf *config.Config, coreFile CoreFile: coreFile, DisconnectChan: disconnectChan, - }, Log) + }, logflags.Debugger()) default: fmt.Printf("Unknown API version: %d\n", APIVersion) return 1 diff --git a/pkg/logflags/logflags.go b/pkg/logflags/logflags.go new file mode 100644 index 00000000..79d9df1c --- /dev/null +++ b/pkg/logflags/logflags.go @@ -0,0 +1,43 @@ +package logflags + +import "strings" + +var debugger = false +var gdbWire = false +var lldbServerOutput = false + +// GdbWire returns true if the gdbserial package should log all the packets +// exchanged with the stub. +func GdbWire() bool { + return gdbWire +} + +// Debugger returns true if the debugger package should log. +func Debugger() bool { + return debugger +} + +// LLDBServerOutput returns true if the output of the LLDB server should be +// redirected to standard output instead of suppressed. +func LLDBServerOutput() bool { + return lldbServerOutput +} + +// Setup sets debugger flags based on the contents of logstr. +func Setup(logstr string) { + if logstr == "true" || logstr == "" { + debugger = true + return + } + v := strings.Split(logstr, ",") + for _, logcmd := range v { + switch logcmd { + case "debugger": + debugger = true + case "gdbwire": + gdbWire = true + case "lldbout": + lldbServerOutput = true + } + } +} diff --git a/pkg/proc/gdbserial/gdbserver.go b/pkg/proc/gdbserial/gdbserver.go index 5de47dc1..b514d1ef 100644 --- a/pkg/proc/gdbserial/gdbserver.go +++ b/pkg/proc/gdbserial/gdbserver.go @@ -79,14 +79,13 @@ import ( "golang.org/x/arch/x86/x86asm" + "github.com/derekparker/delve/pkg/logflags" "github.com/derekparker/delve/pkg/proc" ) const ( - logGdbWire = false - logGdbWireFullStopPacket = false - showLldbServerOutput = false - logGdbWireMaxLen = 120 + gdbWireFullStopPacket = false + gdbWireMaxLen = 120 maxTransmitAttempts = 3 // number of retransmission attempts on failed checksum initialInputBufferSize = 2048 // size of the input buffer for gdbConn @@ -424,7 +423,7 @@ func LLDBLaunch(cmd []string, wd string) (*Process, error) { proc = exec.Command("lldb-server", args...) } - if showLldbServerOutput || logGdbWire { + if logflags.LLDBServerOutput() || logflags.GdbWire() { proc.Stdout = os.Stdout proc.Stderr = os.Stderr } diff --git a/pkg/proc/gdbserial/gdbserver_conn.go b/pkg/proc/gdbserial/gdbserver_conn.go index bcf68651..7be7c92d 100644 --- a/pkg/proc/gdbserial/gdbserver_conn.go +++ b/pkg/proc/gdbserial/gdbserver_conn.go @@ -16,6 +16,7 @@ import ( "sync" "time" + "github.com/derekparker/delve/pkg/logflags" "github.com/derekparker/delve/pkg/proc" ) @@ -632,7 +633,7 @@ func (conn *gdbConn) parseStopPacket(resp []byte, threadID string, tu *threadUpd } sp.sig = uint8(sig) - if logGdbWire && logGdbWireFullStopPacket { + if logflags.GdbWire() && gdbWireFullStopPacket { fmt.Fprintf(os.Stderr, "full stop packet: %s\n", string(resp)) } @@ -704,7 +705,7 @@ const ctrlC = 0x03 // the ASCII character for ^C // executes a ctrl-C on the line func (conn *gdbConn) sendCtrlC() error { - if logGdbWire { + if logflags.GdbWire() { fmt.Println("<- interrupt") } _, err := conn.conn.Write([]byte{ctrlC}) @@ -991,9 +992,9 @@ func (conn *gdbConn) send(cmd []byte) error { attempt := 0 for { - if logGdbWire { - if len(cmd) > logGdbWireMaxLen { - fmt.Printf("<- %s...\n", string(cmd[:logGdbWireMaxLen])) + if logflags.GdbWire() { + if len(cmd) > gdbWireMaxLen { + fmt.Printf("<- %s...\n", string(cmd[:gdbWireMaxLen])) } else { fmt.Printf("<- %s\n", string(cmd)) } @@ -1032,15 +1033,15 @@ func (conn *gdbConn) recv(cmd []byte, context string, binary bool) (resp []byte, if err != nil { return nil, err } - if logGdbWire { + if logflags.GdbWire() { out := resp partial := false if idx := bytes.Index(out, []byte{'\n'}); idx >= 0 { out = resp[:idx] partial = true } - if len(out) > logGdbWireMaxLen { - out = out[:logGdbWireMaxLen] + if len(out) > gdbWireMaxLen { + out = out[:gdbWireMaxLen] partial = true } if !partial { @@ -1097,7 +1098,7 @@ func (conn *gdbConn) readack() bool { if err != nil { return false } - if logGdbWire { + if logflags.GdbWire() { fmt.Printf("-> %s\n", string(b)) } return b == '+' @@ -1109,7 +1110,7 @@ func (conn *gdbConn) sendack(c byte) { panic(fmt.Errorf("sendack(%c)", c)) } conn.conn.Write([]byte{c}) - if logGdbWire { + if logflags.GdbWire() { fmt.Printf("<- %s\n", string(c)) } }