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" }
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
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)