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 } 416