提交 819c476a 编写于 作者: D Derek Parker

Do not attempt to automatically read locals/args

上级 48146367
...@@ -51,6 +51,10 @@ type Client interface { ...@@ -51,6 +51,10 @@ type Client interface {
ListSources(filter string) ([]string, error) ListSources(filter string) ([]string, error)
// ListFunctions lists all functions in the process matching filter. // ListFunctions lists all functions in the process matching filter.
ListFunctions(filter string) ([]string, error) ListFunctions(filter string) ([]string, error)
// ListLocals lists all local variables in scope.
ListLocalVariables() ([]api.Variable, error)
// ListFunctionArgs lists all arguments to the current function.
ListFunctionArgs() ([]api.Variable, error)
// ListGoroutines lists all goroutines. // ListGoroutines lists all goroutines.
ListGoroutines() ([]*api.Goroutine, error) ListGoroutines() ([]*api.Goroutine, error)
......
...@@ -390,6 +390,44 @@ func (d *Debugger) PackageVariables(threadID int, filter string) ([]api.Variable ...@@ -390,6 +390,44 @@ func (d *Debugger) PackageVariables(threadID int, filter string) ([]api.Variable
return vars, err return vars, err
} }
func (d *Debugger) LocalVariables(threadID int) ([]api.Variable, error) {
vars := []api.Variable{}
err := d.withProcess(func(p *proctl.DebuggedProcess) error {
thread, found := p.Threads[threadID]
if !found {
return fmt.Errorf("couldn't find thread %d", threadID)
}
pv, err := thread.LocalVariables()
if err != nil {
return err
}
for _, v := range pv {
vars = append(vars, convertVar(v))
}
return nil
})
return vars, err
}
func (d *Debugger) FunctionArguments(threadID int) ([]api.Variable, error) {
vars := []api.Variable{}
err := d.withProcess(func(p *proctl.DebuggedProcess) error {
thread, found := p.Threads[threadID]
if !found {
return fmt.Errorf("couldn't find thread %d", threadID)
}
pv, err := thread.FunctionArguments()
if err != nil {
return err
}
for _, v := range pv {
vars = append(vars, convertVar(v))
}
return nil
})
return vars, err
}
func (d *Debugger) EvalSymbolInThread(threadID int, symbol string) (*api.Variable, error) { func (d *Debugger) EvalSymbolInThread(threadID int, symbol string) (*api.Variable, error) {
var variable *api.Variable var variable *api.Variable
err := d.withProcess(func(p *proctl.DebuggedProcess) error { err := d.withProcess(func(p *proctl.DebuggedProcess) error {
...@@ -450,24 +488,6 @@ func convertThread(th *proctl.ThreadContext) *api.Thread { ...@@ -450,24 +488,6 @@ func convertThread(th *proctl.ThreadContext) *api.Thread {
Type: fn.Type, Type: fn.Type,
Value: fn.Value, Value: fn.Value,
GoType: fn.GoType, GoType: fn.GoType,
Args: []api.Variable{},
Locals: []api.Variable{},
}
if vars, err := th.LocalVariables(); err == nil {
for _, v := range vars {
function.Locals = append(function.Locals, convertVar(v))
}
} else {
log.Printf("error getting locals for function at %s:%d: %s", file, line, err)
}
if vars, err := th.FunctionArguments(); err == nil {
for _, v := range vars {
function.Args = append(function.Args, convertVar(v))
}
} else {
log.Printf("error getting args for function at %s:%d: %s", file, line, err)
} }
} }
} }
......
...@@ -230,6 +230,24 @@ func (c *RESTClient) ListPackageVariablesFor(threadID int, filter string) ([]api ...@@ -230,6 +230,24 @@ func (c *RESTClient) ListPackageVariablesFor(threadID int, filter string) ([]api
return vars, nil return vars, nil
} }
func (c *RESTClient) ListLocalVariables() ([]api.Variable, error) {
var vars []api.Variable
err := c.doGET("/localvars", &vars)
if err != nil {
return nil, err
}
return vars, nil
}
func (c *RESTClient) ListFunctionArgs() ([]api.Variable, error) {
var vars []api.Variable
err := c.doGET("/args", &vars)
if err != nil {
return nil, err
}
return vars, nil
}
func (c *RESTClient) ListGoroutines() ([]*api.Goroutine, error) { func (c *RESTClient) ListGoroutines() ([]*api.Goroutine, error) {
var goroutines []*api.Goroutine var goroutines []*api.Goroutine
err := c.doGET("/goroutines", &goroutines) err := c.doGET("/goroutines", &goroutines)
......
...@@ -2,6 +2,7 @@ package rest ...@@ -2,6 +2,7 @@ package rest
import ( import (
"net" "net"
"path/filepath"
"testing" "testing"
protest "github.com/derekparker/delve/proctl/test" protest "github.com/derekparker/delve/proctl/test"
...@@ -268,3 +269,51 @@ func TestClientServer_switchThread(t *testing.T) { ...@@ -268,3 +269,51 @@ func TestClientServer_switchThread(t *testing.T) {
} }
}) })
} }
func TestClientServer_infoLocals(t *testing.T) {
withTestClient("testnextprog", t, func(c service.Client) {
fp, err := filepath.Abs("../../_fixtures/testnextprog.go")
if err != nil {
t.Fatal(err)
}
_, err = c.CreateBreakPoint(&api.BreakPoint{File: fp, Line: 23})
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
state, err := c.Continue()
if err != nil {
t.Fatalf("Unexpected error: %v, state: %#v", err, state)
}
locals, err := c.ListLocalVariables()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if len(locals) != 3 {
t.Fatalf("Expected 3 locals, got %d %#v", len(locals), locals)
}
})
}
func TestClientServer_infoArgs(t *testing.T) {
withTestClient("testnextprog", t, func(c service.Client) {
fp, err := filepath.Abs("../../_fixtures/testnextprog.go")
if err != nil {
t.Fatal(err)
}
_, err = c.CreateBreakPoint(&api.BreakPoint{File: fp, Line: 47})
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
state, err := c.Continue()
if err != nil {
t.Fatalf("Unexpected error: %v, state: %#v", err, state)
}
locals, err := c.ListFunctionArgs()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if len(locals) != 2 {
t.Fatalf("Expected 2 function args, got %d %#v", len(locals), locals)
}
})
}
...@@ -88,6 +88,8 @@ func (s *RESTServer) Run() error { ...@@ -88,6 +88,8 @@ func (s *RESTServer) Run() error {
Route(ws.GET("/sources").To(s.listSources)). Route(ws.GET("/sources").To(s.listSources)).
Route(ws.GET("/functions").To(s.listFunctions)). Route(ws.GET("/functions").To(s.listFunctions)).
Route(ws.GET("/vars").To(s.listPackageVars)). Route(ws.GET("/vars").To(s.listPackageVars)).
Route(ws.GET("/localvars").To(s.listLocalVars)).
Route(ws.GET("/args").To(s.listFunctionArgs)).
Route(ws.GET("/eval/{symbol}").To(s.evalSymbol)). Route(ws.GET("/eval/{symbol}").To(s.evalSymbol)).
// TODO: GET might be the wrong verb for this // TODO: GET might be the wrong verb for this
Route(ws.GET("/detach").To(s.detach)) Route(ws.GET("/detach").To(s.detach))
...@@ -293,6 +295,40 @@ func (s *RESTServer) listThreadPackageVars(request *restful.Request, response *r ...@@ -293,6 +295,40 @@ func (s *RESTServer) listThreadPackageVars(request *restful.Request, response *r
response.WriteEntity(vars) response.WriteEntity(vars)
} }
func (s *RESTServer) listLocalVars(request *restful.Request, response *restful.Response) {
state, err := s.debugger.State()
if err != nil {
writeError(response, http.StatusInternalServerError, err.Error())
return
}
vars, err := s.debugger.LocalVariables(state.CurrentThread.ID)
if err != nil {
writeError(response, http.StatusInternalServerError, err.Error())
return
}
response.WriteHeader(http.StatusOK)
response.WriteEntity(vars)
}
func (s *RESTServer) listFunctionArgs(request *restful.Request, response *restful.Response) {
state, err := s.debugger.State()
if err != nil {
writeError(response, http.StatusInternalServerError, err.Error())
return
}
vars, err := s.debugger.FunctionArguments(state.CurrentThread.ID)
if err != nil {
writeError(response, http.StatusInternalServerError, err.Error())
return
}
response.WriteHeader(http.StatusOK)
response.WriteEntity(vars)
}
func (s *RESTServer) evalSymbol(request *restful.Request, response *restful.Response) { func (s *RESTServer) evalSymbol(request *restful.Request, response *restful.Response) {
symbol := request.PathParameter("symbol") symbol := request.PathParameter("symbol")
if len(symbol) == 0 { if len(symbol) == 0 {
......
...@@ -364,24 +364,18 @@ func info(client service.Client, args ...string) error { ...@@ -364,24 +364,18 @@ func info(client service.Client, args ...string) error {
data = funcs data = funcs
case "args": case "args":
state, err := client.GetState() args, err := client.ListFunctionArgs()
if err != nil { if err != nil {
return err return err
} }
if state.CurrentThread == nil || state.CurrentThread.Function == nil { data = filterVariables(args, filter)
return nil
}
data = filterVariables(state.CurrentThread.Function.Args, filter)
case "locals": case "locals":
state, err := client.GetState() locals, err := client.ListLocalVariables()
if err != nil { if err != nil {
return err return err
} }
if state.CurrentThread == nil || state.CurrentThread.Function == nil { data = filterVariables(locals, filter)
return nil
}
data = filterVariables(state.CurrentThread.Function.Locals, filter)
case "vars": case "vars":
regex := "" regex := ""
...@@ -392,9 +386,7 @@ func info(client service.Client, args ...string) error { ...@@ -392,9 +386,7 @@ func info(client service.Client, args ...string) error {
if err != nil { if err != nil {
return err return err
} }
for _, v := range vars { data = filterVariables(vars, filter)
data = append(data, fmt.Sprintf("%s = %s", v.Name, v.Value))
}
default: default:
return fmt.Errorf("unsupported info type, must be args, funcs, locals, sources, or vars") return fmt.Errorf("unsupported info type, must be args, funcs, locals, sources, or vars")
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册