def main(argv): progname = os.path.basename(argv[0]) # parse arguments opt = parse_arguments(argv[1:]) # setup colors and logging colors.setup(opt.color, file=log.out) log.setup(opt.log_level) if not os.path.isfile(opt.file): printf("%s: error: no such file: \'%s\'\n", progname, opt.file, file=sys.stderr) sys.exit(1) try: # open result database db = OutputDatabase(opt.file) v = View(db, port=opt.port) browser_timer = threading.Timer(0.1, open_browser, ['http://localhost:%d/' % opt.port]) browser_timer.start() v.serve() # close database db.close() except sqlite3.DatabaseError as e: printf('%s: error: %s\n', progname, e, file=sys.stderr) sys.exit(1)
def scan_main(argv): # parse arguments opt = scan_parse_arguments(argv[1:]) # setup colors and logging colors.setup(opt.color, file=log.out) log.setup(opt.log_level) # scan server server = ScanServer() server.daemon = True server.start() # setup environment variables os.environ['IKOS_SCAN_COLOR'] = 'yes' if colors.ENABLE else 'no' os.environ['IKOS_SCAN_LOG_LEVEL'] = opt.log_level os.environ['IKOS_SCAN_SERVER'] = 'http://localhost:%d' % server.port os.environ['PATH'] += os.path.pathsep + settings.BIN_DIR os.environ['CC'] = 'ikos-scan-cc' os.environ['CXX'] = 'ikos-scan-c++' os.environ['LD'] = 'ikos-scan-cc' # add -e to make commands, to avoid makefiles overriding CC/CXX/LD if os.path.basename(opt.args[0]) in ('make', 'gmake'): opt.args.insert(1, '-e') # run the build command rc = run(opt.args) # stop the scan server server.cancel() server.join() # skip binaries that have been removed binaries = [binary for binary in server.binaries if os.path.exists(binary['exe_path'])] if not binaries: printf('Nothing to analyze.\n') # analyze each binary for binary in binaries: exe_path = os.path.relpath(binary['exe_path']) bc_path = os.path.relpath(binary['bc_path']) printf('Analyze %s? [Y/n] ', colors.bold(exe_path)) answer = sys.stdin.readline().strip().lower() if answer in ('', 'y', 'yes'): cmd = ['ikos', bc_path, '-o', '%s.db' % exe_path] log.info('Running %s' % colors.bold(command_string(cmd))) cmd = [sys.executable, settings.ikos(), bc_path, '-o', '%s.db' % exe_path, '--color=%s' % opt.color, '--log=%s' % opt.log_level] run(cmd)
def check_output(cmd): ''' Run the given command and return the standard output, in bytes ''' log.debug('Running %s' % command_string(cmd)) try: return subprocess.check_output(cmd) except OSError as e: printf('error: %s: %s\n', cmd[0], e.strerror, file=sys.stderr) sys.exit(e.errno)
def _shift(self, nargs): if len(self.args) < nargs: printf('error: unexpected command line argument\n', file=sys.stderr) sys.exit(1) ret = [] for _ in range(nargs): ret.append(self.args.popleft()) return ret
def filetype(path): ''' Return the file type as returned by the 'file' command ''' try: output = subprocess.check_output(['file', '--brief', path]) except OSError as e: printf('error: file: %s', e.strerror, file=sys.stderr) sys.exit(e.errno) if output.startswith(b'cannot open '): open(path) # raise IOError return output.decode('utf-8').strip()
def run(cmd): ''' Run the given command and return the exit code ''' log.debug('Running %s' % command_string(cmd)) try: proc = subprocess.Popen(cmd) rc = proc.wait() except OSError as e: printf('error: %s: %s\n', cmd[0], e.strerror, file=sys.stderr) sys.exit(e.errno) if rc != 0: sys.exit(rc) return rc
def create_working_directory(wd=None, save=False): ''' Create a temporary working directory ''' if not wd: wd = tempfile.mkdtemp(prefix='ikos-') if not os.path.exists(wd): try: os.makedirs(wd) except OSError as e: printf('error: %s: %s\n', wd, e.strerror, file=sys.stderr) sys.exit(1) if not os.path.isdir(wd): printf('error: %s: Not a directory\n', wd, file=sys.stderr) sys.exit(1) if not save: atexit.register(shutil.rmtree, path=wd) else: log.info('Temporary files will be kept in directory: %s' % wd) return wd
def main(argv): progname = os.path.basename(argv[0]) start_date = datetime.datetime.now() # parse arguments opt = parse_arguments(argv[1:]) # setup colors and logging colors.setup(opt.color, file=log.out) log.setup(opt.log_level) if is_apron_domain(opt.domain) and not settings.HAS_APRON: printf( '%s: error: cannot use apron abstract domains.\n' 'ikos was compiled without apron support, ' 'see analyzer/README.md\n', progname, file=sys.stderr) sys.exit(1) # create working directory wd = create_working_directory(opt.temp_dir, opt.save_temps) input_path = opt.file # compile c/c++ code if path_ext(input_path) in c_extensions + cpp_extensions: bc_path = namer(opt.file, '.bc', wd) try: with stats.timer('clang'): clang(bc_path, input_path, opt.compiler_include_flags, opt.compiler_define_flags, opt.compiler_warning_flags, opt.compiler_disable_warnings, opt.compiler_machine_flags, colors.ENABLE) except subprocess.CalledProcessError as e: printf('%s: error while compiling %s, abort.\n', progname, input_path, file=sys.stderr) sys.exit(e.returncode) input_path = bc_path if path_ext(input_path) not in llvm_extensions: printf('%s: error: unexpected file extension.\n', progname, file=sys.stderr) sys.exit(1) # ikos-pp: preprocess llvm bitcode pp_path = namer(opt.file, '.pp.bc', wd) try: with stats.timer('ikos-pp'): ikos_pp(pp_path, input_path, opt.entry_points, opt.opt_level, opt.inline_all, not opt.no_bc_verify) except subprocess.CalledProcessError as e: printf('%s: error while preprocessing llvm bitcode, abort.\n', progname, file=sys.stderr) sys.exit(e.returncode) # display the llvm bitcode, if requested if opt.display_llvm: display_llvm(pp_path) # ikos-analyzer: analyze llvm bitcode try: with stats.timer('ikos-analyzer'): ikos_analyzer(opt.output_db, pp_path, opt) except AnalyzerError as e: printf('%s: error: %s\n', progname, e, file=sys.stderr) sys.exit(e.returncode) # open output database db = OutputDatabase(path=opt.output_db) # insert timing results in the database db.insert_timing_results(stats.rows()) # insert settings in the database settings_rows = [ ('version', settings.VERSION), ('start-date', start_date.isoformat(' ')), ('end-date', datetime.datetime.now().isoformat(' ')), ('working-directory', wd), ('input', opt.file), ('bc-file', input_path), ('pp-bc-file', pp_path), ('clang', settings.clang()), ('ikos-pp', settings.ikos_pp()), ('opt-level', opt.opt_level), ('inline-all', json.dumps(opt.inline_all)), ('use-libc-intrinsics', json.dumps(not opt.no_libc)), ('use-libcpp-intrinsics', json.dumps(not opt.no_libcpp)), ('use-libikos-intrinsics', json.dumps(not opt.no_libikos)), ('use-simplify-cfg', json.dumps(not opt.no_simplify_cfg)), ('use-simplify-upcast-comparison', json.dumps(not opt.no_simplify_upcast_comparison)), ] if opt.cpu: settings_rows.append(('cpu-limit', opt.cpu)) if opt.mem: settings_rows.append(('mem-limit', opt.mem)) db.insert_settings(settings_rows) first = (log.LEVEL >= log.ERROR) # display timing results if opt.display_times != 'no': if not first: printf('\n') report.print_timing_results(db, opt.display_times == 'full') first = False # display summary if opt.display_summary != 'no': if not first: printf('\n') report.print_summary(db, opt.display_summary == 'full') first = False # display raw checks if opt.display_raw_checks: if not first: printf('\n') report.print_raw_checks(db, opt.procedural == 'inter') first = False # start ikos-view if opt.format == 'web': ikos_view(opt, db) return # report if opt.format != 'no': if not first and opt.report_file is sys.stdout: printf('\n' + colors.bold('# Results') + '\n') first = False # setup colors again (in case opt.color = 'auto') colors.setup(opt.color, file=opt.report_file) # generate report rep = report.generate_report(db, status_filter=opt.status_filter, analyses_filter=None) # format report formatter_class = report.formats[opt.format] formatter = formatter_class(opt.report_file, opt.report_verbosity) formatter.format(rep) # close database db.close() if opt.remove_db: os.remove(opt.output_db)
def compile(mode, argv): progname = os.path.basename(argv[0]) if 'IKOS_SCAN_SERVER' not in os.environ: printf('error: %s: missing environment variable IKOS_SCAN_SERVER.\n', progname, file=sys.stderr) sys.exit(1) # setup colors and logging colors.setup(os.environ.get('IKOS_SCAN_COLOR', args.default_color), file=log.out) log.setup(os.environ.get('IKOS_SCAN_LOG_LEVEL', args.default_log_level)) # first step, run the actual command run([compiler(mode)] + argv[1:]) # second step, parse the command line and compile to llvm bitcode parser = ClangArgumentParser(argv[1:]) if parser.skip_bitcode_gen(): return try: if (len(parser.source_files) == 1 and len(parser.object_files) == 0 and not parser.is_link): # in this case, just compile to llvm bitcode and attach the llvm # bitcode path to the output object file src_path = parser.source_files[0] obj_path = parser.output_file bc_path = '%s.bc' % obj_path build_bitcode(mode, parser, src_path, bc_path) attach_bitcode_path(obj_path, bc_path) return # compile the source files one by one and attach the llvm bitcode path new_object_files = [] for src_path in parser.source_files: # build the object file obj_path = '%s.o' % src_path build_object(mode, parser, src_path, obj_path) new_object_files.append(obj_path) # build the bitcode file if src_path.endswith('.bc'): bc_path = src_path else: bc_path = '%s.bc' % obj_path build_bitcode(mode, parser, src_path, bc_path) # attach the bitcode path to the object file, ready to be linked attach_bitcode_path(obj_path, bc_path) # re-link to merge the llvm bitcode paths section if new_object_files: if parser.is_link: link_objects(mode, parser, new_object_files + parser.object_files, parser.output_file) else: log.warning('New object files but nothing to link') if parser.is_link and u'executable' in filetype(parser.output_file): bc_path = '%s.bc' % parser.output_file extract_bitcode(parser.output_file, bc_path) notify_binary_built(parser.output_file, bc_path) except IOError as error: # ./configure sometimes removes the file while we are still running if error.filename == parser.output_file: pass else: raise error
def _warning_link_unary(self, flag): printf('warning: flag "%s" cannot be used with ikos-scan, ignored.\n', flag, file=sys.stderr)