1 /* 2 * Copyright (C) 2012 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 * This test is used to warn about mixups between bit shifters and bit flags. 20 * 21 */ 22 23 #include "smatch.h" 24 #include "smatch_function_hashtable.h" 25 26 static int my_id; 27 28 static DEFINE_HASHTABLE_INSERT(insert_struct, char, int); 29 static DEFINE_HASHTABLE_SEARCH(search_struct, char, int); 30 static struct hashtable *shifters; 31 32 static const char *get_shifter(struct expression *expr) 33 { 34 const char *name; 35 sval_t expr_value; 36 const int *shifter_value; 37 38 expr = strip_expr(expr); 39 if (expr->type != EXPR_VALUE) 40 return NULL; 41 if (!get_value(expr, &expr_value)) 42 return NULL; 43 name = pos_ident(expr->pos); 44 if (!name) 45 return NULL; 46 shifter_value = search_struct(shifters, (char *)name); 47 if (!shifter_value) 48 return NULL; 49 if (sval_cmp_val(expr_value, *shifter_value) != 0) 50 return NULL; 51 return name; 52 } 53 54 static void match_assign(struct expression *expr) 55 { 56 const char *name; 57 58 if (expr->op != SPECIAL_OR_ASSIGN) 59 return; 60 if (positions_eq(expr->pos, expr->right->pos)) 61 return; 62 name = get_shifter(expr->right); 63 if (!name) 64 return; 65 66 sm_warning("'%s' is a shifter (not for '%s').", 67 name, show_special(expr->op)); 68 } 69 70 static void match_binop(struct expression *expr) 71 { 72 const char *name; 73 74 if (positions_eq(expr->pos, expr->right->pos)) 75 return; 76 if (expr->op != '&') 77 return; 78 name = get_shifter(expr->right); 79 if (!name) 80 return; 81 82 sm_warning("bit shifter '%s' used for logical '%s'", 83 name, show_special(expr->op)); 84 } 85 86 static void register_shifters(void) 87 { 88 char filename[256]; 89 struct token *token; 90 char *name; 91 int *val; 92 93 snprintf(filename, sizeof(filename), "%s.bit_shifters", option_project_str); 94 token = get_tokens_file(filename); 95 if (!token) 96 return; 97 if (token_type(token) != TOKEN_STREAMBEGIN) 98 return; 99 token = token->next; 100 while (token_type(token) != TOKEN_STREAMEND) { 101 if (token_type(token) != TOKEN_IDENT) 102 return; 103 name = alloc_string(show_ident(token->ident)); 104 token = token->next; 105 if (token_type(token) != TOKEN_NUMBER) 106 return; 107 val = malloc(sizeof(int)); 108 *val = atoi(token->number); 109 insert_struct(shifters, name, val); 110 token = token->next; 111 } 112 clear_token_alloc(); 113 } 114 115 static void match_binop_info(struct expression *expr) 116 { 117 char *name; 118 sval_t sval; 119 120 if (positions_eq(expr->pos, expr->right->pos)) 121 return; 122 if (expr->op != SPECIAL_LEFTSHIFT) 123 return; 124 if (expr->right->type != EXPR_VALUE) 125 return; 126 name = pos_ident(expr->right->pos); 127 if (!name) 128 return; 129 if (!get_value(expr->right, &sval)) 130 return; 131 sm_msg("info: bit shifter '%s' '%s'", name, sval_to_str(sval)); 132 } 133 134 static void match_call(const char *fn, struct expression *expr, void *_arg_no) 135 { 136 struct expression *arg_expr; 137 int arg_no = PTR_INT(_arg_no); 138 sval_t sval; 139 char *name; 140 141 arg_expr = get_argument_from_call_expr(expr->args, arg_no); 142 if (positions_eq(expr->pos, arg_expr->pos)) 143 return; 144 name = pos_ident(arg_expr->pos); 145 if (!name) 146 return; 147 if (!get_value(arg_expr, &sval)) 148 return; 149 sm_msg("info: bit shifter '%s' '%s'", name, sval_to_str(sval)); 150 } 151 152 void check_bit_shift(int id) 153 { 154 my_id = id; 155 156 shifters = create_function_hashtable(5000); 157 register_shifters(); 158 159 add_hook(&match_assign, ASSIGNMENT_HOOK); 160 add_hook(&match_binop, BINOP_HOOK); 161 162 if (option_info) { 163 add_hook(&match_binop_info, BINOP_HOOK); 164 if (option_project == PROJ_KERNEL) { 165 add_function_hook("set_bit", &match_call, INT_PTR(0)); 166 add_function_hook("test_bit", &match_call, INT_PTR(0)); 167 } 168 } 169 }