package main import ( "bytes" "flag" "fmt" "io" "io/ioutil" "os" "path/filepath" "strings" "github.com/google/blueprint/parser" ) var ( result = make(map[string]string) defaults = make(map[string]string) Root = "" ) var ( exitCode = 0 ) func report(err error) { fmt.Fprintln(os.Stderr, err) exitCode = 2 } func usage() { usageViolation("") } func usageViolation(violation string) { fmt.Fprintln(os.Stderr, violation) fmt.Fprintln(os.Stderr, "usage: fuzzparser [flags] [path ...]") flag.PrintDefaults() os.Exit(2) } func processFile(filename string, out io.Writer) error { f, err := os.Open(filename) if err != nil { return err } defer f.Close() return processReader(filename, f, out) } func processReader(filename string, in io.Reader, out io.Writer) error { src, err := ioutil.ReadAll(in) if err != nil { return err } r := bytes.NewBuffer(src) file, errs := parser.ParseAndEval(filename, r, parser.NewScope(nil)) modules := findModules(file) // First collect all the defaults into a dictionary for _, mod := range modules { if mod.Type == "cc_defaults" { default_name := "" for _, prop := range mod.Map.Properties { if prop.Name == "name" { value := prop.Value.String() default_name = value[1:strings.Index(value, "@")-1] } else if prop.Name == "static_libs" || prop.Name == "shared_libs" { value := prop.Value.String() for strings.Index(value, "\"") > -1 { value = value[strings.Index(value, "\"")+1:] lib_name := value[:strings.Index(value, "\"")] if _ , ok := defaults[default_name]; ok { defaults[default_name] += "," + lib_name } else { defaults[default_name] += lib_name } value = value[strings.Index(value, "\"")+1:] } } else if prop.Name == "defaults" { // Get the defaults of the default value := prop.Value.String() for strings.Index(value, "\"") > -1 { value = value[strings.Index(value, "\"")+1:] sub_default_name := value[:strings.Index(value, "\"")] if _ , ok := defaults[default_name]; ok { defaults[default_name] += "," + defaults[sub_default_name] } else { defaults[default_name] += defaults[sub_default_name] } value = value[strings.Index(value, "\"")+1:] } } else if prop.Name == "target" { value := prop.Value.String() if default_name == "binder_fuzz_defaults" { fmt.Printf("---> target value for %s: %s\n", default_name ,value) } for strings.Index(value, "\"") > -1 { value = value[strings.Index(value, "\"")+1:] lib := value[:strings.Index(value, "\"")] if _ , ok := defaults[default_name]; ok { defaults[default_name] += "," + lib } else { defaults[default_name] += lib } value = value[strings.Index(value, "\"")+1:] } } } } } for _, mod := range modules { if mod.Type == "cc_fuzz" { fuzzer_name := "" for _, prop := range mod.Map.Properties { // First get the name of the fuzzer if prop.Name == "name" { value := prop.Value.String() fuzzer_name = value[1:strings.Index(value, "@")-1] } else if prop.Name == "defaults" { value := prop.Value.String() if strings.Index(value, "@") == 0 { value = value[1:] } default_name := value[strings.Index(value, "[")+2: strings.Index(value, "@")-1] if _, ok := result[fuzzer_name]; ok { result[fuzzer_name] += "," + defaults[default_name] } else { result[fuzzer_name] += defaults[default_name] } } else if prop.Name == "static_libs" || prop.Name == "shared_libs" { value := prop.Value.String() for strings.Index(value, "\"") > -1 { value = value[strings.Index(value, "\"")+1:] lib_name := value[:strings.Index(value, "\"")] if _ , ok := result[fuzzer_name]; ok { result[fuzzer_name] += "," + lib_name } else { result[fuzzer_name] += lib_name } value = value[strings.Index(value, "\"")+1:] } } } } } if len(errs) > 0 { for _, err := range errs { fmt.Fprintln(os.Stderr, err) } return fmt.Errorf("%d parsing errors", len(errs)) } return err } func findModules(file *parser.File) (modules []*parser.Module) { if file != nil { for _, def := range file.Defs { if module, ok := def.(*parser.Module); ok { modules = append(modules, module) } } } return modules } func walkDir(path string) { visitFile := func(path string, f os.FileInfo, err error) error { if err == nil && f.Name() == "Android.bp" { err = processFile(path, os.Stdout) } if err != nil { fmt.Printf("ERROR") report(err) } return nil } fmt.Printf("Parsing %s recursively...\n", path) filepath.Walk(path, visitFile) } func main() { flag.Usage = usage flag.Parse() for i := 0; i < flag.NArg(); i++ { Root := flag.Arg(i) fmt.Printf("Root %s\n", Root) switch dir, err := os.Stat(Root); { case err != nil: report(err) case dir.IsDir(): walkDir(Root) default: if err := processFile(Root, os.Stdout); err != nil { report(err) } } } fmt.Printf("-------------------------------------\n") fmt.Printf("Fuzzer name -------Library name------\n") if len(result) > 0 { for k, v := range result { if len(v) == 0 { v = "NOT FOUND" } fmt.Printf("%s:%s\n", k, v) } } os.Exit(exitCode) }