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 }