blob: 00638f975d66feb26a943aa7a712b7c9cae73ebe [file] [log] [blame]
#!/usr/bin/env python
#
# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Builds a database of symbol version introductions."""
import argparse
import json
import logging
import os
THIS_DIR = os.path.realpath(os.path.dirname(__file__))
ALL_ARCHITECTURES = (
'arm',
'arm64',
'mips',
'mips64',
'x86',
'x86_64',
)
def logger():
"""Returns the default logger for this module."""
return logging.getLogger(__name__)
def get_platform_versions():
"""Returns a list of the platform versions we have data for."""
versions = []
platforms_dir = os.path.join(THIS_DIR, 'platforms')
logger().debug('Getting platform versions from %s', platforms_dir)
for name in os.listdir(platforms_dir):
if name.startswith('android-'):
versions.append(int(name.split('-')[1]))
return versions
def add_symbols(symbols, symbol_file_path, version, arch, is_var):
"""Adds symbols from a file to the symbol dict."""
with open(symbol_file_path) as symbol_file:
names = symbol_file.readlines()
for name in names:
name = name.strip()
if not name:
continue
introduced_tag = 'introduced-' + arch
if name in symbols:
assert symbols[name]['is_var'] == is_var
if introduced_tag in symbols[name]:
continue
symbols[name][introduced_tag] = version
else:
symbols[name] = {}
symbols[name]['is_var'] = is_var
symbols[name][introduced_tag] = version
def build_symbol_db(lib_name):
"""Returns a dict of symbols and their version information.
Args:
lib_name: Name of the library to return file mapping for.
Returns: dict of symbol information in the following format:
{
"symbol_name": {
"is_var": "true",
"introduced-arm": 9,
"introduced-x86": 14,
"introduced-mips": 16,
"introduced-arm64": 21,
"introduced-mips64": 21,
"introduced-x86_64": 21,
},
...
}
"""
symbols = {}
versions = sorted(get_platform_versions())
for version in versions:
for arch in ALL_ARCHITECTURES:
symbols_dir = os.path.join(
THIS_DIR, 'platforms', 'android-' + str(version),
'arch-' + arch, 'symbols')
if not os.path.exists(symbols_dir):
logger().debug('Skipping non-existent %s', symbols_dir)
continue
logger().info('Processing android-%d arch-%s', version, arch)
funcs_file_name = lib_name + '.so.functions.txt'
funcs_file = os.path.join(symbols_dir, funcs_file_name)
if os.path.exists(funcs_file):
add_symbols(symbols, funcs_file, version, arch, is_var='false')
vars_file_name = lib_name + '.so.variables.txt'
vars_file = os.path.join(symbols_dir, vars_file_name)
if os.path.exists(vars_file):
add_symbols(symbols, vars_file, version, arch, is_var='true')
return symbols
def parse_args():
"""Returns parsed command line arguments."""
parser = argparse.ArgumentParser()
parser.add_argument('-v', '--verbose', action='count', default=0)
parser.add_argument(
'library_name', metavar='LIBRARY_NAME',
help='Name of the library to create a database for.')
return parser.parse_args()
def main():
"""Program entry point."""
args = parse_args()
os.chdir(THIS_DIR)
verbose_map = (logging.WARNING, logging.INFO, logging.DEBUG)
verbosity = args.verbose
if verbosity > 2:
verbosity = 2
logging.basicConfig(level=verbose_map[verbosity])
symbol_db = build_symbol_db(args.library_name)
with open(args.library_name + '.so.json', 'w') as db_file:
json.dump(symbol_db, db_file, indent=4, separators=(',', ': '),
sort_keys=True)
if __name__ == '__main__':
main()