xref: /openbsd/gnu/llvm/lldb/scripts/verify_api.py (revision dda28197)
1061da546Spatrick#!/usr/bin/env python
2061da546Spatrick
3061da546Spatrickimport subprocess
4061da546Spatrickimport optparse
5061da546Spatrickimport os
6061da546Spatrickimport os.path
7061da546Spatrickimport re
8061da546Spatrickimport sys
9061da546Spatrick
10061da546Spatrick
11061da546Spatrickdef extract_exe_symbol_names(arch, exe_path, match_str):
12061da546Spatrick    command = 'dsymutil --arch %s -s "%s" | grep "%s" | colrm 1 69' % (
13061da546Spatrick        arch, exe_path, match_str)
14061da546Spatrick    (command_exit_status, command_output) = subprocess.getstatusoutput(command)
15061da546Spatrick    if command_exit_status == 0:
16061da546Spatrick        if command_output:
17061da546Spatrick            return command_output[0:-1].split("'\n")
18061da546Spatrick        else:
19061da546Spatrick            print('error: command returned no output')
20061da546Spatrick    else:
21061da546Spatrick        print('error: command failed with exit status %i\n    command: %s' % (command_exit_status, command))
22061da546Spatrick    return list()
23061da546Spatrick
24061da546Spatrick
25061da546Spatrickdef verify_api(all_args):
26061da546Spatrick    '''Verify the API in the specified library is valid given one or more binaries.'''
27061da546Spatrick    usage = "usage: verify_api --library <path> [ --library <path> ...] executable1 [executable2 ...]"
28061da546Spatrick    description = '''Verify the API in the specified library is valid given one or more binaries.
29061da546Spatrick
30061da546Spatrick    Example:
31061da546Spatrick
32061da546Spatrick        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
33061da546Spatrick    '''
34061da546Spatrick    parser = optparse.OptionParser(
35061da546Spatrick        description=description,
36061da546Spatrick        prog='verify_api',
37061da546Spatrick        usage=usage)
38061da546Spatrick    parser.add_option(
39061da546Spatrick        '-v',
40061da546Spatrick        '--verbose',
41061da546Spatrick        action='store_true',
42061da546Spatrick        dest='verbose',
43061da546Spatrick        help='display verbose debug info',
44061da546Spatrick        default=False)
45061da546Spatrick    parser.add_option(
46061da546Spatrick        '-a',
47061da546Spatrick        '--arch',
48061da546Spatrick        type='string',
49061da546Spatrick        action='append',
50061da546Spatrick        dest='archs',
51*dda28197Spatrick        help='architecture to use when checking the api')
52061da546Spatrick    parser.add_option(
53061da546Spatrick        '-r',
54061da546Spatrick        '--api-regex',
55061da546Spatrick        type='string',
56061da546Spatrick        dest='api_regex_str',
57061da546Spatrick        help='Exclude any undefined symbols that do not match this regular expression when searching for missing APIs.')
58061da546Spatrick    parser.add_option(
59061da546Spatrick        '-l',
60061da546Spatrick        '--library',
61061da546Spatrick        type='string',
62061da546Spatrick        action='append',
63061da546Spatrick        dest='libraries',
64061da546Spatrick        help='Specify one or more libraries that will contain all needed APIs for the executables.')
65061da546Spatrick    (options, args) = parser.parse_args(all_args)
66061da546Spatrick
67061da546Spatrick    api_external_symbols = list()
68061da546Spatrick    if options.archs:
69061da546Spatrick        for arch in options.archs:
70061da546Spatrick            for library in options.libraries:
71061da546Spatrick                external_symbols = extract_exe_symbol_names(
72061da546Spatrick                    arch, library, "(     SECT EXT)")
73061da546Spatrick                if external_symbols:
74061da546Spatrick                    for external_symbol in external_symbols:
75061da546Spatrick                        api_external_symbols.append(external_symbol)
76061da546Spatrick                else:
77061da546Spatrick                    sys.exit(1)
78061da546Spatrick    else:
79061da546Spatrick        print('error: must specify one or more architectures with the --arch option')
80061da546Spatrick        sys.exit(4)
81061da546Spatrick    if options.verbose:
82061da546Spatrick        print("API symbols:")
83061da546Spatrick        for (i, external_symbol) in enumerate(api_external_symbols):
84061da546Spatrick            print("[%u] %s" % (i, external_symbol))
85061da546Spatrick
86061da546Spatrick    api_regex = None
87061da546Spatrick    if options.api_regex_str:
88061da546Spatrick        api_regex = re.compile(options.api_regex_str)
89061da546Spatrick
90061da546Spatrick    for arch in options.archs:
91061da546Spatrick        for exe_path in args:
92061da546Spatrick            print('Verifying (%s) "%s"...' % (arch, exe_path))
93061da546Spatrick            exe_errors = 0
94061da546Spatrick            undefined_symbols = extract_exe_symbol_names(
95061da546Spatrick                arch, exe_path, "(     UNDF EXT)")
96061da546Spatrick            for undefined_symbol in undefined_symbols:
97061da546Spatrick                if api_regex:
98061da546Spatrick                    match = api_regex.search(undefined_symbol)
99061da546Spatrick                    if not match:
100061da546Spatrick                        if options.verbose:
101061da546Spatrick                            print('ignoring symbol: %s' % (undefined_symbol))
102061da546Spatrick                        continue
103061da546Spatrick                if undefined_symbol in api_external_symbols:
104061da546Spatrick                    if options.verbose:
105061da546Spatrick                        print('verified symbol: %s' % (undefined_symbol))
106061da546Spatrick                else:
107061da546Spatrick                    print('missing symbol: %s' % (undefined_symbol))
108061da546Spatrick                    exe_errors += 1
109061da546Spatrick            if exe_errors:
110061da546Spatrick                print('error: missing %u API symbols from %s' % (exe_errors, options.libraries))
111061da546Spatrick            else:
112061da546Spatrick                print('success')
113061da546Spatrick
114061da546Spatrickif __name__ == '__main__':
115061da546Spatrick    verify_api(sys.argv[1:])
116