Ejemplo n.º 1
0
def compare(args):
    """
    Compare snapshots of linux kernels. Runs the semantic comparison and shows
    information about the compared functions that are semantically different.
    """
    # Parse both the new and the old snapshot.
    old_snapshot = Snapshot.load_from_dir(args.snapshot_dir_old)
    new_snapshot = Snapshot.load_from_dir(args.snapshot_dir_new)

    # Set the output directory
    if not args.stdout:
        if args.output_dir:
            output_dir = args.output_dir
            if os.path.isdir(output_dir):
                sys.stderr.write("Error: output directory exists\n")
                sys.exit(errno.EEXIST)
        else:
            output_dir = default_output_dir(args.snapshot_dir_old,
                                            args.snapshot_dir_new)
    else:
        output_dir = None

    if args.function:
        old_snapshot.filter([args.function])
        new_snapshot.filter([args.function])

    config = Config(old_snapshot, new_snapshot, args.show_diff,
                    args.output_llvm_ir, args.control_flow_only,
                    args.print_asm_diffs, args.verbose, args.enable_simpll_ffi,
                    args.semdiff_tool)
    result = Result(Result.Kind.NONE,
                    args.snapshot_dir_old,
                    args.snapshot_dir_old,
                    start_time=default_timer())

    for group_name, group in sorted(old_snapshot.fun_groups.items()):
        group_printed = False

        # Set the group directory
        if output_dir is not None and group_name is not None:
            group_dir = os.path.join(output_dir, group_name)
        else:
            group_dir = None

        result_graph = None
        cache = SimpLLCache(mkdtemp())

        if args.enable_module_cache:
            module_cache = _generate_module_cache(group.functions.items(),
                                                  group_name, new_snapshot, 3)
        else:
            module_cache = None

        for fun, old_fun_desc in sorted(group.functions.items()):
            # Check if the function exists in the other snapshot
            new_fun_desc = new_snapshot.get_by_name(fun, group_name)
            if not new_fun_desc:
                continue

            # Check if the module exists in both snapshots
            if old_fun_desc.mod is None or new_fun_desc.mod is None:
                result.add_inner(Result(Result.Kind.UNKNOWN, fun, fun))
                if group_name is not None and not group_printed:
                    print("{}:".format(group_name))
                    group_printed = True
                print("{}: unknown".format(fun))
                continue

            # If function has a global variable, set it
            glob_var = KernelParam(old_fun_desc.glob_var) \
                if old_fun_desc.glob_var else None

            # Run the semantic diff
            fun_result = functions_diff(mod_first=old_fun_desc.mod,
                                        mod_second=new_fun_desc.mod,
                                        fun_first=fun,
                                        fun_second=fun,
                                        glob_var=glob_var,
                                        config=config,
                                        prev_result_graph=result_graph,
                                        function_cache=cache,
                                        module_cache=module_cache)
            result_graph = fun_result.graph

            if fun_result is not None:
                if args.regex_filter is not None:
                    # Filter results by regex
                    pattern = re.compile(args.regex_filter)
                    for called_res in fun_result.inner.values():
                        if pattern.search(called_res.diff):
                            break
                    else:
                        fun_result.kind = Result.Kind.EQUAL_SYNTAX

                result.add_inner(fun_result)

                # Printing information about failures and non-equal functions.
                if fun_result.kind in [
                        Result.Kind.NOT_EQUAL, Result.Kind.ERROR,
                        Result.Kind.UNKNOWN
                ]:
                    if fun_result.kind == Result.Kind.NOT_EQUAL:
                        # Create the output directory if needed
                        if output_dir is not None:
                            if not os.path.isdir(output_dir):
                                os.mkdir(output_dir)
                        # Create the group directory or print the group name
                        # if needed
                        if group_dir is not None:
                            if not os.path.isdir(group_dir):
                                os.mkdir(group_dir)
                        elif group_name is not None and not group_printed:
                            print("{}:".format(group_name))
                            group_printed = True
                        print_syntax_diff(
                            snapshot_dir_old=args.snapshot_dir_old,
                            snapshot_dir_new=args.snapshot_dir_new,
                            fun=fun,
                            fun_result=fun_result,
                            fun_tag=old_fun_desc.tag,
                            output_dir=group_dir if group_dir else output_dir,
                            show_diff=args.show_diff,
                            initial_indent=2 if (group_name is not None
                                                 and group_dir is None) else 0)
                    else:
                        # Print the group name if needed
                        if group_name is not None and not group_printed:
                            print("{}:".format(group_name))
                            group_printed = True
                        print("{}: {}".format(fun, str(fun_result.kind)))

            # Clean LLVM modules (allow GC to collect the occupied memory)
            old_fun_desc.mod.clean_module()
            new_fun_desc.mod.clean_module()
            LlvmKernelModule.clean_all()

    old_snapshot.finalize()
    new_snapshot.finalize()

    if output_dir is not None and os.path.isdir(output_dir):
        print("Differences stored in {}/".format(output_dir))

    if args.report_stat:
        print("")
        print("Statistics")
        print("----------")
        result.stop_time = default_timer()
        result.report_stat(args.show_errors)
    return 0
Ejemplo n.º 2
0
def compare(args):
    old_functions = FunctionList(args.snapshot_dir_old)
    with open(os.path.join(args.snapshot_dir_old, "functions.yaml"),
              "r") as fun_list_yaml:
        old_functions.from_yaml(fun_list_yaml.read())
    old_source = KernelSource(args.snapshot_dir_old)
    new_functions = FunctionList(args.snapshot_dir_new)
    with open(os.path.join(args.snapshot_dir_new, "functions.yaml"),
              "r") as fun_list_yaml:
        new_functions.from_yaml(fun_list_yaml.read())
    new_source = KernelSource(args.snapshot_dir_new)

    if args.function:
        old_functions.filter([args.function])
        new_functions.filter([args.function])

    config = Config(old_source, new_source, args.show_diff,
                    args.control_flow_only, args.verbose,
                    args.semdiff_tool)
    result = Result(Result.Kind.NONE, args.snapshot_dir_old,
                    args.snapshot_dir_old)

    for fun, old_mod in sorted(old_functions.functions.items()):
        new_mod = new_functions.get_by_name(fun)
        if not (old_mod.has_function(fun) and new_mod.has_function(fun)):
            continue

        fun_result = functions_diff(
            mod_first=old_mod, mod_second=new_mod,
            fun_first=fun, fun_second=fun,
            glob_var=None, config=config)

        if fun_result is not None:
            if args.regex_filter is not None:
                # Filter results by regex
                pattern = re.compile(args.regex_filter)
                for called_res in fun_result.inner.values():
                    if pattern.search(called_res.diff):
                        break
                else:
                    fun_result.kind = Result.Kind.EQUAL_SYNTAX

            result.add_inner(fun_result)
            if fun_result.kind in [Result.Kind.ERROR, Result.Kind.UNKNOWN]:
                print("{}: {}".format(fun, str(fun_result.kind)))
            elif fun_result.kind == Result.Kind.NOT_EQUAL:
                print_syntax_diff(args.snapshot_dir_old,
                                  args.snapshot_dir_new,
                                  fun, fun_result, False,
                                  args.show_diff)

        # Clean LLVM modules (allow GC to collect the occupied memory)
        old_mod.clean_module()
        new_mod.clean_module()
        LlvmKernelModule.clean_all()

    if args.report_stat:
        print("")
        print("Statistics")
        print("----------")
        result.report_stat(args.show_errors)
    return 0