From 8e0fe5772482743e9738beb83dae69dfeca086ad Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 8 Oct 2011 17:32:54 +0300 Subject: [PATCH] extra, db: record the struct member values in the database This adds a field to the caller_info table called "key" which is used to store the struct member. The --info output looks something like this: arch/x86/kvm/svm.c +659 svm_cpu_init(19) info: passes param_value 'kfree' 0 '$$->save_area' 0 Signed-off-by: Dan Carpenter --- smatch.h | 2 +- smatch_buf_size.c | 2 +- smatch_db.c | 10 +++--- smatch_extra.c | 58 ++++++++++++++++++++++++-------- smatch_scripts/db/caller_info.schema | 2 +- smatch_scripts/db/fill_db_caller_info.pl | 11 +++--- 6 files changed, 59 insertions(+), 26 deletions(-) diff --git a/smatch.h b/smatch.h index f0376bb2..fb130a30 100644 --- a/smatch.h +++ b/smatch.h @@ -398,7 +398,7 @@ enum info_type { BUF_SIZE, }; -void add_definition_db_callback(void (*callback)(const char *name, struct symbol *sym, char *value), int type); +void add_definition_db_callback(void (*callback)(const char *name, struct symbol *sym, char *key, char *value), int type); #define run_sql(call_back, sql...) \ do { \ diff --git a/smatch_buf_size.c b/smatch_buf_size.c index a58cd951..d5acbef8 100644 --- a/smatch_buf_size.c +++ b/smatch_buf_size.c @@ -31,7 +31,7 @@ static struct limiter b0_l2 = {0, 2}; static _Bool params_set[32]; -void set_param_buf_size(const char *name, struct symbol *sym, char *value) +void set_param_buf_size(const char *name, struct symbol *sym, char *key, char *value) { unsigned int size; diff --git a/smatch_db.c b/smatch_db.c index 3c428cc8..723eddbb 100644 --- a/smatch_db.c +++ b/smatch_db.c @@ -18,7 +18,7 @@ static sqlite3 *db; struct def_callback { int hook_type; - void (*callback)(const char *name, struct symbol *sym, char *value); + void (*callback)(const char *name, struct symbol *sym, char *key, char *value); }; ALLOCATOR(def_callback, "definition db hook callbacks"); DECLARE_PTR_LIST(callback_list, struct def_callback); @@ -39,7 +39,7 @@ void sql_exec(int (*callback)(void*, int, char**, char**), const char *sql) } } -void add_definition_db_callback(void (*callback)(const char *name, struct symbol *sym, char *value), int type) +void add_definition_db_callback(void (*callback)(const char *name, struct symbol *sym, char *key, char *value), int type) { struct def_callback *def_callback = __alloc_def_callback(0); @@ -94,7 +94,7 @@ static int db_callback(void *unused, int argc, char **argv, char **azColName) struct symbol *sym; struct def_callback *def_callback; - if (argc != 4) + if (argc != 5) return 0; func_id = atoi(argv[0]); @@ -117,7 +117,7 @@ static int db_callback(void *unused, int argc, char **argv, char **azColName) FOR_EACH_PTR(callbacks, def_callback) { if (def_callback->hook_type == type) - def_callback->callback(name, sym, argv[3]); + def_callback->callback(name, sym, argv[3], argv[4]); } END_FOR_EACH_PTR(def_callback); return 0; @@ -149,7 +149,7 @@ static void match_data_from_db(struct symbol *sym) prev_func_id = -1; __push_fake_cur_slist(); - run_sql(db_callback, "select function_id, type, parameter, value from caller_info" + run_sql(db_callback, "select function_id, type, parameter, key, value from caller_info" " where %s", sql_filter); merge_slist(&final_states, __pop_fake_cur_slist()); diff --git a/smatch_extra.c b/smatch_extra.c index 67f0d5de..558e53bb 100644 --- a/smatch_extra.c +++ b/smatch_extra.c @@ -976,7 +976,7 @@ int is_whole_range(struct smatch_state *state) if (!state) return 1; dinfo = get_dinfo(state); - if (!dinfo) + if (!dinfo || !dinfo->value_ranges) return 1; drange = first_ptr_list((struct ptr_list *)dinfo->value_ranges); if (drange->min == whole_range.min && drange->max == whole_range.max) @@ -984,31 +984,56 @@ int is_whole_range(struct smatch_state *state) return 0; } +static void print_param_info(char *fn, struct expression *expr, int param, struct state_list *slist) +{ + struct range_list *rl = NULL; + struct sm_state *sm; + char *name; + struct symbol *sym; + int len; + char *msg; + + if (get_implied_range_list(expr, &rl) && ! is_whole_range_rl(rl)) { + msg = show_ranges(rl); + sm_msg("info: passes param_value '%s' %d '$$' %s", fn, param, msg); + } + + name = get_variable_from_expr(expr, &sym); + if (!name || !sym) + goto free; + + len = strlen(name); + FOR_EACH_PTR(slist, sm) { + if (sm->sym != sym) + continue; + if (is_whole_range(sm->state)) + continue; + if (strncmp(name, sm->name, len) || sm->name[len] == '\0') + continue; + sm_msg("info: passes param_value '%s' %d '$$%s' %s", fn, param, sm->name + len, sm->state->name); + } END_FOR_EACH_PTR(sm); +free: + free_string(name); +} + static void match_call_info(struct expression *expr) { struct expression *arg; + struct state_list *slist; char *name; int i = 0; if (expr->fn->type != EXPR_SYMBOL) return; + slist = get_all_states(SMATCH_EXTRA); name = get_variable_from_expr(expr->fn, NULL); FOR_EACH_PTR(expr->args, arg) { - struct range_list *rl = NULL; - char *msg; - - if (!get_implied_range_list(arg, &rl)) - goto next; - if (is_whole_range_rl(rl)) - goto next; - - msg = show_ranges(rl); - sm_msg("info: passes param_value '%s' %d %s", name, i, msg); - next: + print_param_info(name, arg, i, slist); i++; } END_FOR_EACH_PTR(arg); free_string(name); + free_slist(&slist); } static void get_value_ranges(char *value, struct range_list **rl) @@ -1065,14 +1090,19 @@ static void get_value_ranges(char *value, struct range_list **rl) } -void set_param_value(const char *name, struct symbol *sym, char *value) +void set_param_value(const char *name, struct symbol *sym, char *key, char *value) { struct range_list *rl = NULL; struct smatch_state *state; + char fullname[256]; + + if (strncmp(key, "$$", 2)) + return; + snprintf(fullname, 256, "%s%s", name, key + 2); get_value_ranges(value, &rl); state = alloc_extra_state_range_list(rl); - set_state(SMATCH_EXTRA, name, sym, state); + set_state(SMATCH_EXTRA, fullname, sym, state); } void register_smatch_extra(int id) diff --git a/smatch_scripts/db/caller_info.schema b/smatch_scripts/db/caller_info.schema index 468788b0..c6cd0aef 100644 --- a/smatch_scripts/db/caller_info.schema +++ b/smatch_scripts/db/caller_info.schema @@ -1,4 +1,4 @@ -CREATE TABLE caller_info (file varchar(256), function varchar(256), function_id integer, type integer, parameter integer, value varchar(256)); +CREATE TABLE caller_info (file varchar(256), function varchar(256), function_id integer, type integer, parameter integer, key varchar(256), value varchar(256)); CREATE INDEX caller_fn_idx on caller_info (function, function_id); CREATE INDEX caller_ff_idx on caller_info (file, function, function_id); diff --git a/smatch_scripts/db/fill_db_caller_info.pl b/smatch_scripts/db/fill_db_caller_info.pl index 64def83d..b5b42398 100755 --- a/smatch_scripts/db/fill_db_caller_info.pl +++ b/smatch_scripts/db/fill_db_caller_info.pl @@ -34,16 +34,17 @@ while () { s/\n//; - my ($file, $line, $dummy, $func, $param, $value); + my ($file, $line, $dummy, $func, $param, $key, $value); if ($_ =~ /info: passes param_value /) { # init/main.c +165 obsolete_checksetup(7) info: passes param_value strlen 0 min-max $type = 1; - ($file, $line, $dummy, $dummy, $dummy, $dummy, $func, $param, $value) = split(/ /, $_); + ($file, $line, $dummy, $dummy, $dummy, $dummy, $func, $param, $key, $value) = split(/ /, $_); } elsif ($_ =~ /info: passes_buffer /) { - # init/main.c +175 obsolete_checksetup(17) info: passes_buffer 'printk' 0 38 + # init/main.c +175 obsolete_checksetup(17) info: passes_buffer 'printk' 0 '$$' 38 $type = 2; + $key = ""; ($file, $line, $dummy, $dummy, $dummy, $func, $param, $value) = split(/ /, $_); } else { next; @@ -54,6 +55,8 @@ while () { } $func =~ s/'//g; + $key =~ s/'//g; + $value =~ s/'//g; if ($prev_fn ne $func || $prev_line ne $line || $param < $prev_param) { $prev_fn = $func; @@ -62,7 +65,7 @@ while () { $func_id++; } - $db->do("insert into caller_info values ('$file', '$func', $func_id, $type, $param, '$value')"); + $db->do("insert into caller_info values ('$file', '$func', $func_id, $type, $param, '$key', '$value')"); } $db->commit(); $db->disconnect(); -- 2.11.4.GIT