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
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"debug/gosym"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"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 {
|
type Commands struct {
|
||||||
cmds map[string]cmdfunc
|
cmds map[string]cmdfunc
|
||||||
@ -17,6 +23,10 @@ type Commands struct {
|
|||||||
func DebugCommands() *Commands {
|
func DebugCommands() *Commands {
|
||||||
cmds := map[string]cmdfunc{
|
cmds := map[string]cmdfunc{
|
||||||
"exit": exitFunc,
|
"exit": exitFunc,
|
||||||
|
"continue": cont,
|
||||||
|
"break": br,
|
||||||
|
"step": step,
|
||||||
|
"clear": clear,
|
||||||
"": nullCommand,
|
"": nullCommand,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,20 +55,101 @@ func (c *Commands) Find(cmdstr string) cmdfunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CommandFunc(fn func() error) cmdfunc {
|
func CommandFunc(fn func() error) cmdfunc {
|
||||||
return func(args ...string) error {
|
return func(p *proctl.DebuggedProcess, args ...string) error {
|
||||||
return fn()
|
return fn()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func noCmdAvailable(args ...string) error {
|
func noCmdAvailable(p *proctl.DebuggedProcess, ars ...string) error {
|
||||||
return fmt.Errorf("command not available")
|
return fmt.Errorf("command not available")
|
||||||
}
|
}
|
||||||
|
|
||||||
func exitFunc(args ...string) error {
|
func exitFunc(p *proctl.DebuggedProcess, ars ...string) error {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
return nil
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,8 @@ package command
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/derekparker/dbg/proctl"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCommandDefault(t *testing.T) {
|
func TestCommandDefault(t *testing.T) {
|
||||||
@ -11,7 +13,7 @@ func TestCommandDefault(t *testing.T) {
|
|||||||
cmd = cmds.Find("non-existant-command")
|
cmd = cmds.Find("non-existant-command")
|
||||||
)
|
)
|
||||||
|
|
||||||
err := cmd()
|
err := cmd(nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("cmd() did not default")
|
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) {
|
func TestCommandReplay(t *testing.T) {
|
||||||
cmds := DebugCommands()
|
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")
|
cmd := cmds.Find("foo")
|
||||||
|
|
||||||
err := cmd()
|
err := cmd(nil)
|
||||||
if err.Error() != "registered command" {
|
if err.Error() != "registered command" {
|
||||||
t.Fatal("wrong command output")
|
t.Fatal("wrong command output")
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = cmds.Find("")
|
cmd = cmds.Find("")
|
||||||
err = cmd()
|
err = cmd(nil)
|
||||||
if err.Error() != "registered command" {
|
if err.Error() != "registered command" {
|
||||||
t.Fatal("wrong command output")
|
t.Fatal("wrong command output")
|
||||||
}
|
}
|
||||||
@ -59,7 +44,7 @@ func TestCommandReplayWithoutPreviousCommand(t *testing.T) {
|
|||||||
var (
|
var (
|
||||||
cmds = DebugCommands()
|
cmds = DebugCommands()
|
||||||
cmd = cmds.Find("")
|
cmd = cmds.Find("")
|
||||||
err = cmd()
|
err = cmd(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
92
main.go
92
main.go
@ -2,10 +2,8 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"debug/gosym"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -24,7 +22,10 @@ func main() {
|
|||||||
// all commands after PTRACE_ATTACH to come from the same thread.
|
// all commands after PTRACE_ATTACH to come from the same thread.
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
|
|
||||||
t := newTerm()
|
var (
|
||||||
|
t = newTerm()
|
||||||
|
cmds = command.DebugCommands()
|
||||||
|
)
|
||||||
|
|
||||||
if len(os.Args) == 1 {
|
if len(os.Args) == 1 {
|
||||||
die("You must provide a pid\n")
|
die("You must provide a pid\n")
|
||||||
@ -40,9 +41,6 @@ func main() {
|
|||||||
die("Could not start debugging process:", err)
|
die("Could not start debugging process:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmds := command.DebugCommands()
|
|
||||||
registerProcessCommands(cmds, dbgproc)
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
cmdstr, err := t.promptForInput()
|
cmdstr, err := t.promptForInput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -52,7 +50,7 @@ func main() {
|
|||||||
cmdstr, args := parseCommand(cmdstr)
|
cmdstr, args := parseCommand(cmdstr)
|
||||||
|
|
||||||
cmd := cmds.Find(cmdstr)
|
cmd := cmds.Find(cmdstr)
|
||||||
err = cmd(args...)
|
err = cmd(dbgproc, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Command failed: %s\n", err)
|
fmt.Fprintf(os.Stderr, "Command failed: %s\n", err)
|
||||||
}
|
}
|
||||||
@ -64,86 +62,6 @@ func die(args ...interface{}) {
|
|||||||
os.Exit(1)
|
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 {
|
func newTerm() *term {
|
||||||
return &term{
|
return &term{
|
||||||
stdin: bufio.NewReader(os.Stdin),
|
stdin: bufio.NewReader(os.Stdin),
|
||||||
|
|||||||
Reference in New Issue
Block a user