blob: e636cdda6498df8073e4e9a6fe3b8b909ec788c8 [file] [log] [blame]
Greg Clayton72935d32012-08-30 21:21:24 +00001#!/usr/bin/env python
2
3import commands
4import optparse
5import os
6import os.path
7import re
8import sys
9
10def extract_exe_symbol_names (arch, exe_path, match_str):
11 command = 'dsymutil --arch %s -s "%s" | grep "%s" | colrm 1 69' % (arch, exe_path, match_str)
12 (command_exit_status, command_output) = commands.getstatusoutput(command)
13 if command_exit_status == 0:
14 if command_output:
15 return command_output[0:-1].split("'\n")
16 else:
17 print 'error: command returned no output'
18 else:
19 print 'error: command failed with exit status %i\n command: %s' % (command_exit_status, command)
20 return list()
21
22def verify_api(all_args):
23 '''Verify the API in the specified library is valid given one or more binaries.'''
24 usage = "usage: verify_api --library <path> [ --library <path> ...] executable1 [executable2 ...]"
25 description='''Verify the API in the specified library is valid given one or more binaries.
26
27 Example:
28
29 verify_api.py --library ~/Documents/src/lldb/build/Debug/LLDB.framework/LLDB --arch x86_64 /Applications/Xcode.app/Contents/PlugIns/DebuggerLLDB.ideplugin/Contents/MacOS/DebuggerLLDB --api-regex lldb
30 '''
31 parser = optparse.OptionParser(description=description, prog='verify_api',usage=usage)
32 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
33 parser.add_option('-a', '--arch', type='string', action='append', dest='archs', help='architecure to use when checking the api')
34 parser.add_option('-r', '--api-regex', type='string', dest='api_regex_str', help='Exclude any undefined symbols that do not match this regular expression when searching for missing APIs.')
35 parser.add_option('-l', '--library', type='string', action='append', dest='libraries', help='Specify one or more libraries that will contain all needed APIs for the executables.')
36 (options, args) = parser.parse_args(all_args)
37
38 api_external_symbols = list()
39 if options.archs:
40 for arch in options.archs:
41 for library in options.libraries:
42 external_symbols = extract_exe_symbol_names(arch, library, "( SECT EXT)");
43 if external_symbols:
44 for external_symbol in external_symbols:
45 api_external_symbols.append(external_symbol)
46 else:
47 sys.exit(1)
48 else:
49 print 'error: must specify one or more architectures with the --arch option'
50 sys.exit(4)
51 if options.verbose:
52 print "API symbols:"
53 for (i, external_symbol) in enumerate(api_external_symbols):
54 print "[%u] %s" % (i, external_symbol)
55
56 api_regex = None
57 if options.api_regex_str:
58 api_regex = re.compile(options.api_regex_str)
59
60 for arch in options.archs:
61 for exe_path in args:
62 print 'Verifying (%s) "%s"...' % (arch, exe_path)
63 exe_errors = 0
64 undefined_symbols = extract_exe_symbol_names(arch, exe_path, "( UNDF EXT)");
65 for undefined_symbol in undefined_symbols:
66 if api_regex:
67 match = api_regex.search(undefined_symbol)
68 if not match:
69 if options.verbose:
70 print 'ignoring symbol: %s' % (undefined_symbol)
71 continue
72 if undefined_symbol in api_external_symbols:
73 if options.verbose:
74 print 'verified symbol: %s' % (undefined_symbol)
75 else:
76 print 'missing symbol: %s' % (undefined_symbol)
77 exe_errors += 1
78 if exe_errors:
79 print 'error: missing %u API symbols from %s' % (exe_errors, options.libraries)
80 else:
81 print 'success'
82
83if __name__ == '__main__':
84 verify_api(sys.argv[1:])