diff --git a/funcSize.go b/funcSize.go new file mode 100644 index 0000000..56d9f9d --- /dev/null +++ b/funcSize.go @@ -0,0 +1,52 @@ +package main + +import ( + "fmt" + "os/exec" + "regexp" +) + +type funcSizeRunner struct { + messageRE *regexp.Regexp +} + +func (r *funcSizeRunner) Init() { + r.messageRE = regexp.MustCompile(`(.*) STEXT.* size=(\d+)`) +} + +func (r *funcSizeRunner) Run(pkg string) error { + cmd := exec.Command("go", r.getCmd(pkg)...) + out, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("%v: %s", err, out) + } + + type resultRow struct { + Fn string `json:"fn"` + Size string `json:"size"` + } + results := []resultRow{} + + // TODO: add a CLI flag for the function name filtering? + // Having to use a grep in 99% of use cases is not very convenient. + for _, submatches := range r.messageRE.FindAllStringSubmatch(string(out), -1) { + results = append(results, resultRow{ + Fn: submatches[1], + Size: submatches[2], + }) + } + + if asJSON { + marshalJSON(results) + return nil + } + + for _, r := range results { + fmt.Printf("%s: %s bytes\n", r.Fn, r.Size) + } + return nil +} + +func (r *funcSizeRunner) getCmd(pkg string) []string { + return goArgs(pkg, goArgsBuild, goArgsGcFlags("-S")) +} diff --git a/main.go b/main.go index 4965aaf..ac258dc 100644 --- a/main.go +++ b/main.go @@ -56,6 +56,14 @@ var cmds = []acmd.Command{ return run(&boundCheckRunner{}) }, }, + { + Name: "funcSize", + Alias: "fsize", + Description: "list function machine code sizes in bytes", + ExecFunc: func(_ context.Context, _ []string) error { + return run(&funcSizeRunner{}) + }, + }, } type subCommandRunner interface {