1 /*
2 * Copyright (C) 2013 Oracle.
3 *
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.
8 *
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.
13 *
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
16 */
17
18 /*
19 * Track how functions are saved as various struct members or passed as
20 * parameters.
21 *
22 */
23
24 #include "scope.h"
25 #include "smatch.h"
26 #include "smatch_slist.h"
27
28 static int my_id;
29
30 static char *get_from__symbol_get(struct expression *expr)
31 {
32 struct expression *arg;
33
34 /*
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"))))));
38 */
39
40 expr = strip_expr(expr);
41
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;
49
50 return alloc_string(arg->string->data);
51 }
52
53 static char *get_array_ptr(struct expression *expr)
54 {
55 struct expression *array;
56 struct symbol *type;
57 char *name;
58 char buf[256];
59
60 array = get_array_base(expr);
61
62 if (array) {
63 name = get_member_name(array);
64 if (name)
65 return name;
66 }
67
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);
78 }
79
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);
90 }
91
92 static int is_local_symbol(struct symbol *sym)
93 {
94 if (!sym ||
95 !(sym->ctype.modifiers & MOD_TOPLEVEL))
96 return 1;
97 return 0;
98 }
99
100 static char *ptr_prefix(struct symbol *sym)
101 {
102 static char buf[128];
103
104
105 if (is_local_symbol(sym))
106 snprintf(buf, sizeof(buf), "%s ptr", get_function());
107 else if (sym && toplevel(sym->scope))
108 snprintf(buf, sizeof(buf), "%s ptr", get_base_file());
109 else
110 snprintf(buf, sizeof(buf), "ptr");
111
112 return buf;
113 }
114
115 char *get_returned_ptr(struct expression *expr)
116 {
117 struct symbol *type;
118 char *name;
119 char buf[256];
120
121 if (expr->type != EXPR_CALL)
122 return NULL;
123 if (!expr->fn || expr->fn->type != EXPR_SYMBOL)
124 return NULL;
125
126 type = get_type(expr);
127 if (type && type->type == SYM_PTR)
128 type = get_real_base_type(type);
129 if (!type || type->type != SYM_FN)
130 return NULL;
131
132 name = expr_to_var(expr->fn);
133 if (!name)
134 return NULL;
135 snprintf(buf, sizeof(buf), "r %s()", name);
136 free_string(name);
137 return alloc_string(buf);
138 }
139
140 char *get_fnptr_name(struct expression *expr)
141 {
142 char *name;
143
144 if (is_zero(expr))
145 return NULL;
146
147 expr = strip_expr(expr);
148
149 /* (*ptrs[0])(a, b, c) is the same as ptrs[0](a, b, c); */
150 if (expr->type == EXPR_PREOP && expr->op == '*')
151 expr = strip_expr(expr->unop);
152
153 name = get_from__symbol_get(expr);
154 if (name)
155 return name;
156
157 name = get_array_ptr(expr);
158 if (name)
159 return name;
160
161 name = get_returned_ptr(expr);
162 if (name)
163 return name;
164
165 name = get_member_name(expr);
166 if (name)
167 return name;
168
169 if (expr->type == EXPR_SYMBOL) {
170 int param;
171 char buf[256];
172 struct symbol *sym;
173 struct symbol *type;
174
175 param = get_param_num_from_sym(expr->symbol);
176 if (param >= 0) {
177 snprintf(buf, sizeof(buf), "%s param %d", get_function(), param);
178 return alloc_string(buf);
179 }
180
181 name = expr_to_var_sym(expr, &sym);
182 if (!name)
183 return NULL;
184 type = get_type(expr);
185 if (type && type->type == SYM_PTR) {
186 snprintf(buf, sizeof(buf), "%s %s", ptr_prefix(sym), name);
187 free_string(name);
188 return alloc_string(buf);
189 }
190 return name;
191 }
192 return expr_to_var(expr);
193 }
194
195 static void match_passes_function_pointer(struct expression *expr)
196 {
197 struct expression *arg, *tmp;
198 struct symbol *type;
199 char *called_name;
200 char *fn_name;
201 char ptr_name[256];
202 int i;
203
204
205 i = -1;
206 FOR_EACH_PTR(expr->args, arg) {
207 i++;
208
209 tmp = strip_expr(arg);
210 if (tmp->type == EXPR_PREOP && tmp->op == '&')
211 tmp = strip_expr(tmp->unop);
212
213 type = get_type(tmp);
214 if (type && type->type == SYM_PTR)
215 type = get_real_base_type(type);
216 if (!type || type->type != SYM_FN)
217 continue;
218
219 called_name = expr_to_var(expr->fn);
220 if (!called_name)
221 return;
222 fn_name = get_fnptr_name(tmp);
223 if (!fn_name)
224 goto free;
225
226 snprintf(ptr_name, sizeof(ptr_name), "%s param %d", called_name, i);
227 sql_insert_function_ptr(fn_name, ptr_name);
228 free:
229 free_string(fn_name);
230 free_string(called_name);
231 } END_FOR_EACH_PTR(arg);
232
233 }
234
235 static int get_row_count(void *_row_count, int argc, char **argv, char **azColName)
236 {
237 int *row_count = _row_count;
238
239 *row_count = 0;
240 if (argc != 1)
241 return 0;
242 *row_count = atoi(argv[0]);
243 return 0;
244 }
245
246 static int can_hold_function_ptr(struct expression *expr)
247 {
248 struct symbol *type;
249
250 type = get_type(expr);
251 if (!type)
252 return 0;
253 if (type->type == SYM_PTR || type->type == SYM_ARRAY) {
254 type = get_real_base_type(type);
255 if (!type)
256 return 0;
257 }
258 if (type->type == SYM_FN)
259 return 1;
260 if (type == &ulong_ctype && expr->type == EXPR_DEREF)
261 return 1;
262 if (type == &void_ctype)
263 return 1;
264 return 0;
265 }
266
267 static void match_function_assign(struct expression *expr)
268 {
269 struct expression *right;
270 struct symbol *type;
271 char *fn_name;
272 char *ptr_name;
273
274 if (__in_fake_assign)
275 return;
276
277 right = strip_expr(expr->right);
278 if (right->type == EXPR_PREOP && right->op == '&')
279 right = strip_expr(right->unop);
280
281 if (right->type != EXPR_SYMBOL &&
282 right->type != EXPR_DEREF)
283 return;
284
285 if (!can_hold_function_ptr(right) ||
286 !can_hold_function_ptr(expr->left))
287 return;
288
289 fn_name = get_fnptr_name(right);
290 ptr_name = get_fnptr_name(expr->left);
291 if (!fn_name || !ptr_name)
292 goto free;
293 if (strcmp(fn_name, ptr_name) == 0)
294 goto free;
295
296
297 type = get_type(right);
298 if (!type)
299 return;
300 if (type->type == SYM_PTR || type->type == SYM_ARRAY) {
301 type = get_real_base_type(type);
302 if (!type)
303 return;
304 }
305 if (type->type != SYM_FN) {
306 int count = 0;
307
308 /* look it up in function_ptr */
309 run_sql(get_row_count, &count,
310 "select count(*) from function_ptr where ptr = '%s'",
311 fn_name);
312 if (count == 0)
313 goto free;
314 }
315
316 sql_insert_function_ptr(fn_name, ptr_name);
317 free:
318 free_string(fn_name);
319 free_string(ptr_name);
320 }
321
322 static void match_returns_function_pointer(struct expression *expr)
323 {
324 struct symbol *type;
325 char *fn_name;
326 char ptr_name[256];
327
328 if (__inline_fn)
329 return;
330
331 type = get_real_base_type(cur_func_sym);
332 if (!type || type->type != SYM_FN)
333 return;
334 type = get_real_base_type(type);
335 if (!type || type->type != SYM_PTR)
336 return;
337 type = get_real_base_type(type);
338 if (!type || type->type != SYM_FN)
339 return;
340
341 if (expr->type == EXPR_PREOP && expr->op == '&')
342 expr = strip_expr(expr->unop);
343
344 fn_name = get_fnptr_name(expr);
345 if (!fn_name)
346 return;
347 snprintf(ptr_name, sizeof(ptr_name), "r %s()", get_function());
348 sql_insert_function_ptr(fn_name, ptr_name);
349 }
350
351 static void print_initializer_list(struct expression_list *expr_list,
352 struct symbol *struct_type)
353 {
354 struct expression *expr;
355 struct symbol *base_type;
356 char struct_name[256];
357
358 FOR_EACH_PTR(expr_list, expr) {
359 if (expr->type == EXPR_INDEX && expr->idx_expression && expr->idx_expression->type == EXPR_INITIALIZER) {
360 print_initializer_list(expr->idx_expression->expr_list, struct_type);
361 continue;
362 }
363 if (expr->type != EXPR_IDENTIFIER)
364 continue;
365 if (!expr->expr_ident)
366 continue;
367 if (!expr->ident_expression ||
368 expr->ident_expression->type != EXPR_SYMBOL ||
369 !expr->ident_expression->symbol_name)
370 continue;
371 base_type = get_type(expr->ident_expression);
372 if (!base_type || base_type->type != SYM_FN)
373 continue;
374 snprintf(struct_name, sizeof(struct_name), "(struct %s)->%s",
375 struct_type->ident->name, expr->expr_ident->name);
376 sql_insert_function_ptr(expr->ident_expression->symbol_name->name,
377 struct_name);
378 } END_FOR_EACH_PTR(expr);
379 }
380
381 static void global_variable(struct symbol *sym)
382 {
383 struct symbol *struct_type;
384
385 if (!sym->ident)
386 return;
387 if (!sym->initializer || sym->initializer->type != EXPR_INITIALIZER)
388 return;
389 struct_type = get_base_type(sym);
390 if (!struct_type)
391 return;
392 if (struct_type->type == SYM_ARRAY) {
393 struct_type = get_base_type(struct_type);
394 if (!struct_type)
395 return;
396 }
397 if (struct_type->type != SYM_STRUCT || !struct_type->ident)
398 return;
399 print_initializer_list(sym->initializer->expr_list, struct_type);
400 }
401
402 void register_function_ptrs(int id)
403 {
404 my_id = id;
405
406 if (!option_info)
407 return;
408
409 add_hook(&global_variable, BASE_HOOK);
410 add_hook(&global_variable, DECLARATION_HOOK);
411 add_hook(&match_passes_function_pointer, FUNCTION_CALL_HOOK);
412 add_hook(&match_returns_function_pointer, RETURN_HOOK);
413 add_hook(&match_function_assign, ASSIGNMENT_HOOK);
414 add_hook(&match_function_assign, GLOBAL_ASSIGNMENT_HOOK);
415 }