delve/cmd/dlv/main.go

177 lines
3.6 KiB
Go
Raw Normal View History

2014-05-20 21:29:01 +00:00
package main
import (
"bufio"
"flag"
2014-05-20 21:29:01 +00:00
"fmt"
"io"
2014-05-20 21:29:01 +00:00
"os"
"os/exec"
2014-09-21 23:59:19 +00:00
"runtime"
2014-05-20 21:29:01 +00:00
"strings"
"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
)
2014-12-11 16:26:31 +00:00
const version string = "0.3.0.beta"
2014-11-10 12:53:33 +00:00
2014-05-20 21:29:01 +00:00
type term struct {
stdin *bufio.Reader
}
const historyFile string = ".dbg_history"
2014-11-23 16:22:04 +00:00
func init() {
// 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.
runtime.LockOSThread()
2014-11-23 16:22:04 +00:00
}
2014-11-23 16:22:04 +00:00
func main() {
var (
2014-12-09 18:11:47 +00:00
pid int
run bool
printv bool
err error
dbp *proctl.DebuggedProcess
t = newTerm()
cmds = command.DebugCommands()
)
2014-05-20 23:11:00 +00:00
flag.IntVar(&pid, "pid", 0, "Pid of running process to attach to.")
flag.BoolVar(&run, "run", false, "Compile program and begin debug session.")
2014-11-10 12:53:33 +00:00
flag.BoolVar(&printv, "v", false, "Print version number and exit.")
flag.Parse()
2014-05-20 23:11:00 +00:00
if flag.NFlag() == 0 && len(flag.Args()) == 0 {
flag.Usage()
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)
}
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-12-09 18:11:47 +00:00
dbp, err = proctl.Launch(append([]string{"./" + debugname}, flag.Args()...))
if err != nil {
die(1, "Could not launch program:", err)
}
case pid != 0:
2014-12-09 18:11:47 +00:00
dbp, err = proctl.Attach(pid)
if err != nil {
die(1, "Could not attach to process:", err)
}
default:
2014-12-09 18:11:47 +00:00
dbp, err = proctl.Launch(flag.Args())
if err != nil {
die(1, "Could not launch program:", err)
}
}
goreadline.LoadHistoryFromFile(historyFile)
2014-10-20 17:06:36 +00:00
fmt.Println("Type 'help' for list of commands.")
for {
cmdstr, err := t.promptForInput()
if err != nil {
if err == io.EOF {
2014-12-09 18:11:47 +00:00
handleExit(t, dbp, 0)
}
die(1, "Prompt for input failed.\n")
}
cmdstr, args := parseCommand(cmdstr)
if cmdstr == "exit" {
2014-12-09 18:11:47 +00:00
handleExit(t, dbp, 0)
}
cmd := cmds.Find(cmdstr)
2014-12-09 18:11:47 +00:00
err = cmd(dbp, args...)
if err != nil {
fmt.Fprintf(os.Stderr, "Command failed: %s\n", err)
}
}
}
2014-12-02 00:06:27 +00:00
func handleExit(t *term, dbp *proctl.DebuggedProcess, status int) {
errno := goreadline.WriteHistoryToFile(historyFile)
fmt.Println("readline:", errno)
fmt.Println("Would you like to kill the process? [y/n]")
answer, err := t.stdin.ReadString('\n')
if err != nil {
die(2, err.Error())
}
2014-11-12 22:47:40 +00:00
for pc := range dbp.BreakPoints {
if _, err := dbp.Clear(pc); err != nil {
fmt.Printf("Can't clear breakpoint @%x: %s\n", pc, err)
}
}
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)
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-12-02 18:40:53 +00:00
prompt := "(dlv) "
linep := goreadline.ReadLine(&prompt)
if linep == nil {
return "", io.EOF
}
line := strings.TrimSuffix(*linep, "\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
}