Refactor: Modify command registraion on bootup

Benefits of this CL:

* Commands no longer rely on closured proc struct
* No two-step process for basic command initializaion
This commit is contained in:
Derek Parker
2014-06-25 14:58:45 -05:00
parent feec416b1a
commit 7fe2037ff1
3 changed files with 110 additions and 116 deletions

View File

@ -3,11 +3,17 @@
package command
import (
"debug/gosym"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/derekparker/dbg/proctl"
)
type cmdfunc func(args ...string) error
type cmdfunc func(proc *proctl.DebuggedProcess, args ...string) error
type Commands struct {
cmds map[string]cmdfunc
@ -17,6 +23,10 @@ type Commands struct {
func DebugCommands() *Commands {
cmds := map[string]cmdfunc{
"exit": exitFunc,
"continue": cont,
"break": br,
"step": step,
"clear": clear,
"": nullCommand,
}
@ -45,20 +55,101 @@ func (c *Commands) Find(cmdstr string) cmdfunc {
}
func CommandFunc(fn func() error) cmdfunc {
return func(args ...string) error {
return func(p *proctl.DebuggedProcess, args ...string) error {
return fn()
}
}
func noCmdAvailable(args ...string) error {
func noCmdAvailable(p *proctl.DebuggedProcess, ars ...string) error {
return fmt.Errorf("command not available")
}
func exitFunc(args ...string) error {
func exitFunc(p *proctl.DebuggedProcess, ars ...string) error {
os.Exit(0)
return nil
}
func nullCommand(args ...string) error {
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
}
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
}
func br(p *proctl.DebuggedProcess, args ...string) error {
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)
pc = fn.Entry
}
if fn == nil {
return fmt.Errorf("No function named %s", fname)
}
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)
return nil
}

View File

@ -3,6 +3,8 @@ package command
import (
"fmt"
"testing"
"github.com/derekparker/dbg/proctl"
)
func TestCommandDefault(t *testing.T) {
@ -11,7 +13,7 @@ func TestCommandDefault(t *testing.T) {
cmd = cmds.Find("non-existant-command")
)
err := cmd()
err := cmd(nil)
if err == nil {
t.Fatal("cmd() did not default")
}
@ -21,35 +23,18 @@ func TestCommandDefault(t *testing.T) {
}
}
func TestCommandRegister(t *testing.T) {
cmds := Commands{make(map[string]cmdfunc)}
cmds.Register("foo", func(args ...string) error { return fmt.Errorf("registered command") })
cmd := cmds.Find("foo")
err := cmd()
if err == nil {
t.Fatal("cmd was not found")
}
if err.Error() != "registered command" {
t.Fatal("wrong command output")
}
}
func TestCommandReplay(t *testing.T) {
cmds := DebugCommands()
cmds.Register("foo", func(args ...string) error { return fmt.Errorf("registered command") })
cmds.Register("foo", func(p *proctl.DebuggedProcess, args ...string) error { return fmt.Errorf("registered command") })
cmd := cmds.Find("foo")
err := cmd()
err := cmd(nil)
if err.Error() != "registered command" {
t.Fatal("wrong command output")
}
cmd = cmds.Find("")
err = cmd()
err = cmd(nil)
if err.Error() != "registered command" {
t.Fatal("wrong command output")
}
@ -59,7 +44,7 @@ func TestCommandReplayWithoutPreviousCommand(t *testing.T) {
var (
cmds = DebugCommands()
cmd = cmds.Find("")
err = cmd()
err = cmd(nil)
)
if err != nil {

92
main.go
View File

@ -2,10 +2,8 @@ package main
import (
"bufio"
"debug/gosym"
"fmt"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
@ -24,7 +22,10 @@ func main() {
// all commands after PTRACE_ATTACH to come from the same thread.
runtime.LockOSThread()
t := newTerm()
var (
t = newTerm()
cmds = command.DebugCommands()
)
if len(os.Args) == 1 {
die("You must provide a pid\n")
@ -40,9 +41,6 @@ func main() {
die("Could not start debugging process:", err)
}
cmds := command.DebugCommands()
registerProcessCommands(cmds, dbgproc)
for {
cmdstr, err := t.promptForInput()
if err != nil {
@ -52,7 +50,7 @@ func main() {
cmdstr, args := parseCommand(cmdstr)
cmd := cmds.Find(cmdstr)
err = cmd(args...)
err = cmd(dbgproc, args...)
if err != nil {
fmt.Fprintf(os.Stderr, "Command failed: %s\n", err)
}
@ -64,86 +62,6 @@ func die(args ...interface{}) {
os.Exit(1)
}
func registerProcessCommands(cmds *command.Commands, proc *proctl.DebuggedProcess) {
cmds.Register("continue", command.CommandFunc(proc.Continue))
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
})
cmds.Register("clear", func(args ...string) error {
fname := args[0]
fn := proc.GoSymTable.LookupFunc(fname)
if fn == nil {
return fmt.Errorf("No function named %s", fname)
}
bp, err := proc.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
})
cmds.Register("break", func(args ...string) error {
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
}
if fn == nil {
return fmt.Errorf("No function named %s", fname)
}
bp, err := proc.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)
return nil
})
}
func newTerm() *term {
return &term{
stdin: bufio.NewReader(os.Stdin),