1c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai#!/usr/bin/perl -w
2c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai#
3c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai# (C) Copyright IBM Corporation 2006.
4c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai#	Released under GPL v2.
5c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai#	Author : Ram Pai (linuxram@us.ibm.com)
6c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai#
7c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai# Usage: export_report.pl -k Module.symvers [-o report_file ] -f *.mod.c
8c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai#
9c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai
10c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiuse Getopt::Std;
11c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiuse strict;
12c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai
13c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paisub numerically {
14c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	my $no1 = (split /\s+/, $a)[1];
15c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	my $no2 = (split /\s+/, $b)[1];
16c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	return $no1 <=> $no2;
17c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai}
18c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai
19c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paisub alphabetically {
20c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	my ($module1, $value1) = @{$a};
21c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	my ($module2, $value2) = @{$b};
22c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	return $value1 <=> $value2 || $module2 cmp $module1;
23c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai}
24c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai
25c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paisub print_depends_on {
26c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	my ($href) = @_;
27c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	print "\n";
28bdabc7a345db97b3839c2c3deef40023cf8017efJim Cromie	for my $mod (sort keys %$href) {
29bdabc7a345db97b3839c2c3deef40023cf8017efJim Cromie		my $list = $href->{$mod};
30c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai		print "\t$mod:\n";
31c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai		foreach my $sym (sort numerically @{$list}) {
32c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai			my ($symbol, $no) = split /\s+/, $sym;
33bdabc7a345db97b3839c2c3deef40023cf8017efJim Cromie			printf("\t\t%-25s\n", $symbol);
34c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai		}
35c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai		print "\n";
36c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	}
37c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	print "\n";
38c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	print "~"x80 , "\n";
39c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai}
40c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai
41c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paisub usage {
42c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai        print "Usage: @_ -h -k Module.symvers  [ -o outputfile ] \n",
43c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	      "\t-f: treat all the non-option argument as .mod.c files. ",
44c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	      "Recommend using this as the last option\n",
45c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	      "\t-h: print detailed help\n",
46c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	      "\t-k: the path to Module.symvers file. By default uses ",
47c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	      "the file from the current directory\n",
48c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	      "\t-o outputfile: output the report to outputfile\n";
49c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	exit 0;
50c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai}
51c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai
52c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paisub collectcfiles {
53de7b0b4110795be914e6cafdfec4276b2618cc78Jim Cromie    my @file;
54de7b0b4110795be914e6cafdfec4276b2618cc78Jim Cromie    while (<.tmp_versions/*.mod>) {
55de7b0b4110795be914e6cafdfec4276b2618cc78Jim Cromie	open my $fh, '<', $_ or die "cannot open $_: $!\n";
56de7b0b4110795be914e6cafdfec4276b2618cc78Jim Cromie	push (@file,
57de7b0b4110795be914e6cafdfec4276b2618cc78Jim Cromie	      grep s/\.ko/.mod.c/,	# change the suffix
58de7b0b4110795be914e6cafdfec4276b2618cc78Jim Cromie	      grep m/.+\.ko/,		# find the .ko path
59de7b0b4110795be914e6cafdfec4276b2618cc78Jim Cromie	      <$fh>);			# lines in opened file
60de7b0b4110795be914e6cafdfec4276b2618cc78Jim Cromie    }
6191416cfdf98bdbc828fd3e5ca7208beba5979d63Stephen Hemminger    chomp @file;
6291416cfdf98bdbc828fd3e5ca7208beba5979d63Stephen Hemminger    return @file;
63c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai}
64c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai
65c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paimy (%SYMBOL, %MODULE, %opt, @allcfiles);
66c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai
67c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiif (not getopts('hk:o:f',\%opt) or defined $opt{'h'}) {
68c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai        usage($0);
69c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai}
70c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai
71c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiif (defined $opt{'f'}) {
72c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	@allcfiles = @ARGV;
73c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai} else {
74c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	@allcfiles = collectcfiles();
75c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai}
76c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai
77c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiif (not defined $opt{'k'}) {
78c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	$opt{'k'} = "Module.symvers";
79c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai}
80c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai
8191416cfdf98bdbc828fd3e5ca7208beba5979d63Stephen Hemmingeropen (my $module_symvers, '<', $opt{'k'})
8291416cfdf98bdbc828fd3e5ca7208beba5979d63Stephen Hemminger    or die "Sorry, cannot open $opt{'k'}: $!\n";
83c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai
84c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiif (defined $opt{'o'}) {
8591416cfdf98bdbc828fd3e5ca7208beba5979d63Stephen Hemminger    open (my $out, '>', $opt{'o'})
8691416cfdf98bdbc828fd3e5ca7208beba5979d63Stephen Hemminger	or die "Sorry, cannot open $opt{'o'} $!\n";
8791416cfdf98bdbc828fd3e5ca7208beba5979d63Stephen Hemminger
8891416cfdf98bdbc828fd3e5ca7208beba5979d63Stephen Hemminger    select $out;
89c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai}
9091416cfdf98bdbc828fd3e5ca7208beba5979d63Stephen Hemminger
91c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai#
92c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai# collect all the symbols and their attributes from the
93c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai# Module.symvers file
94c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai#
9591416cfdf98bdbc828fd3e5ca7208beba5979d63Stephen Hemmingerwhile ( <$module_symvers> ) {
96c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	chomp;
97c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	my (undef, $symbol, $module, $gpl) = split;
98c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	$SYMBOL { $symbol } =  [ $module , "0" , $symbol, $gpl];
99c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai}
10091416cfdf98bdbc828fd3e5ca7208beba5979d63Stephen Hemmingerclose($module_symvers);
101c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai
102c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai#
103c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai# collect the usage count of each symbol.
104c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai#
105ca995cbf77f3df599b7e751c2d08d90787c65c45Jim Cromiemy $modversion_warnings = 0;
106ca995cbf77f3df599b7e751c2d08d90787c65c45Jim Cromie
107c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiforeach my $thismod (@allcfiles) {
10891416cfdf98bdbc828fd3e5ca7208beba5979d63Stephen Hemminger	my $module;
10991416cfdf98bdbc828fd3e5ca7208beba5979d63Stephen Hemminger
11091416cfdf98bdbc828fd3e5ca7208beba5979d63Stephen Hemminger	unless (open ($module, '<', $thismod)) {
11191416cfdf98bdbc828fd3e5ca7208beba5979d63Stephen Hemminger		warn "Sorry, cannot open $thismod: $!\n";
112c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai		next;
113c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	}
11491416cfdf98bdbc828fd3e5ca7208beba5979d63Stephen Hemminger
115c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	my $state=0;
11691416cfdf98bdbc828fd3e5ca7208beba5979d63Stephen Hemminger	while ( <$module> ) {
117c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai		chomp;
11888f567f3a3c1901a40150b43fda87adad1b3e807Ram Pai		if ($state == 0) {
119c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai			$state = 1 if ($_ =~ /static const struct modversion_info/);
120c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai			next;
121c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai		}
12288f567f3a3c1901a40150b43fda87adad1b3e807Ram Pai		if ($state == 1) {
123c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai			$state = 2 if ($_ =~ /__attribute__\(\(section\("__versions"\)\)\)/);
124c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai			next;
125c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai		}
12688f567f3a3c1901a40150b43fda87adad1b3e807Ram Pai		if ($state == 2) {
127cf9a6adeae706849990e5bdd4f32cb45d667e0c5Adrian Bunk			if ( $_ !~ /0x[0-9a-f]+,/ ) {
128c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai				next;
129c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai			}
130c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai			my $sym = (split /([,"])/,)[4];
131c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai			my ($module, $value, $symbol, $gpl) = @{$SYMBOL{$sym}};
132c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai			$SYMBOL{ $sym } =  [ $module, $value+1, $symbol, $gpl];
133c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai			push(@{$MODULE{$thismod}} , $sym);
134c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai		}
135c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	}
13688f567f3a3c1901a40150b43fda87adad1b3e807Ram Pai	if ($state != 2) {
137ca995cbf77f3df599b7e751c2d08d90787c65c45Jim Cromie		warn "WARNING:$thismod is not built with CONFIG_MODVERSIONS enabled\n";
138ca995cbf77f3df599b7e751c2d08d90787c65c45Jim Cromie		$modversion_warnings++;
139c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	}
14091416cfdf98bdbc828fd3e5ca7208beba5979d63Stephen Hemminger	close($module);
141c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai}
142c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai
143c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiprint "\tThis file reports the exported symbols usage patterns by in-tree\n",
144c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	"\t\t\t\tmodules\n";
145c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiprintf("%s\n\n\n","x"x80);
146c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiprintf("\t\t\t\tINDEX\n\n\n");
147c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiprintf("SECTION 1: Usage counts of all exported symbols\n");
148c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiprintf("SECTION 2: List of modules and the exported symbols they use\n");
149c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiprintf("%s\n\n\n","x"x80);
150c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiprintf("SECTION 1:\tThe exported symbols and their usage count\n\n");
151c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiprintf("%-25s\t%-25s\t%-5s\t%-25s\n", "Symbol", "Module", "Usage count",
152c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	"export type");
153c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai
154c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai#
155c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai# print the list of unused exported symbols
156c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai#
157c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiforeach my $list (sort alphabetically values(%SYMBOL)) {
158c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	my ($module, $value, $symbol, $gpl) = @{$list};
159c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	printf("%-25s\t%-25s\t%-10s\t", $symbol, $module, $value);
160c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	if (defined $gpl) {
161c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai		printf("%-25s\n",$gpl);
162c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	} else {
163c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai		printf("\n");
164c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	}
165c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai}
166c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiprintf("%s\n\n\n","x"x80);
167c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai
168c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiprintf("SECTION 2:\n\tThis section reports export-symbol-usage of in-kernel
169c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paimodules. Each module lists the modules, and the symbols from that module that
170c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiit uses.  Each listed symbol reports the number of modules using it\n");
171c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai
172ca995cbf77f3df599b7e751c2d08d90787c65c45Jim Cromieprint "\nNOTE: Got $modversion_warnings CONFIG_MODVERSIONS warnings\n\n"
173ca995cbf77f3df599b7e751c2d08d90787c65c45Jim Cromie    if $modversion_warnings;
174ca995cbf77f3df599b7e751c2d08d90787c65c45Jim Cromie
175c5e3003381f4e39773a1758a9eb68dff9740a56cRam Paiprint "~"x80 , "\n";
176bdabc7a345db97b3839c2c3deef40023cf8017efJim Cromiefor my $thismod (sort keys %MODULE) {
177bdabc7a345db97b3839c2c3deef40023cf8017efJim Cromie	my $list = $MODULE{$thismod};
178c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	my %depends;
179c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	$thismod =~ s/\.mod\.c/.ko/;
180c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	print "\t\t\t$thismod\n";
181c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	foreach my $symbol (@{$list}) {
182c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai		my ($module, $value, undef, $gpl) = @{$SYMBOL{$symbol}};
183c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai		push (@{$depends{"$module"}}, "$symbol $value");
184c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	}
185c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai	print_depends_on(\%depends);
186c5e3003381f4e39773a1758a9eb68dff9740a56cRam Pai}
187