From 169eb664511ecd5f7dfa6f0cb9ea668000373d96 Mon Sep 17 00:00:00 2001 From: Dan Albert <danalbert@google.com> Date: Wed, 21 Jan 2015 16:42:02 -0800 Subject: [PATCH] Add ndk_missing_symbols.py. ndk_missing_symbols.py pulls libc.so and libm.so off a running device or emulator and shows the list of symbols that are in the current bionic that aren't available on the target. Change-Id: Ia92c315a6a0ce2e5c33db0b62c8fab41c08a4c31 --- libc/tools/check-symbols-glibc.py | 91 ++++++++++++------------------- libc/tools/ndk_missing_symbols.py | 44 +++++++++++++++ libc/tools/symbols.py | 74 +++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 55 deletions(-) create mode 100755 libc/tools/ndk_missing_symbols.py create mode 100644 libc/tools/symbols.py diff --git a/libc/tools/check-symbols-glibc.py b/libc/tools/check-symbols-glibc.py index 153b84036..2c352b2eb 100755 --- a/libc/tools/check-symbols-glibc.py +++ b/libc/tools/check-symbols-glibc.py @@ -1,11 +1,27 @@ -#!/usr/bin/python - +#!/usr/bin/env python2 +# +# Copyright (C) 2015 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. +# +# pylint: disable=bad-indentation,bad-continuation import glob import os import re -import subprocess import sys +import symbols + only_unwanted = False if len(sys.argv) > 1: if sys.argv[1] in ('-u', '--unwanted'): @@ -16,62 +32,18 @@ arch = re.sub(r'.*/linux-x86/([^/]+)/.*', r'\1', toolchain) if arch == 'aarch64': arch = 'arm64' -def GetSymbolsFromTxt(txt_file): - symbols = set() - f = open(txt_file, 'r') - for line in f.read().splitlines(): - symbols.add(line) - f.close() - return symbols - -def GetSymbolsFromSo(so_file): - # Example readelf output: - # 264: 0001623c 4 FUNC GLOBAL DEFAULT 8 cabsf - # 266: 00016244 4 FUNC GLOBAL DEFAULT 8 dremf - # 267: 00019018 4 OBJECT GLOBAL DEFAULT 11 __fe_dfl_env - # 268: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_dcmplt - - r = re.compile(r' +\d+: [0-9a-f]+ +\d+ (I?FUNC|OBJECT) +\S+ +\S+ +\d+ (\S+)') - - symbols = set() - - for line in subprocess.check_output(['readelf', '--dyn-syms', '-W', so_file]).split('\n'): - if ' HIDDEN ' in line or ' UND ' in line: - continue - m = r.match(line) - if m: - symbol = m.group(2) - symbol = re.sub('@.*', '', symbol) - symbols.add(symbol) - - return symbols - -def GetSymbolsFromAndroidSo(*files): - symbols = set() - for f in files: - symbols = symbols | GetSymbolsFromSo('%s/system/lib64/%s' % (os.environ['ANDROID_PRODUCT_OUT'], f)) - return symbols - -def GetSymbolsFromSystemSo(*files): - symbols = set() - for f in files: - f = glob.glob('/lib/x86_64-linux-gnu/%s' % f)[-1] - symbols = symbols | GetSymbolsFromSo(f) - return symbols - def MangleGlibcNameToBionic(name): if name in glibc_to_bionic_names: return glibc_to_bionic_names[name] return name -def GetNdkIgnored(): - global arch - symbols = set() +def GetNdkIgnored(arch): # pylint: disable=redefined-outer-name + ignored_symbols = set() files = glob.glob('%s/ndk/build/tools/unwanted-symbols/%s/*' % (os.getenv('ANDROID_BUILD_TOP'), arch)) for f in files: - symbols |= set(open(f, 'r').read().splitlines()) - return symbols + ignored_symbols |= set(open(f, 'r').read().splitlines()) + return ignored_symbols glibc_to_bionic_names = { '__res_init': 'res_init', @@ -81,10 +53,19 @@ glibc_to_bionic_names = { '__xpg_basename': '__gnu_basename', } -glibc = GetSymbolsFromSystemSo('libc.so.*', 'librt.so.*', 'libpthread.so.*', 'libresolv.so.*', 'libm.so.*', 'libutil.so.*') -bionic = GetSymbolsFromAndroidSo('libc.so', 'libm.so') -posix = GetSymbolsFromTxt(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'posix-2013.txt')) -ndk_ignored = GetNdkIgnored() +glibc = symbols.GetFromSystemSo([ + 'libc.so.*', + 'librt.so.*', + 'libpthread.so.*', + 'libresolv.so.*', + 'libm.so.*', + 'libutil.so.*', +]) + +bionic = symbols.GetFromAndroidSo(['libc.so', 'libm.so']) +this_dir = os.path.dirname(os.path.realpath(__file__)) +posix = symbols.GetFromTxt(os.path.join(this_dir, 'posix-2013.txt')) +ndk_ignored = GetNdkIgnored(arch) glibc = set(map(MangleGlibcNameToBionic, glibc)) diff --git a/libc/tools/ndk_missing_symbols.py b/libc/tools/ndk_missing_symbols.py new file mode 100755 index 000000000..7b22ca82b --- /dev/null +++ b/libc/tools/ndk_missing_symbols.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python2 +# +# Copyright (C) 2015 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. +# +import os +import subprocess +import tempfile + +import symbols + + +def adb_pull(src, dst): + with open(os.devnull, 'w') as devnull: + subprocess.check_call(['adb', 'pull', src, dst], + stdout=devnull, stderr=devnull) + + +def main(): + tmp_dir = tempfile.mkdtemp() + adb_pull('/system/lib/libc.so', tmp_dir) + adb_pull('/system/lib/libm.so', tmp_dir) + + current = symbols.GetFromAndroidSo(['libc.so', 'libm.so']) + device = (symbols.GetFromSo(os.path.join(tmp_dir, 'libc.so')) | + symbols.GetFromSo(os.path.join(tmp_dir, 'libm.so'))) + + for symbol in sorted(current - device): + print symbol + + +if __name__ == '__main__': + main() diff --git a/libc/tools/symbols.py b/libc/tools/symbols.py new file mode 100644 index 000000000..43454e491 --- /dev/null +++ b/libc/tools/symbols.py @@ -0,0 +1,74 @@ +# +# Copyright (C) 2015 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. +# +import glob +import os +import re +import subprocess + + +def GetFromTxt(txt_file): + symbols = set() + f = open(txt_file, 'r') + for line in f.read().splitlines(): + symbols.add(line) + f.close() + return symbols + + +def GetFromSo(so_file): + # pylint: disable=line-too-long + # Example readelf output: + # 264: 0001623c 4 FUNC GLOBAL DEFAULT 8 cabsf + # 266: 00016244 4 FUNC GLOBAL DEFAULT 8 dremf + # 267: 00019018 4 OBJECT GLOBAL DEFAULT 11 __fe_dfl_env + # 268: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_dcmplt + + r = re.compile( + r' +\d+: [0-9a-f]+ +\d+ (I?FUNC|OBJECT) +\S+ +\S+ +\d+ (\S+)') + + symbols = set() + + output = subprocess.check_output(['readelf', '--dyn-syms', '-W', so_file]) + for line in output.split('\n'): + if ' HIDDEN ' in line or ' UND ' in line: + continue + m = r.match(line) + if m: + symbol = m.group(2) + symbol = re.sub('@.*', '', symbol) + symbols.add(symbol) + + return symbols + + +def GetFromAndroidSo(files): + out_dir = os.environ['ANDROID_PRODUCT_OUT'] + lib_dir = os.path.join(out_dir, 'system/lib64') + if not os.path.isdir(lib_dir): + lib_dir = os.path.join(out_dir, 'system/lib') + + results = set() + for f in files: + results |= GetFromSo(os.path.join(lib_dir, f)) + return results + + +def GetFromSystemSo(files): + lib_dir = '/lib/x86_64-linux-gnu' + results = set() + for f in files: + results |= GetFromSo(glob.glob(os.path.join(lib_dir, f))[-1]) + return results