main.go 2.8 KB
Newer Older
D
Derek Parker 已提交
1 2 3 4
package main

import (
	"bufio"
5
	"flag"
D
Derek Parker 已提交
6 7
	"fmt"
	"os"
8
	"os/exec"
9
	"runtime"
D
Derek Parker 已提交
10
	"strings"
11
	"syscall"
D
Derek Parker 已提交
12

D
Derek Parker 已提交
13 14
	"github.com/derekparker/dbg/command"
	"github.com/derekparker/dbg/proctl"
D
Derek Parker 已提交
15 16 17 18 19 20 21
)

type term struct {
	stdin *bufio.Reader
}

func main() {
22 23
	// 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
D
Derek Parker 已提交
24
	// all commands after PTRACE_ATTACH to come from the same thread.
25 26
	runtime.LockOSThread()

27
	var (
28 29
		pid  int
		proc string
30 31 32
		t    = newTerm()
		cmds = command.DebugCommands()
	)
D
Derek Parker 已提交
33

34 35 36
	flag.IntVar(&pid, "pid", 0, "Pid of running process to attach to.")
	flag.StringVar(&proc, "proc", "", "Path to process to run and debug.")
	flag.Parse()
D
Derek Parker 已提交
37

38 39 40
	if flag.NFlag() == 0 {
		flag.Usage()
		os.Exit(0)
D
Derek Parker 已提交
41 42
	}

43
	dbgproc := beginTrace(pid, proc)
D
Derek Parker 已提交
44

D
Derek Parker 已提交
45 46 47
	for {
		cmdstr, err := t.promptForInput()
		if err != nil {
48
			die(1, "Prompt for input failed.\n")
D
Derek Parker 已提交
49 50
		}

D
Derek Parker 已提交
51 52
		cmdstr, args := parseCommand(cmdstr)

53 54 55 56
		if cmdstr == "exit" {
			handleExit(t, dbgproc, 0)
		}

D
Derek Parker 已提交
57
		cmd := cmds.Find(cmdstr)
58
		err = cmd(dbgproc, args...)
D
Derek Parker 已提交
59 60 61 62 63 64
		if err != nil {
			fmt.Fprintf(os.Stderr, "Command failed: %s\n", err)
		}
	}
}

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
func beginTrace(pid int, proc string) *proctl.DebuggedProcess {
	var (
		err     error
		dbgproc *proctl.DebuggedProcess
	)

	if pid != 0 {
		dbgproc, err = proctl.NewDebugProcess(pid)
		if err != nil {
			die(1, "Could not start debugging process:", err)
		}
	}

	if proc != "" {
		proc := exec.Command(proc)
		proc.Stdout = os.Stdout

		err = proc.Start()
		if err != nil {
			die(1, "Could not start process:", err)
		}

		dbgproc, err = proctl.NewDebugProcess(proc.Process.Pid)
		if err != nil {
			die(1, "Could not start debugging process:", err)
		}
	}

	return dbgproc
}

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{}) {
D
Derek Parker 已提交
122
	fmt.Fprint(os.Stderr, args)
123 124
	fmt.Fprint(os.Stderr, "\n")
	os.Exit(status)
D
Derek Parker 已提交
125 126
}

D
Derek Parker 已提交
127 128 129 130 131 132
func newTerm() *term {
	return &term{
		stdin: bufio.NewReader(os.Stdin),
	}
}

D
Derek Parker 已提交
133 134 135 136 137
func parseCommand(cmdstr string) (string, []string) {
	vals := strings.Split(cmdstr, " ")
	return vals[0], vals[1:]
}

D
Derek Parker 已提交
138 139 140 141 142 143 144 145
func (t *term) promptForInput() (string, error) {
	fmt.Print("dbg> ")

	line, err := t.stdin.ReadString('\n')
	if err != nil {
		return "", err
	}

D
Derek Parker 已提交
146
	return strings.TrimSuffix(line, "\n"), nil
D
Derek Parker 已提交
147
}