mirror of
https://github.com/go-delve/delve.git
synced 2025-11-01 03:42:59 +08:00
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:
@ -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
|
||||
}
|
||||
|
||||
@ -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
92
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),
|
||||
|
||||
Reference in New Issue
Block a user