--- /dev/null	Fri Dec 21 15:00:04 2018
+++ new/usr/src/tools/smatch/src/check_implicit_dependencies.c	Fri Dec 21 15:00:04 2018
@@ -0,0 +1,309 @@
+#include "smatch.h"
+#include "smatch_slist.h"
+
+static int my_id;
+
+/* If set, we ignore struct type symbols as implicit dependencies */
+static int ignore_structs;
+
+static struct symbol *cur_syscall;
+/* note: cannot track return type and remove from implicit dependencies,
+ * because every syscall returns a long, and we don't have a good way to know
+ * whether or not this is a resource. The only example I can think of is open
+ * returning a filedescriptor, so in the implicit dep parsing, we will just
+ * blacklist struct fd --> file
+ */
+static struct symbol *cur_return_type;
+static char *syscall_name;
+
+static struct tracker_list *read_list;	// what fields does syscall branch on?
+static struct tracker_list *write_list; // what fields does syscall modify?
+static struct tracker_list *arg_list;	// what struct arguments does the syscall take?
+static struct tracker_list *parsed_syscalls; // syscalls we have already checked
+
+static inline void prefix(void)
+{
+	printf("%s:%d %s() ", get_filename(), get_lineno(), get_function());
+}
+
+static void match_syscall_definition(struct symbol *sym)
+{
+	struct symbol *arg;
+	struct tracker *tracker;
+	char *macro;
+	char *name;
+	int is_syscall = 0;
+
+	macro = get_macro_name(sym->pos);
+	if (macro &&
+	    (strncmp("SYSCALL_DEFINE", macro, strlen("SYSCALL_DEFINE")) == 0 ||
+	     strncmp("COMPAT_SYSCALL_DEFINE", macro, strlen("COMPAT_SYSCALL_DEFINE")) == 0))
+		is_syscall = 1;
+
+	name = get_function();
+
+	if (name && strncmp(name, "sys_", 4) == 0)
+		is_syscall = 1;
+
+	if (name && strncmp(name, "compat_sys_", 11) == 0)
+		is_syscall = 1;
+
+	if (!is_syscall)
+		return;
+
+	FOR_EACH_PTR(parsed_syscalls, tracker) {
+		if (tracker->sym == sym) // don't re-parse
+			return;
+	} END_FOR_EACH_PTR(tracker);
+
+	syscall_name = name;
+	cur_syscall = sym;
+
+	cur_return_type = cur_func_return_type();
+	if (cur_return_type && cur_return_type->ident)
+		sm_msg("return type: %s\n", cur_return_type->ident->name);
+
+
+	FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
+		// set_state(my_id, arg->ident->name, arg, &user_data_set);
+		sm_msg("=======check_impl: arguments for call %s=========\n", syscall_name);
+		if (arg->type == SYM_STRUCT)
+			arg = get_real_base_type(arg);
+		if (cur_return_type && cur_return_type->ident)
+			sm_msg("arg type: %s\n", cur_return_type->ident->name);
+		// add_tracker(&arg_list, my_id, member, arg);
+		sm_msg("=================================\n");
+	} END_FOR_EACH_PTR(arg);
+}
+
+static void print_read_list(void)
+{
+    struct tracker *tracker;
+    int i = 0;
+
+    FOR_EACH_PTR(read_list, tracker) {
+	    if (i == 0)
+		    sm_printf("%s read_list: [", syscall_name);
+	    sm_printf("%s, ", tracker->name);
+	    i++;
+    } END_FOR_EACH_PTR(tracker);
+
+    if (i > 0)
+	    sm_printf("]\n");
+}
+
+static void print_write_list(void)
+{
+	struct tracker *tracker;
+	int i = 0;
+
+	FOR_EACH_PTR(write_list, tracker) {
+		if (i == 0)
+			sm_printf("%s write_list: [", syscall_name);
+		sm_printf("%s, ", tracker->name);
+		i++;
+	} END_FOR_EACH_PTR(tracker);
+
+	if (i > 0)
+		sm_printf("]\n");
+}
+
+static void print_arg_list(void)
+{
+	struct tracker *tracker;
+	int i = 0;
+
+	FOR_EACH_PTR(write_list, tracker) {
+		if (i == 0)
+			sm_printf("%s arg_list: [", syscall_name);
+		sm_printf("%s, ", tracker->name);
+		i++;
+	} END_FOR_EACH_PTR(tracker);
+
+	if (i > 0)
+		sm_printf("]\n");
+}
+
+static void match_after_syscall(struct symbol *sym)
+{
+	if (!cur_syscall || sym != cur_syscall)
+		return;
+	// printf("\n"); prefix();
+	// printf("exiting scope of syscall %s\n", get_function());
+	// printf("-------------------------\n");
+	print_read_list();
+	print_write_list();
+	print_arg_list();
+	free_trackers_and_list(&read_list);
+	free_trackers_and_list(&write_list);
+	free_trackers_and_list(&arg_list);
+	add_tracker(&parsed_syscalls, my_id, syscall_name, sym);
+	cur_syscall = NULL;
+	cur_return_type = NULL;
+	syscall_name = NULL;
+}
+
+static void print_read_member_type(struct expression *expr)
+{
+	char *member;
+	struct symbol *sym;
+	struct symbol *member_sym;
+
+	member = get_member_name(expr);
+	if (!member)
+		return;
+
+	sym = get_type(expr->deref);
+	member_sym = get_type(expr);
+
+	if (member_sym->type == SYM_PTR)
+		member_sym = get_real_base_type(member_sym);
+
+	/*
+	if (member_sym->type == SYM_STRUCT)
+		printf("found struct type %s\n", member);
+	else
+		printf("found non-struct type %s with enum value%d\n", member, member_sym->type);
+	*/
+
+	if (ignore_structs && member_sym->type == SYM_STRUCT) {
+		// printf("ignoring %s\n", member);
+		return;
+	}
+
+	add_tracker(&read_list, my_id, member, sym);
+	// sm_msg("info: uses %s", member);
+	// prefix();
+	// printf("info: uses %s\n", member);
+	free_string(member);
+}
+
+static void print_write_member_type(struct expression *expr)
+{
+	char *member;
+	struct symbol *sym;
+	struct symbol *member_sym;
+
+	member = get_member_name(expr);
+	if (!member)
+		return;
+
+	sym = get_type(expr->deref);
+	member_sym = get_type(expr);
+
+	if (member_sym->type == SYM_PTR)
+		member_sym = get_real_base_type(member_sym);
+
+	/*
+	if (member_sym->type == SYM_STRUCT)
+		printf("found struct type %s\n", member);
+	else
+		printf("found non-struct type %s with enum value%d\n", member, member_sym->type);
+	*/
+
+	if (ignore_structs && member_sym->type == SYM_STRUCT) {
+		// printf("ignoring %s\n", member);
+		return;
+	}
+
+	add_tracker(&write_list, my_id, member, sym);
+	free_string(member);
+}
+
+static void match_condition(struct expression *expr)
+{
+	struct expression *arg;
+
+	if (!cur_syscall)
+		return;
+
+	// prefix(); printf("-- condition found\n");
+
+	if (expr->type == EXPR_COMPARE ||
+	    expr->type == EXPR_BINOP ||
+	    expr->type == EXPR_LOGICAL ||
+	    expr->type == EXPR_ASSIGNMENT ||
+	    expr->type == EXPR_COMMA) {
+		match_condition(expr->left);
+		match_condition(expr->right);
+		return;
+	}
+
+	if (expr->type == EXPR_CALL) {
+		FOR_EACH_PTR(expr->args, arg) {
+			// if we find deref in conditional call,
+			// mark it as a read dependency
+			print_read_member_type(arg);
+		} END_FOR_EACH_PTR(arg);
+		return;
+	}
+
+	print_read_member_type(expr);
+}
+
+
+/* when we are parsing an inline function and can no longer nest,
+ * assume that all struct fields passed to nested inline functions
+ * are read dependencies
+ */
+static void match_call_info(struct expression *expr)
+{
+	struct expression *arg;
+	int i;
+
+	if (!__inline_fn || !cur_syscall)
+		return;
+
+	// prefix(); printf("fn: %s\n", expr->fn->symbol->ident->name);
+
+	i = 0;
+	FOR_EACH_PTR(expr->args, arg) {
+		/*
+		   if (arg->type == EXPR_DEREF)
+		   printf("arg %d is deref\n", i);
+		 */
+		print_read_member_type(arg);
+		i++;
+	} END_FOR_EACH_PTR(arg);
+}
+
+static void match_assign_value(struct expression *expr)
+{
+	if (!cur_syscall)
+		return;
+	print_write_member_type(expr->left);
+}
+
+static void unop_expr(struct expression *expr)
+{
+	if (!cur_syscall)
+		return;
+
+	if (expr->op == SPECIAL_ADD_ASSIGN || expr->op == SPECIAL_INCREMENT ||
+	    expr->op == SPECIAL_SUB_ASSIGN || expr->op == SPECIAL_DECREMENT ||
+	    expr->op == SPECIAL_MUL_ASSIGN || expr->op == SPECIAL_DIV_ASSIGN ||
+	    expr->op == SPECIAL_MOD_ASSIGN || expr->op == SPECIAL_AND_ASSIGN ||
+	    expr->op == SPECIAL_OR_ASSIGN || expr->op == SPECIAL_XOR_ASSIGN ||
+	    expr->op == SPECIAL_SHL_ASSIGN || expr->op == SPECIAL_SHR_ASSIGN)
+		print_write_member_type(strip_expr(expr->unop));
+}
+
+void check_implicit_dependencies(int id)
+{
+	my_id = id;
+	ignore_structs = 0;
+
+	if (option_project != PROJ_KERNEL)
+		return;
+	if (!option_info)
+		return;
+
+	add_hook(&match_syscall_definition, AFTER_DEF_HOOK);
+	add_hook(&match_after_syscall, AFTER_FUNC_HOOK);
+	add_hook(&match_condition, CONDITION_HOOK);
+	add_hook(&match_call_info, FUNCTION_CALL_HOOK);
+
+	/* hooks to track written fields */
+	add_hook(&match_assign_value, ASSIGNMENT_HOOK_AFTER);
+	add_hook(&unop_expr, OP_HOOK);
+}
