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