1*1f5207b7SJohn Levon #include "smatch.h"
2*1f5207b7SJohn Levon #include "smatch_slist.h"
3*1f5207b7SJohn Levon 
4*1f5207b7SJohn Levon static int my_id;
5*1f5207b7SJohn Levon 
6*1f5207b7SJohn Levon /* If set, we ignore struct type symbols as implicit dependencies */
7*1f5207b7SJohn Levon static int ignore_structs;
8*1f5207b7SJohn Levon 
9*1f5207b7SJohn Levon static struct symbol *cur_syscall;
10*1f5207b7SJohn Levon /* note: cannot track return type and remove from implicit dependencies,
11*1f5207b7SJohn Levon  * because every syscall returns a long, and we don't have a good way to know
12*1f5207b7SJohn Levon  * whether or not this is a resource. The only example I can think of is open
13*1f5207b7SJohn Levon  * returning a filedescriptor, so in the implicit dep parsing, we will just
14*1f5207b7SJohn Levon  * blacklist struct fd --> file
15*1f5207b7SJohn Levon  */
16*1f5207b7SJohn Levon static struct symbol *cur_return_type;
17*1f5207b7SJohn Levon static char *syscall_name;
18*1f5207b7SJohn Levon 
19*1f5207b7SJohn Levon static struct tracker_list *read_list;	// what fields does syscall branch on?
20*1f5207b7SJohn Levon static struct tracker_list *write_list; // what fields does syscall modify?
21*1f5207b7SJohn Levon static struct tracker_list *arg_list;	// what struct arguments does the syscall take?
22*1f5207b7SJohn Levon static struct tracker_list *parsed_syscalls; // syscalls we have already checked
23*1f5207b7SJohn Levon 
prefix(void)24*1f5207b7SJohn Levon static inline void prefix(void)
25*1f5207b7SJohn Levon {
26*1f5207b7SJohn Levon 	printf("%s:%d %s() ", get_filename(), get_lineno(), get_function());
27*1f5207b7SJohn Levon }
28*1f5207b7SJohn Levon 
match_syscall_definition(struct symbol * sym)29*1f5207b7SJohn Levon static void match_syscall_definition(struct symbol *sym)
30*1f5207b7SJohn Levon {
31*1f5207b7SJohn Levon 	struct symbol *arg;
32*1f5207b7SJohn Levon 	struct tracker *tracker;
33*1f5207b7SJohn Levon 	char *macro;
34*1f5207b7SJohn Levon 	char *name;
35*1f5207b7SJohn Levon 	int is_syscall = 0;
36*1f5207b7SJohn Levon 
37*1f5207b7SJohn Levon 	macro = get_macro_name(sym->pos);
38*1f5207b7SJohn Levon 	if (macro &&
39*1f5207b7SJohn Levon 	    (strncmp("SYSCALL_DEFINE", macro, strlen("SYSCALL_DEFINE")) == 0 ||
40*1f5207b7SJohn Levon 	     strncmp("COMPAT_SYSCALL_DEFINE", macro, strlen("COMPAT_SYSCALL_DEFINE")) == 0))
41*1f5207b7SJohn Levon 		is_syscall = 1;
42*1f5207b7SJohn Levon 
43*1f5207b7SJohn Levon 	name = get_function();
44*1f5207b7SJohn Levon 
45*1f5207b7SJohn Levon 	if (name && strncmp(name, "sys_", 4) == 0)
46*1f5207b7SJohn Levon 		is_syscall = 1;
47*1f5207b7SJohn Levon 
48*1f5207b7SJohn Levon 	if (name && strncmp(name, "compat_sys_", 11) == 0)
49*1f5207b7SJohn Levon 		is_syscall = 1;
50*1f5207b7SJohn Levon 
51*1f5207b7SJohn Levon 	if (!is_syscall)
52*1f5207b7SJohn Levon 		return;
53*1f5207b7SJohn Levon 
54*1f5207b7SJohn Levon 	FOR_EACH_PTR(parsed_syscalls, tracker) {
55*1f5207b7SJohn Levon 		if (tracker->sym == sym) // don't re-parse
56*1f5207b7SJohn Levon 			return;
57*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tracker);
58*1f5207b7SJohn Levon 
59*1f5207b7SJohn Levon 	syscall_name = name;
60*1f5207b7SJohn Levon 	cur_syscall = sym;
61*1f5207b7SJohn Levon 
62*1f5207b7SJohn Levon 	cur_return_type = cur_func_return_type();
63*1f5207b7SJohn Levon 	if (cur_return_type && cur_return_type->ident)
64*1f5207b7SJohn Levon 		sm_msg("return type: %s\n", cur_return_type->ident->name);
65*1f5207b7SJohn Levon 
66*1f5207b7SJohn Levon 
67*1f5207b7SJohn Levon 	FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
68*1f5207b7SJohn Levon 		// set_state(my_id, arg->ident->name, arg, &user_data_set);
69*1f5207b7SJohn Levon 		sm_msg("=======check_impl: arguments for call %s=========\n", syscall_name);
70*1f5207b7SJohn Levon 		if (arg->type == SYM_STRUCT)
71*1f5207b7SJohn Levon 			arg = get_real_base_type(arg);
72*1f5207b7SJohn Levon 		if (cur_return_type && cur_return_type->ident)
73*1f5207b7SJohn Levon 			sm_msg("arg type: %s\n", cur_return_type->ident->name);
74*1f5207b7SJohn Levon 		// add_tracker(&arg_list, my_id, member, arg);
75*1f5207b7SJohn Levon 		sm_msg("=================================\n");
76*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
77*1f5207b7SJohn Levon }
78*1f5207b7SJohn Levon 
print_read_list(void)79*1f5207b7SJohn Levon static void print_read_list(void)
80*1f5207b7SJohn Levon {
81*1f5207b7SJohn Levon     struct tracker *tracker;
82*1f5207b7SJohn Levon     int i = 0;
83*1f5207b7SJohn Levon 
84*1f5207b7SJohn Levon     FOR_EACH_PTR(read_list, tracker) {
85*1f5207b7SJohn Levon 	    if (i == 0)
86*1f5207b7SJohn Levon 		    sm_printf("%s read_list: [", syscall_name);
87*1f5207b7SJohn Levon 	    sm_printf("%s, ", tracker->name);
88*1f5207b7SJohn Levon 	    i++;
89*1f5207b7SJohn Levon     } END_FOR_EACH_PTR(tracker);
90*1f5207b7SJohn Levon 
91*1f5207b7SJohn Levon     if (i > 0)
92*1f5207b7SJohn Levon 	    sm_printf("]\n");
93*1f5207b7SJohn Levon }
94*1f5207b7SJohn Levon 
print_write_list(void)95*1f5207b7SJohn Levon static void print_write_list(void)
96*1f5207b7SJohn Levon {
97*1f5207b7SJohn Levon 	struct tracker *tracker;
98*1f5207b7SJohn Levon 	int i = 0;
99*1f5207b7SJohn Levon 
100*1f5207b7SJohn Levon 	FOR_EACH_PTR(write_list, tracker) {
101*1f5207b7SJohn Levon 		if (i == 0)
102*1f5207b7SJohn Levon 			sm_printf("%s write_list: [", syscall_name);
103*1f5207b7SJohn Levon 		sm_printf("%s, ", tracker->name);
104*1f5207b7SJohn Levon 		i++;
105*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tracker);
106*1f5207b7SJohn Levon 
107*1f5207b7SJohn Levon 	if (i > 0)
108*1f5207b7SJohn Levon 		sm_printf("]\n");
109*1f5207b7SJohn Levon }
110*1f5207b7SJohn Levon 
print_arg_list(void)111*1f5207b7SJohn Levon static void print_arg_list(void)
112*1f5207b7SJohn Levon {
113*1f5207b7SJohn Levon 	struct tracker *tracker;
114*1f5207b7SJohn Levon 	int i = 0;
115*1f5207b7SJohn Levon 
116*1f5207b7SJohn Levon 	FOR_EACH_PTR(write_list, tracker) {
117*1f5207b7SJohn Levon 		if (i == 0)
118*1f5207b7SJohn Levon 			sm_printf("%s arg_list: [", syscall_name);
119*1f5207b7SJohn Levon 		sm_printf("%s, ", tracker->name);
120*1f5207b7SJohn Levon 		i++;
121*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tracker);
122*1f5207b7SJohn Levon 
123*1f5207b7SJohn Levon 	if (i > 0)
124*1f5207b7SJohn Levon 		sm_printf("]\n");
125*1f5207b7SJohn Levon }
126*1f5207b7SJohn Levon 
match_after_syscall(struct symbol * sym)127*1f5207b7SJohn Levon static void match_after_syscall(struct symbol *sym)
128*1f5207b7SJohn Levon {
129*1f5207b7SJohn Levon 	if (!cur_syscall || sym != cur_syscall)
130*1f5207b7SJohn Levon 		return;
131*1f5207b7SJohn Levon 	// printf("\n"); prefix();
132*1f5207b7SJohn Levon 	// printf("exiting scope of syscall %s\n", get_function());
133*1f5207b7SJohn Levon 	// printf("-------------------------\n");
134*1f5207b7SJohn Levon 	print_read_list();
135*1f5207b7SJohn Levon 	print_write_list();
136*1f5207b7SJohn Levon 	print_arg_list();
137*1f5207b7SJohn Levon 	free_trackers_and_list(&read_list);
138*1f5207b7SJohn Levon 	free_trackers_and_list(&write_list);
139*1f5207b7SJohn Levon 	free_trackers_and_list(&arg_list);
140*1f5207b7SJohn Levon 	add_tracker(&parsed_syscalls, my_id, syscall_name, sym);
141*1f5207b7SJohn Levon 	cur_syscall = NULL;
142*1f5207b7SJohn Levon 	cur_return_type = NULL;
143*1f5207b7SJohn Levon 	syscall_name = NULL;
144*1f5207b7SJohn Levon }
145*1f5207b7SJohn Levon 
print_read_member_type(struct expression * expr)146*1f5207b7SJohn Levon static void print_read_member_type(struct expression *expr)
147*1f5207b7SJohn Levon {
148*1f5207b7SJohn Levon 	char *member;
149*1f5207b7SJohn Levon 	struct symbol *sym;
150*1f5207b7SJohn Levon 	struct symbol *member_sym;
151*1f5207b7SJohn Levon 
152*1f5207b7SJohn Levon 	member = get_member_name(expr);
153*1f5207b7SJohn Levon 	if (!member)
154*1f5207b7SJohn Levon 		return;
155*1f5207b7SJohn Levon 
156*1f5207b7SJohn Levon 	sym = get_type(expr->deref);
157*1f5207b7SJohn Levon 	member_sym = get_type(expr);
158*1f5207b7SJohn Levon 
159*1f5207b7SJohn Levon 	if (member_sym->type == SYM_PTR)
160*1f5207b7SJohn Levon 		member_sym = get_real_base_type(member_sym);
161*1f5207b7SJohn Levon 
162*1f5207b7SJohn Levon 	/*
163*1f5207b7SJohn Levon 	if (member_sym->type == SYM_STRUCT)
164*1f5207b7SJohn Levon 		printf("found struct type %s\n", member);
165*1f5207b7SJohn Levon 	else
166*1f5207b7SJohn Levon 		printf("found non-struct type %s with enum value%d\n", member, member_sym->type);
167*1f5207b7SJohn Levon 	*/
168*1f5207b7SJohn Levon 
169*1f5207b7SJohn Levon 	if (ignore_structs && member_sym->type == SYM_STRUCT) {
170*1f5207b7SJohn Levon 		// printf("ignoring %s\n", member);
171*1f5207b7SJohn Levon 		return;
172*1f5207b7SJohn Levon 	}
173*1f5207b7SJohn Levon 
174*1f5207b7SJohn Levon 	add_tracker(&read_list, my_id, member, sym);
175*1f5207b7SJohn Levon 	// sm_msg("info: uses %s", member);
176*1f5207b7SJohn Levon 	// prefix();
177*1f5207b7SJohn Levon 	// printf("info: uses %s\n", member);
178*1f5207b7SJohn Levon 	free_string(member);
179*1f5207b7SJohn Levon }
180*1f5207b7SJohn Levon 
print_write_member_type(struct expression * expr)181*1f5207b7SJohn Levon static void print_write_member_type(struct expression *expr)
182*1f5207b7SJohn Levon {
183*1f5207b7SJohn Levon 	char *member;
184*1f5207b7SJohn Levon 	struct symbol *sym;
185*1f5207b7SJohn Levon 	struct symbol *member_sym;
186*1f5207b7SJohn Levon 
187*1f5207b7SJohn Levon 	member = get_member_name(expr);
188*1f5207b7SJohn Levon 	if (!member)
189*1f5207b7SJohn Levon 		return;
190*1f5207b7SJohn Levon 
191*1f5207b7SJohn Levon 	sym = get_type(expr->deref);
192*1f5207b7SJohn Levon 	member_sym = get_type(expr);
193*1f5207b7SJohn Levon 
194*1f5207b7SJohn Levon 	if (member_sym->type == SYM_PTR)
195*1f5207b7SJohn Levon 		member_sym = get_real_base_type(member_sym);
196*1f5207b7SJohn Levon 
197*1f5207b7SJohn Levon 	/*
198*1f5207b7SJohn Levon 	if (member_sym->type == SYM_STRUCT)
199*1f5207b7SJohn Levon 		printf("found struct type %s\n", member);
200*1f5207b7SJohn Levon 	else
201*1f5207b7SJohn Levon 		printf("found non-struct type %s with enum value%d\n", member, member_sym->type);
202*1f5207b7SJohn Levon 	*/
203*1f5207b7SJohn Levon 
204*1f5207b7SJohn Levon 	if (ignore_structs && member_sym->type == SYM_STRUCT) {
205*1f5207b7SJohn Levon 		// printf("ignoring %s\n", member);
206*1f5207b7SJohn Levon 		return;
207*1f5207b7SJohn Levon 	}
208*1f5207b7SJohn Levon 
209*1f5207b7SJohn Levon 	add_tracker(&write_list, my_id, member, sym);
210*1f5207b7SJohn Levon 	free_string(member);
211*1f5207b7SJohn Levon }
212*1f5207b7SJohn Levon 
match_condition(struct expression * expr)213*1f5207b7SJohn Levon static void match_condition(struct expression *expr)
214*1f5207b7SJohn Levon {
215*1f5207b7SJohn Levon 	struct expression *arg;
216*1f5207b7SJohn Levon 
217*1f5207b7SJohn Levon 	if (!cur_syscall)
218*1f5207b7SJohn Levon 		return;
219*1f5207b7SJohn Levon 
220*1f5207b7SJohn Levon 	// prefix(); printf("-- condition found\n");
221*1f5207b7SJohn Levon 
222*1f5207b7SJohn Levon 	if (expr->type == EXPR_COMPARE ||
223*1f5207b7SJohn Levon 	    expr->type == EXPR_BINOP ||
224*1f5207b7SJohn Levon 	    expr->type == EXPR_LOGICAL ||
225*1f5207b7SJohn Levon 	    expr->type == EXPR_ASSIGNMENT ||
226*1f5207b7SJohn Levon 	    expr->type == EXPR_COMMA) {
227*1f5207b7SJohn Levon 		match_condition(expr->left);
228*1f5207b7SJohn Levon 		match_condition(expr->right);
229*1f5207b7SJohn Levon 		return;
230*1f5207b7SJohn Levon 	}
231*1f5207b7SJohn Levon 
232*1f5207b7SJohn Levon 	if (expr->type == EXPR_CALL) {
233*1f5207b7SJohn Levon 		FOR_EACH_PTR(expr->args, arg) {
234*1f5207b7SJohn Levon 			// if we find deref in conditional call,
235*1f5207b7SJohn Levon 			// mark it as a read dependency
236*1f5207b7SJohn Levon 			print_read_member_type(arg);
237*1f5207b7SJohn Levon 		} END_FOR_EACH_PTR(arg);
238*1f5207b7SJohn Levon 		return;
239*1f5207b7SJohn Levon 	}
240*1f5207b7SJohn Levon 
241*1f5207b7SJohn Levon 	print_read_member_type(expr);
242*1f5207b7SJohn Levon }
243*1f5207b7SJohn Levon 
244*1f5207b7SJohn Levon 
245*1f5207b7SJohn Levon /* when we are parsing an inline function and can no longer nest,
246*1f5207b7SJohn Levon  * assume that all struct fields passed to nested inline functions
247*1f5207b7SJohn Levon  * are read dependencies
248*1f5207b7SJohn Levon  */
match_call_info(struct expression * expr)249*1f5207b7SJohn Levon static void match_call_info(struct expression *expr)
250*1f5207b7SJohn Levon {
251*1f5207b7SJohn Levon 	struct expression *arg;
252*1f5207b7SJohn Levon 	int i;
253*1f5207b7SJohn Levon 
254*1f5207b7SJohn Levon 	if (!__inline_fn || !cur_syscall)
255*1f5207b7SJohn Levon 		return;
256*1f5207b7SJohn Levon 
257*1f5207b7SJohn Levon 	// prefix(); printf("fn: %s\n", expr->fn->symbol->ident->name);
258*1f5207b7SJohn Levon 
259*1f5207b7SJohn Levon 	i = 0;
260*1f5207b7SJohn Levon 	FOR_EACH_PTR(expr->args, arg) {
261*1f5207b7SJohn Levon 		/*
262*1f5207b7SJohn Levon 		   if (arg->type == EXPR_DEREF)
263*1f5207b7SJohn Levon 		   printf("arg %d is deref\n", i);
264*1f5207b7SJohn Levon 		 */
265*1f5207b7SJohn Levon 		print_read_member_type(arg);
266*1f5207b7SJohn Levon 		i++;
267*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
268*1f5207b7SJohn Levon }
269*1f5207b7SJohn Levon 
match_assign_value(struct expression * expr)270*1f5207b7SJohn Levon static void match_assign_value(struct expression *expr)
271*1f5207b7SJohn Levon {
272*1f5207b7SJohn Levon 	if (!cur_syscall)
273*1f5207b7SJohn Levon 		return;
274*1f5207b7SJohn Levon 	print_write_member_type(expr->left);
275*1f5207b7SJohn Levon }
276*1f5207b7SJohn Levon 
unop_expr(struct expression * expr)277*1f5207b7SJohn Levon static void unop_expr(struct expression *expr)
278*1f5207b7SJohn Levon {
279*1f5207b7SJohn Levon 	if (!cur_syscall)
280*1f5207b7SJohn Levon 		return;
281*1f5207b7SJohn Levon 
282*1f5207b7SJohn Levon 	if (expr->op == SPECIAL_ADD_ASSIGN || expr->op == SPECIAL_INCREMENT ||
283*1f5207b7SJohn Levon 	    expr->op == SPECIAL_SUB_ASSIGN || expr->op == SPECIAL_DECREMENT ||
284*1f5207b7SJohn Levon 	    expr->op == SPECIAL_MUL_ASSIGN || expr->op == SPECIAL_DIV_ASSIGN ||
285*1f5207b7SJohn Levon 	    expr->op == SPECIAL_MOD_ASSIGN || expr->op == SPECIAL_AND_ASSIGN ||
286*1f5207b7SJohn Levon 	    expr->op == SPECIAL_OR_ASSIGN || expr->op == SPECIAL_XOR_ASSIGN ||
287*1f5207b7SJohn Levon 	    expr->op == SPECIAL_SHL_ASSIGN || expr->op == SPECIAL_SHR_ASSIGN)
288*1f5207b7SJohn Levon 		print_write_member_type(strip_expr(expr->unop));
289*1f5207b7SJohn Levon }
290*1f5207b7SJohn Levon 
check_implicit_dependencies(int id)291*1f5207b7SJohn Levon void check_implicit_dependencies(int id)
292*1f5207b7SJohn Levon {
293*1f5207b7SJohn Levon 	my_id = id;
294*1f5207b7SJohn Levon 	ignore_structs = 0;
295*1f5207b7SJohn Levon 
296*1f5207b7SJohn Levon 	if (option_project != PROJ_KERNEL)
297*1f5207b7SJohn Levon 		return;
298*1f5207b7SJohn Levon 	if (!option_info)
299*1f5207b7SJohn Levon 		return;
300*1f5207b7SJohn Levon 
301*1f5207b7SJohn Levon 	add_hook(&match_syscall_definition, AFTER_DEF_HOOK);
302*1f5207b7SJohn Levon 	add_hook(&match_after_syscall, AFTER_FUNC_HOOK);
303*1f5207b7SJohn Levon 	add_hook(&match_condition, CONDITION_HOOK);
304*1f5207b7SJohn Levon 	add_hook(&match_call_info, FUNCTION_CALL_HOOK);
305*1f5207b7SJohn Levon 
306*1f5207b7SJohn Levon 	/* hooks to track written fields */
307*1f5207b7SJohn Levon 	add_hook(&match_assign_value, ASSIGNMENT_HOOK_AFTER);
308*1f5207b7SJohn Levon 	add_hook(&unop_expr, OP_HOOK);
309*1f5207b7SJohn Levon }
310