• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2#
3# Copyright (C) 2016 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17"""Builds a database of symbol version introductions."""
18import argparse
19import json
20import logging
21import os
22
23
24THIS_DIR = os.path.realpath(os.path.dirname(__file__))
25
26
27ALL_ARCHITECTURES = (
28    'arm',
29    'arm64',
30    'mips',
31    'mips64',
32    'x86',
33    'x86_64',
34)
35
36
37def logger():
38    """Returns the default logger for this module."""
39    return logging.getLogger(__name__)
40
41
42def get_platform_versions():
43    """Returns a list of the platform versions we have data for."""
44    versions = []
45    platforms_dir = os.path.join(THIS_DIR, 'platforms')
46    logger().debug('Getting platform versions from %s', platforms_dir)
47    for name in os.listdir(platforms_dir):
48        if name.startswith('android-'):
49            versions.append(int(name.split('-')[1]))
50    return versions
51
52
53def add_symbols(symbols, symbol_file_path, version, arch, is_var):
54    """Adds symbols from a file to the symbol dict."""
55    with open(symbol_file_path) as symbol_file:
56        names = symbol_file.readlines()
57
58    for name in names:
59        name = name.strip()
60        if not name:
61            continue
62        introduced_tag = 'introduced-' + arch
63        if name in symbols:
64            assert symbols[name]['is_var'] == is_var
65            if introduced_tag in symbols[name]:
66                continue
67            symbols[name][introduced_tag] = version
68        else:
69            symbols[name] = {}
70            symbols[name]['is_var'] = is_var
71            symbols[name][introduced_tag] = version
72
73
74def build_symbol_db(lib_name):
75    """Returns a dict of symbols and their version information.
76
77    Args:
78        lib_name: Name of the library to return file mapping for.
79
80    Returns: dict of symbol information in the following format:
81        {
82            "symbol_name": {
83                "is_var": "true",
84                "introduced-arm": 9,
85                "introduced-x86": 14,
86                "introduced-mips": 16,
87                "introduced-arm64": 21,
88                "introduced-mips64": 21,
89                "introduced-x86_64": 21,
90            },
91            ...
92        }
93    """
94    symbols = {}
95    versions = sorted(get_platform_versions())
96    for version in versions:
97        for arch in ALL_ARCHITECTURES:
98            symbols_dir = os.path.join(
99                THIS_DIR, 'platforms', 'android-' + str(version),
100                'arch-' + arch, 'symbols')
101            if not os.path.exists(symbols_dir):
102                logger().debug('Skipping non-existent %s', symbols_dir)
103                continue
104
105            logger().info('Processing android-%d arch-%s', version, arch)
106
107            funcs_file_name = lib_name + '.so.functions.txt'
108            funcs_file = os.path.join(symbols_dir, funcs_file_name)
109            if os.path.exists(funcs_file):
110                add_symbols(symbols, funcs_file, version, arch, is_var='false')
111
112            vars_file_name = lib_name + '.so.variables.txt'
113            vars_file = os.path.join(symbols_dir, vars_file_name)
114            if os.path.exists(vars_file):
115                add_symbols(symbols, vars_file, version, arch, is_var='true')
116    return symbols
117
118
119def parse_args():
120    """Returns parsed command line arguments."""
121    parser = argparse.ArgumentParser()
122
123    parser.add_argument('-v', '--verbose', action='count', default=0)
124
125    parser.add_argument(
126        'library_name', metavar='LIBRARY_NAME',
127        help='Name of the library to create a database for.')
128
129    return parser.parse_args()
130
131
132def main():
133    """Program entry point."""
134    args = parse_args()
135    os.chdir(THIS_DIR)
136
137    verbose_map = (logging.WARNING, logging.INFO, logging.DEBUG)
138    verbosity = args.verbose
139    if verbosity > 2:
140        verbosity = 2
141    logging.basicConfig(level=verbose_map[verbosity])
142
143    symbol_db = build_symbol_db(args.library_name)
144    with open(args.library_name + '.so.json', 'w') as db_file:
145        json.dump(symbol_db, db_file, indent=4, separators=(',', ': '),
146                  sort_keys=True)
147
148
149if __name__ == '__main__':
150    main()
151