summaryrefslogtreecommitdiff
path: root/lib/sanitizer_common/scripts/gen_dynamic_list.py
blob: 25632ed77b9468553803926894a3dcc61a1fbf09 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/usr/bin/env python
#===- lib/sanitizer_common/scripts/gen_dynamic_list.py ---------------------===#
#
#                     The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
#
# Generates the list of functions that should be exported from sanitizer
# runtimes. The output format is recognized by --dynamic-list linker option.
# Usage:
#   gen_dynamic_list.py libclang_rt.*san*.a [ files ... ]
#
#===------------------------------------------------------------------------===#
import argparse
import os
import re
import subprocess
import sys
import platform

new_delete = set([
                  '_Znam', '_ZnamRKSt9nothrow_t',    # operator new[](unsigned long)
                  '_Znwm', '_ZnwmRKSt9nothrow_t',    # operator new(unsigned long)
                  '_Znaj', '_ZnajRKSt9nothrow_t',    # operator new[](unsigned int)
                  '_Znwj', '_ZnwjRKSt9nothrow_t',    # operator new(unsigned int)
                  # operator new(unsigned long, std::align_val_t)
                  '_ZnwmSt11align_val_t', '_ZnwmSt11align_val_tRKSt9nothrow_t',
                  # operator new(unsigned int, std::align_val_t)
                  '_ZnwjSt11align_val_t', '_ZnwjSt11align_val_tRKSt9nothrow_t',
                  # operator new[](unsigned long, std::align_val_t)
                  '_ZnamSt11align_val_t', '_ZnamSt11align_val_tRKSt9nothrow_t',
                  # operator new[](unsigned int, std::align_val_t)
                  '_ZnajSt11align_val_t', '_ZnajSt11align_val_tRKSt9nothrow_t',
                  '_ZdaPv', '_ZdaPvRKSt9nothrow_t',  # operator delete[](void *)
                  '_ZdlPv', '_ZdlPvRKSt9nothrow_t',  # operator delete(void *)
                  '_ZdaPvm',                         # operator delete[](void*, unsigned long)
                  '_ZdlPvm',                         # operator delete(void*, unsigned long)
                  '_ZdaPvj',                         # operator delete[](void*, unsigned int)
                  '_ZdlPvj',                         # operator delete(void*, unsigned int)
                  # operator delete(void*, std::align_val_t)
                  '_ZdlPvSt11align_val_t', '_ZdlPvSt11align_val_tRKSt9nothrow_t',
                  # operator delete[](void*, std::align_val_t)
                  '_ZdaPvSt11align_val_t', '_ZdaPvSt11align_val_tRKSt9nothrow_t',
                  # operator delete(void*, unsigned long,  std::align_val_t)
                  '_ZdlPvmSt11align_val_t',
                  # operator delete[](void*, unsigned long, std::align_val_t)
                  '_ZdaPvmSt11align_val_t',
                  # operator delete(void*, unsigned int,  std::align_val_t)
                  '_ZdlPvjSt11align_val_t',
                  # operator delete[](void*, unsigned int, std::align_val_t)
                  '_ZdaPvjSt11align_val_t',
                  ])

versioned_functions = set(['memcpy', 'pthread_attr_getaffinity_np',
                           'pthread_cond_broadcast',
                           'pthread_cond_destroy', 'pthread_cond_init',
                           'pthread_cond_signal', 'pthread_cond_timedwait',
                           'pthread_cond_wait', 'realpath',
                           'sched_getaffinity'])

def get_global_functions(library):
  functions = []
  nm = os.environ.get('NM', 'nm')
  nm_proc = subprocess.Popen([nm, library], stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
  nm_out = nm_proc.communicate()[0].decode().split('\n')
  if nm_proc.returncode != 0:
    raise subprocess.CalledProcessError(nm_proc.returncode, nm)
  func_symbols = ['T', 'W']
  # On PowerPC, nm prints function descriptors from .data section.
  if platform.uname()[4] in ["powerpc", "ppc64"]:
    func_symbols += ['D']
  for line in nm_out:
    cols = line.split(' ')
    if len(cols) == 3 and cols[1] in func_symbols :
      functions.append(cols[2])
  return functions

def main(argv):
  parser = argparse.ArgumentParser()
  parser.add_argument('--version-list', action='store_true')
  parser.add_argument('--extra', default=[], action='append')
  parser.add_argument('libraries', default=[], nargs='+')
  args = parser.parse_args()

  result = []

  all_functions = []
  for library in args.libraries:
    all_functions.extend(get_global_functions(library))
  function_set = set(all_functions)
  for func in all_functions:
    # Export new/delete operators.
    if func in new_delete:
      result.append(func)
      continue
    # Export interceptors.
    match = re.match('__interceptor_(.*)', func)
    if match:
      result.append(func)
      # We have to avoid exporting the interceptors for versioned library
      # functions due to gold internal error.
      orig_name = match.group(1)
      if orig_name in function_set and (args.version_list or orig_name not in versioned_functions):
        result.append(orig_name)
      continue
    # Export sanitizer interface functions.
    if re.match('__sanitizer_(.*)', func):
      result.append(func)

  # Additional exported functions from files.
  for fname in args.extra:
    f = open(fname, 'r')
    for line in f:
      result.append(line.rstrip())
  # Print the resulting list in the format recognized by ld.
  print('{')
  if args.version_list:
    print('global:')
  result.sort()
  for f in result:
    print(u'  %s;' % f)
  if args.version_list:
    print('local:')
    print('  *;')
  print('};')

if __name__ == '__main__':
  main(sys.argv)