modification_hooks: use modification info from the database
[smatch.git] / smatch_modification_hooks.c
blob7c1c6f71436e4335d7846ac9964f10ab383bbe2f
1 /*
2 * sparse/smatch_modification_hooks.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include "smatch.h"
13 #include "smatch_extra.h"
14 #include "smatch_slist.h"
16 enum {
17 match_none = 0,
18 match_exact,
19 match_indirect
22 static modification_hook **hooks;
23 static modification_hook **indirect_hooks; /* parent struct modified etc */
25 void add_modification_hook(int owner, modification_hook *call_back)
27 hooks[owner] = call_back;
30 void add_indirect_modification_hook(int owner, modification_hook *call_back)
32 indirect_hooks[owner] = call_back;
35 static int matches(char *name, struct symbol *sym, struct sm_state *sm)
37 int len;
39 if (sym != sm->sym)
40 return match_none;
42 len = strlen(name);
43 if (strncmp(sm->name, name, len) == 0) {
44 if (sm->name[len] == '\0')
45 return match_exact;
46 if (sm->name[len] == '-' || sm->name[len] == '.')
47 return match_indirect;
49 if (sm->name[0] != '*')
50 return match_none;
51 if (strncmp(sm->name + 1, name, len) == 0) {
52 if (sm->name[len + 1] == '\0')
53 return match_indirect;
54 if (sm->name[len + 1] == '-' || sm->name[len + 1] == '.')
55 return match_indirect;
57 return match_none;
60 static void call_modification_hooks_name_sym(char *name, struct symbol *sym)
62 struct state_list *slist;
63 struct sm_state *sm;
64 int match;
66 slist = __get_cur_slist();
68 FOR_EACH_PTR(slist, sm) {
69 if (sm->owner > num_checks)
70 continue;
71 match = matches(name, sym, sm);
73 if (match && hooks[sm->owner])
74 (hooks[sm->owner])(sm);
76 if (match == match_indirect && indirect_hooks[sm->owner])
77 (indirect_hooks[sm->owner])(sm);
78 } END_FOR_EACH_PTR(sm);
81 static void call_modification_hooks(struct expression *expr)
83 char *name;
84 struct symbol *sym;
86 name = expr_to_var_sym(expr, &sym);
87 if (!name || !sym)
88 goto free;
89 call_modification_hooks_name_sym(name, sym);
90 free:
91 free_string(name);
94 static char *get_variable_from_key(struct expression *arg, char *key, struct symbol **sym)
96 char buf[256];
97 char *tmp;
99 if (strcmp(key, "$$") == 0)
100 return expr_to_var_sym(arg, sym);
102 if (strcmp(key, "*$$") == 0) {
103 if (arg->type == EXPR_PREOP && arg->op == '&') {
104 arg = strip_expr(arg->unop);
105 return expr_to_var_sym(arg, sym);
106 } else {
107 tmp = expr_to_var_sym(arg, sym);
108 if (!tmp)
109 return NULL;
110 snprintf(buf, sizeof(buf), "*%s", tmp);
111 free_string(tmp);
112 return alloc_string(buf);
116 if (arg->type == EXPR_PREOP && arg->op == '&') {
117 arg = strip_expr(arg->unop);
118 tmp = expr_to_var_sym(arg, sym);
119 if (!tmp)
120 return NULL;
121 snprintf(buf, sizeof(buf), "%s.%s", tmp, key + 4);
122 return alloc_string(buf);
125 tmp = expr_to_var_sym(arg, sym);
126 if (!tmp)
127 return NULL;
128 snprintf(buf, sizeof(buf), "%s%s", tmp, key + 2);
129 free_string(tmp);
130 return alloc_string(buf);
133 static void db_param_add(struct expression *expr, int param, char *key, char *value)
135 struct expression *arg;
136 char *name;
137 struct symbol *sym;
139 while (expr->type == EXPR_ASSIGNMENT)
140 expr = strip_expr(expr->right);
141 if (expr->type != EXPR_CALL)
142 return;
144 arg = get_argument_from_call_expr(expr->args, param);
145 if (!arg)
146 return;
148 name = get_variable_from_key(arg, key, &sym);
149 if (!name || !sym)
150 goto free;
152 call_modification_hooks_name_sym(name, sym);
153 free:
154 free_string(name);
157 static void match_assign(struct expression *expr)
159 call_modification_hooks(expr->left);
162 static void unop_expr(struct expression *expr)
164 if (expr->op != SPECIAL_DECREMENT && expr->op != SPECIAL_INCREMENT)
165 return;
167 expr = strip_expr(expr->unop);
168 call_modification_hooks(expr);
171 static void match_call(struct expression *expr)
173 struct expression *arg, *tmp;
175 FOR_EACH_PTR(expr->args, arg) {
176 tmp = strip_expr(arg);
177 if (tmp->type == EXPR_PREOP && tmp->op == '&') {
178 tmp = strip_expr(tmp->unop);
179 call_modification_hooks(tmp);
180 } else {
181 call_modification_hooks(deref_expression(tmp));
183 } END_FOR_EACH_PTR(arg);
186 static void asm_expr(struct statement *stmt)
189 struct expression *expr;
190 int state = 0;
192 FOR_EACH_PTR(stmt->asm_outputs, expr) {
193 switch (state) {
194 case 0: /* identifier */
195 case 1: /* constraint */
196 state++;
197 continue;
198 case 2: /* expression */
199 state = 0;
200 call_modification_hooks(expr);
201 continue;
203 } END_FOR_EACH_PTR(expr);
206 void register_modification_hooks(int id)
208 hooks = malloc((num_checks + 1) * sizeof(*hooks));
209 memset(hooks, 0, (num_checks + 1) * sizeof(*hooks));
210 indirect_hooks = malloc((num_checks + 1) * sizeof(*hooks));
211 memset(indirect_hooks, 0, (num_checks + 1) * sizeof(*hooks));
213 add_hook(&match_assign, ASSIGNMENT_HOOK);
214 add_hook(&unop_expr, OP_HOOK);
215 add_hook(&asm_expr, ASM_HOOK);
218 void register_modification_hooks_late(int id)
220 add_hook(&match_call, FUNCTION_CALL_HOOK);
221 add_db_return_states_callback(ADDED_VALUE, &db_param_add);