New command 'types'
Lists all the types defined in the debugged program.
This commit is contained in:
parent
14a92352bc
commit
c8f4cee97d
@ -143,11 +143,7 @@ func (reader *Reader) SeekToType(entry *dwarf.Entry, resolveTypedefs bool, resol
|
||||
return nil, TypeNotFoundErr
|
||||
}
|
||||
|
||||
// SeekToTypeNamed moves the reader to the type specified by the name.
|
||||
// If the reader is set to a struct type the NextMemberVariable call
|
||||
// can be used to walk all member data.
|
||||
func (reader *Reader) SeekToTypeNamed(name string) (*dwarf.Entry, error) {
|
||||
// Walk the types to the base
|
||||
func (reader *Reader) NextType() (*dwarf.Entry, error) {
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -155,9 +151,21 @@ func (reader *Reader) SeekToTypeNamed(name string) (*dwarf.Entry, error) {
|
||||
|
||||
switch entry.Tag {
|
||||
case dwarf.TagArrayType, dwarf.TagBaseType, dwarf.TagClassType, dwarf.TagStructType, dwarf.TagUnionType, dwarf.TagConstType, dwarf.TagVolatileType, dwarf.TagRestrictType, dwarf.TagEnumerationType, dwarf.TagPointerType, dwarf.TagSubroutineType, dwarf.TagTypedef, dwarf.TagUnspecifiedType:
|
||||
//ok
|
||||
default:
|
||||
continue
|
||||
return entry, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// SeekToTypeNamed moves the reader to the type specified by the name.
|
||||
// If the reader is set to a struct type the NextMemberVariable call
|
||||
// can be used to walk all member data.
|
||||
func (reader *Reader) SeekToTypeNamed(name string) (*dwarf.Entry, error) {
|
||||
// Walk the types to the base
|
||||
for entry, err := reader.NextType(); entry != nil; entry, err = reader.NextType() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, ok := entry.Val(dwarf.AttrName).(string)
|
||||
|
19
proc/proc.go
19
proc/proc.go
@ -656,6 +656,25 @@ func (dbp *Process) Funcs() []gosym.Func {
|
||||
return dbp.goSymTable.Funcs
|
||||
}
|
||||
|
||||
// Types returns list of types present in the debugged program.
|
||||
func (dbp *Process) Types() ([]string, error) {
|
||||
reader := dbp.DwarfReader()
|
||||
types := []string{}
|
||||
seen := map[string]struct{}{}
|
||||
for entry, err := reader.NextType(); entry != nil; entry, err = reader.NextType() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n, ok := entry.Val(dwarf.AttrName).(string); ok {
|
||||
if _, isseen := seen[n]; !isseen {
|
||||
seen[n] = struct{}{}
|
||||
types = append(types, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
return types, nil
|
||||
}
|
||||
|
||||
// PCToLine converts an instruction address to a file/line/function.
|
||||
func (dbp *Process) PCToLine(pc uint64) (string, int, *gosym.Func) {
|
||||
return dbp.goSymTable.PCToLine(pc)
|
||||
|
@ -69,6 +69,8 @@ type Client interface {
|
||||
ListSources(filter string) ([]string, error)
|
||||
// ListFunctions lists all functions in the process matching filter.
|
||||
ListFunctions(filter string) ([]string, error)
|
||||
// ListTypes lists all types in the process matching filter.
|
||||
ListTypes(filter string) ([]string, error)
|
||||
// ListLocals lists all local variables in scope.
|
||||
ListLocalVariables(scope api.EvalScope) ([]api.Variable, error)
|
||||
// ListFunctionArgs lists all arguments to the current function.
|
||||
|
@ -498,6 +498,30 @@ func (d *Debugger) Functions(filter string) ([]string, error) {
|
||||
return regexFilterFuncs(filter, d.process.Funcs())
|
||||
}
|
||||
|
||||
func (d *Debugger) Types(filter string) ([]string, error) {
|
||||
d.processMutex.Lock()
|
||||
defer d.processMutex.Unlock()
|
||||
|
||||
regex, err := regexp.Compile(filter)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid filter argument: %s", err.Error())
|
||||
}
|
||||
|
||||
types, err := d.process.Types()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := make([]string, 0, len(types))
|
||||
for _, typ := range types {
|
||||
if regex.Match([]byte(typ)) {
|
||||
r = append(r, typ)
|
||||
}
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func regexFilterFuncs(filter string, allFuncs []gosym.Func) ([]string, error) {
|
||||
regex, err := regexp.Compile(filter)
|
||||
if err != nil {
|
||||
|
@ -209,6 +209,12 @@ func (c *RPCClient) ListFunctions(filter string) ([]string, error) {
|
||||
return funcs, err
|
||||
}
|
||||
|
||||
func (c *RPCClient) ListTypes(filter string) ([]string, error) {
|
||||
var types []string
|
||||
err := c.call("ListTypes", filter, &types)
|
||||
return types, err
|
||||
}
|
||||
|
||||
func (c *RPCClient) ListPackageVariables(filter string) ([]api.Variable, error) {
|
||||
var vars []api.Variable
|
||||
err := c.call("ListPackageVars", filter, &vars)
|
||||
|
@ -345,6 +345,15 @@ func (s *RPCServer) ListFunctions(filter string, funcs *[]string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *RPCServer) ListTypes(filter string, types *[]string) error {
|
||||
tps, err := s.debugger.Types(filter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*types = tps
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *RPCServer) ListGoroutines(arg interface{}, goroutines *[]*api.Goroutine) error {
|
||||
gs, err := s.debugger.Goroutines()
|
||||
if err != nil {
|
||||
|
@ -104,24 +104,24 @@ func TestRestart_breakpointPreservation(t *testing.T) {
|
||||
_, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 1, Name: "firstbreakpoint", Tracepoint: true})
|
||||
assertNoError(err, t, "CreateBreakpoint()")
|
||||
stateCh := c.Continue()
|
||||
|
||||
state := <- stateCh
|
||||
|
||||
state := <-stateCh
|
||||
if state.CurrentThread.Breakpoint.Name != "firstbreakpoint" || !state.CurrentThread.Breakpoint.Tracepoint {
|
||||
t.Fatalf("Wrong breakpoint: %#v\n", state.CurrentThread.Breakpoint)
|
||||
}
|
||||
state = <- stateCh
|
||||
state = <-stateCh
|
||||
if !state.Exited {
|
||||
t.Fatal("Did not exit after first tracepoint")
|
||||
}
|
||||
|
||||
|
||||
t.Log("Restart")
|
||||
c.Restart()
|
||||
stateCh = c.Continue()
|
||||
state = <- stateCh
|
||||
state = <-stateCh
|
||||
if state.CurrentThread.Breakpoint.Name != "firstbreakpoint" || !state.CurrentThread.Breakpoint.Tracepoint {
|
||||
t.Fatalf("Wrong breakpoint (after restart): %#v\n", state.CurrentThread.Breakpoint)
|
||||
}
|
||||
state = <- stateCh
|
||||
state = <-stateCh
|
||||
if !state.Exited {
|
||||
t.Fatal("Did not exit after first tracepoint (after restart)")
|
||||
}
|
||||
@ -1089,3 +1089,29 @@ func TestIssue419(t *testing.T) {
|
||||
assertNoError(state.Err, t, "Continue()")
|
||||
})
|
||||
}
|
||||
|
||||
func TestTypesCommand(t *testing.T) {
|
||||
withTestClient("testvariables2", t, func(c service.Client) {
|
||||
state := <-c.Continue()
|
||||
assertNoError(state.Err, t, "Continue()")
|
||||
types, err := c.ListTypes("")
|
||||
assertNoError(err, t, "ListTypes()")
|
||||
|
||||
found := false
|
||||
for i := range types {
|
||||
if types[i] == "main.astruct" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatal("Type astruct not found in ListTypes output")
|
||||
}
|
||||
|
||||
types, err = c.ListTypes("main.astruct")
|
||||
assertNoError(err, t, "ListTypes(\"main.astruct\")")
|
||||
if len(types) <= 0 {
|
||||
t.Fatal("ListTypes(\"main.astruct\") did not return anything")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -75,6 +75,7 @@ func DebugCommands(client service.Client) *Commands {
|
||||
{aliases: []string{"set"}, cmdFn: g0f0(setVar), helpMsg: "Changes the value of a variable."},
|
||||
{aliases: []string{"sources"}, cmdFn: filterSortAndOutput(sources), helpMsg: "Print list of source files, optionally filtered by a regexp."},
|
||||
{aliases: []string{"funcs"}, cmdFn: filterSortAndOutput(funcs), helpMsg: "Print list of functions, optionally filtered by a regexp."},
|
||||
{aliases: []string{"types"}, cmdFn: filterSortAndOutput(types), helpMsg: "Print list of types, optionally filtered by a regexp."},
|
||||
{aliases: []string{"args"}, cmdFn: filterSortAndOutput(g0f0filter(args)), helpMsg: "Print function arguments, optionally filtered by a regexp."},
|
||||
{aliases: []string{"locals"}, cmdFn: filterSortAndOutput(g0f0filter(locals)), helpMsg: "Print function locals, optionally filtered by a regexp."},
|
||||
{aliases: []string{"vars"}, cmdFn: filterSortAndOutput(vars), helpMsg: "Print package variables, optionally filtered by a regexp."},
|
||||
@ -703,6 +704,10 @@ func funcs(t *Term, filter string) ([]string, error) {
|
||||
return t.client.ListFunctions(filter)
|
||||
}
|
||||
|
||||
func types(t *Term, filter string) ([]string, error) {
|
||||
return t.client.ListTypes(filter)
|
||||
}
|
||||
|
||||
func args(t *Term, scope api.EvalScope, filter string) ([]string, error) {
|
||||
vars, err := t.client.ListFunctionArgs(scope)
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user