def test_create_snapshot_from_source(): """Create a new kernel directory snapshot.""" kernel_dir = "kernel/linux-3.10.0-957.el7" output_dir = "snapshots/linux-3.10.0-957.el7" snap = Snapshot.create_from_source(kernel_dir, output_dir, None, False) assert snap.kernel_source is not None assert kernel_dir in snap.kernel_source.kernel_dir assert snap.snapshot_source is not None assert output_dir in snap.snapshot_source.kernel_dir assert snap.fun_kind is None assert len(snap.fun_groups) == 1 assert len(snap.fun_groups[None].functions) == 0 snap = Snapshot.create_from_source(kernel_dir, output_dir, "sysctl", False) assert snap.fun_kind == "sysctl" assert len(snap.fun_groups) == 0
def test_to_yaml_sysctls(): """ Dump a snapshot with multiple sysctl groups into YAML. YAML string should contain the version of Diffkemp, source kernel directory, a simple list of function groups, each one containing a function list with the "name", "llvm", "glob_var" and "tag" fields set, and the kind of this list, which should be a group list. The LLVM paths in the YAML should be relative to the snapshot directory. """ kernel_dir = "kernel/linux-3.10.0-957.el7" output_dir = "snapshots-sysctl/linux-3.10.0-957.el7" snap = Snapshot.create_from_source(kernel_dir, output_dir, KernelLlvmSourceBuilder, None, "sysctl", False) snap.add_fun_group("kernel.sched_latency_ns") snap.add_fun_group("kernel.timer_migration") snap.add_fun( "sched_proc_update_handler", LlvmModule("snapshots-sysctl/linux-3.10.0-957.el7/" "kernel/sched/fair.ll"), None, "proc handler", "kernel.sched_latency_ns") snap.add_fun( "proc_dointvec_minmax", LlvmModule("snapshots-sysctl/linux-3.10.0-957.el7/kernel/sysctl.ll"), None, "proc handler", "kernel.timer_migration") yaml_str = snap.to_yaml() yaml_snap = yaml.safe_load(yaml_str) assert len(yaml_snap) == 1 yaml_dict = yaml_snap[0] assert len(yaml_dict) == 7 assert yaml_dict["llvm_source_finder"]["kind"] == "kernel_with_builder" assert isinstance(yaml_dict["created_time"], datetime.datetime) assert len(yaml_dict["list"]) == 2 assert set([g["sysctl"] for g in yaml_dict["list"] ]) == {"kernel.sched_latency_ns", "kernel.timer_migration"} for g in yaml_dict["list"]: assert len(g["functions"]) == 1 if g["sysctl"] == "kernel.sched_latency_ns": assert g["functions"][0] == { "name": "sched_proc_update_handler", "llvm": "kernel/sched/fair.ll", "glob_var": None, "tag": "proc handler" } elif g["sysctl"] == "kernel.timer_migration": assert g["functions"][0] == { "name": "proc_dointvec_minmax", "llvm": "kernel/sysctl.ll", "glob_var": None, "tag": "proc handler" }
def test_add_sysctl_fun_group(): """Create a snapshot and check the creation of a sysctl function group.""" kernel_dir = "kernel/linux-3.10.0-957.el7" output_dir = "snapshots/linux-3.10.0-957.el7" snap = Snapshot.create_from_source(kernel_dir, output_dir, "sysctl", False) snap.add_fun_group("kernel.sched_latency_ns") assert len(snap.fun_groups) == 1 assert "kernel.sched_latency_ns" in snap.fun_groups
def test_filter(): """Filter snapshot functions.""" kernel_dir = "kernel/linux-3.10.0-957.el7" output_dir = "snapshots/linux-3.10.0-957.el7" snap = Snapshot.create_from_source(kernel_dir, output_dir, None, False) snap.add_fun("___pskb_trim", LlvmKernelModule("net/core/skbuff.ll")) snap.add_fun("__alloc_pages_nodemask", LlvmKernelModule("mm/page_alloc.ll")) snap.filter(["__alloc_pages_nodemask"]) assert len(snap.fun_groups[None].functions) == 1 assert "___pskb_trim" not in snap.fun_groups[None].functions assert "__alloc_pages_nodemask" in snap.fun_groups[None].functions
def test_add_fun_none_group(): """Create a snapshot and try to add functions into a None group.""" kernel_dir = "kernel/linux-3.10.0-957.el7" output_dir = "snapshots/linux-3.10.0-957.el7" snap = Snapshot.create_from_source(kernel_dir, output_dir, None, False) mod = LlvmKernelModule("net/core/skbuff.ll") snap.add_fun("___pskb_trim", mod) assert "___pskb_trim" in snap.fun_groups[None].functions fun_desc = snap.fun_groups[None].functions["___pskb_trim"] assert fun_desc.mod is mod assert fun_desc.glob_var is None assert fun_desc.tag is None
def test_get_by_name_functions(): """Get the module of inserted function by its name.""" kernel_dir = "kernel/linux-3.10.0-957.el7" output_dir = "snapshots/linux-3.10.0-957.el7" snap = Snapshot.create_from_source(kernel_dir, output_dir, None, False) mod_buff = LlvmKernelModule("net/core/skbuff.ll") mod_alloc = LlvmKernelModule("mm/page_alloc.ll") snap.add_fun("___pskb_trim", mod_buff) snap.add_fun("__alloc_pages_nodemask", mod_alloc) fun = snap.get_by_name("___pskb_trim") assert fun.mod is mod_buff fun = snap.get_by_name("__alloc_pages_nodemask") assert fun.mod is mod_alloc
def test_add_fun_sysctl_group(): """Create a snapshot and try to add functions into sysctl groups.""" kernel_dir = "kernel/linux-3.10.0-957.el7" output_dir = "snapshots/linux-3.10.0-957.el7" snap = Snapshot.create_from_source(kernel_dir, output_dir, "sysctl", False) snap.add_fun_group("kernel.sched_latency_ns") mod = LlvmKernelModule("kernel/sched/debug.ll") snap.add_fun("sched_debug_header", mod, "sysctl_sched_latency", "using_data_variable \"sysctl_sched_latency\"", "kernel.sched_latency_ns") assert "sched_debug_header" in snap.fun_groups[ "kernel.sched_latency_ns"].functions fun_desc = snap.fun_groups["kernel.sched_latency_ns"].functions[ "sched_debug_header"] assert fun_desc.mod is mod assert fun_desc.glob_var == "sysctl_sched_latency" assert fun_desc.tag == "using_data_variable \"sysctl_sched_latency\""
def test_to_yaml_functions(): """ Dump a snapshot with a single "None" group into YAML. YAML string should contain the version of Diffkemp, source kernel directory, a simple list of functions, each one having the "name", "llvm", "glob_var" and "tag" fields set, and the kind of this list, which should be a function list. The LLVM paths in the YAML should be relative to the snapshot directory. """ kernel_dir = "kernel/linux-3.10.0-957.el7" output_dir = "snapshots/linux-3.10.0-957.el7" snap = Snapshot.create_from_source(kernel_dir, output_dir, KernelLlvmSourceBuilder, None, None, False) snap.add_fun( "___pskb_trim", LlvmModule("snapshots/linux-3.10.0-957.el7/net/core/skbuff.ll")) snap.add_fun("__alloc_pages_nodemask", LlvmModule("snapshots/linux-3.10.0-957.el7/mm/page_alloc.ll")) yaml_str = snap.to_yaml() yaml_snap = yaml.safe_load(yaml_str) assert len(yaml_snap) == 1 yaml_dict = yaml_snap[0] assert len(yaml_dict) == 7 assert isinstance(yaml_dict["created_time"], datetime.datetime) assert yaml_dict["llvm_source_finder"]["kind"] == "kernel_with_builder" assert len(yaml_dict["list"]) == 2 assert set([f["name"] for f in yaml_dict["list"]]) ==\ {"___pskb_trim", "__alloc_pages_nodemask"} for f in yaml_dict["list"]: if f["name"] == "___pskb_trim": assert f["llvm"] == "net/core/skbuff.ll" elif f["name"] == "__alloc_pages_nodemask": assert f["llvm"] == "mm/page_alloc.ll"
def test_get_by_name_sysctls(): """Get the module of inserted function by its name and sysctl group.""" kernel_dir = "kernel/linux-3.10.0-957.el7" output_dir = "snapshots/linux-3.10.0-957.el7" snap = Snapshot.create_from_source(kernel_dir, output_dir, "sysctl", False) snap.add_fun_group("kernel.sched_latency_ns") snap.add_fun_group("kernel.timer_migration") mod_fair = LlvmKernelModule( "snapshots-sysctl/linux-3.10.0-957.el7/kernel/sched/fair.ll") mod_sysctl = LlvmKernelModule( "snapshots-sysctl/linux-3.10.0-957.el7/kernel/sysctl.ll") snap.add_fun("sched_proc_update_handler", mod_fair, None, "proc handler", "kernel.sched_latency_ns") snap.add_fun("proc_dointvec_minmax", mod_sysctl, None, "proc handler", "kernel.timer_migration") # Test that the function fun = snap.get_by_name("proc_dointvec_minmax", "kernel.sched_latency_ns") assert fun is None fun = snap.get_by_name("proc_dointvec_minmax", "kernel.timer_migration") assert fun.mod is mod_sysctl
def test_get_modules(): """ Test getting all modules in the snapshot function lists. Check if the snapshot returns a list of all modules of all groups in case that multiple groups are present. """ kernel_dir = "kernel/linux-3.10.0-957.el7" output_dir = "snapshots/linux-3.10.0-957.el7" snap = Snapshot.create_from_source(kernel_dir, output_dir, "sysctl", False) snap.add_fun_group("kernel.sched_latency_ns") snap.add_fun_group("kernel.timer_migration") snap.add_fun("sched_proc_update_handler", LlvmKernelModule("kernel/sched/fair.ll"), None, "proc_handler", "kernel.sched_latency_ns") snap.add_fun("proc_dointvec_minmax", LlvmKernelModule("kernel/sysctl.ll"), None, "proc_handler", "kernel.timer_migration") modules = snap.modules() assert len(modules) == 2 assert set([m.llvm for m in modules ]) == {"kernel/sched/fair.ll", "kernel/sysctl.ll"}
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 """ # Create a new snapshot from the source directory. snapshot = Snapshot.create_from_source(args.kernel_dir, args.output_dir, "sysctl" if args.sysctl else None) source = snapshot.kernel_source # Build sources for symbols from the list into LLVM IR with open(args.functions_list, "r") as fun_list_file: for line in fun_list_file.readlines(): symbol = line.strip() if not symbol or not (symbol[0].isalpha() or symbol[0] == "_"): continue if args.sysctl: # For a sysctl parameter, we have to: # - get LLVM of a file which defines the sysctl option # - find and compile proc handler function and add it to the # snapshot # - find sysctl data variable # - find, complile, and add to snapshot all functions that # use the data variable # Get module with sysctl definitions try: sysctl_mod = source.get_sysctl_module(symbol) except SourceNotFoundException: print("{}: sysctl not supported".format(symbol)) # Iterate all sysctls represented by the symbol (it can be # a pattern). sysctl_list = sysctl_mod.parse_sysctls(symbol) if not sysctl_list: print("{}: no sysctl found".format(symbol)) for sysctl in sysctl_list: print("{}:".format(sysctl)) # New group in function list for the sysctl snapshot.add_fun_group(sysctl) # Proc handler function for sysctl proc_fun = sysctl_mod.get_proc_fun(sysctl) if proc_fun: try: proc_fun_mod = source.get_module_for_symbol( proc_fun) snapshot.add_fun(name=proc_fun, llvm_mod=proc_fun_mod, glob_var=None, tag="proc handler function", group=sysctl) print(" {}: {} (proc handler)".format( proc_fun, os.path.relpath(proc_fun_mod.llvm, args.kernel_dir))) except SourceNotFoundException: print(" could not build proc handler") # Functions using the sysctl data variable data = sysctl_mod.get_data(sysctl) if not data: continue for data_src in source.find_srcs_using_symbol(data.name): data_mod = source.get_module_from_source(data_src) if not data_mod: continue for data_fun in \ data_mod.get_functions_using_param(data): if data_fun == proc_fun: continue snapshot.add_fun(name=data_fun, llvm_mod=data_mod, glob_var=data.name, tag="function using sysctl data " "variable \"{}\"".format( data.name), group=sysctl) print( " {}: {} (using data variable \"{}\")".format( data_fun, os.path.relpath(data_mod.llvm, args.kernel_dir), data.name)) else: try: # For a normal function, we compile its source and include # it into the snapshot sys.stdout.write("{}: ".format(symbol)) llvm_mod = source.get_module_for_symbol(symbol) if not llvm_mod.has_function(symbol): print("unsupported") continue print(os.path.relpath(llvm_mod.llvm, args.kernel_dir)) snapshot.add_fun(symbol, llvm_mod) except SourceNotFoundException: print("source not found") snapshot.add_fun(symbol, None) snapshot.generate_snapshot_dir() snapshot.finalize()