export_report.pl 4.53 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
#!/usr/bin/perl -w
#
# (C) Copyright IBM Corporation 2006.
#	Released under GPL v2.
#	Author : Ram Pai (linuxram@us.ibm.com)
#
# Usage: export_report.pl -k Module.symvers [-o report_file ] -f *.mod.c
#

use Getopt::Std;
use strict;

sub numerically {
	my $no1 = (split /\s+/, $a)[1];
	my $no2 = (split /\s+/, $b)[1];
	return $no1 <=> $no2;
}

sub alphabetically {
	my ($module1, $value1) = @{$a};
	my ($module2, $value2) = @{$b};
	return $value1 <=> $value2 || $module2 cmp $module1;
}

sub print_depends_on {
	my ($href) = @_;
	print "\n";
28 29
	for my $mod (sort keys %$href) {
		my $list = $href->{$mod};
30 31 32
		print "\t$mod:\n";
		foreach my $sym (sort numerically @{$list}) {
			my ($symbol, $no) = split /\s+/, $sym;
33
			printf("\t\t%-25s\n", $symbol);
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
		}
		print "\n";
	}
	print "\n";
	print "~"x80 , "\n";
}

sub usage {
        print "Usage: @_ -h -k Module.symvers  [ -o outputfile ] \n",
	      "\t-f: treat all the non-option argument as .mod.c files. ",
	      "Recommend using this as the last option\n",
	      "\t-h: print detailed help\n",
	      "\t-k: the path to Module.symvers file. By default uses ",
	      "the file from the current directory\n",
	      "\t-o outputfile: output the report to outputfile\n";
	exit 0;
}

sub collectcfiles {
53 54 55 56 57 58 59 60
    my @file;
    while (<.tmp_versions/*.mod>) {
	open my $fh, '<', $_ or die "cannot open $_: $!\n";
	push (@file,
	      grep s/\.ko/.mod.c/,	# change the suffix
	      grep m/.+\.ko/,		# find the .ko path
	      <$fh>);			# lines in opened file
    }
61 62
    chomp @file;
    return @file;
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
}

my (%SYMBOL, %MODULE, %opt, @allcfiles);

if (not getopts('hk:o:f',\%opt) or defined $opt{'h'}) {
        usage($0);
}

if (defined $opt{'f'}) {
	@allcfiles = @ARGV;
} else {
	@allcfiles = collectcfiles();
}

if (not defined $opt{'k'}) {
	$opt{'k'} = "Module.symvers";
}

81 82
open (my $module_symvers, '<', $opt{'k'})
    or die "Sorry, cannot open $opt{'k'}: $!\n";
83 84

if (defined $opt{'o'}) {
85 86 87 88
    open (my $out, '>', $opt{'o'})
	or die "Sorry, cannot open $opt{'o'} $!\n";

    select $out;
89
}
90

91 92 93 94
#
# collect all the symbols and their attributes from the
# Module.symvers file
#
95
while ( <$module_symvers> ) {
96 97 98 99
	chomp;
	my (undef, $symbol, $module, $gpl) = split;
	$SYMBOL { $symbol } =  [ $module , "0" , $symbol, $gpl];
}
100
close($module_symvers);
101 102 103 104

#
# collect the usage count of each symbol.
#
105 106
my $modversion_warnings = 0;

107
foreach my $thismod (@allcfiles) {
108 109 110 111
	my $module;

	unless (open ($module, '<', $thismod)) {
		warn "Sorry, cannot open $thismod: $!\n";
112 113
		next;
	}
114

115
	my $state=0;
116
	while ( <$module> ) {
117
		chomp;
118
		if ($state == 0) {
119 120 121
			$state = 1 if ($_ =~ /static const struct modversion_info/);
			next;
		}
122
		if ($state == 1) {
123 124 125
			$state = 2 if ($_ =~ /__attribute__\(\(section\("__versions"\)\)\)/);
			next;
		}
126
		if ($state == 2) {
Adrian Bunk's avatar
Adrian Bunk committed
127
			if ( $_ !~ /0x[0-9a-f]+,/ ) {
128 129 130 131 132 133 134 135
				next;
			}
			my $sym = (split /([,"])/,)[4];
			my ($module, $value, $symbol, $gpl) = @{$SYMBOL{$sym}};
			$SYMBOL{ $sym } =  [ $module, $value+1, $symbol, $gpl];
			push(@{$MODULE{$thismod}} , $sym);
		}
	}
136
	if ($state != 2) {
137 138
		warn "WARNING:$thismod is not built with CONFIG_MODVERSIONS enabled\n";
		$modversion_warnings++;
139
	}
140
	close($module);
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
}

print "\tThis file reports the exported symbols usage patterns by in-tree\n",
	"\t\t\t\tmodules\n";
printf("%s\n\n\n","x"x80);
printf("\t\t\t\tINDEX\n\n\n");
printf("SECTION 1: Usage counts of all exported symbols\n");
printf("SECTION 2: List of modules and the exported symbols they use\n");
printf("%s\n\n\n","x"x80);
printf("SECTION 1:\tThe exported symbols and their usage count\n\n");
printf("%-25s\t%-25s\t%-5s\t%-25s\n", "Symbol", "Module", "Usage count",
	"export type");

#
# print the list of unused exported symbols
#
foreach my $list (sort alphabetically values(%SYMBOL)) {
	my ($module, $value, $symbol, $gpl) = @{$list};
	printf("%-25s\t%-25s\t%-10s\t", $symbol, $module, $value);
	if (defined $gpl) {
		printf("%-25s\n",$gpl);
	} else {
		printf("\n");
	}
}
printf("%s\n\n\n","x"x80);

printf("SECTION 2:\n\tThis section reports export-symbol-usage of in-kernel
modules. Each module lists the modules, and the symbols from that module that
it uses.  Each listed symbol reports the number of modules using it\n");

172 173 174
print "\nNOTE: Got $modversion_warnings CONFIG_MODVERSIONS warnings\n\n"
    if $modversion_warnings;

175
print "~"x80 , "\n";
176 177
for my $thismod (sort keys %MODULE) {
	my $list = $MODULE{$thismod};
178 179 180 181 182 183 184 185 186
	my %depends;
	$thismod =~ s/\.mod\.c/.ko/;
	print "\t\t\t$thismod\n";
	foreach my $symbol (@{$list}) {
		my ($module, $value, undef, $gpl) = @{$SYMBOL{$symbol}};
		push (@{$depends{"$module"}}, "$symbol $value");
	}
	print_depends_on(\%depends);
}