def test_get_functions_using_param(mod):
    """Test finding functions using a parameter (global variable)."""
    param = KernelParam("major")
    funs = mod.get_functions_using_param(param)
    assert funs == {
        "snd_register_device", "alsa_sound_init", "alsa_sound_exit"
    }
Exemple #2
0
    def _get_global_variable_at_index(self, sysctl_name, index):
        """
        Find sysctl with given name and get its element at the given index.
        The element is expected to be a global variable.
        :param sysctl_name: Name of the sysctl to be found.
        :param index: Index to look for.
        :return: KernelParam object with the given global variable description.
        """
        # Get the sysctl entry
        sysctl = self._get_sysctl(sysctl_name)
        if not sysctl or sysctl.get_num_operands() <= index:
            return None
        # Get operand at the given index
        data = sysctl.get_operand(index)
        if data.is_null():
            return None
        indices = None

        # Address is a GEP, we have to extract the actual variable.
        if (data.get_kind() == ConstantExprValueKind
                and data.get_const_opcode() == Opcode['GetElementPtr']):
            all_constant = True
            indices = list()
            # Look whether are all indices constant.
            for i in range(1, data.get_num_operands()):
                indices.append(data.get_operand(i).const_int_get_z_ext())
                if not data.get_operand(i).is_constant():
                    all_constant = False
            if all_constant:
                data = data.get_operand(0)

        # Address is typed to "void *", we need to get rid of the bitcast
        # operator.
        if (data.get_kind() == ConstantExprValueKind
                and data.get_const_opcode() == Opcode['BitCast']):
            data = data.get_operand(0)

        if data.get_kind() == GlobalVariableValueKind:
            data = data.get_name().decode("utf-8")
            return KernelParam(data, indices)
        return None
Exemple #3
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
def test_get_functions_using_param_with_index(source):
    """Test finding functions using a component of a parameter."""
    mod = source.get_module_from_source("net/core/sysctl_net_core.c")
    param = KernelParam("netdev_rss_key", [0, 0])
    funs = mod.get_functions_using_param(param)
    assert funs == {"proc_do_rss_key"}
 def get_data(self, sysctl_name):
     """Get the name of the data variable for the given sysctl option."""
     result = self.table_object.get_data(sysctl_name)
     return (KernelParam(result[0], result[1])
             if result is not None else None)
 def get_child(self, sysctl_name):
     """Get the name of the child node of the given sysctl table entry."""
     result = self.table_object.get_child(sysctl_name)
     return (KernelParam(result[0], result[1])
             if result is not None else None)