command.go 3.2 KB
Newer Older
D
Derek Parker 已提交
1 2
// Package command implements functions for responding to user
// input and dispatching to appropriate backend commands.
D
Derek Parker 已提交
3 4 5
package command

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

	"github.com/derekparker/dbg/proctl"
D
Derek Parker 已提交
13 14
)

15
type cmdfunc func(proc *proctl.DebuggedProcess, args ...string) error
D
Derek Parker 已提交
16 17 18 19 20

type Commands struct {
	cmds map[string]cmdfunc
}

21
// Returns a Commands struct with default commands defined.
D
Derek Parker 已提交
22 23
func DebugCommands() *Commands {
	cmds := map[string]cmdfunc{
24
		"continue": cont,
D
Derek Parker 已提交
25
		"next":     next,
D
Derek Parker 已提交
26
		"break":    breakpoint,
27 28 29
		"step":     step,
		"clear":    clear,
		"":         nullCommand,
D
Derek Parker 已提交
30 31 32 33 34
	}

	return &Commands{cmds}
}

D
Derek Parker 已提交
35 36
// Register custom commands. Expects cf to be a func of type cmdfunc,
// returning only an error.
D
Derek Parker 已提交
37 38 39 40
func (c *Commands) Register(cmdstr string, cf cmdfunc) {
	c.cmds[cmdstr] = cf
}

41 42 43
// Find will look up the command function for the given command input.
// If it cannot find the command it will defualt to noCmdAvailable().
// If the command is an empty string it will replay the last command.
D
Derek Parker 已提交
44 45 46 47 48 49
func (c *Commands) Find(cmdstr string) cmdfunc {
	cmd, ok := c.cmds[cmdstr]
	if !ok {
		return noCmdAvailable
	}

50 51 52
	// Allow <enter> to replay last command
	c.cmds[""] = cmd

D
Derek Parker 已提交
53 54 55
	return cmd
}

D
Derek Parker 已提交
56
func CommandFunc(fn func() error) cmdfunc {
57
	return func(p *proctl.DebuggedProcess, args ...string) error {
D
Derek Parker 已提交
58 59 60 61
		return fn()
	}
}

62
func noCmdAvailable(p *proctl.DebuggedProcess, ars ...string) error {
D
Derek Parker 已提交
63 64 65
	return fmt.Errorf("command not available")
}

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
func nullCommand(p *proctl.DebuggedProcess, ars ...string) error {
	return nil
}

func cont(p *proctl.DebuggedProcess, ars ...string) error {
	return p.Continue()
}

func step(p *proctl.DebuggedProcess, args ...string) error {
	err := p.Step()
	if err != nil {
		return err
	}

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

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

	return nil
}

D
Derek Parker 已提交
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
func next(p *proctl.DebuggedProcess, args ...string) error {
	err := p.Next()
	if err != nil {
		return err
	}

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

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

	return nil
}

108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
func clear(p *proctl.DebuggedProcess, args ...string) error {
	fname := args[0]
	fn := p.GoSymTable.LookupFunc(fname)
	if fn == nil {
		return fmt.Errorf("No function named %s", fname)
	}

	bp, err := p.Clear(fn.Entry)
	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 已提交
125
func breakpoint(p *proctl.DebuggedProcess, args ...string) error {
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
	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 = p.GoSymTable.LineToPC(f, l)
		if err != nil {
			return err
		}
	} else {
		fn = p.GoSymTable.LookupFunc(fname)
151 152 153
		if fn == nil {
			return fmt.Errorf("No function named %s", fname)
		}
154

155
		pc = fn.Entry
156 157 158 159 160 161 162 163 164
	}

	bp, err := p.Break(uintptr(pc))
	if err != nil {
		return err
	}

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

165 166
	return nil
}