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         expr = strip_expr(expr);
 145 
 146         /* (*ptrs[0])(a, b, c) is the same as ptrs[0](a, b, c); */
 147         if (expr->type == EXPR_PREOP && expr->op == '*')
 148                 expr = strip_expr(expr->unop);
 149 
 150         name = get_from__symbol_get(expr);
 151         if (name)
 152                 return name;
 153 
 154         name = get_array_ptr(expr);
 155         if (name)
 156                 return name;
 157 
 158         name = get_returned_ptr(expr);
 159         if (name)
 160                 return name;
 161 
 162         name = get_member_name(expr);
 163         if (name)
 164                 return name;
 165 
 166         if (expr->type == EXPR_SYMBOL) {
 167                 int param;
 168                 char buf[256];
 169                 struct symbol *sym;
 170                 struct symbol *type;
 171 
 172                 param = get_param_num_from_sym(expr->symbol);
 173                 if (param >= 0) {
 174                         snprintf(buf, sizeof(buf), "%s param %d", get_function(), param);
 175                         return alloc_string(buf);
 176                 }
 177 
 178                 name =  expr_to_var_sym(expr, &sym);
 179                 if (!name)
 180                         return NULL;
 181                 type = get_type(expr);
 182                 if (type && type->type == SYM_PTR) {
 183                         snprintf(buf, sizeof(buf), "%s %s", ptr_prefix(sym), name);
 184                         free_string(name);
 185                         return alloc_string(buf);
 186                 }
 187                 return name;
 188         }
 189         return expr_to_var(expr);
 190 }
 191 
 192 static void match_passes_function_pointer(struct expression *expr)
 193 {
 194         struct expression *arg, *tmp;
 195         struct symbol *type;
 196         char *called_name;
 197         char *fn_name;
 198         char ptr_name[256];
 199         int i;
 200 
 201 
 202         i = -1;
 203         FOR_EACH_PTR(expr->args, arg) {
 204                 i++;
 205 
 206                 tmp = strip_expr(arg);
 207                 if (tmp->type == EXPR_PREOP && tmp->op == '&')
 208                         tmp = strip_expr(tmp->unop);
 209 
 210                 type = get_type(tmp);
 211                 if (type && type->type == SYM_PTR)
 212                         type = get_real_base_type(type);
 213                 if (!type || type->type != SYM_FN)
 214                         continue;
 215 
 216                 called_name = expr_to_var(expr->fn);
 217                 if (!called_name)
 218                         return;
 219                 fn_name = get_fnptr_name(tmp);
 220                 if (!fn_name)
 221                         goto free;
 222 
 223                 snprintf(ptr_name, sizeof(ptr_name), "%s param %d", called_name, i);
 224                 sql_insert_function_ptr(fn_name, ptr_name);
 225 free:
 226                 free_string(fn_name);
 227                 free_string(called_name);
 228         } END_FOR_EACH_PTR(arg);
 229 
 230 }
 231 
 232 static int get_row_count(void *_row_count, int argc, char **argv, char **azColName)
 233 {
 234         int *row_count = _row_count;
 235 
 236         *row_count = 0;
 237         if (argc != 1)
 238                 return 0;
 239         *row_count = atoi(argv[0]);
 240         return 0;
 241 }
 242 
 243 static int can_hold_function_ptr(struct expression *expr)
 244 {
 245         struct symbol *type;
 246 
 247         type = get_type(expr);
 248         if (!type)
 249                 return 0;
 250         if (type->type == SYM_PTR || type->type == SYM_ARRAY) {
 251                 type = get_real_base_type(type);
 252                 if (!type)
 253                         return 0;
 254         }
 255         if (type->type == SYM_FN)
 256                 return 1;
 257         if (type == &ulong_ctype && expr->type == EXPR_DEREF)
 258                 return 1;
 259         if (type == &void_ctype)
 260                 return 1;
 261         return 0;
 262 }
 263 
 264 static void match_function_assign(struct expression *expr)
 265 {
 266         struct expression *right;
 267         struct symbol *type;
 268         char *fn_name;
 269         char *ptr_name;
 270 
 271         if (__in_fake_assign)
 272                 return;
 273 
 274         right = strip_expr(expr->right);
 275         if (right->type == EXPR_PREOP && right->op == '&')
 276                 right = strip_expr(right->unop);
 277 
 278         if (right->type != EXPR_SYMBOL &&
 279             right->type != EXPR_DEREF)
 280                 return;
 281 
 282         if (!can_hold_function_ptr(right) ||
 283             !can_hold_function_ptr(expr->left))
 284                 return;
 285 
 286         fn_name = get_fnptr_name(right);
 287         ptr_name = get_fnptr_name(expr->left);
 288         if (!fn_name || !ptr_name)
 289                 goto free;
 290         if (strcmp(fn_name, ptr_name) == 0)
 291                 goto free;
 292 
 293 
 294         type = get_type(right);
 295         if (!type)
 296                 return;
 297         if (type->type == SYM_PTR || type->type == SYM_ARRAY) {
 298                 type = get_real_base_type(type);
 299                 if (!type)
 300                         return;
 301         }
 302         if (type->type != SYM_FN) {
 303                 int count = 0;
 304 
 305                 /* look it up in function_ptr */
 306                 run_sql(get_row_count, &count,
 307                         "select count(*) from function_ptr where ptr = '%s'",
 308                         fn_name);
 309                 if (count == 0)
 310                         goto free;
 311         }
 312 
 313         sql_insert_function_ptr(fn_name, ptr_name);
 314 free:
 315         free_string(fn_name);
 316         free_string(ptr_name);
 317 }
 318 
 319 static void match_returns_function_pointer(struct expression *expr)
 320 {
 321         struct symbol *type;
 322         char *fn_name;
 323         char ptr_name[256];
 324 
 325         if (__inline_fn)
 326                 return;
 327 
 328         type = get_real_base_type(cur_func_sym);
 329         if (!type || type->type != SYM_FN)
 330                 return;
 331         type = get_real_base_type(type);
 332         if (!type || type->type != SYM_PTR)
 333                 return;
 334         type = get_real_base_type(type);
 335         if (!type || type->type != SYM_FN)
 336                 return;
 337 
 338         if (expr->type == EXPR_PREOP && expr->op == '&')
 339                 expr = strip_expr(expr->unop);
 340 
 341         fn_name = get_fnptr_name(expr);
 342         if (!fn_name)
 343                 return;
 344         snprintf(ptr_name, sizeof(ptr_name), "r %s()", get_function());
 345         sql_insert_function_ptr(fn_name, ptr_name);
 346 }
 347 
 348 void register_function_ptrs(int id)
 349 {
 350         my_id = id;
 351 
 352         if (!option_info)
 353                 return;
 354 
 355         add_hook(&match_passes_function_pointer, FUNCTION_CALL_HOOK);
 356         add_hook(&match_returns_function_pointer, RETURN_HOOK);
 357         add_hook(&match_function_assign, ASSIGNMENT_HOOK);
 358         add_hook(&match_function_assign, GLOBAL_ASSIGNMENT_HOOK);
 359 }