1 #!/usr/perl5/bin/perl -w
5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
24 # Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
25 # Copyright 2014 Garrett D'Amore <garrett@damore.org>
29 # Check ELF information.
31 # This script descends a directory hierarchy inspecting ELF dynamic executables
32 # and shared objects. The general theme is to verify that common Makefile rules
33 # have been used to build these objects. Typical failures occur when Makefile
34 # rules are re-invented rather than being inherited from "cmd/lib" Makefiles.
36 # As always, a number of components don't follow the rules, and these are
37 # excluded to reduce this scripts output.
39 # By default any file that has conditions that should be reported is first
40 # listed and then each condition follows. The -o (one-line) option produces a
41 # more terse output which is better for sorting/diffing with "nightly".
43 # NOTE: missing dependencies, symbols or versions are reported by running the
44 # file through ldd(1). As objects within a proto area are built to exist in a
45 # base system, standard use of ldd(1) will bind any objects to dependencies
46 # that exist in the base system. It is frequently the case that newer objects
47 # exist in the proto area that are required to satisfy other objects
48 # dependencies, and without using these newer objects an ldd(1) will produce
49 # misleading error messages. To compensate for this, the -D/-d options, or the
50 # existence of the CODEMSG_WS/ROOT environment variables, cause the creation of
51 # alternative dependency mappings via crle(1) configuration files that establish
52 # any proto shared objects as alternatives to their base system location. Thus
53 # ldd(1) can be executed against these configuration files so that objects in a
54 # proto area bind to their dependencies in the same proto area.
57 # Define all global variables (required for strict)
58 use vars
qw($Prog $Env $Ena64 $Tmpdir);
59 use vars qw($LddNoU $Conf32 $Conf64);
61 use vars qw($ErrFH $ErrTtl $InfoFH $InfoTtl $OutCnt1 $OutCnt2);
63 # An exception file is used to specify regular expressions to match
64 # objects. These directives specify special attributes of the object.
65 # The regular expressions are read from the file and compiled into the
66 # regular expression variables.
68 # The name of each regular expression variable is of the form
72 # where xxx is the name of the exception in lower case. For example,
73 # the regular expression variable for EXEC_STACK is $EXRE_exec_stack.
75 # onbld_elfmod::LoadExceptionsToEXRE() depends on this naming convention
76 # to initialize the regular expression variables, and to detect invalid
79 # If a given exception is not used in the exception file, its regular
80 # expression variable will be undefined. Users of these variables must
81 # test the variable with defined() prior to use:
83 # defined($EXRE_exec_stack) && ($foo =~ $EXRE_exec_stack)
85 # or if the test is to make sure the item is not specified:
87 # !defined($EXRE_exec_stack) || ($foo !~ $EXRE_exec_stack)
94 # Objects that are not required to have non-executable writable
98 # Objects that are not required to have a non-executable stack
101 # Objects allowed to link to 'forbidden' objects
104 # Objects to which nobody not excepted with FORBIDDEN_DEP may link
107 # Objects that should be skipped by AltObjectConfig() when building
108 # the crle script that maps objects to the proto area.
111 # Objects that are not required to use direct bindings
114 # Objects we should not check for duplicate addresses in
115 # the symbol sort sections.
118 # Objects that are no longer needed because their functionalty
119 # has migrated elsewhere. These are usually pure filters that
123 # Files and directories that should be excluded from analysis.
126 # Objects that are allowed to contain stab debugging sections
129 # Object for which relocations are allowed to the text segment
132 # Objects that are allowed undefined references
135 # "unreferenced object=" ldd(1) diagnostics.
138 # Objects that are allowed to have unused dependencies
141 # Objects that are allowed to be unused dependencies
144 # Objects with unused runpaths
147 use vars qw($EXRE_exec_data $EXRE_exec_stack $EXRE_nocrlealt);
148 use vars qw($EXRE_nodirect $EXRE_nosymsort $EXRE_forbidden_dep $EXRE_forbidden);
149 use vars qw($EXRE_olddep $EXRE_skip $EXRE_stab $EXRE_textrel $EXRE_undef_ref);
150 use vars qw($EXRE_unref_obj $EXRE_unused_deps $EXRE_unused_obj);
151 use vars qw($EXRE_unused_rpath);
158 # Reliably compare two OS revisions. Arguments are <ver1> <op> <ver2>.
159 # <op> is the string form of a normal numeric comparison operator.
161 my @ver1 = split(/\./, $_[0]);
163 my @ver2 = split(/\./, $_[2]);
165 push @ver2, ("0") x $#ver1 - $#ver2;
166 push @ver1, ("0") x $#ver2 - $#ver1;
169 while (@ver1 || @ver2) {
170 if (($diff = shift(@ver1) - shift(@ver2)) != 0) {
174 return (eval "$diff $op 0" ? 1 : 0);
177 ## ProcFile(FullPath, RelPath, File, Class, Type, Verdef)
179 # Determine whether this a ELF dynamic object and if so investigate its runtime
183 my($FullPath, $RelPath, $Class, $Type, $Verdef) = @_;
184 my(@Elf, @Ldd, $Dyn, $Sym, $ExecStack);
185 my($Sun, $Relsz, $Pltsz, $Tex, $Stab, $Strip, $Lddopt, $SymSort);
186 my($Val, $Header, $IsX86, $RWX, $UnDep);
187 my($HasDirectBinding);
189 # Only look at executables and sharable objects
190 return if ($Type ne 'EXEC') && ($Type ne 'DYN') && ($Type ne 'PIE');
192 # Ignore symbolic links
193 return if -l $FullPath;
195 # Is this an object or directory hierarchy we don't care about?
196 return if (defined($EXRE_skip) && ($RelPath =~ $EXRE_skip));
198 # Bail if we can't stat the file. Otherwise, note if it is SUID/SGID.
199 return if !stat($FullPath);
200 my $Secure = (-u _ || -g _) ? 1 : 0;
202 # Reset output message counts for new input file
203 $$ErrTtl = $$InfoTtl = 0;
207 # Determine whether we have access to inspect the file.
208 if (!(-r $FullPath)) {
209 onbld_elfmod::OutMsg($ErrFH, $ErrTtl, $RelPath,
210 "unable to inspect file: permission denied");
214 # Determine whether we have a executable (static or dynamic) or a
216 @Elf = split(/\n/, `elfdump -epdcy $FullPath 2>&1`);
218 $Dyn = $ExecStack = $IsX86 = $RWX = 0;
220 foreach my $Line (@Elf) {
221 # If we have an invalid file type (which we can tell from the
222 # first line), or we're processing an archive, bail.
223 if ($Header eq 'None') {
224 if (($Line =~ /invalid file/) ||
225 ($Line =~ /\Q$FullPath\E(.*):/)) {
230 if ($Line =~ /^ELF Header/) {
235 if ($Line =~ /^Program Header/) {
241 if ($Line =~ /^Dynamic Section/) {
242 # A dynamic section indicates we're a dynamic object
243 # (this makes sure we don't check static executables).
248 if (($Header eq 'Ehdr') && ($Line =~ /e_machine:/)) {
249 # If it's a X86 object, we need to enforce RW- data.
250 $IsX86 = 1 if $Line =~ /(EM_AMD64|EM_386)/;
254 if (($Header eq 'Phdr') &&
255 ($Line =~ /\[ PF_X\s+PF_W\s+PF_R \]/)) {
261 if (($Header eq 'Phdr') &&
262 ($Line =~ /\[ PT_LOAD \]/ && $RWX && $IsX86)) {
263 # Seen an RWX PT_LOAD segment.
264 if (!defined($EXRE_exec_data) ||
265 ($RelPath !~ $EXRE_exec_data)) {
266 onbld_elfmod::OutMsg($ErrFH, $ErrTtl, $RelPath,
267 "application requires non-executable " .
268 "data\t<remove -Mmapfile_execdata?>");
273 if (($Header eq 'Phdr') && $RWX == 1 &&
274 ($Line =~ /\[ PT_SUNWSTACK \]/)) {
275 # This object defines an executable stack.
281 # Applications should not contain an executable stack definition.
282 if (($Type eq 'EXEC') && ($ExecStack == 1) &&
283 (!defined($EXRE_exec_stack) || ($RelPath !~ $EXRE_exec_stack))) {
284 onbld_elfmod::OutMsg($ErrFH, $ErrTtl, $RelPath,
285 "non-executable stack required\t<remove -Mmapfile_execstack?>");
288 # Having caught any static executables in the mcs(1) check and non-
289 # executable stack definition check, continue with dynamic objects
295 # Use ldd unless its a 64-bit object and we lack the hardware.
296 if (($Class == 32) || $Ena64) {
297 my $LDDFullPath = $FullPath;
300 # The execution of a secure application over an nfs file
301 # system mounted nosuid will result in warning messages
302 # being sent to /var/log/messages. As this type of
303 # environment can occur with root builds, move the file
304 # being investigated to a safe place first. In addition
305 # remove its secure permission so that it can be
306 # influenced by any alternative dependency mappings.
309 $File =~ s!^.*/!!; # basename
311 my($TmpPath) = "$Tmpdir/$File";
313 system('cp', $LDDFullPath, $TmpPath);
314 chmod 0777, $TmpPath;
315 $LDDFullPath = $TmpPath;
318 # Use ldd(1) to determine the objects relocatability and use.
319 # By default look for all unreferenced dependencies. However,
320 # some objects have legitimate dependencies that they do not
327 @Ldd = split(/\n/, `ldd $Lddopt $Env $LDDFullPath 2>&1`);
337 foreach my $Line (@Ldd) {
341 # Make sure ldd(1) worked. One possible failure is that
342 # this is an old ldd(1) prior to -e addition (4390308).
343 if ($Line =~ /usage:/) {
344 $Line =~ s/$/\t<old ldd(1)?>/;
345 onbld_elfmod::OutMsg($ErrFH, $ErrTtl,
348 } elsif ($Line =~ /execution failed/) {
349 onbld_elfmod::OutMsg($ErrFH, $ErrTtl,
354 # It's possible this binary can't be executed, ie. we've
355 # found a sparc binary while running on an intel system,
356 # or a sparcv9 binary on a sparcv7/8 system.
357 if ($Line =~ /wrong class/) {
358 onbld_elfmod::OutMsg($ErrFH, $ErrTtl, $RelPath,
359 "has wrong class or data encoding");
363 # Historically, ldd(1) likes executable objects to have
364 # their execute bit set.
365 if ($Line =~ /not executable/) {
366 onbld_elfmod::OutMsg($ErrFH, $ErrTtl, $RelPath,
367 "is not executable");
372 # Look for "file" or "versions" that aren't found. Note that
373 # these lines will occur before we find any symbol referencing
375 if (($Sym == 5) && ($Line =~ /not found\)/)) {
376 if ($Line =~ /file not found\)/) {
377 $Line =~ s/$/\t<no -zdefs?>/;
379 onbld_elfmod::OutMsg($ErrFH, $ErrTtl, $RelPath, $Line);
382 # Look for relocations whose symbols can't be found. Note, we
383 # only print out the first 5 relocations for any file as this
384 # output can be excessive.
385 if ($Sym && ($Line =~ /symbol not found/)) {
386 # Determine if this file is allowed undefined
388 if (($Sym == 5) && defined($EXRE_undef_ref) &&
389 ($RelPath =~ $EXRE_undef_ref)) {
394 onbld_elfmod::OutMsg($ErrFH, $ErrTtl, $RelPath,
395 "continued ...") if !$opt{o};
398 # Just print the symbol name.
399 $Line =~ s/$/\t<no -zdefs?>/;
400 onbld_elfmod::OutMsg($ErrFH, $ErrTtl, $RelPath, $Line);
403 # Look for any unused search paths.
404 if ($Line =~ /unused search path=/) {
405 next if defined($EXRE_unused_rpath) &&
406 ($Line =~ $EXRE_unused_rpath);
409 $Line =~ s!$Tmpdir/!!;
411 $Line =~ s/^[ \t]*(.*)/\t$1\t<remove search path?>/;
412 onbld_elfmod::OutMsg($ErrFH, $ErrTtl, $RelPath, $Line);
416 # Look for unreferenced dependencies. Note, if any unreferenced
417 # objects are ignored, then set $UnDep so as to suppress any
418 # associated unused-object messages.
419 if ($Line =~ /unreferenced object=/) {
420 if (defined($EXRE_unref_obj) &&
421 ($Line =~ $EXRE_unref_obj)) {
426 $Line =~ s!$Tmpdir/!!;
428 $Line =~ s/^[ \t]*(.*)/$1\t<remove lib or -zignore?>/;
429 onbld_elfmod::OutMsg($ErrFH, $ErrTtl, $RelPath, $Line);
432 # Look for any unused dependencies.
433 if ($UnDep && ($Line =~ /unused/)) {
434 # Skip if object is allowed to have unused dependencies
435 next if defined($EXRE_unused_deps) &&
436 ($RelPath =~ $EXRE_unused_deps);
438 # Skip if dependency is always allowed to be unused
439 next if defined($EXRE_unused_obj) &&
440 ($Line =~ $EXRE_unused_obj);
442 $Line =~ s!$Tmpdir/!! if $Secure;
443 $Line =~ s/^[ \t]*(.*)/$1\t<remove lib or -zignore?>/;
444 onbld_elfmod::OutMsg($ErrFH, $ErrTtl, $RelPath, $Line);
449 # Reuse the elfdump(1) data to investigate additional dynamic linking
452 $Sun = $Relsz = $Pltsz = $Dyn = $Stab = $SymSort = 0;
454 $HasDirectBinding = 0;
457 ELF: foreach my $Line (@Elf) {
458 # We're only interested in the section headers and the dynamic
460 if ($Line =~ /^Section Header/) {
463 if (($Sun == 0) && ($Line =~ /\.SUNW_reloc/)) {
464 # This object has a combined relocation section.
467 } elsif (($Stab == 0) && ($Line =~ /\.stab/)) {
468 # This object contain .stabs sections
470 } elsif (($SymSort == 0) &&
471 ($Line =~ /\.SUNW_dyn(sym)|(tls)sort/)) {
472 # This object contains a symbol sort section
476 if (($Strip == 1) && ($Line =~ /\.symtab/)) {
477 # This object contains a complete symbol table.
482 } elsif ($Line =~ /^Dynamic Section/) {
485 } elsif ($Line =~ /^Syminfo Section/) {
488 } elsif (($Header ne 'Dyn') && ($Header ne 'Syminfo')) {
492 # Look into the Syminfo section.
493 # Does this object have at least one Directly Bound symbol?
494 if (($Header eq 'Syminfo')) {
497 if ($HasDirectBinding == 1) {
501 @Symword = split(' ', $Line);
503 if (!defined($Symword[1])) {
506 if ($Symword[1] =~ /B/) {
507 $HasDirectBinding = 1;
512 # Does this object contain text relocations.
513 if ($Tex && ($Line =~ /TEXTREL/)) {
514 # Determine if this file is allowed text relocations.
515 if (defined($EXRE_textrel) &&
516 ($RelPath =~ $EXRE_textrel)) {
520 onbld_elfmod::OutMsg($ErrFH, $ErrTtl, $RelPath,
521 "TEXTREL .dynamic tag\t\t\t<no -Kpic?>");
526 # Does this file have any relocation sections (there are a few
527 # psr libraries with no relocations at all, thus a .SUNW_reloc
528 # section won't exist either).
529 if (($Relsz == 0) && ($Line =~ / RELA?SZ/)) {
530 $Relsz = hex((split(' ', $Line))[2]);
534 # Does this file have any plt relocations. If the plt size is
535 # equivalent to the total relocation size then we don't have
536 # any relocations suitable for combining into a .SUNW_reloc
538 if (($Pltsz == 0) && ($Line =~ / PLTRELSZ/)) {
539 $Pltsz = hex((split(' ', $Line))[2]);
543 # Does this object have any dependencies.
544 if ($Line =~ /NEEDED/) {
545 my($Need) = (split(' ', $Line))[3];
547 if (defined($EXRE_olddep) && ($Need =~ $EXRE_olddep)) {
548 # Catch any old (unnecessary) dependencies.
549 onbld_elfmod::OutMsg($ErrFH, $ErrTtl, $RelPath,
550 "NEEDED=$Need\t<dependency no " .
551 "longer necessary>");
552 } elsif ((defined($EXRE_forbidden) &&
553 ($Need =~ $EXRE_forbidden)) &&
554 (!defined($EXRE_forbidden_dep) ||
555 ($FullPath !~ $EXRE_forbidden_dep))) {
556 onbld_elfmod::OutMsg($ErrFH, $ErrTtl, $RelPath,
557 "NEEDED=$Need\t<forbidden dependency, " .
558 "missing -nodefaultlibs?>");
560 # Under the -i (information) option print out
561 # any useful dynamic entries.
562 onbld_elfmod::OutMsg($InfoFH, $InfoTtl, $RelPath,
568 # Is this object built with -B direct flag on?
569 if ($Line =~ / DIRECT /) {
570 $HasDirectBinding = 1;
573 # Does this object specify a runpath.
574 if ($opt{i} && ($Line =~ /RPATH/)) {
575 my($Rpath) = (split(' ', $Line))[3];
576 onbld_elfmod::OutMsg($InfoFH, $InfoTtl,
577 $RelPath, "RPATH=$Rpath");
582 # No objects released to a customer should have any .stabs sections
583 # remaining, they should be stripped.
584 if ($opt{s} && $Stab) {
585 goto DONESTAB if defined($EXRE_stab) && ($RelPath =~ $EXRE_stab);
587 onbld_elfmod::OutMsg($ErrFH, $ErrTtl, $RelPath,
588 "debugging sections should be deleted\t<no strip -x?>");
593 # All objects should have a full symbol table to provide complete
594 # debugging stack traces.
595 onbld_elfmod::OutMsg($ErrFH, $ErrTtl, $RelPath,
596 "symbol table should not be stripped\t<remove -s?>") if $Strip;
598 # If there are symbol sort sections in this object, report on
599 # any that have duplicate addresses.
600 ProcSymSort($FullPath, $RelPath) if $SymSort;
602 # If -v was specified, and the object has a version definition
603 # section, generate output showing each public symbol and the
604 # version it belongs to.
605 ProcVerdef($FullPath, $RelPath)
606 if ($Verdef eq 'VERDEF') && $opt{v};
610 ## ProcSymSortOutMsg(RelPath, secname, addr, names...)
612 # Call onbld_elfmod::OutMsg for a duplicate address error in a symbol sort
615 sub ProcSymSortOutMsg {
616 my($RelPath, $secname, $addr, @names) = @_;
618 onbld_elfmod::OutMsg($ErrFH, $ErrTtl, $RelPath,
619 "$secname: duplicate $addr: ". join(', ', @names));
623 ## ProcSymSort(FullPath, RelPath)
625 # Examine the symbol sort sections for the given object and report
626 # on any duplicate addresses found. Ideally, mapfile directives
627 # should be used when building objects that have multiple symbols
628 # with the same address so that only one of them appears in the sort
629 # section. This saves space, reduces user confusion, and ensures that
630 # libproc and debuggers always display public names instead of symbols
631 # that are merely implementation details.
635 my($FullPath, $RelPath) = @_;
637 # If this object is exempt from checking, return quietly
638 return if defined($EXRE_nosymsort) && ($FullPath =~ $EXRE_nosymsort);
641 open(SORT, "elfdump -S $FullPath|") ||
642 die "$Prog: Unable to execute elfdump (symbol sort sections)\n";
648 while ($line = <SORT>) {
651 next if ($line eq '');
653 # If this is a header line, pick up the section name
654 if ($line =~ /^Symbol Sort Section:\s+([^\s]+)\s+/) {
657 # Every new section is followed by a column header line
658 $line = <SORT>; # Toss header line
660 # Flush anything left from previous section
661 ProcSymSortOutMsg($RelPath, $secname, $last_addr, @dups)
662 if (scalar(@dups) > 1);
664 # Reset variables for new sort section
671 # Process symbol line
672 my @fields = split /\s+/, $line;
673 my $new_addr = $fields[2];
674 my $new_type = $fields[8];
675 my $new_name = $fields[9];
677 if ($new_type eq 'UNDEF') {
678 onbld_elfmod::OutMsg($ErrFH, $ErrTtl, $RelPath,
679 "$secname: unexpected UNDEF symbol " .
680 "(link-editor error): $new_name");
684 if ($new_addr eq $last_addr) {
685 push @dups, $new_name;
687 ProcSymSortOutMsg($RelPath, $secname,
688 $last_addr, @dups) if (scalar(@dups) > 1);
689 @dups = ( $new_name );
690 $last_addr = $new_addr;
694 ProcSymSortOutMsg($RelPath, $secname, $last_addr, @dups)
695 if (scalar(@dups) > 1);
701 ## ProcVerdef(FullPath, RelPath)
703 # Examine the version definition section for the given object and report
704 # each public symbol along with the version it belongs to.
708 my($FullPath, $RelPath) = @_;
711 my $tab = $opt{o} ? '' : "\t";
713 # pvs -dov provides information about the versioning hierarchy
714 # in the file. Lines are of the format:
715 # path - version[XXX];
716 # where [XXX] indicates optional information, such as flags
717 # or inherited versions.
719 # Private versions are allowed to change freely, so ignore them.
720 open(PVS, "pvs -dov $FullPath|") ||
721 die "$Prog: Unable to execute pvs (version definition section)\n";
723 while ($line = <PVS>) {
726 if ($line =~ /^[^\s]+\s+-\s+([^;]+)/) {
729 next if $ver =~ /private/i;
730 onbld_elfmod::OutMsg($InfoFH, $InfoTtl, $RelPath,
731 "${tab}VERDEF=$ver");
736 # pvs -dos lists the symbols assigned to each version definition.
737 # Lines are of the format:
738 # path - version: symbol;
739 # path - version: symbol (size);
740 # where the (size) is added to data items, but not for functions.
741 # We strip off the size, if present.
743 open(PVS, "pvs -dos $FullPath|") ||
744 die "$Prog: Unable to execute pvs (version definition section)\n";
745 while ($line = <PVS>) {
747 if ($line =~ /^[^\s]+\s+-\s+([^:]+):\s*([^\s;]+)/) {
751 next if $ver =~ /private/i;
754 onbld_elfmod::OutMsg($InfoFH, $InfoTtl, $RelPath,
755 "VERSION=$ver, SYMBOL=$sym");
757 if ($cur_ver ne $ver) {
758 onbld_elfmod::OutMsg($InfoFH, $InfoTtl,
759 $RelPath, "VERSION=$ver");
762 onbld_elfmod::OutMsg($InfoFH, $InfoTtl,
763 $RelPath, "SYMBOL=$sym");
772 ## OpenFindElf(file, FileHandleRef, LineNumRef)
774 # Open file in 'find_elf -r' format, and return the value of
775 # the opening PREFIX line.
778 # file - file, or find_elf child process, to open
779 # FileHandleRef - Reference to file handle to open
780 # LineNumRef - Reference to integer to increment as lines are input
783 # This routine issues a fatal error and does not return on error.
784 # Otherwise, the value of PREFIX is returned.
787 my ($file, $fh, $LineNum) = @_;
791 open($fh, $file) || die "$Prog: Unable to open: $file";
794 # This script requires relative paths as created by 'find_elf -r'.
795 # When this is done, the first non-comment line will always
796 # be PREFIX. Obtain that line, or issue a fatal error.
797 while ($line = onbld_elfmod::GetLine($fh, $LineNum)) {
798 if ($line =~ /^PREFIX\s+(.*)$/i) {
803 die "$Prog: No PREFIX line seen on line $$LineNum: $file";
812 # Open the specified file, which must be produced by "find_elf -r",
813 # and process the files it describes.
820 my $prefix = OpenFindElf($file, \*FIND_ELF, \$LineNum);
822 while ($line = onbld_elfmod::GetLine(\*FIND_ELF, \$LineNum)) {
823 next if !($line =~ /^OBJECT\s/i);
825 my ($item, $class, $type, $verdef, $obj) =
826 split(/\s+/, $line, 5);
828 ProcFile("$prefix/$obj", $obj, $class, $type, $verdef);
835 ## AltObjectConfig(file)
837 # Recurse through a directory hierarchy looking for appropriate dependencies
838 # to map from their standard system locations to the proto area via a crle
842 # file - File of ELF objects, in 'find_elf -r' format, to examine.
845 # Scripts are generated for the 32 and 64-bit cases to run crle
846 # and create runtime configuration files that will establish
847 # alternative dependency mappings for the objects identified.
849 # $Env - Set to environment variable definitions that will cause
850 # the config files generated by this routine to be used
852 # $Conf32, $Conf64 - Undefined, or set to the config files generated
853 # by this routine. If defined, the caller is responsible for
854 # unlinking the files before exiting.
856 sub AltObjectConfig {
858 my ($Crle32, $Crle64);
865 my $prefix = OpenFindElf($file, \*FIND_ELF);
868 while ($line = onbld_elfmod::GetLine(\*FIND_ELF, \$LineNum)) {
871 if ($line =~ /^OBJECT\s/i) {
872 my ($item, $class, $type, $verdef, $obj) =
873 split(/\s+/, $line, 5);
875 if ($type eq 'DYN') {
880 # Only want shared libraries
886 # We need to follow links to sharable objects so
887 # that any dependencies are expressed in all their
888 # available forms. We depend on ALIAS lines directly
889 # following the object they alias, so if we have
890 # a current object, this alias belongs to it.
891 if ($obj_active && ($line =~ /^ALIAS\s/i)) {
892 my ($item, $real_obj, $obj) =
893 split(/\s+/, $line, 3);
898 # Skip unrecognized item
902 next if !$obj_active;
904 my $full = "$prefix/$obj_path";
906 next if defined($EXRE_nocrlealt) &&
907 ($obj_path =~ $EXRE_nocrlealt);
910 $Dir =~ s/^(.*)\/.*$/$1/;
912 # Create a crle(1) script for the dependency we've found.
913 # We build separate scripts for the 32 and 64-bit cases.
914 # We create and initialize each script when we encounter
915 # the first object that needs it.
916 if ($obj_class == 32) {
918 $Crle32 = "$Tmpdir/$Prog.crle32.$$";
919 open(CRLE32, "> $Crle32") ||
920 die "$Prog: open failed: $Crle32: $!";
921 print CRLE32 "#!/bin/sh\ncrle \\\n";
923 print CRLE32 "\t-o $Dir -a /$obj_path \\\n";
926 $Crle64 = "$Tmpdir/$Prog.crle64.$$";
927 open(CRLE64, "> $Crle64") ||
928 die "$Prog: open failed: $Crle64: $!";
929 print CRLE64 "#!/bin/sh\ncrle -64\\\n";
931 print CRLE64 "\t-o $Dir -a /$obj_path \\\n";
938 # Now that the config scripts are complete, use them to generate
939 # runtime linker config files.
941 $Conf64 = "$Tmpdir/$Prog.conf64.$$";
942 print CRLE64 "\t-c $Conf64\n";
947 undef $Conf64 if system($Crle64);
949 # Done with the script
953 $Conf32 = "$Tmpdir/$Prog.conf32.$$";
954 print CRLE32 "\t-c $Conf32\n";
959 undef $Conf32 if system($Crle32);
961 # Done with the script
965 # Set $Env so that we will use the config files generated above
967 if ($Crle64 && $Conf64 && $Crle32 && $Conf32) {
968 $Env = "-e LD_FLAGS=config_64=$Conf64,config_32=$Conf32";
969 } elsif ($Crle64 && $Conf64) {
970 $Env = "-e LD_FLAGS=config_64=$Conf64";
971 } elsif ($Crle32 && $Conf32) {
972 $Env = "-e LD_FLAGS=config_32=$Conf32";
976 # -----------------------------------------------------------------------------
978 # This script relies on ldd returning output reflecting only the binary
979 # contents. But if LD_PRELOAD* environment variables are present, libraries
980 # named by them will also appear in the output, disrupting our analysis.
981 # So, before we get too far, scrub the environment.
983 delete($ENV{LD_PRELOAD});
984 delete($ENV{LD_PRELOAD_32});
985 delete($ENV{LD_PRELOAD_64});
987 # Establish a program name for any error diagnostics.
988 chomp($Prog = `basename $0`);
990 # The onbld_elfmod package is maintained in the same directory as this
991 # script, and is installed in ../lib/perl. Use the local one if present,
992 # and the installed one otherwise.
993 my $moddir = dirname($0);
994 $moddir = "$moddir/../lib/perl" if ! -f "$moddir/onbld_elfmod.pm";
995 require "$moddir/onbld_elfmod.pm";
997 # Determine what machinery is available.
998 my $Mach = `uname -p`;
999 my$Isalist = `isalist`;
1000 if ($Mach =~ /sparc/) {
1001 if ($Isalist =~ /sparcv9/) {
1004 } elsif ($Mach =~ /i386/) {
1005 if ($Isalist =~ /amd64/) {
1010 # $Env is used with all calls to ldd. It is set by AltObjectConfig to
1011 # cause an alternate object mapping runtime config file to be used.
1014 # Check that we have arguments.
1015 if ((getopts('D:d:E:e:f:I:imosvw:', \%opt) == 0) ||
1016 (!$opt{f} && ($#ARGV == -1))) {
1017 print "usage: $Prog [-imosv] [-D depfile | -d depdir] [-E errfile]\n";
1018 print "\t\t[-e exfile] [-f listfile] [-I infofile] [-w outdir]\n";
1019 print "\t\t[file | dir]...\n";
1021 print "\t[-D depfile]\testablish dependencies from 'find_elf -r' file list\n";
1022 print "\t[-d depdir]\testablish dependencies from under directory\n";
1023 print "\t[-E errfile]\tdirect error output to file\n";
1024 print "\t[-e exfile]\texceptions file\n";
1025 print "\t[-f listfile]\tuse file list produced by find_elf -r\n";
1026 print "\t[-I infofile]\tdirect informational output (-i, -v) to file\n";
1027 print "\t[-i]\t\tproduce dynamic table entry information\n";
1028 print "\t[-o]\t\tproduce one-liner output (prefixed with pathname)\n";
1029 print "\t[-s]\t\tprocess .stab and .symtab entries\n";
1030 print "\t[-v]\t\tprocess version definition entries\n";
1031 print "\t[-w outdir]\tinterpret all files relative to given directory\n";
1035 die "$Prog: -D and -d options are mutually exclusive\n" if ($opt{D} && $opt{d});
1037 $Tmpdir = "/tmp" if (!($Tmpdir = $ENV{TMPDIR}) || (! -d $Tmpdir));
1039 # If -w, change working directory to given location
1040 !$opt{w} || chdir($opt{w}) || die "$Prog: can't cd to $opt{w}";
1042 # Locate and process the exceptions file
1043 onbld_elfmod::LoadExceptionsToEXRE('check_rtime');
1045 # Is there a proto area available, either via the -d option, or because
1046 # we are part of an activated workspace?
1049 # User specified dependency directory - make sure it exists.
1050 -d $opt{d} || die "$Prog: $opt{d} is not a directory\n";
1052 } elsif ($ENV{SRCTOP}) {
1055 # Without a user specified dependency directory see if we're
1056 # part of a codemanager workspace and if a proto area exists.
1057 $Proto = $Root if ($Root = $ENV{ROOT}) && (-d $Root);
1060 # If we are basing this analysis off the sharable objects found in
1061 # a proto area, then gather dependencies and construct an alternative
1062 # dependency mapping via a crle(1) configuration file.
1064 # To support alternative dependency mapping we'll need ldd(1)'s
1065 # -e option. This is relatively new (s81_30), so make sure
1066 # ldd(1) is capable before gathering any dependency information.
1067 if ($opt{D} || $Proto) {
1068 if (system('ldd -e /usr/lib/lddstub 2> /dev/null')) {
1069 print "ldd: does not support -e, unable to ";
1070 print "create alternative dependency mappingings.\n";
1071 print "ldd: option added under 4390308 (s81_30).\n\n";
1073 # If -D was specified, it supplies a list of files in
1074 # 'find_elf -r' format, and can use it directly. Otherwise,
1075 # we will run find_elf as a child process to find the
1076 # sharable objects found under $Proto.
1077 AltObjectConfig($opt{D} ? $opt{D} : "find_elf -frs $Proto|");
1081 # To support unreferenced dependency detection we'll need ldd(1)'s -U
1082 # option. This is relatively new (4638070), and if not available we
1083 # can still fall back to -u. Even with this option, don't use -U with
1084 # releases prior to 5.10 as the cleanup for -U use only got integrated
1085 # into 5.10 under 4642023. Note, that nightly doesn't typically set a
1086 # RELEASE from the standard <env> files. Users who wish to disable use
1087 # of ldd(1)'s -U should set (or uncomment) RELEASE in their <env> file
1088 # if using nightly, or otherwise establish it in their environment.
1089 if (system('ldd -U /usr/lib/lddstub 2> /dev/null')) {
1094 if (($Release = $ENV{RELEASE}) && (cmp_os_ver($Release, "<", "5.10"))) {
1101 # Set up variables used to handle output files:
1103 # Error messages go to stdout unless -E is specified. $ErrFH is a
1104 # file handle reference that points at the file handle where error messages
1105 # are sent, and $ErrTtl is a reference that points at an integer used
1106 # to count how many lines have been sent there.
1108 # Informational messages go to stdout unless -I is specified. $InfoFH is a
1109 # file handle reference that points at the file handle where info messages
1110 # are sent, and $InfoTtl is a reference that points at an integer used
1111 # to count how many lines have been sent there.
1114 open(ERROR, ">$opt{E}") || die "$Prog: open failed: $opt{E}";
1121 open(INFO, ">$opt{I}") || die "$Prog: open failed: $opt{I}";
1126 my ($err_dev, $err_ino) = stat($ErrFH);
1127 my ($info_dev, $info_ino) = stat($InfoFH);
1128 $ErrTtl = \$OutCnt1;
1129 $InfoTtl = (($err_dev == $info_dev) && ($err_ino == $info_ino)) ?
1130 \$OutCnt1 : \$OutCnt2;
1133 # If we were given a list of objects in 'find_elf -r' format, then
1135 ProcFindElf($opt{f}) if $opt{f};
1137 # Process each argument
1138 foreach my $Arg (@ARGV) {
1139 # Run find_elf to find the files given by $Arg and process them
1140 ProcFindElf("find_elf -fr $Arg|");
1143 # Cleanup output files
1144 unlink $Conf64 if $Conf64;
1145 unlink $Conf32 if $Conf32;
1146 close ERROR if $opt{E};
1147 close INFO if $opt{I};