import os import shutil import subprocess import sys import tempfile from utils import FindBaseNaCl, shellcmd def subsToMacros(subs, src): macros = ['#include ', '#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)