Documentation
¶
Overview ¶
Package cli implements the interactive argot CLI.
Package cli implements the the Argot interactive CLI: a terminal application that lets you run most of the analyses that are available in argot, with additional functionality to print verbose output and with commands to help you understand, and possibly debug your analyses.
Usage:
argot cli [flags] -config config-file.yaml [program files]
The flags are:
-verbose=false verbose mode, overrides any verbose option specified in the config file -config config-file.yaml a configuration file for the analyses. The configuration file can be empty, but should always be specified. If [program files] is only one main.go file, the program will look for a file config.yaml in the same folder as the config file.
There are 29 commands you can use once you have started the argot-cli and your program has been loaded and some information has been collected.
Basic Commands ¶
There are a few basic commands:
help print a list of the commands, with short help messages for each cd,ls cd and ls allow you to change the working directory of the terminal and list its contents exit exit exits the program gracefully state? show a summary of the state, including path to config file and program stats show some statistics about the current program
Commands that let you manipulate the state, reloading programs and configuration files:
load path load a program, the path is the same type of argument you would pass to the argot-cli initially rebuild reload the current program and rebuild it reconfig [path] reload the config file, or load the config file at path if specified
Inspecting Functions ¶
Commands that let you inspect the functions in the program:
list [name] list all the functions matching name, or all loaded functions if no name is specified . Flag -r shows only reachable functions, and -s only summarized functions. where "name" show the locations of all the function matching name callees "name" print the list of callees the functions matching name callers "name" print the list of callers of the functions matching name showssa "name" print the SSA form of the functions matching name
Running Analyses ¶
Commands to run analyses and inspect resulting information:
summarize [name] summarize all functions matching name, or every reachable function if no name is supplied summary "name" print the summary of all functions matching name, if any buildgraph builds the cross-cross function graph. You must first use `summarize` to build summaries taint run the taint analysis trace run a dataflow graph exploration (taint analysis from any node given its id) showdataflow build and print the dataflow graph of a program showescape "name" print the escape graph of all functions matching name
Focused Mode ¶
Commands to use in "focused" mode, which lets you focus on a particular function and obtained detailed information about that function:
focus "name" focus name focuses on a specific function and enters "focus" mode unfocus exit "focus" mode intra run the intra-procedural dataflow analysis and show its result. . The -v flag shows intermediate results mayalias "value" show all the aliases of the values matching value ssaval "value" show information about all the values matching value in the function ssainstr "instr" show information about all the instructions matching instr in the function pkg print the name of the focuse function's package
The commands showssa, summary and where can be used without an argument in focused mode, in which case the function defaults to the currently focused function.
Index ¶
- Constants
- Variables
- func Run(flags tools.CommonFlags)
- func WriteErr(tt *term.Terminal, format string, a ...any)
- func WriteSuccess(tt *term.Terminal, format string, a ...any)
- type Command
- type CommandDefinition
- type NameAndLoc
- type Outputter
- func (o Outputter) EscBlue() []byte
- func (o Outputter) EscCyan() []byte
- func (o Outputter) EscGreen() []byte
- func (o Outputter) EscMagenta() []byte
- func (o Outputter) EscRed() []byte
- func (o Outputter) EscReset() []byte
- func (o Outputter) EscWhite() []byte
- func (o Outputter) EscYellow() []byte
- func (o Outputter) Write(format string, a ...any)
- func (o Outputter) WriteErr(format string, a ...any)
- func (o Outputter) WriteSuccess(format string, a ...any)
- func (o Outputter) Writer() io.Writer
- type Session
Constants ¶
const ( // CmdAstName is the name of the ast command CmdAstName = "ast" // CmdBacktraceName is the name of the backtrace command CmdBacktraceName = "backtrace" // CmdBuildGraphName is the name of the buildgraph command CmdBuildGraphName = "buildgraph" // CmdCalleesName is the name of the callees command CmdCalleesName = "callees" // CmdCallersName is the name of the callers command CmdCallersName = "callers" // CmdCdName is the name of the cd command CmdCdName = "cd" // CmdExitName is the name of the exit command CmdExitName = "exit" // CmdFocusName is the name of the focus command CmdFocusName = "focus" // CmdHelpName is the name of the help command CmdHelpName = "help" // CmdIntraName is the name of the intra command CmdIntraName = "intra" // CmdLoadName is the name of the load command CmdLoadName = "load" // CmdLoadPackagesName is the name of the load-pkg command CmdLoadPackagesName = "load-pkg" // CmdLoadWholeProgramName is the name of the load-program command CmdLoadWholeProgramName = "load-program" // CmdListName is the name of the list command CmdListName = "list" // CmdLsName is the name of the ls command CmdLsName = "ls" // CmdMarkName is the name of the mark command CmdMarkName = "mark" // CmdMayAliasName is the name of the mayalias command CmdMayAliasName = "mayalias" // CmdPackageName is the name of the function-pkg command CmdPackageName = "function-pkg" // CmdRebuildName is the name of the rebuild command CmdRebuildName = "rebuild" // CmdReconfigName is the name of the reconfig command CmdReconfigName = "reconfig" // CmdScanName is the name of the scan command CmdScanName = "scan" // CmdShowPackageName is the name of the showpkg command CmdShowPackageName = "showpkg" // CmdShowDataflowName is the name of the showdataflow command CmdShowDataflowName = "showdataflow" // CmdShowEscapeName is the name of the showescape command CmdShowEscapeName = "showescape" // CmdMembersName is the name of the members command CmdMembersName = "members" // CmdRunPointerName is the name of the run-pointer command CmdRunPointerName = "run-pointer" // CmdRunDataflowName is the name of the run-dataflow command CmdRunDataflowName = "run-dataflow" // CmdShowSsaName is the name of the showssa command CmdShowSsaName = "showssa" // CmdSrcName is the name of the src command CmdSrcName = "src" // CmdSsaInstrName is the name of the ssainstr command CmdSsaInstrName = "ssainstr" // CmdSsaValueName is the name of the ssaval command CmdSsaValueName = "ssaval" // CmdStateName is the name of the state? command CmdStateName = "state?" // CmdStatsName is the name of the stats command CmdStatsName = "stats" // CmdSummarizeName is the name of the summarize command CmdSummarizeName = "summarize" // CmdSummaryName is the name of the summary command CmdSummaryName = "summary" // CmdTaintName is the name of the taint command CmdTaintName = "taint" // CmdTraceName is the name of the trace command CmdTraceName = "trace" // CmdUnfocusName is the name of the unfocus command CmdUnfocusName = "unfocus" // CmdWhereName is the name of the where command CmdWhereName = "where" )
const Usage = `Interactive CLI for exploring the program and running various analyses.
Usage:
argot cli [options] <package path(s)>`
Usage for CLI
Variables ¶
var Commands = map[string]CommandDefinition{ CmdAstName: { Name: toolAstName, Description: "Print the AST of a function or file (shows detailed AST)", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "regex": map[string]interface{}{ "type": "string", "description": "Regex to match function or file names", }, "file": map[string]interface{}{ "type": "boolean", "description": "Print AST of file instead of function", }, }, Required: []string{"regex"}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { regex, ok := props["regex"].(string) if !ok || regex == "" { return Command{}, fmt.Errorf("regex must be a non-empty string") } fileFlag := false if file, ok := props["file"]; ok { fileFlag, ok = file.(bool) if !ok { return Command{}, fmt.Errorf("file must be a boolean") } } return Command{ Args: []string{regex}, Flags: map[string]bool{"file": fileFlag}, }, nil }, Function: cmdAst, }, CmdBacktraceName: { Name: toolBacktraceName, Description: "Run the backtrace analysis with parameters in config", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{}, Required: []string{}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { return Command{ Args: []string{}, Flags: map[string]bool{}, }, nil }, Function: cmdBacktrace, }, CmdBuildGraphName: { Name: toolBuildGraphName, Description: "Build the inter-procedural dataflow graph", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{}, Required: []string{}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { return Command{ Args: []string{}, Flags: map[string]bool{}, }, nil }, Function: cmdBuildGraph, }, CmdCallersName: { Name: toolCallersName, Description: "Show the callers of a function. Uses the best analysis loaded (e.g. pointer when loaded).", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "regex": map[string]interface{}{ "type": "string", "description": "Regex to match function names", }, }, Required: []string{"regex"}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { regex, ok := props["regex"].(string) if !ok || regex == "" { return Command{}, fmt.Errorf("regex must be a non-empty string") } return Command{ Args: []string{regex}, Flags: map[string]bool{}, }, nil }, Function: cmdCallers, }, CmdCalleesName: { Name: toolCalleesName, Description: "Show callees of a function. Uses the best analysis loaded (e.g. pointer when loaded).", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "regex": map[string]interface{}{ "type": "string", "description": "Regex to match function names", }, }, Required: []string{"regex"}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { regex, ok := props["regex"].(string) if !ok || regex == "" { return Command{}, fmt.Errorf("regex must be a non-empty string") } return Command{ Args: []string{regex}, Flags: map[string]bool{}, }, nil }, Function: cmdCallees, }, CmdCdName: { Name: toolCdName, Description: "Move to relative directory (system command)", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "directory": map[string]interface{}{ "type": "string", "description": "Directory path to change to", }, }, Required: []string{"directory"}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { directory, ok := props["directory"].(string) if !ok { return Command{}, fmt.Errorf("directory must be provided") } return Command{ Args: []string{directory}, Flags: map[string]bool{}, }, nil }, Function: cmdCd, }, CmdExitName: { Name: toolExitName, Description: "Exit the program (system command, terminates the server).", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{}, Required: []string{}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { return Command{ Args: []string{}, Flags: map[string]bool{}, }, nil }, Function: cmdExit, }, CmdFocusName: { Name: toolFocusName, Description: "Focus on a specific function, so you can inspect ssa values, instructions, aliases...", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "regex": map[string]interface{}{ "type": "string", "description": "Regex to match function names", }, }, Required: []string{"regex"}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { regex, ok := props["regex"].(string) if !ok || regex == "" { return Command{}, fmt.Errorf("regex must be a non-empty string") } return Command{ Args: []string{regex}, Flags: map[string]bool{}, }, nil }, Function: cmdFocus, }, CmdIntraName: { Name: toolIntraName, Description: "Run intra-procedural dataflow analysis (requires focused function)", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{}, Required: []string{}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { return Command{ Args: []string{}, Flags: map[string]bool{}, }, nil }, Function: cmdIntra, }, CmdListName: { Name: toolListName, Description: "List functions matching a regex (golang), " + "with options on listing reachable and summarized functions." + "Matches against the full function name (package name + opt. receiver + function name)", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "regex": map[string]interface{}{ "type": "string", "description": "Regex to match full function names", }, "reachable_only": map[string]interface{}{ "type": "boolean", "description": "List only reachable functions", }, "summarized_only": map[string]interface{}{ "type": "boolean", "description": "List only summarized functions", }, }, Required: []string{}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { regex := "" if regexObj, ok := props["regex"]; ok { if regexStr, ok := regexObj.(string); ok { regex = regexStr } else { return Command{}, fmt.Errorf("regex must be a string") } } flags := map[string]bool{} if reachableOnly, ok := props["reachable_only"]; ok { if reachableBool, ok := reachableOnly.(bool); ok { flags["r"] = reachableBool } else { return Command{}, fmt.Errorf("reachable_only must be a boolean") } } if summarizedOnly, ok := props["summarized_only"]; ok { if summarizedBool, ok := summarizedOnly.(bool); ok { flags["s"] = summarizedBool } else { return Command{}, fmt.Errorf("summarized_only must be a boolean") } } args := []string{} if regex != "" { args = []string{regex} } return Command{ Args: args, Flags: flags, }, nil }, Function: cmdList, }, CmdLoadName: { Name: toolLoadName, Description: "Load new program from package paths. This resets the analysis state (pointer, dataflow, ..)", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "paths": map[string]interface{}{ "type": "array", "items": map[string]interface{}{"type": "string"}, "description": "Paths to load (files or directory)", }, "target": map[string]interface{}{ "type": "string", "description": "Target to load (state? shows available targets from config, required loaded config)", }, }, Required: []string{"paths"}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { packagesObj, ok := props["paths"] if !ok { return Command{}, fmt.Errorf("paths must be provided") } packages, ok := packagesObj.([]interface{}) if !ok { return Command{}, fmt.Errorf("paths must be an array") } args := make([]string, len(packages)) for i, pkg := range packages { args[i], ok = pkg.(string) if !ok { return Command{}, fmt.Errorf("path must be a string") } } namedArgs := map[string]string{} if target, ok := props["target"]; ok { if targetStr, ok := target.(string); ok { namedArgs["target"] = targetStr } else { return Command{}, fmt.Errorf("target must be a string") } } return Command{ Args: args, Flags: map[string]bool{}, NamedArgs: namedArgs, }, nil }, Function: cmdLoad, }, CmdLoadPackagesName: { Name: toolLoadPackagesName, Description: "Load Go packages with optional type information for inspection." + " This is faster than loading a whole program, and doesn't require loading the main entry point." + "However, dataflow and pointer analyses will not be available.", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "packages": map[string]interface{}{ "type": "array", "items": map[string]interface{}{"type": "string"}, "description": "Package paths to load", }, "with_types": map[string]interface{}{ "type": "boolean", "description": "Load packages with types", }, }, Required: []string{"packages"}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { packagesObj, ok := props["packages"] if !ok { return Command{}, fmt.Errorf("packages must be provided") } packages, ok := packagesObj.([]interface{}) if !ok { return Command{}, fmt.Errorf("packages must be an array") } args := make([]string, len(packages)) for i, pkg := range packages { args[i], ok = pkg.(string) if !ok { return Command{}, fmt.Errorf("package must be a string") } } flags := map[string]bool{} if withTypes, ok := props["with_types"]; ok { if withTypesBool, ok := withTypes.(bool); ok { flags["t"] = withTypesBool } else { return Command{}, fmt.Errorf("with_types must be a boolean") } } return Command{ Args: args, Flags: flags, }, nil }, Function: cmdLoadPackages, }, CmdLsName: { Name: toolLsName, Description: "List files in directory (system command)", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "path": map[string]interface{}{ "type": "string", "description": "Path to list (defaults to current directory)", }, }, Required: []string{}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { path := "." if pathObj, ok := props["path"]; ok { if pathStr, ok := pathObj.(string); ok { path = pathStr } else { return Command{}, fmt.Errorf("path must be a string") } } return Command{ Args: []string{path}, Flags: map[string]bool{}, }, nil }, Function: cmdLs, }, CmdMarkName: { Name: toolMarkName, Description: "Show dataflow marks and associated instructions (requires focused function)", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "regex": map[string]interface{}{ "type": "string", "description": "Regex to match names", }, }, Required: []string{"regex"}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { regex, ok := props["regex"].(string) if !ok || regex == "" { return Command{}, fmt.Errorf("regex must be a non-empty string") } return Command{ Args: []string{regex}, Flags: map[string]bool{}, }, nil }, Function: cmdMark, }, CmdMayAliasName: { Name: toolMayAliasName, Description: "Check if values may alias (requires focused function)", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "values": map[string]interface{}{ "type": "string", "description": "Regex matching values to check for aliasing.", }, }, Required: []string{"values"}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { if values, ok := props["values"].(string); ok { return Command{ Args: []string{values}, Flags: map[string]bool{}, }, nil } return Command{}, fmt.Errorf("values must be a string") }, Function: cmdMayAlias, }, CmdPackageName: { Name: toolPackageName, Description: "Show package information of focused function (requires focused function)", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "regex": map[string]interface{}{ "type": "string", "description": "Regex to match package names", }, }, Required: []string{}, }, Function: cmdPackage, }, CmdRebuildName: { Name: toolRebuildName, Description: "Rebuild the program being analyzed. Re-initializes the complex analyses!", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{}, Required: []string{}, }, Function: cmdRebuild, }, CmdReconfigName: { Name: toolReconfigName, Description: "Reload current config or load new configuration file. Re-initializes all the analyses.", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "config_file": map[string]interface{}{ "type": "string", "description": "Path to config file", }, }, Required: []string{"config_file"}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { configFile, ok := props["config_file"].(string) if !ok || configFile == "" { return Command{}, fmt.Errorf("config_file must be a non-empty string") } return Command{ Args: []string{configFile}, Flags: map[string]bool{}, }, nil }, Function: cmdReconfig, }, CmdScanName: { Name: toolScanName, Description: "Scan AST for identifiers and types matching regex patterns.", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "pattern": map[string]interface{}{ "type": "string", "description": "Pattern to scan for", }, }, Required: []string{"pattern"}, }, Function: cmdScan, }, CmdShowPackageName: { Name: toolShowPackageName, Description: "Show detailed information about a loaded package including files and imports.", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "regex": map[string]interface{}{ "type": "string", "description": "Regex to match package names", }, }, Required: []string{}, }, Function: cmdShowPackage, }, CmdShowSsaName: { Name: toolShowSsaName, Description: "Print the SSA representation of a function.", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "regex": map[string]interface{}{ "type": "string", "description": "Regex to match full function names", }, }, Required: []string{}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { regex, ok := props["regex"].(string) if ok && regex == "" { return Command{}, fmt.Errorf("regex must be a non-empty string if provided") } return Command{ Args: []string{regex}, Flags: map[string]bool{}, }, nil }, Function: cmdShowSsa, }, CmdShowEscapeName: { Name: toolShowEscapeName, Description: "Print the escape graph of a function", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "regex": map[string]interface{}{ "type": "string", "description": "Regex to match full function names", }, }, Required: []string{}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { regex, ok := props["regex"].(string) if !ok || regex == "" { return Command{}, fmt.Errorf("regex must be a non-empty string") } return Command{ Args: []string{regex}, Flags: map[string]bool{}, }, nil }, Function: cmdShowEscape, }, CmdMembersName: { Name: toolMembersName, Description: "Print package members (functions, types, constants, globals) matching a regex", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "regex": map[string]interface{}{ "type": "string", "description": "Regex to match package names", }, }, Required: []string{"regex"}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { regex, ok := props["regex"].(string) if !ok || regex == "" { return Command{}, fmt.Errorf("regex must be a non-empty string") } return Command{ Args: []string{regex}, Flags: map[string]bool{}, }, nil }, Function: cmdMembers, }, CmdRunDataflowName: { Name: toolRunDataflowName, Description: "Run the dataflow analysis (advanced analysis)", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{}, Required: []string{}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { return Command{ Args: []string{}, Flags: map[string]bool{}, }, nil }, Function: cmdRunDataflow, }, CmdRunPointerName: { Name: toolRunPointerName, Description: "Run the pointer analysis (advanced analysis, use to get callees)", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{}, Required: []string{}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { return Command{ Args: []string{}, Flags: map[string]bool{}, }, nil }, Function: cmdRunPointer, }, CmdShowDataflowName: { Name: toolShowDataflowName, Description: "Build and print the inter-procedural dataflow graph (advanced analysis, run summarize first)", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{}, Required: []string{}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { return Command{ Args: []string{}, Flags: map[string]bool{}, }, nil }, Function: cmdShowDataflow, }, CmdSrcName: { Name: toolSrcName, Description: "Print the source code of a function.", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "regex": map[string]interface{}{ "type": "string", "description": "Regex to match full function names", }, }, Required: []string{}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { regex, ok := props["regex"].(string) if !ok || regex == "" { return Command{}, fmt.Errorf("regex must be a non-empty string") } return Command{ Args: []string{regex}, Flags: map[string]bool{}, }, nil }, Function: cmdSrc, }, CmdSsaInstrName: { Name: toolSsaInstrName, Description: "Show SSA instruction details (requires focused function)", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "instruction": map[string]interface{}{ "type": "string", "description": "SSA instruction to examine", }, }, Required: []string{"instruction"}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { instruction, ok := props["instruction"].(string) if !ok || instruction == "" { return Command{}, fmt.Errorf("instruction must be a non-empty string") } return Command{ Args: []string{instruction}, Flags: map[string]bool{}, }, nil }, Function: cmdSsaInstr, }, CmdSsaValueName: { Name: toolSsaValueName, Description: "Show SSA value details (requires focused function)", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "value": map[string]interface{}{ "type": "string", "description": "SSA value to examine", }, }, Required: []string{"value"}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { value, ok := props["value"].(string) if !ok || value == "" { return Command{}, fmt.Errorf("value must be a non-empty string") } return Command{ Args: []string{value}, Flags: map[string]bool{}, }, nil }, Function: cmdSsaValue, }, CmdStateName: { Name: toolStateName, Description: "Show current analysis state.", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{}, Required: []string{}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { return Command{ Args: []string{}, Flags: map[string]bool{}, }, nil }, Function: cmdState, }, CmdStatsName: { Name: toolStatsName, Description: "Display comprehensive program statistics including SSA, defers, and closure usage.", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{}, Required: []string{}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { return Command{ Args: []string{}, Flags: map[string]bool{}, }, nil }, Function: cmdStats, }, CmdSummaryName: { Name: toolSummaryName, Description: "Print the internal dataflow summary of functions matching a regex. " + "You should have run summarize on that function first (or on all functions)." + "Running this may be very expensive!", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "regex": map[string]interface{}{ "type": "string", "description": "Regex to match full function names", }, "filter": map[string]interface{}{ "type": "string", "description": "Filter for summary display", }, }, Required: []string{"regex"}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { regex, ok := props["regex"].(string) if !ok || regex == "" { return Command{}, fmt.Errorf("regex must be a non-empty string") } namedArgs := map[string]string{} filter, ok := props["filter"].(string) if ok { namedArgs["f"] = filter } return Command{ Args: []string{regex, filter}, Flags: map[string]bool{}, NamedArgs: namedArgs, }, nil }, Function: cmdSummary, }, CmdSummarizeName: { Name: toolSummarizeName, Description: "Build dataflow summaries for functions using intra-procedural analysis." + "Depending on internal parameters, running the tool without arguments may only instantiate " + "the summaries without building them.", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "regex": map[string]interface{}{ "type": "string", "description": "Regex to match full function names (optional)", }, "force": map[string]interface{}{ "type": "boolean", "description": "Force summarization and bypass filters", }, }, Required: []string{"regex"}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { forceFlag := false if force, ok := props["force"]; ok { if forceBool, ok := force.(bool); ok { forceFlag = forceBool } else { return Command{}, fmt.Errorf("force flag must be a boolean") } } regex := "" regexObj, ok := props["regex"] if !ok { return Command{}, fmt.Errorf("regex must be provided") } if ok { if regexStr, ok := regexObj.(string); ok { regex = regexStr } else { return Command{}, fmt.Errorf("regex must be a string") } } return Command{ Args: []string{regex}, Flags: map[string]bool{"force": forceFlag}, }, nil }, Function: cmdSummarize, }, CmdTaintName: { Name: toolTaintName, Description: "Run the taint analysis with parameters in config file. Does nothing if no config file has been" + "loaded, or the config file does not define any taint analysis problem.", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{}, Required: []string{}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { return Command{ Args: []string{}, Flags: map[string]bool{}, }, nil }, Function: cmdTaint, }, CmdTraceName: { Name: toolTraceName, Description: "Trace dataflow paths for a specific SSA value through the program (advanced debugging analysis)", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "target": map[string]interface{}{ "type": "string", "description": "Target to trace", }, }, Required: []string{"target"}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { target, ok := props["target"].(string) if !ok || target == "" { return Command{}, fmt.Errorf("target must be a non-empty string") } return Command{ Args: []string{target}, Flags: map[string]bool{}, }, nil }, Function: cmdTrace, }, CmdUnfocusName: { Name: toolUnfocusName, Description: "Remove focus from current function (requires focused function)", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{}, Required: []string{}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { return Command{ Args: []string{}, Flags: map[string]bool{}, }, nil }, Function: cmdUnfocus, }, CmdWhereName: { Name: toolWhereName, Description: "Show source file location of functions or current focused function (requires focused function)", InputSchema: tools.MCPInputSchema{ Type: "object", Properties: map[string]interface{}{ "target": map[string]interface{}{ "type": "string", "description": "Target to locate", }, }, Required: []string{"target"}, }, SchemaTranslation: func(props map[string]interface{}) (Command, error) { target, ok := props["target"].(string) if !ok || target == "" { return Command{}, fmt.Errorf("target must be a non-empty string") } return Command{ Args: []string{target}, Flags: map[string]bool{}, }, nil }, Function: cmdWhere, }, }
Commands lists all the commands available in the cli.
Functions ¶
func Run ¶
func Run(flags tools.CommonFlags)
Run runs a simple CLI-based stdin-stdout server to allow us to explore the code.
func WriteErr ¶
WriteErr writes a formatted error message to the terminal in red color. The message is automatically terminated with a newline and the color formatting is reset after the message.
Parameters:
- tt: Terminal to write to
- format: Printf-style format string
- a: Arguments for the format string
This is a convenience function for writing error messages with consistent red coloring in terminal environments.
func WriteSuccess ¶
WriteSuccess writes a formatted success message to the terminal in green color. The message is automatically terminated with a newline and the color formatting is reset after the message.
Parameters:
- tt: Terminal to write to
- format: Printf-style format string
- a: Arguments for the format string
This is a convenience function for writing success messages with consistent green coloring in terminal environments.
Types ¶
type Command ¶
type Command struct {
// Name is the name of the command (e.g. exit, ls, ...)
Name string
// Args contains all the non-named arguments (arguments without keys)
Args []string
// NamedArgs contains all the named arguments (arguments --key value)
NamedArgs map[string]string
// Flags contains all the flags (arguments -key)
Flags map[string]bool
}
Command contains the parsed arguments and name of a command in the command-line tool
func ParseCommand ¶
ParseCommand parses a command of the form "command arg1 arg2 -name1 namedArg1 -flag1 arg3"
- the first string is the name of the command
- every string preceded by -- is a named argument, and the next string will be parsed as its value A valid named argument MUST have a value.
- every string preceded by - but not -- is a flag,
- every other string will be a non named argument
type CommandDefinition ¶ added in v0.5.0
type CommandDefinition struct {
// Name of the command
Name string
// Description of the command
Description string
// InputSchema of the command (for the MCP server)
InputSchema tools.MCPInputSchema
// SchemaTranslation is the translation from the input schema to the command schema
SchemaTranslation func(props map[string]interface{}) (Command, error)
// Function to run the command
Function func(o Outputter, s *Session, command Command, withTest bool) bool
}
A CommandDefinition defines a command both for the cli and for the MCP server.
func (CommandDefinition) ToMCPToolDefinition ¶ added in v0.5.0
func (c CommandDefinition) ToMCPToolDefinition() tools.MCPTool
ToMCPToolDefinition returns the MCP tool definition of the command.
type NameAndLoc ¶
type NameAndLoc struct {
// contains filtered or unexported fields
}
NameAndLoc hold a name and location together
type Outputter ¶ added in v0.5.0
type Outputter struct {
// contains filtered or unexported fields
}
Outputter provides a unified interface for writing output to either a terminal or standard writers. It automatically handles color formatting when writing to a terminal and falls back to plain text when writing to regular io.Writers.
The Outputter can operate in two modes:
- Terminal mode: Uses a term.Terminal for colored output with escape sequences
- Writer mode: Uses separate io.Writers for normal output and error output
This abstraction allows the same code to work in both interactive terminal environments and non-interactive contexts (like file output or pipes).
func NewOutputter ¶ added in v0.5.0
NewOutputter creates a new Outputter that writes to the provided io.Writers. This constructor is used for non-interactive environments where colored output is not desired or supported.
Parameters:
- out: Writer for normal output messages
- err: Writer for error messages
Returns an Outputter configured for plain text output without terminal features.
func NewTerminalOutputter ¶ added in v0.5.0
NewTerminalOutputter creates a new Outputter that writes to a terminal. This constructor is used for interactive environments where colored output and terminal escape sequences are supported.
Parameters:
- tt: Terminal instance that supports colored output and escape sequences
Returns an Outputter configured for terminal output with color support.
func (Outputter) EscBlue ¶ added in v0.5.0
EscBlue returns the ANSI escape sequence for blue text color. When using a terminal, returns the terminal's blue escape sequence. When using writers, returns an empty byte slice (no coloring).
This method allows manual control over text coloring in terminal mode.
func (Outputter) EscCyan ¶ added in v0.5.0
EscCyan returns the ANSI escape sequence for cyan text color. When using a terminal, returns the terminal's cyan escape sequence. When using writers, returns an empty byte slice (no coloring).
This method allows manual control over text coloring in terminal mode.
func (Outputter) EscGreen ¶ added in v0.5.0
EscGreen returns the ANSI escape sequence for green text color. When using a terminal, returns the terminal's green escape sequence. When using writers, returns an empty byte slice (no coloring).
This method allows manual control over text coloring in terminal mode.
func (Outputter) EscMagenta ¶ added in v0.5.0
EscMagenta returns the ANSI escape sequence for magenta text color. When using a terminal, returns the terminal's magenta escape sequence. When using writers, returns an empty byte slice (no coloring).
This method allows manual control over text coloring in terminal mode.
func (Outputter) EscRed ¶ added in v0.5.0
EscRed returns the ANSI escape sequence for red text color. When using a terminal, returns the terminal's red escape sequence. When using writers, returns an empty byte slice (no coloring).
This method allows manual control over text coloring in terminal mode.
func (Outputter) EscReset ¶ added in v0.5.0
EscReset returns the ANSI escape sequence to reset text formatting. When using a terminal, returns the terminal's reset escape sequence. When using writers, returns an empty byte slice (no formatting reset needed).
This method should be used after applying color escape sequences to return text formatting to normal.
func (Outputter) EscWhite ¶ added in v0.5.0
EscWhite returns the ANSI escape sequence for white text color. When using a terminal, returns the terminal's white escape sequence. When using writers, returns an empty byte slice (no coloring).
This method allows manual control over text coloring in terminal mode.
func (Outputter) EscYellow ¶ added in v0.5.0
EscYellow returns the ANSI escape sequence for yellow text color. When using a terminal, returns the terminal's yellow escape sequence. When using writers, returns an empty byte slice (no coloring).
This method allows manual control over text coloring in terminal mode.
func (Outputter) Write ¶ added in v0.5.0
Write writes formatted output to the appropriate output channel. This is the standard method for writing normal output messages. No special coloring is applied - use WriteErr or WriteSuccess for colored output.
Parameters:
- format: Printf-style format string
- a: Arguments for the format string
Unlike WriteErr and WriteSuccess, this method does not automatically add a newline.
func (Outputter) WriteErr ¶ added in v0.5.0
WriteErr writes formatted error messages to the appropriate output channel. When using a terminal, the message is displayed in red color. When using writers, the message is written to the error writer.
Parameters:
- format: Printf-style format string
- a: Arguments for the format string
The message is automatically terminated with a newline when using terminal mode.
func (Outputter) WriteSuccess ¶ added in v0.5.0
WriteSuccess writes formatted success messages to the appropriate output channel. When using a terminal, the message is displayed in green color. When using writers, the message is written to the normal output writer.
Parameters:
- format: Printf-style format string
- a: Arguments for the format string
The message is automatically terminated with a newline when using terminal mode.
func (Outputter) Writer ¶ added in v0.5.0
Writer returns the appropriate io.Writer for normal output. If the Outputter is configured with a terminal, it returns the terminal. Otherwise, it returns the configured output writer.
This method provides access to the underlying writer for cases where direct writing is needed without formatting.
type Session ¶ added in v0.5.0
type Session struct {
// contains filtered or unexported fields
}
Session stores state information about the current cli Session
func NewSession ¶ added in v0.5.0
func NewSession(flags tools.CommonFlags, isTt bool) *Session
NewSession returns a new session with the provided flags.
func (*Session) LoadConfig ¶ added in v0.5.0
LoadConfig triggers the config loading for the session. Does nothing when the config state is non-null and reload is not true.