Ejemplo n.º 1
0
    def create_from_source(cls, kernel_dir, output_dir, fun_kind=None,
                           setup_dir=True):
        """
        Create a snapshot from a kernel source directory and prepare it for
        snapshot directory generation.
        :param kernel_dir: Source kernel directory.
        :param output_dir: Snapshot output directory.
        :param fun_kind: Snapshot function kind.
        :param setup_dir: Whether to recreate the output directory.
        :return: Desired instance of Snapshot.
        """
        output_path = os.path.abspath(output_dir)

        # Cleanup or create the output directory of the new snapshot.
        if setup_dir:
            if os.path.isdir(output_path):
                shutil.rmtree(output_path)
            os.mkdir(output_path)

        # Prepare source representations for the new snapshot
        kernel_source = KernelSource(kernel_dir, True)
        snapshot_source = KernelSource(output_path)

        kernel_snapshot = cls(kernel_source, snapshot_source, fun_kind)

        # Add a new None group to the snapshot if the function kind is None.
        if fun_kind is None:
            kernel_snapshot._add_none_group()

        return kernel_snapshot
Ejemplo n.º 2
0
def mod():
    """
    Build LlvmSysctlModule for net.core.* sysctl options shared among tests.
    """
    source = KernelSource("kernel/linux-3.10.0-862.el7", True)
    kernel_module = source.get_module_from_source("net/core/sysctl_net_core.c")
    yield LlvmSysctlModule(kernel_module, "net_core_table")
    source.finalize()
Ejemplo n.º 3
0
def test_find_param_var():
    """
    Test finding the name of a variable corresponding to a module parameter.
    This is necessary since for parameters defined with module_param_named,
    names of the parameter and of the variable differ.
    """
    source = KernelSource("kernel/linux-3.10", True)
    mod = source.get_module_from_source("net/rfkill/core.c")
    assert mod.find_param_var("default_state").name == "rfkill_default_state"
Ejemplo n.º 4
0
    def _from_yaml(self, yaml_file):
        """
        Load the snaphot from its YAML representation. Paths are assumed to be
        relative to the root directory.
        :param yaml_file: Contents of the YAML file.
        """
        yaml_file = yaml.safe_load(yaml_file)
        yaml_dict = yaml_file[0]

        self.created_time = yaml_dict["created_time"]

        if os.path.isdir(yaml_dict["source_kernel_dir"]):
            self.kernel_source = KernelSource(yaml_dict["source_kernel_dir"],
                                              True)

        for g in yaml_dict["list"]:
            if "sysctl" in g:
                self.kind = "sysctl"
                group = g["sysctl"]
                functions = g["functions"]
            else:
                group = None
                functions = yaml_dict["list"]
            self.fun_groups[group] = self.FunctionGroup()
            for f in functions:
                self.add_fun(
                    f["name"],
                    LlvmKernelModule(
                        os.path.join(
                            os.path.relpath(self.snapshot_source.kernel_dir),
                            f["llvm"])) if f["llvm"] else None, f["glob_var"],
                    f["tag"], group)
Ejemplo n.º 5
0
    def __init__(self, spec, task_name, tasks_path, kernel_path):
        self.old_kernel_dir = os.path.join(kernel_path, spec["old_kernel"])
        self.new_kernel_dir = os.path.join(kernel_path, spec["new_kernel"])
        self.name = task_name
        self.task_dir = os.path.join(tasks_path, task_name)
        if "control_flow_only" in spec:
            self.control_flow_only = spec["control_flow_only"]
        else:
            self.control_flow_only = False

        # Create LLVM sources and configuration
        self.old_kernel = KernelSource(self.old_kernel_dir, True)
        self.new_kernel = KernelSource(self.new_kernel_dir, True)
        self.config = Config(self.old_kernel, self.new_kernel, False,
                             self.control_flow_only, False, None)

        self.functions = dict()
Ejemplo n.º 6
0
def generate(args):
    """
    Generate snapshot of sources of kernel functions.
    This involves:
      - find source code with functions definitions
      - compile the source codes into LLVM IR
      - copy LLVM and C source files into snapshot directory
      - create YAML with list mapping functions to their LLVM sources
    """
    source = KernelSource(args.kernel_dir, True)
    args.output_dir = os.path.abspath(args.output_dir)
    fun_list = FunctionList(args.output_dir)

    # Cleanup or create the output directory
    if os.path.isdir(args.output_dir):
        shutil.rmtree(args.output_dir)
    os.mkdir(args.output_dir)

    # Build sources for functions from the list into LLVM IR
    with open(args.functions_list, "r") as fun_list_file:
        for line in fun_list_file.readlines():
            fun = line.strip()
            if not fun or not (fun[0].isalpha() or fun[0] == "_"):
                continue
            sys.stdout.write("{}: ".format(fun))
            try:
                llvm_mod = source.get_module_for_symbol(fun)
                print(os.path.relpath(llvm_mod.llvm, args.kernel_dir))
                fun_list.add(fun, llvm_mod)
            except SourceNotFoundException:
                print("source not found")

    # Copy LLVM files to the snapshot
    source.copy_source_files(fun_list.modules(), args.output_dir)
    source.copy_cscope_files(args.output_dir)

    # Create YAML with functions list
    with open(os.path.join(args.output_dir, "functions.yaml"),
              "w") as fun_list_yaml:
        fun_list_yaml.write(fun_list.to_yaml())

    source.finalize()
Ejemplo n.º 7
0
    def load_from_dir(cls, snapshot_dir, config_file="snapshot.yaml"):
        """
        Loads a snapshot from its directory.
        :param snapshot_dir: Target snapshot directory.
        :param config_file: Name of the snapshot configuration file.
        :return: Desired instance of Snapshot.
        """
        snapshot_source = KernelSource(snapshot_dir)
        loaded_snapshot = cls(None, snapshot_source)

        with open(os.path.join(snapshot_dir, config_file), "r") as \
                snapshot_yaml:
            loaded_snapshot._from_yaml(snapshot_yaml.read())

        return loaded_snapshot
Ejemplo n.º 8
0
def test_syntax_diff():
    f = "dio_iodone2_helper"
    diff = ('*************** static void dio_iodone2_helper(struct dio *dio, l'
            'off_t offset,\n*** 246,250 ***\n  {\n! \tif (dio->end_io && dio->'
            'result)\n! \t\tdio->end_io(dio->iocb, offset,\n! \t\t\t\ttransfer'
            'red, dio->private, ret, is_async);\n  \n--- 246,249 ---\n  {\n! '
            '\tif (dio->end_io)\n! \t\tdio->end_io(dio->iocb, offset, ret, dio'
            '->private, 0, 0);\n  \n')

    source_first = KernelSource("kernel/linux-3.10.0-862.el7", True)
    source_second = KernelSource("kernel/linux-3.10.0-957.el7", True)
    config = Config(source_first, source_second, show_diff=True,
                    control_flow_only=True, verbosity=False, semdiff_tool=None)
    first = source_first.get_module_for_symbol(f)
    second = source_second.get_module_for_symbol(f)
    fun_result = functions_diff(mod_first=first, mod_second=second,
                                fun_first=f, fun_second=f, glob_var=None,
                                config=config)
    assert fun_result.inner[f].diff == diff
Ejemplo n.º 9
0
def source():
    """Create KernelSource shared among multiple tests."""
    s = KernelSource("kernel/linux-3.10.0-957.el7", True)
    yield s
    s.finalize()
Ejemplo n.º 10
0
class TaskSpec:
    """
    Task specification representing testing scenario.
    Contains a list of functions to be compared with DiffKemp during the test.
    """
    def __init__(self, spec, task_name, tasks_path, kernel_path):
        self.old_kernel_dir = os.path.join(kernel_path, spec["old_kernel"])
        self.new_kernel_dir = os.path.join(kernel_path, spec["new_kernel"])
        self.name = task_name
        self.task_dir = os.path.join(tasks_path, task_name)
        if "control_flow_only" in spec:
            self.control_flow_only = spec["control_flow_only"]
        else:
            self.control_flow_only = False

        # Create LLVM sources and configuration
        self.old_kernel = KernelSource(self.old_kernel_dir, True)
        self.new_kernel = KernelSource(self.new_kernel_dir, True)
        self.old_snapshot = Snapshot(self.old_kernel, self.old_kernel)
        self.new_snapshot = Snapshot(self.new_kernel, self.new_kernel)
        self.config = Config(self.old_snapshot, self.new_snapshot, False,
                             False, self.control_flow_only, False, False,
                             False, None)

        self.functions = dict()

    def finalize(self):
        """
        Task finalization - should be called before the task is destroyed.
        """
        self.old_kernel.finalize()
        self.new_kernel.finalize()

    def add_function_spec(self, fun, result):
        """Add a function comparison specification."""
        self.functions[fun] = FunctionSpec(fun, result)

    def build_modules_for_function(self, fun):
        """
        Build LLVM modules containing definition of the compared function in
        both kernels.
        """
        # Since PyTest may share KernelSource objects among tasks, we need
        # to explicitly initialize kernels.
        self.old_kernel.initialize()
        self.new_kernel.initialize()
        mod_old = self.old_kernel.get_module_for_symbol(fun)
        mod_new = self.new_kernel.get_module_for_symbol(fun)
        self.functions[fun].old_module = mod_old
        self.functions[fun].new_module = mod_new
        return mod_old, mod_new

    def _file_name(self, suffix, ext, name=None):
        """
        Get name of a task file having the given name, suffix, and extension.
        """
        return os.path.join(self.task_dir,
                            "{}_{}.{}".format(name or self.name, suffix, ext))

    def old_llvm_file(self, name=None):
        """Name of the old LLVM file in the task dir."""
        return self._file_name("old", "ll", name)

    def new_llvm_file(self, name=None):
        """Name of the new LLVM file in the task dir."""
        return self._file_name("new", "ll", name)

    def old_src_file(self, name=None):
        """Name of the old C file in the task dir."""
        return self._file_name("old", "c", name)

    def new_src_file(self, name=None):
        """Name of the new C file in the task dir."""
        return self._file_name("new", "c", name)

    def prepare_dir(self, old_module, new_module, old_src, new_src, name=None):
        """
        Create the task directory and copy the LLVM and the C files there.
        :param old_module: Old LLVM module (instance of LlvmKernelModule).
        :param old_src: C source from the old kernel version to be copied.
        :param new_module: New LLVM module (instance of LlvmKernelModule).
        :param new_src: C source from the new kernel version to be copied.
        :param name: Optional parameter to specify the new file names. If None
                     then the spec name is used.
        """
        if not os.path.isdir(self.task_dir):
            os.mkdir(self.task_dir)

        if not os.path.isfile(self.old_llvm_file(name)):
            shutil.copyfile(old_module.llvm, self.old_llvm_file(name))
        if old_src and not os.path.isfile(self.old_src_file(name)):
            shutil.copyfile(old_src, self.old_src_file(name))
        if not os.path.isfile(self.new_llvm_file(name)):
            shutil.copyfile(new_module.llvm, self.new_llvm_file(name))
        if new_src and not os.path.isfile(self.new_src_file(name)):
            shutil.copyfile(new_src, self.new_src_file(name))
Ejemplo n.º 11
0
def source():
    s = KernelSource("kernel/linux-3.10.0-957.el7", True)
    yield s
    s.finalize()
Ejemplo n.º 12
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
Ejemplo n.º 13
0
def test_get_child():
    """Test getting child of a sysctl definition."""
    source = KernelSource("kernel/linux-3.10.0-862.el7", True)
    kernel_module = source.get_module_from_source("kernel/sysctl.c")
    sysctl_module = LlvmSysctlModule(kernel_module, "sysctl_base_table")
    assert sysctl_module.get_child("vm").name == "vm_table"