forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
kbuild: export-symbol usage report generator
The following patch provides the ability to generate a report of (1) All the exported symbols and their in-kernel-module usage count (2) For each module, lists the modules and their exported symbols, on which it depends. the report can be generated by executing: perl scripts/export_report The tool warns if the modules are not build using MODVERSIONING. Signed-off-by: Ram Pai <[email protected]> Signed-off-by: Sam Ravnborg <[email protected]>
- Loading branch information
Ram Pai
authored and
Sam Ravnborg
committed
Jun 24, 2006
1 parent
e5c44fd
commit c5e3003
Showing
1 changed file
with
169 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
#!/usr/bin/perl -w | ||
# | ||
# (C) Copyright IBM Corporation 2006. | ||
# Released under GPL v2. | ||
# Author : Ram Pai ([email protected]) | ||
# | ||
# 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"; | ||
while (my ($mod, $list) = each %$href) { | ||
print "\t$mod:\n"; | ||
foreach my $sym (sort numerically @{$list}) { | ||
my ($symbol, $no) = split /\s+/, $sym; | ||
printf("\t\t%-25s\t%-25d\n", $symbol, $no); | ||
} | ||
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 { | ||
my @file = `cat .tmp_versions/*.mod | grep '.*\.ko\$'`; | ||
@file = grep {s/\.ko/.mod.c/} @file; | ||
chomp @file; | ||
return @file; | ||
} | ||
|
||
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"; | ||
} | ||
|
||
unless (open(MODULE_SYMVERS, $opt{'k'})) { | ||
die "Sorry, cannot open $opt{'k'}: $!\n"; | ||
} | ||
|
||
if (defined $opt{'o'}) { | ||
unless (open(OUTPUT_HANDLE, ">$opt{'o'}")) { | ||
die "Sorry, cannot open $opt{'o'} $!\n"; | ||
} | ||
select OUTPUT_HANDLE; | ||
} | ||
# | ||
# collect all the symbols and their attributes from the | ||
# Module.symvers file | ||
# | ||
while ( <MODULE_SYMVERS> ) { | ||
chomp; | ||
my (undef, $symbol, $module, $gpl) = split; | ||
$SYMBOL { $symbol } = [ $module , "0" , $symbol, $gpl]; | ||
} | ||
close(MODULE_SYMVERS); | ||
|
||
# | ||
# collect the usage count of each symbol. | ||
# | ||
foreach my $thismod (@allcfiles) { | ||
unless (open(MODULE_MODULE, $thismod)) { | ||
print "Sorry, cannot open $thismod: $!\n"; | ||
next; | ||
} | ||
my $state=0; | ||
while ( <MODULE_MODULE> ) { | ||
chomp; | ||
if ($state eq 0) { | ||
$state = 1 if ($_ =~ /static const struct modversion_info/); | ||
next; | ||
} | ||
if ($state eq 1) { | ||
$state = 2 if ($_ =~ /__attribute__\(\(section\("__versions"\)\)\)/); | ||
next; | ||
} | ||
if ($state eq 2) { | ||
if ( $_ !~ /0x[0-9a-f]{7,8},/ ) { | ||
next; | ||
} | ||
my $sym = (split /([,"])/,)[4]; | ||
my ($module, $value, $symbol, $gpl) = @{$SYMBOL{$sym}}; | ||
$SYMBOL{ $sym } = [ $module, $value+1, $symbol, $gpl]; | ||
push(@{$MODULE{$thismod}} , $sym); | ||
} | ||
} | ||
if ($state ne 2) { | ||
print "WARNING:$thismod is not built with CONFIG_MODVERSION enabled\n"; | ||
} | ||
close(MODULE_MODULE); | ||
} | ||
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"); | ||
print "~"x80 , "\n"; | ||
while (my ($thismod, $list) = each %MODULE) { | ||
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); | ||
} |