From 993cf15fbfd835dbb7b7f1c3cb1135d08b60d358 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 14 Feb 2013 02:31:30 +0300 Subject: [PATCH] db: move caller_info as close as possible to raw SQL I can't move caller_info to use raw SQL because I want each call to have a unique call id. That lets us group the records for one call together. The other thing which is a bit tricky is that I want to ignore the functions which are called over 200 times. Both of those are easier to do after we have processed the whole kernel. But I still want to move it to something closer to SQL because it will make future work a bit easier. Signed-off-by: Dan Carpenter --- check_list.h | 1 + check_user_data.c | 9 +- smatch.h | 2 + smatch_buf_size.c | 13 +- smatch_capped.c | 9 +- smatch_db.c | 24 ++- smatch_extra.c | 6 +- smatch_scripts/db/fill_db_caller_info.pl | 243 ++++++++++--------------------- 8 files changed, 122 insertions(+), 185 deletions(-) rewrite smatch_scripts/db/fill_db_caller_info.pl (82%) diff --git a/check_list.h b/check_list.h index 357efea7..d2f61257 100644 --- a/check_list.h +++ b/check_list.h @@ -112,6 +112,7 @@ CK(register_modification_hooks_late) CK(register_smatch_extra_late) CK(register_function_hooks) CK(register_returns) +CK(register_db_call_marker) /* always second last */ CK(register_implications) /* implications always has to be last */ #ifdef __undo_CK_def diff --git a/check_user_data.c b/check_user_data.c index 7b24b348..92207632 100644 --- a/check_user_data.c +++ b/check_user_data.c @@ -301,9 +301,10 @@ static void match_caller_info(struct expression *expr) i = 0; FOR_EACH_PTR(expr->args, tmp) { - if (is_user_data(tmp)) - sm_msg("info: passes user_data '%s' %d '$$' %s", func, i, - is_static(expr->fn) ? "static" : "global"); + if (is_user_data(tmp)) { + sql_insert_caller_info(func, is_static(expr->fn), + USER_DATA, i, "$$", "1"); + } i++; } END_FOR_EACH_PTR(tmp); @@ -314,7 +315,7 @@ static void struct_member_callback(char *fn, int static_flag, int param, char *p { if (state == &capped) return; - sm_msg("info: passes user_data '%s' %d '%s' %s", fn, param, printed_name, static_flag ? "static" : "global"); + sql_insert_caller_info(fn, static_flag, USER_DATA, param, printed_name, "1"); } static void print_returned_user_data(int return_id, char *return_ranges, struct expression *expr, struct state_list *slist) diff --git a/smatch.h b/smatch.h index afe60e70..f4a1ba48 100644 --- a/smatch.h +++ b/smatch.h @@ -500,6 +500,8 @@ do { \ void sql_insert_return_states(int return_id, const char *return_ranges, int type, int param, const char *key, const char *value); +void sql_insert_caller_info(const char *fn, int static_flag, int type, + int param, const char *key, const char *value); void sql_insert_function_ptr(const char *fn, const char *struct_name); void sql_insert_return_values(const char *return_values); void sql_insert_call_implies(int type, int param, int value); diff --git a/smatch_buf_size.c b/smatch_buf_size.c index beda9a3b..ed081818 100644 --- a/smatch_buf_size.c +++ b/smatch_buf_size.c @@ -613,10 +613,13 @@ static void match_call(struct expression *expr) i = 0; FOR_EACH_PTR(expr->args, arg) { bytes = get_array_size_bytes(arg); - if (bytes > 1) - sm_msg("info: passes_buffer '%s' %d '$$' %d %s", - name, i, bytes, - is_static(expr->fn) ? "static" : "global"); + if (bytes > 1) { + char buf[11]; + + snprintf(buf, sizeof(buf), "%d", bytes); + sql_insert_caller_info(name, is_static(expr->fn), + BUF_SIZE, i, "$$", buf); + } i++; } END_FOR_EACH_PTR(arg); @@ -627,7 +630,7 @@ static void struct_member_callback(char *fn, int static_flag, int param, char *p { if (state == &merged) return; - sm_msg("info: passes_buffer '%s' %d '%s' %s %s", fn, param, printed_name, state->name, static_flag ? "static" : "global"); + sql_insert_caller_info(fn, static_flag, BUF_SIZE, param, printed_name, state->name); } static void match_func_end(struct symbol *sym) diff --git a/smatch_capped.c b/smatch_capped.c index 83f79c25..0465080f 100644 --- a/smatch_capped.c +++ b/smatch_capped.c @@ -150,9 +150,10 @@ static void match_caller_info(struct expression *expr) i = 0; FOR_EACH_PTR(expr->args, tmp) { - if (is_capped(tmp)) - sm_msg("info: passes capped_data %s %d '$$' %s", func, - i, is_static(expr->fn) ? "static" : "global"); + if (is_capped(tmp)) { + sql_insert_caller_info(func, is_static(expr->fn), + CAPPED_DATA, i, "$$", "1"); + } i++; } END_FOR_EACH_PTR(tmp); @@ -163,7 +164,7 @@ static void struct_member_callback(char *fn, int static_flag, int param, char *p { if (state != &capped) return; - sm_msg("info: passes capped_data '%s' %d '%s' %s", fn, param, printed_name, static_flag ? "static" : "global"); + sql_insert_caller_info(fn, static_flag, CAPPED_DATA, param, printed_name, "1"); } void register_capped(int id) diff --git a/smatch_db.c b/smatch_db.c index dbd1f866..2c212594 100644 --- a/smatch_db.c +++ b/smatch_db.c @@ -87,6 +87,18 @@ void sql_insert_return_states(int return_id, const char *return_ranges, fn_static(), type, param, key, value); } +void sql_insert_caller_info(const char *fn, int static_flag, int type, + int param, const char *key, const char *value) +{ + if (!option_info) + return; + + sm_msg("SQL_caller_info: insert into caller_info values (" + "'%s', '%s', '%s', %%FUNC_ID%%, %d, %d, %d, '%s', '%s');", + get_filename(), get_function(), fn, static_flag, type, param, + key, value); +} + void sql_insert_function_ptr(const char *fn, const char *struct_name) { sql_insert(function_ptr, "'%s', '%s', '%s'", get_filename(), fn, @@ -201,7 +213,7 @@ struct range_list *db_return_vals(struct expression *expr) return return_range_list; } -static void match_call_hack(struct expression *expr) +static void match_call_marker(struct expression *expr) { char *name; @@ -214,7 +226,7 @@ static void match_call_hack(struct expression *expr) name = get_fnptr_name(expr->fn); if (!name) return; - sm_msg("info: call_marker '%s' %s", name, is_static(expr->fn) ? "static" : "global"); + sql_insert_caller_info(name, is_static(expr->fn), INTERNAL, -1, "%call_marker%", ""); free_string(name); } @@ -754,7 +766,6 @@ void register_definition_db_callbacks(int id) if (option_info) { add_hook(&match_call_info, FUNCTION_CALL_HOOK); - add_hook(&match_call_hack, FUNCTION_CALL_HOOK); add_hook(&match_function_assign, ASSIGNMENT_HOOK); add_hook(&match_function_assign, GLOBAL_ASSIGNMENT_HOOK); add_hook(&global_variable, BASE_HOOK); @@ -772,6 +783,13 @@ void register_definition_db_callbacks(int id) add_hook(&match_call_implies, FUNCTION_CALL_HOOK); } +void register_db_call_marker(int id) +{ + if (!option_info) + return; + add_hook(&match_call_marker, FUNCTION_CALL_HOOK); +} + char *get_variable_from_key(struct expression *arg, char *key, struct symbol **sym) { char buf[256]; diff --git a/smatch_extra.c b/smatch_extra.c index 995e494d..d00dcbbb 100644 --- a/smatch_extra.c +++ b/smatch_extra.c @@ -992,7 +992,7 @@ static void struct_member_callback(char *fn, int static_flag, int param, char *p { if (estate_is_whole(state)) return; - sm_msg("info: passes param_value '%s' %d '%s' %s %s", fn, param, printed_name, state->name, static_flag ? "static" : "global"); + sql_insert_caller_info(fn, static_flag, PARAM_VALUE, param, printed_name, state->name); } static void db_limited_before(void) @@ -1206,9 +1206,7 @@ static void match_call_info(struct expression *expr) else rl = cast_rl(type, alloc_whole_rl(get_type(arg))); - sm_msg("info: passes param_value '%s' %d '$$' %s %s", - name, i, show_rl(rl), - is_static(expr->fn) ? "static" : "global"); + sql_insert_caller_info(name, is_static(expr->fn), PARAM_VALUE, i, "$$", show_rl(rl)); i++; } END_FOR_EACH_PTR(arg); diff --git a/smatch_scripts/db/fill_db_caller_info.pl b/smatch_scripts/db/fill_db_caller_info.pl dissimilarity index 82% index c648c4fb..a17a23b5 100755 --- a/smatch_scripts/db/fill_db_caller_info.pl +++ b/smatch_scripts/db/fill_db_caller_info.pl @@ -1,165 +1,78 @@ -#!/usr/bin/perl -w - -use strict; -use DBI; -use Scalar::Util qw(looks_like_number); - -sub usage() -{ - print "usage: $0 \n"; - exit(1); -} - -my %too_common_funcs; -sub get_too_common_functions($) -{ - my $warns = shift; - - open(FUNCS, "cat $warns | grep 'info: call_marker ' | cut -d \"'\" -f 2 | sort | uniq -c | "); - - while () { - if ($_ =~ /(\d+) (.*)/) { - if (int($1) > 200) { - $too_common_funcs{$2} = 1; - } - } - } - - close(FUNCS); -} - -my $warns = shift; - -if (!defined($warns)) { - usage(); -} - -get_too_common_functions($warns); - -my $db = DBI->connect("dbi:SQLite:smatch_db.sqlite", "", "", {AutoCommit => 0}); -$db->do("PRAGMA synchronous = OFF"); -$db->do("PRAGMA cache_size = 800000"); -$db->do("PRAGMA journal_mode = OFF"); - -my $prev_fn = ""; -my $prev_line = "+0"; -my $prev_param = 0; -my $func_id = 1; -my $type; - -$db->do("delete from caller_info"); - -open(WARNS, "<$warns"); -while () { - if (!($_ =~ /info:/)) { - next; - } - if ($_ =~ /__builtin_/) { - next; - } - if ($_ =~ /(printk|memset|memcpy|kfree|printf|dev_err|writel)/) { - next; - } - - s/\n//; - - my ($file_and_line, $file, $line, $caller, $dummy, $func, $param, $key, $value, $gs); - - if ($_ =~ /info: call_marker /) { - # crypto/zlib.c:50 zlib_comp_exit() info: call_marker 'zlib_deflateEnd' global - $type = 0; # INTERNAL - ($file_and_line, $caller, $dummy, $dummy, $func, $gs) = split(/ /, $_); - ($file, $line) = split(/:/, $file_and_line); - $param = -1; - $key = ""; - $value = ""; - - if ($func eq "'(struct") { - ($file_and_line, $dummy, $dummy, $dummy, $dummy, $func, $gs) = split(/ /, $_); - ($file, $line) = split(/:/, $file_and_line); - $func = "$dummy $func"; - } - - } elsif ($_ =~ /info: passes param_value /) { - # init/main.c +165 obsolete_checksetup(7) info: passes param_value strlen 0 min-max static - $type = 1; # PARAM_VALUE - ($file_and_line, $caller, $dummy, $dummy, $dummy, $func, $param, $key, $value, $gs) = split(/ /, $_); - ($file, $line) = split(/:/, $file_and_line); - - if ($func eq "'(struct") { - ($file_and_line, $dummy, $dummy, $dummy, $dummy, $dummy, $func, $param, $key, $value, $gs) = split(/ /, $_); - ($file, $line) = split(/:/, $file_and_line); - $func = "$dummy $func"; - } - - } elsif ($_ =~ /info: passes_buffer /) { - # init/main.c +175 obsolete_checksetup(17) info: passes_buffer 'printk' 0 '$$' 38 global - $type = 2; # BUF_SIZE - ($file_and_line, $caller, $dummy, $dummy, $func, $param, $key, $value, $gs) = split(/ /, $_); - ($file, $line) = split(/:/, $file_and_line); - - if ($func eq "'(struct") { - ($file_and_line, $caller, $dummy, $dummy, $dummy, $func, $param, $key, $value, $gs) = split(/ /, $_); - ($file, $line) = split(/:/, $file_and_line); - $func = "$dummy $func"; - } - } elsif ($_ =~ /info: passes user_data /) { - # test.c +24 func(11) info: passes user_data 'frob' 2 '$$->data' global - $type = 3; # USER_DATA - $value = 1; - ($file_and_line, $caller, $dummy, $dummy, $dummy, $func, $param, $key, $gs) = split(/ /, $_); - ($file, $line) = split(/:/, $file_and_line); - - if ($func eq "'(struct") { - ($file_and_line, $caller, $dummy, $dummy, $dummy, $dummy, $func, $param, $key, $gs) = split(/ /, $_); - ($file, $line) = split(/:/, $file_and_line); - $func = "$dummy $func"; - } - - } elsif ($_ =~ /info: passes capped_data /) { - # test.c +24 func(11) info: passes capped_data 'frob' 2 '$$->data' static - $type = 4; # CAPPED_DATA - $value = 1; - ($file_and_line, $caller, $dummy, $dummy, $dummy, $func, $param, $key, $gs) = split(/ /, $_); - ($file, $line) = split(/:/, $file_and_line); - - if ($func eq "'(struct") { - ($file_and_line, $caller, $dummy, $dummy, $dummy, $dummy, $func, $param, $key, $gs) = split(/ /, $_); - ($file, $line) = split(/:/, $file_and_line); - $func = "$dummy $func"; - } - - } else { - next; - } - - if (!looks_like_number($param)) { - next; - } - - $caller =~ s/\(\)//; - $func =~ s/'//g; - $key =~ s/'//g; - $value =~ s/'//g; - - if (defined($too_common_funcs{$func})) { - next; - } - - if ($prev_fn ne $func || $prev_line ne $line) { - $prev_fn = $func; - $prev_line = $line; - $prev_param = $param; - $func_id++; - } - - my $static = 0; - if ($gs =~ /static/) { - $static = 1; - } - -# print "insert into caller_info values ('$file', '$caller', '$func', $func_id, $type, $param, '$key', '$value')\n"; - $db->do("insert into caller_info values ('$file', '$caller', '$func', $func_id, $static, $type, $param, '$key', '$value')"); -} -$db->commit(); -$db->disconnect(); +#!/usr/bin/perl -w + +use strict; +use DBI; +use Scalar::Util qw(looks_like_number); + +sub usage() +{ + print "usage: $0 \n"; + exit(1); +} + +my %too_common_funcs; +sub get_too_common_functions($) +{ + my $warns = shift; + + open(FUNCS, "cat $warns | grep 'SQL_caller_info: ' | grep '%call_marker%' | cut -d \"'\" -f 6 | sort | uniq -c | "); + + while () { + if ($_ =~ /(\d+) (.*)/) { + if (int($1) > 200) { + $too_common_funcs{$2} = 1; + } + } + } + + close(FUNCS); +} + +my $warns = shift; + +if (!defined($warns)) { + usage(); +} + +get_too_common_functions($warns); + +my $db = DBI->connect("dbi:SQLite:smatch_db.sqlite", "", "", {AutoCommit => 0}); +$db->do("PRAGMA synchronous = OFF"); +$db->do("PRAGMA cache_size = 800000"); +$db->do("PRAGMA journal_mode = OFF"); + +my $func_id = 0; +my ($fn, $dummy, $sql); + +open(WARNS, "<$warns"); +while () { + # test.c:11 frob() SQL_caller_info: insert into caller_info values ('test.c', 'frob', '__smatch_buf_size', %FUNC_ID%, 1, 0, -1, '', '); + + if (!($_ =~ /^.*? \w+\(\) SQL_caller_info: /)) { + next; + } + ($dummy, $dummy, $dummy, $dummy, $dummy, $fn, $dummy) = split(/'/); + + if ($fn =~ /__builtin_/) { + next; + } + if ($fn =~ /(printk|memset|memcpy|kfree|printf|dev_err|writel)/) { + next; + } + + if (defined($too_common_funcs{$fn})) { + next; + } + + ($dummy, $dummy, $sql) = split(/:/); + + $sql =~ s/%FUNC_ID%/$func_id/; + if ($sql =~ /%call_marker%/) { + $sql =~ s/%call_marker%//; # don't need this taking space in the db. + $func_id++; + } + + $db->do($sql); +} +$db->commit(); +$db->disconnect(); -- 2.11.4.GIT