| import os | |
| import shutil | |
| import subprocess | |
| import sys | |
| import tempfile | |
| from utils import FindBaseNaCl, shellcmd | |
| def subsToMacros(subs, src): | |
| macros = ['#include <stddef.h>', | |
| '#ifdef __cplusplus', | |
| 'extern "C" {', | |
| '#endif'] | |
| for func in subs: | |
| args = [('{atype} a{num}').format(atype=atype, num=i) for | |
| i, atype in enumerate(subs[func]['sig'][1:])] | |
| macros.append(( | |
| '{ftype} {name}({args});' | |
| ).format(ftype=subs[func]['sig'][0], | |
| name=subs[func]['sub'], | |
| args=', '.join(args))) | |
| macros.append(( | |
| '#define {func}(args...) ({sub}(args))' | |
| ).format(func=func, sub=subs[func]['sub'])) | |
| macros += ['#ifdef __cplusplus', | |
| '} // extern "C"', | |
| '#endif', | |
| '#line 1 "{src}"'.format(src=src)] | |
| return '\n'.join(macros) + '\n' | |
| def run(is_cpp): | |
| """Passes its arguments directly to pnacl-clang. | |
| If -fsanitize-address is specified, extra information is passed to | |
| pnacl-clang to ensure that later instrumentation in pnacl-sz can be | |
| performed. For example, clang automatically inlines many memory allocation | |
| functions, so this script will redefine them at compile time to make sure | |
| they can be correctly instrumented by pnacl-sz. | |
| """ | |
| pnacl_root = FindBaseNaCl() | |
| dummy_subs = {'calloc': {'sig': ['void *', 'size_t', 'size_t'], | |
| 'sub': '__asan_dummy_calloc'}, | |
| '_calloc': {'sig': ['void *', 'size_t', 'size_t'], | |
| 'sub': '__asan_dummy_calloc'}} | |
| subs_src = ( | |
| '{root}/toolchain_build/src/subzero/pydir/sz_clang_dummies.c' | |
| ).format(root=pnacl_root) | |
| clang = ( | |
| '{root}/toolchain/linux_x86/pnacl_newlib_raw/bin/pnacl-clang{pp}' | |
| ).format(root=pnacl_root, pp='++' if is_cpp else '') | |
| args = sys.argv | |
| args[0] = clang | |
| tmp_dir = '' | |
| if '-fsanitize-address' in args: | |
| args.remove('-fsanitize-address') | |
| include_dirs = set() | |
| tmp_dir = tempfile.mkdtemp() | |
| for i, arg in enumerate(args[1:], 1): | |
| if not os.path.isfile(arg): | |
| continue | |
| src = os.path.basename(arg) | |
| ext = os.path.splitext(arg)[1] | |
| if ext in ['.c', '.cc', '.cpp']: | |
| include_dirs |= {os.path.dirname(arg)} | |
| dest_name = os.path.join(tmp_dir, src) | |
| with open(dest_name, 'w') as dest: | |
| dest.write(subsToMacros(dummy_subs, arg)) | |
| with open(arg) as src: | |
| for line in src: | |
| dest.write(line) | |
| args[i] = dest_name | |
| # If linking (not single file compilation) then add dummy definitions | |
| if not ('-o' in args and | |
| ('-c' in args or '-S' in args or '-E' in args)): | |
| args.append(subs_src) | |
| for d in include_dirs: | |
| args.append('-iquote {d}'.format(d=d)) | |
| if '-fno-inline' not in args: | |
| args.append('-fno-inline') | |
| err_code = 0 | |
| try: | |
| shellcmd(args, echo=True) | |
| except subprocess.CalledProcessError as e: | |
| print e.output | |
| err_code = e.returncode | |
| if tmp_dir != '': | |
| shutil.rmtree(tmp_dir) | |
| exit(err_code) |