delve/client/cli/cli.go

198 lines
4.0 KiB
Go
Raw Normal View History

package cli
import (
"fmt"
"io"
"os"
"os/exec"
"os/signal"
"path/filepath"
2015-03-09 02:26:45 +00:00
"strconv"
"strings"
sys "golang.org/x/sys/unix"
"github.com/derekparker/delve/command"
"github.com/derekparker/delve/proctl"
2015-02-27 21:02:46 +00:00
"github.com/peterh/liner"
)
const historyFile string = ".dbg_history"
2015-03-09 02:26:45 +00:00
func Run(args []string) {
var (
2015-02-27 21:02:46 +00:00
dbp *proctl.DebuggedProcess
err error
line = liner.NewLiner()
)
2015-02-27 21:02:46 +00:00
defer line.Close()
2015-03-09 02:26:45 +00:00
switch args[0] {
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-20 05:10:32 +00:00
dbp, err = proctl.Launch(append([]string{"./" + debugname}, args...))
if err != nil {
die(1, "Could not launch program:", err)
}
case "test":
wd, err := os.Getwd()
if err != nil {
die(1, err)
}
base := filepath.Base(wd)
cmd := exec.Command("go", "test", "-c", "-gcflags", "-N -l")
err = cmd.Run()
if err != nil {
die(1, "Could not compile program:", err)
}
debugname := "./" + base + ".test"
defer os.Remove(debugname)
dbp, err = proctl.Launch(append([]string{debugname}, args...))
if err != nil {
die(1, "Could not launch program:", err)
}
2015-03-09 02:26:45 +00:00
case "attach":
pid, err := strconv.Atoi(args[1])
if err != nil {
die(1, "Invalid pid", args[1])
}
dbp, err = proctl.Attach(pid)
if err != nil {
die(1, "Could not attach to process:", err)
}
default:
2014-12-20 05:10:32 +00:00
dbp, err = proctl.Launch(args)
if err != nil {
die(1, "Could not launch program:", err)
}
}
ch := make(chan os.Signal)
signal.Notify(ch, sys.SIGINT)
go func() {
for _ = range ch {
if dbp.Running() {
dbp.RequestManualStop()
}
}
}()
cmds := command.DebugCommands()
2015-03-01 16:15:16 +00:00
f, err := os.Open(historyFile)
if err != nil {
f, _ = os.Create(historyFile)
2015-02-27 21:02:46 +00:00
}
2015-03-01 16:15:16 +00:00
line.ReadHistory(f)
f.Close()
fmt.Println("Type 'help' for list of commands.")
for {
2015-02-27 21:02:46 +00:00
cmdstr, err := promptForInput(line)
if err != nil {
if err == io.EOF {
2015-02-27 21:02:46 +00:00
handleExit(dbp, line, 0)
}
die(1, "Prompt for input failed.\n")
}
cmdstr, args := parseCommand(cmdstr)
if cmdstr == "exit" {
2015-02-27 21:02:46 +00:00
handleExit(dbp, line, 0)
}
cmd := cmds.Find(cmdstr)
if err := cmd(dbp, args...); err != nil {
switch err.(type) {
case proctl.ProcessExitedError:
pe := err.(proctl.ProcessExitedError)
fmt.Fprintf(os.Stderr, "Process exited with status %d\n", pe.Status)
default:
fmt.Fprintf(os.Stderr, "Command failed: %s\n", err)
}
}
}
}
2015-02-27 21:02:46 +00:00
func handleExit(dbp *proctl.DebuggedProcess, line *liner.State, status int) {
2015-03-01 16:15:16 +00:00
if f, err := os.OpenFile(historyFile, os.O_RDWR, 0666); err == nil {
_, err := line.WriteHistory(f)
if err != nil {
2015-03-01 16:17:30 +00:00
fmt.Println("readline history error: ", err)
2015-03-01 16:15:16 +00:00
}
2015-02-27 21:02:46 +00:00
f.Close()
2014-12-20 05:10:32 +00:00
}
2015-02-27 21:02:46 +00:00
answer, err := line.Prompt("Would you like to kill the process? [y/n]")
if err != nil {
die(2, io.EOF)
}
2015-02-27 21:02:46 +00:00
answer = strings.TrimSuffix(answer, "\n")
for _, bp := range dbp.HWBreakPoints {
if bp == nil {
continue
}
if _, err := dbp.Clear(bp.Addr); err != nil {
fmt.Printf("Can't clear breakpoint @%x: %s\n", bp.Addr, err)
}
}
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...")
2015-02-27 21:02:46 +00:00
err = sys.PtraceDetach(dbp.Process.Pid)
if err != nil {
die(2, "Could not detach", err)
}
if answer == "y" {
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{}) {
fmt.Fprint(os.Stderr, args)
fmt.Fprint(os.Stderr, "\n")
os.Exit(status)
}
func parseCommand(cmdstr string) (string, []string) {
vals := strings.Split(cmdstr, " ")
return vals[0], vals[1:]
}
2015-02-27 21:02:46 +00:00
func promptForInput(line *liner.State) (string, error) {
l, err := line.Prompt("(dlv) ")
if err != nil {
return "", err
}
2015-02-27 21:02:46 +00:00
l = strings.TrimSuffix(l, "\n")
if l != "" {
line.AppendHistory(l)
}
2015-02-27 21:02:46 +00:00
return l, nil
}