1 #!/usr/bin/python
3 import glob
4 import os
5 import re
6 import subprocess
7 import sys
9 only_unwanted = False
10 if len(sys.argv) > 1:
11 if sys.argv[1] in ('-u', '--unwanted'):
12 only_unwanted = True
14 toolchain = os.environ['ANDROID_TOOLCHAIN']
15 arch = re.sub(r'.*/linux-x86/([^/]+)/.*', r'\1', toolchain)
16 if arch == 'aarch64':
17 arch = 'arm64'
19 def GetSymbolsFromSo(so_file):
20 # Example readelf output:
21 # 264: 0001623c 4 FUNC GLOBAL DEFAULT 8 cabsf
22 # 266: 00016244 4 FUNC GLOBAL DEFAULT 8 dremf
23 # 267: 00019018 4 OBJECT GLOBAL DEFAULT 11 __fe_dfl_env
24 # 268: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_dcmplt
26 r = re.compile(r' +\d+: [0-9a-f]+ +\d+ (I?FUNC|OBJECT) +\S+ +\S+ +\d+ (\S+)')
28 symbols = set()
30 for line in subprocess.check_output(['readelf', '--dyn-syms', '-W', so_file]).split('\n'):
31 if ' HIDDEN ' in line or ' UND ' in line:
32 continue
33 m = r.match(line)
34 if m:
35 symbol = m.group(2)
36 symbol = re.sub('@.*', '', symbol)
37 symbols.add(symbol)
39 return symbols
41 def GetSymbolsFromAndroidSo(*files):
42 symbols = set()
43 for f in files:
44 symbols = symbols | GetSymbolsFromSo('%s/system/lib64/%s' % (os.environ['ANDROID_PRODUCT_OUT'], f))
45 return symbols
47 def GetSymbolsFromSystemSo(*files):
48 symbols = set()
49 for f in files:
50 f = glob.glob('/lib/x86_64-linux-gnu/%s' % f)[-1]
51 symbols = symbols | GetSymbolsFromSo(f)
52 return symbols
54 def MangleGlibcNameToBionic(name):
55 if name in glibc_to_bionic_names:
56 return glibc_to_bionic_names[name]
57 return name
59 def GetNdkIgnored():
60 global arch
61 symbols = set()
62 files = glob.glob('%s/ndk/build/tools/unwanted-symbols/%s/*' %
63 (os.getenv('ANDROID_BUILD_TOP'), arch))
64 for f in files:
65 symbols |= set(open(f, 'r').read().splitlines())
66 return symbols
68 glibc_to_bionic_names = {
69 '__res_init': 'res_init',
70 '__res_mkquery': 'res_mkquery',
71 '__res_query': 'res_query',
72 '__res_search': 'res_search',
73 }
75 glibc = GetSymbolsFromSystemSo('libc.so.*', 'librt.so.*', 'libpthread.so.*', 'libresolv.so.*', 'libm.so.*')
76 bionic = GetSymbolsFromAndroidSo('libc.so', 'libm.so')
77 ndk_ignored = GetNdkIgnored()
79 glibc = map(MangleGlibcNameToBionic, glibc)
81 # bionic includes various BSD symbols to ease porting other BSD-licensed code.
82 bsd_stuff = set([
83 'basename_r',
84 'dirname_r',
85 'fgetln',
86 'fpurge',
87 'funopen',
88 'gamma_r',
89 'gammaf_r',
90 'getprogname',
91 'setprogname',
92 'strlcat',
93 'strlcpy',
94 'sys_signame',
95 'wcslcat',
96 'wcslcpy'
97 ])
98 # Some symbols are part of the FORTIFY implementation.
99 FORTIFY_stuff = set([
100 '__FD_CLR_chk',
101 '__FD_ISSET_chk',
102 '__FD_SET_chk',
103 '__stack_chk_guard',
104 '__stpncpy_chk2',
105 '__strchr_chk',
106 '__strlcat_chk',
107 '__strlcpy_chk',
108 '__strlen_chk',
109 '__strncpy_chk2',
110 '__strrchr_chk',
111 '__umask_chk'
112 ])
113 # Some symbols are used to implement public macros.
114 macro_stuff = set([
115 '__assert2',
116 '__errno',
117 '__fe_dfl_env',
118 '__get_h_errno',
119 '__fpclassifyd',
120 '__isfinite',
121 '__isfinitef',
122 '__isfinitel',
123 '__isnormal',
124 '__isnormalf',
125 '__isnormall',
126 '__sF',
127 '__pthread_cleanup_pop',
128 '__pthread_cleanup_push',
129 ])
130 # bionic exposes various Linux features that glibc doesn't.
131 linux_stuff = set([
132 'getauxval',
133 'gettid',
134 'tgkill'
135 ])
136 # Some standard stuff isn't yet in the versions of glibc we're using.
137 std_stuff = set([
138 'at_quick_exit',
139 'c16rtomb',
140 'c32rtomb',
141 'mbrtoc16',
142 'mbrtoc32',
143 ])
144 # These have mangled names in glibc, with a macro taking the "obvious" name.
145 weird_stuff = set([
146 'fstat',
147 'fstat64',
148 'fstatat',
149 'fstatat64',
150 'isfinite',
151 'isfinitef',
152 'isfinitel',
153 'isnormal',
154 'isnormalf',
155 'isnormall',
156 'lstat',
157 'lstat64',
158 'mknod',
159 'mknodat',
160 'stat',
161 'stat64',
162 'optreset',
163 'sigsetjmp',
164 ])
165 # These exist in glibc, but under slightly different names (generally one extra
166 # or one fewer _). TODO: check against glibc names.
167 libresolv_stuff = set([
168 '__res_send_setqhook',
169 '__res_send_setrhook',
170 '_resolv_flush_cache_for_net',
171 '_resolv_set_nameservers_for_net',
172 'dn_expand',
173 'nsdispatch',
174 ])
175 # Implementation details we know we export (and can't get away from).
176 known = set([
177 '_ctype_',
178 '__libc_init',
179 ])
181 if not only_unwanted:
182 print 'glibc:'
183 for symbol in sorted(glibc):
184 print symbol
186 print
187 print 'bionic:'
188 for symbol in sorted(bionic):
189 print symbol
191 print
192 print 'in bionic but not glibc:'
194 allowed_stuff = (bsd_stuff | FORTIFY_stuff | linux_stuff | macro_stuff |
195 std_stuff | weird_stuff | libresolv_stuff | known)
196 for symbol in sorted((bionic - allowed_stuff).difference(glibc)):
197 if symbol in ndk_ignored:
198 symbol += '*'
199 print symbol
201 sys.exit(0)