Home | History | Annotate | Download | only in tools
      1 #!/usr/bin/python
      2 
      3 import glob
      4 import os
      5 import re
      6 import string
      7 import subprocess
      8 import sys
      9 
     10 toolchain = os.environ['ANDROID_TOOLCHAIN']
     11 arch = re.sub(r'.*/linux-x86/([^/]+)/.*', r'\1', toolchain)
     12 
     13 sys.stderr.write('Checking symbols for arch "%s"...\n' % arch)
     14 
     15 def GetSymbols(library, functions_or_variables):
     16   global api
     17   global arch
     18 
     19   api = '9'
     20   if library == 'libm' and arch == 'arm':
     21     api = '3'
     22 
     23   # There were no 64-bit ABIs before API level 21.
     24   if '64' in arch:
     25     api = '21'
     26 
     27   # What GCC calls aarch64, Android calls arm64.
     28   if arch == 'aarch64':
     29     arch = 'arm64'
     30 
     31   path = '%s/development/ndk/platforms/android-%s/arch-%s/symbols/%s.so.%s.txt' % (os.environ['ANDROID_BUILD_TOP'], api, arch, library, functions_or_variables)
     32   symbols = set()
     33   for line in open(path, 'r'):
     34     symbols.add(line.rstrip())
     35   #sys.stdout.write('%d %s in %s for %s\n' % (len(symbols), functions_or_variables, library, arch))
     36   return symbols
     37 
     38 def CheckSymbols(library, functions_or_variables):
     39   expected_symbols = GetSymbols(library, functions_or_variables)
     40 
     41   lib_dir = 'lib'
     42   if '64' in arch:
     43     lib_dir = 'lib64'
     44 
     45   so_file = '%s/system/%s/%s.so' % (os.environ['ANDROID_PRODUCT_OUT'], lib_dir, library)
     46 
     47   # Example readelf output:
     48   #   264: 0001623c     4 FUNC    GLOBAL DEFAULT    8 cabsf
     49   #   266: 00016244     4 FUNC    GLOBAL DEFAULT    8 dremf
     50   #   267: 00019018     4 OBJECT  GLOBAL DEFAULT   11 __fe_dfl_env
     51   #   268: 00000000     0 FUNC    GLOBAL DEFAULT  UND __aeabi_dcmplt
     52 
     53 
     54   r = re.compile(r' +\d+: [0-9a-f]+ +\d+ (FUNC|OBJECT) +\S+ +\S+ +\d+ (\S+)')
     55 
     56   actual_symbols = set()
     57   for line in subprocess.check_output(['readelf', '-W', '--dyn-syms', so_file]).split('\n'):
     58     m = r.match(line)
     59     if m:
     60       symbol = string.split(m.group(2), '@')[0]
     61       if m.group(1) == 'FUNC' and functions_or_variables == 'functions':
     62         actual_symbols.add(symbol)
     63       elif m.group(1) == 'OBJECT' and functions_or_variables == 'variables':
     64         actual_symbols.add(symbol)
     65     #else:
     66       #print 'ignoring: ' % line
     67 
     68   missing = expected_symbols - actual_symbols
     69   if len(missing) > 0:
     70     sys.stderr.write('%d missing %s in %s for %s:\n' % (len(missing), functions_or_variables, library, arch))
     71     for miss in sorted(missing):
     72       sys.stderr.write('  %s\n' % miss)
     73 
     74   extra = actual_symbols - expected_symbols
     75   if len(extra) > 0:
     76     sys.stderr.write('%d extra %s in %s for %s:\n' % (len(extra), functions_or_variables, library, arch))
     77     for s in sorted(extra):
     78       sys.stderr.write('  %s\n' % s)
     79 
     80   return len(missing) == 0
     81 
     82 CheckSymbols("libc", "functions")
     83 CheckSymbols("libc", "variables")
     84 CheckSymbols("libm", "functions")
     85 CheckSymbols("libm", "variables")
     86 
     87 sys.exit(0)
     88