mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 02:36:18 +08:00 
			
		
		
		
	New command 'types'
Lists all the types defined in the debugged program.
This commit is contained in:
		| @ -143,11 +143,7 @@ func (reader *Reader) SeekToType(entry *dwarf.Entry, resolveTypedefs bool, resol | |||||||
| 	return nil, TypeNotFoundErr | 	return nil, TypeNotFoundErr | ||||||
| } | } | ||||||
|  |  | ||||||
| // SeekToTypeNamed moves the reader to the type specified by the name. | func (reader *Reader) NextType() (*dwarf.Entry, error) { | ||||||
| // 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.Next(); entry != nil; entry, err = reader.Next() { | 	for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() { | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| @ -155,9 +151,21 @@ func (reader *Reader) SeekToTypeNamed(name string) (*dwarf.Entry, error) { | |||||||
|  |  | ||||||
| 		switch entry.Tag { | 		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: | 		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 | 			return entry, nil | ||||||
| 		default: | 		} | ||||||
| 			continue | 	} | ||||||
|  |  | ||||||
|  | 	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) | 		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 | 	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. | // PCToLine converts an instruction address to a file/line/function. | ||||||
| func (dbp *Process) PCToLine(pc uint64) (string, int, *gosym.Func) { | func (dbp *Process) PCToLine(pc uint64) (string, int, *gosym.Func) { | ||||||
| 	return dbp.goSymTable.PCToLine(pc) | 	return dbp.goSymTable.PCToLine(pc) | ||||||
|  | |||||||
| @ -69,6 +69,8 @@ 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) | ||||||
|  | 	// ListTypes lists all types in the process matching filter. | ||||||
|  | 	ListTypes(filter string) ([]string, error) | ||||||
| 	// ListLocals lists all local variables in scope. | 	// ListLocals lists all local variables in scope. | ||||||
| 	ListLocalVariables(scope api.EvalScope) ([]api.Variable, error) | 	ListLocalVariables(scope api.EvalScope) ([]api.Variable, error) | ||||||
| 	// ListFunctionArgs lists all arguments to the current function. | 	// 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()) | 	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) { | func regexFilterFuncs(filter string, allFuncs []gosym.Func) ([]string, error) { | ||||||
| 	regex, err := regexp.Compile(filter) | 	regex, err := regexp.Compile(filter) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | |||||||
| @ -209,6 +209,12 @@ func (c *RPCClient) ListFunctions(filter string) ([]string, error) { | |||||||
| 	return funcs, err | 	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) { | func (c *RPCClient) ListPackageVariables(filter string) ([]api.Variable, error) { | ||||||
| 	var vars []api.Variable | 	var vars []api.Variable | ||||||
| 	err := c.call("ListPackageVars", filter, &vars) | 	err := c.call("ListPackageVars", filter, &vars) | ||||||
|  | |||||||
| @ -345,6 +345,15 @@ func (s *RPCServer) ListFunctions(filter string, funcs *[]string) error { | |||||||
| 	return nil | 	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 { | func (s *RPCServer) ListGoroutines(arg interface{}, goroutines *[]*api.Goroutine) error { | ||||||
| 	gs, err := s.debugger.Goroutines() | 	gs, err := s.debugger.Goroutines() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | |||||||
| @ -1089,3 +1089,29 @@ func TestIssue419(t *testing.T) { | |||||||
| 		assertNoError(state.Err, t, "Continue()") | 		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{"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{"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{"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{"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{"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."}, | 		{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) | 	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) { | func args(t *Term, scope api.EvalScope, filter string) ([]string, error) { | ||||||
| 	vars, err := t.client.ListFunctionArgs(scope) | 	vars, err := t.client.ListFunctionArgs(scope) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 aarzilli
					aarzilli