2 #include "smatch_slist.h"
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
)
30 struct tracker
*tracker
;
35 macro
= get_macro_name(sym
->pos
);
37 (strncmp("SYSCALL_DEFINE", macro
, strlen("SYSCALL_DEFINE")) == 0 ||
38 strncmp("COMPAT_SYSCALL_DEFINE", macro
, strlen("COMPAT_SYSCALL_DEFINE")) == 0))
41 name
= get_function();
43 if (name
&& strncmp(name
, "sys_", 4) == 0)
46 if (name
&& strncmp(name
, "compat_sys_", 11) == 0)
52 FOR_EACH_PTR(parsed_syscalls
, tracker
) {
53 if (tracker
->sym
== sym
) { // don't re-parse
57 } END_FOR_EACH_PTR(tracker
);
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
;
85 FOR_EACH_PTR(read_list
, tracker
) {
87 sm_printf("%s read_list: [", syscall_name
);
88 sm_printf("%s, ", tracker
->name
);
90 } END_FOR_EACH_PTR(tracker
);
95 static void print_write_list()
97 struct tracker
*tracker
;
99 FOR_EACH_PTR(write_list
, tracker
) {
101 sm_printf("%s write_list: [", syscall_name
);
102 sm_printf("%s, ", tracker
->name
);
104 } END_FOR_EACH_PTR(tracker
);
109 static void print_arg_list()
111 struct tracker
*tracker
;
113 FOR_EACH_PTR(write_list
, tracker
) {
115 sm_printf("%s arg_list: [", syscall_name
);
116 sm_printf("%s, ", tracker
->name
);
118 } END_FOR_EACH_PTR(tracker
);
123 static void match_after_syscall(struct symbol
*sym
) {
124 if (!cur_syscall
|| sym
!= cur_syscall
)
126 // printf("\n"); prefix();
127 // printf("exiting scope of syscall %s\n", get_function());
128 // printf("-------------------------\n");
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
);
137 cur_return_type
= NULL
;
141 static void print_read_member_type(struct expression
*expr
)
145 struct symbol
*member_sym
;
147 member
= get_member_name(expr
);
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);
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);
171 add_tracker(&read_list
, my_id
, member
, sym
);
172 // sm_msg("info: uses %s", member);
174 // printf("info: uses %s\n", member);
178 static void print_write_member_type(struct expression
*expr
)
182 struct symbol
*member_sym
;
184 member
= get_member_name(expr
);
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);
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);
206 add_tracker(&write_list
, my_id
, member
, sym
);
210 static void match_condition(struct expression
*expr
) {
211 struct expression
*arg
;
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
);
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
);
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
;
247 if (!__inline_fn
|| !cur_syscall
)
250 // prefix(); printf("fn: %s\n", expr->fn->symbol->ident->name);
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
);
260 } END_FOR_EACH_PTR(arg
);
263 static void match_assign_value(struct expression
*expr
)
267 print_write_member_type(expr
->left
);
270 static void unop_expr(struct expression
*expr
)
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
)
289 if (option_project
!= PROJ_KERNEL
)
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
);