2 * Copyright (C) 2009 Dan Carpenter.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 * There are a number of ways that variables are modified:
21 * 2) increment/decrement
23 * 4) inside functions.
25 * For setting stuff inside a function then, of course, it's more accurate if
26 * you have the cross function database built. Otherwise we are super
27 * aggressive about marking things as modified and if you have "frob(foo);" then
28 * we assume "foo->bar" is modified.
34 #include "smatch_extra.h"
35 #include "smatch_slist.h"
49 static modification_hook
**hooks
;
50 static modification_hook
**indirect_hooks
; /* parent struct modified etc */
51 static modification_hook
**hooks_late
;
52 static modification_hook
**indirect_hooks_late
; /* parent struct modified etc */
54 ALLOCATOR(modification_data
, "modification data");
57 static struct smatch_state
*alloc_my_state(struct expression
*expr
, struct smatch_state
*prev
)
59 struct smatch_state
*state
;
60 struct modification_data
*data
;
63 state
= __alloc_smatch_state(0);
64 expr
= strip_expr(expr
);
65 name
= expr_to_str(expr
);
66 state
->name
= alloc_sname(name
);
69 data
= __alloc_modification_data(0);
77 void add_modification_hook(int owner
, modification_hook
*call_back
)
79 hooks
[owner
] = call_back
;
82 void add_indirect_modification_hook(int owner
, modification_hook
*call_back
)
84 indirect_hooks
[owner
] = call_back
;
87 void add_modification_hook_late(int owner
, modification_hook
*call_back
)
89 hooks_late
[owner
] = call_back
;
92 void add_indirect_modification_hook_late(int owner
, modification_hook
*call_back
)
94 indirect_hooks_late
[owner
] = call_back
;
97 static int matches(char *name
, struct symbol
*sym
, struct sm_state
*sm
)
105 if (strncmp(sm
->name
, name
, len
) == 0) {
106 if (sm
->name
[len
] == '\0')
108 if (sm
->name
[len
] == '-' || sm
->name
[len
] == '.')
109 return match_indirect
;
111 if (sm
->name
[0] != '*')
113 if (strncmp(sm
->name
+ 1, name
, len
) == 0) {
114 if (sm
->name
[len
+ 1] == '\0')
115 return match_indirect
;
116 if (sm
->name
[len
+ 1] == '-' || sm
->name
[len
+ 1] == '.')
117 return match_indirect
;
122 static void call_modification_hooks_name_sym(char *name
, struct symbol
*sym
, struct expression
*mod_expr
, int late
)
126 struct smatch_state
*prev
;
129 prev
= get_state(my_id
, name
, sym
);
130 set_state(my_id
, name
, sym
, alloc_my_state(mod_expr
, prev
));
132 stree
= __get_cur_stree();
134 FOR_EACH_SM(stree
, sm
) {
135 if (sm
->owner
> num_checks
)
137 match
= matches(name
, sym
, sm
);
141 if (late
== EARLY
|| late
== BOTH
) {
142 if (hooks
[sm
->owner
])
143 (hooks
[sm
->owner
])(sm
, mod_expr
);
144 if (match
== match_indirect
&& indirect_hooks
[sm
->owner
])
145 (indirect_hooks
[sm
->owner
])(sm
, mod_expr
);
147 if (late
== LATE
|| late
== BOTH
) {
148 if (hooks_late
[sm
->owner
])
149 (hooks_late
[sm
->owner
])(sm
, mod_expr
);
150 if (match
== match_indirect
&& indirect_hooks_late
[sm
->owner
])
151 (indirect_hooks_late
[sm
->owner
])(sm
, mod_expr
);
154 } END_FOR_EACH_SM(sm
);
157 static void call_modification_hooks(struct expression
*expr
, struct expression
*mod_expr
, int late
)
162 name
= expr_to_known_chunk_sym(expr
, &sym
);
165 call_modification_hooks_name_sym(name
, sym
, mod_expr
, late
);
170 static void db_param_add(struct expression
*expr
, int param
, char *key
, char *value
)
172 struct expression
*arg
;
176 while (expr
->type
== EXPR_ASSIGNMENT
)
177 expr
= strip_expr(expr
->right
);
178 if (expr
->type
!= EXPR_CALL
)
181 arg
= get_argument_from_call_expr(expr
->args
, param
);
185 name
= get_variable_from_key(arg
, key
, &sym
);
189 call_modification_hooks_name_sym(name
, sym
, expr
, BOTH
);
194 static void match_assign(struct expression
*expr
, int late
)
196 call_modification_hooks(expr
->left
, expr
, late
);
199 static void unop_expr(struct expression
*expr
, int late
)
201 if (expr
->op
!= SPECIAL_DECREMENT
&& expr
->op
!= SPECIAL_INCREMENT
)
204 call_modification_hooks(expr
->unop
, expr
, late
);
207 static void match_call(struct expression
*expr
)
209 struct expression
*arg
, *tmp
;
211 FOR_EACH_PTR(expr
->args
, arg
) {
212 tmp
= strip_expr(arg
);
213 if (tmp
->type
== EXPR_PREOP
&& tmp
->op
== '&')
214 call_modification_hooks(tmp
->unop
, expr
, BOTH
);
215 else if (option_no_db
)
216 call_modification_hooks(deref_expression(tmp
), expr
, BOTH
);
217 } END_FOR_EACH_PTR(arg
);
220 static void asm_expr(struct statement
*stmt
, int late
)
222 struct expression
*expr
;
225 FOR_EACH_PTR(stmt
->asm_outputs
, expr
) {
227 case 0: /* identifier */
228 case 1: /* constraint */
231 case 2: /* expression */
233 call_modification_hooks(expr
, NULL
, late
);
236 } END_FOR_EACH_PTR(expr
);
240 static void match_assign_early(struct expression
*expr
)
242 match_assign(expr
, EARLY
);
245 static void unop_expr_early(struct expression
*expr
)
247 unop_expr(expr
, EARLY
);
250 static void asm_expr_early(struct statement
*stmt
)
252 asm_expr(stmt
, EARLY
);
255 static void match_assign_late(struct expression
*expr
)
257 match_assign(expr
, LATE
);
260 static void unop_expr_late(struct expression
*expr
)
262 unop_expr(expr
, LATE
);
265 static void asm_expr_late(struct statement
*stmt
)
267 asm_expr(stmt
, LATE
);
270 static void scope_end(void *_sym
)
272 struct symbol
*sym
= _sym
;
273 struct expression
*expr
= symbol_expression(sym
);
275 call_modification_hooks(expr
, NULL
, BOTH
);
278 static void match_declaration(struct symbol
*sym
)
280 add_scope_hook(&scope_end
, sym
);
283 struct smatch_state
*get_modification_state(struct expression
*expr
)
285 return get_state_expr(my_id
, expr
);
288 void register_modification_hooks(int id
)
292 hooks
= malloc((num_checks
+ 1) * sizeof(*hooks
));
293 memset(hooks
, 0, (num_checks
+ 1) * sizeof(*hooks
));
294 indirect_hooks
= malloc((num_checks
+ 1) * sizeof(*hooks
));
295 memset(indirect_hooks
, 0, (num_checks
+ 1) * sizeof(*hooks
));
296 hooks_late
= malloc((num_checks
+ 1) * sizeof(*hooks
));
297 memset(hooks_late
, 0, (num_checks
+ 1) * sizeof(*hooks
));
298 indirect_hooks_late
= malloc((num_checks
+ 1) * sizeof(*hooks
));
299 memset(indirect_hooks_late
, 0, (num_checks
+ 1) * sizeof(*hooks
));
301 add_hook(&match_assign_early
, ASSIGNMENT_HOOK
);
302 add_hook(&unop_expr_early
, OP_HOOK
);
303 add_hook(&asm_expr_early
, ASM_HOOK
);
306 void register_modification_hooks_late(int id
)
308 add_hook(&match_call
, FUNCTION_CALL_HOOK
);
310 add_hook(&match_assign_late
, ASSIGNMENT_HOOK
);
311 add_hook(&unop_expr_late
, OP_HOOK
);
312 add_hook(&asm_expr_late
, ASM_HOOK
);
314 select_return_states_hook(PARAM_ADD
, &db_param_add
);
315 select_return_states_hook(PARAM_SET
, &db_param_add
);
316 add_hook(&match_declaration
, DECLARATION_HOOK
);