1*1f5207b7SJohn Levon /* 2*1f5207b7SJohn Levon * Copyright (C) 2009 Dan Carpenter. 3*1f5207b7SJohn Levon * 4*1f5207b7SJohn Levon * This program is free software; you can redistribute it and/or 5*1f5207b7SJohn Levon * modify it under the terms of the GNU General Public License 6*1f5207b7SJohn Levon * as published by the Free Software Foundation; either version 2 7*1f5207b7SJohn Levon * of the License, or (at your option) any later version. 8*1f5207b7SJohn Levon * 9*1f5207b7SJohn Levon * This program is distributed in the hope that it will be useful, 10*1f5207b7SJohn Levon * but WITHOUT ANY WARRANTY; without even the implied warranty of 11*1f5207b7SJohn Levon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12*1f5207b7SJohn Levon * GNU General Public License for more details. 13*1f5207b7SJohn Levon * 14*1f5207b7SJohn Levon * You should have received a copy of the GNU General Public License 15*1f5207b7SJohn Levon * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt 16*1f5207b7SJohn Levon */ 17*1f5207b7SJohn Levon 18*1f5207b7SJohn Levon /* 19*1f5207b7SJohn Levon * There are a number of ways that variables are modified: 20*1f5207b7SJohn Levon * 1) assignment 21*1f5207b7SJohn Levon * 2) increment/decrement 22*1f5207b7SJohn Levon * 3) assembly 23*1f5207b7SJohn Levon * 4) inside functions. 24*1f5207b7SJohn Levon * 25*1f5207b7SJohn Levon * For setting stuff inside a function then, of course, it's more accurate if 26*1f5207b7SJohn Levon * you have the cross function database built. Otherwise we are super 27*1f5207b7SJohn Levon * aggressive about marking things as modified and if you have "frob(foo);" then 28*1f5207b7SJohn Levon * we assume "foo->bar" is modified. 29*1f5207b7SJohn Levon */ 30*1f5207b7SJohn Levon 31*1f5207b7SJohn Levon #include <stdlib.h> 32*1f5207b7SJohn Levon #include <stdio.h> 33*1f5207b7SJohn Levon #include "smatch.h" 34*1f5207b7SJohn Levon #include "smatch_extra.h" 35*1f5207b7SJohn Levon #include "smatch_slist.h" 36*1f5207b7SJohn Levon 37*1f5207b7SJohn Levon enum { 38*1f5207b7SJohn Levon EARLY = 0, 39*1f5207b7SJohn Levon LATE = 1, 40*1f5207b7SJohn Levon BOTH = 2 41*1f5207b7SJohn Levon }; 42*1f5207b7SJohn Levon 43*1f5207b7SJohn Levon static modification_hook **hooks; 44*1f5207b7SJohn Levon static modification_hook **hooks_late; 45*1f5207b7SJohn Levon 46*1f5207b7SJohn Levon ALLOCATOR(modification_data, "modification data"); 47*1f5207b7SJohn Levon 48*1f5207b7SJohn Levon static int my_id; 49*1f5207b7SJohn Levon static struct smatch_state *alloc_my_state(struct expression *expr, struct smatch_state *prev) 50*1f5207b7SJohn Levon { 51*1f5207b7SJohn Levon struct smatch_state *state; 52*1f5207b7SJohn Levon struct modification_data *data; 53*1f5207b7SJohn Levon char *name; 54*1f5207b7SJohn Levon 55*1f5207b7SJohn Levon state = __alloc_smatch_state(0); 56*1f5207b7SJohn Levon expr = strip_expr(expr); 57*1f5207b7SJohn Levon name = expr_to_str(expr); 58*1f5207b7SJohn Levon state->name = alloc_sname(name); 59*1f5207b7SJohn Levon free_string(name); 60*1f5207b7SJohn Levon 61*1f5207b7SJohn Levon data = __alloc_modification_data(0); 62*1f5207b7SJohn Levon data->prev = prev; 63*1f5207b7SJohn Levon data->cur = expr; 64*1f5207b7SJohn Levon state->data = data; 65*1f5207b7SJohn Levon 66*1f5207b7SJohn Levon return state; 67*1f5207b7SJohn Levon } 68*1f5207b7SJohn Levon 69*1f5207b7SJohn Levon void add_modification_hook(int owner, modification_hook *call_back) 70*1f5207b7SJohn Levon { 71*1f5207b7SJohn Levon if (hooks[owner]) 72*1f5207b7SJohn Levon sm_fatal("multiple modification hooks for %s", check_name(owner)); 73*1f5207b7SJohn Levon hooks[owner] = call_back; 74*1f5207b7SJohn Levon } 75*1f5207b7SJohn Levon 76*1f5207b7SJohn Levon void add_modification_hook_late(int owner, modification_hook *call_back) 77*1f5207b7SJohn Levon { 78*1f5207b7SJohn Levon if (hooks_late[owner]) 79*1f5207b7SJohn Levon sm_fatal("multiple late modification hooks for %s", check_name(owner)); 80*1f5207b7SJohn Levon hooks_late[owner] = call_back; 81*1f5207b7SJohn Levon } 82*1f5207b7SJohn Levon 83*1f5207b7SJohn Levon static int matches(char *name, struct symbol *sym, struct sm_state *sm) 84*1f5207b7SJohn Levon { 85*1f5207b7SJohn Levon int len; 86*1f5207b7SJohn Levon 87*1f5207b7SJohn Levon if (sym != sm->sym) 88*1f5207b7SJohn Levon return false; 89*1f5207b7SJohn Levon 90*1f5207b7SJohn Levon len = strlen(name); 91*1f5207b7SJohn Levon if (strncmp(sm->name, name, len) == 0) { 92*1f5207b7SJohn Levon if (sm->name[len] == '\0') 93*1f5207b7SJohn Levon return true; 94*1f5207b7SJohn Levon if (sm->name[len] == '-' || sm->name[len] == '.') 95*1f5207b7SJohn Levon return true; 96*1f5207b7SJohn Levon } 97*1f5207b7SJohn Levon if (sm->name[0] != '*') 98*1f5207b7SJohn Levon return false; 99*1f5207b7SJohn Levon if (strncmp(sm->name + 1, name, len) == 0) { 100*1f5207b7SJohn Levon if (sm->name[len + 1] == '\0') 101*1f5207b7SJohn Levon return true; 102*1f5207b7SJohn Levon if (sm->name[len + 1] == '-' || sm->name[len + 1] == '.') 103*1f5207b7SJohn Levon return true; 104*1f5207b7SJohn Levon } 105*1f5207b7SJohn Levon return false; 106*1f5207b7SJohn Levon } 107*1f5207b7SJohn Levon 108*1f5207b7SJohn Levon static void call_modification_hooks_name_sym(char *name, struct symbol *sym, struct expression *mod_expr, int late) 109*1f5207b7SJohn Levon { 110*1f5207b7SJohn Levon struct sm_state *sm; 111*1f5207b7SJohn Levon struct smatch_state *prev; 112*1f5207b7SJohn Levon int match; 113*1f5207b7SJohn Levon 114*1f5207b7SJohn Levon prev = get_state(my_id, name, sym); 115*1f5207b7SJohn Levon 116*1f5207b7SJohn Levon if (cur_func_sym && !__in_fake_assign) 117*1f5207b7SJohn Levon set_state(my_id, name, sym, alloc_my_state(mod_expr, prev)); 118*1f5207b7SJohn Levon 119*1f5207b7SJohn Levon FOR_EACH_SM(__get_cur_stree(), sm) { 120*1f5207b7SJohn Levon if (sm->owner > num_checks) 121*1f5207b7SJohn Levon continue; 122*1f5207b7SJohn Levon match = matches(name, sym, sm); 123*1f5207b7SJohn Levon if (!match) 124*1f5207b7SJohn Levon continue; 125*1f5207b7SJohn Levon 126*1f5207b7SJohn Levon if (late == EARLY || late == BOTH) { 127*1f5207b7SJohn Levon if (hooks[sm->owner]) 128*1f5207b7SJohn Levon (hooks[sm->owner])(sm, mod_expr); 129*1f5207b7SJohn Levon } 130*1f5207b7SJohn Levon if (late == LATE || late == BOTH) { 131*1f5207b7SJohn Levon if (hooks_late[sm->owner]) 132*1f5207b7SJohn Levon (hooks_late[sm->owner])(sm, mod_expr); 133*1f5207b7SJohn Levon } 134*1f5207b7SJohn Levon 135*1f5207b7SJohn Levon } END_FOR_EACH_SM(sm); 136*1f5207b7SJohn Levon } 137*1f5207b7SJohn Levon 138*1f5207b7SJohn Levon static void call_modification_hooks(struct expression *expr, struct expression *mod_expr, int late) 139*1f5207b7SJohn Levon { 140*1f5207b7SJohn Levon char *name; 141*1f5207b7SJohn Levon struct symbol *sym; 142*1f5207b7SJohn Levon 143*1f5207b7SJohn Levon if (late == LATE) 144*1f5207b7SJohn Levon update_mtag_data(expr); 145*1f5207b7SJohn Levon 146*1f5207b7SJohn Levon name = expr_to_known_chunk_sym(expr, &sym); 147*1f5207b7SJohn Levon if (!name) 148*1f5207b7SJohn Levon goto free; 149*1f5207b7SJohn Levon call_modification_hooks_name_sym(name, sym, mod_expr, late); 150*1f5207b7SJohn Levon free: 151*1f5207b7SJohn Levon free_string(name); 152*1f5207b7SJohn Levon } 153*1f5207b7SJohn Levon 154*1f5207b7SJohn Levon static void db_param_add(struct expression *expr, int param, char *key, char *value) 155*1f5207b7SJohn Levon { 156*1f5207b7SJohn Levon struct expression *arg, *gen_expr; 157*1f5207b7SJohn Levon char *name, *other_name; 158*1f5207b7SJohn Levon struct symbol *sym, *other_sym; 159*1f5207b7SJohn Levon 160*1f5207b7SJohn Levon while (expr->type == EXPR_ASSIGNMENT) 161*1f5207b7SJohn Levon expr = strip_expr(expr->right); 162*1f5207b7SJohn Levon if (expr->type != EXPR_CALL) 163*1f5207b7SJohn Levon return; 164*1f5207b7SJohn Levon 165*1f5207b7SJohn Levon arg = get_argument_from_call_expr(expr->args, param); 166*1f5207b7SJohn Levon if (!arg) 167*1f5207b7SJohn Levon return; 168*1f5207b7SJohn Levon 169*1f5207b7SJohn Levon gen_expr = gen_expression_from_key(arg, key); 170*1f5207b7SJohn Levon if (gen_expr) 171*1f5207b7SJohn Levon update_mtag_data(gen_expr); 172*1f5207b7SJohn Levon 173*1f5207b7SJohn Levon name = get_variable_from_key(arg, key, &sym); 174*1f5207b7SJohn Levon if (!name || !sym) 175*1f5207b7SJohn Levon goto free; 176*1f5207b7SJohn Levon 177*1f5207b7SJohn Levon __in_fake_assign++; 178*1f5207b7SJohn Levon call_modification_hooks_name_sym(name, sym, expr, BOTH); 179*1f5207b7SJohn Levon __in_fake_assign--; 180*1f5207b7SJohn Levon 181*1f5207b7SJohn Levon other_name = map_long_to_short_name_sym(name, sym, &other_sym); 182*1f5207b7SJohn Levon if (other_name) { 183*1f5207b7SJohn Levon __in_fake_assign++; 184*1f5207b7SJohn Levon call_modification_hooks_name_sym(other_name, other_sym, expr, BOTH); 185*1f5207b7SJohn Levon __in_fake_assign--; 186*1f5207b7SJohn Levon free_string(other_name); 187*1f5207b7SJohn Levon } 188*1f5207b7SJohn Levon 189*1f5207b7SJohn Levon free: 190*1f5207b7SJohn Levon free_string(name); 191*1f5207b7SJohn Levon } 192*1f5207b7SJohn Levon 193*1f5207b7SJohn Levon static void match_assign(struct expression *expr, int late) 194*1f5207b7SJohn Levon { 195*1f5207b7SJohn Levon call_modification_hooks(expr->left, expr, late); 196*1f5207b7SJohn Levon } 197*1f5207b7SJohn Levon 198*1f5207b7SJohn Levon static void unop_expr(struct expression *expr, int late) 199*1f5207b7SJohn Levon { 200*1f5207b7SJohn Levon if (expr->op != SPECIAL_DECREMENT && expr->op != SPECIAL_INCREMENT) 201*1f5207b7SJohn Levon return; 202*1f5207b7SJohn Levon 203*1f5207b7SJohn Levon call_modification_hooks(expr->unop, expr, late); 204*1f5207b7SJohn Levon } 205*1f5207b7SJohn Levon 206*1f5207b7SJohn Levon static void match_call(struct expression *expr) 207*1f5207b7SJohn Levon { 208*1f5207b7SJohn Levon struct expression *arg, *tmp; 209*1f5207b7SJohn Levon 210*1f5207b7SJohn Levon /* If we have the DB then trust the DB */ 211*1f5207b7SJohn Levon if (!option_no_db) 212*1f5207b7SJohn Levon return; 213*1f5207b7SJohn Levon 214*1f5207b7SJohn Levon FOR_EACH_PTR(expr->args, arg) { 215*1f5207b7SJohn Levon tmp = strip_expr(arg); 216*1f5207b7SJohn Levon if (tmp->type == EXPR_PREOP && tmp->op == '&') 217*1f5207b7SJohn Levon call_modification_hooks(tmp->unop, expr, BOTH); 218*1f5207b7SJohn Levon else 219*1f5207b7SJohn Levon call_modification_hooks(deref_expression(tmp), expr, BOTH); 220*1f5207b7SJohn Levon } END_FOR_EACH_PTR(arg); 221*1f5207b7SJohn Levon } 222*1f5207b7SJohn Levon 223*1f5207b7SJohn Levon static void asm_expr(struct statement *stmt, int late) 224*1f5207b7SJohn Levon { 225*1f5207b7SJohn Levon struct expression *expr; 226*1f5207b7SJohn Levon int state = 0; 227*1f5207b7SJohn Levon 228*1f5207b7SJohn Levon FOR_EACH_PTR(stmt->asm_outputs, expr) { 229*1f5207b7SJohn Levon switch (state) { 230*1f5207b7SJohn Levon case 0: /* identifier */ 231*1f5207b7SJohn Levon case 1: /* constraint */ 232*1f5207b7SJohn Levon state++; 233*1f5207b7SJohn Levon continue; 234*1f5207b7SJohn Levon case 2: /* expression */ 235*1f5207b7SJohn Levon state = 0; 236*1f5207b7SJohn Levon call_modification_hooks(expr, NULL, late); 237*1f5207b7SJohn Levon continue; 238*1f5207b7SJohn Levon } 239*1f5207b7SJohn Levon } END_FOR_EACH_PTR(expr); 240*1f5207b7SJohn Levon } 241*1f5207b7SJohn Levon 242*1f5207b7SJohn Levon 243*1f5207b7SJohn Levon static void match_assign_early(struct expression *expr) 244*1f5207b7SJohn Levon { 245*1f5207b7SJohn Levon match_assign(expr, EARLY); 246*1f5207b7SJohn Levon } 247*1f5207b7SJohn Levon 248*1f5207b7SJohn Levon static void unop_expr_early(struct expression *expr) 249*1f5207b7SJohn Levon { 250*1f5207b7SJohn Levon unop_expr(expr, EARLY); 251*1f5207b7SJohn Levon } 252*1f5207b7SJohn Levon 253*1f5207b7SJohn Levon static void asm_expr_early(struct statement *stmt) 254*1f5207b7SJohn Levon { 255*1f5207b7SJohn Levon asm_expr(stmt, EARLY); 256*1f5207b7SJohn Levon } 257*1f5207b7SJohn Levon 258*1f5207b7SJohn Levon static void match_assign_late(struct expression *expr) 259*1f5207b7SJohn Levon { 260*1f5207b7SJohn Levon match_assign(expr, LATE); 261*1f5207b7SJohn Levon } 262*1f5207b7SJohn Levon 263*1f5207b7SJohn Levon static void unop_expr_late(struct expression *expr) 264*1f5207b7SJohn Levon { 265*1f5207b7SJohn Levon unop_expr(expr, LATE); 266*1f5207b7SJohn Levon } 267*1f5207b7SJohn Levon 268*1f5207b7SJohn Levon static void asm_expr_late(struct statement *stmt) 269*1f5207b7SJohn Levon { 270*1f5207b7SJohn Levon asm_expr(stmt, LATE); 271*1f5207b7SJohn Levon } 272*1f5207b7SJohn Levon 273*1f5207b7SJohn Levon struct smatch_state *get_modification_state(struct expression *expr) 274*1f5207b7SJohn Levon { 275*1f5207b7SJohn Levon return get_state_expr(my_id, expr); 276*1f5207b7SJohn Levon } 277*1f5207b7SJohn Levon 278*1f5207b7SJohn Levon void register_modification_hooks(int id) 279*1f5207b7SJohn Levon { 280*1f5207b7SJohn Levon my_id = id; 281*1f5207b7SJohn Levon 282*1f5207b7SJohn Levon hooks = malloc((num_checks + 1) * sizeof(*hooks)); 283*1f5207b7SJohn Levon memset(hooks, 0, (num_checks + 1) * sizeof(*hooks)); 284*1f5207b7SJohn Levon hooks_late = malloc((num_checks + 1) * sizeof(*hooks)); 285*1f5207b7SJohn Levon memset(hooks_late, 0, (num_checks + 1) * sizeof(*hooks)); 286*1f5207b7SJohn Levon 287*1f5207b7SJohn Levon add_hook(&match_assign_early, ASSIGNMENT_HOOK); 288*1f5207b7SJohn Levon add_hook(&unop_expr_early, OP_HOOK); 289*1f5207b7SJohn Levon add_hook(&asm_expr_early, ASM_HOOK); 290*1f5207b7SJohn Levon } 291*1f5207b7SJohn Levon 292*1f5207b7SJohn Levon void register_modification_hooks_late(int id) 293*1f5207b7SJohn Levon { 294*1f5207b7SJohn Levon add_hook(&match_call, FUNCTION_CALL_HOOK); 295*1f5207b7SJohn Levon 296*1f5207b7SJohn Levon select_return_states_hook(PARAM_ADD, &db_param_add); 297*1f5207b7SJohn Levon select_return_states_hook(PARAM_SET, &db_param_add); 298*1f5207b7SJohn Levon 299*1f5207b7SJohn Levon add_hook(&match_assign_late, ASSIGNMENT_HOOK_AFTER); 300*1f5207b7SJohn Levon add_hook(&unop_expr_late, OP_HOOK); 301*1f5207b7SJohn Levon add_hook(&asm_expr_late, ASM_HOOK); 302*1f5207b7SJohn Levon } 303*1f5207b7SJohn Levon 304