busybox/examples/depmod.pl
<<
>>
Prefs
   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