diff --git a/cmd/dlv/main.go b/cmd/dlv/main.go index 37309c3d..c282d5bc 100644 --- a/cmd/dlv/main.go +++ b/cmd/dlv/main.go @@ -8,10 +8,12 @@ import ( "os/signal" "path/filepath" "strconv" + "strings" sys "golang.org/x/sys/unix" "github.com/derekparker/delve/service" + "github.com/derekparker/delve/service/api" "github.com/derekparker/delve/service/rpc" "github.com/derekparker/delve/terminal" "github.com/spf13/cobra" @@ -82,6 +84,91 @@ starts and attaches to it, and enables you to immediately begin debugging your p } rootCommand.AddCommand(runCommand) + // 'trace' subcommand. + traceCommand := &cobra.Command{ + Use: "trace [regexp]", + Short: "Compile and begin tracing program.", + Long: "Trace program execution. Will set a tracepoint on every function matching [regexp] and output information when tracepoint is hit.", + Run: func(cmd *cobra.Command, args []string) { + status := func() int { + const debugname = "debug" + goBuild := exec.Command("go", "build", "-o", debugname, "-gcflags", "-N -l") + goBuild.Stderr = os.Stderr + err := goBuild.Run() + if err != nil { + return 1 + } + fp, err := filepath.Abs("./" + debugname) + if err != nil { + fmt.Fprintf(os.Stderr, err.Error()) + return 1 + } + defer os.Remove(fp) + + processArgs := append([]string{"./" + debugname}, args...) + // Make a TCP listener + listener, err := net.Listen("tcp", Addr) + if err != nil { + fmt.Printf("couldn't start listener: %s\n", err) + return 1 + } + defer listener.Close() + + // Create and start a debugger server + server := rpc.NewServer(&service.Config{ + Listener: listener, + ProcessArgs: processArgs, + }, Log) + if err := server.Run(); err != nil { + fmt.Fprintln(os.Stderr, err) + return 1 + } + sigChan := make(chan os.Signal) + signal.Notify(sigChan, sys.SIGINT) + client := rpc.NewClient(listener.Addr().String()) + funcs, err := client.ListFunctions(args[0]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + return 1 + } + for i := range funcs { + _, err := client.CreateBreakpoint(&api.Breakpoint{FunctionName: funcs[i], Tracepoint: true}) + if err != nil { + fmt.Fprintln(os.Stderr, err) + return 1 + } + } + stateChan := client.Continue() + for { + select { + case state := <-stateChan: + if state.Err != nil { + fmt.Fprintln(os.Stderr, state.Err) + return 0 + } + var args []string + var fname string + if state.CurrentThread != nil && state.CurrentThread.Function != nil { + fname = state.CurrentThread.Function.Name + } + if state.BreakpointInfo != nil { + for _, arg := range state.BreakpointInfo.Arguments { + args = append(args, arg.Value) + } + } + fmt.Printf("%s(%s) %s:%d\n", fname, strings.Join(args, ", "), state.CurrentThread.File, state.CurrentThread.Line) + case <-sigChan: + server.Stop(true) + return 1 + } + } + return 0 + }() + os.Exit(status) + }, + } + rootCommand.AddCommand(traceCommand) + // 'test' subcommand. testCommand := &cobra.Command{ Use: "test", diff --git a/dwarf/reader/reader.go b/dwarf/reader/reader.go index b6e0e489..c82d9545 100755 --- a/dwarf/reader/reader.go +++ b/dwarf/reader/reader.go @@ -55,7 +55,7 @@ func (reader *Reader) SeekToFunction(pc uint64) (*dwarf.Entry, error) { continue } - if lowpc <= pc && highpc >= pc { + if lowpc <= pc && highpc > pc { return entry, nil } } diff --git a/proc/variables.go b/proc/variables.go index b95e51b6..68ac8dcb 100644 --- a/proc/variables.go +++ b/proc/variables.go @@ -770,7 +770,6 @@ func (thread *Thread) readMemory(addr uintptr, size int) ([]byte, error) { if size == 0 { return nil, nil } - buf := make([]byte, size) _, err := readMemory(thread, addr, buf) if err != nil { diff --git a/service/api/conversions.go b/service/api/conversions.go index c97eadae..cb6e8ebd 100644 --- a/service/api/conversions.go +++ b/service/api/conversions.go @@ -2,6 +2,8 @@ package api import ( "debug/gosym" + "os" + "strings" "github.com/derekparker/delve/proc" ) @@ -11,7 +13,7 @@ func ConvertBreakpoint(bp *proc.Breakpoint) *Breakpoint { return &Breakpoint{ ID: bp.ID, FunctionName: bp.FunctionName, - File: bp.File, + File: shortenFilePath(bp.File), Line: bp.Line, Addr: bp.Addr, Tracepoint: bp.Tracepoint, @@ -41,7 +43,7 @@ func ConvertThread(th *proc.Thread) *Thread { return &Thread{ ID: th.Id, PC: pc, - File: file, + File: shortenFilePath(file), Line: line, Function: function, } @@ -74,7 +76,7 @@ func ConvertGoroutine(g *proc.G) *Goroutine { return &Goroutine{ ID: g.Id, PC: g.PC, - File: g.File, + File: shortenFilePath(g.File), Line: g.Line, Function: ConvertFunction(g.Func), } @@ -83,8 +85,13 @@ func ConvertGoroutine(g *proc.G) *Goroutine { func ConvertLocation(loc proc.Location) Location { return Location{ PC: loc.PC, - File: loc.File, + File: shortenFilePath(loc.File), Line: loc.Line, Function: ConvertFunction(loc.Fn), } } + +func shortenFilePath(fullPath string) string { + workingDir, _ := os.Getwd() + return strings.Replace(fullPath, workingDir, ".", 1) +} diff --git a/service/api/types.go b/service/api/types.go index 9f90e393..fd91e98d 100644 --- a/service/api/types.go +++ b/service/api/types.go @@ -112,6 +112,7 @@ type BreakpointInfo struct { Stacktrace []Location `json:"stacktrace,omitempty"` Goroutine *Goroutine `json:"goroutine,omitempty"` Variables []Variable `json:"variables,omitempty"` + Arguments []Variable `json:"arguments,omitempty"` } const ( diff --git a/service/debugger/debugger.go b/service/debugger/debugger.go index 7dbd05c3..83412a3e 100644 --- a/service/debugger/debugger.go +++ b/service/debugger/debugger.go @@ -272,6 +272,10 @@ func (d *Debugger) collectBreakpointInformation(state *api.DebuggerState) error } bpi.Variables[i] = api.ConvertVar(v) } + vars, err := d.FunctionArguments(d.process.CurrentThread.Id) + if err == nil { + bpi.Arguments = vars + } return nil } @@ -370,7 +374,7 @@ func (d *Debugger) FunctionArguments(threadID int) ([]api.Variable, error) { for _, v := range pv { vars = append(vars, api.ConvertVar(v)) } - return vars, err + return vars, nil } func (d *Debugger) EvalVariableInThread(threadID int, symbol string) (*api.Variable, error) { diff --git a/service/rpc/client.go b/service/rpc/client.go index 46d1672b..d5e2ca4a 100644 --- a/service/rpc/client.go +++ b/service/rpc/client.go @@ -66,7 +66,7 @@ func (c *RPCClient) Continue() <-chan *api.DebuggerState { state.Err = fmt.Errorf("Process %d has exited with status %d", c.ProcessPid(), state.ExitStatus) } ch <- state - if err != nil || state.Breakpoint == nil || !state.Breakpoint.Tracepoint { + if err != nil || state.Exited || state.Breakpoint == nil || !state.Breakpoint.Tracepoint { close(ch) return } diff --git a/terminal/command.go b/terminal/command.go index b1b60a5a..6e9918c9 100644 --- a/terminal/command.go +++ b/terminal/command.go @@ -537,11 +537,19 @@ func printcontext(state *api.DebuggerState) error { var context []string - fn := "" + var fn *api.Function if state.CurrentThread.Function != nil { - fn = state.CurrentThread.Function.Name + fn = state.CurrentThread.Function + } + if state.Breakpoint != nil && state.Breakpoint.Tracepoint { + var args []string + for _, arg := range state.CurrentThread.Function.Args { + args = append(args, arg.Value) + } + fmt.Printf("%s(%s) %s:%d\n", fn.Name, strings.Join(args, ", "), state.CurrentThread.File, state.CurrentThread.Line) + } else { + fmt.Printf("%s() %s:%d\n", fn.Name, state.CurrentThread.File, state.CurrentThread.Line) } - fmt.Printf("current loc: %s %s:%d\n", fn, state.CurrentThread.File, state.CurrentThread.Line) if state.BreakpointInfo != nil { bpi := state.BreakpointInfo