def main(): log.setLevel(logging.INFO) args = parse_args() if args.log_level: log.setLevel(args.log_level) log.debug(f'setting log level to {args.log_level}') seg_c = args.segment_file orig_dir = args.original_file log.debug(f'segment: {seg_c}, original: {orig_dir}') clang_args = args.clang_args.split() if clang_args: log.debug(f' provided clang args: {clang_args}') if args.verbose: global verbose verbose = True log.debug(f'verbose logging enabled') seg_cur = parse(seg_c, clang_args) seg_target = select_target(seg_cur, target_name=args.target) parms = list(seg_target.get_arguments()) log.debug(f'target: {pp(seg_target)}') import re target_name = re.match(r'helium_(.*)', seg_target.spelling).group(1) from pathlib import Path for orig_c in Path(orig_dir).glob('**/*.c'): orig_cur = parse(orig_c) orig_funcdecls = find(orig_cur, CursorKind.FUNCTION_DECL, verbose) orig_target = next((f.get_definition() for f in orig_funcdecls if is_the_same(f, seg_target) and f.get_definition() is not None), None) if orig_target is not None: break log.debug(f'target: {pp(orig_target)}') orig_body = find(orig_target, lambda c: c is not None and c.kind.is_statement(), verbose=verbose) first_stmt = next(iter(orig_body)) first_stmt_file, first_stmt_line = first_stmt.location.file.name, first_stmt.location.line diff = gen_patch(first_stmt_file, first_stmt_line, parms, args.array) print('\n'.join(diff))
def read_input_file(translation_unit): input_lines = open(translation_unit.spelling, 'r').readlines() def is_main_definition(n): return n.kind == CursorKind.FUNCTION_DECL and n.is_definition( ) and n.spelling == 'main' main_def = next(iter(find(translation_unit, is_main_definition)), None) if main_def: start, end = main_def.extent.start.line, main_def.extent.end.line input_lines = input_lines[:start - 1] + input_lines[end:] return ''.join(input_lines)
def select_target(func_name, cur): """ Select target function with the given name from cur """ funcdecls = find(cur, CursorKind.FUNCTION_DECL) if func_name: target = next((n for n in funcdecls if n.spelling == func_name), None) if target is None: raise Exception(f'no function named {func_name}') else: target = max(funcdecls, key=lambda n: n.location.line if n.spelling != 'main' and n.location.file.name.endswith('.c') else -1) log.info(f'target function: {pp(target)}') return target
def select_target(cur, target_name=None): """ Select a target function from a cursor """ func_decls = find(cur, CursorKind.FUNCTION_DECL) if target_name: # Select the function matching a name try: return next(filter(lambda f: f.spelling == target_name, func_decls)) except: log.exception(f'could not find target function with name {target_name}') raise else: # Select the last eligible function based on heuristic eligible = filter(lambda f: '.c' in f.location.file.name and f.spelling != 'main', func_decls) return max(eligible, key=lambda f: f.location.line)
def get_static_locations(dynamic_locations, clang_include_paths): """ Get locations for certain constructs which are only available statically. - Variable declarations without any executable code "int i;" - Case statements "case foo:" - Default statements "default: " """ static_locations = [] def ancestor_node(n): """ Get the nearest significant ancestor. """ if n.kind == CursorKind.FUNCTION_DECL: return n else: if n.semantic_parent is None: return n else: return ancestor_node(n.semantic_parent) def good(n): """ Node should be added to the trace. """ if n.kind in (CursorKind.VAR_DECL, CursorKind.CASE_STMT, CursorKind.DEFAULT_STMT): return True else: return False filepaths = defaultdict(list) for l in dynamic_locations: filepaths[l.filepath].append(l) for filepath, locations in filepaths.items(): log.debug( f'Parsing source file {filepath} with args {clang_include_paths}') root = nodeutils.parse(filepath, clang_include_paths) ancestors = [] file = File.from_name(root.translation_unit, filepath) for l in locations: source_location = SourceLocation.from_position( root.translation_unit, file, l.lineno, l.column) node = Cursor.from_location(root.translation_unit, source_location) l.node = node if node.kind.is_invalid(): continue ancestor = ancestor_node(node) if ancestor not in ancestors: log.debug( f'node {nodeutils.pp(node)} has ancestor {nodeutils.pp(ancestor)}' ) ancestors.append(ancestor) for a in ancestors: if a.kind.is_translation_unit(): continue # Do not include global constructs else: nodes = nodeutils.find(a, good) locations = [ Location(n.location.file.name, n.location.line, n.location.column, n) for n in nodes ] for l in locations: log.debug(f'static location {l}') static_locations += locations return static_locations