1#!/usr/bin/env python3
2#
3# Copyright (C) 2015 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the 'License');
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an 'AS IS' BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17# pylint: disable=bad-indentation,bad-continuation
18import glob
19import os
20import re
21import sys
22
23import symbols
24
25only_unwanted = False
26if len(sys.argv) > 1:
27  if sys.argv[1] in ('-u', '--unwanted'):
28    only_unwanted = True
29
30toolchain = os.environ['ANDROID_TOOLCHAIN']
31arch = re.sub(r'.*/linux-x86/([^/]+)/.*', r'\1', toolchain)
32if arch == 'aarch64':
33  arch = 'arm64'
34
35def MangleGlibcNameToBionic(name):
36  if name in glibc_to_bionic_names:
37    return glibc_to_bionic_names[name]
38  return name
39
40def GetNdkIgnored(arch):  # pylint: disable=redefined-outer-name
41  ignored_symbols = set()
42  files = glob.glob('%s/ndk/build/tools/unwanted-symbols/%s/*' %
43                    (os.getenv('ANDROID_BUILD_TOP'), arch))
44  for f in files:
45    ignored_symbols |= set(open(f, 'r').read().splitlines())
46  return ignored_symbols
47
48glibc_to_bionic_names = {
49  '__res_init': 'res_init',
50  '__res_mkquery': 'res_mkquery',
51  '__res_query': 'res_query',
52  '__res_search': 'res_search',
53  '__xpg_basename': '__gnu_basename',
54}
55
56glibc = symbols.GetFromSystemSo([
57    'libc.so.*',
58    'librt.so.*',
59    'libpthread.so.*',
60    'libresolv.so.*',
61    'libm.so.*',
62    'libutil.so.*',
63])
64
65bionic = symbols.GetFromAndroidSo(['libc.so', 'libm.so'])
66this_dir = os.path.dirname(os.path.realpath(__file__))
67posix = symbols.GetFromTxt(os.path.join(this_dir, 'posix-2013.txt'))
68ndk_ignored = GetNdkIgnored(arch)
69
70glibc = set(map(MangleGlibcNameToBionic, glibc))
71
72# bionic includes various BSD symbols to ease porting other BSD-licensed code.
73bsd_stuff = set([
74  'arc4random',
75  'arc4random_buf',
76  'arc4random_uniform',
77  'basename_r',
78  'dirname_r',
79  'fgetln',
80  'fpurge',
81  'funopen',
82  'funopen64',
83  'gamma_r',
84  'gammaf_r',
85  'getprogname',
86  'setprogname',
87  'strlcat',
88  'strlcpy',
89  'sys_signame',
90  'wcslcat',
91  'wcslcpy',
92])
93# Some symbols are part of the FORTIFY implementation.
94FORTIFY_stuff = set([
95  '__FD_CLR_chk',
96  '__FD_ISSET_chk',
97  '__FD_SET_chk',
98  '__fwrite_chk',
99  '__memchr_chk',
100  '__memrchr_chk',
101  '__pwrite64_chk',
102  '__pwrite_chk',
103  '__sendto_chk',
104  '__stack_chk_guard',
105  '__stpncpy_chk2',
106  '__strchr_chk',
107  '__strlcat_chk',
108  '__strlcpy_chk',
109  '__strlen_chk',
110  '__strncpy_chk2',
111  '__strrchr_chk',
112  '__umask_chk',
113  '__write_chk',
114])
115# Some symbols are used to implement public functions/macros.
116macro_stuff = set([
117  '__assert2',
118  '__errno',
119  '__fe_dfl_env',
120  '__get_h_errno',
121  '__gnu_strerror_r',
122  '__fpclassifyd',
123  '__isfinite',
124  '__isfinitef',
125  '__isfinitel',
126  '__isnormal',
127  '__isnormalf',
128  '__isnormall',
129  '__sF',
130  '__pthread_cleanup_pop',
131  '__pthread_cleanup_push',
132])
133# bionic exposes various Linux features that glibc doesn't.
134linux_stuff = set([
135  'getauxval',
136  'gettid',
137  'pthread_gettid_np',
138  'tgkill',
139])
140# Some standard stuff isn't yet in the versions of glibc we're using.
141std_stuff = set([
142  'at_quick_exit',
143  'c16rtomb',
144  'c32rtomb',
145  'mbrtoc16',
146  'mbrtoc32',
147])
148# These have mangled names in glibc, with a macro taking the "obvious" name.
149weird_stuff = set([
150  'fstat',
151  'fstat64',
152  'fstatat',
153  'fstatat64',
154  'isfinite',
155  'isfinitef',
156  'isfinitel',
157  'isnormal',
158  'isnormalf',
159  'isnormall',
160  'lstat',
161  'lstat64',
162  'mknod',
163  'mknodat',
164  'stat',
165  'stat64',
166  'optreset',
167  'sigsetjmp',
168])
169# These exist in glibc, but under slightly different names (generally one extra
170# or one fewer _). TODO: check against glibc names.
171libresolv_stuff = set([
172  '__res_send_setqhook',
173  '__res_send_setrhook',
174  '_resolv_delete_cache_for_net',
175  '_resolv_flush_cache_for_net',
176  '_resolv_set_nameservers_for_net',
177  'dn_expand',
178  'nsdispatch',
179])
180# Implementation details we know we export (and can't get away from).
181known = set([
182  '_ctype_',
183  '__libc_init',
184])
185# POSIX has some stuff that's unusable in the modern world (a64l) or not
186# actually implemented in glibc unless you count always failing with ENOSYS
187# as being implemented (fattach). Other stuff (fmtmsg) isn't used in any
188# codebase I have access to, internal or external.
189in_posix_and_glibc_but_dead_or_useless = set([
190  'a64l', # obsolete
191  'confstr', # obsolete
192  'endutxent', # no utmp on Android
193  'fattach', # <stropts.h> marked obsolescent
194  'fdetach', # <stropts.h> marked obsolescent
195  'fmtmsg', # unused
196  'getdate', # unused
197  'getdate_err', # unused
198  'gethostid', # obsolete
199  'getmsg', # <stropts.h> marked obsolescent
200  'getpmsg', # <stropts.h> marked obsolescent
201  'getutxent', # no utmp on Android
202  'getutxid', # no utmp on Android
203  'getutxline', # no utmp on Android
204  'isastream', # <stropts.h> marked obsolescent
205  'l64a', # obsolete
206  'mq_close', # disallowed by SELinux
207  'mq_getattr', # disallowed by SELinux
208  'mq_notify', # disallowed by SELinux
209  'mq_open', # disallowed by SELinux
210  'mq_receive', # disallowed by SELinux
211  'mq_send', # disallowed by SELinux
212  'mq_setattr', # disallowed by SELinux
213  'mq_timedreceive', # disallowed by SELinux
214  'mq_timedsend', # disallowed by SELinux
215  'mq_unlink', # disallowed by SELinux
216  'pthread_getconcurrency', # marked obsolescent
217  'pthread_setconcurrency', # marked obsolescent
218  'putmsg', # <stropts.h> marked obsolescent
219  'putpmsg', # <stropts.h> marked obsolescent
220  'pututxline', # no utmp on Android
221  'shm_open', # disallowed by SELinux
222  'shm_unlink', # disallowed by SELinux
223  'setutxent', # no utmp on Android
224  'sockatmark', # obsolete (https://tools.ietf.org/html/rfc6093)
225  'strfmon', # icu4c
226  'strfmon_l', # icu4c
227  'ulimit', # <ulimit.h> marked obsolescent
228])
229
230posix = posix - in_posix_and_glibc_but_dead_or_useless
231glibc = glibc - in_posix_and_glibc_but_dead_or_useless
232
233if not only_unwanted:
234  #print('glibc:')
235  #for symbol in sorted(glibc):
236  #  print(symbol)
237  #print()
238
239  #print('bionic:')
240  #for symbol in sorted(bionic):
241  #  print(symbol)
242  #print()
243
244  print('in glibc (but not posix) but not bionic:')
245  for symbol in sorted((glibc - posix).difference(bionic)):
246    print(symbol)
247  print()
248
249  print('in posix (and implemented in glibc) but not bionic:')
250  for symbol in sorted((posix.intersection(glibc)).difference(bionic)):
251    print(symbol)
252  print()
253
254  print('in bionic but not glibc:')
255
256allowed_stuff = (bsd_stuff | FORTIFY_stuff | linux_stuff | macro_stuff |
257                 std_stuff | weird_stuff | libresolv_stuff | known)
258for symbol in sorted((bionic - allowed_stuff).difference(glibc)):
259  if symbol in ndk_ignored:
260    symbol += '*'
261  print(symbol)
262
263sys.exit(0)
264