db/fixup_kernel.sh: handle __kernel_write() a bit better
[smatch.git] / smatch_function_ptrs.c
blobd6ba3ad75bb7073e7f0ccbb5cc67ef96d0806bc8
1 /*
2 * Copyright (C) 2013 Oracle.
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 * Track how functions are saved as various struct members or passed as
20 * parameters.
24 #include "scope.h"
25 #include "smatch.h"
26 #include "smatch_slist.h"
28 static int my_id;
30 static char *get_from__symbol_get(struct expression *expr)
32 struct expression *arg;
35 * typeof(&dib0070_attach) __a =
36 * ((((typeof(&dib0070_attach)) (__symbol_get("dib0070_attach")))) ?:
37 * (__request_module(true, "symbol:" "dib0070_attach"), (((typeof(&dib0070_attach))(__symbol_get("dib0070_attach"))))));
40 expr = strip_expr(expr);
42 if (expr->type != EXPR_CALL)
43 return NULL;
44 if (!sym_name_is("__symbol_get", expr->fn))
45 return NULL;
46 arg = get_argument_from_call_expr(expr->args, 0);
47 if (!arg || arg->type != EXPR_STRING)
48 return NULL;
50 return alloc_string(arg->string->data);
53 static char *get_array_ptr(struct expression *expr)
55 struct expression *array;
56 struct symbol *type;
57 char *name;
58 char buf[256];
60 array = get_array_base(expr);
62 if (array) {
63 name = get_member_name(array);
64 if (name)
65 return name;
68 /* FIXME: is_array() should probably be is_array_element() */
69 type = get_type(expr);
70 if (!array && type && type->type == SYM_ARRAY)
71 array = expr;
72 if (array) {
73 name = expr_to_var(array);
74 if (!name)
75 return NULL;
76 snprintf(buf, sizeof(buf), "%s[]", name);
77 return alloc_string(buf);
80 expr = get_assigned_expr(expr);
81 array = get_array_base(expr);
82 if (!array)
83 return NULL;
84 name = expr_to_var(array);
85 if (!name)
86 return NULL;
87 snprintf(buf, sizeof(buf), "%s[]", name);
88 free_string(name);
89 return alloc_string(buf);
92 static int is_local_symbol(struct symbol *sym)
94 if (!sym || !sym->scope || !sym->scope->token)
95 return 0;
96 if (positions_eq(sym->scope->token->pos, cur_func_sym->pos))
97 return 1;
98 return 0;
101 static char *ptr_prefix(struct symbol *sym)
103 static char buf[128];
106 if (is_local_symbol(sym))
107 snprintf(buf, sizeof(buf), "%s ptr", get_function());
108 else if (sym && toplevel(sym->scope))
109 snprintf(buf, sizeof(buf), "%s ptr", get_base_file());
110 else
111 snprintf(buf, sizeof(buf), "ptr");
113 return buf;
116 char *get_returned_ptr(struct expression *expr)
118 struct symbol *type;
119 char *name;
120 char buf[256];
122 if (expr->type != EXPR_CALL)
123 return NULL;
124 if (!expr->fn || expr->fn->type != EXPR_SYMBOL)
125 return NULL;
127 type = get_type(expr);
128 if (type && type->type == SYM_PTR)
129 type = get_real_base_type(type);
130 if (!type || type->type != SYM_FN)
131 return NULL;
133 name = expr_to_var(expr->fn);
134 if (!name)
135 return NULL;
136 snprintf(buf, sizeof(buf), "r %s()", name);
137 free_string(name);
138 return alloc_string(buf);
141 char *get_fnptr_name(struct expression *expr)
143 char *name;
145 expr = strip_expr(expr);
147 /* (*ptrs[0])(a, b, c) is the same as ptrs[0](a, b, c); */
148 if (expr->type == EXPR_PREOP && expr->op == '*')
149 expr = strip_expr(expr->unop);
151 name = get_from__symbol_get(expr);
152 if (name)
153 return name;
155 name = get_array_ptr(expr);
156 if (name)
157 return name;
159 name = get_returned_ptr(expr);
160 if (name)
161 return name;
163 name = get_member_name(expr);
164 if (name)
165 return name;
167 if (expr->type == EXPR_SYMBOL) {
168 int param;
169 char buf[256];
170 struct symbol *sym;
171 struct symbol *type;
173 param = get_param_num_from_sym(expr->symbol);
174 if (param >= 0) {
175 snprintf(buf, sizeof(buf), "%s param %d", get_function(), param);
176 return alloc_string(buf);
179 name = expr_to_var_sym(expr, &sym);
180 if (!name)
181 return NULL;
182 type = get_type(expr);
183 if (type && type->type == SYM_PTR) {
184 snprintf(buf, sizeof(buf), "%s %s", ptr_prefix(sym), name);
185 free_string(name);
186 return alloc_string(buf);
188 return name;
190 return expr_to_var(expr);
193 static void match_passes_function_pointer(struct expression *expr)
195 struct expression *arg, *tmp;
196 struct symbol *type;
197 char *called_name;
198 char *fn_name;
199 char ptr_name[256];
200 int i;
203 i = -1;
204 FOR_EACH_PTR(expr->args, arg) {
205 i++;
207 tmp = strip_expr(arg);
208 if (tmp->type == EXPR_PREOP && tmp->op == '&')
209 tmp = strip_expr(tmp->unop);
211 type = get_type(tmp);
212 if (type && type->type == SYM_PTR)
213 type = get_real_base_type(type);
214 if (!type || type->type != SYM_FN)
215 continue;
217 called_name = expr_to_var(expr->fn);
218 if (!called_name)
219 return;
220 fn_name = get_fnptr_name(tmp);
221 if (!fn_name)
222 goto free;
224 snprintf(ptr_name, sizeof(ptr_name), "%s param %d", called_name, i);
225 sql_insert_function_ptr(fn_name, ptr_name);
226 free:
227 free_string(fn_name);
228 free_string(called_name);
229 } END_FOR_EACH_PTR(arg);
233 static void match_function_assign(struct expression *expr)
235 struct expression *right;
236 struct symbol *sym;
237 char *fn_name;
238 char *ptr_name;
240 if (__in_fake_assign)
241 return;
243 right = strip_expr(expr->right);
244 if (right->type == EXPR_PREOP && right->op == '&')
245 right = strip_expr(right->unop);
246 if (right->type != EXPR_SYMBOL && right->type != EXPR_DEREF && right->type != EXPR_CALL)
247 return;
248 sym = get_type(right);
249 if (!sym)
250 return;
251 if (sym->type == SYM_NODE)
252 sym = get_real_base_type(sym);
253 if (sym->type != SYM_FN && sym->type != SYM_PTR && sym->type != SYM_ARRAY)
254 return;
255 if (sym->type == SYM_PTR) {
256 sym = get_real_base_type(sym);
257 if (!sym)
258 return;
259 if (sym->type != SYM_FN && sym != &void_ctype)
260 return;
263 fn_name = get_fnptr_name(right);
264 ptr_name = get_fnptr_name(expr->left);
265 if (!fn_name || !ptr_name)
266 goto free;
267 if (strcmp(fn_name, ptr_name) == 0)
268 goto free;
270 sql_insert_function_ptr(fn_name, ptr_name);
272 free:
273 free_string(fn_name);
274 free_string(ptr_name);
277 static void match_returns_function_pointer(struct expression *expr)
279 struct symbol *type;
280 char *fn_name;
281 char ptr_name[256];
283 if (__inline_fn)
284 return;
286 type = get_real_base_type(cur_func_sym);
287 if (!type || type->type != SYM_FN)
288 return;
289 type = get_real_base_type(type);
290 if (!type || type->type != SYM_PTR)
291 return;
292 type = get_real_base_type(type);
293 if (!type || type->type != SYM_FN)
294 return;
296 if (expr->type == EXPR_PREOP && expr->op == '&')
297 expr = strip_expr(expr->unop);
299 fn_name = get_fnptr_name(expr);
300 if (!fn_name)
301 return;
302 snprintf(ptr_name, sizeof(ptr_name), "r %s()", get_function());
303 sql_insert_function_ptr(fn_name, ptr_name);
306 void register_function_ptrs(int id)
308 my_id = id;
310 if (!option_info)
311 return;
313 add_hook(&match_passes_function_pointer, FUNCTION_CALL_HOOK);
314 add_hook(&match_returns_function_pointer, RETURN_HOOK);
315 add_hook(&match_function_assign, ASSIGNMENT_HOOK);
316 add_hook(&match_function_assign, GLOBAL_ASSIGNMENT_HOOK);