2006-06-24 03:44:38 +04:00
#!/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" ;
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 ;
2007-08-25 02:32:22 +04:00
if ( $ state == 0 ) {
2006-06-24 03:44:38 +04:00
$ state = 1 if ( $ _ =~ /static const struct modversion_info/ ) ;
next ;
}
2007-08-25 02:32:22 +04:00
if ( $ state == 1 ) {
2006-06-24 03:44:38 +04:00
$ state = 2 if ( $ _ =~ /__attribute__\(\(section\("__versions"\)\)\)/ ) ;
next ;
}
2007-08-25 02:32:22 +04:00
if ( $ state == 2 ) {
2007-08-25 01:04:51 +04:00
if ( $ _ !~ /0x[0-9a-f]+,/ ) {
2006-06-24 03:44:38 +04:00
next ;
}
my $ sym = ( split /([,"])/ , ) [ 4 ] ;
my ( $ module , $ value , $ symbol , $ gpl ) = @ { $ SYMBOL { $ sym } } ;
$ SYMBOL { $ sym } = [ $ module , $ value + 1 , $ symbol , $ gpl ] ;
push ( @ { $ MODULE { $ thismod } } , $ sym ) ;
}
}
2007-08-25 02:32:22 +04:00
if ( $ state != 2 ) {
2006-06-24 03:44:38 +04:00
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 ) ;
}