randomconfig fixes
[oweals/busybox.git] / examples / depmod.pl
1 #!/usr/bin/perl -w
2 # vi: set sw=4 ts=4:
3 # Copyright (c) 2001 David Schleef <ds@schleef.org>
4 # Copyright (c) 2001 Erik Andersen <andersen@codepoet.org>
5 # Copyright (c) 2001 Stuart Hughes <seh@zee2.com>
6 # Copyright (c) 2002 Steven J. Hill <shill@broadcom.com>
7 # Copyright (c) 2006 Freescale Semiconductor, Inc <stuarth@freescale.com>
8 #
9 # History:
10 # March 2006: Stuart Hughes <stuarth@freescale.com>.
11 #             Significant updates, including implementing the '-F' option
12 #             and adding support for 2.6 kernels.
13
14 # This program is free software; you can redistribute it and/or modify it
15 # under the same terms as Perl itself.
16 use Getopt::Long qw(:config no_auto_abbrev no_ignore_case);
17 use File::Find;
18 use strict;
19
20 # Set up some default values
21 my $kdir="";
22 my $basedir="";
23 my $kernel="";
24 my $kernelsyms="";
25 my $symprefix="";
26 my $all=0;
27 my $quick=0;
28 my $errsyms=0;
29 my $stdout=0;
30 my $verbose=0;
31 my $help=0;
32 my $nm = $ENV{'NM'} || "nm";
33
34 # more globals
35 my (@liblist) = ();
36 my $exp = {};
37 my $dep = {};
38 my $mod = {};
39
40 my $usage = <<TXT;
41 $0 -b basedir { -k <vmlinux> | -F <System.map> } [options]...
42   Where:
43    -h --help          : Show this help screen
44    -b --basedir       : Modules base directory (e.g /lib/modules/<2.x.y>)
45    -k --kernel        : Kernel binary for the target (e.g. vmlinux)
46    -F --kernelsyms    : Kernel symbol file (e.g. System.map)
47    -n --stdout        : Write to stdout instead of <basedir>/modules.dep
48    -v --verbose       : Print out lots of debugging stuff
49    -P --symbol-prefix : Symbol prefix
50    -a --all           : Probe all modules (default/only thing supported)
51    -e --errsyms       : Report any symbols not supplied by modules/kernel
52 TXT
53
54 # get command-line options
55 GetOptions(
56         "help|h"            => \$help,
57         "basedir|b=s"       => \$basedir,
58         "kernel|k=s"        => \$kernel,
59         "kernelsyms|F=s"    => \$kernelsyms,
60         "stdout|n"          => \$stdout,
61         "verbose|v"         => \$verbose,
62         "symbol-prefix|P=s" => \$symprefix,
63         "all|a"             => \$all,
64         # unsupported options
65         "quick|A"           => \$quick,
66         # ignored options (for historical usage)
67         "quiet|q",
68         "root|r",
69         "unresolved-error|u"
70 );
71
72 die $usage if $help;
73 die $usage unless $basedir && ( $kernel || $kernelsyms );
74 die "can't use both -k and -F\n\n$usage" if $kernel && $kernelsyms;
75 die "sorry, -A/--quick is not supported" if $quick;
76 die "--errsyms requires --kernelsyms" if $errsyms && !$kernelsyms;
77
78 # Strip any trailing or multiple slashes from basedir
79 $basedir =~ s-/+$--g;
80
81 # The base directory should contain /lib/modules somewhere
82 if($basedir !~ m-/lib/modules-) {
83     warn "WARNING: base directory does not match ..../lib/modules\n";
84 }
85
86 # if no kernel version is contained in the basedir, try to find one
87 if($basedir !~ m-/lib/modules/\d\.\d-) {
88     opendir(BD, $basedir) or die "can't open basedir $basedir : $!\n";
89     foreach ( readdir(BD) ) {
90         next if /^\.\.?$/;
91         next unless -d "$basedir/$_";
92         warn "dir = $_\n" if $verbose;
93         if( /^\d\.\d/ ) {
94             $kdir = $_;
95             warn("Guessed module directory as $basedir/$kdir\n");
96             last;
97         }
98     }
99     closedir(BD);
100     die "Cannot find a kernel version under $basedir\n" unless $kdir;
101     $basedir = "$basedir/$kdir";
102 }
103
104 # Find the list of .o or .ko files living under $basedir
105 warn "**** Locating all modules\n" if $verbose;
106 find sub {
107     my $file;
108         if ( -f $_  && ! -d $_ ) {
109                 $file = $File::Find::name;
110                 if ( $file =~ /\.k?o$/ ) {
111                         push(@liblist, $file);
112                         warn "$file\n" if $verbose;
113                 }
114         }
115 }, $basedir;
116 warn "**** Finished locating modules\n" if $verbose;
117
118 foreach my $obj ( @liblist ){
119     # turn the input file name into a target tag name
120     my ($tgtname) = $obj =~ m-(/lib/modules/.*)$-;
121
122     warn "\nMODULE = $tgtname\n" if $verbose;
123
124     # get a list of symbols
125         my @output=`$nm $obj`;
126
127     build_ref_tables($tgtname, \@output, $exp, $dep);
128 }
129
130
131 # vmlinux is a special name that is only used to resolve symbols
132 my $tgtname = 'vmlinux';
133 my @output = $kernelsyms ? `cat $kernelsyms` : `$nm $kernel`;
134 warn "\nMODULE = $tgtname\n" if $verbose;
135 build_ref_tables($tgtname, \@output, $exp, $dep);
136
137 # resolve the dependencies for each module
138 # reduce dependencies: remove unresolvable and resolved from vmlinux/System.map
139 # remove duplicates
140 foreach my $module (keys %$dep) {
141     warn "reducing module: $module\n" if $verbose;
142     $mod->{$module} = {};
143     foreach (@{$dep->{$module}}) {
144         if( $exp->{$_} ) {
145             warn "resolved symbol $_ in file $exp->{$_}\n" if $verbose;
146             next if $exp->{$_} =~ /vmlinux/;
147             $mod->{$module}{$exp->{$_}} = 1;
148         } else {
149             warn "unresolved symbol $_ in file $module\n";
150         }
151     }
152 }
153
154 # build a complete dependency list for each module and make sure it
155 # is kept in order proper order
156 my $mod2 = {};
157 sub maybe_unshift
158 {
159         my ($array, $ele) = @_;
160         # chop off the leading path /lib/modules/<kver>/ as modprobe
161         # will handle relative paths just fine
162         $ele =~ s:^/lib/modules/[^/]*/::;
163         foreach (@{$array}) {
164                 if ($_ eq $ele) {
165                         return;
166                 }
167         }
168         unshift (@{$array}, $ele);
169 }
170 sub add_mod_deps
171 {
172         my ($depth, $mod, $mod2, $module, $this_module) = @_;
173
174         $depth .= " ";
175         warn "${depth}loading deps of module: $this_module\n" if $verbose;
176         if (length($depth) > 50) {
177                 die "too much recursion (circular dependencies in modules?)";
178         }
179
180         foreach my $md (keys %{$mod->{$this_module}}) {
181                 add_mod_deps ($depth, $mod, $mod2, $module, $md);
182                 warn "${depth} outputting $md\n" if $verbose;
183                 maybe_unshift (\@{$$mod2->{$module}}, $md);
184         }
185
186         if (!%{$mod->{$this_module}}) {
187                 warn "${depth} no deps\n" if $verbose;
188         }
189 }
190 foreach my $module (keys %$mod) {
191         warn "filling out module: $module\n" if $verbose;
192         @{$mod2->{$module}} = ();
193         add_mod_deps ("", $mod, \$mod2, $module, $module);
194 }
195
196 # figure out where the output should go
197 if ($stdout == 0) {
198         warn "writing $basedir/modules.dep\n" if $verbose;
199     open(STDOUT, ">$basedir/modules.dep")
200                              or die "cannot open $basedir/modules.dep: $!";
201 }
202 my $kseries = $basedir =~ m,/2\.4\.[^/]*, ? '2.4' : 'others';
203
204 foreach my $module ( keys %$mod ) {
205     if($kseries eq '2.4') {
206             print "$module:\t";
207             my @sorted = sort bydep keys %{$mod->{$module}};
208             print join(" \\\n\t",@sorted);
209             print "\n\n";
210     } else {
211             my $shortmod = $module;
212             $shortmod =~ s:^/lib/modules/[^/]*/::;
213             print "$shortmod:";
214             my @sorted = @{$mod2->{$module}};
215             printf " " if @sorted;
216             print join(" ",@sorted);
217             print "\n";
218     }
219 }
220
221
222 sub build_ref_tables
223 {
224     my ($name, $sym_ar, $exp, $dep) = @_;
225
226         my $ksymtab = grep m/ ${symprefix}__ksymtab/, @$sym_ar;
227
228     # gather the exported symbols
229         if($ksymtab){
230         # explicitly exported
231         foreach ( @$sym_ar ) {
232             / ${symprefix}__ksymtab_(.*)$/ and do {
233                 my $sym = ${symprefix} . $1;
234                 warn "sym = $sym\n" if $verbose;
235                 $exp->{$sym} = $name;
236             };
237         }
238         } else {
239         # exporting all symbols
240         foreach ( @$sym_ar ) {
241             / [ABCDGRSTW] (.*)$/ and do {
242                 warn "syma = $1\n" if $verbose;
243                 $exp->{$1} = $name;
244             };
245         }
246         }
247
248     # this takes makes sure modules with no dependencies get listed
249     push @{$dep->{$name}}, $symprefix . 'printk' unless $name eq 'vmlinux';
250
251     # gather the unresolved symbols
252     foreach ( @$sym_ar ) {
253         !/ ${symprefix}__this_module/ && / U (.*)$/ and do {
254             warn "und = $1\n" if $verbose;
255             push @{$dep->{$name}}, $1;
256         };
257     }
258 }
259
260 sub bydep
261 {
262     foreach my $f ( keys %{$mod->{$b}} ) {
263         if($f eq $a) {
264             return 1;
265         }
266     }
267     return -1;
268 }
269
270
271
272 __END__
273
274 =head1 NAME
275
276 depmod.pl - a cross platform script to generate kernel module
277 dependency lists (modules.conf) which can then be used by modprobe
278 on the target platform.
279
280 It supports Linux 2.4 and 2.6 styles of modules.conf (auto-detected)
281
282 =head1 SYNOPSIS
283
284 depmod.pl [OPTION]... [basedir]...
285
286 Example:
287
288         depmod.pl -F linux/System.map -b target/lib/modules/2.6.11
289
290 =head1 DESCRIPTION
291
292 The purpose of this script is to automagically generate a list of of kernel
293 module dependencies.  This script produces dependency lists that should be
294 identical to the depmod program from the modutils package.  Unlike the depmod
295 binary, however, depmod.pl is designed to be run on your host system, not
296 on your target system.
297
298 This script was written by David Schleef <ds@schleef.org> to be used in
299 conjunction with the BusyBox modprobe applet.
300
301 =head1 OPTIONS
302
303 =over 4
304
305 =item B<-h --help>
306
307 This displays the help message.
308
309 =item B<-b --basedir>
310
311 The base directory uner which the target's modules will be found.  This
312 defaults to the /lib/modules directory.
313
314 If you don't specify the kernel version, this script will search for
315 one under the specified based directory and use the first thing that
316 looks like a kernel version.
317
318 =item B<-k --kernel>
319
320 Kernel binary for the target (vmlinux).  You must either supply a kernel binary
321 or a kernel symbol file (using the -F option).
322
323 =item B<-F --kernelsyms>
324
325 Kernel symbol file for the target (System.map).
326
327 =item B<-n --stdout>
328
329 Write to stdout instead of modules.dep
330 kernel binary for the target (using the -k option).
331
332 =item B<--verbose>
333
334 Verbose (debug) output
335
336 =back
337
338 =head1 COPYRIGHT AND LICENSE
339
340  Copyright (c) 2001 David Schleef <ds@schleef.org>
341  Copyright (c) 2001 Erik Andersen <andersen@codepoet.org>
342  Copyright (c) 2001 Stuart Hughes <seh@zee2.com>
343  Copyright (c) 2002 Steven J. Hill <shill@broadcom.com>
344  Copyright (c) 2006 Freescale Semiconductor, Inc <stuarth@freescale.com>
345
346 This program is free software; you can redistribute it and/or modify it
347 under the same terms as Perl itself.
348
349 =head1 AUTHOR
350
351 David Schleef <ds@schleef.org>
352
353 =cut