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