162306a36Sopenharmony_ci#!/usr/bin/env perl 262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0-only 362306a36Sopenharmony_ci# 462306a36Sopenharmony_ci# (C) Copyright IBM Corporation 2006. 562306a36Sopenharmony_ci# Author : Ram Pai (linuxram@us.ibm.com) 662306a36Sopenharmony_ci# 762306a36Sopenharmony_ci# Usage: export_report.pl -k Module.symvers [-o report_file ] -f *.mod.c 862306a36Sopenharmony_ci# 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ciuse warnings; 1162306a36Sopenharmony_ciuse Getopt::Std; 1262306a36Sopenharmony_ciuse strict; 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cisub numerically { 1562306a36Sopenharmony_ci my $no1 = (split /\s+/, $a)[1]; 1662306a36Sopenharmony_ci my $no2 = (split /\s+/, $b)[1]; 1762306a36Sopenharmony_ci return $no1 <=> $no2; 1862306a36Sopenharmony_ci} 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cisub alphabetically { 2162306a36Sopenharmony_ci my ($module1, $value1) = @{$a}; 2262306a36Sopenharmony_ci my ($module2, $value2) = @{$b}; 2362306a36Sopenharmony_ci return $value1 <=> $value2 || $module2 cmp $module1; 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cisub print_depends_on { 2762306a36Sopenharmony_ci my ($href) = @_; 2862306a36Sopenharmony_ci print "\n"; 2962306a36Sopenharmony_ci for my $mod (sort keys %$href) { 3062306a36Sopenharmony_ci my $list = $href->{$mod}; 3162306a36Sopenharmony_ci print "\t$mod:\n"; 3262306a36Sopenharmony_ci foreach my $sym (sort numerically @{$list}) { 3362306a36Sopenharmony_ci my ($symbol, $no) = split /\s+/, $sym; 3462306a36Sopenharmony_ci printf("\t\t%-25s\n", $symbol); 3562306a36Sopenharmony_ci } 3662306a36Sopenharmony_ci print "\n"; 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci print "\n"; 3962306a36Sopenharmony_ci print "~"x80 , "\n"; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cisub usage { 4362306a36Sopenharmony_ci print "Usage: @_ -h -k Module.symvers [ -o outputfile ] \n", 4462306a36Sopenharmony_ci "\t-f: treat all the non-option argument as .mod.c files. ", 4562306a36Sopenharmony_ci "Recommend using this as the last option\n", 4662306a36Sopenharmony_ci "\t-h: print detailed help\n", 4762306a36Sopenharmony_ci "\t-k: the path to Module.symvers file. By default uses ", 4862306a36Sopenharmony_ci "the file from the current directory\n", 4962306a36Sopenharmony_ci "\t-o outputfile: output the report to outputfile\n"; 5062306a36Sopenharmony_ci exit 0; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cisub collectcfiles { 5462306a36Sopenharmony_ci my @file; 5562306a36Sopenharmony_ci open my $fh, '< modules.order' or die "cannot open modules.order: $!\n"; 5662306a36Sopenharmony_ci while (<$fh>) { 5762306a36Sopenharmony_ci s/\.ko$/.mod.c/; 5862306a36Sopenharmony_ci push (@file, $_) 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci close($fh); 6162306a36Sopenharmony_ci chomp @file; 6262306a36Sopenharmony_ci return @file; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cimy (%SYMBOL, %MODULE, %opt, @allcfiles); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ciif (not getopts('hk:o:f',\%opt) or defined $opt{'h'}) { 6862306a36Sopenharmony_ci usage($0); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ciif (defined $opt{'f'}) { 7262306a36Sopenharmony_ci @allcfiles = @ARGV; 7362306a36Sopenharmony_ci} else { 7462306a36Sopenharmony_ci @allcfiles = collectcfiles(); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ciif (not defined $opt{'k'}) { 7862306a36Sopenharmony_ci $opt{'k'} = "Module.symvers"; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ciopen (my $module_symvers, '<', $opt{'k'}) 8262306a36Sopenharmony_ci or die "Sorry, cannot open $opt{'k'}: $!\n"; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ciif (defined $opt{'o'}) { 8562306a36Sopenharmony_ci open (my $out, '>', $opt{'o'}) 8662306a36Sopenharmony_ci or die "Sorry, cannot open $opt{'o'} $!\n"; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci select $out; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci# 9262306a36Sopenharmony_ci# collect all the symbols and their attributes from the 9362306a36Sopenharmony_ci# Module.symvers file 9462306a36Sopenharmony_ci# 9562306a36Sopenharmony_ciwhile ( <$module_symvers> ) { 9662306a36Sopenharmony_ci chomp; 9762306a36Sopenharmony_ci my (undef, $symbol, $module, $gpl, $namespace) = split('\t'); 9862306a36Sopenharmony_ci $SYMBOL { $symbol } = [ $module , "0" , $symbol, $gpl]; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ciclose($module_symvers); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci# 10362306a36Sopenharmony_ci# collect the usage count of each symbol. 10462306a36Sopenharmony_ci# 10562306a36Sopenharmony_cimy $modversion_warnings = 0; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ciforeach my $thismod (@allcfiles) { 10862306a36Sopenharmony_ci my $module; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci unless (open ($module, '<', $thismod)) { 11162306a36Sopenharmony_ci warn "Sorry, cannot open $thismod: $!\n"; 11262306a36Sopenharmony_ci next; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci my $state=0; 11662306a36Sopenharmony_ci while ( <$module> ) { 11762306a36Sopenharmony_ci chomp; 11862306a36Sopenharmony_ci if ($state == 0) { 11962306a36Sopenharmony_ci $state = 1 if ($_ =~ /static const struct modversion_info/); 12062306a36Sopenharmony_ci next; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci if ($state == 1) { 12362306a36Sopenharmony_ci $state = 2 if ($_ =~ /__attribute__\(\(section\("__versions"\)\)\)/); 12462306a36Sopenharmony_ci next; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci if ($state == 2) { 12762306a36Sopenharmony_ci if ( $_ !~ /0x[0-9a-f]+,/ ) { 12862306a36Sopenharmony_ci next; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci my $sym = (split /([,"])/,)[4]; 13162306a36Sopenharmony_ci my ($module, $value, $symbol, $gpl) = @{$SYMBOL{$sym}}; 13262306a36Sopenharmony_ci $SYMBOL{ $sym } = [ $module, $value+1, $symbol, $gpl]; 13362306a36Sopenharmony_ci push(@{$MODULE{$thismod}} , $sym); 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci if ($state != 2) { 13762306a36Sopenharmony_ci warn "WARNING:$thismod is not built with CONFIG_MODVERSIONS enabled\n"; 13862306a36Sopenharmony_ci $modversion_warnings++; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci close($module); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ciprint "\tThis file reports the exported symbols usage patterns by in-tree\n", 14462306a36Sopenharmony_ci "\t\t\t\tmodules\n"; 14562306a36Sopenharmony_ciprintf("%s\n\n\n","x"x80); 14662306a36Sopenharmony_ciprintf("\t\t\t\tINDEX\n\n\n"); 14762306a36Sopenharmony_ciprintf("SECTION 1: Usage counts of all exported symbols\n"); 14862306a36Sopenharmony_ciprintf("SECTION 2: List of modules and the exported symbols they use\n"); 14962306a36Sopenharmony_ciprintf("%s\n\n\n","x"x80); 15062306a36Sopenharmony_ciprintf("SECTION 1:\tThe exported symbols and their usage count\n\n"); 15162306a36Sopenharmony_ciprintf("%-25s\t%-25s\t%-5s\t%-25s\n", "Symbol", "Module", "Usage count", 15262306a36Sopenharmony_ci "export type"); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci# 15562306a36Sopenharmony_ci# print the list of unused exported symbols 15662306a36Sopenharmony_ci# 15762306a36Sopenharmony_ciforeach my $list (sort alphabetically values(%SYMBOL)) { 15862306a36Sopenharmony_ci my ($module, $value, $symbol, $gpl) = @{$list}; 15962306a36Sopenharmony_ci printf("%-25s\t%-25s\t%-10s\t", $symbol, $module, $value); 16062306a36Sopenharmony_ci if (defined $gpl) { 16162306a36Sopenharmony_ci printf("%-25s\n",$gpl); 16262306a36Sopenharmony_ci } else { 16362306a36Sopenharmony_ci printf("\n"); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ciprintf("%s\n\n\n","x"x80); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ciprintf("SECTION 2:\n\tThis section reports export-symbol-usage of in-kernel 16962306a36Sopenharmony_cimodules. Each module lists the modules, and the symbols from that module that 17062306a36Sopenharmony_ciit uses. Each listed symbol reports the number of modules using it\n"); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ciprint "\nNOTE: Got $modversion_warnings CONFIG_MODVERSIONS warnings\n\n" 17362306a36Sopenharmony_ci if $modversion_warnings; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ciprint "~"x80 , "\n"; 17662306a36Sopenharmony_cifor my $thismod (sort keys %MODULE) { 17762306a36Sopenharmony_ci my $list = $MODULE{$thismod}; 17862306a36Sopenharmony_ci my %depends; 17962306a36Sopenharmony_ci $thismod =~ s/\.mod\.c/.ko/; 18062306a36Sopenharmony_ci print "\t\t\t$thismod\n"; 18162306a36Sopenharmony_ci foreach my $symbol (@{$list}) { 18262306a36Sopenharmony_ci my ($module, $value, undef, $gpl) = @{$SYMBOL{$symbol}}; 18362306a36Sopenharmony_ci push (@{$depends{"$module"}}, "$symbol $value"); 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci print_depends_on(\%depends); 18662306a36Sopenharmony_ci} 187