godbg> funcs <regexp>

Implementation Goal

The previous section introduced the implementation of the debugger backend ListFunctions. This section will cover the implementation of godbg> funcs <expr> based on that foundation.

Basic Knowledge

We previously discussed how communication between the frontend and backend works in a debug session, and also covered the implementation of ListFunctions. Now, implementing the debug session command godbg> funcs <expr> becomes straightforward - it's simply a matter of calling the remote procedure ListFunctions through the JSON-RPC client.

Code Implementation

Let's look at the key code logic for this part.

Request and Response Parameter Types

The ListFunctions RPC call accepts two parameters:

type ListFunctionsIn struct {
    Filter      string  // Regular expression pattern for filtering function names
    FollowCalls int     // Depth for tracking function calls (0 means no tracking)
}

type ListFunctionsOut struct {
    Funcs []string      // List of matching function names
}

Regular Expression Filtering

Function name filtering is implemented using regular expressions. When a filter pattern is provided, it is compiled into a regular expression object:

This allows users to search for functions using patterns like:

  • main.* - All functions starting with "main"
  • .*Handler - All functions ending with "Handler"
  • [A-Z].* - All exported functions

Function Call Traversal

The Go function call path is roughly as follows:

// clientside execution of debug command
tinydbg> funcs <expr>
    \--> funcsCmd.cmdFn()
            \--> funcs(s *Session, ctx callContext, args string)
                    \--> t.printSortedStrings(t.client.ListFunctions(...))
                            \--> rpc2.(*RPCClient).ListFunctions(...)

Let's look at how the clientside is implemented:

func (c *RPCClient) ListFunctions(filter string, TraceFollow int) ([]string, error) {
    funcs := new(ListFunctionsOut)
    err := c.call("ListFunctions", ListFunctionsIn{filter, TraceFollow}, funcs)
    return funcs.Funcs, err
}

Now let's see how the serverside is implemented:

t.client.ListFunctions(...) corresponds to the server-side ListFunctions handler:

// ListFunctions lists all functions in the process matching filter.
func (s *RPCServer) ListFunctions(arg ListFunctionsIn, out *ListFunctionsOut) error {
    fns, err := s.debugger.Functions(arg.Filter, arg.FollowCalls)
    if err != nil {
        return err
    }
    out.Funcs = fns
    return nil
}

The server side calls this function (*RPCServer).ListFunctions(...), which then calls debugger.Functions. Let's look at s.debugger.Functions(filter, followCalls):

// Functions returns a list of functions in the target process.
func (d *Debugger) Functions(filter string, followCalls int) ([]string, error) {
    d.targetMutex.Lock()
    defer d.targetMutex.Unlock()

    regex, err := regexp.Compile(filter)
    if err != nil {
        return nil, fmt.Errorf("invalid filter argument: %s", err.Error())
    }

    funcs := []string{}
    t := proc.ValidTargets{Group: d.target}
    for t.Next() {
        for _, f := range t.BinInfo().Functions {
            if regex.MatchString(f.Name) {
                if followCalls > 0 {
                    newfuncs, err := traverse(t, &f, 1, followCalls)
                    if err != nil {
                        return nil, fmt.Errorf("traverse failed with error %w", err)
                    }
                    funcs = append(funcs, newfuncs...)
                } else {
                    funcs = append(funcs, f.Name)
                }
            }
        }
    }
    // uniq = sort + compact
    sort.Strings(funcs)
    funcs = slices.Compact(funcs)
    return funcs, nil
}

The above code demonstrates how to add multi-agent intelligence, which is not impossible.

Summary

This section introduced the implementation of the debugger command godbg> funcs <expr>. The command calls the remote ListFunctions procedure through JSON-RPC, supports regular expression filtering of function names, and allows setting the function call tracking depth. The implementation shows the key code handling logic between the debugger's frontend and backend.

results matching ""

    No results matching ""