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 os
     18 import re
     19 import subprocess
     20 import sys
     21 
     22 new_delete = set(['_ZdaPv', '_ZdaPvRKSt9nothrow_t',
     23                   '_ZdlPv', '_ZdlPvRKSt9nothrow_t',
     24                   '_Znam', '_ZnamRKSt9nothrow_t',
     25                   '_Znwm', '_ZnwmRKSt9nothrow_t'])
     26 
     27 versioned_functions = set(['memcpy', 'pthread_attr_getaffinity_np',
     28                            'pthread_cond_broadcast',
     29                            'pthread_cond_destroy', 'pthread_cond_init',
     30                            'pthread_cond_signal', 'pthread_cond_timedwait',
     31                            'pthread_cond_wait', 'realpath',
     32                            'sched_getaffinity'])
     33 
     34 def get_global_functions(library):
     35   functions = []
     36   nm_proc = subprocess.Popen(['nm', library], stdout=subprocess.PIPE,
     37                              stderr=subprocess.PIPE)
     38   nm_out = nm_proc.communicate()[0].decode().split('\n')
     39   if nm_proc.returncode != 0:
     40     raise subprocess.CalledProcessError(nm_proc.returncode, 'nm')
     41   for line in nm_out:
     42     cols = line.split(' ')
     43     if (len(cols) == 3 and cols[1] in ('T', 'W')) :
     44       functions.append(cols[2])
     45   return functions
     46 
     47 def main(argv):
     48   result = []
     49 
     50   library = argv[1]
     51   all_functions = get_global_functions(library)
     52   function_set = set(all_functions)
     53   for func in all_functions:
     54     # Export new/delete operators.
     55     if func in new_delete:
     56       result.append(func)
     57       continue
     58     # Export interceptors.
     59     match = re.match('__interceptor_(.*)', func)
     60     if match:
     61       result.append(func)
     62       # We have to avoid exporting the interceptors for versioned library
     63       # functions due to gold internal error.
     64       orig_name = match.group(1)
     65       if orig_name in function_set and orig_name not in versioned_functions:
     66         result.append(orig_name)
     67       continue
     68     # Export sanitizer interface functions.
     69     if re.match('__sanitizer_(.*)', func):
     70       result.append(func)
     71 
     72   # Additional exported functions from files.
     73   for fname in argv[2:]:
     74     f = open(fname, 'r')
     75     for line in f:
     76       result.append(line.rstrip())
     77   # Print the resulting list in the format recognized by ld.
     78   print('{')
     79   result.sort()
     80   for f in result:
     81     print('  ' + f + ';')
     82   print('};')
     83 
     84 if __name__ == '__main__':
     85   main(sys.argv)
     86