bionic/libc/tools/check-symbols-glibc.py
Elliott Hughes 0393221f47 Make the missing symbols script more useful.
If something's in POSIX, we don't need to show it in the glibc list.

If something's not implemented by glibc, we don't need to show it in the
POSIX list (because it's probably either a macro or obsolete).

Change-Id: Ied0f8d97d3fffb280c22e9cdf6782430d776c02f
2014-12-04 11:24:48 -08:00

222 lines
5.2 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 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()
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.*', '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 = set(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 glibc (but not posix) but not bionic:'
for symbol in sorted((glibc - posix).difference(bionic)):
print symbol
print
print 'in posix (and implemented in glibc) but not bionic:'
for symbol in sorted((posix.intersection(glibc)).difference(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)