1 /* 2 * Copyright (C) 2014 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 #include "smatch.h" 19 #include "smatch_extra.h" 20 21 static int my_id; 22 23 STATE(readl); 24 STATE(readl_ff); 25 STATE(readl_00); 26 27 DECLARE_PTR_LIST(state_stack, struct smatch_state); 28 struct state_stack *state_at_start; 29 30 static int readl_has_been_called; 31 static int returned; 32 33 static int is_readl_call(struct expression *expr) 34 { 35 struct symbol *sym; 36 37 expr = strip_expr(expr); 38 if (expr->type != EXPR_CALL) 39 return 0; 40 if (expr->fn->type != EXPR_SYMBOL) 41 return 0; 42 sym = expr->fn->symbol; 43 if (!sym || !sym->ident) 44 return 0; 45 if (strcmp(sym->ident->name, "readl") != 0) 46 return 0; 47 return 1; 48 } 49 50 static int is_readl(struct expression *expr) 51 { 52 if (is_readl_call(expr)) 53 return 1; 54 if (get_state_expr(my_id, expr) == &readl) 55 return 1; 56 return 0; 57 } 58 59 static void match_assign(struct expression *expr) 60 { 61 if (is_readl(expr->right)) 62 set_state_expr(my_id, expr->left, &readl); 63 else if (get_state_expr(my_id, expr->left)) 64 set_state_expr(my_id, expr->left, &undefined); 65 } 66 67 static int condition_depends_on_readl(struct expression *expr) 68 { 69 if (expr->type == EXPR_BINOP) { 70 if (condition_depends_on_readl(expr->left)) 71 return 1; 72 if (condition_depends_on_readl(expr->right)) 73 return 1; 74 return 0; 75 } 76 if (is_readl(expr)) 77 return 1; 78 return 0; 79 } 80 81 static void check_condition(struct expression *expr) 82 { 83 if (expr->op != '&') 84 return; 85 if (!condition_depends_on_readl(expr)) 86 return; 87 readl_has_been_called = 1; 88 set_true_false_states(my_id, "depends on", NULL, &readl_ff, &readl_00); 89 } 90 91 static void match_return(struct expression *expr) 92 { 93 94 if (__inline_fn) 95 return; 96 returned = 1; 97 #if 0 98 struct smatch_state *tmp; 99 100 if (!readl_has_been_called) 101 return; 102 103 FOR_EACH_PTR(state_at_start, tmp) { 104 REPLACE_CURRENT_PTR(tmp, NULL); 105 } 106 #endif 107 } 108 109 static void push_state_at_start(struct smatch_state *state) 110 { 111 add_ptr_list(&state_at_start, state); 112 } 113 114 static struct smatch_state *pop_state_at_start(void) 115 { 116 struct smatch_state *state; 117 118 state = last_ptr_list((struct ptr_list *)state_at_start); 119 delete_ptr_list_last((struct ptr_list **)&state_at_start); 120 return state; 121 } 122 123 static void before_loop(struct statement *stmt) 124 { 125 struct smatch_state *state; 126 127 if (!stmt || stmt->type != STMT_ITERATOR) 128 return; 129 if (ptr_list_empty((struct ptr_list *)state_at_start)) 130 returned = 0; 131 state = get_state(my_id, "depends on", NULL); 132 push_state_at_start(state); 133 } 134 135 static void after_loop(struct statement *stmt) 136 { 137 struct smatch_state *old_state; 138 139 if (!stmt || stmt->type != STMT_ITERATOR) 140 return; 141 old_state = pop_state_at_start(); 142 if (old_state == &readl_00) 143 return; 144 if (returned) 145 return; 146 if (get_state(my_id, "depends on", NULL) != &readl_00) 147 return; 148 sm_warning("this loop depends on readl() succeeding"); 149 } 150 151 void check_readl_infinite_loops(int id) 152 { 153 if (option_project != PROJ_KERNEL) 154 return; 155 156 my_id = id; 157 158 add_hook(match_assign, ASSIGNMENT_HOOK); 159 add_hook(check_condition, CONDITION_HOOK); 160 161 add_hook(&match_return, RETURN_HOOK); 162 163 add_hook(before_loop, STMT_HOOK); 164 add_hook(after_loop, STMT_HOOK_AFTER); 165 } 166