• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# Copyright 2017 Google Inc.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16################################################################################
17
18from __future__ import print_function
19import os
20import subprocess
21import sys
22
23import msan_build
24
25GCC_ONLY_ARGS = [
26    '-aux-info',
27]
28
29
30def InvokedAsGcc():
31  """Return whether or not we're pretending to be GCC."""
32  return sys.argv[0].endswith('gcc') or sys.argv[0].endswith('g++')
33
34
35def Is32Bit(args):
36  """Return whether or not we're 32-bit."""
37  M32_BIT_ARGS = [
38      '-m32',
39      '-mx32',
40  ]
41
42  return any(arg in M32_BIT_ARGS for arg in args)
43
44
45def FilterWlArg(arg):
46  """Remove -z,defs and equivalents from a single -Wl option."""
47  parts = arg.split(',')[1:]
48
49  filtered = []
50  for part in parts:
51    if part == 'defs':
52      removed = filtered.pop()
53      assert removed == '-z'
54      continue
55
56    if part == '--no-undefined':
57      continue
58
59    filtered.append(part)
60
61  if filtered:
62    return '-Wl,' + ','.join(filtered)
63
64  # Filtered entire argument.
65  return None
66
67
68def _RemoveLastMatching(l, find):
69  for i in xrange(len(l) - 1, -1, -1):
70    if l[i] == find:
71      del l[i]
72      return
73
74  raise IndexError('Not found')
75
76
77def RemoveZDefs(args):
78  """Remove unsupported -Wl,-z,defs linker option."""
79  filtered = []
80
81  for arg in args:
82    if arg == '-Wl,defs':
83      _RemoveLastMatching(filtered, '-Wl,-z')
84      continue
85
86    if arg == '-Wl,--no-undefined':
87      continue
88
89    if arg.startswith('-Wl,'):
90      arg = FilterWlArg(arg)
91      if not arg:
92        continue
93
94    filtered.append(arg)
95
96  return filtered
97
98
99def GetCompilerArgs(args, is_cxx):
100  """Generate compiler args."""
101  compiler_args = args[1:]
102
103  if Is32Bit(args):
104    # 32 bit builds not supported.
105    compiler_args.extend([
106        '-fno-sanitize=memory',
107        '-fno-sanitize-memory-track-origins',
108    ])
109
110    return compiler_args
111
112  compiler_args = RemoveZDefs(compiler_args)
113  compiler_args.extend([
114      # FORTIFY_SOURCE is not supported by sanitizers.
115      '-U_FORTIFY_SOURCE',
116      '-Wp,-U_FORTIFY_SOURCE',
117      # Reduce binary size.
118      '-gline-tables-only',
119      # Disable all warnings.
120      '-w',
121      # LTO isn't supported.
122      '-fno-lto',
123  ])
124
125  if InvokedAsGcc():
126    compiler_args.extend([
127      # For better compatibility with flags passed via -Wa,...
128      '-fno-integrated-as',
129    ])
130
131  if '-fsanitize=memory' not in args:
132    # If MSan flags weren't added for some reason, add them here.
133    compiler_args.extend(msan_build.GetInjectedFlags())
134
135  if is_cxx:
136    compiler_args.append('-stdlib=libc++')
137
138  return compiler_args
139
140
141def FindRealClang():
142  """Return path to real clang."""
143  return os.environ['REAL_CLANG_PATH']
144
145
146def FallbackToGcc(args):
147  """Check whether if we should fall back to GCC."""
148  if not InvokedAsGcc():
149    return False
150
151  return any(arg in GCC_ONLY_ARGS for arg in args[1:])
152
153
154def main(args):
155  if FallbackToGcc(args):
156    sys.exit(subprocess.call(['/usr/bin/' + os.path.basename(args[0])] +
157                             args[1:]))
158
159  is_cxx = args[0].endswith('++')
160  real_clang = FindRealClang()
161
162  if is_cxx:
163    real_clang += '++'
164
165  args = [real_clang] + GetCompilerArgs(args, is_cxx)
166  debug_log_path = os.getenv('WRAPPER_DEBUG_LOG_PATH')
167  if debug_log_path:
168    with open(debug_log_path, 'a') as f:
169      f.write(str(args) + '\n')
170
171  sys.exit(subprocess.call(args))
172
173
174if __name__ == '__main__':
175  main(sys.argv)
176