#!/usr/bin/perl # # Emulation of the linux 'ldd' on IRIX # Ariel Faigon # # Linux output example # % ldd /usr/local/netscape/netscape # libBrokenLocale.so.1 => /lib/libBrokenLocale.so.1 (0x40010000) # libXt.so.6 => /usr/X11R6/lib/libXt.so.6 (0x40012000) # libSM.so.6 => /usr/X11R6/lib/libSM.so.6 (0x4005a000) # libICE.so.6 => /usr/X11R6/lib/libICE.so.6 (0x40065000) # libXmu.so.6 => /usr/X11R6/lib/libXmu.so.6 (0x4007a000) # libXpm.so.4 => /usr/X11R6/lib/libXpm.so.4 (0x4008c000) # libXext.so.6 => /usr/X11R6/lib/libXext.so.6 (0x4009a000) # libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0x400a6000) # libdl.so.2 => /lib/libdl.so.2 (0x4014a000) # libc.so.6 => /lib/libc.so.6 (0x4014d000) # libg++.so.2.7.2 => /usr/lib/libg++.so.2.7.2 (0x401f2000) # libstdc++.so.2.7.2 => /usr/lib/libstdc++.so.2.7.2 (0x4022a000) # libm.so.6 => /lib/libm.so.6 (0x40267000) # /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) # # From the IRIX 'man dso' # # 11) Where does the system look for shared objects at runtime? # # The search path for shared objects is acquired in the following # order for the old 32bit ABI: # # 1) the path of the shared object if given in the liblist, # # 2) in any directories specified via the -rpath flag when the # executable was built # # 3) in any directory specified by the LD_LIBRARY_PATH environment # variable, if it is defined # # 4) in the directories in the default path # (/usr/lib:/lib:/lib/cc:/usr/lib/cc) # # If the _RLD_ROOT environment variable is defined, then its value is # appended to the front of any path specified by -rpath and the default # path. _RLD_ROOT itself is also a colon(:) separated list. # # For the new 32bit ABI the rules are similar, but the following # differences exist: 1) the LD_LIBRARYN32_PATH is used if defined, # otherwise LD_LIBRARY_PATH is used 2) _RLDN32_ROOT is used for the # list of paths 3) The default path list is (/usr/lib32:/lib32). # # For the 64bit ABI the rules are similar, but the following differences # exist: 1) The LD_LIBRARY64_PATH is used if defined, otherwise # LD_LIBRARY_PATH is used 2) _RLD64_ROOT is used for the list of paths # 3) The default path list is (/usr/lib64:/lib64). # # See the rld(1) manpage for details. # Also note: _RLD_LIST _RLDN32_LIST _RLD64_LIST # use Getopt::Std; $ELFdump = '/bin/elfdump'; %rld_list_vars = ( 'o32' => '_RLD_LIST', 'n32' => '_RLDN32_LIST', 'n64' => '_RLD64_LIST', ); %rld_root_vars = ( 'o32' => '_RLD_ROOT', 'n32' => '_RLDN32_ROOT', 'n64' => '_RLD64_ROOT', ); %ld_library_path_vars = ( 'o32' => 'LD_LIBRARY_PATH', 'n32' => 'LD_LIBRARYN32_PATH', 'n64' => 'LD_LIBRARY64_PATH', ); %default_rpath = ( 'o32' => [ '/usr/lib', '/lib', '/lib/cc', '/usr/lib/cc' ], 'n32' => [ '/usr/lib32', '/lib32' ], 'n64' => [ '/usr/lib64', '/lib64' ], ); sub rld_roots($) { my ($ev, $val, @roots); $ev = $rld_root_vars{$abi}; if ($val = $ENV{$ev}) { warn "$0: $ev='$val': affects the search path. See 'man dso'.\n"; foreach $dir (split(':', $val)) { if (-d $dir) { push(@roots, $dir); } else { warn "\t$0 warning: $ev: $dir: no such dir.\n\n"; } } } @roots; } sub env_paths($$) { my ($abi, $arch) = @_; my ($oev, $ev, $oval, $val, @rpath, @tmp, $dir); $ev = $rld_list_vars{$abi}; if ($val = $ENV{$ev}) { warn "$0: $ev='$val': affects the search path. See 'man dso'.\n"; @tmp = split(':', $val); } $ev = $ld_library_path_vars{$abi}; if ($val = $ENV{$ev}) { warn "$0: $ev='$val': affects the search path. See 'man dso'.\n"; push(@tmp, split(':', $val)); } # # special cases: # $oev = 'LD_LIBRARY_PATH'; $ev = $ld_library_path_vars{$abi}; if ($abi ne 'o32' && $ENV{$oev} && ! $ENV{$ev}) { $oval = $ENV{$oev}; $val = $ENV{$ev}; warn "\t$0 warning: $abi executable run with:\n", "\t\t$oev='$oval'\n", "\t\t$ev=(undef)\n", "\tThis is probably *not* what you want. See 'man dso'.\n\n"; push(@tmp, $val); } for $dir (@tmp) { if (-d $dir) { if (-d "$dir/$arch") { push(@rpath, "$dir/$arch"); } push(@rpath, $dir); } else { warn "\t$0 warning: $dir: no such dir.\n\n"; } } @rpath; } sub abi_arch($) { my ($file) = @_; my ($abi, $arch, $fileo); $fileo = `/bin/file $file`; $fileo =~ s,^[^:]+:\s*,,; chop($fileo); die "$0: $file is not an ELF object file ($fileo)\n" if ($fileo !~ /^ELF/); $abi = ($fileo =~ /N32/) ? 'n32' : ($fileo =~ /64/) ? 'n64' : 'o32'; ($arch) = ($fileo =~ /(mips-\d+)/); $arch =~ tr,-,,d; ($abi, $arch, $fileo); } sub lib_list($) { my ($file) = @_; my (@liblist, $lib); open(ED, "$ELFdump -Dl $file |"); while () { next unless (/^\[\d+\]/); $lib = (split(" ", $_))[7]; push(@liblist, $lib); } warn "\tliblist:\t@liblist\n" if ($opt_v); close(ED); @liblist; } sub file_rpath($$$@) { my ($file, $abi, $arch, @roots) = @_; my (@rpath, $rpath, $path, @paths, $dir); # elfdump -L /usr/freeware/bin/perl | grep RPATH # [29] RPATH /usr/freeware/lib/perl5/5.00502/irix-n32/CORE @roots = ('') unless (@roots); open(ED, "$ELFdump -L $file |"); while () { # warn "file_rpath $_"; next unless (/^\[\d+\]\s+RPATH\s+/); chop($rpath = $'); # warn "file_rpath $rpath\n"; @paths = split(':', $rpath); foreach $root (@roots) { for $path (@paths) { if (-d "$root$path/$arch") { push (@rpath, "$root$path/$arch"); } if (-d "$root$path") { push (@rpath, "$root$path"); } else { warn "\t$0 warning: $root$path: no such dir.\n\n"; } } } } close(ED); # warn "file_rpath returns: @rpath\n"; @rpath; } sub default_rpath($$@) { my ($abi, $arch, @roots) = @_; my (@rpath, $root, $path); @roots = ('') unless (@roots); foreach $root (@roots) { foreach $path (@{$default_rpath{$abi}}) { if (-d "$root$path/$arch") { push (@rpath, "$root$path/$arch"); } if (-d "$root$path") { push (@rpath, "$root$path"); } } } @rpath; } sub ldd($$) { my ($pathlist_ref, $liblist_ref) = @_; my ($lib, $dir, $fullpath); die "$0 requires $ELFdump which is missing from your system\n" unless (-x $ELFdump); LIB: foreach $lib (@$liblist_ref) { next unless ($lib); printf "\t%s => ", $lib; foreach $dir (@$pathlist_ref) { next unless ($dir); $fullpath = "$dir/$lib"; if (-e $fullpath) { print "$fullpath\n"; next LIB; } } print "[not found!]\n"; } } sub do_file($) { my ($file) = @_; my ($abi, $arch, $type, @roots, @env_paths, @liblist, @search_path, @file_rpath); warn "$file:\n" if ($opt_v); ($abi, $arch, $type) = abi_arch($file); warn "\tfile-type:\t$type\n" if ($opt_v); warn "\tabi/arch:\t$abi/$arch\n" if ($opt_v); @liblist = lib_list($file); @roots = rld_roots($abi); @env_paths = env_paths($abi, $arch); @file_rpath = file_rpath($file, $abi, $arch, @roots); push (@search_path, @env_paths) unless (-u $file); push (@search_path, @file_rpath); push (@search_path, default_rpath($abi, $arch, @roots)); warn "\trpath:\t\t@file_rpath\n" if (@file_rpath && $opt_v); warn "\tsearch-path:\t@search_path\n\n" if ($opt_v); ldd(\@search_path, \@liblist); } # --- main --- $0 =~ s,.*/,,; getopts('v') || die "Usage: $0 [-v] object-file\n"; $ARGV[0] || die "Usage: $0 [-v] object-file\n"; (-e $ARGV[0]) || die "$0: $ARGV[0]: $!\n"; do_file($ARGV[0]); __END__