dlv: Misc refactors
Mainly just cleans up the code in cmd/dlv/main.go
This commit is contained in:
parent
8a1f36a1ce
commit
94a265f098
333
cmd/dlv/main.go
333
cmd/dlv/main.go
@ -37,31 +37,37 @@ var (
|
|||||||
InitFile string
|
InitFile string
|
||||||
// BuildFlags is the flags passed during compiler invocation.
|
// BuildFlags is the flags passed during compiler invocation.
|
||||||
BuildFlags string
|
BuildFlags string
|
||||||
|
|
||||||
|
traceAttachPid int
|
||||||
|
traceStackDepth int
|
||||||
|
|
||||||
|
conf *config.Config
|
||||||
|
|
||||||
|
rootCommand *cobra.Command
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
const dlvCommandLongDesc = `Delve is a source level debugger for Go programs.
|
||||||
// Config setup and load.
|
|
||||||
conf := config.LoadConfig()
|
|
||||||
|
|
||||||
// Main dlv root command.
|
|
||||||
rootCommand := &cobra.Command{
|
|
||||||
Use: "dlv",
|
|
||||||
Short: "Delve is a debugger for the Go programming language.",
|
|
||||||
Long: `Delve is a source level debugger for Go programs.
|
|
||||||
|
|
||||||
Delve enables you to interact with your program by controlling the execution of the process,
|
Delve enables you to interact with your program by controlling the execution of the process,
|
||||||
evaluating variables, and providing information of thread / goroutine state, CPU register state and more.
|
evaluating variables, and providing information of thread / goroutine state, CPU register state and more.
|
||||||
|
|
||||||
The goal of this tool is to provide a simple yet powerful interface for debugging Go programs.
|
The goal of this tool is to provide a simple yet powerful interface for debugging Go programs.
|
||||||
`,
|
`
|
||||||
}
|
|
||||||
|
|
||||||
|
func init() {
|
||||||
buildFlagsDefault := ""
|
buildFlagsDefault := ""
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
// Work-around for https://github.com/golang/go/issues/13154
|
// Work-around for https://github.com/golang/go/issues/13154
|
||||||
buildFlagsDefault = "-ldflags=-linkmode internal"
|
buildFlagsDefault = "-ldflags=-linkmode internal"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Main dlv root command.
|
||||||
|
rootCommand = &cobra.Command{
|
||||||
|
Use: "dlv",
|
||||||
|
Short: "Delve is a debugger for the Go programming language.",
|
||||||
|
Long: dlvCommandLongDesc,
|
||||||
|
}
|
||||||
|
|
||||||
rootCommand.PersistentFlags().StringVarP(&Addr, "listen", "l", "localhost:0", "Debugging server listen address.")
|
rootCommand.PersistentFlags().StringVarP(&Addr, "listen", "l", "localhost:0", "Debugging server listen address.")
|
||||||
rootCommand.PersistentFlags().BoolVarP(&Log, "log", "", false, "Enable debugging server logging.")
|
rootCommand.PersistentFlags().BoolVarP(&Log, "log", "", false, "Enable debugging server logging.")
|
||||||
rootCommand.PersistentFlags().BoolVarP(&Headless, "headless", "", false, "Run debug server only, in headless mode.")
|
rootCommand.PersistentFlags().BoolVarP(&Headless, "headless", "", false, "Run debug server only, in headless mode.")
|
||||||
@ -95,27 +101,7 @@ The goal of this tool is to provide a simple yet powerful interface for debuggin
|
|||||||
Short: "Compile and begin debugging program.",
|
Short: "Compile and begin debugging program.",
|
||||||
Long: `Compiles your program with optimizations disabled,
|
Long: `Compiles your program with optimizations disabled,
|
||||||
starts and attaches to it, and enables you to immediately begin debugging your program.`,
|
starts and attaches to it, and enables you to immediately begin debugging your program.`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: debugCmd,
|
||||||
status := func() int {
|
|
||||||
const debugname = "debug"
|
|
||||||
goBuild := exec.Command("go", "build", "-o", debugname, "-gcflags", "-N -l", BuildFlags)
|
|
||||||
goBuild.Stderr = os.Stderr
|
|
||||||
err := goBuild.Run()
|
|
||||||
if err != nil {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
fp, err := filepath.Abs("./" + debugname)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, err.Error())
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
defer os.Remove(fp)
|
|
||||||
|
|
||||||
processArgs := append([]string{"./" + debugname}, args...)
|
|
||||||
return execute(0, processArgs, conf)
|
|
||||||
}()
|
|
||||||
os.Exit(status)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
rootCommand.AddCommand(debugCommand)
|
rootCommand.AddCommand(debugCommand)
|
||||||
|
|
||||||
@ -136,79 +122,17 @@ starts and attaches to it, and enables you to immediately begin debugging your p
|
|||||||
rootCommand.AddCommand(execCommand)
|
rootCommand.AddCommand(execCommand)
|
||||||
|
|
||||||
// 'trace' subcommand.
|
// 'trace' subcommand.
|
||||||
var traceAttachPid, traceStackDepth int
|
|
||||||
traceCommand := &cobra.Command{
|
traceCommand := &cobra.Command{
|
||||||
Use: "trace [regexp]",
|
Use: "trace [regexp]",
|
||||||
Short: "Compile and begin tracing program.",
|
Short: "Compile and begin tracing program.",
|
||||||
Long: "Trace program execution. Will set a tracepoint on every function matching [regexp] and output information when tracepoint is hit.",
|
Long: "Trace program execution. Will set a tracepoint on every function matching [regexp] and output information when tracepoint is hit.",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
status := func() int {
|
if len(args) == 0 {
|
||||||
if len(args) == 0 {
|
return errors.New("you must provide a function to trace")
|
||||||
fmt.Fprintln(os.Stderr, "You must provide a function to trace.")
|
}
|
||||||
return 1
|
return nil
|
||||||
}
|
|
||||||
const debugname = "debug"
|
|
||||||
var processArgs []string
|
|
||||||
if traceAttachPid == 0 {
|
|
||||||
goBuild := exec.Command("go", "build", "-o", debugname, "-gcflags", "-N -l", BuildFlags)
|
|
||||||
goBuild.Stderr = os.Stderr
|
|
||||||
err := goBuild.Run()
|
|
||||||
if err != nil {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
fp, err := filepath.Abs("./" + debugname)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, err.Error())
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
defer os.Remove(fp)
|
|
||||||
|
|
||||||
processArgs = append([]string{"./" + debugname}, args...)
|
|
||||||
}
|
|
||||||
// Make a TCP listener
|
|
||||||
listener, err := net.Listen("tcp", Addr)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("couldn't start listener: %s\n", err)
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
defer listener.Close()
|
|
||||||
|
|
||||||
// Create and start a debugger server
|
|
||||||
server := rpc.NewServer(&service.Config{
|
|
||||||
Listener: listener,
|
|
||||||
ProcessArgs: processArgs,
|
|
||||||
AttachPid: traceAttachPid,
|
|
||||||
}, Log)
|
|
||||||
if err := server.Run(); err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, err)
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
sigChan := make(chan os.Signal)
|
|
||||||
signal.Notify(sigChan, syscall.SIGINT)
|
|
||||||
client := rpc.NewClient(listener.Addr().String())
|
|
||||||
funcs, err := client.ListFunctions(args[0])
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, err)
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
for i := range funcs {
|
|
||||||
_, err := client.CreateBreakpoint(&api.Breakpoint{FunctionName: funcs[i], Line: -1, Tracepoint: true, Stacktrace: traceStackDepth})
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, err)
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cmds := terminal.DebugCommands(client)
|
|
||||||
cmd := cmds.Find("continue")
|
|
||||||
err = cmd(terminal.New(client, nil), "")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, err)
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}()
|
|
||||||
os.Exit(status)
|
|
||||||
},
|
},
|
||||||
|
Run: traceCmd,
|
||||||
}
|
}
|
||||||
traceCommand.Flags().IntVarP(&traceAttachPid, "pid", "p", 0, "Pid to attach to.")
|
traceCommand.Flags().IntVarP(&traceAttachPid, "pid", "p", 0, "Pid to attach to.")
|
||||||
traceCommand.Flags().IntVarP(&traceStackDepth, "stack", "s", 0, "Show stack trace with given depth.")
|
traceCommand.Flags().IntVarP(&traceStackDepth, "stack", "s", 0, "Show stack trace with given depth.")
|
||||||
@ -218,34 +142,8 @@ starts and attaches to it, and enables you to immediately begin debugging your p
|
|||||||
testCommand := &cobra.Command{
|
testCommand := &cobra.Command{
|
||||||
Use: "test",
|
Use: "test",
|
||||||
Short: "Compile test binary and begin debugging program.",
|
Short: "Compile test binary and begin debugging program.",
|
||||||
Long: `Compiles a test binary with optimizations disabled,
|
Long: `Compiles a test binary with optimizations disabled, starts and attaches to it, and enable you to immediately begin debugging your program.`,
|
||||||
starts and attaches to it, and enable you to immediately begin debugging your program.`,
|
Run: testCmd,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
status := func() int {
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, err.Error())
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
base := filepath.Base(wd)
|
|
||||||
goTest := exec.Command("go", "test", "-c", "-gcflags", "-N -l", BuildFlags)
|
|
||||||
goTest.Stderr = os.Stderr
|
|
||||||
err = goTest.Run()
|
|
||||||
if err != nil {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
debugname := "./" + base + ".test"
|
|
||||||
// On Windows, "go test" generates an executable with the ".exe" extension
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
debugname += ".exe"
|
|
||||||
}
|
|
||||||
defer os.Remove(debugname)
|
|
||||||
processArgs := append([]string{debugname}, args...)
|
|
||||||
|
|
||||||
return execute(0, processArgs, conf)
|
|
||||||
}()
|
|
||||||
os.Exit(status)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
rootCommand.AddCommand(testCommand)
|
rootCommand.AddCommand(testCommand)
|
||||||
|
|
||||||
@ -260,14 +158,7 @@ starts and attaches to it, and enable you to immediately begin debugging your pr
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: attachCmd,
|
||||||
pid, err := strconv.Atoi(args[0])
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Invalid pid: %s\n", args[0])
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
os.Exit(execute(pid, nil, conf))
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
rootCommand.AddCommand(attachCommand)
|
rootCommand.AddCommand(attachCommand)
|
||||||
|
|
||||||
@ -276,24 +167,148 @@ starts and attaches to it, and enable you to immediately begin debugging your pr
|
|||||||
Use: "connect [addr]",
|
Use: "connect [addr]",
|
||||||
Short: "Connect to a headless debug server.",
|
Short: "Connect to a headless debug server.",
|
||||||
Long: "Connect to a headless debug server.",
|
Long: "Connect to a headless debug server.",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
fmt.Fprintf(os.Stderr, "An address was not provided. You must provide an address as the first argument.\n")
|
return errors.New("you must provide an address as the first argument")
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
addr := args[0]
|
return nil
|
||||||
if addr == "" {
|
|
||||||
fmt.Fprintf(os.Stderr, "An empty address was provided. You must provide an address as the first argument.\n")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
os.Exit(connect(addr, conf))
|
|
||||||
},
|
},
|
||||||
|
Run: connectCmd,
|
||||||
}
|
}
|
||||||
rootCommand.AddCommand(connectCommand)
|
rootCommand.AddCommand(connectCommand)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Config setup and load.
|
||||||
|
conf = config.LoadConfig()
|
||||||
|
|
||||||
rootCommand.Execute()
|
rootCommand.Execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func debugCmd(cmd *cobra.Command, args []string) {
|
||||||
|
status := func() int {
|
||||||
|
const debugname = "debug"
|
||||||
|
err := gobuild(debugname)
|
||||||
|
if err != nil {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
fp, err := filepath.Abs("./" + debugname)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
defer os.Remove(fp)
|
||||||
|
|
||||||
|
processArgs := append([]string{"./" + debugname}, args...)
|
||||||
|
return execute(0, processArgs, conf)
|
||||||
|
}()
|
||||||
|
os.Exit(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
func traceCmd(cmd *cobra.Command, args []string) {
|
||||||
|
status := func() int {
|
||||||
|
const debugname = "debug"
|
||||||
|
var processArgs []string
|
||||||
|
if traceAttachPid == 0 {
|
||||||
|
if err := gobuild(debugname); err != nil {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
fp, err := filepath.Abs("./" + debugname)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
defer os.Remove(fp)
|
||||||
|
|
||||||
|
processArgs = append([]string{"./" + debugname}, args...)
|
||||||
|
}
|
||||||
|
// Make a TCP listener
|
||||||
|
listener, err := net.Listen("tcp", Addr)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("couldn't start listener: %s\n", err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
defer listener.Close()
|
||||||
|
|
||||||
|
// Create and start a debug server
|
||||||
|
server := rpc.NewServer(&service.Config{
|
||||||
|
Listener: listener,
|
||||||
|
ProcessArgs: processArgs,
|
||||||
|
AttachPid: traceAttachPid,
|
||||||
|
}, Log)
|
||||||
|
if err := server.Run(); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
client := rpc.NewClient(listener.Addr().String())
|
||||||
|
funcs, err := client.ListFunctions(args[0])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
for i := range funcs {
|
||||||
|
_, err := client.CreateBreakpoint(&api.Breakpoint{FunctionName: funcs[i], Tracepoint: true, Line: -1, Stacktrace: traceStackDepth})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmds := terminal.DebugCommands(client)
|
||||||
|
cmd := cmds.Find("continue")
|
||||||
|
err = cmd(terminal.New(client, nil), "")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}()
|
||||||
|
os.Exit(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCmd(cmd *cobra.Command, args []string) {
|
||||||
|
status := func() int {
|
||||||
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
base := filepath.Base(wd)
|
||||||
|
err = gotestbuild()
|
||||||
|
if err != nil {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
debugname := "./" + base + ".test"
|
||||||
|
// On Windows, "go test" generates an executable with the ".exe" extension
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
debugname += ".exe"
|
||||||
|
}
|
||||||
|
defer os.Remove(debugname)
|
||||||
|
processArgs := append([]string{debugname}, args...)
|
||||||
|
|
||||||
|
return execute(0, processArgs, conf)
|
||||||
|
}()
|
||||||
|
os.Exit(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
func attachCmd(cmd *cobra.Command, args []string) {
|
||||||
|
pid, err := strconv.Atoi(args[0])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Invalid pid: %s\n", args[0])
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
os.Exit(execute(pid, nil, conf))
|
||||||
|
}
|
||||||
|
|
||||||
|
func connectCmd(cmd *cobra.Command, args []string) {
|
||||||
|
addr := args[0]
|
||||||
|
if addr == "" {
|
||||||
|
fmt.Fprintf(os.Stderr, "An empty address was provided. You must provide an address as the first argument.\n")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
os.Exit(connect(addr, conf))
|
||||||
|
}
|
||||||
|
|
||||||
func connect(addr string, conf *config.Config) int {
|
func connect(addr string, conf *config.Config) int {
|
||||||
// Create and start a terminal - attach to running instance
|
// Create and start a terminal - attach to running instance
|
||||||
var client service.Client
|
var client service.Client
|
||||||
@ -331,18 +346,18 @@ func execute(attachPid int, processArgs []string, conf *config.Config) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var status int
|
var status int
|
||||||
if !Headless {
|
if Headless {
|
||||||
|
ch := make(chan os.Signal)
|
||||||
|
signal.Notify(ch, syscall.SIGINT)
|
||||||
|
<-ch
|
||||||
|
err = server.Stop(true)
|
||||||
|
} else {
|
||||||
// Create and start a terminal
|
// Create and start a terminal
|
||||||
var client service.Client
|
var client service.Client
|
||||||
client = rpc.NewClient(listener.Addr().String())
|
client = rpc.NewClient(listener.Addr().String())
|
||||||
term := terminal.New(client, conf)
|
term := terminal.New(client, conf)
|
||||||
term.InitFile = InitFile
|
term.InitFile = InitFile
|
||||||
status, err = term.Run()
|
status, err = term.Run()
|
||||||
} else {
|
|
||||||
ch := make(chan os.Signal)
|
|
||||||
signal.Notify(ch, syscall.SIGINT)
|
|
||||||
<-ch
|
|
||||||
err = server.Stop(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -351,3 +366,19 @@ func execute(attachPid int, processArgs []string, conf *config.Config) int {
|
|||||||
|
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func gobuild(debugname string) error {
|
||||||
|
return gocommand("build", "-o", debugname, BuildFlags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gotestbuild() error {
|
||||||
|
return gocommand("test", "-c", BuildFlags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gocommand(command string, args ...string) error {
|
||||||
|
allargs := []string{command, "-gcflags", "-N -l"}
|
||||||
|
allargs = append(allargs, args...)
|
||||||
|
goBuild := exec.Command("go", allargs...)
|
||||||
|
goBuild.Stderr = os.Stderr
|
||||||
|
return goBuild.Run()
|
||||||
|
}
|
||||||
|
@ -65,6 +65,7 @@ func (s *ServerImpl) Run() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
defer s.s.listener.Close()
|
||||||
|
|
||||||
rpcs := grpc.NewServer()
|
rpcs := grpc.NewServer()
|
||||||
rpcs.Register(s.s)
|
rpcs.Register(s.s)
|
||||||
|
Loading…
Reference in New Issue
Block a user