示例#1
0
def modules_diff(mod_first, mod_second, glob_var, fun, config):
    """
    Analyse semantic difference of two LLVM IR modules w.r.t. some parameter
    :param mod_first: First LLVM module
    :param mod_second: Second LLVM module
    :param glob_var: Parameter (global variable) to compare (if specified, all
                  functions using this variable are compared).
    :param fun: Function to be compared.
    :param config: Configuration.
    """
    result = Result(Result.Kind.NONE, mod_first, mod_second)

    if fun:
        funs_first = {fun}
        funs_second = {fun}
    elif glob_var:
        funs_first = mod_first.get_functions_using_param(glob_var)
        funs_second = mod_second.get_functions_using_param(glob_var)
    else:
        funs_first = []
        funs_second = []

    for fun in funs_first:
        if fun not in funs_second:
            continue
        if (not mod_first.has_function(fun)
                or not mod_second.has_function(fun)):
            print("    Given function not found in module")
            result.kind = Result.Kind.ERROR
            return result

        fun_result = functions_diff(mod_first=mod_first,
                                    mod_second=mod_second,
                                    fun_first=fun,
                                    fun_second=fun,
                                    glob_var=glob_var,
                                    config=config)
        result.add_inner(fun_result)

    return result
示例#2
0
def diff_all_modules_using_global(glob_first, glob_second, config):
    """
    Compare semantics of all modules using given global variable.
    Finds all source files that use the given globals and compare all of them.
    :param glob_first: First global to compare
    :param glob_second: Second global to compare
    :param config: Configuration
    """
    result = Result(Result.Kind.NONE, glob_first.name, glob_second.name)
    if glob_first.name != glob_second.name:
        # Variables with different names are treated as unequal
        result.kind = Result.Kind.NOT_EQUAL
        return result

    srcs_first = config.source_first.find_srcs_using_symbol(glob_first.name)
    srcs_second = config.source_second.find_srcs_using_symbol(glob_second.name)
    # Compare all sources containing functions using the variable
    for src in srcs_first:
        if src not in srcs_second:
            result.add_inner(Result(Result.Kind.NOT_EQUAL, src, src))
        else:
            try:
                mod_first = config.source_first.get_module_from_source(src)
                mod_second = config.source_second.get_module_from_source(src)
                mod_first.parse_module()
                mod_second.parse_module()
                if (mod_first.has_global(glob_first.name)
                        and mod_second.has_global(glob_second.name)):
                    src_result = modules_diff(mod_first=mod_first,
                                              mod_second=mod_second,
                                              glob_var=glob_first,
                                              fun=None,
                                              config=config)
                    for res in src_result.inner.values():
                        result.add_inner(res)
            except BuildException as e:
                if config.verbosity:
                    print(e)
                result.add_inner(Result(Result.Kind.ERROR, src, src))
    return result
示例#3
0
def functions_diff(mod_first,
                   mod_second,
                   fun_first,
                   fun_second,
                   glob_var,
                   config,
                   prev_result_graph=None,
                   function_cache=None):
    """
    Compare two functions for equality.

    First, functions are simplified and compared for syntactic equality using
    the SimpLL tool. If they are not syntactically equal, SimpLL prints a list
    of functions that the syntactic equality depends on. These are then
    compared for semantic equality.
    :param mod_first: First LLVM module
    :param mod_second: Second LLVM module
    :param fun_first: Function from the first module to be compared
    :param fun_second: Function from the second module to be compared
    :param glob_var: Global variable whose effect on the functions to compare
    :param config: Configuration
    :param prev_result_graph: Graph generated by the previous comparison (used
    to pass already known results to be used in this comparison).
    :param function_cache: Cache for SimpLL containing all functions
    present in the current graph (passed to this function to be updated with
    the results of the comparison).
    """
    result = Result(Result.Kind.NONE, fun_first, fun_second)
    curr_result_graph = None
    try:
        if config.verbosity:
            if fun_first == fun_second:
                fun_str = fun_first
            else:
                fun_str = "{} and {}".format(fun_first, fun_second)
            print("Syntactic diff of {} (in {})".format(
                fun_str, mod_first.llvm))

        simplify = True
        while simplify:
            simplify = False
            if (prev_result_graph and fun_first in prev_result_graph.vertices
                    and (prev_result_graph.vertices[fun_first].result !=
                         Result.Kind.ASSUMED_EQUAL)):
                first_simpl = ""
                second_simpl = ""
                curr_result_graph = prev_result_graph
            else:
                # Simplify modules and get the output graph.
                first_simpl, second_simpl, curr_result_graph, missing_defs = \
                    run_simpll(first=mod_first.llvm, second=mod_second.llvm,
                               fun_first=fun_first, fun_second=fun_second,
                               var=glob_var.name if glob_var else None,
                               suffix=glob_var.name if glob_var else "simpl",
                               cache_dir=function_cache.directory
                               if function_cache else None,
                               control_flow_only=config.control_flow_only,
                               output_llvm_ir=config.output_llvm_ir,
                               print_asm_diffs=config.print_asm_diffs,
                               verbose=config.verbosity,
                               use_ffi=config.use_ffi)
                if missing_defs:
                    # If there are missing function definitions, try to find
                    # their implementation, link them to the current modules,
                    # and rerun the simplification.
                    for fun_pair in missing_defs:
                        if "first" in fun_pair:
                            if _link_symbol_def(config.snapshot_first,
                                                mod_first, fun_pair["first"]):
                                simplify = True

                        if "second" in fun_pair:
                            if _link_symbol_def(config.snapshot_second,
                                                mod_second,
                                                fun_pair["second"]):
                                simplify = True
                if prev_result_graph and not simplify:
                    # Note: "curr_result_graph" is here the partial result
                    # graph, i.e. can contain unknown results that are known in
                    # the graph from the previous comparison.
                    prev_result_graph.absorb_graph(curr_result_graph)
                    curr_result_graph = prev_result_graph

                    # Add the newly received results to the ignored functions
                    # file.
                    # Note: there won't be any duplicates, since all functions
                    # that were in the cache before will be marked as unknown.
                    if function_cache:
                        function_cache.update([
                            v for v in curr_result_graph.vertices.values()
                            if v.result not in
                            [Result.Kind.UNKNOWN, Result.Kind.ASSUMED_EQUAL]
                        ])

        objects_to_compare, syndiff_bodies_left, syndiff_bodies_right = \
            curr_result_graph.graph_to_fun_pair_list(fun_first, fun_second)

        mod_first.restore_unlinked_llvm()
        mod_second.restore_unlinked_llvm()

        if not objects_to_compare:
            result.kind = Result.Kind.EQUAL_SYNTAX
        else:
            # If the functions are not syntactically equal, objects_to_compare
            # contains a list of functions and macros that are different.
            for fun_pair in objects_to_compare:
                if (not fun_pair[0].diff_kind == "function"
                        and config.semdiff_tool is not None):
                    # If a semantic diff tool is set, use it for further
                    # comparison of non-equal functions
                    fun_result = functions_semdiff(first_simpl, second_simpl,
                                                   fun_pair[0].name,
                                                   fun_pair[1].name, config)
                else:
                    fun_result = Result(fun_pair[2], fun_first, fun_second)
                fun_result.first = fun_pair[0]
                fun_result.second = fun_pair[1]
                if fun_result.kind == Result.Kind.NOT_EQUAL:
                    if fun_result.first.diff_kind in ["function", "type"]:
                        # Get the syntactic diff of functions or types
                        fun_result.diff = syntax_diff(
                            fun_result.first.filename,
                            fun_result.second.filename, fun_result.first.name,
                            fun_result.first.diff_kind, fun_pair[0].line,
                            fun_pair[1].line)
                    elif fun_result.first.diff_kind == "syntactic":
                        # Find the syntax differences and append the left and
                        # right value to create the resulting diff
                        fun_result.diff = "  {}\n\n  {}\n".format(
                            syndiff_bodies_left[fun_result.first.name],
                            syndiff_bodies_right[fun_result.second.name])
                    else:
                        sys.stderr.write(
                            "warning: unknown diff kind: {}\n".format(
                                fun_result.first.diff_kind))
                        fun_result.diff = "unknown\n"
                result.add_inner(fun_result)
        if config.verbosity:
            print("  {}".format(result))
    except ValueError:
        result.kind = Result.Kind.ERROR
    except SimpLLException as e:
        if config.verbosity:
            print(e)
        result.kind = Result.Kind.ERROR
    result.graph = (curr_result_graph
                    if curr_result_graph else prev_result_graph)
    return result