| #!/usr/bin/env python2 | 
 | # | 
 | # Copyright (C) 2015 The Android Open Source Project | 
 | # | 
 | # Licensed under the Apache License, Version 2.0 (the 'License'); | 
 | # you may not use this file except in compliance with the License. | 
 | # You may obtain a copy of the License at | 
 | # | 
 | #      http://www.apache.org/licenses/LICENSE-2.0 | 
 | # | 
 | # Unless required by applicable law or agreed to in writing, software | 
 | # distributed under the License is distributed on an 'AS IS' BASIS, | 
 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | # See the License for the specific language governing permissions and | 
 | # limitations under the License. | 
 | # | 
 | # pylint: disable=bad-indentation,bad-continuation | 
 | import glob | 
 | import os | 
 | import re | 
 | import sys | 
 |  | 
 | import symbols | 
 |  | 
 | 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 MangleGlibcNameToBionic(name): | 
 |   if name in glibc_to_bionic_names: | 
 |     return glibc_to_bionic_names[name] | 
 |   return name | 
 |  | 
 | def GetNdkIgnored(arch):  # pylint: disable=redefined-outer-name | 
 |   ignored_symbols = set() | 
 |   files = glob.glob('%s/ndk/build/tools/unwanted-symbols/%s/*' % | 
 |                     (os.getenv('ANDROID_BUILD_TOP'), arch)) | 
 |   for f in files: | 
 |     ignored_symbols |= set(open(f, 'r').read().splitlines()) | 
 |   return ignored_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 = symbols.GetFromSystemSo([ | 
 |     'libc.so.*', | 
 |     'librt.so.*', | 
 |     'libpthread.so.*', | 
 |     'libresolv.so.*', | 
 |     'libm.so.*', | 
 |     'libutil.so.*', | 
 | ]) | 
 |  | 
 | bionic = symbols.GetFromAndroidSo(['libc.so', 'libm.so']) | 
 | this_dir = os.path.dirname(os.path.realpath(__file__)) | 
 | posix = symbols.GetFromTxt(os.path.join(this_dir, 'posix-2013.txt')) | 
 | ndk_ignored = GetNdkIgnored(arch) | 
 |  | 
 | 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) |