2320b02c7d
Change-Id: I3836b14a797c4a8d121c6d29d95791ac768257da
203 lines
4.6 KiB
Python
Executable File
203 lines
4.6 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',
|
|
'__xpg_basename': '__gnu_basename',
|
|
}
|
|
|
|
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',
|
|
])
|
|
# 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 | known)
|
|
for symbol in sorted((bionic - allowed_stuff).difference(glibc)):
|
|
if symbol in ndk_ignored:
|
|
symbol += '*'
|
|
print symbol
|
|
|
|
sys.exit(0)
|