1*4882a593Smuzhiyun#!/usr/bin/env perl 2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# (C) Copyright IBM Corporation 2006. 5*4882a593Smuzhiyun# Author : Ram Pai (linuxram@us.ibm.com) 6*4882a593Smuzhiyun# 7*4882a593Smuzhiyun# Usage: export_report.pl -k Module.symvers [-o report_file ] -f *.mod.c 8*4882a593Smuzhiyun# 9*4882a593Smuzhiyun 10*4882a593Smuzhiyunuse warnings; 11*4882a593Smuzhiyunuse Getopt::Std; 12*4882a593Smuzhiyunuse strict; 13*4882a593Smuzhiyun 14*4882a593Smuzhiyunsub numerically { 15*4882a593Smuzhiyun my $no1 = (split /\s+/, $a)[1]; 16*4882a593Smuzhiyun my $no2 = (split /\s+/, $b)[1]; 17*4882a593Smuzhiyun return $no1 <=> $no2; 18*4882a593Smuzhiyun} 19*4882a593Smuzhiyun 20*4882a593Smuzhiyunsub alphabetically { 21*4882a593Smuzhiyun my ($module1, $value1) = @{$a}; 22*4882a593Smuzhiyun my ($module2, $value2) = @{$b}; 23*4882a593Smuzhiyun return $value1 <=> $value2 || $module2 cmp $module1; 24*4882a593Smuzhiyun} 25*4882a593Smuzhiyun 26*4882a593Smuzhiyunsub print_depends_on { 27*4882a593Smuzhiyun my ($href) = @_; 28*4882a593Smuzhiyun print "\n"; 29*4882a593Smuzhiyun for my $mod (sort keys %$href) { 30*4882a593Smuzhiyun my $list = $href->{$mod}; 31*4882a593Smuzhiyun print "\t$mod:\n"; 32*4882a593Smuzhiyun foreach my $sym (sort numerically @{$list}) { 33*4882a593Smuzhiyun my ($symbol, $no) = split /\s+/, $sym; 34*4882a593Smuzhiyun printf("\t\t%-25s\n", $symbol); 35*4882a593Smuzhiyun } 36*4882a593Smuzhiyun print "\n"; 37*4882a593Smuzhiyun } 38*4882a593Smuzhiyun print "\n"; 39*4882a593Smuzhiyun print "~"x80 , "\n"; 40*4882a593Smuzhiyun} 41*4882a593Smuzhiyun 42*4882a593Smuzhiyunsub usage { 43*4882a593Smuzhiyun print "Usage: @_ -h -k Module.symvers [ -o outputfile ] \n", 44*4882a593Smuzhiyun "\t-f: treat all the non-option argument as .mod.c files. ", 45*4882a593Smuzhiyun "Recommend using this as the last option\n", 46*4882a593Smuzhiyun "\t-h: print detailed help\n", 47*4882a593Smuzhiyun "\t-k: the path to Module.symvers file. By default uses ", 48*4882a593Smuzhiyun "the file from the current directory\n", 49*4882a593Smuzhiyun "\t-o outputfile: output the report to outputfile\n"; 50*4882a593Smuzhiyun exit 0; 51*4882a593Smuzhiyun} 52*4882a593Smuzhiyun 53*4882a593Smuzhiyunsub collectcfiles { 54*4882a593Smuzhiyun my @file; 55*4882a593Smuzhiyun open my $fh, '< modules.order' or die "cannot open modules.order: $!\n"; 56*4882a593Smuzhiyun while (<$fh>) { 57*4882a593Smuzhiyun s/\.ko$/.mod.c/; 58*4882a593Smuzhiyun push (@file, $_) 59*4882a593Smuzhiyun } 60*4882a593Smuzhiyun close($fh); 61*4882a593Smuzhiyun chomp @file; 62*4882a593Smuzhiyun return @file; 63*4882a593Smuzhiyun} 64*4882a593Smuzhiyun 65*4882a593Smuzhiyunmy (%SYMBOL, %MODULE, %opt, @allcfiles); 66*4882a593Smuzhiyun 67*4882a593Smuzhiyunif (not getopts('hk:o:f',\%opt) or defined $opt{'h'}) { 68*4882a593Smuzhiyun usage($0); 69*4882a593Smuzhiyun} 70*4882a593Smuzhiyun 71*4882a593Smuzhiyunif (defined $opt{'f'}) { 72*4882a593Smuzhiyun @allcfiles = @ARGV; 73*4882a593Smuzhiyun} else { 74*4882a593Smuzhiyun @allcfiles = collectcfiles(); 75*4882a593Smuzhiyun} 76*4882a593Smuzhiyun 77*4882a593Smuzhiyunif (not defined $opt{'k'}) { 78*4882a593Smuzhiyun $opt{'k'} = "Module.symvers"; 79*4882a593Smuzhiyun} 80*4882a593Smuzhiyun 81*4882a593Smuzhiyunopen (my $module_symvers, '<', $opt{'k'}) 82*4882a593Smuzhiyun or die "Sorry, cannot open $opt{'k'}: $!\n"; 83*4882a593Smuzhiyun 84*4882a593Smuzhiyunif (defined $opt{'o'}) { 85*4882a593Smuzhiyun open (my $out, '>', $opt{'o'}) 86*4882a593Smuzhiyun or die "Sorry, cannot open $opt{'o'} $!\n"; 87*4882a593Smuzhiyun 88*4882a593Smuzhiyun select $out; 89*4882a593Smuzhiyun} 90*4882a593Smuzhiyun 91*4882a593Smuzhiyun# 92*4882a593Smuzhiyun# collect all the symbols and their attributes from the 93*4882a593Smuzhiyun# Module.symvers file 94*4882a593Smuzhiyun# 95*4882a593Smuzhiyunwhile ( <$module_symvers> ) { 96*4882a593Smuzhiyun chomp; 97*4882a593Smuzhiyun my (undef, $symbol, $module, $gpl, $namespace) = split('\t'); 98*4882a593Smuzhiyun $SYMBOL { $symbol } = [ $module , "0" , $symbol, $gpl]; 99*4882a593Smuzhiyun} 100*4882a593Smuzhiyunclose($module_symvers); 101*4882a593Smuzhiyun 102*4882a593Smuzhiyun# 103*4882a593Smuzhiyun# collect the usage count of each symbol. 104*4882a593Smuzhiyun# 105*4882a593Smuzhiyunmy $modversion_warnings = 0; 106*4882a593Smuzhiyun 107*4882a593Smuzhiyunforeach my $thismod (@allcfiles) { 108*4882a593Smuzhiyun my $module; 109*4882a593Smuzhiyun 110*4882a593Smuzhiyun unless (open ($module, '<', $thismod)) { 111*4882a593Smuzhiyun warn "Sorry, cannot open $thismod: $!\n"; 112*4882a593Smuzhiyun next; 113*4882a593Smuzhiyun } 114*4882a593Smuzhiyun 115*4882a593Smuzhiyun my $state=0; 116*4882a593Smuzhiyun while ( <$module> ) { 117*4882a593Smuzhiyun chomp; 118*4882a593Smuzhiyun if ($state == 0) { 119*4882a593Smuzhiyun $state = 1 if ($_ =~ /static const struct modversion_info/); 120*4882a593Smuzhiyun next; 121*4882a593Smuzhiyun } 122*4882a593Smuzhiyun if ($state == 1) { 123*4882a593Smuzhiyun $state = 2 if ($_ =~ /__attribute__\(\(section\("__versions"\)\)\)/); 124*4882a593Smuzhiyun next; 125*4882a593Smuzhiyun } 126*4882a593Smuzhiyun if ($state == 2) { 127*4882a593Smuzhiyun if ( $_ !~ /0x[0-9a-f]+,/ ) { 128*4882a593Smuzhiyun next; 129*4882a593Smuzhiyun } 130*4882a593Smuzhiyun my $sym = (split /([,"])/,)[4]; 131*4882a593Smuzhiyun my ($module, $value, $symbol, $gpl) = @{$SYMBOL{$sym}}; 132*4882a593Smuzhiyun $SYMBOL{ $sym } = [ $module, $value+1, $symbol, $gpl]; 133*4882a593Smuzhiyun push(@{$MODULE{$thismod}} , $sym); 134*4882a593Smuzhiyun } 135*4882a593Smuzhiyun } 136*4882a593Smuzhiyun if ($state != 2) { 137*4882a593Smuzhiyun warn "WARNING:$thismod is not built with CONFIG_MODVERSIONS enabled\n"; 138*4882a593Smuzhiyun $modversion_warnings++; 139*4882a593Smuzhiyun } 140*4882a593Smuzhiyun close($module); 141*4882a593Smuzhiyun} 142*4882a593Smuzhiyun 143*4882a593Smuzhiyunprint "\tThis file reports the exported symbols usage patterns by in-tree\n", 144*4882a593Smuzhiyun "\t\t\t\tmodules\n"; 145*4882a593Smuzhiyunprintf("%s\n\n\n","x"x80); 146*4882a593Smuzhiyunprintf("\t\t\t\tINDEX\n\n\n"); 147*4882a593Smuzhiyunprintf("SECTION 1: Usage counts of all exported symbols\n"); 148*4882a593Smuzhiyunprintf("SECTION 2: List of modules and the exported symbols they use\n"); 149*4882a593Smuzhiyunprintf("%s\n\n\n","x"x80); 150*4882a593Smuzhiyunprintf("SECTION 1:\tThe exported symbols and their usage count\n\n"); 151*4882a593Smuzhiyunprintf("%-25s\t%-25s\t%-5s\t%-25s\n", "Symbol", "Module", "Usage count", 152*4882a593Smuzhiyun "export type"); 153*4882a593Smuzhiyun 154*4882a593Smuzhiyun# 155*4882a593Smuzhiyun# print the list of unused exported symbols 156*4882a593Smuzhiyun# 157*4882a593Smuzhiyunforeach my $list (sort alphabetically values(%SYMBOL)) { 158*4882a593Smuzhiyun my ($module, $value, $symbol, $gpl) = @{$list}; 159*4882a593Smuzhiyun printf("%-25s\t%-25s\t%-10s\t", $symbol, $module, $value); 160*4882a593Smuzhiyun if (defined $gpl) { 161*4882a593Smuzhiyun printf("%-25s\n",$gpl); 162*4882a593Smuzhiyun } else { 163*4882a593Smuzhiyun printf("\n"); 164*4882a593Smuzhiyun } 165*4882a593Smuzhiyun} 166*4882a593Smuzhiyunprintf("%s\n\n\n","x"x80); 167*4882a593Smuzhiyun 168*4882a593Smuzhiyunprintf("SECTION 2:\n\tThis section reports export-symbol-usage of in-kernel 169*4882a593Smuzhiyunmodules. Each module lists the modules, and the symbols from that module that 170*4882a593Smuzhiyunit uses. Each listed symbol reports the number of modules using it\n"); 171*4882a593Smuzhiyun 172*4882a593Smuzhiyunprint "\nNOTE: Got $modversion_warnings CONFIG_MODVERSIONS warnings\n\n" 173*4882a593Smuzhiyun if $modversion_warnings; 174*4882a593Smuzhiyun 175*4882a593Smuzhiyunprint "~"x80 , "\n"; 176*4882a593Smuzhiyunfor my $thismod (sort keys %MODULE) { 177*4882a593Smuzhiyun my $list = $MODULE{$thismod}; 178*4882a593Smuzhiyun my %depends; 179*4882a593Smuzhiyun $thismod =~ s/\.mod\.c/.ko/; 180*4882a593Smuzhiyun print "\t\t\t$thismod\n"; 181*4882a593Smuzhiyun foreach my $symbol (@{$list}) { 182*4882a593Smuzhiyun my ($module, $value, undef, $gpl) = @{$SYMBOL{$symbol}}; 183*4882a593Smuzhiyun push (@{$depends{"$module"}}, "$symbol $value"); 184*4882a593Smuzhiyun } 185*4882a593Smuzhiyun print_depends_on(\%depends); 186*4882a593Smuzhiyun} 187