xref: /aosp_15_r20/development/vndk/tools/elfcheck/bpflatten/main.go (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1*90c8c64dSAndroid Build Coastguard Worker// Copyright (C) 2020 The Android Open Source Project
2*90c8c64dSAndroid Build Coastguard Worker//
3*90c8c64dSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*90c8c64dSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*90c8c64dSAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*90c8c64dSAndroid Build Coastguard Worker//
7*90c8c64dSAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*90c8c64dSAndroid Build Coastguard Worker//
9*90c8c64dSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*90c8c64dSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*90c8c64dSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*90c8c64dSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*90c8c64dSAndroid Build Coastguard Worker// limitations under the License.
14*90c8c64dSAndroid Build Coastguard Worker
15*90c8c64dSAndroid Build Coastguard Workerpackage main
16*90c8c64dSAndroid Build Coastguard Worker
17*90c8c64dSAndroid Build Coastguard Workerimport (
18*90c8c64dSAndroid Build Coastguard Worker	"encoding/json"
19*90c8c64dSAndroid Build Coastguard Worker	"flag"
20*90c8c64dSAndroid Build Coastguard Worker	"fmt"
21*90c8c64dSAndroid Build Coastguard Worker	"io"
22*90c8c64dSAndroid Build Coastguard Worker	"os"
23*90c8c64dSAndroid Build Coastguard Worker	"strings"
24*90c8c64dSAndroid Build Coastguard Worker
25*90c8c64dSAndroid Build Coastguard Worker	"github.com/google/blueprint/parser"
26*90c8c64dSAndroid Build Coastguard Worker)
27*90c8c64dSAndroid Build Coastguard Worker
28*90c8c64dSAndroid Build Coastguard Workertype FlatModule struct {
29*90c8c64dSAndroid Build Coastguard Worker	Type        string
30*90c8c64dSAndroid Build Coastguard Worker	Name        string
31*90c8c64dSAndroid Build Coastguard Worker	PropertyMap map[string]interface{}
32*90c8c64dSAndroid Build Coastguard Worker}
33*90c8c64dSAndroid Build Coastguard Worker
34*90c8c64dSAndroid Build Coastguard Workerfunc expandScalarTypeExpression(value parser.Expression) (scalar interface{}, isScalar bool) {
35*90c8c64dSAndroid Build Coastguard Worker	if s, ok := value.(*parser.Bool); ok {
36*90c8c64dSAndroid Build Coastguard Worker		return s.Value, true
37*90c8c64dSAndroid Build Coastguard Worker	} else if s, ok := value.(*parser.String); ok {
38*90c8c64dSAndroid Build Coastguard Worker		return s.Value, true
39*90c8c64dSAndroid Build Coastguard Worker	} else if s, ok := value.(*parser.Int64); ok {
40*90c8c64dSAndroid Build Coastguard Worker		return s.Value, true
41*90c8c64dSAndroid Build Coastguard Worker	}
42*90c8c64dSAndroid Build Coastguard Worker	return nil, false
43*90c8c64dSAndroid Build Coastguard Worker}
44*90c8c64dSAndroid Build Coastguard Worker
45*90c8c64dSAndroid Build Coastguard Workerfunc populatePropertyMap(propMap map[string]interface{}, prefix string, m *parser.Map) {
46*90c8c64dSAndroid Build Coastguard Worker	for _, prop := range m.Properties {
47*90c8c64dSAndroid Build Coastguard Worker		name := prop.Name
48*90c8c64dSAndroid Build Coastguard Worker		if prefix != "" {
49*90c8c64dSAndroid Build Coastguard Worker			name = prefix + "." + name
50*90c8c64dSAndroid Build Coastguard Worker		}
51*90c8c64dSAndroid Build Coastguard Worker		value := prop.Value
52*90c8c64dSAndroid Build Coastguard Worker		if s, isScalar := expandScalarTypeExpression(value); isScalar {
53*90c8c64dSAndroid Build Coastguard Worker			propMap[name] = s
54*90c8c64dSAndroid Build Coastguard Worker		} else if list, ok := value.(*parser.List); ok {
55*90c8c64dSAndroid Build Coastguard Worker			var l []interface{}
56*90c8c64dSAndroid Build Coastguard Worker			for _, v := range list.Values {
57*90c8c64dSAndroid Build Coastguard Worker				if s, isScalar := expandScalarTypeExpression(v); isScalar {
58*90c8c64dSAndroid Build Coastguard Worker					l = append(l, s)
59*90c8c64dSAndroid Build Coastguard Worker				}
60*90c8c64dSAndroid Build Coastguard Worker			}
61*90c8c64dSAndroid Build Coastguard Worker			propMap[name] = l
62*90c8c64dSAndroid Build Coastguard Worker		} else if mm, ok := value.(*parser.Map); ok {
63*90c8c64dSAndroid Build Coastguard Worker			populatePropertyMap(propMap, name, mm)
64*90c8c64dSAndroid Build Coastguard Worker		}
65*90c8c64dSAndroid Build Coastguard Worker	}
66*90c8c64dSAndroid Build Coastguard Worker}
67*90c8c64dSAndroid Build Coastguard Worker
68*90c8c64dSAndroid Build Coastguard Workervar anonymousModuleCount int
69*90c8c64dSAndroid Build Coastguard Worker
70*90c8c64dSAndroid Build Coastguard Workerfunc flattenModule(module *parser.Module) (flattened FlatModule) {
71*90c8c64dSAndroid Build Coastguard Worker	flattened.Type = module.Type
72*90c8c64dSAndroid Build Coastguard Worker	if prop, found := module.GetProperty("name"); found {
73*90c8c64dSAndroid Build Coastguard Worker		if value, ok := prop.Value.(*parser.String); ok {
74*90c8c64dSAndroid Build Coastguard Worker			flattened.Name = value.Value
75*90c8c64dSAndroid Build Coastguard Worker		}
76*90c8c64dSAndroid Build Coastguard Worker	} else {
77*90c8c64dSAndroid Build Coastguard Worker		flattened.Name = fmt.Sprintf("anonymous@<%d>", anonymousModuleCount)
78*90c8c64dSAndroid Build Coastguard Worker		anonymousModuleCount++
79*90c8c64dSAndroid Build Coastguard Worker	}
80*90c8c64dSAndroid Build Coastguard Worker	flattened.PropertyMap = make(map[string]interface{})
81*90c8c64dSAndroid Build Coastguard Worker	populatePropertyMap(flattened.PropertyMap, "", &module.Map)
82*90c8c64dSAndroid Build Coastguard Worker	return flattened
83*90c8c64dSAndroid Build Coastguard Worker}
84*90c8c64dSAndroid Build Coastguard Worker
85*90c8c64dSAndroid Build Coastguard Workerfunc processFile(filename string, in io.Reader) ([]FlatModule, error) {
86*90c8c64dSAndroid Build Coastguard Worker	if in == nil {
87*90c8c64dSAndroid Build Coastguard Worker		if file, err := os.Open(filename); err != nil {
88*90c8c64dSAndroid Build Coastguard Worker			return nil, err
89*90c8c64dSAndroid Build Coastguard Worker		} else {
90*90c8c64dSAndroid Build Coastguard Worker			defer file.Close()
91*90c8c64dSAndroid Build Coastguard Worker			in = file
92*90c8c64dSAndroid Build Coastguard Worker		}
93*90c8c64dSAndroid Build Coastguard Worker	}
94*90c8c64dSAndroid Build Coastguard Worker
95*90c8c64dSAndroid Build Coastguard Worker	ast, errs := parser.ParseAndEval(filename, in, &parser.Scope{})
96*90c8c64dSAndroid Build Coastguard Worker	if len(errs) > 0 {
97*90c8c64dSAndroid Build Coastguard Worker		for _, err := range errs {
98*90c8c64dSAndroid Build Coastguard Worker			fmt.Fprintln(os.Stderr, err)
99*90c8c64dSAndroid Build Coastguard Worker		}
100*90c8c64dSAndroid Build Coastguard Worker		return nil, fmt.Errorf("%d parsing errors", len(errs))
101*90c8c64dSAndroid Build Coastguard Worker	}
102*90c8c64dSAndroid Build Coastguard Worker
103*90c8c64dSAndroid Build Coastguard Worker	var modules []FlatModule
104*90c8c64dSAndroid Build Coastguard Worker	for _, def := range ast.Defs {
105*90c8c64dSAndroid Build Coastguard Worker		if module, ok := def.(*parser.Module); ok {
106*90c8c64dSAndroid Build Coastguard Worker			modules = append(modules, flattenModule(module))
107*90c8c64dSAndroid Build Coastguard Worker		}
108*90c8c64dSAndroid Build Coastguard Worker	}
109*90c8c64dSAndroid Build Coastguard Worker	return modules, nil
110*90c8c64dSAndroid Build Coastguard Worker}
111*90c8c64dSAndroid Build Coastguard Worker
112*90c8c64dSAndroid Build Coastguard Workerfunc quoteBashString(s string) string {
113*90c8c64dSAndroid Build Coastguard Worker	return strings.ReplaceAll(s, "$", "\\$")
114*90c8c64dSAndroid Build Coastguard Worker}
115*90c8c64dSAndroid Build Coastguard Worker
116*90c8c64dSAndroid Build Coastguard Workerfunc printBash(flatModules []FlatModule, w io.Writer) {
117*90c8c64dSAndroid Build Coastguard Worker	var moduleNameList []string
118*90c8c64dSAndroid Build Coastguard Worker	if len(flatModules) == 0 {
119*90c8c64dSAndroid Build Coastguard Worker		// Early bail out if we have nothing to output
120*90c8c64dSAndroid Build Coastguard Worker		return
121*90c8c64dSAndroid Build Coastguard Worker	}
122*90c8c64dSAndroid Build Coastguard Worker	fmt.Fprintf(w, "declare -a MODULE_NAMES\n")
123*90c8c64dSAndroid Build Coastguard Worker	fmt.Fprintf(w, "declare -A MODULE_TYPE_DICT\n")
124*90c8c64dSAndroid Build Coastguard Worker	fmt.Fprintf(w, "declare -A MODULE_PROP_KEYS_DICT\n")
125*90c8c64dSAndroid Build Coastguard Worker	fmt.Fprintf(w, "declare -A MODULE_PROP_VALUES_DICT\n")
126*90c8c64dSAndroid Build Coastguard Worker	fmt.Fprintf(w, "\n")
127*90c8c64dSAndroid Build Coastguard Worker	for _, module := range flatModules {
128*90c8c64dSAndroid Build Coastguard Worker		name := quoteBashString(module.Name)
129*90c8c64dSAndroid Build Coastguard Worker		moduleNameList = append(moduleNameList, name)
130*90c8c64dSAndroid Build Coastguard Worker		var modulePropKeys []string
131*90c8c64dSAndroid Build Coastguard Worker		for k := range module.PropertyMap {
132*90c8c64dSAndroid Build Coastguard Worker			modulePropKeys = append(modulePropKeys, k)
133*90c8c64dSAndroid Build Coastguard Worker		}
134*90c8c64dSAndroid Build Coastguard Worker		fmt.Fprintf(w, "MODULE_TYPE_DICT[%q]=%q\n", name, quoteBashString(module.Type))
135*90c8c64dSAndroid Build Coastguard Worker		fmt.Fprintf(w, "MODULE_PROP_KEYS_DICT[%q]=%q\n", name,
136*90c8c64dSAndroid Build Coastguard Worker			quoteBashString(strings.Join(modulePropKeys, " ")))
137*90c8c64dSAndroid Build Coastguard Worker		for k, v := range module.PropertyMap {
138*90c8c64dSAndroid Build Coastguard Worker			var propValue string
139*90c8c64dSAndroid Build Coastguard Worker			if vl, ok := v.([]interface{}); ok {
140*90c8c64dSAndroid Build Coastguard Worker				var list []string
141*90c8c64dSAndroid Build Coastguard Worker				for _, s := range vl {
142*90c8c64dSAndroid Build Coastguard Worker					list = append(list, fmt.Sprintf("%v", s))
143*90c8c64dSAndroid Build Coastguard Worker				}
144*90c8c64dSAndroid Build Coastguard Worker				propValue = fmt.Sprintf("%s", strings.Join(list, " "))
145*90c8c64dSAndroid Build Coastguard Worker			} else {
146*90c8c64dSAndroid Build Coastguard Worker				propValue = fmt.Sprintf("%v", v)
147*90c8c64dSAndroid Build Coastguard Worker			}
148*90c8c64dSAndroid Build Coastguard Worker			key := name + ":" + quoteBashString(k)
149*90c8c64dSAndroid Build Coastguard Worker			fmt.Fprintf(w, "MODULE_PROP_VALUES_DICT[%q]=%q\n", key, quoteBashString(propValue))
150*90c8c64dSAndroid Build Coastguard Worker		}
151*90c8c64dSAndroid Build Coastguard Worker		fmt.Fprintf(w, "\n")
152*90c8c64dSAndroid Build Coastguard Worker	}
153*90c8c64dSAndroid Build Coastguard Worker	fmt.Fprintf(w, "MODULE_NAMES=(\n")
154*90c8c64dSAndroid Build Coastguard Worker	for _, name := range moduleNameList {
155*90c8c64dSAndroid Build Coastguard Worker		fmt.Fprintf(w, "  %q\n", name)
156*90c8c64dSAndroid Build Coastguard Worker	}
157*90c8c64dSAndroid Build Coastguard Worker	fmt.Fprintf(w, ")\n")
158*90c8c64dSAndroid Build Coastguard Worker}
159*90c8c64dSAndroid Build Coastguard Worker
160*90c8c64dSAndroid Build Coastguard Workervar (
161*90c8c64dSAndroid Build Coastguard Worker	outputBashFlag = flag.Bool("bash", false, "Output in bash format")
162*90c8c64dSAndroid Build Coastguard Worker	outputJsonFlag = flag.Bool("json", false, "Output in json format (this is the default)")
163*90c8c64dSAndroid Build Coastguard Worker	helpFlag = flag.Bool("help", false, "Display this message and exit")
164*90c8c64dSAndroid Build Coastguard Worker	exitCode = 0
165*90c8c64dSAndroid Build Coastguard Worker)
166*90c8c64dSAndroid Build Coastguard Worker
167*90c8c64dSAndroid Build Coastguard Workerfunc init() {
168*90c8c64dSAndroid Build Coastguard Worker	flag.Usage = usage
169*90c8c64dSAndroid Build Coastguard Worker}
170*90c8c64dSAndroid Build Coastguard Worker
171*90c8c64dSAndroid Build Coastguard Workerfunc usage() {
172*90c8c64dSAndroid Build Coastguard Worker	fmt.Fprintf(os.Stderr, "Usage: %s [OPTION]... [FILE]...\n", os.Args[0])
173*90c8c64dSAndroid Build Coastguard Worker	fmt.Fprintf(os.Stderr, "Flatten Android.bp to python friendly json text.\n")
174*90c8c64dSAndroid Build Coastguard Worker	fmt.Fprintf(os.Stderr, "If no file list is specified, read from standard input.\n")
175*90c8c64dSAndroid Build Coastguard Worker	fmt.Fprintf(os.Stderr, "\n")
176*90c8c64dSAndroid Build Coastguard Worker	flag.PrintDefaults()
177*90c8c64dSAndroid Build Coastguard Worker}
178*90c8c64dSAndroid Build Coastguard Worker
179*90c8c64dSAndroid Build Coastguard Workerfunc main() {
180*90c8c64dSAndroid Build Coastguard Worker	defer func() {
181*90c8c64dSAndroid Build Coastguard Worker		if err := recover(); err != nil {
182*90c8c64dSAndroid Build Coastguard Worker			fmt.Fprintf(os.Stderr, "error: %v\n", err)
183*90c8c64dSAndroid Build Coastguard Worker			exitCode = 1
184*90c8c64dSAndroid Build Coastguard Worker		}
185*90c8c64dSAndroid Build Coastguard Worker		os.Exit(exitCode)
186*90c8c64dSAndroid Build Coastguard Worker	}()
187*90c8c64dSAndroid Build Coastguard Worker
188*90c8c64dSAndroid Build Coastguard Worker	flag.Parse()
189*90c8c64dSAndroid Build Coastguard Worker
190*90c8c64dSAndroid Build Coastguard Worker	if *helpFlag {
191*90c8c64dSAndroid Build Coastguard Worker		usage()
192*90c8c64dSAndroid Build Coastguard Worker		return
193*90c8c64dSAndroid Build Coastguard Worker	}
194*90c8c64dSAndroid Build Coastguard Worker
195*90c8c64dSAndroid Build Coastguard Worker	flatModules := []FlatModule{}
196*90c8c64dSAndroid Build Coastguard Worker
197*90c8c64dSAndroid Build Coastguard Worker	if flag.NArg() == 0 {
198*90c8c64dSAndroid Build Coastguard Worker		if modules, err := processFile("<stdin>", os.Stdin); err != nil {
199*90c8c64dSAndroid Build Coastguard Worker			panic(err)
200*90c8c64dSAndroid Build Coastguard Worker		} else {
201*90c8c64dSAndroid Build Coastguard Worker			flatModules = append(flatModules, modules...)
202*90c8c64dSAndroid Build Coastguard Worker		}
203*90c8c64dSAndroid Build Coastguard Worker	}
204*90c8c64dSAndroid Build Coastguard Worker
205*90c8c64dSAndroid Build Coastguard Worker	for _, pathname := range flag.Args() {
206*90c8c64dSAndroid Build Coastguard Worker		switch fileInfo, err := os.Stat(pathname); {
207*90c8c64dSAndroid Build Coastguard Worker		case err != nil:
208*90c8c64dSAndroid Build Coastguard Worker			panic(err)
209*90c8c64dSAndroid Build Coastguard Worker		case fileInfo.IsDir():
210*90c8c64dSAndroid Build Coastguard Worker			panic(fmt.Errorf("%q is a directory", pathname))
211*90c8c64dSAndroid Build Coastguard Worker		default:
212*90c8c64dSAndroid Build Coastguard Worker			if modules, err := processFile(pathname, nil); err != nil {
213*90c8c64dSAndroid Build Coastguard Worker				panic(err)
214*90c8c64dSAndroid Build Coastguard Worker			} else {
215*90c8c64dSAndroid Build Coastguard Worker				flatModules = append(flatModules, modules...)
216*90c8c64dSAndroid Build Coastguard Worker			}
217*90c8c64dSAndroid Build Coastguard Worker		}
218*90c8c64dSAndroid Build Coastguard Worker	}
219*90c8c64dSAndroid Build Coastguard Worker
220*90c8c64dSAndroid Build Coastguard Worker	if *outputBashFlag {
221*90c8c64dSAndroid Build Coastguard Worker		printBash(flatModules, os.Stdout)
222*90c8c64dSAndroid Build Coastguard Worker	} else {
223*90c8c64dSAndroid Build Coastguard Worker		if b, err := json.MarshalIndent(flatModules, "", "  "); err != nil {
224*90c8c64dSAndroid Build Coastguard Worker			panic(err)
225*90c8c64dSAndroid Build Coastguard Worker		} else {
226*90c8c64dSAndroid Build Coastguard Worker			fmt.Printf("%s\n", b)
227*90c8c64dSAndroid Build Coastguard Worker		}
228*90c8c64dSAndroid Build Coastguard Worker	}
229*90c8c64dSAndroid Build Coastguard Worker}
230