150 lines
4.5 KiB
Python
Executable file
150 lines
4.5 KiB
Python
Executable file
#!/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()
|