1#!/usr/bin/python
2
3import glob
4import os
5import re
6import string
7import subprocess
8import sys
9
10toolchain = os.environ['ANDROID_TOOLCHAIN']
11arch = re.sub(r'.*/linux-x86/([^/]+)/.*', r'\1', toolchain)
12
13sys.stderr.write('Checking symbols for arch "%s"...\n' % arch)
14
15def 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
38def 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
82CheckSymbols("libc", "functions")
83CheckSymbols("libc", "variables")
84CheckSymbols("libm", "functions")
85CheckSymbols("libm", "variables")
86
87sys.exit(0)
88