2014-05-20 21:29:01 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2014-08-23 13:20:56 +00:00
|
|
|
"flag"
|
2014-05-20 21:29:01 +00:00
|
|
|
"fmt"
|
2015-03-20 21:11:11 +00:00
|
|
|
"net"
|
2014-05-20 21:29:01 +00:00
|
|
|
"os"
|
2015-03-20 21:11:11 +00:00
|
|
|
"os/exec"
|
2015-04-17 20:49:49 +00:00
|
|
|
"os/signal"
|
2015-03-20 21:11:11 +00:00
|
|
|
"path/filepath"
|
|
|
|
"strconv"
|
2014-05-20 21:29:01 +00:00
|
|
|
|
2015-05-08 22:26:09 +00:00
|
|
|
sys "golang.org/x/sys/unix"
|
|
|
|
|
2015-06-21 03:47:44 +00:00
|
|
|
"github.com/derekparker/delve/service"
|
|
|
|
"github.com/derekparker/delve/service/rpc"
|
2015-03-20 21:11:11 +00:00
|
|
|
"github.com/derekparker/delve/terminal"
|
2014-05-20 21:29:01 +00:00
|
|
|
)
|
|
|
|
|
2015-03-01 16:18:05 +00:00
|
|
|
const version string = "0.5.0.beta"
|
2014-11-10 12:53:33 +00:00
|
|
|
|
2015-04-25 14:49:12 +00:00
|
|
|
var usage string = `Delve version %s
|
2015-03-09 02:26:45 +00:00
|
|
|
flags:
|
2015-04-25 14:49:12 +00:00
|
|
|
%s
|
2015-03-09 02:26:45 +00:00
|
|
|
Invoke with the path to a binary:
|
2015-03-09 03:01:14 +00:00
|
|
|
dlv ./path/to/prog
|
2015-03-09 02:26:45 +00:00
|
|
|
or use the following commands:
|
|
|
|
run - Build, run, and attach to program
|
2015-03-09 03:59:37 +00:00
|
|
|
test - Build test binary, run and attach to it
|
2015-03-09 02:26:45 +00:00
|
|
|
attach - Attach to running process
|
2015-04-25 14:49:12 +00:00
|
|
|
`
|
2015-03-09 02:26:45 +00:00
|
|
|
|
2014-11-23 16:22:04 +00:00
|
|
|
func init() {
|
2015-04-25 14:49:12 +00:00
|
|
|
flag.Usage = help
|
2014-11-23 16:22:04 +00:00
|
|
|
}
|
2014-05-23 20:27:08 +00:00
|
|
|
|
2014-11-23 16:22:04 +00:00
|
|
|
func main() {
|
2015-04-25 14:49:12 +00:00
|
|
|
var printv, printhelp bool
|
2015-03-20 21:11:11 +00:00
|
|
|
var addr string
|
|
|
|
var logEnabled bool
|
2015-04-17 20:49:49 +00:00
|
|
|
var headless bool
|
2015-03-09 02:26:45 +00:00
|
|
|
|
2015-03-20 21:11:11 +00:00
|
|
|
flag.BoolVar(&printv, "version", false, "Print version number and exit.")
|
|
|
|
flag.StringVar(&addr, "addr", "localhost:0", "Debugging server listen address.")
|
|
|
|
flag.BoolVar(&logEnabled, "log", false, "Enable debugging server logging.")
|
2015-04-17 20:49:49 +00:00
|
|
|
flag.BoolVar(&headless, "headless", false, "Run in headless mode.")
|
2014-08-23 13:20:56 +00:00
|
|
|
flag.Parse()
|
2014-05-20 23:11:00 +00:00
|
|
|
|
2014-11-14 07:41:12 +00:00
|
|
|
if flag.NFlag() == 0 && len(flag.Args()) == 0 {
|
2015-04-25 14:49:12 +00:00
|
|
|
help()
|
2014-08-23 13:20:56 +00:00
|
|
|
os.Exit(0)
|
2014-05-20 23:11:00 +00:00
|
|
|
}
|
|
|
|
|
2014-11-10 12:53:33 +00:00
|
|
|
if printv {
|
|
|
|
fmt.Printf("Delve version: %s\n", version)
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
|
2015-04-25 14:49:12 +00:00
|
|
|
if printhelp {
|
|
|
|
help()
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
|
2015-06-27 04:05:15 +00:00
|
|
|
defer func() {
|
|
|
|
if err := recover(); err != nil {
|
|
|
|
fmt.Fprintln(os.Stderr, err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2015-06-24 13:08:48 +00:00
|
|
|
status := run(addr, logEnabled, headless)
|
2015-06-13 23:16:09 +00:00
|
|
|
fmt.Println("[Hope I was of service hunting your bug!]")
|
|
|
|
os.Exit(status)
|
|
|
|
}
|
|
|
|
|
2015-06-24 13:08:48 +00:00
|
|
|
func run(addr string, logEnabled, headless bool) int {
|
2015-03-20 21:11:11 +00:00
|
|
|
// Collect launch arguments
|
|
|
|
var processArgs []string
|
|
|
|
var attachPid int
|
|
|
|
switch flag.Args()[0] {
|
|
|
|
case "run":
|
|
|
|
const debugname = "debug"
|
|
|
|
cmd := exec.Command("go", "build", "-o", debugname, "-gcflags", "-N -l")
|
|
|
|
err := cmd.Run()
|
|
|
|
if err != nil {
|
2015-06-13 23:16:09 +00:00
|
|
|
fmt.Println("Could not compile program:", err)
|
|
|
|
return 1
|
2015-03-20 21:11:11 +00:00
|
|
|
}
|
2015-06-13 23:16:09 +00:00
|
|
|
fp, err := filepath.Abs("./" + debugname)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
defer os.Remove(fp)
|
2015-03-20 21:11:11 +00:00
|
|
|
|
2015-05-08 20:14:04 +00:00
|
|
|
processArgs = append([]string{"./" + debugname}, flag.Args()[1:]...)
|
2015-03-20 21:11:11 +00:00
|
|
|
case "test":
|
|
|
|
wd, err := os.Getwd()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
2015-06-13 23:16:09 +00:00
|
|
|
return 1
|
2015-03-20 21:11:11 +00:00
|
|
|
}
|
|
|
|
base := filepath.Base(wd)
|
|
|
|
cmd := exec.Command("go", "test", "-c", "-gcflags", "-N -l")
|
|
|
|
err = cmd.Run()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Errorf("Could not compile program: %s\n", err)
|
2015-06-13 23:16:09 +00:00
|
|
|
return 1
|
2015-03-20 21:11:11 +00:00
|
|
|
}
|
|
|
|
debugname := "./" + base + ".test"
|
|
|
|
defer os.Remove(debugname)
|
|
|
|
|
2015-05-08 20:14:04 +00:00
|
|
|
processArgs = append([]string{debugname}, flag.Args()[1:]...)
|
2015-03-20 21:11:11 +00:00
|
|
|
case "attach":
|
|
|
|
pid, err := strconv.Atoi(flag.Args()[1])
|
|
|
|
if err != nil {
|
|
|
|
fmt.Errorf("Invalid pid: %d", flag.Args()[1])
|
2015-06-13 23:16:09 +00:00
|
|
|
return 1
|
2015-03-20 21:11:11 +00:00
|
|
|
}
|
|
|
|
attachPid = pid
|
|
|
|
default:
|
|
|
|
processArgs = flag.Args()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make a TCP listener
|
|
|
|
listener, err := net.Listen("tcp", addr)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("couldn't start listener: %s\n", err)
|
2015-06-13 23:16:09 +00:00
|
|
|
return 1
|
2015-03-20 21:11:11 +00:00
|
|
|
}
|
2015-06-27 04:05:15 +00:00
|
|
|
defer listener.Close()
|
2015-03-20 21:11:11 +00:00
|
|
|
|
2015-06-21 03:47:44 +00:00
|
|
|
// Create and start a debugger server
|
|
|
|
var server service.Server
|
2015-06-24 13:08:48 +00:00
|
|
|
server = rpc.NewServer(&service.Config{
|
|
|
|
Listener: listener,
|
|
|
|
ProcessArgs: processArgs,
|
|
|
|
AttachPid: attachPid,
|
|
|
|
}, logEnabled)
|
2015-06-27 04:05:15 +00:00
|
|
|
if err := server.Run(); err != nil {
|
|
|
|
fmt.Fprintln(os.Stderr, err)
|
|
|
|
return 1
|
|
|
|
}
|
2015-03-20 21:11:11 +00:00
|
|
|
|
2015-06-13 23:16:09 +00:00
|
|
|
var status int
|
2015-04-17 20:49:49 +00:00
|
|
|
if !headless {
|
|
|
|
// Create and start a terminal
|
2015-06-21 03:47:44 +00:00
|
|
|
var client service.Client
|
2015-06-24 13:08:48 +00:00
|
|
|
client = rpc.NewClient(listener.Addr().String())
|
2015-04-17 20:49:49 +00:00
|
|
|
term := terminal.New(client)
|
|
|
|
err, status = term.Run()
|
|
|
|
} else {
|
|
|
|
ch := make(chan os.Signal)
|
|
|
|
signal.Notify(ch, sys.SIGINT)
|
|
|
|
<-ch
|
|
|
|
err = server.Stop(true)
|
|
|
|
}
|
|
|
|
|
2015-03-20 21:11:11 +00:00
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
}
|
2015-06-13 23:16:09 +00:00
|
|
|
|
|
|
|
return status
|
2014-05-20 21:29:01 +00:00
|
|
|
}
|
2015-04-25 14:49:12 +00:00
|
|
|
|
|
|
|
// help prints help text to os.Stderr.
|
|
|
|
func help() {
|
|
|
|
flags := ""
|
|
|
|
flag.VisitAll(func(f *flag.Flag) {
|
|
|
|
doc := fmt.Sprintf(" -%s=%s: %s\n", f.Name, f.DefValue, f.Usage)
|
|
|
|
flags += doc
|
|
|
|
})
|
|
|
|
fmt.Fprintf(os.Stderr, usage, version, flags)
|
|
|
|
}
|