76212eeb53
Also scan NDK's unwanted symbols list (to show the things that we're exporting but the NDK isn't. Symbols hidden in the NDK will be marked with a *. Add a -u (--unwanted) flag to disable the first two printed groups (all symbols in bionic, all symbols in glibc). This is helpful when wanting to grep in the list of unwanted symbols. Finally, update the list of known differences between us and glibc. Change-Id: I6fdb4126823098430454763c391bd8cd369a75bb
220 lines
5 KiB
Python
Executable file
220 lines
5 KiB
Python
Executable file
#!/usr/bin/python
|
|
|
|
import glob
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
|
|
only_unwanted = False
|
|
if len(sys.argv) > 1:
|
|
if sys.argv[1] in ('-u', '--unwanted'):
|
|
only_unwanted = True
|
|
|
|
toolchain = os.environ['ANDROID_TOOLCHAIN']
|
|
arch = re.sub(r'.*/linux-x86/([^/]+)/.*', r'\1', toolchain)
|
|
if arch == 'aarch64':
|
|
arch = 'arm64'
|
|
|
|
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()
|
|
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
|
|
|
|
glibc_to_bionic_names = {
|
|
'__res_init': 'res_init',
|
|
'__res_mkquery': 'res_mkquery',
|
|
'__res_query': 'res_query',
|
|
'__res_search': 'res_search',
|
|
}
|
|
|
|
glibc = GetSymbolsFromSystemSo('libc.so.*', 'librt.so.*', 'libpthread.so.*', 'libresolv.so.*', 'libm.so.*')
|
|
bionic = GetSymbolsFromAndroidSo('libc.so', 'libm.so')
|
|
ndk_ignored = GetNdkIgnored()
|
|
|
|
glibc = map(MangleGlibcNameToBionic, glibc)
|
|
|
|
# bionic includes various BSD symbols to ease porting other BSD-licensed code.
|
|
bsd_stuff = set([
|
|
'basename_r',
|
|
'dirname_r',
|
|
'fgetln',
|
|
'fpurge',
|
|
'funopen',
|
|
'gamma_r',
|
|
'gammaf_r',
|
|
'getprogname',
|
|
'setprogname',
|
|
'strlcat',
|
|
'strlcpy',
|
|
'sys_signame',
|
|
'wcslcat',
|
|
'wcslcpy'
|
|
])
|
|
# Some symbols are part of the FORTIFY implementation.
|
|
FORTIFY_stuff = set([
|
|
'__FD_CLR_chk',
|
|
'__FD_ISSET_chk',
|
|
'__FD_SET_chk',
|
|
'__stack_chk_guard',
|
|
'__stpncpy_chk2',
|
|
'__strchr_chk',
|
|
'__strlcat_chk',
|
|
'__strlcpy_chk',
|
|
'__strlen_chk',
|
|
'__strncpy_chk2',
|
|
'__strrchr_chk',
|
|
'__umask_chk'
|
|
])
|
|
# Some symbols are used to implement public macros.
|
|
macro_stuff = set([
|
|
'__assert2',
|
|
'__errno',
|
|
'__fe_dfl_env',
|
|
'__get_h_errno',
|
|
'__fpclassifyd',
|
|
'__isfinite',
|
|
'__isfinitef',
|
|
'__isfinitel',
|
|
'__isnormal',
|
|
'__isnormalf',
|
|
'__isnormall',
|
|
'__sF',
|
|
'__pthread_cleanup_pop',
|
|
'__pthread_cleanup_push',
|
|
])
|
|
# bionic exposes various Linux features that glibc doesn't.
|
|
linux_stuff = set([
|
|
'getauxval',
|
|
'gettid',
|
|
'tgkill'
|
|
])
|
|
# Some standard stuff isn't yet in the versions of glibc we're using.
|
|
std_stuff = set([
|
|
'at_quick_exit',
|
|
'c16rtomb',
|
|
'c32rtomb',
|
|
'mbrtoc16',
|
|
'mbrtoc32',
|
|
])
|
|
# These have mangled names in glibc, with a macro taking the "obvious" name.
|
|
weird_stuff = set([
|
|
'fstat',
|
|
'fstat64',
|
|
'fstatat',
|
|
'fstatat64',
|
|
'isfinite',
|
|
'isfinitef',
|
|
'isfinitel',
|
|
'isnormal',
|
|
'isnormalf',
|
|
'isnormall',
|
|
'lstat',
|
|
'lstat64',
|
|
'mknod',
|
|
'mknodat',
|
|
'stat',
|
|
'stat64',
|
|
'optreset',
|
|
'sigsetjmp',
|
|
])
|
|
# These exist in glibc, but under slightly different names (generally one extra
|
|
# or one fewer _). TODO: check against glibc names.
|
|
libresolv_stuff = set([
|
|
'__res_send_setqhook',
|
|
'__res_send_setrhook',
|
|
'_resolv_flush_cache_for_net',
|
|
'_resolv_set_nameservers_for_net',
|
|
'dn_expand',
|
|
'nsdispatch',
|
|
])
|
|
# libstdc++ stuff we took over.
|
|
libstdcxx_stuff = set([
|
|
# new, delete, nothrow
|
|
'_ZSt7nothrow',
|
|
'_ZdaPv',
|
|
'_ZdaPvRKSt9nothrow_t',
|
|
'_ZdlPv',
|
|
'_ZdlPvRKSt9nothrow_t',
|
|
'_Znam',
|
|
'_ZnamRKSt9nothrow_t',
|
|
'_Znwm',
|
|
'_ZnwmRKSt9nothrow_t',
|
|
|
|
'__cxa_guard_abort',
|
|
'__cxa_guard_acquire',
|
|
'__cxa_guard_release',
|
|
'__cxa_pure_virtual',
|
|
])
|
|
# Implementation details we know we export (and can't get away from).
|
|
known = set([
|
|
'_ctype_',
|
|
'__libc_init',
|
|
])
|
|
|
|
if not only_unwanted:
|
|
print 'glibc:'
|
|
for symbol in sorted(glibc):
|
|
print symbol
|
|
|
|
print
|
|
print 'bionic:'
|
|
for symbol in sorted(bionic):
|
|
print symbol
|
|
|
|
print
|
|
print 'in bionic but not glibc:'
|
|
|
|
allowed_stuff = (bsd_stuff | FORTIFY_stuff | linux_stuff | macro_stuff |
|
|
std_stuff | weird_stuff | libresolv_stuff | libstdcxx_stuff |
|
|
known)
|
|
for symbol in sorted((bionic - allowed_stuff).difference(glibc)):
|
|
if symbol in ndk_ignored:
|
|
symbol += '*'
|
|
print symbol
|
|
|
|
sys.exit(0)
|