Example #1
0
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))
Example #2
0
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)
Example #3
0
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
Example #4
0
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)
Example #5
0
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