Home | History | Annotate | Download | only in scripts
      1 #!/usr/bin/env python
      2 #===- lib/sanitizer_common/scripts/gen_dynamic_list.py ---------------------===#
      3 #
      4 #                     The LLVM Compiler Infrastructure
      5 #
      6 # This file is distributed under the University of Illinois Open Source
      7 # License. See LICENSE.TXT for details.
      8 #
      9 #===------------------------------------------------------------------------===#
     10 #
     11 # Generates the list of functions that should be exported from sanitizer
     12 # runtimes. The output format is recognized by --dynamic-list linker option.
     13 # Usage:
     14 #   gen_dynamic_list.py libclang_rt.*san*.a [ files ... ]
     15 #
     16 #===------------------------------------------------------------------------===#
     17 import argparse
     18 import os
     19 import re
     20 import subprocess
     21 import sys
     22 
     23 new_delete = set([
     24                   '_Znam', '_ZnamRKSt9nothrow_t',    # operator new[](unsigned long)
     25                   '_Znwm', '_ZnwmRKSt9nothrow_t',    # operator new(unsigned long)
     26                   '_Znaj', '_ZnajRKSt9nothrow_t',    # operator new[](unsigned int)
     27                   '_Znwj', '_ZnwjRKSt9nothrow_t',    # operator new(unsigned int)
     28                   '_ZdaPv', '_ZdaPvRKSt9nothrow_t',  # operator delete[](void *)
     29                   '_ZdlPv', '_ZdlPvRKSt9nothrow_t',  # operator delete(void *)
     30                   '_ZdaPvm',                         # operator delete[](void*, unsigned long)
     31                   '_ZdlPvm',                         # operator delete(void*, unsigned long)
     32                   '_ZdaPvj',                         # operator delete[](void*, unsigned int)
     33                   '_ZdlPvj',                         # operator delete(void*, unsigned int)
     34                   ])
     35 
     36 versioned_functions = set(['memcpy', 'pthread_attr_getaffinity_np',
     37                            'pthread_cond_broadcast',
     38                            'pthread_cond_destroy', 'pthread_cond_init',
     39                            'pthread_cond_signal', 'pthread_cond_timedwait',
     40                            'pthread_cond_wait', 'realpath',
     41                            'sched_getaffinity'])
     42 
     43 def get_global_functions(library):
     44   functions = []
     45   nm_proc = subprocess.Popen(['nm', library], stdout=subprocess.PIPE,
     46                              stderr=subprocess.PIPE)
     47   nm_out = nm_proc.communicate()[0].decode().split('\n')
     48   if nm_proc.returncode != 0:
     49     raise subprocess.CalledProcessError(nm_proc.returncode, 'nm')
     50   func_symbols = ['T', 'W']
     51   # On PowerPC, nm prints function descriptors from .data section.
     52   if os.uname()[4] in ["powerpc", "ppc64"]:
     53     func_symbols += ['D']
     54   for line in nm_out:
     55     cols = line.split(' ')
     56     if len(cols) == 3 and cols[1] in func_symbols :
     57       functions.append(cols[2])
     58   return functions
     59 
     60 def main(argv):
     61   parser = argparse.ArgumentParser()
     62   parser.add_argument('--version-list', action='store_true')
     63   parser.add_argument('--extra', default=[], action='append')
     64   parser.add_argument('libraries', default=[], nargs='+')
     65   args = parser.parse_args()
     66 
     67   result = []
     68 
     69   all_functions = []
     70   for library in args.libraries:
     71     all_functions.extend(get_global_functions(library))
     72   function_set = set(all_functions)
     73   for func in all_functions:
     74     # Export new/delete operators.
     75     if func in new_delete:
     76       result.append(func)
     77       continue
     78     # Export interceptors.
     79     match = re.match('__interceptor_(.*)', func)
     80     if match:
     81       result.append(func)
     82       # We have to avoid exporting the interceptors for versioned library
     83       # functions due to gold internal error.
     84       orig_name = match.group(1)
     85       if orig_name in function_set and (args.version_list or orig_name not in versioned_functions):
     86         result.append(orig_name)
     87       continue
     88     # Export sanitizer interface functions.
     89     if re.match('__sanitizer_(.*)', func):
     90       result.append(func)
     91 
     92   # Additional exported functions from files.
     93   for fname in args.extra:
     94     f = open(fname, 'r')
     95     for line in f:
     96       result.append(line.rstrip())
     97   # Print the resulting list in the format recognized by ld.
     98   print('{')
     99   if args.version_list:
    100     print('global:')
    101   result.sort()
    102   for f in result:
    103     print(u'  %s;' % f)
    104   if args.version_list:
    105     print('local:')
    106     print('  *;')
    107   print('};')
    108 
    109 if __name__ == '__main__':
    110   main(sys.argv)
    111