db: move caller_info as close as possible to raw SQL
authorDan Carpenter <dan.carpenter@oracle.com>
Wed, 13 Feb 2013 23:31:30 +0000 (14 02:31 +0300)
committerDan Carpenter <dan.carpenter@oracle.com>
Thu, 14 Feb 2013 12:03:13 +0000 (14 15:03 +0300)
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 <dan.carpenter@oracle.com>
check_list.h
check_user_data.c
smatch.h
smatch_buf_size.c
smatch_capped.c
smatch_db.c
smatch_extra.c
smatch_scripts/db/fill_db_caller_info.pl

index 357efea..d2f6125 100644 (file)
@@ -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
index 7b24b34..9220763 100644 (file)
@@ -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)
index afe60e7..f4a1ba4 100644 (file)
--- 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);
index beda9a3..ed08181 100644 (file)
@@ -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)
index 83f79c2..0465080 100644 (file)
@@ -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)
index dbd1f86..2c21259 100644 (file)
@@ -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];
index 995e494..d00dcbb 100644 (file)
@@ -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);
 
dissimilarity index 82%
index c648c4f..a17a23b 100755 (executable)
-#!/usr/bin/perl -w
-
-use strict;
-use DBI;
-use Scalar::Util qw(looks_like_number);
-
-sub usage()
-{
-    print "usage:  $0 <warns.txt>\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 (<FUNCS>) {
-        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 (<WARNS>) {
-    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 <warns.txt>\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 (<FUNCS>) {
+        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 (<WARNS>) {
+    # 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();