1#!/usr/bin/perl -w
2
3use strict;
4use DBI;
5use Scalar::Util qw(looks_like_number);
6
7sub usage()
8{
9    print "usage:  $0 <project> <smatch_warns.txt> <db_file>\n";
10    exit(1);
11}
12
13my %too_common_funcs;
14sub 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
42my $exec_name = $0;
43my $path = $exec_name;
44$path =~ s/(.*)\/.*/$1/;
45my $project = shift;
46my $warns = shift;
47my $db_file = shift;
48
49if (!defined($db_file)) {
50    usage();
51}
52
53get_too_common_functions($path, $project, $warns);
54
55my $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
62foreach 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
66my $call_id = 0;
67my ($fn, $dummy, $sql);
68
69open(WARNS, "<$warns");
70while (<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();
97