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

import (
	"bufio"
5
	"debug/gosym"
D
Derek Parker 已提交
6 7
	"fmt"
	"os"
8
	"path/filepath"
9
	"runtime"
D
Derek Parker 已提交
10
	"strconv"
D
Derek Parker 已提交
11 12
	"strings"

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()

D
Derek Parker 已提交
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
	t := newTerm()

	if len(os.Args) == 1 {
		printStderrAndDie("You must provide a pid\n")
	}

	pid, err := strconv.Atoi(os.Args[1])
	if err != nil {
		printStderrAndDie(err)
	}

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

	cmds := command.DebugCommands()
	registerProcessCommands(cmds, dbgproc)
D
Derek Parker 已提交
45 46 47 48

	for {
		cmdstr, err := t.promptForInput()
		if err != nil {
D
Derek Parker 已提交
49
			printStderrAndDie("Prompt for input failed.\n")
D
Derek Parker 已提交
50 51
		}

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

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

D
Derek Parker 已提交
62 63 64 65 66 67
func printStderrAndDie(args ...interface{}) {
	fmt.Fprint(os.Stderr, args)
	os.Exit(1)
}

func registerProcessCommands(cmds *command.Commands, proc *proctl.DebuggedProcess) {
D
Derek Parker 已提交
68
	cmds.Register("continue", command.CommandFunc(proc.Continue))
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
	cmds.Register("step", func(args ...string) error {
		err := proc.Step()
		if err != nil {
			return err
		}

		regs, err := proc.Registers()
		if err != nil {
			return err
		}

		f, l, _ := proc.GoSymTable.PCToLine(regs.PC())
		fmt.Printf("Stopped at: %s:%d\n", f, l)

		return nil
	})

D
Derek Parker 已提交
86 87
	cmds.Register("clear", func(args ...string) error {
		fname := args[0]
D
Derek Parker 已提交
88 89 90 91 92 93
		fn := proc.GoSymTable.LookupFunc(fname)
		if fn == nil {
			return fmt.Errorf("No function named %s", fname)
		}

		bp, err := proc.Clear(fn.Entry)
D
Derek Parker 已提交
94 95 96 97 98 99 100 101 102
		if err != nil {
			return err
		}

		fmt.Printf("Breakpoint cleared at %#v for %s %s:%d\n", bp.Addr, bp.FunctionName, bp.File, bp.Line)

		return nil
	})

D
Derek Parker 已提交
103
	cmds.Register("break", func(args ...string) error {
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
		var (
			fn    *gosym.Func
			pc    uint64
			fname = args[0]
		)

		if strings.ContainsRune(fname, ':') {
			fl := strings.Split(fname, ":")

			f, err := filepath.Abs(fl[0])
			if err != nil {
				return err
			}

			l, err := strconv.Atoi(fl[1])
			if err != nil {
				return err
			}

			pc, fn, err = proc.GoSymTable.LineToPC(f, l)
			if err != nil {
				return err
			}
		} else {
			fn = proc.GoSymTable.LookupFunc(fname)
			pc = fn.Entry
		}

D
Derek Parker 已提交
132 133 134 135
		if fn == nil {
			return fmt.Errorf("No function named %s", fname)
		}

136
		bp, err := proc.Break(uintptr(pc))
D
Derek Parker 已提交
137 138 139 140 141 142 143 144
		if err != nil {
			return err
		}

		fmt.Printf("Breakpoint set at %#v for %s %s:%d\n", bp.Addr, bp.FunctionName, bp.File, bp.Line)

		return nil
	})
D
Derek Parker 已提交
145 146
}

D
Derek Parker 已提交
147 148 149 150 151 152
func newTerm() *term {
	return &term{
		stdin: bufio.NewReader(os.Stdin),
	}
}

D
Derek Parker 已提交
153 154 155 156 157
func parseCommand(cmdstr string) (string, []string) {
	vals := strings.Split(cmdstr, " ")
	return vals[0], vals[1:]
}

D
Derek Parker 已提交
158 159 160 161 162 163 164 165
func (t *term) promptForInput() (string, error) {
	fmt.Print("dbg> ")

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

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