Add ndk_missing_symbols.py.

ndk_missing_symbols.py pulls libc.so and libm.so off a running device
or emulator and shows the list of symbols that are in the current
bionic that aren't available on the target.

Change-Id: Ia92c315a6a0ce2e5c33db0b62c8fab41c08a4c31
diff --git a/libc/tools/check-symbols-glibc.py b/libc/tools/check-symbols-glibc.py
index 153b840..2c352b2 100755
--- a/libc/tools/check-symbols-glibc.py
+++ b/libc/tools/check-symbols-glibc.py
@@ -1,11 +1,27 @@
-#!/usr/bin/python
-
+#!/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 subprocess
 import sys
 
+import symbols
+
 only_unwanted = False
 if len(sys.argv) > 1:
   if sys.argv[1] in ('-u', '--unwanted'):
@@ -16,62 +32,18 @@
 if arch == 'aarch64':
   arch = 'arm64'
 
-def GetSymbolsFromTxt(txt_file):
-  symbols = set()
-  f = open(txt_file, 'r')
-  for line in f.read().splitlines():
-    symbols.add(line)
-  f.close()
-  return symbols
-
-def GetSymbolsFromSo(so_file):
-  # Example readelf output:
-  #   264: 0001623c     4 FUNC    GLOBAL DEFAULT    8 cabsf
-  #   266: 00016244     4 FUNC    GLOBAL DEFAULT    8 dremf
-  #   267: 00019018     4 OBJECT  GLOBAL DEFAULT   11 __fe_dfl_env
-  #   268: 00000000     0 FUNC    GLOBAL DEFAULT  UND __aeabi_dcmplt
-
-  r = re.compile(r' +\d+: [0-9a-f]+ +\d+ (I?FUNC|OBJECT) +\S+ +\S+ +\d+ (\S+)')
-
-  symbols = set()
-
-  for line in subprocess.check_output(['readelf', '--dyn-syms', '-W', so_file]).split('\n'):
-    if ' HIDDEN ' in line or ' UND ' in line:
-      continue
-    m = r.match(line)
-    if m:
-      symbol = m.group(2)
-      symbol = re.sub('@.*', '', symbol)
-      symbols.add(symbol)
-
-  return symbols
-
-def GetSymbolsFromAndroidSo(*files):
-  symbols = set()
-  for f in files:
-    symbols = symbols | GetSymbolsFromSo('%s/system/lib64/%s' % (os.environ['ANDROID_PRODUCT_OUT'], f))
-  return symbols
-
-def GetSymbolsFromSystemSo(*files):
-  symbols = set()
-  for f in files:
-    f = glob.glob('/lib/x86_64-linux-gnu/%s' % f)[-1]
-    symbols = symbols | GetSymbolsFromSo(f)
-  return symbols
-
 def MangleGlibcNameToBionic(name):
   if name in glibc_to_bionic_names:
     return glibc_to_bionic_names[name]
   return name
 
-def GetNdkIgnored():
-  global arch
-  symbols = set()
+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:
-    symbols |= set(open(f, 'r').read().splitlines())
-  return symbols
+    ignored_symbols |= set(open(f, 'r').read().splitlines())
+  return ignored_symbols
 
 glibc_to_bionic_names = {
   '__res_init': 'res_init',
@@ -81,10 +53,19 @@
   '__xpg_basename': '__gnu_basename',
 }
 
-glibc = GetSymbolsFromSystemSo('libc.so.*', 'librt.so.*', 'libpthread.so.*', 'libresolv.so.*', 'libm.so.*', 'libutil.so.*')
-bionic = GetSymbolsFromAndroidSo('libc.so', 'libm.so')
-posix = GetSymbolsFromTxt(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'posix-2013.txt'))
-ndk_ignored = GetNdkIgnored()
+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))