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#===------------------------------------------------------------------------===#
17import os
18import re
19import subprocess
20import sys
21
22new_delete = set(['_ZdaPv', '_ZdaPvRKSt9nothrow_t',
23                  '_ZdlPv', '_ZdlPvRKSt9nothrow_t',
24                  '_Znam', '_ZnamRKSt9nothrow_t',
25                  '_Znwm', '_ZnwmRKSt9nothrow_t'])
26
27versioned_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
34def 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  func_symbols = ['T', 'W']
42  # On PowerPC, nm prints function descriptors from .data section.
43  if os.uname()[4] in ["powerpc", "ppc64"]:
44    func_symbols += ['D']
45  for line in nm_out:
46    cols = line.split(' ')
47    if len(cols) == 3 and cols[1] in func_symbols :
48      functions.append(cols[2])
49  return functions
50
51def main(argv):
52  result = []
53
54  library = argv[1]
55  all_functions = get_global_functions(library)
56  function_set = set(all_functions)
57  for func in all_functions:
58    # Export new/delete operators.
59    if func in new_delete:
60      result.append(func)
61      continue
62    # Export interceptors.
63    match = re.match('__interceptor_(.*)', func)
64    if match:
65      result.append(func)
66      # We have to avoid exporting the interceptors for versioned library
67      # functions due to gold internal error.
68      orig_name = match.group(1)
69      if orig_name in function_set and orig_name not in versioned_functions:
70        result.append(orig_name)
71      continue
72    # Export sanitizer interface functions.
73    if re.match('__sanitizer_(.*)', func):
74      result.append(func)
75
76  # Additional exported functions from files.
77  for fname in argv[2:]:
78    f = open(fname, 'r')
79    for line in f:
80      result.append(line.rstrip())
81  # Print the resulting list in the format recognized by ld.
82  print('{')
83  result.sort()
84  for f in result:
85    print('  ' + f + ';')
86  print('};')
87
88if __name__ == '__main__':
89  main(sys.argv)
90