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_slist.h" 20 21 STATE(capable); 22 23 static int capable_id; 24 static int ns_capable_id; 25 26 static void match_capable(const char *fn, struct expression *expr, void *_param) 27 { 28 struct expression *arg; 29 sval_t sval; 30 char buf[32]; 31 32 arg = get_argument_from_call_expr(expr->args, 0); 33 if (!get_implied_value(arg, &sval)) 34 return; 35 snprintf(buf, sizeof(buf), "%s", sval_to_str(sval)); 36 set_state(capable_id, buf, NULL, &capable); 37 } 38 39 static void match_ns_capable(const char *fn, struct expression *expr, void *_param) 40 { 41 struct expression *arg; 42 sval_t sval; 43 char buf[32]; 44 45 if (get_function() && strcmp(get_function(), "capable") == 0) 46 return; 47 48 arg = get_argument_from_call_expr(expr->args, 1); 49 if (!get_implied_value(arg, &sval)) 50 return; 51 snprintf(buf, sizeof(buf), "%s", sval_to_str(sval)); 52 set_state(ns_capable_id, buf, NULL, &capable); 53 } 54 55 static void save_call_info(struct expression *call) 56 { 57 struct sm_state *sm; 58 59 FOR_EACH_MY_SM(capable_id, __get_cur_stree(), sm) { 60 if (sm->state == &capable) 61 sql_insert_caller_info(call, CAPABLE, 0, sm->name, ""); 62 } END_FOR_EACH_SM(sm); 63 64 FOR_EACH_MY_SM(ns_capable_id, __get_cur_stree(), sm) { 65 if (sm->state == &capable) 66 sql_insert_caller_info(call, NS_CAPABLE, 0, sm->name, ""); 67 } END_FOR_EACH_SM(sm); 68 } 69 70 static void save_return_info(int return_id, char *return_ranges, struct expression *expr) 71 { 72 struct sm_state *sm; 73 74 FOR_EACH_MY_SM(capable_id, __get_cur_stree(), sm) { 75 if (sm->state == &capable) 76 sql_insert_return_states(return_id, return_ranges, 77 CAPABLE, 0, sm->name, ""); 78 } END_FOR_EACH_SM(sm); 79 80 FOR_EACH_MY_SM(ns_capable_id, __get_cur_stree(), sm) { 81 if (sm->state == &capable) 82 sql_insert_return_states(return_id, return_ranges, 83 CAPABLE, 0, sm->name, ""); 84 } END_FOR_EACH_SM(sm); 85 } 86 87 static void set_db_capable(const char *name, struct symbol *sym, char *key, char *value) 88 { 89 char buf[32]; 90 91 snprintf(buf, sizeof(buf), "%s", key); 92 set_state(capable_id, buf, NULL, &capable); 93 } 94 95 static void set_db_ns_capable(const char *name, struct symbol *sym, char *key, char *value) 96 { 97 char buf[32]; 98 99 snprintf(buf, sizeof(buf), "%s", key); 100 set_state(ns_capable_id, buf, NULL, &capable); 101 } 102 103 void check_capable(int id) 104 { 105 if (option_project != PROJ_KERNEL) 106 return; 107 108 capable_id = id; 109 add_function_hook("capable", &match_capable, INT_PTR(0)); 110 111 add_hook(&save_call_info, FUNCTION_CALL_HOOK); 112 add_split_return_callback(save_return_info); 113 select_caller_info_hook(set_db_capable, CAPABLE); 114 } 115 116 void check_ns_capable(int id) 117 { 118 if (option_project != PROJ_KERNEL) 119 return; 120 121 ns_capable_id = id; 122 add_function_hook("ns_capable", &match_ns_capable, INT_PTR(0)); 123 select_caller_info_hook(set_db_ns_capable, NS_CAPABLE); 124 } 125