1 /* 2 * Copyright (C) 2017 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 * Say you have assign a function to a function pointer and you assign a 20 * pointer to the data argument then we want to record some information about 21 * the argument. Right now what I mainly want to record is the type of it, I 22 * guess. 23 * 24 */ 25 26 #include "smatch.h" 27 #include "smatch_extra.h" 28 #include "smatch_slist.h" 29 #include <ctype.h> 30 31 static int my_id; 32 33 static int assigns_parameters(struct expression *fn, struct expression *arg) 34 { 35 int fn_param, arg_param; 36 char buf[32]; 37 38 fn_param = get_param_num(fn); 39 if (fn_param < 0) 40 return 0; 41 42 arg_param = get_param_num(arg); 43 if (arg_param < 0) 44 return 0; 45 46 snprintf(buf, sizeof(buf), "%d", arg_param); 47 sql_insert_return_implies(FN_ARG_LINK, fn_param, "$", buf); 48 return 1; 49 } 50 51 static void link_function_arg(struct expression *fn, int param, struct expression *arg) 52 { 53 struct symbol *type; 54 55 if (!fn || !arg) 56 return; 57 if (assigns_parameters(fn, arg)) 58 return; 59 60 type = get_type(arg); 61 if (!type || type->type != SYM_PTR) 62 return; 63 type = get_real_base_type(type); 64 if (!type) 65 return; 66 // FIXME: param shouldn't always be 0? 67 sql_insert_fn_data_link(fn, PASSES_TYPE, param, "$", type_to_str(type)); 68 } 69 70 char *next_param_name; 71 struct symbol *next_param_sym; 72 struct expression *next_fn; 73 static void match_assign_param(struct expression *expr) 74 { 75 struct symbol *sym; 76 char *name; 77 78 if (!next_param_name) 79 return; 80 81 name = expr_to_var_sym(expr->left, &sym); 82 if (!name || !sym) { 83 free_string(name); 84 return; 85 } 86 87 if (sym != next_param_sym || 88 strcmp(name, next_param_name) != 0) 89 return; 90 91 link_function_arg(next_fn, 0, strip_expr(expr->right)); 92 93 next_param_name = 0; 94 next_param_sym = NULL; 95 next_fn = NULL; 96 } 97 98 static int get_arg_ptr(void *_arg_ptr, int argc, char **argv, char **azColName) 99 { 100 char **arg_ptr = _arg_ptr; 101 102 *arg_ptr = NULL; 103 if (argc != 1) 104 return 0; 105 *arg_ptr = alloc_string(argv[0]); 106 return 0; 107 } 108 109 static char *get_data_member(char *fn_member, struct expression *expr, struct symbol **sym) 110 { 111 struct symbol *tmp_sym; 112 char *fn_str; 113 char *arg_ptr = NULL; 114 char *end_type; 115 int len_ptr, len_str; 116 char buf[128]; 117 118 *sym = NULL; 119 run_sql(get_arg_ptr, &arg_ptr, 120 "select data from fn_ptr_data_link where fn_ptr = '%s';", fn_member); 121 if (!arg_ptr) 122 return NULL; 123 end_type = strchr(arg_ptr, '>'); 124 if (!end_type) 125 return NULL; 126 end_type++; 127 fn_str = expr_to_var_sym(expr, &tmp_sym); 128 if (!fn_str || !tmp_sym) 129 return NULL; 130 len_ptr = strlen(fn_member); 131 len_str = strlen(fn_str); 132 while (len_str > 0 && len_ptr > 0) { 133 if (fn_str[len_str - 1] != fn_member[len_ptr - 1]) 134 break; 135 if (fn_str[len_str - 1] == '>') 136 break; 137 len_str--; 138 len_ptr--; 139 } 140 141 strncpy(buf, fn_str, sizeof(buf)); 142 snprintf(buf + len_str, sizeof(buf) - len_str, end_type); 143 *sym = tmp_sym; 144 return alloc_string(buf); 145 } 146 147 static void match_assign_function(struct expression *expr) 148 { 149 struct expression *right, *arg; 150 struct symbol *sym; 151 char *data_member; 152 struct symbol *type; 153 char *member_name; 154 155 right = strip_expr(expr->right); 156 if (right->type == EXPR_PREOP && right->op == '&') 157 right = strip_expr(right->unop); 158 159 type = get_type(right); 160 if (type && type->type == SYM_PTR) 161 type = get_real_base_type(type); 162 if (!type || type->type != SYM_FN) 163 return; 164 165 member_name = get_member_name(expr->left); 166 if (!member_name) 167 return; 168 169 data_member = get_data_member(member_name, expr->left, &sym); 170 if (!data_member || !sym) { 171 free_string(data_member); 172 data_member = NULL; 173 } 174 175 arg = get_assigned_expr_name_sym(data_member, sym); 176 if (arg) { 177 link_function_arg(right, 0, arg); 178 } else { 179 next_param_name = data_member; 180 next_param_sym = sym; 181 next_fn = right; 182 } 183 } 184 185 static int is_recursive_call(struct expression *call) 186 { 187 if (call->fn->type != EXPR_SYMBOL) 188 return 0; 189 if (call->fn->symbol == cur_func_sym) 190 return 1; 191 return 0; 192 } 193 194 static void check_passes_fn_and_data(struct expression *call, struct expression *fn, char *key, char *value) 195 { 196 struct expression *arg; 197 struct symbol *type; 198 int data_nr; 199 200 if (is_recursive_call(call)) 201 return; 202 203 type = get_type(fn); 204 if (!type || type->type != SYM_FN) 205 return; 206 207 if (!isdigit(value[0])) 208 return; 209 data_nr = atoi(value); 210 arg = get_argument_from_call_expr(call->args, data_nr); 211 if (!arg) 212 return; 213 link_function_arg(fn, 0, arg); 214 } 215 216 static void match_end_func(struct symbol *sym) 217 { 218 next_param_sym = NULL; 219 next_fn = NULL; 220 } 221 222 void register_about_fn_ptr_arg(int id) 223 { 224 my_id = id; 225 226 if (0 && !option_info) 227 return; 228 add_hook(match_assign_param, ASSIGNMENT_HOOK); 229 add_hook(match_assign_function, ASSIGNMENT_HOOK); 230 select_return_implies_hook(FN_ARG_LINK, &check_passes_fn_and_data); 231 add_hook(&match_end_func, END_FUNC_HOOK); 232 } 233