2 #include "smatch_slist.h"
6 /* If set, we ignore struct type symbols as implicit dependencies */
7 static int ignore_structs
;
9 static struct symbol
*cur_syscall
;
10 /* note: cannot track return type and remove from implicit dependencies,
11 * because every syscall returns a long, and we don't have a good way to know
12 * whether or not this is a resource. The only example I can think of is open
13 * returning a filedescriptor, so in the implicit dep parsing, we will just
14 * blacklist struct fd --> file
16 static struct symbol
*cur_return_type
;
17 static char *syscall_name
;
19 static struct tracker_list
*read_list
; // what fields does syscall branch on?
20 static struct tracker_list
*write_list
; // what fields does syscall modify?
21 static struct tracker_list
*arg_list
; // what struct arguments does the syscall take?
22 static struct tracker_list
*parsed_syscalls
; // syscalls we have already checked
24 static inline void prefix(void)
26 printf("%s:%d %s() ", get_filename(), get_lineno(), get_function());
29 static void match_syscall_definition(struct symbol
*sym
)
32 struct tracker
*tracker
;
37 macro
= get_macro_name(sym
->pos
);
39 (strncmp("SYSCALL_DEFINE", macro
, strlen("SYSCALL_DEFINE")) == 0 ||
40 strncmp("COMPAT_SYSCALL_DEFINE", macro
, strlen("COMPAT_SYSCALL_DEFINE")) == 0))
43 name
= get_function();
45 if (name
&& strncmp(name
, "sys_", 4) == 0)
48 if (name
&& strncmp(name
, "compat_sys_", 11) == 0)
54 FOR_EACH_PTR(parsed_syscalls
, tracker
) {
55 if (tracker
->sym
== sym
) // don't re-parse
57 } END_FOR_EACH_PTR(tracker
);
62 cur_return_type
= cur_func_return_type();
63 if (cur_return_type
&& cur_return_type
->ident
)
64 sm_msg("return type: %s\n", cur_return_type
->ident
->name
);
67 FOR_EACH_PTR(sym
->ctype
.base_type
->arguments
, arg
) {
68 // set_state(my_id, arg->ident->name, arg, &user_data_set);
69 sm_msg("=======check_impl: arguments for call %s=========\n", syscall_name
);
70 if (arg
->type
== SYM_STRUCT
)
71 arg
= get_real_base_type(arg
);
72 if (cur_return_type
&& cur_return_type
->ident
)
73 sm_msg("arg type: %s\n", cur_return_type
->ident
->name
);
74 // add_tracker(&arg_list, my_id, member, arg);
75 sm_msg("=================================\n");
76 } END_FOR_EACH_PTR(arg
);
79 static void print_read_list(void)
81 struct tracker
*tracker
;
84 FOR_EACH_PTR(read_list
, tracker
) {
86 sm_printf("%s read_list: [", syscall_name
);
87 sm_printf("%s, ", tracker
->name
);
89 } END_FOR_EACH_PTR(tracker
);
95 static void print_write_list(void)
97 struct tracker
*tracker
;
100 FOR_EACH_PTR(write_list
, tracker
) {
102 sm_printf("%s write_list: [", syscall_name
);
103 sm_printf("%s, ", tracker
->name
);
105 } END_FOR_EACH_PTR(tracker
);
111 static void print_arg_list(void)
113 struct tracker
*tracker
;
116 FOR_EACH_PTR(write_list
, tracker
) {
118 sm_printf("%s arg_list: [", syscall_name
);
119 sm_printf("%s, ", tracker
->name
);
121 } END_FOR_EACH_PTR(tracker
);
127 static void match_after_syscall(struct symbol
*sym
)
129 if (!cur_syscall
|| sym
!= cur_syscall
)
131 // printf("\n"); prefix();
132 // printf("exiting scope of syscall %s\n", get_function());
133 // printf("-------------------------\n");
137 free_trackers_and_list(&read_list
);
138 free_trackers_and_list(&write_list
);
139 free_trackers_and_list(&arg_list
);
140 add_tracker(&parsed_syscalls
, my_id
, syscall_name
, sym
);
142 cur_return_type
= NULL
;
146 static void print_read_member_type(struct expression
*expr
)
150 struct symbol
*member_sym
;
152 member
= get_member_name(expr
);
156 sym
= get_type(expr
->deref
);
157 member_sym
= get_type(expr
);
159 if (member_sym
->type
== SYM_PTR
)
160 member_sym
= get_real_base_type(member_sym
);
163 if (member_sym->type == SYM_STRUCT)
164 printf("found struct type %s\n", member);
166 printf("found non-struct type %s with enum value%d\n", member, member_sym->type);
169 if (ignore_structs
&& member_sym
->type
== SYM_STRUCT
) {
170 // printf("ignoring %s\n", member);
174 add_tracker(&read_list
, my_id
, member
, sym
);
175 // sm_msg("info: uses %s", member);
177 // printf("info: uses %s\n", member);
181 static void print_write_member_type(struct expression
*expr
)
185 struct symbol
*member_sym
;
187 member
= get_member_name(expr
);
191 sym
= get_type(expr
->deref
);
192 member_sym
= get_type(expr
);
194 if (member_sym
->type
== SYM_PTR
)
195 member_sym
= get_real_base_type(member_sym
);
198 if (member_sym->type == SYM_STRUCT)
199 printf("found struct type %s\n", member);
201 printf("found non-struct type %s with enum value%d\n", member, member_sym->type);
204 if (ignore_structs
&& member_sym
->type
== SYM_STRUCT
) {
205 // printf("ignoring %s\n", member);
209 add_tracker(&write_list
, my_id
, member
, sym
);
213 static void match_condition(struct expression
*expr
)
215 struct expression
*arg
;
220 // prefix(); printf("-- condition found\n");
222 if (expr
->type
== EXPR_COMPARE
||
223 expr
->type
== EXPR_BINOP
||
224 expr
->type
== EXPR_LOGICAL
||
225 expr
->type
== EXPR_ASSIGNMENT
||
226 expr
->type
== EXPR_COMMA
) {
227 match_condition(expr
->left
);
228 match_condition(expr
->right
);
232 if (expr
->type
== EXPR_CALL
) {
233 FOR_EACH_PTR(expr
->args
, arg
) {
234 // if we find deref in conditional call,
235 // mark it as a read dependency
236 print_read_member_type(arg
);
237 } END_FOR_EACH_PTR(arg
);
241 print_read_member_type(expr
);
245 /* when we are parsing an inline function and can no longer nest,
246 * assume that all struct fields passed to nested inline functions
247 * are read dependencies
249 static void match_call_info(struct expression
*expr
)
251 struct expression
*arg
;
254 if (!__inline_fn
|| !cur_syscall
)
257 // prefix(); printf("fn: %s\n", expr->fn->symbol->ident->name);
260 FOR_EACH_PTR(expr
->args
, arg
) {
262 if (arg->type == EXPR_DEREF)
263 printf("arg %d is deref\n", i);
265 print_read_member_type(arg
);
267 } END_FOR_EACH_PTR(arg
);
270 static void match_assign_value(struct expression
*expr
)
274 print_write_member_type(expr
->left
);
277 static void unop_expr(struct expression
*expr
)
282 if (expr
->op
== SPECIAL_ADD_ASSIGN
|| expr
->op
== SPECIAL_INCREMENT
||
283 expr
->op
== SPECIAL_SUB_ASSIGN
|| expr
->op
== SPECIAL_DECREMENT
||
284 expr
->op
== SPECIAL_MUL_ASSIGN
|| expr
->op
== SPECIAL_DIV_ASSIGN
||
285 expr
->op
== SPECIAL_MOD_ASSIGN
|| expr
->op
== SPECIAL_AND_ASSIGN
||
286 expr
->op
== SPECIAL_OR_ASSIGN
|| expr
->op
== SPECIAL_XOR_ASSIGN
||
287 expr
->op
== SPECIAL_SHL_ASSIGN
|| expr
->op
== SPECIAL_SHR_ASSIGN
)
288 print_write_member_type(strip_expr(expr
->unop
));
291 void check_implicit_dependencies(int id
)
296 if (option_project
!= PROJ_KERNEL
)
301 add_hook(&match_syscall_definition
, AFTER_DEF_HOOK
);
302 add_hook(&match_after_syscall
, AFTER_FUNC_HOOK
);
303 add_hook(&match_condition
, CONDITION_HOOK
);
304 add_hook(&match_call_info
, FUNCTION_CALL_HOOK
);
306 /* hooks to track written fields */
307 add_hook(&match_assign_value
, ASSIGNMENT_HOOK_AFTER
);
308 add_hook(&unop_expr
, OP_HOOK
);