From 7fe2037ff190031a413588bbbc0283e84c4285c9 Mon Sep 17 00:00:00 2001 From: Derek Parker Date: Wed, 25 Jun 2014 14:58:45 -0500 Subject: [PATCH] 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 --- command/command.go | 105 +++++++++++++++++++++++++++++++++++++--- command/command_test.go | 29 +++-------- main.go | 92 ++--------------------------------- 3 files changed, 110 insertions(+), 116 deletions(-) diff --git a/command/command.go b/command/command.go index edf6ecdf..c12316fe 100644 --- a/command/command.go +++ b/command/command.go @@ -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 @@ -16,8 +22,12 @@ type Commands struct { // Returns a Commands struct with default commands defined. func DebugCommands() *Commands { cmds := map[string]cmdfunc{ - "exit": exitFunc, - "": nullCommand, + "exit": exitFunc, + "continue": cont, + "break": br, + "step": step, + "clear": clear, + "": nullCommand, } return &Commands{cmds} @@ -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 } diff --git a/command/command_test.go b/command/command_test.go index b40ee6eb..8644d7a1 100644 --- a/command/command_test.go +++ b/command/command_test.go @@ -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 { diff --git a/main.go b/main.go index 6afc446f..d1890a09 100644 --- a/main.go +++ b/main.go @@ -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),