18c2ecf20Sopenharmony_ci#!/usr/bin/env perl 28c2ecf20Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0-only 38c2ecf20Sopenharmony_ci# 48c2ecf20Sopenharmony_ci# (C) Copyright IBM Corporation 2006. 58c2ecf20Sopenharmony_ci# Author : Ram Pai (linuxram@us.ibm.com) 68c2ecf20Sopenharmony_ci# 78c2ecf20Sopenharmony_ci# Usage: export_report.pl -k Module.symvers [-o report_file ] -f *.mod.c 88c2ecf20Sopenharmony_ci# 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ciuse warnings; 118c2ecf20Sopenharmony_ciuse Getopt::Std; 128c2ecf20Sopenharmony_ciuse strict; 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cisub numerically { 158c2ecf20Sopenharmony_ci my $no1 = (split /\s+/, $a)[1]; 168c2ecf20Sopenharmony_ci my $no2 = (split /\s+/, $b)[1]; 178c2ecf20Sopenharmony_ci return $no1 <=> $no2; 188c2ecf20Sopenharmony_ci} 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cisub alphabetically { 218c2ecf20Sopenharmony_ci my ($module1, $value1) = @{$a}; 228c2ecf20Sopenharmony_ci my ($module2, $value2) = @{$b}; 238c2ecf20Sopenharmony_ci return $value1 <=> $value2 || $module2 cmp $module1; 248c2ecf20Sopenharmony_ci} 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cisub print_depends_on { 278c2ecf20Sopenharmony_ci my ($href) = @_; 288c2ecf20Sopenharmony_ci print "\n"; 298c2ecf20Sopenharmony_ci for my $mod (sort keys %$href) { 308c2ecf20Sopenharmony_ci my $list = $href->{$mod}; 318c2ecf20Sopenharmony_ci print "\t$mod:\n"; 328c2ecf20Sopenharmony_ci foreach my $sym (sort numerically @{$list}) { 338c2ecf20Sopenharmony_ci my ($symbol, $no) = split /\s+/, $sym; 348c2ecf20Sopenharmony_ci printf("\t\t%-25s\n", $symbol); 358c2ecf20Sopenharmony_ci } 368c2ecf20Sopenharmony_ci print "\n"; 378c2ecf20Sopenharmony_ci } 388c2ecf20Sopenharmony_ci print "\n"; 398c2ecf20Sopenharmony_ci print "~"x80 , "\n"; 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cisub usage { 438c2ecf20Sopenharmony_ci print "Usage: @_ -h -k Module.symvers [ -o outputfile ] \n", 448c2ecf20Sopenharmony_ci "\t-f: treat all the non-option argument as .mod.c files. ", 458c2ecf20Sopenharmony_ci "Recommend using this as the last option\n", 468c2ecf20Sopenharmony_ci "\t-h: print detailed help\n", 478c2ecf20Sopenharmony_ci "\t-k: the path to Module.symvers file. By default uses ", 488c2ecf20Sopenharmony_ci "the file from the current directory\n", 498c2ecf20Sopenharmony_ci "\t-o outputfile: output the report to outputfile\n"; 508c2ecf20Sopenharmony_ci exit 0; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cisub collectcfiles { 548c2ecf20Sopenharmony_ci my @file; 558c2ecf20Sopenharmony_ci open my $fh, '< modules.order' or die "cannot open modules.order: $!\n"; 568c2ecf20Sopenharmony_ci while (<$fh>) { 578c2ecf20Sopenharmony_ci s/\.ko$/.mod.c/; 588c2ecf20Sopenharmony_ci push (@file, $_) 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci close($fh); 618c2ecf20Sopenharmony_ci chomp @file; 628c2ecf20Sopenharmony_ci return @file; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cimy (%SYMBOL, %MODULE, %opt, @allcfiles); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ciif (not getopts('hk:o:f',\%opt) or defined $opt{'h'}) { 688c2ecf20Sopenharmony_ci usage($0); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ciif (defined $opt{'f'}) { 728c2ecf20Sopenharmony_ci @allcfiles = @ARGV; 738c2ecf20Sopenharmony_ci} else { 748c2ecf20Sopenharmony_ci @allcfiles = collectcfiles(); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ciif (not defined $opt{'k'}) { 788c2ecf20Sopenharmony_ci $opt{'k'} = "Module.symvers"; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ciopen (my $module_symvers, '<', $opt{'k'}) 828c2ecf20Sopenharmony_ci or die "Sorry, cannot open $opt{'k'}: $!\n"; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ciif (defined $opt{'o'}) { 858c2ecf20Sopenharmony_ci open (my $out, '>', $opt{'o'}) 868c2ecf20Sopenharmony_ci or die "Sorry, cannot open $opt{'o'} $!\n"; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci select $out; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci# 928c2ecf20Sopenharmony_ci# collect all the symbols and their attributes from the 938c2ecf20Sopenharmony_ci# Module.symvers file 948c2ecf20Sopenharmony_ci# 958c2ecf20Sopenharmony_ciwhile ( <$module_symvers> ) { 968c2ecf20Sopenharmony_ci chomp; 978c2ecf20Sopenharmony_ci my (undef, $symbol, $module, $gpl, $namespace) = split('\t'); 988c2ecf20Sopenharmony_ci $SYMBOL { $symbol } = [ $module , "0" , $symbol, $gpl]; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ciclose($module_symvers); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci# 1038c2ecf20Sopenharmony_ci# collect the usage count of each symbol. 1048c2ecf20Sopenharmony_ci# 1058c2ecf20Sopenharmony_cimy $modversion_warnings = 0; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ciforeach my $thismod (@allcfiles) { 1088c2ecf20Sopenharmony_ci my $module; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci unless (open ($module, '<', $thismod)) { 1118c2ecf20Sopenharmony_ci warn "Sorry, cannot open $thismod: $!\n"; 1128c2ecf20Sopenharmony_ci next; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci my $state=0; 1168c2ecf20Sopenharmony_ci while ( <$module> ) { 1178c2ecf20Sopenharmony_ci chomp; 1188c2ecf20Sopenharmony_ci if ($state == 0) { 1198c2ecf20Sopenharmony_ci $state = 1 if ($_ =~ /static const struct modversion_info/); 1208c2ecf20Sopenharmony_ci next; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci if ($state == 1) { 1238c2ecf20Sopenharmony_ci $state = 2 if ($_ =~ /__attribute__\(\(section\("__versions"\)\)\)/); 1248c2ecf20Sopenharmony_ci next; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci if ($state == 2) { 1278c2ecf20Sopenharmony_ci if ( $_ !~ /0x[0-9a-f]+,/ ) { 1288c2ecf20Sopenharmony_ci next; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci my $sym = (split /([,"])/,)[4]; 1318c2ecf20Sopenharmony_ci my ($module, $value, $symbol, $gpl) = @{$SYMBOL{$sym}}; 1328c2ecf20Sopenharmony_ci $SYMBOL{ $sym } = [ $module, $value+1, $symbol, $gpl]; 1338c2ecf20Sopenharmony_ci push(@{$MODULE{$thismod}} , $sym); 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci if ($state != 2) { 1378c2ecf20Sopenharmony_ci warn "WARNING:$thismod is not built with CONFIG_MODVERSIONS enabled\n"; 1388c2ecf20Sopenharmony_ci $modversion_warnings++; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci close($module); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ciprint "\tThis file reports the exported symbols usage patterns by in-tree\n", 1448c2ecf20Sopenharmony_ci "\t\t\t\tmodules\n"; 1458c2ecf20Sopenharmony_ciprintf("%s\n\n\n","x"x80); 1468c2ecf20Sopenharmony_ciprintf("\t\t\t\tINDEX\n\n\n"); 1478c2ecf20Sopenharmony_ciprintf("SECTION 1: Usage counts of all exported symbols\n"); 1488c2ecf20Sopenharmony_ciprintf("SECTION 2: List of modules and the exported symbols they use\n"); 1498c2ecf20Sopenharmony_ciprintf("%s\n\n\n","x"x80); 1508c2ecf20Sopenharmony_ciprintf("SECTION 1:\tThe exported symbols and their usage count\n\n"); 1518c2ecf20Sopenharmony_ciprintf("%-25s\t%-25s\t%-5s\t%-25s\n", "Symbol", "Module", "Usage count", 1528c2ecf20Sopenharmony_ci "export type"); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci# 1558c2ecf20Sopenharmony_ci# print the list of unused exported symbols 1568c2ecf20Sopenharmony_ci# 1578c2ecf20Sopenharmony_ciforeach my $list (sort alphabetically values(%SYMBOL)) { 1588c2ecf20Sopenharmony_ci my ($module, $value, $symbol, $gpl) = @{$list}; 1598c2ecf20Sopenharmony_ci printf("%-25s\t%-25s\t%-10s\t", $symbol, $module, $value); 1608c2ecf20Sopenharmony_ci if (defined $gpl) { 1618c2ecf20Sopenharmony_ci printf("%-25s\n",$gpl); 1628c2ecf20Sopenharmony_ci } else { 1638c2ecf20Sopenharmony_ci printf("\n"); 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ciprintf("%s\n\n\n","x"x80); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ciprintf("SECTION 2:\n\tThis section reports export-symbol-usage of in-kernel 1698c2ecf20Sopenharmony_cimodules. Each module lists the modules, and the symbols from that module that 1708c2ecf20Sopenharmony_ciit uses. Each listed symbol reports the number of modules using it\n"); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ciprint "\nNOTE: Got $modversion_warnings CONFIG_MODVERSIONS warnings\n\n" 1738c2ecf20Sopenharmony_ci if $modversion_warnings; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ciprint "~"x80 , "\n"; 1768c2ecf20Sopenharmony_cifor my $thismod (sort keys %MODULE) { 1778c2ecf20Sopenharmony_ci my $list = $MODULE{$thismod}; 1788c2ecf20Sopenharmony_ci my %depends; 1798c2ecf20Sopenharmony_ci $thismod =~ s/\.mod\.c/.ko/; 1808c2ecf20Sopenharmony_ci print "\t\t\t$thismod\n"; 1818c2ecf20Sopenharmony_ci foreach my $symbol (@{$list}) { 1828c2ecf20Sopenharmony_ci my ($module, $value, undef, $gpl) = @{$SYMBOL{$symbol}}; 1838c2ecf20Sopenharmony_ci push (@{$depends{"$module"}}, "$symbol $value"); 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci print_depends_on(\%depends); 1868c2ecf20Sopenharmony_ci} 187