xref: /aosp_15_r20/external/boringssl/src/util/read_symbols.go (revision 8fb009dc861624b67b6cdb62ea21f0f22d0c584b)
1*8fb009dcSAndroid Build Coastguard Worker// Copyright (c) 2018, Google Inc.
2*8fb009dcSAndroid Build Coastguard Worker//
3*8fb009dcSAndroid Build Coastguard Worker// Permission to use, copy, modify, and/or distribute this software for any
4*8fb009dcSAndroid Build Coastguard Worker// purpose with or without fee is hereby granted, provided that the above
5*8fb009dcSAndroid Build Coastguard Worker// copyright notice and this permission notice appear in all copies.
6*8fb009dcSAndroid Build Coastguard Worker//
7*8fb009dcSAndroid Build Coastguard Worker// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8*8fb009dcSAndroid Build Coastguard Worker// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9*8fb009dcSAndroid Build Coastguard Worker// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10*8fb009dcSAndroid Build Coastguard Worker// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11*8fb009dcSAndroid Build Coastguard Worker// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12*8fb009dcSAndroid Build Coastguard Worker// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13*8fb009dcSAndroid Build Coastguard Worker// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14*8fb009dcSAndroid Build Coastguard Worker
15*8fb009dcSAndroid Build Coastguard Worker//go:build ignore
16*8fb009dcSAndroid Build Coastguard Worker
17*8fb009dcSAndroid Build Coastguard Worker// read_symbols scans one or more .a files and, for each object contained in
18*8fb009dcSAndroid Build Coastguard Worker// the .a files, reads the list of symbols in that object file.
19*8fb009dcSAndroid Build Coastguard Workerpackage main
20*8fb009dcSAndroid Build Coastguard Worker
21*8fb009dcSAndroid Build Coastguard Workerimport (
22*8fb009dcSAndroid Build Coastguard Worker	"bytes"
23*8fb009dcSAndroid Build Coastguard Worker	"debug/elf"
24*8fb009dcSAndroid Build Coastguard Worker	"debug/macho"
25*8fb009dcSAndroid Build Coastguard Worker	"debug/pe"
26*8fb009dcSAndroid Build Coastguard Worker	"flag"
27*8fb009dcSAndroid Build Coastguard Worker	"fmt"
28*8fb009dcSAndroid Build Coastguard Worker	"os"
29*8fb009dcSAndroid Build Coastguard Worker	"runtime"
30*8fb009dcSAndroid Build Coastguard Worker	"sort"
31*8fb009dcSAndroid Build Coastguard Worker	"strings"
32*8fb009dcSAndroid Build Coastguard Worker
33*8fb009dcSAndroid Build Coastguard Worker	"boringssl.googlesource.com/boringssl/util/ar"
34*8fb009dcSAndroid Build Coastguard Worker)
35*8fb009dcSAndroid Build Coastguard Worker
36*8fb009dcSAndroid Build Coastguard Workerconst (
37*8fb009dcSAndroid Build Coastguard Worker	ObjFileFormatELF   = "elf"
38*8fb009dcSAndroid Build Coastguard Worker	ObjFileFormatMachO = "macho"
39*8fb009dcSAndroid Build Coastguard Worker	ObjFileFormatPE    = "pe"
40*8fb009dcSAndroid Build Coastguard Worker)
41*8fb009dcSAndroid Build Coastguard Worker
42*8fb009dcSAndroid Build Coastguard Workervar (
43*8fb009dcSAndroid Build Coastguard Worker	outFlag       = flag.String("out", "-", "File to write output symbols")
44*8fb009dcSAndroid Build Coastguard Worker	objFileFormat = flag.String("obj-file-format", defaultObjFileFormat(runtime.GOOS), "Object file format to expect (options are elf, macho, pe)")
45*8fb009dcSAndroid Build Coastguard Worker)
46*8fb009dcSAndroid Build Coastguard Worker
47*8fb009dcSAndroid Build Coastguard Workerfunc defaultObjFileFormat(goos string) string {
48*8fb009dcSAndroid Build Coastguard Worker	switch goos {
49*8fb009dcSAndroid Build Coastguard Worker	case "linux":
50*8fb009dcSAndroid Build Coastguard Worker		return ObjFileFormatELF
51*8fb009dcSAndroid Build Coastguard Worker	case "darwin":
52*8fb009dcSAndroid Build Coastguard Worker		return ObjFileFormatMachO
53*8fb009dcSAndroid Build Coastguard Worker	case "windows":
54*8fb009dcSAndroid Build Coastguard Worker		return ObjFileFormatPE
55*8fb009dcSAndroid Build Coastguard Worker	default:
56*8fb009dcSAndroid Build Coastguard Worker		// By returning a value here rather than panicking, the user can still
57*8fb009dcSAndroid Build Coastguard Worker		// cross-compile from an unsupported platform to a supported platform by
58*8fb009dcSAndroid Build Coastguard Worker		// overriding this default with a flag. If the user doesn't provide the
59*8fb009dcSAndroid Build Coastguard Worker		// flag, we will panic during flag parsing.
60*8fb009dcSAndroid Build Coastguard Worker		return "unsupported"
61*8fb009dcSAndroid Build Coastguard Worker	}
62*8fb009dcSAndroid Build Coastguard Worker}
63*8fb009dcSAndroid Build Coastguard Worker
64*8fb009dcSAndroid Build Coastguard Workerfunc printAndExit(format string, args ...any) {
65*8fb009dcSAndroid Build Coastguard Worker	s := fmt.Sprintf(format, args...)
66*8fb009dcSAndroid Build Coastguard Worker	fmt.Fprintln(os.Stderr, s)
67*8fb009dcSAndroid Build Coastguard Worker	os.Exit(1)
68*8fb009dcSAndroid Build Coastguard Worker}
69*8fb009dcSAndroid Build Coastguard Worker
70*8fb009dcSAndroid Build Coastguard Workerfunc main() {
71*8fb009dcSAndroid Build Coastguard Worker	flag.Parse()
72*8fb009dcSAndroid Build Coastguard Worker	if flag.NArg() < 1 {
73*8fb009dcSAndroid Build Coastguard Worker		printAndExit("Usage: %s [-out OUT] [-obj-file-format FORMAT] ARCHIVE_FILE [ARCHIVE_FILE [...]]", os.Args[0])
74*8fb009dcSAndroid Build Coastguard Worker	}
75*8fb009dcSAndroid Build Coastguard Worker	archiveFiles := flag.Args()
76*8fb009dcSAndroid Build Coastguard Worker
77*8fb009dcSAndroid Build Coastguard Worker	out := os.Stdout
78*8fb009dcSAndroid Build Coastguard Worker	if *outFlag != "-" {
79*8fb009dcSAndroid Build Coastguard Worker		var err error
80*8fb009dcSAndroid Build Coastguard Worker		out, err = os.Create(*outFlag)
81*8fb009dcSAndroid Build Coastguard Worker		if err != nil {
82*8fb009dcSAndroid Build Coastguard Worker			printAndExit("Error opening %q: %s", *outFlag, err)
83*8fb009dcSAndroid Build Coastguard Worker		}
84*8fb009dcSAndroid Build Coastguard Worker		defer out.Close()
85*8fb009dcSAndroid Build Coastguard Worker	}
86*8fb009dcSAndroid Build Coastguard Worker
87*8fb009dcSAndroid Build Coastguard Worker	var symbols []string
88*8fb009dcSAndroid Build Coastguard Worker	// Only add first instance of any symbol; keep track of them in this map.
89*8fb009dcSAndroid Build Coastguard Worker	added := make(map[string]struct{})
90*8fb009dcSAndroid Build Coastguard Worker	for _, archive := range archiveFiles {
91*8fb009dcSAndroid Build Coastguard Worker		f, err := os.Open(archive)
92*8fb009dcSAndroid Build Coastguard Worker		if err != nil {
93*8fb009dcSAndroid Build Coastguard Worker			printAndExit("Error opening %s: %s", archive, err)
94*8fb009dcSAndroid Build Coastguard Worker		}
95*8fb009dcSAndroid Build Coastguard Worker		objectFiles, err := ar.ParseAR(f)
96*8fb009dcSAndroid Build Coastguard Worker		f.Close()
97*8fb009dcSAndroid Build Coastguard Worker		if err != nil {
98*8fb009dcSAndroid Build Coastguard Worker			printAndExit("Error parsing %s: %s", archive, err)
99*8fb009dcSAndroid Build Coastguard Worker		}
100*8fb009dcSAndroid Build Coastguard Worker
101*8fb009dcSAndroid Build Coastguard Worker		for name, contents := range objectFiles {
102*8fb009dcSAndroid Build Coastguard Worker			syms, err := listSymbols(contents)
103*8fb009dcSAndroid Build Coastguard Worker			if err != nil {
104*8fb009dcSAndroid Build Coastguard Worker				printAndExit("Error listing symbols from %q in %q: %s", name, archive, err)
105*8fb009dcSAndroid Build Coastguard Worker			}
106*8fb009dcSAndroid Build Coastguard Worker			for _, s := range syms {
107*8fb009dcSAndroid Build Coastguard Worker				if _, ok := added[s]; !ok {
108*8fb009dcSAndroid Build Coastguard Worker					added[s] = struct{}{}
109*8fb009dcSAndroid Build Coastguard Worker					symbols = append(symbols, s)
110*8fb009dcSAndroid Build Coastguard Worker				}
111*8fb009dcSAndroid Build Coastguard Worker			}
112*8fb009dcSAndroid Build Coastguard Worker		}
113*8fb009dcSAndroid Build Coastguard Worker	}
114*8fb009dcSAndroid Build Coastguard Worker
115*8fb009dcSAndroid Build Coastguard Worker	sort.Strings(symbols)
116*8fb009dcSAndroid Build Coastguard Worker	for _, s := range symbols {
117*8fb009dcSAndroid Build Coastguard Worker		var skipSymbols = []string{
118*8fb009dcSAndroid Build Coastguard Worker			// Inline functions, etc., from the compiler or language
119*8fb009dcSAndroid Build Coastguard Worker			// runtime will naturally end up in the library, to be
120*8fb009dcSAndroid Build Coastguard Worker			// deduplicated against other object files. Such symbols
121*8fb009dcSAndroid Build Coastguard Worker			// should not be prefixed. It is a limitation of this
122*8fb009dcSAndroid Build Coastguard Worker			// symbol-prefixing strategy that we cannot distinguish
123*8fb009dcSAndroid Build Coastguard Worker			// our own inline symbols (which should be prefixed)
124*8fb009dcSAndroid Build Coastguard Worker			// from the system's (which should not), so we skip known
125*8fb009dcSAndroid Build Coastguard Worker			// system symbols.
126*8fb009dcSAndroid Build Coastguard Worker			"__local_stdio_printf_options",
127*8fb009dcSAndroid Build Coastguard Worker			"__local_stdio_scanf_options",
128*8fb009dcSAndroid Build Coastguard Worker			"_vscprintf",
129*8fb009dcSAndroid Build Coastguard Worker			"_vscprintf_l",
130*8fb009dcSAndroid Build Coastguard Worker			"_vsscanf_l",
131*8fb009dcSAndroid Build Coastguard Worker			"_xmm",
132*8fb009dcSAndroid Build Coastguard Worker			"sscanf",
133*8fb009dcSAndroid Build Coastguard Worker			"vsnprintf",
134*8fb009dcSAndroid Build Coastguard Worker			// sdallocx is a weak symbol and intended to merge with
135*8fb009dcSAndroid Build Coastguard Worker			// the real one, if present.
136*8fb009dcSAndroid Build Coastguard Worker			"sdallocx",
137*8fb009dcSAndroid Build Coastguard Worker		}
138*8fb009dcSAndroid Build Coastguard Worker		var skip bool
139*8fb009dcSAndroid Build Coastguard Worker		for _, sym := range skipSymbols {
140*8fb009dcSAndroid Build Coastguard Worker			if sym == s {
141*8fb009dcSAndroid Build Coastguard Worker				skip = true
142*8fb009dcSAndroid Build Coastguard Worker				break
143*8fb009dcSAndroid Build Coastguard Worker			}
144*8fb009dcSAndroid Build Coastguard Worker		}
145*8fb009dcSAndroid Build Coastguard Worker		if skip || isCXXSymbol(s) || strings.HasPrefix(s, "__real@") || strings.HasPrefix(s, "__x86.get_pc_thunk.") || strings.HasPrefix(s, "DW.") {
146*8fb009dcSAndroid Build Coastguard Worker			continue
147*8fb009dcSAndroid Build Coastguard Worker		}
148*8fb009dcSAndroid Build Coastguard Worker		if _, err := fmt.Fprintln(out, s); err != nil {
149*8fb009dcSAndroid Build Coastguard Worker			printAndExit("Error writing to %s: %s", *outFlag, err)
150*8fb009dcSAndroid Build Coastguard Worker		}
151*8fb009dcSAndroid Build Coastguard Worker	}
152*8fb009dcSAndroid Build Coastguard Worker}
153*8fb009dcSAndroid Build Coastguard Worker
154*8fb009dcSAndroid Build Coastguard Workerfunc isCXXSymbol(s string) bool {
155*8fb009dcSAndroid Build Coastguard Worker	if *objFileFormat == ObjFileFormatPE {
156*8fb009dcSAndroid Build Coastguard Worker		return strings.HasPrefix(s, "?")
157*8fb009dcSAndroid Build Coastguard Worker	}
158*8fb009dcSAndroid Build Coastguard Worker	return strings.HasPrefix(s, "_Z")
159*8fb009dcSAndroid Build Coastguard Worker}
160*8fb009dcSAndroid Build Coastguard Worker
161*8fb009dcSAndroid Build Coastguard Worker// listSymbols lists the exported symbols from an object file.
162*8fb009dcSAndroid Build Coastguard Workerfunc listSymbols(contents []byte) ([]string, error) {
163*8fb009dcSAndroid Build Coastguard Worker	switch *objFileFormat {
164*8fb009dcSAndroid Build Coastguard Worker	case ObjFileFormatELF:
165*8fb009dcSAndroid Build Coastguard Worker		return listSymbolsELF(contents)
166*8fb009dcSAndroid Build Coastguard Worker	case ObjFileFormatMachO:
167*8fb009dcSAndroid Build Coastguard Worker		return listSymbolsMachO(contents)
168*8fb009dcSAndroid Build Coastguard Worker	case ObjFileFormatPE:
169*8fb009dcSAndroid Build Coastguard Worker		return listSymbolsPE(contents)
170*8fb009dcSAndroid Build Coastguard Worker	default:
171*8fb009dcSAndroid Build Coastguard Worker		return nil, fmt.Errorf("unsupported object file format %q", *objFileFormat)
172*8fb009dcSAndroid Build Coastguard Worker	}
173*8fb009dcSAndroid Build Coastguard Worker}
174*8fb009dcSAndroid Build Coastguard Worker
175*8fb009dcSAndroid Build Coastguard Workerfunc listSymbolsELF(contents []byte) ([]string, error) {
176*8fb009dcSAndroid Build Coastguard Worker	f, err := elf.NewFile(bytes.NewReader(contents))
177*8fb009dcSAndroid Build Coastguard Worker	if err != nil {
178*8fb009dcSAndroid Build Coastguard Worker		return nil, err
179*8fb009dcSAndroid Build Coastguard Worker	}
180*8fb009dcSAndroid Build Coastguard Worker	syms, err := f.Symbols()
181*8fb009dcSAndroid Build Coastguard Worker	if err == elf.ErrNoSymbols {
182*8fb009dcSAndroid Build Coastguard Worker		return nil, nil
183*8fb009dcSAndroid Build Coastguard Worker	}
184*8fb009dcSAndroid Build Coastguard Worker	if err != nil {
185*8fb009dcSAndroid Build Coastguard Worker		return nil, err
186*8fb009dcSAndroid Build Coastguard Worker	}
187*8fb009dcSAndroid Build Coastguard Worker
188*8fb009dcSAndroid Build Coastguard Worker	var names []string
189*8fb009dcSAndroid Build Coastguard Worker	for _, sym := range syms {
190*8fb009dcSAndroid Build Coastguard Worker		// Only include exported, defined symbols
191*8fb009dcSAndroid Build Coastguard Worker		if elf.ST_BIND(sym.Info) != elf.STB_LOCAL && sym.Section != elf.SHN_UNDEF {
192*8fb009dcSAndroid Build Coastguard Worker			names = append(names, sym.Name)
193*8fb009dcSAndroid Build Coastguard Worker		}
194*8fb009dcSAndroid Build Coastguard Worker	}
195*8fb009dcSAndroid Build Coastguard Worker	return names, nil
196*8fb009dcSAndroid Build Coastguard Worker}
197*8fb009dcSAndroid Build Coastguard Worker
198*8fb009dcSAndroid Build Coastguard Workerfunc listSymbolsMachO(contents []byte) ([]string, error) {
199*8fb009dcSAndroid Build Coastguard Worker	f, err := macho.NewFile(bytes.NewReader(contents))
200*8fb009dcSAndroid Build Coastguard Worker	if err != nil {
201*8fb009dcSAndroid Build Coastguard Worker		return nil, err
202*8fb009dcSAndroid Build Coastguard Worker	}
203*8fb009dcSAndroid Build Coastguard Worker	if f.Symtab == nil {
204*8fb009dcSAndroid Build Coastguard Worker		return nil, nil
205*8fb009dcSAndroid Build Coastguard Worker	}
206*8fb009dcSAndroid Build Coastguard Worker	var names []string
207*8fb009dcSAndroid Build Coastguard Worker	for _, sym := range f.Symtab.Syms {
208*8fb009dcSAndroid Build Coastguard Worker		// Source: https://opensource.apple.com/source/xnu/xnu-3789.51.2/EXTERNAL_HEADERS/mach-o/nlist.h.auto.html
209*8fb009dcSAndroid Build Coastguard Worker		const (
210*8fb009dcSAndroid Build Coastguard Worker			N_PEXT uint8 = 0x10 // Private external symbol bit
211*8fb009dcSAndroid Build Coastguard Worker			N_EXT  uint8 = 0x01 // External symbol bit, set for external symbols
212*8fb009dcSAndroid Build Coastguard Worker			N_TYPE uint8 = 0x0e // mask for the type bits
213*8fb009dcSAndroid Build Coastguard Worker
214*8fb009dcSAndroid Build Coastguard Worker			N_UNDF uint8 = 0x0 // undefined, n_sect == NO_SECT
215*8fb009dcSAndroid Build Coastguard Worker			N_ABS  uint8 = 0x2 // absolute, n_sect == NO_SECT
216*8fb009dcSAndroid Build Coastguard Worker			N_SECT uint8 = 0xe // defined in section number n_sect
217*8fb009dcSAndroid Build Coastguard Worker			N_PBUD uint8 = 0xc // prebound undefined (defined in a dylib)
218*8fb009dcSAndroid Build Coastguard Worker			N_INDR uint8 = 0xa // indirect
219*8fb009dcSAndroid Build Coastguard Worker		)
220*8fb009dcSAndroid Build Coastguard Worker
221*8fb009dcSAndroid Build Coastguard Worker		// Only include exported, defined symbols.
222*8fb009dcSAndroid Build Coastguard Worker		if sym.Type&N_EXT != 0 && sym.Type&N_TYPE != N_UNDF {
223*8fb009dcSAndroid Build Coastguard Worker			if len(sym.Name) == 0 || sym.Name[0] != '_' {
224*8fb009dcSAndroid Build Coastguard Worker				return nil, fmt.Errorf("unexpected symbol without underscore prefix: %q", sym.Name)
225*8fb009dcSAndroid Build Coastguard Worker			}
226*8fb009dcSAndroid Build Coastguard Worker			names = append(names, sym.Name[1:])
227*8fb009dcSAndroid Build Coastguard Worker		}
228*8fb009dcSAndroid Build Coastguard Worker	}
229*8fb009dcSAndroid Build Coastguard Worker	return names, nil
230*8fb009dcSAndroid Build Coastguard Worker}
231*8fb009dcSAndroid Build Coastguard Worker
232*8fb009dcSAndroid Build Coastguard Workerfunc listSymbolsPE(contents []byte) ([]string, error) {
233*8fb009dcSAndroid Build Coastguard Worker	f, err := pe.NewFile(bytes.NewReader(contents))
234*8fb009dcSAndroid Build Coastguard Worker	if err != nil {
235*8fb009dcSAndroid Build Coastguard Worker		return nil, err
236*8fb009dcSAndroid Build Coastguard Worker	}
237*8fb009dcSAndroid Build Coastguard Worker	var ret []string
238*8fb009dcSAndroid Build Coastguard Worker	for _, sym := range f.Symbols {
239*8fb009dcSAndroid Build Coastguard Worker		const (
240*8fb009dcSAndroid Build Coastguard Worker			// https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#section-number-values
241*8fb009dcSAndroid Build Coastguard Worker			IMAGE_SYM_UNDEFINED = 0
242*8fb009dcSAndroid Build Coastguard Worker			// https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#storage-class
243*8fb009dcSAndroid Build Coastguard Worker			IMAGE_SYM_CLASS_EXTERNAL = 2
244*8fb009dcSAndroid Build Coastguard Worker		)
245*8fb009dcSAndroid Build Coastguard Worker		if sym.SectionNumber != IMAGE_SYM_UNDEFINED && sym.StorageClass == IMAGE_SYM_CLASS_EXTERNAL {
246*8fb009dcSAndroid Build Coastguard Worker			name := sym.Name
247*8fb009dcSAndroid Build Coastguard Worker			if f.Machine == pe.IMAGE_FILE_MACHINE_I386 {
248*8fb009dcSAndroid Build Coastguard Worker				// On 32-bit Windows, C symbols are decorated by calling
249*8fb009dcSAndroid Build Coastguard Worker				// convention.
250*8fb009dcSAndroid Build Coastguard Worker				// https://msdn.microsoft.com/en-us/library/56h2zst2.aspx#FormatC
251*8fb009dcSAndroid Build Coastguard Worker				if strings.HasPrefix(name, "_") || strings.HasPrefix(name, "@") {
252*8fb009dcSAndroid Build Coastguard Worker					// __cdecl, __stdcall, or __fastcall. Remove the prefix and
253*8fb009dcSAndroid Build Coastguard Worker					// suffix, if present.
254*8fb009dcSAndroid Build Coastguard Worker					name = name[1:]
255*8fb009dcSAndroid Build Coastguard Worker					if idx := strings.LastIndex(name, "@"); idx >= 0 {
256*8fb009dcSAndroid Build Coastguard Worker						name = name[:idx]
257*8fb009dcSAndroid Build Coastguard Worker					}
258*8fb009dcSAndroid Build Coastguard Worker				} else if idx := strings.LastIndex(name, "@@"); idx >= 0 {
259*8fb009dcSAndroid Build Coastguard Worker					// __vectorcall. Remove the suffix.
260*8fb009dcSAndroid Build Coastguard Worker					name = name[:idx]
261*8fb009dcSAndroid Build Coastguard Worker				}
262*8fb009dcSAndroid Build Coastguard Worker			}
263*8fb009dcSAndroid Build Coastguard Worker			ret = append(ret, name)
264*8fb009dcSAndroid Build Coastguard Worker		}
265*8fb009dcSAndroid Build Coastguard Worker	}
266*8fb009dcSAndroid Build Coastguard Worker	return ret, nil
267*8fb009dcSAndroid Build Coastguard Worker}
268