1 #!/usr/bin/perl -w
   2 
   3 use strict;
   4 use DBI;
   5 use Scalar::Util qw(looks_like_number);
   6 
   7 sub usage()
   8 {
   9     print "usage:  $0 <project> <smatch_warns.txt> <db_file>\n";
  10     exit(1);
  11 }
  12 
  13 my %too_common_funcs;
  14 sub get_too_common_functions($$$)
  15 {
  16     my $path = shift;
  17     my $project = shift;
  18     my $warns = shift;
  19 
  20     open(FUNCS, "grep 'SQL_caller_info: ' $warns | grep '%call_marker%' | cut -d \"'\" -f 6 | sort | uniq -c | ");
  21 
  22     while (<FUNCS>) {
  23         if ($_ =~ /(\d+) (.*)/) {
  24             if (int($1) > 200) {
  25                 $too_common_funcs{$2} = 1;
  26             }
  27         }
  28     }
  29 
  30     close(FUNCS);
  31 
  32     open(FILE, ">", "$path/../$project.common_functions");
  33     foreach my $func (keys %too_common_funcs) {
  34         if ($func =~ / /) {
  35             next;
  36         }
  37         print FILE "$func\n";
  38     }
  39     close(FILE);
  40 }
  41 
  42 my $exec_name = $0;
  43 my $path = $exec_name;
  44 $path =~ s/(.*)\/.*/$1/;
  45 my $project = shift;
  46 my $warns = shift;
  47 my $db_file = shift;
  48 
  49 if (!defined($db_file)) {
  50     usage();
  51 }
  52 
  53 get_too_common_functions($path, $project, $warns);
  54 
  55 my $db = DBI->connect("dbi:SQLite:$db_file", "", "", {AutoCommit => 0});
  56 $db->do("PRAGMA cache_size = 800000");
  57 $db->do("PRAGMA journal_mode = OFF");
  58 $db->do("PRAGMA count_changes = OFF");
  59 $db->do("PRAGMA temp_store = MEMORY");
  60 $db->do("PRAGMA locking = EXCLUSIVE");
  61 
  62 foreach my $func (keys %too_common_funcs) {
  63     $db->do("insert into common_caller_info values ('unknown', 'too common', '$func', 0, 0, 0, -1, '', '');");
  64 }
  65 
  66 my $call_id = 0;
  67 my ($fn, $dummy, $sql);
  68 
  69 open(WARNS, "<$warns");
  70 while (<WARNS>) {
  71     # test.c:11 frob() SQL_caller_info: insert into caller_info values ('test.c', 'frob', '__smatch_buf_size', %CALL_ID%, 1, 0, -1, '', ');
  72 
  73     if (!($_ =~ /^.*? \w+\(\) SQL_caller_info: /)) {
  74         next;
  75     }
  76     ($dummy, $dummy, $dummy, $dummy, $dummy, $fn, $dummy) = split(/'/);
  77 
  78     if ($fn =~ /__builtin_/) {
  79         next;
  80     }
  81     if ($fn =~ /^(printk|memset|memcpy|kfree|printf|dev_err|writel)$/) {
  82         next;
  83     }
  84 
  85     ($dummy, $dummy, $sql) = split(/:/, $_, 3);
  86 
  87     if ($sql =~ /%call_marker%/) {
  88         $sql =~ s/%call_marker%//; # don't need this taking space in the db.
  89         $call_id++;
  90     }
  91     $sql =~ s/%CALL_ID%/$call_id/;
  92 
  93     $db->do($sql);
  94 }
  95 $db->commit();
  96 $db->disconnect();