1 #!/usr/bin/python 2 3 import glob 4 import os 5 import re 6 import string 7 import subprocess 8 import sys 9 10 toolchain = os.environ['ANDROID_TOOLCHAIN'] 11 arch = re.sub(r'.*/linux-x86/([^/]+)/.*', r'\1', toolchain) 12 13 def GetSymbolsFromSo(so_file): 14 # Example readelf output: 15 # 264: 0001623c 4 FUNC GLOBAL DEFAULT 8 cabsf 16 # 266: 00016244 4 FUNC GLOBAL DEFAULT 8 dremf 17 # 267: 00019018 4 OBJECT GLOBAL DEFAULT 11 __fe_dfl_env 18 # 268: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_dcmplt 19 20 r = re.compile(r' +\d+: [0-9a-f]+ +\d+ (I?FUNC|OBJECT) +\S+ +\S+ +\d+ (\S+)') 21 22 symbols = set() 23 24 for line in subprocess.check_output(['readelf', '--dyn-syms', '-W', so_file]).split('\n'): 25 if ' HIDDEN ' in line or ' UND ' in line: 26 continue 27 m = r.match(line) 28 if m: 29 symbol = m.group(2) 30 symbol = re.sub('@.*', '', symbol) 31 symbols.add(symbol) 32 33 return symbols 34 35 def GetSymbolsFromAndroidSo(*files): 36 symbols = set() 37 for f in files: 38 symbols = symbols | GetSymbolsFromSo('%s/system/lib64/%s' % (os.environ['ANDROID_PRODUCT_OUT'], f)) 39 return symbols 40 41 def GetSymbolsFromSystemSo(*files): 42 symbols = set() 43 for f in files: 44 f = glob.glob('/lib/x86_64-linux-gnu/%s' % f)[-1] 45 symbols = symbols | GetSymbolsFromSo(f) 46 return symbols 47 48 def MangleGlibcNameToBionic(name): 49 if name in glibc_to_bionic_names: 50 return glibc_to_bionic_names[name] 51 return name 52 53 glibc_to_bionic_names = { 54 '__res_init': 'res_init', 55 '__res_mkquery': 'res_mkquery', 56 '__res_query': 'res_query', 57 '__res_search': 'res_search', 58 } 59 60 glibc = GetSymbolsFromSystemSo('libc.so.*', 'librt.so.*', 'libpthread.so.*', 'libresolv.so.*', 'libm.so.*') 61 bionic = GetSymbolsFromAndroidSo('libc.so', 'libm.so') 62 63 glibc = map(MangleGlibcNameToBionic, glibc) 64 65 # bionic includes various BSD symbols to ease porting other BSD-licensed code. 66 bsd_stuff = set([ 67 'basename_r', 68 'dirname_r', 69 'fgetln', 70 'fpurge', 71 'funopen', 72 'gamma_r', 73 'gammaf_r', 74 'getprogname', 75 'setprogname', 76 'strlcat', 77 'strlcpy', 78 'sys_signame', 79 'wcslcat', 80 'wcslcpy' 81 ]) 82 # Some symbols are part of the FORTIFY implementation. 83 FORTIFY_stuff = set([ 84 '__FD_CLR_chk', 85 '__FD_ISSET_chk', 86 '__FD_SET_chk', 87 '__stack_chk_guard', 88 '__stpncpy_chk2', 89 '__strchr_chk', 90 '__strlcat_chk', 91 '__strlcpy_chk', 92 '__strlen_chk', 93 '__strncpy_chk2', 94 '__strrchr_chk', 95 '__umask_chk' 96 ]) 97 # Some symbols are used to implement public macros. 98 macro_stuff = set([ 99 '__assert2', 100 '__errno', 101 '__fe_dfl_env', 102 '__get_h_errno', 103 ]) 104 # bionic exposes various Linux features that glibc doesn't. 105 linux_stuff = set([ 106 'getauxval', 107 'gettid', 108 'tgkill' 109 ]) 110 # Some standard stuff isn't yet in the versions of glibc we're using. 111 std_stuff = set([ 112 'at_quick_exit', 113 'c16rtomb', 114 'c32rtomb', 115 'mbrtoc16', 116 'mbrtoc32', 117 ]) 118 # These have mangled names in glibc, with a macro taking the "obvious" name. 119 weird_stuff = set([ 120 'fstat', 121 'fstat64', 122 'fstatat', 123 'fstatat64', 124 'isfinite', 125 'isfinitef', 126 'isfinitel', 127 'isnormal', 128 'isnormalf', 129 'isnormall', 130 'lstat', 131 'lstat64', 132 'mknod', 133 'mknodat', 134 'stat', 135 'stat64', 136 ]) 137 138 print 'glibc:' 139 for symbol in sorted(glibc): 140 print symbol 141 142 print 143 print 'bionic:' 144 for symbol in sorted(bionic): 145 print symbol 146 147 print 148 print 'in bionic but not glibc:' 149 allowed_stuff = (bsd_stuff | FORTIFY_stuff | linux_stuff | macro_stuff | std_stuff | weird_stuff) 150 for symbol in sorted((bionic - allowed_stuff).difference(glibc)): 151 print symbol 152 153 sys.exit(0) 154