2014-05-20 21:29:01 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
2014-08-23 13:20:56 +00:00
|
|
|
"flag"
|
2014-05-20 21:29:01 +00:00
|
|
|
"fmt"
|
|
|
|
"os"
|
2014-08-23 13:20:56 +00:00
|
|
|
"os/exec"
|
2014-09-21 23:59:19 +00:00
|
|
|
|
2014-05-23 20:27:08 +00:00
|
|
|
"runtime"
|
2014-05-20 21:29:01 +00:00
|
|
|
"strings"
|
2014-08-23 13:20:56 +00:00
|
|
|
"syscall"
|
2014-05-20 21:29:01 +00:00
|
|
|
|
2014-10-15 14:21:46 +00:00
|
|
|
"github.com/derekparker/delve/command"
|
|
|
|
"github.com/derekparker/delve/goreadline"
|
|
|
|
"github.com/derekparker/delve/proctl"
|
2014-05-20 21:29:01 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type term struct {
|
|
|
|
stdin *bufio.Reader
|
|
|
|
}
|
|
|
|
|
2014-09-30 13:50:12 +00:00
|
|
|
const historyFile string = ".dbg_history"
|
|
|
|
|
2014-05-20 21:29:01 +00:00
|
|
|
func main() {
|
2014-05-23 20:27:08 +00:00
|
|
|
// We must ensure here that we are running on the same thread during
|
|
|
|
// the execution of dbg. This is due to the fact that ptrace(2) expects
|
2014-05-24 00:01:56 +00:00
|
|
|
// all commands after PTRACE_ATTACH to come from the same thread.
|
2014-05-23 20:27:08 +00:00
|
|
|
runtime.LockOSThread()
|
|
|
|
|
2014-06-25 19:58:45 +00:00
|
|
|
var (
|
2014-10-13 23:30:37 +00:00
|
|
|
pid int
|
|
|
|
proc string
|
|
|
|
run bool
|
|
|
|
err error
|
|
|
|
dbgproc *proctl.DebuggedProcess
|
|
|
|
t = newTerm()
|
|
|
|
cmds = command.DebugCommands()
|
2014-06-25 19:58:45 +00:00
|
|
|
)
|
2014-05-20 23:11:00 +00:00
|
|
|
|
2014-08-23 13:20:56 +00:00
|
|
|
flag.IntVar(&pid, "pid", 0, "Pid of running process to attach to.")
|
|
|
|
flag.StringVar(&proc, "proc", "", "Path to process to run and debug.")
|
2014-10-13 23:30:37 +00:00
|
|
|
flag.BoolVar(&run, "run", false, "Compile program and begin debug session.")
|
2014-08-23 13:20:56 +00:00
|
|
|
flag.Parse()
|
2014-05-20 23:11:00 +00:00
|
|
|
|
2014-08-23 13:20:56 +00:00
|
|
|
if flag.NFlag() == 0 {
|
|
|
|
flag.Usage()
|
|
|
|
os.Exit(0)
|
2014-05-20 23:11:00 +00:00
|
|
|
}
|
|
|
|
|
2014-10-13 23:30:37 +00:00
|
|
|
start := func(name string) *proctl.DebuggedProcess {
|
|
|
|
proc := exec.Command(name)
|
|
|
|
proc.Stdout = os.Stdout
|
2014-05-20 23:11:00 +00:00
|
|
|
|
2014-10-13 23:30:37 +00:00
|
|
|
err = proc.Start()
|
2014-05-20 21:29:01 +00:00
|
|
|
if err != nil {
|
2014-10-13 23:30:37 +00:00
|
|
|
die(1, "Could not start process:", err)
|
2014-08-23 13:20:56 +00:00
|
|
|
}
|
|
|
|
|
2014-10-13 23:30:37 +00:00
|
|
|
dbgproc, err = proctl.NewDebugProcess(proc.Process.Pid)
|
2014-05-20 21:29:01 +00:00
|
|
|
if err != nil {
|
2014-10-13 23:30:37 +00:00
|
|
|
die(1, "Could not start debugging process:", err)
|
2014-05-20 21:29:01 +00:00
|
|
|
}
|
2014-10-13 23:30:37 +00:00
|
|
|
|
|
|
|
return dbgproc
|
2014-05-20 21:29:01 +00:00
|
|
|
}
|
|
|
|
|
2014-10-13 23:30:37 +00:00
|
|
|
switch {
|
|
|
|
case run:
|
|
|
|
const debugname = "debug"
|
|
|
|
cmd := exec.Command("go", "build", "-o", debugname, "-gcflags", "-N -l")
|
|
|
|
err := cmd.Run()
|
|
|
|
if err != nil {
|
|
|
|
die(1, "Could not compile program:", err)
|
|
|
|
}
|
|
|
|
defer os.Remove(debugname)
|
2014-08-23 13:20:56 +00:00
|
|
|
|
2014-10-13 23:30:37 +00:00
|
|
|
dbgproc = start("./" + debugname)
|
|
|
|
case pid != 0:
|
2014-08-23 13:20:56 +00:00
|
|
|
dbgproc, err = proctl.NewDebugProcess(pid)
|
|
|
|
if err != nil {
|
|
|
|
die(1, "Could not start debugging process:", err)
|
|
|
|
}
|
2014-10-13 23:30:37 +00:00
|
|
|
case proc != "":
|
|
|
|
dbgproc = start(proc)
|
2014-08-23 13:20:56 +00:00
|
|
|
}
|
|
|
|
|
2014-10-13 23:30:37 +00:00
|
|
|
goreadline.LoadHistoryFromFile(historyFile)
|
2014-08-23 13:20:56 +00:00
|
|
|
|
2014-10-13 23:30:37 +00:00
|
|
|
for {
|
|
|
|
cmdstr, err := t.promptForInput()
|
2014-08-23 13:20:56 +00:00
|
|
|
if err != nil {
|
2014-10-13 23:30:37 +00:00
|
|
|
die(1, "Prompt for input failed.\n")
|
2014-08-23 13:20:56 +00:00
|
|
|
}
|
|
|
|
|
2014-10-13 23:30:37 +00:00
|
|
|
cmdstr, args := parseCommand(cmdstr)
|
|
|
|
|
|
|
|
if cmdstr == "exit" {
|
|
|
|
err := goreadline.WriteHistoryToFile(historyFile)
|
|
|
|
fmt.Println(err)
|
|
|
|
handleExit(t, dbgproc, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd := cmds.Find(cmdstr)
|
|
|
|
err = cmd(dbgproc, args...)
|
2014-08-23 13:20:56 +00:00
|
|
|
if err != nil {
|
2014-10-13 23:30:37 +00:00
|
|
|
fmt.Fprintf(os.Stderr, "Command failed: %s\n", err)
|
2014-08-23 13:20:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func handleExit(t *term, dbp *proctl.DebuggedProcess, status int) {
|
|
|
|
fmt.Println("Would you like to kill the process? [y/n]")
|
|
|
|
answer, err := t.stdin.ReadString('\n')
|
|
|
|
if err != nil {
|
|
|
|
die(2, err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println("Detaching from process...")
|
|
|
|
err = syscall.PtraceDetach(dbp.Process.Pid)
|
|
|
|
if err != nil {
|
|
|
|
die(2, "Could not detach", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if answer == "y\n" {
|
|
|
|
fmt.Println("Killing process", dbp.Process.Pid)
|
|
|
|
|
|
|
|
err := dbp.Process.Kill()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println("Could not kill process", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
die(status, "Hope I was of service hunting your bug!")
|
|
|
|
}
|
|
|
|
|
|
|
|
func die(status int, args ...interface{}) {
|
2014-05-20 23:11:00 +00:00
|
|
|
fmt.Fprint(os.Stderr, args)
|
2014-08-23 13:20:56 +00:00
|
|
|
fmt.Fprint(os.Stderr, "\n")
|
|
|
|
os.Exit(status)
|
2014-05-20 23:11:00 +00:00
|
|
|
}
|
|
|
|
|
2014-05-20 21:29:01 +00:00
|
|
|
func newTerm() *term {
|
|
|
|
return &term{
|
|
|
|
stdin: bufio.NewReader(os.Stdin),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-27 15:44:29 +00:00
|
|
|
func parseCommand(cmdstr string) (string, []string) {
|
|
|
|
vals := strings.Split(cmdstr, " ")
|
|
|
|
return vals[0], vals[1:]
|
|
|
|
}
|
|
|
|
|
2014-05-20 21:29:01 +00:00
|
|
|
func (t *term) promptForInput() (string, error) {
|
2014-09-19 22:02:06 +00:00
|
|
|
prompt := "dbg> "
|
|
|
|
line := *goreadline.ReadLine(&prompt)
|
2014-09-21 23:59:19 +00:00
|
|
|
line = strings.TrimSuffix(line, "\n")
|
2014-09-19 22:02:06 +00:00
|
|
|
if line != "" {
|
|
|
|
goreadline.AddHistory(line)
|
2014-05-20 21:29:01 +00:00
|
|
|
}
|
|
|
|
|
2014-09-21 23:59:19 +00:00
|
|
|
return line, nil
|
2014-05-20 21:29:01 +00:00
|
|
|
}
|