xref: /titanic_51/usr/src/cmd/sgs/lari/lari.pl (revision 69112edd987c28fa551d4f8d9362a84a45365f17)
17c478bd9Sstevel@tonic-gate#!/usr/perl5/bin/perl -w
27c478bd9Sstevel@tonic-gate#
37c478bd9Sstevel@tonic-gate# CDDL HEADER START
47c478bd9Sstevel@tonic-gate#
57c478bd9Sstevel@tonic-gate# The contents of this file are subject to the terms of the
6c1c6f601Srie# Common Development and Distribution License (the "License").
7c1c6f601Srie# You may not use this file except in compliance with the License.
87c478bd9Sstevel@tonic-gate#
97c478bd9Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate# See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate# and limitations under the License.
137c478bd9Sstevel@tonic-gate#
147c478bd9Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate#
207c478bd9Sstevel@tonic-gate# CDDL HEADER END
217c478bd9Sstevel@tonic-gate#
22c1c6f601Srie
237c478bd9Sstevel@tonic-gate#
24*69112eddSAli Bahrami# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate# Use is subject to license terms.
267c478bd9Sstevel@tonic-gate#
277c478bd9Sstevel@tonic-gate# Link Analysis of Runtime Interfaces.
287c478bd9Sstevel@tonic-gate#
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate# Define all global variables (required for strict)
3160758829Srieuse vars  qw($Prog $DestDir $ObjRef $ObjFlag $ObjSize $ObjVis $TmpDir);
3260758829Srieuse vars  qw($LddArgs $SymFlag);
333906e0c2Srieuse vars  qw($Glob $Intp $Dirc $Cpyr $Prot $Extn $Self $Gfte $Plta $User $Func);
343c4993fbSrieuse vars  qw($Rejt $Sfte $Afte $Objt $Nodi $Osft $Oaft $Ssft $Saft $Msft);
353906e0c2Srieuse vars  qw($Rtld $GlobWeak $MultSyms $CrtSyms $Platform $DbgSeed %opt);
363906e0c2Srie
373906e0c2Srie# Global arrays that must be cleared for multi input file use.
383906e0c2Srieuse vars  qw(%Symbols %Objects %Versioned %DemSyms %ObjFltrs %SymFltes);
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gateuse strict;
417c478bd9Sstevel@tonic-gate
427c478bd9Sstevel@tonic-gateuse Getopt::Std;
437c478bd9Sstevel@tonic-gateuse File::Basename;
447c478bd9Sstevel@tonic-gate
453906e0c2Srie# Pattern match to skip the runtime linker.
467010c12aSrie$Rtld = qr{
477c478bd9Sstevel@tonic-gate	/lib/ld\.so\.1 |
487c478bd9Sstevel@tonic-gate	/usr/lib/ld\.so\.1 |
497c478bd9Sstevel@tonic-gate	/lib/sparcv9/ld\.so\.1 |
50c1c6f601Srie	/usr/lib/sparcv9/ld\.so\.1 |
51c1c6f601Srie	/lib/amd64/ld\.so\.1 |
52c1c6f601Srie	/usr/lib/amd64/ld\.so\.1
537c478bd9Sstevel@tonic-gate}x;
547c478bd9Sstevel@tonic-gate
557c478bd9Sstevel@tonic-gate# Pattern matching required to determine a global symbol.
567c478bd9Sstevel@tonic-gate$GlobWeak = qr{ ^(?:
577c478bd9Sstevel@tonic-gate	GLOB |
587c478bd9Sstevel@tonic-gate	WEAK
597c478bd9Sstevel@tonic-gate	)$
607c478bd9Sstevel@tonic-gate}x;
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate# Pattern matching to determine link-editor specific symbols and those common
637c478bd9Sstevel@tonic-gate# to the compilation environment (ie. provided by all crt's).
647c478bd9Sstevel@tonic-gate$MultSyms = qr{ ^(?:
657c478bd9Sstevel@tonic-gate	 _DYNAMIC |
667c478bd9Sstevel@tonic-gate	 _GLOBAL_OFFSET_TABLE_ |
677c478bd9Sstevel@tonic-gate	 _PROCEDURE_LINKAGE_TABLE_ |
687c478bd9Sstevel@tonic-gate	 _etext |
697c478bd9Sstevel@tonic-gate	 _edata |
707c478bd9Sstevel@tonic-gate	 _end |
717c478bd9Sstevel@tonic-gate	 _init |
727c478bd9Sstevel@tonic-gate	 _fini |
737c478bd9Sstevel@tonic-gate	 _lib_version |			# Defined in values
747c478bd9Sstevel@tonic-gate	 __xpg4 |			# Defined in values
757c478bd9Sstevel@tonic-gate	 __xpg6				# Defined in values
767c478bd9Sstevel@tonic-gate	)$
777c478bd9Sstevel@tonic-gate}x;
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate$CrtSyms = qr{ ^(?:
807c478bd9Sstevel@tonic-gate	 ___Argv |			# Defined in crt
817c478bd9Sstevel@tonic-gate	 __environ_lock |		# Defined in crt
827c478bd9Sstevel@tonic-gate	 _environ |			# Defined in crt
837c478bd9Sstevel@tonic-gate	 environ			# Defined in crt
847c478bd9Sstevel@tonic-gate	 )$
857c478bd9Sstevel@tonic-gate}x;
867c478bd9Sstevel@tonic-gate
877c478bd9Sstevel@tonic-gate# Symbol flags.
887c478bd9Sstevel@tonic-gate$Glob = 0x00001;	# symbol is global
893906e0c2Srie$Sfte = 0x00002;	# symbol is a filtee backing a standard filter
903906e0c2Srie$Afte = 0x00004;	# symbol is a filtee backing a auxiliary filter
913906e0c2Srie$Gfte = 0x00008;	# symbol bound as a filtee
929a411307Srie$Intp = 0x00010;	# symbol originates from explicit interposer
937c478bd9Sstevel@tonic-gate$Dirc = 0x00020;	# symbol bound to directly
947c478bd9Sstevel@tonic-gate$Cpyr = 0x00040;	# symbol bound to copy-relocation reference
957c478bd9Sstevel@tonic-gate$Prot = 0x00080;	# symbol is protected (symbolic)
967c478bd9Sstevel@tonic-gate$Extn = 0x00100;	# symbol has been bound to from an external reference
977c478bd9Sstevel@tonic-gate$Self = 0x00200;	# symbol has been bound to from the same object
983c4993fbSrie$Rejt = 0x00400;	# symbol binding was (at some point) rejected
997c478bd9Sstevel@tonic-gate$Plta = 0x00800;	# symbol bound to executables plt address
1007c478bd9Sstevel@tonic-gate$User = 0x01000;	# symbol binding originates from user (dlsym) request
1017c478bd9Sstevel@tonic-gate$Func = 0x02000;	# symbol is of type function
1027c478bd9Sstevel@tonic-gate$Objt = 0x04000;	# symbol is of type object
1037c478bd9Sstevel@tonic-gate$Nodi = 0x08000;	# symbol prohibits direct binding
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate$Osft = 0x10000;	# symbol is an standard object filter
1067c478bd9Sstevel@tonic-gate$Oaft = 0x20000;	# symbol is an auxiliary object filter
1077c478bd9Sstevel@tonic-gate$Ssft = 0x40000;	# symbol is a per-symbol standard filter
1083906e0c2Srie$Saft = 0x80000;	# symbol is a per-symbol auxiliary filter
1097c478bd9Sstevel@tonic-gate$Msft = 0xf0000;	# filter mask
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate# Offsets into $Symbols{$SymName}{$Obj} array.
1127c478bd9Sstevel@tonic-gate$ObjRef =	0;
1137c478bd9Sstevel@tonic-gate$ObjFlag =	1;
1147c478bd9Sstevel@tonic-gate$ObjSize =	2;
11560758829Srie$ObjVis =	3;
1167c478bd9Sstevel@tonic-gate
1173906e0c2Srie# Offset into $SymFltr{$SymName}{$Filtee} array.
1183906e0c2Srie$SymFlag = 	0;
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate# Establish locale
1217c478bd9Sstevel@tonic-gateuse POSIX qw(locale_h);
1227c478bd9Sstevel@tonic-gateuse Sun::Solaris::Utils qw(textdomain gettext);
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gatesetlocale(LC_ALL, "");
1257c478bd9Sstevel@tonic-gatetextdomain("SUNW_OST_SGS");
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate# Establish a program name for any error diagnostics.
1287c478bd9Sstevel@tonic-gate$Prog = basename($0);
1297c478bd9Sstevel@tonic-gate
1307c478bd9Sstevel@tonic-gatesub inappropriate {
1317c478bd9Sstevel@tonic-gate	my ($Opt1, $Opt2, $Flag) = @_;
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate	if ($Flag) {
1347c478bd9Sstevel@tonic-gate	    printf STDERR
1357c478bd9Sstevel@tonic-gate		gettext("%s: inappropriate use of %s with %s: %s ignored\n"),
1367c478bd9Sstevel@tonic-gate		$Prog, $Opt1, $Opt2, $Opt1;
1377c478bd9Sstevel@tonic-gate	} else {
1387c478bd9Sstevel@tonic-gate	    printf STDERR
1397c478bd9Sstevel@tonic-gate		gettext("%s: inappropriate use of %s without %s: %s ignored\n"),
1407c478bd9Sstevel@tonic-gate		$Prog, $Opt1, $Opt2, $Opt1;
1417c478bd9Sstevel@tonic-gate	}
1427c478bd9Sstevel@tonic-gate}
1437c478bd9Sstevel@tonic-gate
1443906e0c2Srie# Cleanup any temporary files on interruption.
1457c478bd9Sstevel@tonic-gatesub Cleanup {
1467c478bd9Sstevel@tonic-gate	my ($Sig) = @_;
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate	$SIG{$Sig} = 'IGNORE';
1497c478bd9Sstevel@tonic-gate
1507c478bd9Sstevel@tonic-gate	if ($DbgSeed ne "") {
1517c478bd9Sstevel@tonic-gate		foreach my $File (<\Q${DbgSeed}\E.*>) {
1527c478bd9Sstevel@tonic-gate			if ($File =~ /^\Q$DbgSeed\E\.\d+$/) {
1537c478bd9Sstevel@tonic-gate				unlink($File);
1547c478bd9Sstevel@tonic-gate			}
1557c478bd9Sstevel@tonic-gate		}
1567c478bd9Sstevel@tonic-gate	}
1577c478bd9Sstevel@tonic-gate	exit 1;
1587c478bd9Sstevel@tonic-gate}
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate# Check that we have arguments.
16160758829Srieif ((getopts('abCDd:imosVv', \%opt) == 0) || ($#ARGV < 0)) {
1627c478bd9Sstevel@tonic-gate	printf STDERR gettext("usage:\n");
1637c478bd9Sstevel@tonic-gate	printf STDERR
16460758829Srie	    gettext("    %s [-bCDsVv] [-a | -i | -o ] file | dir ...\n"), $Prog;
1657c478bd9Sstevel@tonic-gate	printf STDERR
16660758829Srie	    gettext("    %s [-CDosVv] [-m [-d mapdir]] file\n"), $Prog;
1677c478bd9Sstevel@tonic-gate	print STDERR
1687c478bd9Sstevel@tonic-gate	    gettext("\t[-a]     print diagnostics for all symbols\n");
1697c478bd9Sstevel@tonic-gate	print STDERR
1703906e0c2Srie	    gettext("\t[-b]     limit diagnostics to bound symbols\n");
1717c478bd9Sstevel@tonic-gate	print STDERR
1727c478bd9Sstevel@tonic-gate	    gettext("\t[-C]     print demangled symbol names also\n");
1737c478bd9Sstevel@tonic-gate	print STDERR
1747c478bd9Sstevel@tonic-gate	    gettext("\t[-D]     read debugging information from \"file\"\n");
1757c478bd9Sstevel@tonic-gate	print STDERR
1767c478bd9Sstevel@tonic-gate	    gettext("\t[-d dir] create mapfiles in \"mapdir\"\n");
1777c478bd9Sstevel@tonic-gate	print STDERR
1787c478bd9Sstevel@tonic-gate	    gettext("\t[-i]     print interesting information (default)\n");
1797c478bd9Sstevel@tonic-gate	print STDERR
1807c478bd9Sstevel@tonic-gate	    gettext("\t[-m]     create mapfiles for interface requirements\n");
1817c478bd9Sstevel@tonic-gate	print STDERR
1823906e0c2Srie	    gettext("\t[-o]     limit diagnostics to overhead information\n");
1837c478bd9Sstevel@tonic-gate	print STDERR
1847c478bd9Sstevel@tonic-gate	    gettext("\t[-s]     save bindings information created by ldd(1)\n");
1857c478bd9Sstevel@tonic-gate	print STDERR
18660758829Srie	    gettext("\t[-V]     append interesting symbol visibilities\n");
18760758829Srie	print STDERR
1887c478bd9Sstevel@tonic-gate	    gettext("\t[-v]     ignore versioned objects\n");
1897c478bd9Sstevel@tonic-gate	exit 1;
1907c478bd9Sstevel@tonic-gate} else {
1917c478bd9Sstevel@tonic-gate	my ($Mult, $Error);
1927c478bd9Sstevel@tonic-gate
1937c478bd9Sstevel@tonic-gate	# Catch any incompatible argument usage.
1947c478bd9Sstevel@tonic-gate	if ($opt{m}) {
1957c478bd9Sstevel@tonic-gate		if ($opt{a}) {
1967c478bd9Sstevel@tonic-gate			inappropriate("-a", "-m", 1);
1977c478bd9Sstevel@tonic-gate			$opt{a} = 0;
1987c478bd9Sstevel@tonic-gate		}
1997c478bd9Sstevel@tonic-gate		if ($opt{i}) {
2007c478bd9Sstevel@tonic-gate			inappropriate("-i", "-m", 1);
2017c478bd9Sstevel@tonic-gate			$opt{i} = 0;
2027c478bd9Sstevel@tonic-gate		}
2037c478bd9Sstevel@tonic-gate	} else {
2047c478bd9Sstevel@tonic-gate		if ($opt{d}) {
2057c478bd9Sstevel@tonic-gate			inappropriate("-d", "-m", 0);
2067c478bd9Sstevel@tonic-gate			$opt{d} = 0;
2077c478bd9Sstevel@tonic-gate		}
2087c478bd9Sstevel@tonic-gate	}
2097c478bd9Sstevel@tonic-gate	if ($opt{a}) {
2107c478bd9Sstevel@tonic-gate		if ($opt{o}) {
2117c478bd9Sstevel@tonic-gate			inappropriate("-a", "-o", 1);
2127c478bd9Sstevel@tonic-gate			$opt{o} = 0;
2137c478bd9Sstevel@tonic-gate		}
2147c478bd9Sstevel@tonic-gate		if ($opt{i}) {
2157c478bd9Sstevel@tonic-gate			inappropriate("-a", "-i", 1);
2167c478bd9Sstevel@tonic-gate			$opt{i} = 0;
2177c478bd9Sstevel@tonic-gate		}
2187c478bd9Sstevel@tonic-gate	}
2197010c12aSrie	if ($opt{o}) {
2207010c12aSrie		if ($opt{i}) {
2217c478bd9Sstevel@tonic-gate			inappropriate("-o", "-i", 1);
2227c478bd9Sstevel@tonic-gate			$opt{i} = 0;
2237c478bd9Sstevel@tonic-gate		}
2247010c12aSrie		if ($opt{b}) {
2257010c12aSrie			inappropriate("-o", "-b", 1);
2267010c12aSrie			$opt{b} = 0;
2277010c12aSrie		}
2287010c12aSrie	}
2297c478bd9Sstevel@tonic-gate
2307c478bd9Sstevel@tonic-gate	# If -m is used, only one input file is applicable.
2317c478bd9Sstevel@tonic-gate	if ($opt{m} && ($#ARGV != 0)) {
2327c478bd9Sstevel@tonic-gate		printf STDERR gettext("%s: only one input file is allowed " .
2337c478bd9Sstevel@tonic-gate		    "with the -m option\n"), $Prog;
2347c478bd9Sstevel@tonic-gate		exit 1;
2357c478bd9Sstevel@tonic-gate	}
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate	# Insure any specified directory exists, or apply a default.
2387c478bd9Sstevel@tonic-gate	if ($opt{d}) {
2397c478bd9Sstevel@tonic-gate		# User specified directory - make sure it exists.
2407c478bd9Sstevel@tonic-gate		if (! -d $opt{d}) {
2417c478bd9Sstevel@tonic-gate			printf STDERR gettext("%s: %s is not a directory\n"),
2427c478bd9Sstevel@tonic-gate			    $Prog, $opt{d};
2437c478bd9Sstevel@tonic-gate			exit 1;
2447c478bd9Sstevel@tonic-gate		}
2457c478bd9Sstevel@tonic-gate		$DestDir = $opt{d};
2467c478bd9Sstevel@tonic-gate	} else {
2477c478bd9Sstevel@tonic-gate		$DestDir = ".";
2487c478bd9Sstevel@tonic-gate	}
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate	# Establish a temporary directory if necessary.
2517c478bd9Sstevel@tonic-gate	if (!$opt{D}) {
2527c478bd9Sstevel@tonic-gate		if (!($TmpDir = $ENV{TMPDIR}) || (! -d $TmpDir)) {
2537c478bd9Sstevel@tonic-gate			$TmpDir = "/tmp";
2547c478bd9Sstevel@tonic-gate		}
2557c478bd9Sstevel@tonic-gate	}
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate	# Establish any initial ldd(1) argument requirements.
2587c478bd9Sstevel@tonic-gate	if ($LddArgs = $ENV{LARI_LDD_ARGS}) {
2597c478bd9Sstevel@tonic-gate		$LddArgs = $LddArgs . ' -r -e LD_DEBUG=bindings,files,detail';
2607c478bd9Sstevel@tonic-gate	} else {
2617c478bd9Sstevel@tonic-gate		$LddArgs = '-r -e LD_DEBUG=bindings,files,detail';
2627c478bd9Sstevel@tonic-gate	}
2637c478bd9Sstevel@tonic-gate
2647c478bd9Sstevel@tonic-gate	# If we've been asked to demangle symbols, make sure we can find the
2657c478bd9Sstevel@tonic-gate	# demangler.
2667c478bd9Sstevel@tonic-gate	if ($opt{C}) {
2677c478bd9Sstevel@tonic-gate		my ($DemName) = `dem XXXX 2> /dev/null`;
2687c478bd9Sstevel@tonic-gate		if (!$DemName) {
2697c478bd9Sstevel@tonic-gate			printf STDERR gettext("%s: can not locate demangler: " .
2707c478bd9Sstevel@tonic-gate			    "-C ignored\n"), $Prog;
2717c478bd9Sstevel@tonic-gate			$opt{C} = 0;
2727c478bd9Sstevel@tonic-gate		}
2737c478bd9Sstevel@tonic-gate	}
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate	# If -a or -o hasn't been specified, default to -i.
2767c478bd9Sstevel@tonic-gate	if (!$opt{a} && !$opt{o}) {
2777c478bd9Sstevel@tonic-gate		$opt{i} = 1;
2787c478bd9Sstevel@tonic-gate	}
2797c478bd9Sstevel@tonic-gate
2807010c12aSrie	# Determine whether we have multiple input files.
2817c478bd9Sstevel@tonic-gate	if ($#ARGV == 0) {
2827c478bd9Sstevel@tonic-gate		$Mult = 0;
2837c478bd9Sstevel@tonic-gate	} else {
2847c478bd9Sstevel@tonic-gate		$Mult = 1;
2857c478bd9Sstevel@tonic-gate	}
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate	# Determine what platform we're running on - some inappropriate
2887c478bd9Sstevel@tonic-gate	# platform specific dependencies are better skipped.
2897c478bd9Sstevel@tonic-gate	chomp($Platform = `uname -i`);
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gate	# Establish signal handlers
2927c478bd9Sstevel@tonic-gate	$SIG{INT} = \&Cleanup;
2937c478bd9Sstevel@tonic-gate	$SIG{QUIT} = \&Cleanup;
2947c478bd9Sstevel@tonic-gate
2957c478bd9Sstevel@tonic-gate	$DbgSeed = "";
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate	# For each argument determine if we're dealing with a file or directory.
2987c478bd9Sstevel@tonic-gate	$Error = 0;
2997c478bd9Sstevel@tonic-gate	foreach my $Arg (@ARGV) {
3007c478bd9Sstevel@tonic-gate		if (!stat($Arg)) {
3017c478bd9Sstevel@tonic-gate			printf STDERR gettext("%s: %s: unable to stat file\n"),
3027c478bd9Sstevel@tonic-gate			    $Prog, $Arg;
3037c478bd9Sstevel@tonic-gate			$Error = 1;
3047c478bd9Sstevel@tonic-gate			next;
3057c478bd9Sstevel@tonic-gate		}
3067c478bd9Sstevel@tonic-gate
3077c478bd9Sstevel@tonic-gate		# Process simple files.
3087c478bd9Sstevel@tonic-gate		if (-f _) {
3097c478bd9Sstevel@tonic-gate			if (!-r _) {
3107c478bd9Sstevel@tonic-gate				printf STDERR gettext("%s: %s: unable to " .
3117c478bd9Sstevel@tonic-gate				   "read file\n"), $Prog, $Arg;
3127c478bd9Sstevel@tonic-gate				$Error = 1;
3137c478bd9Sstevel@tonic-gate				next;
3147c478bd9Sstevel@tonic-gate			}
3157c478bd9Sstevel@tonic-gate			if (!$opt{D}) {
3167c478bd9Sstevel@tonic-gate				if (ProcFile($Arg, $Mult, 1) == 0) {
3177c478bd9Sstevel@tonic-gate					$Error = 1;
3187c478bd9Sstevel@tonic-gate				}
3197c478bd9Sstevel@tonic-gate			} else {
3207c478bd9Sstevel@tonic-gate				# If the -D option is specified, read the
3217c478bd9Sstevel@tonic-gate				# bindings debugging information from the
3227c478bd9Sstevel@tonic-gate				# specified file.
3237c478bd9Sstevel@tonic-gate				if ($Mult) {
3247c478bd9Sstevel@tonic-gate					print STDOUT "$Arg:\n";
3257c478bd9Sstevel@tonic-gate				}
3267c478bd9Sstevel@tonic-gate				ProcBindings($Arg, $Mult, $Arg);
3277c478bd9Sstevel@tonic-gate			}
3287c478bd9Sstevel@tonic-gate			next;
3297c478bd9Sstevel@tonic-gate		}
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate		# Process directories.
3327c478bd9Sstevel@tonic-gate		if (-d _) {
3337c478bd9Sstevel@tonic-gate			ProcDir($Arg);
3347c478bd9Sstevel@tonic-gate			next;
3357c478bd9Sstevel@tonic-gate		}
3367c478bd9Sstevel@tonic-gate
3377c478bd9Sstevel@tonic-gate		printf STDERR gettext("%s: %s: is not a file or directory\n"),
3387c478bd9Sstevel@tonic-gate		    $Prog, $Arg;
3397c478bd9Sstevel@tonic-gate		$Error = 1;
3407c478bd9Sstevel@tonic-gate	}
3417c478bd9Sstevel@tonic-gate	exit $Error;
3427c478bd9Sstevel@tonic-gate}
3437c478bd9Sstevel@tonic-gate
3447c478bd9Sstevel@tonic-gatesub ProcDir {
3457c478bd9Sstevel@tonic-gate	my ($Dir) = @_;
3467c478bd9Sstevel@tonic-gate	my ($File);
3477c478bd9Sstevel@tonic-gate
3487c478bd9Sstevel@tonic-gate	# Open the directory and read each entry, omit "." and "..".  Sorting
3497c478bd9Sstevel@tonic-gate	# the directory listing makes analyzing different source hierarchies
3507c478bd9Sstevel@tonic-gate	# easier.
3517c478bd9Sstevel@tonic-gate	if (opendir(DIR, $Dir)) {
3527c478bd9Sstevel@tonic-gate		foreach my $Entry (sort(readdir(DIR))) {
3537c478bd9Sstevel@tonic-gate			if (($Entry eq '.') || ($Entry eq '..')) {
3547c478bd9Sstevel@tonic-gate				next;
3557c478bd9Sstevel@tonic-gate			}
3567c478bd9Sstevel@tonic-gate
3573906e0c2Srie			# If we're descending into a platform directory, ignore
3587c478bd9Sstevel@tonic-gate			# any inappropriate platform specific files.  These
3597c478bd9Sstevel@tonic-gate			# files can have dependencies that in turn bring in the
3607c478bd9Sstevel@tonic-gate			# appropriate platform specific file, resulting in more
3617c478bd9Sstevel@tonic-gate			# than one dependency offering the same interfaces.  In
3627c478bd9Sstevel@tonic-gate			# practice, the non-appropriate platform specific file
3637c478bd9Sstevel@tonic-gate			# wouldn't be loaded with a process.
3647c478bd9Sstevel@tonic-gate			if (($Dir =~ /\/platform$/) &&
3657c478bd9Sstevel@tonic-gate			    ($Entry !~ /^$Platform$/)) {
3667c478bd9Sstevel@tonic-gate				next;
3677c478bd9Sstevel@tonic-gate			}
3687c478bd9Sstevel@tonic-gate
3697c478bd9Sstevel@tonic-gate			$File = "$Dir/$Entry";
3707c478bd9Sstevel@tonic-gate			if (!lstat($File)) {
3717c478bd9Sstevel@tonic-gate				next;
3727c478bd9Sstevel@tonic-gate			}
3737c478bd9Sstevel@tonic-gate			# Ignore symlinks.
3747c478bd9Sstevel@tonic-gate			if (-l _) {
3757c478bd9Sstevel@tonic-gate				next;
3767c478bd9Sstevel@tonic-gate			}
3777c478bd9Sstevel@tonic-gate
3787c478bd9Sstevel@tonic-gate			# Descend into, and process any directories.
3797c478bd9Sstevel@tonic-gate			if (-d _) {
3807c478bd9Sstevel@tonic-gate				ProcDir($File);
3817c478bd9Sstevel@tonic-gate				next;
3827c478bd9Sstevel@tonic-gate			}
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate			# Process any standard files.
3857c478bd9Sstevel@tonic-gate			if (-f _ && -r _) {
3867c478bd9Sstevel@tonic-gate				ProcFile($File, 1, 0);
3877c478bd9Sstevel@tonic-gate				next;
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate			}
3907c478bd9Sstevel@tonic-gate		}
3917c478bd9Sstevel@tonic-gate		closedir(DIR);
3927c478bd9Sstevel@tonic-gate	}
3937c478bd9Sstevel@tonic-gate}
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate# Process a file.  If the file was explicitly defined on the command-line, and
3967c478bd9Sstevel@tonic-gate# an error occurs, tell the user.  Otherwise, this file probably came about from
3977c478bd9Sstevel@tonic-gate# scanning a directory, in which case just skip it and move on.
3987c478bd9Sstevel@tonic-gatesub ProcFile {
3997c478bd9Sstevel@tonic-gate	my ($File, $Mult, $CmdLine) = @_;
4007c478bd9Sstevel@tonic-gate	my (@Ldd, $NoFound, $DbgFile, @DbgGlob, $Type);
4017c478bd9Sstevel@tonic-gate
4027010c12aSrie	# If we're scanning a directory (ie. /lib) and have picked up ld.so.1,
4037010c12aSrie	# ignore it.
4047010c12aSrie	if (($CmdLine eq 0) && ($File =~ $Rtld)) {
4057010c12aSrie		return 1;
4067010c12aSrie	}
4077010c12aSrie
4087c478bd9Sstevel@tonic-gate	$Type = `LC_ALL=C file '$File' 2>&1`;
4097c478bd9Sstevel@tonic-gate	if (($Type !~ /dynamically linked/) || ($Type =~ /Sun demand paged/)) {
4107c478bd9Sstevel@tonic-gate		if ($CmdLine) {
4117c478bd9Sstevel@tonic-gate			printf STDERR gettext("%s: %s: is an invalid file " .
4127c478bd9Sstevel@tonic-gate			    "type\n"), $Prog, $File;
4137c478bd9Sstevel@tonic-gate		}
4147c478bd9Sstevel@tonic-gate		return 0;
4157c478bd9Sstevel@tonic-gate	}
4167c478bd9Sstevel@tonic-gate
4177c478bd9Sstevel@tonic-gate	# Create a temporary filename for capturing binding information.
4187c478bd9Sstevel@tonic-gate	$DbgSeed = basename($File);
4197c478bd9Sstevel@tonic-gate	$DbgSeed = "$TmpDir/lari.dbg.$$.$DbgSeed";
4207c478bd9Sstevel@tonic-gate
4217c478bd9Sstevel@tonic-gate	# Exercise the file under ldd(1), capturing all the bindings.
4227c478bd9Sstevel@tonic-gate	@Ldd = split(/\n/,
4237c478bd9Sstevel@tonic-gate	    `LC_ALL=C ldd $LddArgs -e LD_DEBUG_OUTPUT='$DbgSeed' '$File' 2>&1`);
4247c478bd9Sstevel@tonic-gate
4257c478bd9Sstevel@tonic-gate	# If ldd isn't -e capable we'll get a usage message.  The -e option was
4267c478bd9Sstevel@tonic-gate	# introduced in Solaris 9 and related patches.  Also, make sure the user
4277c478bd9Sstevel@tonic-gate	# sees any ldd errors.
4287c478bd9Sstevel@tonic-gate	$NoFound = 0;
4297c478bd9Sstevel@tonic-gate	for my $Line (@Ldd) {
4307c478bd9Sstevel@tonic-gate		if ($Line =~ /^usage: ldd/) {
4317c478bd9Sstevel@tonic-gate			printf STDERR gettext("%s: ldd: does not support -e, " .
4327c478bd9Sstevel@tonic-gate			    "unable to capture bindings output\n"), $Prog;
4337c478bd9Sstevel@tonic-gate			exit 1;
4347c478bd9Sstevel@tonic-gate		}
4357c478bd9Sstevel@tonic-gate		if ($Line =~ /not found/) {
4367c478bd9Sstevel@tonic-gate			$NoFound = 1;
4377c478bd9Sstevel@tonic-gate			last;
4387c478bd9Sstevel@tonic-gate		}
4397c478bd9Sstevel@tonic-gate	}
4407c478bd9Sstevel@tonic-gate
4417c478bd9Sstevel@tonic-gate	# The runtime linker will have appended a process id to the debug file.
4427c478bd9Sstevel@tonic-gate	# As we have to intuit the name, make sure there is only one debug
4437c478bd9Sstevel@tonic-gate	# file match, otherwise there must be some clutter in the output
4447c478bd9Sstevel@tonic-gate	# directory that is going to mess up our analysis.
4457c478bd9Sstevel@tonic-gate	foreach my $Match (<\Q${DbgSeed}\E.*>) {
4467c478bd9Sstevel@tonic-gate		if ($Match =~ /^\Q$DbgSeed\E\.\d+$/) {
4477c478bd9Sstevel@tonic-gate			push(@DbgGlob, $Match);
4487c478bd9Sstevel@tonic-gate		}
4497c478bd9Sstevel@tonic-gate	}
4507c478bd9Sstevel@tonic-gate	if (@DbgGlob == 0) {
4517c478bd9Sstevel@tonic-gate		# If there is no debug file, bail.  This can occur if the file
4527c478bd9Sstevel@tonic-gate		# being processed is secure.
4537c478bd9Sstevel@tonic-gate		if ($CmdLine) {
4547c478bd9Sstevel@tonic-gate			printf STDERR gettext("%s: %s: unable to capture " .
4557c478bd9Sstevel@tonic-gate			    "bindings output - possible secure application?\n"),
4567c478bd9Sstevel@tonic-gate			    $Prog, $File;
4577c478bd9Sstevel@tonic-gate		}
4587c478bd9Sstevel@tonic-gate		return 0;
4597c478bd9Sstevel@tonic-gate	} elsif (@DbgGlob > 1) {
4607c478bd9Sstevel@tonic-gate		# Too many debug files found.
4617c478bd9Sstevel@tonic-gate		if ($CmdLine) {
4627c478bd9Sstevel@tonic-gate			printf STDERR gettext("%s: %s: multiple bindings " .
4637c478bd9Sstevel@tonic-gate			    "output files exist: %s: clean up temporary " .
4647c478bd9Sstevel@tonic-gate			    "directory\n"), $Prog, $File, $DbgSeed;
4657c478bd9Sstevel@tonic-gate		}
4667c478bd9Sstevel@tonic-gate		return 0;
4677c478bd9Sstevel@tonic-gate	} else {
4687c478bd9Sstevel@tonic-gate		$DbgFile = $DbgGlob[0];
4697c478bd9Sstevel@tonic-gate	}
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate	# Ok, we're ready to process the bindings information.  Print a header
4727c478bd9Sstevel@tonic-gate	# if necessary, and if there were any ldd(1) errors push some of them
4737c478bd9Sstevel@tonic-gate	# out before any bindings information.  Limit the output, as it can
4747c478bd9Sstevel@tonic-gate	# sometimes be excessive.  If there are errors, the bindings information
4757c478bd9Sstevel@tonic-gate	# is likely to be incomplete.
4767c478bd9Sstevel@tonic-gate	if ($Mult) {
4777c478bd9Sstevel@tonic-gate		print STDOUT "$File:\n";
4787c478bd9Sstevel@tonic-gate	}
4797c478bd9Sstevel@tonic-gate	if ($NoFound) {
4807c478bd9Sstevel@tonic-gate		my ($Cnt) = 4;
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate		for my $Line (@Ldd) {
4837c478bd9Sstevel@tonic-gate			if ($Line =~ /not found/) {
4847c478bd9Sstevel@tonic-gate				print STDOUT "$Line\n";
4857c478bd9Sstevel@tonic-gate				$Cnt--;
4867c478bd9Sstevel@tonic-gate			}
4877c478bd9Sstevel@tonic-gate			if ($Cnt == 0) {
4887c478bd9Sstevel@tonic-gate				print STDOUT gettext("\tcontinued ...\n");
4897c478bd9Sstevel@tonic-gate				last;
4907c478bd9Sstevel@tonic-gate			}
4917c478bd9Sstevel@tonic-gate		}
4927c478bd9Sstevel@tonic-gate	}
4937c478bd9Sstevel@tonic-gate
4947c478bd9Sstevel@tonic-gate	# If the user wants the original debugging file left behind, rename it
4957c478bd9Sstevel@tonic-gate	# so that it doesn't get re-read by another instance of lari processing
4967c478bd9Sstevel@tonic-gate	# this file.
4977c478bd9Sstevel@tonic-gate	if ($opt{s}) {
4987c478bd9Sstevel@tonic-gate		rename($DbgFile, $DbgSeed);
4997c478bd9Sstevel@tonic-gate		$DbgFile = $DbgSeed;
5007c478bd9Sstevel@tonic-gate		printf STDOUT gettext("%s: %s: bindings information " .
5017c478bd9Sstevel@tonic-gate		    "saved as: %s\n"), $Prog, $File, $DbgFile;
5027c478bd9Sstevel@tonic-gate	}
5037c478bd9Sstevel@tonic-gate
5047c478bd9Sstevel@tonic-gate	ProcBindings($File, $Mult, $DbgFile);
5057c478bd9Sstevel@tonic-gate
5067c478bd9Sstevel@tonic-gate	# Now that we've finished with the debugging file, nuke it if necessary.
5077c478bd9Sstevel@tonic-gate	if (!$opt{s}) {
5087c478bd9Sstevel@tonic-gate		unlink($DbgFile);
5097c478bd9Sstevel@tonic-gate	}
5107c478bd9Sstevel@tonic-gate	$DbgSeed = "";
5117c478bd9Sstevel@tonic-gate	return 1;
5127c478bd9Sstevel@tonic-gate}
5137c478bd9Sstevel@tonic-gate
5147c478bd9Sstevel@tonic-gatesub ProcBindings {
5157c478bd9Sstevel@tonic-gate	my ($File, $Mult, $DbgFile) = @_;
5167c478bd9Sstevel@tonic-gate	my (%Filtees, $FileHandle);
5177c478bd9Sstevel@tonic-gate
5187c478bd9Sstevel@tonic-gate	# Reinitialize our arrays when we're dealing with multiple files.
5197c478bd9Sstevel@tonic-gate	if ($Mult) {
5207c478bd9Sstevel@tonic-gate		%Symbols = ();
5217c478bd9Sstevel@tonic-gate		%Objects = ();
5227c478bd9Sstevel@tonic-gate		%Versioned = ();
5233906e0c2Srie		%DemSyms = ();
5243906e0c2Srie		%ObjFltrs = ();
5253906e0c2Srie		%SymFltes = ();
5267c478bd9Sstevel@tonic-gate	}
5277c478bd9Sstevel@tonic-gate
5287c478bd9Sstevel@tonic-gate	# As debugging output can be significant, read a line at a time.
5297c478bd9Sstevel@tonic-gate	open($FileHandle, "<$DbgFile");
5307c478bd9Sstevel@tonic-gate	while (defined(my $Line = <$FileHandle>)) {
5317c478bd9Sstevel@tonic-gate		chomp($Line);
5327c478bd9Sstevel@tonic-gate
5337c478bd9Sstevel@tonic-gate		# Collect the symbols from any file analyzed.
5347c478bd9Sstevel@tonic-gate		if ($Line =~ /^.*: file=(.*);  analyzing .*/) {
5357c478bd9Sstevel@tonic-gate			GetAllSymbols($1);
5367c478bd9Sstevel@tonic-gate			next;
5377c478bd9Sstevel@tonic-gate		}
5387c478bd9Sstevel@tonic-gate
5397c478bd9Sstevel@tonic-gate		# Process any symbolic relocations that bind to a file.
5407c478bd9Sstevel@tonic-gate		if ($Line =~ /: binding file=.* to file=/) {
5417c478bd9Sstevel@tonic-gate			my ($RefFile, $DstFile, $SymName);
5427c478bd9Sstevel@tonic-gate			my (@Syms, $Found, @Fields);
5437c478bd9Sstevel@tonic-gate			my ($BndInfo) = 0;
5447c478bd9Sstevel@tonic-gate			my ($Offset) = 1;
5457c478bd9Sstevel@tonic-gate			my ($Dlsym) = 0;
5467c478bd9Sstevel@tonic-gate			my ($Detail) = 0;
5477c478bd9Sstevel@tonic-gate
5487c478bd9Sstevel@tonic-gate			# For greatest flexibility, split the line into fields
5497c478bd9Sstevel@tonic-gate			# and walk each field until we find what we need.
5507c478bd9Sstevel@tonic-gate			@Fields = split(' ', $Line);
5517c478bd9Sstevel@tonic-gate
5523c4993fbSrie			# The referencing file, "... binding file=.* ".
5537c478bd9Sstevel@tonic-gate			while ($Fields[$Offset]) {
5547c478bd9Sstevel@tonic-gate				if ($Fields[$Offset] =~ /^file=(.*)/) {
5557c478bd9Sstevel@tonic-gate					$RefFile = $1;
5567c478bd9Sstevel@tonic-gate					$Offset++;
5577c478bd9Sstevel@tonic-gate					last;
5587c478bd9Sstevel@tonic-gate				}
5597c478bd9Sstevel@tonic-gate				$Offset++;
5607c478bd9Sstevel@tonic-gate			}
5617c478bd9Sstevel@tonic-gate			# The referencing offset, typically this is the address
5627c478bd9Sstevel@tonic-gate			# of the reference, "(0x1234...)", but in the case of a
5637c478bd9Sstevel@tonic-gate			# user lookup it's the string "(dlsym)".  If we don't
5647c478bd9Sstevel@tonic-gate			# find this offset information we've been given a debug
5653906e0c2Srie			# file that didn't use the "detail" token, in which case
5667c478bd9Sstevel@tonic-gate			# we're not getting all the information we need.
5677c478bd9Sstevel@tonic-gate			if ($Fields[$Offset] =~ /^\((.*)\)/) {
5687c478bd9Sstevel@tonic-gate				if ($1 eq 'dlsym') {
5697c478bd9Sstevel@tonic-gate					$Dlsym = 1;
5707c478bd9Sstevel@tonic-gate				}
5717c478bd9Sstevel@tonic-gate				$Detail = 1;
5727c478bd9Sstevel@tonic-gate				$Offset++;
5737c478bd9Sstevel@tonic-gate			}
5743c4993fbSrie			# The destination file, "... to file=.* ".  Note, in the
5753c4993fbSrie			# case of a rejection message, the file is terminated
5763c4993fbSrie			# with a colon, "... to file=.*: ", which must be
5773c4993fbSrie			# removed
5787c478bd9Sstevel@tonic-gate			while ($Fields[$Offset]) {
5797c478bd9Sstevel@tonic-gate				if ($Fields[$Offset] =~ /^file=(.*)/) {
5807c478bd9Sstevel@tonic-gate					$DstFile = $1;
5813c4993fbSrie					$DstFile =~ s/:$//;
5827c478bd9Sstevel@tonic-gate					$Offset++;
5837c478bd9Sstevel@tonic-gate					last;
5847c478bd9Sstevel@tonic-gate				}
5857c478bd9Sstevel@tonic-gate				$Offset++;
5867c478bd9Sstevel@tonic-gate			}
587*69112eddSAli Bahrami			# The symbol being bound. Over the years, we have used
588*69112eddSAli Bahrami			# a ` quoting style, and more recently a ' style.
589*69112eddSAli Bahrami			# Match either of:
590*69112eddSAli Bahrami			#	"... symbol `.*' ...".
591*69112eddSAli Bahrami			#	"... symbol '.*' ...".
5927c478bd9Sstevel@tonic-gate			while ($Fields[$Offset]) {
593*69112eddSAli Bahrami				if ($Fields[$Offset] =~ /^(\`|\')(.*)\'$/) {
594*69112eddSAli Bahrami					$SymName = $2;
5957c478bd9Sstevel@tonic-gate					$Offset++;
5967c478bd9Sstevel@tonic-gate					last;
5977c478bd9Sstevel@tonic-gate				}
5987c478bd9Sstevel@tonic-gate				$Offset++;
5997c478bd9Sstevel@tonic-gate			}
6003c4993fbSrie			# Possible trailing binding info, "... (direct,...", or
6013c4993fbSrie			# a rejection, "... (rejected - ...".
6027c478bd9Sstevel@tonic-gate			while ($Fields[$Offset]) {
6033c4993fbSrie				if ($Fields[$Offset] =~ /^\((.*)/) {
6047c478bd9Sstevel@tonic-gate					$BndInfo = $1;
6053c4993fbSrie					$Detail = 1;
6067c478bd9Sstevel@tonic-gate					$Offset++;
6077c478bd9Sstevel@tonic-gate					last;
6087c478bd9Sstevel@tonic-gate				}
6097c478bd9Sstevel@tonic-gate				$Offset++;
6107c478bd9Sstevel@tonic-gate			}
6117c478bd9Sstevel@tonic-gate
6127c478bd9Sstevel@tonic-gate			if ($Detail == 0) {
6137c478bd9Sstevel@tonic-gate				printf STDERR gettext("%s: %s: debug file " .
6147c478bd9Sstevel@tonic-gate				    "does not contain `detail' information\n"),
6157c478bd9Sstevel@tonic-gate				    $Prog, $DbgFile;
6167c478bd9Sstevel@tonic-gate				return;
6177c478bd9Sstevel@tonic-gate			}
6187c478bd9Sstevel@tonic-gate
6197c478bd9Sstevel@tonic-gate			# Collect the symbols from each object.
6207c478bd9Sstevel@tonic-gate			GetAllSymbols($RefFile);
6217c478bd9Sstevel@tonic-gate			GetAllSymbols($DstFile);
6227c478bd9Sstevel@tonic-gate
6237c478bd9Sstevel@tonic-gate			# Identify that this definition has been bound to.
6247c478bd9Sstevel@tonic-gate			$Symbols{$SymName}{$DstFile}[$ObjRef]++;
6257c478bd9Sstevel@tonic-gate			if ($RefFile eq $DstFile) {
6267c478bd9Sstevel@tonic-gate				# If the reference binds to a definition within
6277c478bd9Sstevel@tonic-gate				# the same file this symbol may be a candidate
6287c478bd9Sstevel@tonic-gate				# for reducing to local.
6297c478bd9Sstevel@tonic-gate				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Self;
6307c478bd9Sstevel@tonic-gate				$Objects{$DstFile}{$SymName} |= $Self;
6317c478bd9Sstevel@tonic-gate			} else {
6327c478bd9Sstevel@tonic-gate				# This symbol is required to satisfy an external
6337c478bd9Sstevel@tonic-gate				# reference.
6347c478bd9Sstevel@tonic-gate				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Extn;
6357c478bd9Sstevel@tonic-gate				$Objects{$DstFile}{$SymName} |= $Extn;
6367c478bd9Sstevel@tonic-gate			}
6377c478bd9Sstevel@tonic-gate
6387c478bd9Sstevel@tonic-gate			# Assign any other state indicated by the binding info
6397c478bd9Sstevel@tonic-gate			# associated with the diagnostic output.
6407c478bd9Sstevel@tonic-gate			if (!$BndInfo) {
6417c478bd9Sstevel@tonic-gate				next;
6427c478bd9Sstevel@tonic-gate			}
6437c478bd9Sstevel@tonic-gate
6447c478bd9Sstevel@tonic-gate			if ($BndInfo =~ /direct/) {
6457c478bd9Sstevel@tonic-gate				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Dirc;
6467c478bd9Sstevel@tonic-gate				$Objects{$DstFile}{$SymName} |= $Dirc;
6477c478bd9Sstevel@tonic-gate			}
6487c478bd9Sstevel@tonic-gate			if ($BndInfo =~ /copy-ref/) {
6497c478bd9Sstevel@tonic-gate				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Cpyr;
6507c478bd9Sstevel@tonic-gate				$Objects{$DstFile}{$SymName} |= $Cpyr;
6517c478bd9Sstevel@tonic-gate			}
6527c478bd9Sstevel@tonic-gate			if ($BndInfo =~ /filtee/) {
6533906e0c2Srie				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Gfte;
6543906e0c2Srie				$Objects{$DstFile}{$SymName} |= $Gfte;
6557c478bd9Sstevel@tonic-gate			}
6567c478bd9Sstevel@tonic-gate			if ($BndInfo =~ /interpose/) {
6577c478bd9Sstevel@tonic-gate				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Intp;
6587c478bd9Sstevel@tonic-gate				$Objects{$DstFile}{$SymName} |= $Intp;
6597c478bd9Sstevel@tonic-gate			}
6607c478bd9Sstevel@tonic-gate			if ($BndInfo =~ /plt-addr/) {
6617c478bd9Sstevel@tonic-gate				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Plta;
6627c478bd9Sstevel@tonic-gate				$Objects{$DstFile}{$SymName} |= $Plta;
6637c478bd9Sstevel@tonic-gate			}
6643c4993fbSrie			if ($BndInfo =~ /rejected/) {
6653c4993fbSrie				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Rejt;
6663c4993fbSrie				$Objects{$DstFile}{$SymName} |= $Rejt;
6673c4993fbSrie			}
6687c478bd9Sstevel@tonic-gate			if ($Dlsym) {
6697c478bd9Sstevel@tonic-gate				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $User;
6707c478bd9Sstevel@tonic-gate				$Objects{$DstFile}{$SymName} |= $User;
6717c478bd9Sstevel@tonic-gate			}
6727c478bd9Sstevel@tonic-gate		}
6737c478bd9Sstevel@tonic-gate	}
6747c478bd9Sstevel@tonic-gate	close($FileHandle);
6757c478bd9Sstevel@tonic-gate
6763906e0c2Srie	# Now that we've processed all objects, traverse the set of object
6773906e0c2Srie	# filters that have been captured from parsing any FILTER and AUXILIARY
6783906e0c2Srie	# dynamic tags.  For each filtee, determine which of the symbols it
6793906e0c2Srie	# exports are also defined in the filter.  If a filter is bound to, the
6807c478bd9Sstevel@tonic-gate	# runtime linkers diagnostics will indicate a filtee binding.  However,
6817c478bd9Sstevel@tonic-gate	# some of the filtee symbols may not be bound to, so here we mark them
6827c478bd9Sstevel@tonic-gate	# all so as to remove them from any interesting output.
6833906e0c2Srie	for my $Filter (keys(%ObjFltrs)) {
6847c478bd9Sstevel@tonic-gate
6853906e0c2Srie		# Determine the filtees that are associated with this filter.
6863906e0c2Srie		for my $Filtee (keys(%{$ObjFltrs{$Filter}})) {
6873906e0c2Srie			my ($FileName);
6883906e0c2Srie
6893906e0c2Srie			# Reduce the filtee to a simple file name.  Then, try
6903906e0c2Srie			# and associate this simple file name with the objects
6913906e0c2Srie			# that have been processed.  These objects are typically
6923906e0c2Srie			# recorded with a full path name.
6933906e0c2Srie			chomp($FileName = `basename $Filtee`);
6943906e0c2Srie			for my $Obj (keys(%Objects)) {
6953906e0c2Srie				if ($Obj =~ /\/$FileName$/) {
6963906e0c2Srie					$Filtee = $Obj;
6973906e0c2Srie					last;
6983906e0c2Srie				}
6993906e0c2Srie			}
7003906e0c2Srie
7017c478bd9Sstevel@tonic-gate			if (!exists($Objects{$Filtee})) {
7027c478bd9Sstevel@tonic-gate				next;
7037c478bd9Sstevel@tonic-gate			}
7047c478bd9Sstevel@tonic-gate
7053906e0c2Srie			# Traverse the symbols of the filtee (these are
7063906e0c2Srie			# typically a smaller set than the filter) and if the
7073906e0c2Srie			# symbol is defined by the filter tag the symbol as a
7083906e0c2Srie			# filtee.
7093906e0c2Srie			for my $SymName (keys(%{$Objects{$Filtee}})) {
7103906e0c2Srie				my ($OFlag, $FFlag);
7117c478bd9Sstevel@tonic-gate
7123906e0c2Srie				# Ignore the usual stuff.
7133906e0c2Srie				if (($SymName =~ $MultSyms) ||
7143906e0c2Srie				    ($SymName =~ $CrtSyms)) {
7157c478bd9Sstevel@tonic-gate					next;
7167c478bd9Sstevel@tonic-gate				}
7177c478bd9Sstevel@tonic-gate
7187c478bd9Sstevel@tonic-gate				if (!$Symbols{$SymName}{$Filter}) {
7197c478bd9Sstevel@tonic-gate					next;
7207c478bd9Sstevel@tonic-gate				}
7213906e0c2Srie
7223906e0c2Srie				# Determine the type of filter.
7233906e0c2Srie				$OFlag = $Symbols{$SymName}{$Filter}[$ObjFlag];
7243906e0c2Srie
7253906e0c2Srie				# Specifically identify the type of filtee we
7263906e0c2Srie				# have and remove any generic filtee flag.
7273906e0c2Srie				if ($OFlag & ($Osft | $Ssft)) {
7283906e0c2Srie					$FFlag = $Sfte;
7293906e0c2Srie				} else {
7303906e0c2Srie					$FFlag = $Afte;
7313906e0c2Srie				}
7323906e0c2Srie
7333906e0c2Srie				$Symbols{$SymName}{$Filtee}[$ObjFlag] |= $FFlag;
7343906e0c2Srie				$Symbols{$SymName}{$Filtee}[$ObjFlag] &= ~$Gfte;
7353906e0c2Srie			}
7363906e0c2Srie		}
7373906e0c2Srie	}
7383906e0c2Srie
7393906e0c2Srie	# Traverse the set of per-symbol filters making sure we've tagged any
7403906e0c2Srie	# associated filtee symbols, as we did above for object filters.
7413906e0c2Srie	for my $Filtee (keys(%SymFltes)) {
7423906e0c2Srie		my ($FullPath) = $Filtee;
7433906e0c2Srie		my ($FileName);
7443906e0c2Srie
7453906e0c2Srie		# Reduce the filtee to a simple file name.  Then, try and
7463906e0c2Srie		# associate this simple file name with the objects that have
7473906e0c2Srie		# been processed.  These objects are typically recorded with a
7483906e0c2Srie		# full path name.
7493906e0c2Srie		chomp($FileName = `basename $Filtee`);
7503906e0c2Srie		for my $Obj (keys(%Objects)) {
7513906e0c2Srie			if ($Obj =~ /\/$FileName$/) {
7523906e0c2Srie				$FullPath = $Obj;
7533906e0c2Srie				last;
7543906e0c2Srie			}
7553906e0c2Srie		}
7563906e0c2Srie
7573906e0c2Srie		if (!exists($Objects{$FullPath})) {
7587c478bd9Sstevel@tonic-gate			next;
7597c478bd9Sstevel@tonic-gate		}
7603906e0c2Srie
7613906e0c2Srie		for my $SymName (keys(%{$SymFltes{$Filtee}})) {
7623906e0c2Srie			my ($OFlag, $FFlag);
7633906e0c2Srie
7643906e0c2Srie			# Determine the type of filter.
7653906e0c2Srie			$OFlag = $SymFltes{$Filtee}{$SymName}[$SymFlag];
7663906e0c2Srie
7673906e0c2Srie			# Specifically identify the type of filtee we have and
7683906e0c2Srie			# remove any generic filtee flag.
7693906e0c2Srie			if ($OFlag & $Ssft) {
7703906e0c2Srie				$FFlag = $Sfte;
7713906e0c2Srie			} else {
7723906e0c2Srie				$FFlag = $Afte;
7737c478bd9Sstevel@tonic-gate			}
7743906e0c2Srie
7753906e0c2Srie			$Symbols{$SymName}{$FullPath}[$ObjFlag] |= $FFlag;
7763906e0c2Srie			$Symbols{$SymName}{$FullPath}[$ObjFlag] &= ~$Gfte;
7777c478bd9Sstevel@tonic-gate		}
7787c478bd9Sstevel@tonic-gate	}
7797c478bd9Sstevel@tonic-gate
7807c478bd9Sstevel@tonic-gate	# Process objects and their symbols as required.
7817c478bd9Sstevel@tonic-gate	if ($opt{m}) {
7827c478bd9Sstevel@tonic-gate		# If we're creating a mapfile, traverse each object we've
7837c478bd9Sstevel@tonic-gate		# collected.
7847c478bd9Sstevel@tonic-gate		foreach my $Obj (keys(%Objects)) {
7857c478bd9Sstevel@tonic-gate			my ($File, $Path);
7867c478bd9Sstevel@tonic-gate
787c1c6f601Srie			# Skip any objects that should be ignored.
7887c478bd9Sstevel@tonic-gate			if ($Obj =~ $Rtld) {
7897c478bd9Sstevel@tonic-gate				next;
7907c478bd9Sstevel@tonic-gate			}
7917c478bd9Sstevel@tonic-gate
7927c478bd9Sstevel@tonic-gate			# Skip any versioned objects if required.
7937c478bd9Sstevel@tonic-gate			if ($opt{v} && $Versioned{$Obj}) {
7947c478bd9Sstevel@tonic-gate				next;
7957c478bd9Sstevel@tonic-gate			}
7967c478bd9Sstevel@tonic-gate
7977c478bd9Sstevel@tonic-gate			# Open the mapfile if required.
7987c478bd9Sstevel@tonic-gate			$File = basename($Obj);
7997c478bd9Sstevel@tonic-gate			$Path = "$DestDir/mapfile-$File";
8007c478bd9Sstevel@tonic-gate			if (!open(MAPOUT, "> $Path")) {
8017c478bd9Sstevel@tonic-gate				printf STDERR gettext("%s: %s: open failed:" .
8027c478bd9Sstevel@tonic-gate				    "%s\n"), $Prog, $Path, $!;
8037c478bd9Sstevel@tonic-gate				exit 1;
8047c478bd9Sstevel@tonic-gate			}
8057c478bd9Sstevel@tonic-gate
8067c478bd9Sstevel@tonic-gate			# Establish the mapfile preamble.
8077c478bd9Sstevel@tonic-gate			print MAPOUT "#\n# Interface Definition mapfile for:\n";
8087c478bd9Sstevel@tonic-gate			print MAPOUT "#\tDynamic Object: $Obj\n";
8097c478bd9Sstevel@tonic-gate			print MAPOUT "#\tProcess:        $File\n#\n\n";
8107c478bd9Sstevel@tonic-gate
8117c478bd9Sstevel@tonic-gate			# Process each global symbol.
8127c478bd9Sstevel@tonic-gate			print MAPOUT "$File {\n\tglobal:\n";
8137c478bd9Sstevel@tonic-gate
8147c478bd9Sstevel@tonic-gate			foreach my $SymName (sort(keys(%{$Objects{$Obj}}))) {
8157c478bd9Sstevel@tonic-gate				my ($Flag) = $Objects{$Obj}{$SymName};
8167c478bd9Sstevel@tonic-gate
8177c478bd9Sstevel@tonic-gate				# For the first pass we're only interested in
8187c478bd9Sstevel@tonic-gate				# symbols that have been bound to from an
8197c478bd9Sstevel@tonic-gate				# external object, or must be global to enable
8207c478bd9Sstevel@tonic-gate				# a binding to an interposing definition.
8213906e0c2Srie				# Skip bindings to ourself, as these are
8227c478bd9Sstevel@tonic-gate				# candidates for demoting to local.
8237c478bd9Sstevel@tonic-gate				if (!($Flag & ($Extn | $Intp))) {
8247c478bd9Sstevel@tonic-gate					next;
8257c478bd9Sstevel@tonic-gate				}
8267c478bd9Sstevel@tonic-gate				if (($Flag & ($Extn | $Self)) == $Self) {
8277c478bd9Sstevel@tonic-gate					next;
8287c478bd9Sstevel@tonic-gate				}
8297c478bd9Sstevel@tonic-gate
8307c478bd9Sstevel@tonic-gate				# Add the demangled name as a comment if
8317c478bd9Sstevel@tonic-gate				# required.
8327c478bd9Sstevel@tonic-gate				if ($opt{C}) {
8337c478bd9Sstevel@tonic-gate					my ($DemName) = Demangle($SymName);
8347c478bd9Sstevel@tonic-gate
8357c478bd9Sstevel@tonic-gate					if ($DemName ne "") {
8367c478bd9Sstevel@tonic-gate						print MAPOUT "\t\t#$DemName\n";
8377c478bd9Sstevel@tonic-gate					}
8387c478bd9Sstevel@tonic-gate				}
8397c478bd9Sstevel@tonic-gate				print MAPOUT "\t\t$SymName;\n";
8407c478bd9Sstevel@tonic-gate			}
8417c478bd9Sstevel@tonic-gate
8427c478bd9Sstevel@tonic-gate			# Process each local demotion.
8437c478bd9Sstevel@tonic-gate			print MAPOUT "\tlocal:\n";
8447c478bd9Sstevel@tonic-gate
8457c478bd9Sstevel@tonic-gate			if ($opt{o}) {
8467c478bd9Sstevel@tonic-gate				foreach my $SymName
8477c478bd9Sstevel@tonic-gate				    (sort(keys(%{$Objects{$Obj}}))) {
8487c478bd9Sstevel@tonic-gate					my ($Flag) = $Objects{$Obj}{$SymName};
8497c478bd9Sstevel@tonic-gate
8507c478bd9Sstevel@tonic-gate					# For this pass we're only interested
8517c478bd9Sstevel@tonic-gate					# in symbol definitions that haven't
8527c478bd9Sstevel@tonic-gate					# been bound to, or have only been
8537c478bd9Sstevel@tonic-gate					# bound to from the same object.
8547c478bd9Sstevel@tonic-gate					if ($Flag & $Extn) {
8557c478bd9Sstevel@tonic-gate						next;
8567c478bd9Sstevel@tonic-gate					}
8577c478bd9Sstevel@tonic-gate
8587c478bd9Sstevel@tonic-gate					# Add the demangled name as a comment if
8597c478bd9Sstevel@tonic-gate					# required.
8607c478bd9Sstevel@tonic-gate					if ($opt{C}) {
8617c478bd9Sstevel@tonic-gate						my ($DemName) =
8627c478bd9Sstevel@tonic-gate						    Demangle($SymName);
8637c478bd9Sstevel@tonic-gate
8647c478bd9Sstevel@tonic-gate						if ($DemName ne "") {
8657c478bd9Sstevel@tonic-gate							print MAPOUT
8667c478bd9Sstevel@tonic-gate							    "\t\t#$DemName\n";
8677c478bd9Sstevel@tonic-gate						}
8687c478bd9Sstevel@tonic-gate					}
8697c478bd9Sstevel@tonic-gate					print MAPOUT "\t\t$SymName;\n";
8707c478bd9Sstevel@tonic-gate				}
8717c478bd9Sstevel@tonic-gate			}
8727c478bd9Sstevel@tonic-gate
8737c478bd9Sstevel@tonic-gate			# Capture everything else as local.
8747c478bd9Sstevel@tonic-gate			print MAPOUT "\t\t\*;\n};\n";
8757c478bd9Sstevel@tonic-gate			close MAPOUT;
8767c478bd9Sstevel@tonic-gate		}
8777c478bd9Sstevel@tonic-gate
8787c478bd9Sstevel@tonic-gate	} else {
8797c478bd9Sstevel@tonic-gate		# If we're gathering information regarding the symbols used by
8807c478bd9Sstevel@tonic-gate		# the process, automatically sort any standard output using the
8817c478bd9Sstevel@tonic-gate		# symbol name.
8827c478bd9Sstevel@tonic-gate		if (!open(SORT, "| sort +1")) {
8837c478bd9Sstevel@tonic-gate			printf STDERR gettext("%s: fork failed: %s\n"),
8847c478bd9Sstevel@tonic-gate			    $Prog, $!;
8857c478bd9Sstevel@tonic-gate			exit 1;
8867c478bd9Sstevel@tonic-gate		}
8877c478bd9Sstevel@tonic-gate
8887c478bd9Sstevel@tonic-gate		foreach my $SymName (keys(%Symbols)) {
8897c478bd9Sstevel@tonic-gate			my ($Cnt);
8907c478bd9Sstevel@tonic-gate
8917c478bd9Sstevel@tonic-gate			# If we're looking for interesting symbols, inspect
8927c478bd9Sstevel@tonic-gate			# each definition of each symbol.  If one is found to
8937c478bd9Sstevel@tonic-gate			# be interesting, the whole family are printed.
8947c478bd9Sstevel@tonic-gate			if (($Cnt = Interesting($SymName)) == 0) {
8957c478bd9Sstevel@tonic-gate				next;
8967c478bd9Sstevel@tonic-gate			}
8977c478bd9Sstevel@tonic-gate
8987c478bd9Sstevel@tonic-gate			# We've found something interesting, or all symbols
8997c478bd9Sstevel@tonic-gate			# should be output.  List all objects that define this
9007c478bd9Sstevel@tonic-gate			# symbol.
9017c478bd9Sstevel@tonic-gate			foreach my $Obj (keys(%{$Symbols{$SymName}})) {
9027c478bd9Sstevel@tonic-gate				my ($DemName, $Type);
9037c478bd9Sstevel@tonic-gate				my ($Flag) = $Symbols{$SymName}{$Obj}[$ObjFlag];
9047c478bd9Sstevel@tonic-gate				my ($Str) = "$Cnt:";
90560758829Srie				my ($Vis);
90660758829Srie				my ($DisVis) = "";
9077c478bd9Sstevel@tonic-gate
9087c478bd9Sstevel@tonic-gate				# Do we just want overhead symbols.  Consider
9093c4993fbSrie				# copy-relocations, rejections, and plt address
9103c4993fbSrie				# binding, as overhead too.
9117c478bd9Sstevel@tonic-gate				if ($opt{o} && (($Flag &
9123c4993fbSrie				    ($Rejt | $Extn | $Cpyr | $Plta)) == $Extn)) {
9137c478bd9Sstevel@tonic-gate					next;
9147c478bd9Sstevel@tonic-gate				}
9157c478bd9Sstevel@tonic-gate
9167c478bd9Sstevel@tonic-gate				# Do we just want all symbols that have been
9177c478bd9Sstevel@tonic-gate				# bound to.
9187c478bd9Sstevel@tonic-gate				if (($opt{a} || $opt{o}) && $opt{b} &&
9197c478bd9Sstevel@tonic-gate				    (($Flag & ($Extn | $Self | $Prot)) == 0)) {
9207c478bd9Sstevel@tonic-gate					next;
9217c478bd9Sstevel@tonic-gate				}
9227c478bd9Sstevel@tonic-gate
9237c478bd9Sstevel@tonic-gate				# If we haven't been asked for all symbols, only
9247c478bd9Sstevel@tonic-gate				# print those reserved symbols that have been
9257c478bd9Sstevel@tonic-gate				# bound to, as the number of reserved symbols
9263906e0c2Srie				# can be quite excessive.  Also, remove any
9273906e0c2Srie				# standard filters, as nothing can bind to these
9283c4993fbSrie				# symbols anyway, provided they have not
9293c4993fbSrie				# contributed to a rejected binding.
9307c478bd9Sstevel@tonic-gate				if (!$opt{a} && ((($SymName =~ $MultSyms) &&
9317c478bd9Sstevel@tonic-gate				    (($Flag & ($Extn | $Self)) == 0)) ||
9327c478bd9Sstevel@tonic-gate				    (($SymName =~ $CrtSyms) && (($Flag &
9333906e0c2Srie				    ($Extn | $Self | $Prot)) == 0)) ||
9343c4993fbSrie				    (($Flag & ($Ssft | $Osft)) &&
9353c4993fbSrie				    (($Flag & $Rejt) == 0)))) {
9367c478bd9Sstevel@tonic-gate					next;
9377c478bd9Sstevel@tonic-gate				}
9387c478bd9Sstevel@tonic-gate
9397c478bd9Sstevel@tonic-gate				# Skip any versioned objects if required.
9407c478bd9Sstevel@tonic-gate				if ($opt{v} && $Versioned{$Obj}) {
9417c478bd9Sstevel@tonic-gate					next;
9427c478bd9Sstevel@tonic-gate				}
9437c478bd9Sstevel@tonic-gate
9447c478bd9Sstevel@tonic-gate				# Display this symbol.
9457c478bd9Sstevel@tonic-gate				if ($Symbols{$SymName}{$Obj}[$ObjRef]) {
9467c478bd9Sstevel@tonic-gate					$Str = $Str .
9477c478bd9Sstevel@tonic-gate					    $Symbols{$SymName}{$Obj}[$ObjRef];
9487c478bd9Sstevel@tonic-gate				} else {
9497c478bd9Sstevel@tonic-gate					$Str = $Str . '0';
9507c478bd9Sstevel@tonic-gate				}
9517c478bd9Sstevel@tonic-gate
9527c478bd9Sstevel@tonic-gate				# Has the symbol been bound to externally
9537c478bd9Sstevel@tonic-gate				if ($Flag & $Extn) {
9547c478bd9Sstevel@tonic-gate					$Str = $Str . 'E';
9557c478bd9Sstevel@tonic-gate				}
9567c478bd9Sstevel@tonic-gate				# Has the symbol been bound to from the same
9577c478bd9Sstevel@tonic-gate				# object.
9587c478bd9Sstevel@tonic-gate				if ($Flag & $Self) {
9597c478bd9Sstevel@tonic-gate					$Str = $Str . 'S';
9607c478bd9Sstevel@tonic-gate				}
9617c478bd9Sstevel@tonic-gate				# Has the symbol been bound to directly.
9627c478bd9Sstevel@tonic-gate				if ($Flag & $Dirc) {
9637c478bd9Sstevel@tonic-gate					$Str = $Str . 'D';
9647c478bd9Sstevel@tonic-gate				}
9657c478bd9Sstevel@tonic-gate				# Does this symbol originate for an explicit
9667c478bd9Sstevel@tonic-gate				# interposer.
9677c478bd9Sstevel@tonic-gate				if ($Flag & $Intp) {
9687c478bd9Sstevel@tonic-gate					$Str = $Str . 'I';
9697c478bd9Sstevel@tonic-gate				}
9707c478bd9Sstevel@tonic-gate				# Is this symbol the reference data of a copy
9717c478bd9Sstevel@tonic-gate				# relocation.
9727c478bd9Sstevel@tonic-gate				if ($Flag & $Cpyr) {
9737c478bd9Sstevel@tonic-gate					$Str = $Str . 'C';
9747c478bd9Sstevel@tonic-gate				}
9757c478bd9Sstevel@tonic-gate				# Is this symbol part of filtee.
9763906e0c2Srie				if ($Flag & ($Sfte | $Afte | $Gfte)) {
9777c478bd9Sstevel@tonic-gate					$Str = $Str . 'F';
9787c478bd9Sstevel@tonic-gate				}
9797c478bd9Sstevel@tonic-gate				# Is this symbol protected (in which case there
9807c478bd9Sstevel@tonic-gate				# may be a symbolic binding within the same
9817c478bd9Sstevel@tonic-gate				# object to this symbol).
9827c478bd9Sstevel@tonic-gate				if ($Flag & $Prot) {
9837c478bd9Sstevel@tonic-gate					$Str = $Str . 'P';
9847c478bd9Sstevel@tonic-gate				}
9857c478bd9Sstevel@tonic-gate				# Is this symbol an executables .plt address.
9867c478bd9Sstevel@tonic-gate				if ($Flag & $Plta) {
9877c478bd9Sstevel@tonic-gate					$Str = $Str . 'A';
9887c478bd9Sstevel@tonic-gate				}
9897c478bd9Sstevel@tonic-gate				# Does this binding originate from a user
9907c478bd9Sstevel@tonic-gate				# (dlsym) request.
9917c478bd9Sstevel@tonic-gate				if ($Flag & $User) {
9927c478bd9Sstevel@tonic-gate					$Str = $Str . 'U';
9937c478bd9Sstevel@tonic-gate				}
9947c478bd9Sstevel@tonic-gate				# Does this definition redirect the binding.
9957c478bd9Sstevel@tonic-gate				if ($Flag & $Msft) {
9967c478bd9Sstevel@tonic-gate					$Str = $Str . 'R';
9977c478bd9Sstevel@tonic-gate				}
9983906e0c2Srie				# Does this definition explicitly define no
9997c478bd9Sstevel@tonic-gate				# direct binding.
10007c478bd9Sstevel@tonic-gate				if ($Flag & $Nodi) {
10017c478bd9Sstevel@tonic-gate					$Str = $Str . 'N';
10027c478bd9Sstevel@tonic-gate				}
10033c4993fbSrie				# Was a binding to this definition rejected at
10043c4993fbSrie				# some point.
10053c4993fbSrie				if ($Flag & $Rejt) {
10063c4993fbSrie					$Str = $Str . 'r';
10073c4993fbSrie				}
10087c478bd9Sstevel@tonic-gate
10097c478bd9Sstevel@tonic-gate				# Determine whether this is a function or a data
10107c478bd9Sstevel@tonic-gate				# object.  For the latter, display the symbol
10117c478bd9Sstevel@tonic-gate				# size.  Otherwise, the symbol is a reserved
10127c478bd9Sstevel@tonic-gate				# label, and is left untyped.
10137c478bd9Sstevel@tonic-gate				if ($Flag & $Func) {
10147c478bd9Sstevel@tonic-gate					$Type = '()';
10157c478bd9Sstevel@tonic-gate				} elsif ($Flag & $Objt) {
10167c478bd9Sstevel@tonic-gate					$Type = '[' .
10177c478bd9Sstevel@tonic-gate					    $Symbols{$SymName}{$Obj}[$ObjSize] .
10187c478bd9Sstevel@tonic-gate					']';
10197c478bd9Sstevel@tonic-gate				} else {
10207c478bd9Sstevel@tonic-gate					$Type = "";
10217c478bd9Sstevel@tonic-gate				}
10227c478bd9Sstevel@tonic-gate
10237c478bd9Sstevel@tonic-gate				# Demangle the symbol name if desired.
10247c478bd9Sstevel@tonic-gate				$DemName = Demangle($SymName);
10257c478bd9Sstevel@tonic-gate
102660758829Srie				# If symbol visibility differences are
102760758829Srie				# interesting, append the verbose representation
102860758829Srie				# of any interesting visibilities.
102960758829Srie				$Vis = $Symbols{$SymName}{$Obj}[$ObjVis];
103060758829Srie				if ($opt{V} && $Vis) {
103160758829Srie					if ($Vis =~ 'S') {
103260758829Srie						$DisVis = "  (singleton)";
103360758829Srie					} elsif ($Vis =~ 'P') {
103460758829Srie						$DisVis = "  (protected)";
103560758829Srie					}
103660758829Srie				}
10377c478bd9Sstevel@tonic-gate				if ($Mult) {
10387c478bd9Sstevel@tonic-gate					print SORT "  [$Str]: " .
103960758829Srie					    "$SymName$Type$DemName: " .
104060758829Srie					    "$Obj$DisVis\n";
10417c478bd9Sstevel@tonic-gate				} else {
10427c478bd9Sstevel@tonic-gate					print SORT "[$Str]: " .
104360758829Srie					    "$SymName$Type$DemName: " .
104460758829Srie					    "$Obj$DisVis\n";
10457c478bd9Sstevel@tonic-gate				}
10467c478bd9Sstevel@tonic-gate			}
10477c478bd9Sstevel@tonic-gate		}
10487c478bd9Sstevel@tonic-gate		close SORT;
10497c478bd9Sstevel@tonic-gate	}
10507c478bd9Sstevel@tonic-gate}
10517c478bd9Sstevel@tonic-gate
10527c478bd9Sstevel@tonic-gate# Heuristics to determine whether a symbol binding is interesting.  In most
10537c478bd9Sstevel@tonic-gate# applications there can be a large amount of symbol binding information to
10547c478bd9Sstevel@tonic-gate# wade through.  The most typical binding, to a single definition, probably
10557c478bd9Sstevel@tonic-gate# isn't interesting or the cause of unexpected behavior.  Here, we try and
10567c478bd9Sstevel@tonic-gate# determine those bindings that may can cause unexpected behavior.
10577c478bd9Sstevel@tonic-gate#
10587c478bd9Sstevel@tonic-gate# Note, this routine is actually called for all symbols so that their count
10597c478bd9Sstevel@tonic-gate# can be calculated in one place.
10607c478bd9Sstevel@tonic-gatesub Interesting
10617c478bd9Sstevel@tonic-gate{
10627c478bd9Sstevel@tonic-gate	my ($SymName) = @_;
10637c478bd9Sstevel@tonic-gate	my ($ObjCnt, $GFlags, $BndCnt, $FltCnt, $NodiCnt, $RdirCnt, $ExRef);
10643c4993fbSrie	my ($RejCnt, $TotCnt);
10657c478bd9Sstevel@tonic-gate
10667c478bd9Sstevel@tonic-gate	# Scan all definitions of this symbol, thus determining the definition
10677c478bd9Sstevel@tonic-gate	# count, the number of filters, redirections, executable references
10687c478bd9Sstevel@tonic-gate	# (copy-relocations, or plt addresses), no-direct bindings, and the
10697c478bd9Sstevel@tonic-gate	# number of definitions that have been bound to.
10707c478bd9Sstevel@tonic-gate	$ObjCnt = $GFlags = $BndCnt = $FltCnt =
10713c4993fbSrie	    $NodiCnt = $RdirCnt = $ExRef = $RejCnt = $TotCnt = 0;
10727c478bd9Sstevel@tonic-gate	foreach my $Obj (keys(%{$Symbols{$SymName}})) {
10737c478bd9Sstevel@tonic-gate		my ($Flag) = $Symbols{$SymName}{$Obj}[$ObjFlag];
10747c478bd9Sstevel@tonic-gate
10753906e0c2Srie		$TotCnt++;
10763906e0c2Srie
10777c478bd9Sstevel@tonic-gate		# Ignore standard filters when determining the symbol count, as
10787c478bd9Sstevel@tonic-gate		# a standard filter can never be bound to.
10797c478bd9Sstevel@tonic-gate		if (($Flag & ($Osft | $Ssft)) == 0) {
10807c478bd9Sstevel@tonic-gate			$ObjCnt++;
10817c478bd9Sstevel@tonic-gate		}
10827c478bd9Sstevel@tonic-gate
10833906e0c2Srie		# If we're only looking at interesting objects, then standard
10843906e0c2Srie		# filters are ignored, so suppress any standard filtee tagging.
10853906e0c2Srie		if (!$opt{a}) {
10863906e0c2Srie			$Flag = $Symbols{$SymName}{$Obj}[$ObjFlag] &= ~$Sfte;
10873906e0c2Srie		}
10883906e0c2Srie
10897c478bd9Sstevel@tonic-gate		$GFlags |= $Flag;
10903906e0c2Srie		if ($Flag & ($Sfte | $Afte | $Gfte)) {
10917c478bd9Sstevel@tonic-gate			$FltCnt++;
10927c478bd9Sstevel@tonic-gate		}
10937c478bd9Sstevel@tonic-gate		if ($Flag & $Nodi) {
10947c478bd9Sstevel@tonic-gate			$NodiCnt++;
10957c478bd9Sstevel@tonic-gate		}
10967c478bd9Sstevel@tonic-gate		if ($Flag & ($Cpyr | $Plta)) {
10977c478bd9Sstevel@tonic-gate			$ExRef++;
10987c478bd9Sstevel@tonic-gate		}
10997c478bd9Sstevel@tonic-gate		if ($Flag & $Msft) {
11007c478bd9Sstevel@tonic-gate			$RdirCnt++;
11017c478bd9Sstevel@tonic-gate		}
11023c4993fbSrie		if ($Flag & $Rejt) {
11033c4993fbSrie			$RejCnt++;
11043c4993fbSrie		}
11057c478bd9Sstevel@tonic-gate
11067c478bd9Sstevel@tonic-gate		# Ignore bindings to undefined .plts, and copy-relocation
11077c478bd9Sstevel@tonic-gate		# references.  These are implementation details, rather than
11087c478bd9Sstevel@tonic-gate		# a truly interesting multiple-binding.  If a symbol is tagged
11097c478bd9Sstevel@tonic-gate		# as protected, count it as having bound to itself, even though
11107c478bd9Sstevel@tonic-gate		# we can't tell if it's really been used.
11117c478bd9Sstevel@tonic-gate		if (($Flag & ($Self | $Extn | $Prot)) &&
11127c478bd9Sstevel@tonic-gate		    (($Flag & ($Plta | $Cpyr)) == 0)) {
11137c478bd9Sstevel@tonic-gate			$BndCnt++;
11147c478bd9Sstevel@tonic-gate		}
11157c478bd9Sstevel@tonic-gate	}
11167c478bd9Sstevel@tonic-gate
11177010c12aSrie	# If we want all overhead symbols, return the count.
11187010c12aSrie	if ($opt{o}) {
11197010c12aSrie		return $ObjCnt;
11207010c12aSrie	}
11217010c12aSrie
11227010c12aSrie	# If we want all symbols, return the count.  If we want all bound
11237010c12aSrie	# symbols, return the count provided it is non-zero.
11247010c12aSrie	if ($opt{a} && (!$opt{b} || ($BndCnt > 0))) {
11253906e0c2Srie		return $TotCnt;
11267c478bd9Sstevel@tonic-gate	}
11277c478bd9Sstevel@tonic-gate
11283c4993fbSrie	# Any rejected symbol is interesting
11293c4993fbSrie	if ($RejCnt) {
11303c4993fbSrie		return $TotCnt;
11313c4993fbSrie	}
11323c4993fbSrie
11337c478bd9Sstevel@tonic-gate	# Single instance symbol definitions aren't very interesting.
11347c478bd9Sstevel@tonic-gate	if ($ObjCnt == 1) {
11357c478bd9Sstevel@tonic-gate		return 0;
11367c478bd9Sstevel@tonic-gate	}
11377c478bd9Sstevel@tonic-gate
11387c478bd9Sstevel@tonic-gate	# Traverse each symbol definition looking for the following:
11397c478bd9Sstevel@tonic-gate	#
11407c478bd9Sstevel@tonic-gate	#   .	Multiple symbols are bound to externally.
11417c478bd9Sstevel@tonic-gate	#   .	A symbol is bound to externally, and possibly symbolically.
11427c478bd9Sstevel@tonic-gate	#
11437c478bd9Sstevel@tonic-gate	# Two symbol bindings are acceptable in some cases, and thus aren't
11447c478bd9Sstevel@tonic-gate	# interesting:
11457c478bd9Sstevel@tonic-gate	#
11467c478bd9Sstevel@tonic-gate	#   .	Copy relocations.  Here, the executable binds to a shared object
11477c478bd9Sstevel@tonic-gate	#	to access the data definition, which is then copied to the
11487c478bd9Sstevel@tonic-gate	#	executable.  All other references should then bind to the copied
11497c478bd9Sstevel@tonic-gate	#	data.
11507c478bd9Sstevel@tonic-gate	#   .	Non-plt relocations to functions that are referenced by the
11517c478bd9Sstevel@tonic-gate	#	executable will bind to the .plt in the executable.  This
11527c478bd9Sstevel@tonic-gate	#	provides for address comparison calculations (although plainly
11537c478bd9Sstevel@tonic-gate	#	an overhead).
11547c478bd9Sstevel@tonic-gate	#
11557c478bd9Sstevel@tonic-gate	# Multiple symbol bindings are acceptable in some cases, and thus aren't
11567c478bd9Sstevel@tonic-gate	# interesting:
11577c478bd9Sstevel@tonic-gate	#
11587c478bd9Sstevel@tonic-gate	#   .	Filtees.  Multiple filtees may exist for one filter.
11597c478bd9Sstevel@tonic-gate	#
11607c478bd9Sstevel@tonic-gate	if ((($ObjCnt == 2) && ($GFlags & ($Cpyr | $Plta))) ||
11617c478bd9Sstevel@tonic-gate	    ($ObjCnt == ($FltCnt + 1))) {
11627c478bd9Sstevel@tonic-gate		return 0;
11637c478bd9Sstevel@tonic-gate	}
11647c478bd9Sstevel@tonic-gate
11657010c12aSrie	# Only display any reserved symbols if more than one binding has
11667010c12aSrie	# occurred.
11677010c12aSrie	if ((($SymName =~ $MultSyms) || ($SymName =~ $CrtSyms)) &&
11687c478bd9Sstevel@tonic-gate	    ($BndCnt < 2)) {
11697c478bd9Sstevel@tonic-gate		return (0);
11707c478bd9Sstevel@tonic-gate	}
11717c478bd9Sstevel@tonic-gate
11727010c12aSrie	# For all other symbols, determine whether a binding has occurred.
11737010c12aSrie	# Note: definitions within an executable are tagged as protected ("P")
11747010c12aSrie	# as they may have been bound to from within the executable - we can't
11757010c12aSrie	# tell.
11767010c12aSrie	if ($opt{b} && ($BndCnt == 0)) {
11777010c12aSrie		return (0);
11787010c12aSrie	}
11797010c12aSrie
11807c478bd9Sstevel@tonic-gate	# Multiple instances of a definition, where all but one are filter
11817c478bd9Sstevel@tonic-gate	# references and/or copy relocations, are also uninteresting.
11827c478bd9Sstevel@tonic-gate	# Effectively, only one symbol is providing the final binding.
11837c478bd9Sstevel@tonic-gate	if (($FltCnt && $RdirCnt) &&
11847c478bd9Sstevel@tonic-gate	    (($FltCnt + $RdirCnt + $ExRef) == $ObjCnt)) {
11857c478bd9Sstevel@tonic-gate		return (0);
11867c478bd9Sstevel@tonic-gate	}
11877c478bd9Sstevel@tonic-gate
11887c478bd9Sstevel@tonic-gate	# Multiple instances of explicitly defined no-direct binding symbols
11897c478bd9Sstevel@tonic-gate	# are known to occur, and their no-binding definition indicates they
11907c478bd9Sstevel@tonic-gate	# are expected and accounted for.  Thus, these aren't interesting.
11917c478bd9Sstevel@tonic-gate	if (($ExRef + $NodiCnt) == $ObjCnt) {
11927c478bd9Sstevel@tonic-gate		return (0);
11937c478bd9Sstevel@tonic-gate	}
11947c478bd9Sstevel@tonic-gate
11957c478bd9Sstevel@tonic-gate	# We have an interesting symbol, returns its count.
11967c478bd9Sstevel@tonic-gate	return $ObjCnt;
11977c478bd9Sstevel@tonic-gate}
11987c478bd9Sstevel@tonic-gate
11997c478bd9Sstevel@tonic-gate# Obtain the global symbol definitions of an object and determine whether the
12007c478bd9Sstevel@tonic-gate# object has been versioned.
12017c478bd9Sstevel@tonic-gatesub GetAllSymbols {
12027c478bd9Sstevel@tonic-gate	my ($Obj) = @_;
12033906e0c2Srie	my ($Type, $FileHandle);
12047c478bd9Sstevel@tonic-gate	my (%AddrToName, %NameToAddr);
12053906e0c2Srie	my ($Exec) = 0;
12067c478bd9Sstevel@tonic-gate	my ($Symb) = 0;
12077c478bd9Sstevel@tonic-gate	my ($Copy) = 0;
12087c478bd9Sstevel@tonic-gate	my ($Interpose) = 0;
12097c478bd9Sstevel@tonic-gate	my ($Fltr) = 0;
12103906e0c2Srie	my ($Ehdr) = 0;
12113906e0c2Srie	my ($Dyn) = 0;
12123906e0c2Srie	my ($Rel) = 0;
12133906e0c2Srie	my ($Info) = 0;
12147c478bd9Sstevel@tonic-gate
12157c478bd9Sstevel@tonic-gate	# Determine whether we've already retrieved this object's symbols.
12167c478bd9Sstevel@tonic-gate	# Also, ignore the runtime linker, it's on a separate link-map, and
12177c478bd9Sstevel@tonic-gate	# except for the filtee symbols that might be bound via libdl, is
12187010c12aSrie	# uninteresting.  Tag the runtime linker as versioned to simplify
12197010c12aSrie	# possible -v processing.
12207010c12aSrie	if ($Objects{$Obj}) {
12217010c12aSrie		return;
12227010c12aSrie	}
12237010c12aSrie
12247010c12aSrie	if ($Obj =~ $Rtld) {
12257010c12aSrie		$Versioned{$Obj} = 1;
12267c478bd9Sstevel@tonic-gate		return;
12277c478bd9Sstevel@tonic-gate	}
12287c478bd9Sstevel@tonic-gate
12293906e0c2Srie	# Get as much ELF information as we can from elfdump(1).  A second
12303906e0c2Srie	# invocation of elfdump(1) is required to obtain the symbol table, whose
12313906e0c2Srie	# processing can be affected by states determined during this pass.
12323906e0c2Srie	#
12333906e0c2Srie	# The information required:
12343906e0c2Srie	#	-e	ELF header provides the file type
12353906e0c2Srie	#	-d	dynamic information provides filter names
12363906e0c2Srie	#	-r	relocations provide for copy relocations
1237090a8d9eSAli Bahrami	#	-v	object versioning
12383906e0c2Srie	#	-y	symbol information section provide pre-symbol filters
12393906e0c2Srie	#		and direct binding information
12403906e0c2Srie	#
12413906e0c2Srie	# As this information can be quite large, process the elfdump(1) output
12423906e0c2Srie	# through a pipe.
1243090a8d9eSAli Bahrami	open($FileHandle, "LC_ALL=C elfdump -edrvy '$Obj' 2> /dev/null |");
12447c478bd9Sstevel@tonic-gate
12453906e0c2Srie	while (defined(my $Line = <$FileHandle>)) {
12463906e0c2Srie		my (@Fields);
12477c478bd9Sstevel@tonic-gate
12483906e0c2Srie		chomp($Line);
12493906e0c2Srie
12503906e0c2Srie		# Each collection of data is preceded with a title that
12513906e0c2Srie		# starts in column 0.  Items of data all have some form of
12523906e0c2Srie		# indentation.
12533906e0c2Srie		if ($Line =~ /^[A-Z]/) {
12543906e0c2Srie			if ($Line =~ /^ELF Header/) {
12553906e0c2Srie				$Ehdr = 1;
12563906e0c2Srie				$Dyn = $Rel = $Info = 0;
12573906e0c2Srie			} elsif ($Line =~ /^Dynamic Section:/) {
12583906e0c2Srie				$Dyn = 1;
12593906e0c2Srie				$Ehdr = $Rel = $Info = 0;
12603906e0c2Srie			} elsif ($Line =~ /^Relocation Section:/) {
12613906e0c2Srie				$Rel = 1;
12623906e0c2Srie				$Ehdr = $Dyn = $Info = 0;
12633906e0c2Srie			} elsif ($Line =~ /^Syminfo Section:/) {
12643906e0c2Srie				$Info = 1;
12653906e0c2Srie				$Ehdr = $Dyn = $Rel = 0;
1266090a8d9eSAli Bahrami			} elsif ($Line =~ /^Version Definition Section:/) {
1267090a8d9eSAli Bahrami				# The existance of a VERDEF section is all we
1268090a8d9eSAli Bahrami				# are looking for. There is no need to parse
1269090a8d9eSAli Bahrami				# the specific version definitions.
1270090a8d9eSAli Bahrami				$Versioned{$Obj} = 1;
1271090a8d9eSAli Bahrami			    	$Ehdr = $Dyn = $Rel = $Info = 0;
12723906e0c2Srie			} else {
12733906e0c2Srie				$Ehdr = $Dyn = $Rel = $Info = 0;
12743906e0c2Srie			}
12753906e0c2Srie			next;
12767c478bd9Sstevel@tonic-gate		}
12777c478bd9Sstevel@tonic-gate
12783906e0c2Srie		# Inspect the ELF header.
12793906e0c2Srie		if ($Ehdr eq 1) {
12803906e0c2Srie			# Determine the ELF file type from the e_type element.
12813906e0c2Srie			if ($Line =~ /e_type:/) {
12823906e0c2Srie				if ($Line =~ /ET_EXEC/) {
12833906e0c2Srie					$Exec = 1;
12843906e0c2Srie				}
12853906e0c2Srie
12863906e0c2Srie				# There's nothing of interest left in the ELF
12873906e0c2Srie				# header, so skip processing other entries.
12883906e0c2Srie				$Ehdr = 0;
12893906e0c2Srie				next;
12903906e0c2Srie			}
12913906e0c2Srie		}
12923906e0c2Srie
12933906e0c2Srie		# Inspect the .dynamic section.
12943906e0c2Srie		if ($Dyn eq 1) {
12957c478bd9Sstevel@tonic-gate			@Fields = split(' ', $Line);
12967c478bd9Sstevel@tonic-gate
12973906e0c2Srie			# Determine if the FILTER or AUXILIARY tag is set.
12987c478bd9Sstevel@tonic-gate			if ($#Fields == 3) {
12993906e0c2Srie				my ($Flte) = 0;
13003906e0c2Srie
13013906e0c2Srie				if ($Fields[1] eq 'FILTER') {
13027c478bd9Sstevel@tonic-gate					$Fltr |= $Osft;
13033906e0c2Srie					$Flte = 1;
13043906e0c2Srie				}
13053906e0c2Srie				elsif ($Fields[1] eq 'AUXILIARY') {
13063906e0c2Srie					$Fltr |= $Oaft;
13073906e0c2Srie					$Flte = 1;
13083906e0c2Srie				}
13093906e0c2Srie				if ($Flte eq 1) {
13103906e0c2Srie					my (@Filtees) = split(':', $Fields[3]);
13113906e0c2Srie
13123906e0c2Srie					for my $Filtee (@Filtees) {
13133906e0c2Srie						if ($Filtee =~ $Rtld) {
13147c478bd9Sstevel@tonic-gate							next;
13157c478bd9Sstevel@tonic-gate						}
13163906e0c2Srie						$ObjFltrs{$Obj}{$Filtee} = 1;
13173906e0c2Srie					}
13187c478bd9Sstevel@tonic-gate				}
13197c478bd9Sstevel@tonic-gate				next;
13207c478bd9Sstevel@tonic-gate			}
13217c478bd9Sstevel@tonic-gate
13227c478bd9Sstevel@tonic-gate			# We're only interested in the FLAGS entry.
13233906e0c2Srie			if (($#Fields < 4) || ($Fields[1] !~ /^FLAGS/)) {
13247c478bd9Sstevel@tonic-gate				next;
13257c478bd9Sstevel@tonic-gate			}
13263906e0c2Srie
13273906e0c2Srie			# Determine whether we've got a symbolicly bound object.
13283906e0c2Srie			# With newer link-editors, all symbols will be marked as
13293906e0c2Srie			# protected ("P"), but with older link-editors this
13303906e0c2Srie			# state could only be inferred from the symbolic dynamic
13313906e0c2Srie			# tag.
13323906e0c2Srie			if (($Fields[1] eq 'FLAGS') &&
13333906e0c2Srie			    ($Line =~ / SYMBOLIC /)) {
13347c478bd9Sstevel@tonic-gate				$Symb = 1;
13357c478bd9Sstevel@tonic-gate				next;
13367c478bd9Sstevel@tonic-gate			}
13373906e0c2Srie
13383906e0c2Srie			# Determine whether this object is an interposer.
13393906e0c2Srie			if (($Fields[1] eq 'FLAGS_1') &&
13409a411307Srie			    ($Line =~ / OBJECT-INTERPOSE /)) {
13417c478bd9Sstevel@tonic-gate				$Interpose = 1;
13427c478bd9Sstevel@tonic-gate				next;
13437c478bd9Sstevel@tonic-gate			}
13443906e0c2Srie			next;
13453906e0c2Srie		}
13463906e0c2Srie
13473906e0c2Srie		# Inspect the relocation information.  As we're only looking
13483906e0c2Srie		# for copy relocations, this processing is only necessary for
13493906e0c2Srie		# executables.
13503906e0c2Srie		if ($Rel eq 1) {
13513906e0c2Srie			my ($SymName);
13523906e0c2Srie
13533906e0c2Srie			if ($Exec eq 0) {
13543906e0c2Srie				$Rel = 0;
13553906e0c2Srie				next;
13563906e0c2Srie			}
13573906e0c2Srie
13583906e0c2Srie			# Obtain any copy relocations.
13593906e0c2Srie			if ($Line !~ / R_[A-Z0-9]+_COPY /) {
13603906e0c2Srie				next;
13613906e0c2Srie			}
13623906e0c2Srie
13633906e0c2Srie			@Fields = split(' ', $Line);
13643906e0c2Srie
13657010c12aSrie			# Intel relocation records don't contain an addend,
13667010c12aSrie			# where as every other supported platform does.
13677010c12aSrie			if ($Fields[0] eq 'R_386_COPY') {
13687c478bd9Sstevel@tonic-gate				$SymName = $Fields[3];
13697c478bd9Sstevel@tonic-gate			} else {
13707010c12aSrie				$SymName = $Fields[4];
13717c478bd9Sstevel@tonic-gate			}
13727c478bd9Sstevel@tonic-gate
13737c478bd9Sstevel@tonic-gate			$Symbols{$SymName}{$Obj}[$ObjFlag] |= $Cpyr;
13747c478bd9Sstevel@tonic-gate			$Objects{$Obj}{$SymName} |= $Cpyr;
13757c478bd9Sstevel@tonic-gate			$Copy = 1;
13767c478bd9Sstevel@tonic-gate		}
13773906e0c2Srie
13783906e0c2Srie		# Inspect the .SUNW_syminfo section.
13793906e0c2Srie		if ($Info eq 1) {
13803906e0c2Srie			my ($SymName);
13813906e0c2Srie			my ($Flags) = 0;
13823906e0c2Srie
13833906e0c2Srie			@Fields = split(' ', $Line);
13843906e0c2Srie
13853906e0c2Srie			# Binding attributes are in the second column.
13863906e0c2Srie			if ($#Fields < 1) {
13873906e0c2Srie				next;
13883906e0c2Srie			}
13893906e0c2Srie			if ($Fields[1] =~ /N/) {
13903906e0c2Srie				$Flags |= $Nodi;
13913906e0c2Srie			}
13923906e0c2Srie			if ($Fields[1] =~ /F/) {
13933906e0c2Srie				$Flags |= $Ssft;
13943906e0c2Srie			}
13953906e0c2Srie			if ($Fields[1] =~ /A/) {
13963906e0c2Srie				$Flags |= $Saft;
13977c478bd9Sstevel@tonic-gate			}
13989a411307Srie			if ($Fields[1] =~ /I/) {
13999a411307Srie				$Flags |= $Intp;
14009a411307Srie			}
14017c478bd9Sstevel@tonic-gate
14023906e0c2Srie			# Determine the symbol name based upon the number of
14033906e0c2Srie			# fields.
14043906e0c2Srie			if ($Flags) {
14053906e0c2Srie				$SymName = $Fields[$#Fields];
14063906e0c2Srie				$Symbols{$SymName}{$Obj}[$ObjFlag] |= $Flags;
14073906e0c2Srie				$Objects{$Obj}{$SymName} |= $Flags;
14083906e0c2Srie			}
14093906e0c2Srie
14103906e0c2Srie			# If this is a filter, we need to tag the associated
14113906e0c2Srie			# filtee symbol.  However, the filtee might not have
14123906e0c2Srie			# been processed yet, so save this information for later.
14139a411307Srie			$Flags &= ~($Nodi | $Intp);
14143906e0c2Srie			if ($Flags) {
14153906e0c2Srie				my ($Filtee) = $Fields[$#Fields - 1];
14163906e0c2Srie
14173906e0c2Srie				if ($Filtee =~ $Rtld) {
14183906e0c2Srie					next;
14193906e0c2Srie				}
14203906e0c2Srie				$SymFltes{$Filtee}{$SymName}[$SymFlag] = $Flags;
14213906e0c2Srie			}
14223906e0c2Srie		}
14233906e0c2Srie	}
14243906e0c2Srie
14253906e0c2Srie	close($FileHandle);
14263906e0c2Srie
14273906e0c2Srie	# If there's no expected information, it's possible we've been given a
14283906e0c2Srie	# debug output file and are processing the file from a location from
14293906e0c2Srie	# which the dependencies specified in the debug file aren't accessible.
14303906e0c2Srie	if ($Dyn eq 0) {
14313906e0c2Srie		printf STDERR gettext("%s: %s: unable to process ELF file\n"),
14323906e0c2Srie		    $Prog, $Obj;
14333906e0c2Srie
14343906e0c2Srie		# Add the file to our list, so that we don't create the same
14353906e0c2Srie		# message again.  Processing should continue so that we can
14363906e0c2Srie		# flush out as many error messages as possible.
14373906e0c2Srie		$Objects{$Obj}{"DoesNotExist"} = 0;
14383906e0c2Srie		return;
14393906e0c2Srie	}
14403906e0c2Srie
14417a5d89c4Sab196087	# Process elfdump(1) once more to obtain the .dynsym symbol table. We
14427a5d89c4Sab196087	# are only interested in global symbols, so .SUNW_ldynsym is not needed.
14437c478bd9Sstevel@tonic-gate	open($FileHandle, "LC_ALL=C elfdump -sN.dynsym '$Obj' 2> /dev/null |");
14447c478bd9Sstevel@tonic-gate
14457c478bd9Sstevel@tonic-gate	while (defined(my $Line = <$FileHandle>)) {
14467c478bd9Sstevel@tonic-gate		chomp($Line);
14477c478bd9Sstevel@tonic-gate
14487c478bd9Sstevel@tonic-gate		my (@Fields) = split(' ', $Line);
14497c478bd9Sstevel@tonic-gate		my ($Flags);
14507c478bd9Sstevel@tonic-gate
14513906e0c2Srie		# We're only interested in defined symbol entries.  Unless
14523906e0c2Srie		# we've been asked for all symbols, ignore any ABS or NOTY
14533906e0c2Srie		# symbols.  The former are typically reserved symbols or
14543906e0c2Srie		# versioning names.  The latter are labels that are not bound
14553906e0c2Srie		# to.  Note, ABS and NOTY symbols of non-zero size have been
14563906e0c2Srie		# known to occur, so capture them.
14577c478bd9Sstevel@tonic-gate		if (($#Fields < 8) || ($Fields[4] !~ $GlobWeak) ||
14583906e0c2Srie		    ($Fields[7] eq 'UNDEF') ||
14593906e0c2Srie		    (!$opt{a} && (oct($Fields[2]) eq 0) &&
14603906e0c2Srie		    ((($Fields[7] eq 'ABS') && ($Fields[3] eq 'OBJT')) ||
14613906e0c2Srie		    ($Fields[3] eq 'NOTY')))) {
14627c478bd9Sstevel@tonic-gate			next;
14637c478bd9Sstevel@tonic-gate		}
14647c478bd9Sstevel@tonic-gate
14653906e0c2Srie		# If we're found copy relocations, save the address of all OBJT
14663906e0c2Srie		# definitions, together with the copy symbol.  These definitions
14673906e0c2Srie		# are used to determine whether the copy symbol has any aliases
14683906e0c2Srie		# (ie. __iob and _iob).
14693906e0c2Srie		if (($Copy eq 1) && ($Fields[3] eq 'OBJT')) {
14707c478bd9Sstevel@tonic-gate			push(@{$AddrToName{$Fields[1]}}, $Fields[8]);
14713906e0c2Srie
14727c478bd9Sstevel@tonic-gate			if (($Symbols{$Fields[8]}{$Obj}) &&
14737c478bd9Sstevel@tonic-gate			    ($Symbols{$Fields[8]}{$Obj}[$ObjFlag] & $Cpyr)) {
14747c478bd9Sstevel@tonic-gate				$NameToAddr{$Fields[8]} = $Fields[1];
14757c478bd9Sstevel@tonic-gate			}
14763906e0c2Srie		}
14773906e0c2Srie
14783906e0c2Srie		# Identify this symbol as global, and associate it with any
14793906e0c2Srie		# object filtering.
14803906e0c2Srie		$Flags = $Glob | $Fltr;
14817c478bd9Sstevel@tonic-gate
14827c478bd9Sstevel@tonic-gate		# If the symbol visibility is protected, this is an internal
14833906e0c2Srie		# symbolic binding.  Note, an INTERNAL visibility for a global
14847c478bd9Sstevel@tonic-gate		# symbol is invalid, but for a while ld(1) was setting this
14853906e0c2Srie		# attribute mistakenly for protected.  If this is a dynamic
14863906e0c2Srie		# executable, mark its symbols as protected.  These symbols
14873906e0c2Srie		# can't be interposed on any more than symbols defined as
14887c478bd9Sstevel@tonic-gate		# protected within shared objects).
14897c478bd9Sstevel@tonic-gate		if (($Fields[5] =~ /^[IP]$/) || $Symb || $Exec) {
14907c478bd9Sstevel@tonic-gate			$Flags |= $Prot;
14917c478bd9Sstevel@tonic-gate		}
14927c478bd9Sstevel@tonic-gate
14937c478bd9Sstevel@tonic-gate		# If this object is marked as an interposer, tag each symbol.
14947c478bd9Sstevel@tonic-gate		if ($Interpose) {
14957c478bd9Sstevel@tonic-gate			$Flags |= $Intp;
14967c478bd9Sstevel@tonic-gate		}
14977c478bd9Sstevel@tonic-gate
14987c478bd9Sstevel@tonic-gate		# Identify the symbol as a function or data type, and for the
14993906e0c2Srie		# latter, capture the symbol size.  Ignore the standard symbolic
15003906e0c2Srie		# labels, as we don't want to type them.
15017c478bd9Sstevel@tonic-gate		if ($Fields[8] !~ $MultSyms) {
15027c478bd9Sstevel@tonic-gate			if ($Fields[3] =~ /^FUNC$/) {
15037c478bd9Sstevel@tonic-gate				$Flags |= $Func;
15047c478bd9Sstevel@tonic-gate			} elsif ($Fields[3] =~ /^OBJT$/) {
15057c478bd9Sstevel@tonic-gate				my ($Size) = $Fields[2];
15067c478bd9Sstevel@tonic-gate
15077c478bd9Sstevel@tonic-gate				if (oct($Size) eq 0) {
15087c478bd9Sstevel@tonic-gate					$Size = "0";
15097c478bd9Sstevel@tonic-gate				} else {
15107c478bd9Sstevel@tonic-gate					$Size =~ s/0x0*/0x/;
15117c478bd9Sstevel@tonic-gate				}
15127c478bd9Sstevel@tonic-gate				$Flags |= $Objt;
15137c478bd9Sstevel@tonic-gate				$Symbols{$Fields[8]}{$Obj}[$ObjSize] = $Size;
15147c478bd9Sstevel@tonic-gate			}
15157c478bd9Sstevel@tonic-gate		}
15167c478bd9Sstevel@tonic-gate
15177c478bd9Sstevel@tonic-gate		$Symbols{$Fields[8]}{$Obj}[$ObjFlag] |= $Flags;
151860758829Srie		$Symbols{$Fields[8]}{$Obj}[$ObjVis] = $Fields[5];
15197c478bd9Sstevel@tonic-gate		$Objects{$Obj}{$Fields[8]} |= $Flags;
15207c478bd9Sstevel@tonic-gate	}
15217c478bd9Sstevel@tonic-gate	close($FileHandle);
15227c478bd9Sstevel@tonic-gate
15233906e0c2Srie	# Process any copy relocation symbols to see if the copy symbol has any
15243906e0c2Srie	# aliases, which should also be marked as copy relocations.
15257c478bd9Sstevel@tonic-gate	if ($Copy) {
15267c478bd9Sstevel@tonic-gate		foreach my $SymName (keys(%NameToAddr)) {
15277c478bd9Sstevel@tonic-gate			my ($Addr) = $NameToAddr{$SymName};
15287c478bd9Sstevel@tonic-gate
15297c478bd9Sstevel@tonic-gate			# Determine all symbols that have the same address.
15307c478bd9Sstevel@tonic-gate			foreach my $AliasName (@{$AddrToName{$Addr}}) {
15317c478bd9Sstevel@tonic-gate				if ($SymName eq $AliasName) {
15327c478bd9Sstevel@tonic-gate					next;
15337c478bd9Sstevel@tonic-gate				}
15347c478bd9Sstevel@tonic-gate				$Symbols{$AliasName}{$Obj}[$ObjFlag] |= $Cpyr;
15357c478bd9Sstevel@tonic-gate				$Objects{$Obj}{$AliasName} |= $Cpyr;
15367c478bd9Sstevel@tonic-gate			}
15377c478bd9Sstevel@tonic-gate		}
15387c478bd9Sstevel@tonic-gate	}
15397c478bd9Sstevel@tonic-gate}
15407c478bd9Sstevel@tonic-gate
15417c478bd9Sstevel@tonic-gate# Demangle a symbol name if required.
15427c478bd9Sstevel@tonic-gatesub Demangle
15437c478bd9Sstevel@tonic-gate{
15447c478bd9Sstevel@tonic-gate	my ($SymName) = @_;
15457c478bd9Sstevel@tonic-gate	my ($DemName);
15467c478bd9Sstevel@tonic-gate
15477c478bd9Sstevel@tonic-gate	if ($opt{C}) {
15487c478bd9Sstevel@tonic-gate		my (@Dem);
15497c478bd9Sstevel@tonic-gate
15507c478bd9Sstevel@tonic-gate		# Determine if we've already demangled this name.
15517c478bd9Sstevel@tonic-gate		if (exists($DemSyms{$SymName})) {
15527c478bd9Sstevel@tonic-gate			return $DemSyms{$SymName};
15537c478bd9Sstevel@tonic-gate		}
15547c478bd9Sstevel@tonic-gate
15557c478bd9Sstevel@tonic-gate		@Dem = split(/\n/, `dem '$SymName'`);
15567c478bd9Sstevel@tonic-gate		foreach my $Line (@Dem) {
15577c478bd9Sstevel@tonic-gate			my (@Fields) = split(' ', $Line);
15587c478bd9Sstevel@tonic-gate
15597c478bd9Sstevel@tonic-gate			if (($#Fields < 2) || ($Fields[1] ne '==') ||
15607c478bd9Sstevel@tonic-gate			    ($Fields[0] eq $Fields[2])) {
15617c478bd9Sstevel@tonic-gate				next;
15627c478bd9Sstevel@tonic-gate			}
15637c478bd9Sstevel@tonic-gate			$DemName = $Line;
15647c478bd9Sstevel@tonic-gate			$DemName =~ s/.*== (.*)$/ \[$1]/;
15657c478bd9Sstevel@tonic-gate			$DemSyms{$SymName} = $DemName;
15667c478bd9Sstevel@tonic-gate			return($DemName);
15677c478bd9Sstevel@tonic-gate		}
15687c478bd9Sstevel@tonic-gate	}
15697c478bd9Sstevel@tonic-gate	$DemSyms{$SymName} = "";
15707c478bd9Sstevel@tonic-gate	return("");
15717c478bd9Sstevel@tonic-gate}
1572