1#!/usr/bin/env python2
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  '__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  '__write_chk',
113])
114# Some symbols are used to implement public macros.
115macro_stuff = set([
116  '__assert2',
117  '__errno',
118  '__fe_dfl_env',
119  '__get_h_errno',
120  '__fpclassifyd',
121  '__isfinite',
122  '__isfinitef',
123  '__isfinitel',
124  '__isnormal',
125  '__isnormalf',
126  '__isnormall',
127  '__sF',
128  '__pthread_cleanup_pop',
129  '__pthread_cleanup_push',
130])
131# bionic exposes various Linux features that glibc doesn't.
132linux_stuff = set([
133  'getauxval',
134  'gettid',
135  'tgkill'
136])
137# Some standard stuff isn't yet in the versions of glibc we're using.
138std_stuff = set([
139  'at_quick_exit',
140  'c16rtomb',
141  'c32rtomb',
142  'mbrtoc16',
143  'mbrtoc32',
144])
145# These have mangled names in glibc, with a macro taking the "obvious" name.
146weird_stuff = set([
147  'fstat',
148  'fstat64',
149  'fstatat',
150  'fstatat64',
151  'isfinite',
152  'isfinitef',
153  'isfinitel',
154  'isnormal',
155  'isnormalf',
156  'isnormall',
157  'lstat',
158  'lstat64',
159  'mknod',
160  'mknodat',
161  'stat',
162  'stat64',
163  'optreset',
164  'sigsetjmp',
165])
166# These exist in glibc, but under slightly different names (generally one extra
167# or one fewer _). TODO: check against glibc names.
168libresolv_stuff = set([
169  '__res_send_setqhook',
170  '__res_send_setrhook',
171  '_resolv_flush_cache_for_net',
172  '_resolv_set_nameservers_for_net',
173  'dn_expand',
174  'nsdispatch',
175])
176# Implementation details we know we export (and can't get away from).
177known = set([
178  '_ctype_',
179  '__libc_init',
180])
181
182if not only_unwanted:
183  #print 'glibc:'
184  #for symbol in sorted(glibc):
185  #  print symbol
186  #print
187
188  #print 'bionic:'
189  #for symbol in sorted(bionic):
190  #  print symbol
191  #print
192
193  print 'in glibc (but not posix) but not bionic:'
194  for symbol in sorted((glibc - posix).difference(bionic)):
195    print symbol
196  print
197
198  print 'in posix (and implemented in glibc) but not bionic:'
199  for symbol in sorted((posix.intersection(glibc)).difference(bionic)):
200    print symbol
201  print
202
203  print 'in bionic but not glibc:'
204
205allowed_stuff = (bsd_stuff | FORTIFY_stuff | linux_stuff | macro_stuff |
206                 std_stuff | weird_stuff | libresolv_stuff | known)
207for symbol in sorted((bionic - allowed_stuff).difference(glibc)):
208  if symbol in ndk_ignored:
209    symbol += '*'
210  print symbol
211
212sys.exit(0)
213