xref: /aosp_15_r20/tools/security/fuzzing/fuzzer_parser/fuzzparser.go (revision d9ecfb0f4d734c9ce41cde8ac4d585b094fd4222)
1package main
2
3import (
4	"bytes"
5	"flag"
6	"fmt"
7	"io"
8	"io/ioutil"
9	"os"
10	"path/filepath"
11	"strings"
12
13	"github.com/google/blueprint/parser"
14)
15
16var (
17	result	= make(map[string]string)
18	defaults = make(map[string]string)
19	Root = ""
20)
21
22var (
23	exitCode = 0
24)
25
26func report(err error) {
27	fmt.Fprintln(os.Stderr, err)
28	exitCode = 2
29}
30
31func usage() {
32	usageViolation("")
33}
34
35func usageViolation(violation string) {
36	fmt.Fprintln(os.Stderr, violation)
37	fmt.Fprintln(os.Stderr, "usage: fuzzparser [flags] [path ...]")
38	flag.PrintDefaults()
39	os.Exit(2)
40}
41
42func processFile(filename string, out io.Writer) error {
43	f, err := os.Open(filename)
44	if err != nil {
45		return err
46	}
47	defer f.Close()
48
49	return processReader(filename, f, out)
50}
51
52func processReader(filename string, in io.Reader, out io.Writer) error {
53	src, err := ioutil.ReadAll(in)
54	if err != nil {
55		return err
56	}
57
58	r := bytes.NewBuffer(src)
59	file, errs := parser.ParseAndEval(filename, r, parser.NewScope(nil))
60
61	modules := findModules(file)
62	// First collect all the defaults into a dictionary
63	for _, mod := range modules {
64	    if mod.Type == "cc_defaults" {
65	    	default_name := ""
66	    	for _, prop := range mod.Map.Properties {
67				if prop.Name == "name" {
68					value := prop.Value.String()
69					default_name = value[1:strings.Index(value, "@")-1]
70				} else if prop.Name == "static_libs" || prop.Name == "shared_libs" {
71					value := prop.Value.String()
72					for strings.Index(value, "\"") > -1 {
73						value = value[strings.Index(value, "\"")+1:]
74						lib_name := value[:strings.Index(value, "\"")]
75						if _ , ok := defaults[default_name]; ok {
76							defaults[default_name] += "," + lib_name
77						} else {
78							defaults[default_name] += lib_name
79						}
80						value = value[strings.Index(value, "\"")+1:]
81					}
82				} else if prop.Name == "defaults" {
83					// Get the defaults of the default
84					value := prop.Value.String()
85					for strings.Index(value, "\"") > -1 {
86						value = value[strings.Index(value, "\"")+1:]
87						sub_default_name := value[:strings.Index(value, "\"")]
88						if _ , ok := defaults[default_name]; ok {
89							defaults[default_name] += "," + defaults[sub_default_name]
90						} else {
91							defaults[default_name] += defaults[sub_default_name]
92						}
93						value = value[strings.Index(value, "\"")+1:]
94					}
95				} else if prop.Name == "target" {
96					value := prop.Value.String()
97					if default_name == "binder_fuzz_defaults" {
98						fmt.Printf("---> target value for %s: %s\n", default_name ,value)
99					}
100					for strings.Index(value, "\"") > -1 {
101						value = value[strings.Index(value, "\"")+1:]
102						lib := value[:strings.Index(value, "\"")]
103						if _ , ok := defaults[default_name]; ok {
104							defaults[default_name] += "," + lib
105						} else {
106							defaults[default_name] += lib
107						}
108						value = value[strings.Index(value, "\"")+1:]
109					}
110				}
111			}
112		}
113    }
114
115	for _, mod := range modules {
116		if mod.Type == "cc_fuzz" {
117			fuzzer_name := ""
118			for _, prop := range mod.Map.Properties {
119				// First get the name of the fuzzer
120				if prop.Name == "name" {
121					value := prop.Value.String()
122					fuzzer_name = value[1:strings.Index(value, "@")-1]
123				} else if prop.Name == "defaults" {
124					value := prop.Value.String()
125					if strings.Index(value, "@") == 0 {
126						value = value[1:]
127					}
128					default_name := value[strings.Index(value, "[")+2: strings.Index(value, "@")-1]
129					if _, ok := result[fuzzer_name]; ok {
130						result[fuzzer_name] += "," + defaults[default_name]
131					} else {
132						result[fuzzer_name] += defaults[default_name]
133					}
134				} else if prop.Name == "static_libs" || prop.Name == "shared_libs" {
135					value := prop.Value.String()
136					for strings.Index(value, "\"") > -1 {
137						value = value[strings.Index(value, "\"")+1:]
138						lib_name := value[:strings.Index(value, "\"")]
139						if _ , ok := result[fuzzer_name]; ok {
140							result[fuzzer_name] += "," + lib_name
141						} else {
142							result[fuzzer_name] += lib_name
143						}
144						value = value[strings.Index(value, "\"")+1:]
145					}
146				}
147			}
148	    }
149	}
150
151	if len(errs) > 0 {
152		for _, err := range errs {
153			fmt.Fprintln(os.Stderr, err)
154		}
155		return fmt.Errorf("%d parsing errors", len(errs))
156	}
157
158    return err
159}
160
161func findModules(file *parser.File) (modules []*parser.Module) {
162    if file != nil {
163		for _, def := range file.Defs {
164			if module, ok := def.(*parser.Module); ok {
165				modules = append(modules, module)
166			}
167		}
168	}
169	return modules
170}
171
172func walkDir(path string) {
173	visitFile := func(path string, f os.FileInfo, err error) error {
174		if err == nil && f.Name() == "Android.bp" {
175			err = processFile(path, os.Stdout)
176		}
177		if err != nil {
178			fmt.Printf("ERROR")
179			report(err)
180		}
181		return nil
182	}
183    fmt.Printf("Parsing %s recursively...\n", path)
184	filepath.Walk(path, visitFile)
185}
186
187func main() {
188	flag.Usage = usage
189	flag.Parse()
190
191	for i := 0; i < flag.NArg(); i++ {
192		Root := flag.Arg(i)
193		fmt.Printf("Root %s\n", Root)
194		switch dir, err := os.Stat(Root); {
195		case err != nil:
196			report(err)
197		case dir.IsDir():
198			walkDir(Root)
199		default:
200			if err := processFile(Root, os.Stdout); err != nil {
201				report(err)
202			}
203		}
204	}
205
206	fmt.Printf("-------------------------------------\n")
207	fmt.Printf("Fuzzer name -------Library name------\n")
208	if len(result) > 0 {
209		for k, v := range result {
210			if len(v) == 0 {
211				v = "NOT FOUND"
212			}
213			fmt.Printf("%s:%s\n", k, v)
214		}
215	}
216
217	os.Exit(exitCode)
218}
219