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 int xxx_is_array(struct expression *expr)
  54 {
  55         struct symbol *type;
  56 
  57         expr = strip_expr(expr);
  58         if (!expr)
  59                 return 0;
  60 
  61         if (expr->type == EXPR_PREOP && expr->op == '*') {
  62                 expr = strip_expr(expr->unop);
  63                 if (!expr)
  64                         return 0;
  65                 if (expr->type == EXPR_BINOP && expr->op == '+')
  66                         return 1;
  67         }
  68 
  69         if (expr->type != EXPR_BINOP || expr->op != '+')
  70                 return 0;
  71 
  72         type = get_type(expr->left);
  73         if (!type)
  74                 return 0;
  75         if (type->type != SYM_ARRAY && type->type != SYM_PTR)
  76                 return 0;
  77 
  78         return 1;
  79 }
  80 
  81 static struct expression *xxx_get_array_base(struct expression *expr)
  82 {
  83         if (!xxx_is_array(expr))
  84                 return NULL;
  85         expr = strip_expr(expr);
  86         if (expr->type == EXPR_PREOP && expr->op == '*')
  87                 expr = strip_expr(expr->unop);
  88         if (expr->type != EXPR_BINOP || expr->op != '+')
  89                 return NULL;
  90         return strip_parens(expr->left);
  91 }
  92 
  93 static char *get_array_ptr(struct expression *expr)
  94 {
  95         struct expression *array;
  96         struct symbol *type;
  97         char *name;
  98         char buf[256];
  99 
 100         array = xxx_get_array_base(expr);
 101 
 102         if (array) {
 103                 name = get_member_name(array);
 104                 if (name)
 105                         return name;
 106         }
 107 
 108         /* FIXME:  is_array() should probably be is_array_element() */
 109         type = get_type(expr);
 110         if (!array && type && type->type == SYM_ARRAY)
 111                 array = expr;
 112         if (array) {
 113                 name = expr_to_var(array);
 114                 if (!name)
 115                         return NULL;
 116                 snprintf(buf, sizeof(buf), "%s[]", name);
 117                 return alloc_string(buf);
 118         }
 119 
 120         expr = get_assigned_expr(expr);
 121         array = xxx_get_array_base(expr);
 122         if (!array)
 123                 return NULL;
 124         name = expr_to_var(array);
 125         if (!name)
 126                 return NULL;
 127         snprintf(buf, sizeof(buf), "%s[]", name);
 128         free_string(name);
 129         return alloc_string(buf);
 130 }
 131 
 132 static int is_local_symbol(struct symbol *sym)
 133 {
 134         if (!sym ||
 135             !(sym->ctype.modifiers & MOD_TOPLEVEL))
 136                 return 1;
 137         return 0;
 138 }
 139 
 140 static char *ptr_prefix(struct symbol *sym)
 141 {
 142         static char buf[128];
 143 
 144 
 145         if (is_local_symbol(sym))
 146                 snprintf(buf, sizeof(buf), "%s ptr", get_function());
 147         else if (sym && toplevel(sym->scope))
 148                 snprintf(buf, sizeof(buf), "%s ptr", get_base_file());
 149         else
 150                 snprintf(buf, sizeof(buf), "ptr");
 151 
 152         return buf;
 153 }
 154 
 155 char *get_returned_ptr(struct expression *expr)
 156 {
 157         struct symbol *type;
 158         char *name;
 159         char buf[256];
 160 
 161         if (expr->type != EXPR_CALL)
 162                 return NULL;
 163         if (!expr->fn || expr->fn->type != EXPR_SYMBOL)
 164                 return NULL;
 165 
 166         type = get_type(expr);
 167         if (type && type->type == SYM_PTR)
 168                 type = get_real_base_type(type);
 169         if (!type || type->type != SYM_FN)
 170                 return NULL;
 171 
 172         name = expr_to_var(expr->fn);
 173         if (!name)
 174                 return NULL;
 175         snprintf(buf, sizeof(buf), "r %s()", name);
 176         free_string(name);
 177         return alloc_string(buf);
 178 }
 179 
 180 char *get_fnptr_name(struct expression *expr)
 181 {
 182         char *name;
 183 
 184         if (expr_is_zero(expr))
 185                 return NULL;
 186 
 187         expr = strip_expr(expr);
 188 
 189         /* (*ptrs[0])(a, b, c) is the same as ptrs[0](a, b, c); */
 190         if (expr->type == EXPR_PREOP && expr->op == '*')
 191                 expr = strip_expr(expr->unop);
 192 
 193         name = get_from__symbol_get(expr);
 194         if (name)
 195                 return name;
 196 
 197         name = get_array_ptr(expr);
 198         if (name)
 199                 return name;
 200 
 201         name = get_returned_ptr(expr);
 202         if (name)
 203                 return name;
 204 
 205         name = get_member_name(expr);
 206         if (name)
 207                 return name;
 208 
 209         if (expr->type == EXPR_SYMBOL) {
 210                 int param;
 211                 char buf[256];
 212                 struct symbol *sym;
 213                 struct symbol *type;
 214 
 215                 param = get_param_num_from_sym(expr->symbol);
 216                 if (param >= 0) {
 217                         snprintf(buf, sizeof(buf), "%s param %d", get_function(), param);
 218                         return alloc_string(buf);
 219                 }
 220 
 221                 name =  expr_to_var_sym(expr, &sym);
 222                 if (!name)
 223                         return NULL;
 224                 type = get_type(expr);
 225                 if (type && type->type == SYM_PTR) {
 226                         snprintf(buf, sizeof(buf), "%s %s", ptr_prefix(sym), name);
 227                         free_string(name);
 228                         return alloc_string(buf);
 229                 }
 230                 return name;
 231         }
 232         return expr_to_var(expr);
 233 }
 234 
 235 static void match_passes_function_pointer(struct expression *expr)
 236 {
 237         struct expression *arg, *tmp;
 238         struct symbol *type;
 239         char *called_name;
 240         char *fn_name;
 241         char ptr_name[256];
 242         int i;
 243 
 244 
 245         i = -1;
 246         FOR_EACH_PTR(expr->args, arg) {
 247                 i++;
 248 
 249                 tmp = strip_expr(arg);
 250                 if (tmp->type == EXPR_PREOP && tmp->op == '&')
 251                         tmp = strip_expr(tmp->unop);
 252 
 253                 type = get_type(tmp);
 254                 if (type && type->type == SYM_PTR)
 255                         type = get_real_base_type(type);
 256                 if (!type || type->type != SYM_FN)
 257                         continue;
 258 
 259                 called_name = expr_to_var(expr->fn);
 260                 if (!called_name)
 261                         return;
 262                 fn_name = get_fnptr_name(tmp);
 263                 if (!fn_name)
 264                         goto free;
 265 
 266                 snprintf(ptr_name, sizeof(ptr_name), "%s param %d", called_name, i);
 267                 sql_insert_function_ptr(fn_name, ptr_name);
 268 free:
 269                 free_string(fn_name);
 270                 free_string(called_name);
 271         } END_FOR_EACH_PTR(arg);
 272 
 273 }
 274 
 275 static int get_row_count(void *_row_count, int argc, char **argv, char **azColName)
 276 {
 277         int *row_count = _row_count;
 278 
 279         *row_count = 0;
 280         if (argc != 1)
 281                 return 0;
 282         *row_count = atoi(argv[0]);
 283         return 0;
 284 }
 285 
 286 static int can_hold_function_ptr(struct expression *expr)
 287 {
 288         struct symbol *type;
 289 
 290         type = get_type(expr);
 291         if (!type)
 292                 return 0;
 293         if (type->type == SYM_PTR || type->type == SYM_ARRAY) {
 294                 type = get_real_base_type(type);
 295                 if (!type)
 296                         return 0;
 297         }
 298         /* pointer to a pointer */
 299         if (type->type == SYM_PTR || type->type == SYM_ARRAY) {
 300                 type = get_real_base_type(type);
 301                 if (!type)
 302                         return 0;
 303         }
 304         if (type->type == SYM_FN)
 305                 return 1;
 306         if (type == &ulong_ctype && expr->type == EXPR_DEREF)
 307                 return 1;
 308         if (type == &void_ctype)
 309                 return 1;
 310         return 0;
 311 }
 312 
 313 static void match_function_assign(struct expression *expr)
 314 {
 315         struct expression *right;
 316         struct symbol *type;
 317         char *fn_name;
 318         char *ptr_name;
 319 
 320         if (__in_fake_assign)
 321                 return;
 322 
 323         right = strip_expr(expr->right);
 324         if (right->type == EXPR_PREOP && right->op == '&')
 325                 right = strip_expr(right->unop);
 326 
 327         if (right->type != EXPR_SYMBOL &&
 328             right->type != EXPR_DEREF &&
 329             right->type != EXPR_CALL)
 330                 return;
 331 
 332         if (!can_hold_function_ptr(right) ||
 333             !can_hold_function_ptr(expr->left))
 334                 return;
 335 
 336         fn_name = get_fnptr_name(right);
 337         ptr_name = get_fnptr_name(expr->left);
 338         if (!fn_name || !ptr_name)
 339                 goto free;
 340         if (strcmp(fn_name, ptr_name) == 0)
 341                 goto free;
 342 
 343 
 344         type = get_type(right);
 345         if (!type)
 346                 return;
 347         if (type->type == SYM_PTR || type->type == SYM_ARRAY) {
 348                 type = get_real_base_type(type);
 349                 if (!type)
 350                         return;
 351         }
 352         if (type->type != SYM_FN) {
 353                 int count = 0;
 354 
 355                 /* look it up in function_ptr */
 356                 run_sql(get_row_count, &count,
 357                         "select count(*) from function_ptr where ptr = '%s'",
 358                         fn_name);
 359                 if (count == 0)
 360                         goto free;
 361         }
 362 
 363         sql_insert_function_ptr(fn_name, ptr_name);
 364 free:
 365         free_string(fn_name);
 366         free_string(ptr_name);
 367 }
 368 
 369 static void match_returns_function_pointer(struct expression *expr)
 370 {
 371         struct symbol *type;
 372         char *fn_name;
 373         char ptr_name[256];
 374 
 375         if (__inline_fn)
 376                 return;
 377 
 378         type = get_real_base_type(cur_func_sym);
 379         if (!type || type->type != SYM_FN)
 380                 return;
 381         type = get_real_base_type(type);
 382         if (!type || type->type != SYM_PTR)
 383                 return;
 384         type = get_real_base_type(type);
 385         if (!type || type->type != SYM_FN)
 386                 return;
 387 
 388         if (expr->type == EXPR_PREOP && expr->op == '&')
 389                 expr = strip_expr(expr->unop);
 390 
 391         fn_name = get_fnptr_name(expr);
 392         if (!fn_name)
 393                 return;
 394         snprintf(ptr_name, sizeof(ptr_name), "r %s()", get_function());
 395         sql_insert_function_ptr(fn_name, ptr_name);
 396 }
 397 
 398 static void print_initializer_list(struct expression_list *expr_list,
 399                 struct symbol *struct_type)
 400 {
 401         struct expression *expr;
 402         struct symbol *base_type;
 403         char struct_name[256];
 404 
 405         FOR_EACH_PTR(expr_list, expr) {
 406                 if (expr->type == EXPR_INDEX && expr->idx_expression && expr->idx_expression->type == EXPR_INITIALIZER) {
 407                         print_initializer_list(expr->idx_expression->expr_list, struct_type);
 408                         continue;
 409                 }
 410                 if (expr->type != EXPR_IDENTIFIER)
 411                         continue;
 412                 if (!expr->expr_ident)
 413                         continue;
 414                 if (!expr->ident_expression ||
 415                     expr->ident_expression->type != EXPR_SYMBOL ||
 416                     !expr->ident_expression->symbol_name)
 417                         continue;
 418                 base_type = get_type(expr->ident_expression);
 419                 if (!base_type || base_type->type != SYM_FN)
 420                         continue;
 421                 snprintf(struct_name, sizeof(struct_name), "(struct %s)->%s",
 422                          struct_type->ident->name, expr->expr_ident->name);
 423                 sql_insert_function_ptr(expr->ident_expression->symbol_name->name,
 424                                         struct_name);
 425         } END_FOR_EACH_PTR(expr);
 426 }
 427 
 428 static void global_variable(struct symbol *sym)
 429 {
 430         struct symbol *struct_type;
 431 
 432         if (!sym->ident)
 433                 return;
 434         if (!sym->initializer || sym->initializer->type != EXPR_INITIALIZER)
 435                 return;
 436         struct_type = get_base_type(sym);
 437         if (!struct_type)
 438                 return;
 439         if (struct_type->type == SYM_ARRAY) {
 440                 struct_type = get_base_type(struct_type);
 441                 if (!struct_type)
 442                         return;
 443         }
 444         if (struct_type->type != SYM_STRUCT || !struct_type->ident)
 445                 return;
 446         print_initializer_list(sym->initializer->expr_list, struct_type);
 447 }
 448 
 449 void register_function_ptrs(int id)
 450 {
 451         my_id = id;
 452 
 453         if (!option_info)
 454                 return;
 455 
 456         add_hook(&global_variable, BASE_HOOK);
 457         add_hook(&global_variable, DECLARATION_HOOK);
 458         add_hook(&match_passes_function_pointer, FUNCTION_CALL_HOOK);
 459         add_hook(&match_returns_function_pointer, RETURN_HOOK);
 460         add_hook(&match_function_assign, ASSIGNMENT_HOOK);
 461         add_hook(&match_function_assign, GLOBAL_ASSIGNMENT_HOOK);
 462 }