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. 16use Getopt::Long qw(:config no_auto_abbrev no_ignore_case); 17use File::Find; 18use strict; 19 20# Set up some default values 21my $kdir=""; 22my $basedir=""; 23my $kernel=""; 24my $kernelsyms=""; 25my $symprefix=""; 26my $all=0; 27my $quick=0; 28my $errsyms=0; 29my $stdout=0; 30my $verbose=0; 31my $help=0; 32my $nm = $ENV{'NM'} || "nm"; 33 34# more globals 35my (@liblist) = (); 36my $exp = {}; 37my $dep = {}; 38my $mod = {}; 39 40my $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 52TXT 53 54# get command-line options 55GetOptions( 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 72die $usage if $help; 73die $usage unless $basedir && ( $kernel || $kernelsyms ); 74die "can't use both -k and -F\n\n$usage" if $kernel && $kernelsyms; 75die "sorry, -A/--quick is not supported" if $quick; 76die "--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 82if($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 87if($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 105warn "**** Locating all modules\n" if $verbose; 106find 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; 116warn "**** Finished locating modules\n" if $verbose; 117 118foreach 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 132my $tgtname = 'vmlinux'; 133my @output = $kernelsyms ? `cat $kernelsyms` : `$nm $kernel`; 134warn "\nMODULE = $tgtname\n" if $verbose; 135build_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 140foreach 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 156my $mod2 = {}; 157sub 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} 170sub 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} 190foreach 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 197if ($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} 202my $kseries = $basedir =~ m,/2\.4\.[^/]*, ? '2.4' : 'others'; 203 204foreach 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 222sub 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 260sub 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 276depmod.pl - a cross platform script to generate kernel module 277dependency lists (modules.conf) which can then be used by modprobe 278on the target platform. 279 280It supports Linux 2.4 and 2.6 styles of modules.conf (auto-detected) 281 282=head1 SYNOPSIS 283 284depmod.pl [OPTION]... [basedir]... 285 286Example: 287 288 depmod.pl -F linux/System.map -b target/lib/modules/2.6.11 289 290=head1 DESCRIPTION 291 292The purpose of this script is to automagically generate a list of of kernel 293module dependencies. This script produces dependency lists that should be 294identical to the depmod program from the modutils package. Unlike the depmod 295binary, however, depmod.pl is designed to be run on your host system, not 296on your target system. 297 298This script was written by David Schleef <ds@schleef.org> to be used in 299conjunction with the BusyBox modprobe applet. 300 301=head1 OPTIONS 302 303=over 4 304 305=item B<-h --help> 306 307This displays the help message. 308 309=item B<-b --basedir> 310 311The base directory uner which the target's modules will be found. This 312defaults to the /lib/modules directory. 313 314If you don't specify the kernel version, this script will search for 315one under the specified based directory and use the first thing that 316looks like a kernel version. 317 318=item B<-k --kernel> 319 320Kernel binary for the target (vmlinux). You must either supply a kernel binary 321or a kernel symbol file (using the -F option). 322 323=item B<-F --kernelsyms> 324 325Kernel symbol file for the target (System.map). 326 327=item B<-n --stdout> 328 329Write to stdout instead of modules.dep 330kernel binary for the target (using the -k option). 331 332=item B<--verbose> 333 334Verbose (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 346This program is free software; you can redistribute it and/or modify it 347under the same terms as Perl itself. 348 349=head1 AUTHOR 350 351David Schleef <ds@schleef.org> 352 353=cut 354