delve/client/cli/cli.go

169 lines
3.3 KiB
Go
Raw Normal View History

package cli
import (
"fmt"
"io"
"os"
"os/exec"
"os/signal"
"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"
2014-12-20 05:10:32 +00:00
func Run(run bool, pid int, 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()
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-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 pid != 0:
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)
err = cmd(dbp, args...)
if err != nil {
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 {
fmt.Println("readline histroy: ", err)
}
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
}