xref: /titanic_52/usr/src/cmd/sgs/lari/lari.pl (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate#!/usr/perl5/bin/perl -w
2*7c478bd9Sstevel@tonic-gate#
3*7c478bd9Sstevel@tonic-gate# CDDL HEADER START
4*7c478bd9Sstevel@tonic-gate#
5*7c478bd9Sstevel@tonic-gate# The contents of this file are subject to the terms of the
6*7c478bd9Sstevel@tonic-gate# Common Development and Distribution License, Version 1.0 only
7*7c478bd9Sstevel@tonic-gate# (the "License").  You may not use this file except in compliance
8*7c478bd9Sstevel@tonic-gate# with the License.
9*7c478bd9Sstevel@tonic-gate#
10*7c478bd9Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11*7c478bd9Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing.
12*7c478bd9Sstevel@tonic-gate# See the License for the specific language governing permissions
13*7c478bd9Sstevel@tonic-gate# and limitations under the License.
14*7c478bd9Sstevel@tonic-gate#
15*7c478bd9Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each
16*7c478bd9Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17*7c478bd9Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the
18*7c478bd9Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying
19*7c478bd9Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner]
20*7c478bd9Sstevel@tonic-gate#
21*7c478bd9Sstevel@tonic-gate# CDDL HEADER END
22*7c478bd9Sstevel@tonic-gate#
23*7c478bd9Sstevel@tonic-gate#
24*7c478bd9Sstevel@tonic-gate# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25*7c478bd9Sstevel@tonic-gate# Use is subject to license terms.
26*7c478bd9Sstevel@tonic-gate#
27*7c478bd9Sstevel@tonic-gate# ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate#
29*7c478bd9Sstevel@tonic-gate# Link Analysis of Runtime Interfaces.
30*7c478bd9Sstevel@tonic-gate#
31*7c478bd9Sstevel@tonic-gate
32*7c478bd9Sstevel@tonic-gate# Define all global variables (required for strict)
33*7c478bd9Sstevel@tonic-gateuse vars  qw($Prog $DestDir $ObjRef $ObjFlag $ObjSize $TmpDir $LddArgs);
34*7c478bd9Sstevel@tonic-gateuse vars  qw($Glob $Intp $Cpyr $Prot $Extn $Self $Filt $Dirc $Plta $User $Func);
35*7c478bd9Sstevel@tonic-gateuse vars  qw($Objt $UndefSym $IgnSyms $Rtld $MultSyms $CrtSyms $GlobWeak);
36*7c478bd9Sstevel@tonic-gateuse vars  qw($DbgSeed %opt %Symbols %Objects %Versioned %DemSyms);
37*7c478bd9Sstevel@tonic-gateuse vars  qw($Platform $Nodi $Osft $Oaft $Ssft $Saft $Msft);
38*7c478bd9Sstevel@tonic-gate
39*7c478bd9Sstevel@tonic-gateuse strict;
40*7c478bd9Sstevel@tonic-gate
41*7c478bd9Sstevel@tonic-gateuse Getopt::Std;
42*7c478bd9Sstevel@tonic-gateuse File::Basename;
43*7c478bd9Sstevel@tonic-gate
44*7c478bd9Sstevel@tonic-gate# Pattern match to skip objects.
45*7c478bd9Sstevel@tonic-gate$Rtld = qr{ ^(?:
46*7c478bd9Sstevel@tonic-gate	/lib/ld\.so\.1 |
47*7c478bd9Sstevel@tonic-gate	/usr/lib/ld\.so\.1 |
48*7c478bd9Sstevel@tonic-gate	/lib/sparcv9/ld\.so\.1 |
49*7c478bd9Sstevel@tonic-gate	/usr/lib/sparcv9/ld\.so\.1
50*7c478bd9Sstevel@tonic-gate	)$
51*7c478bd9Sstevel@tonic-gate}x;
52*7c478bd9Sstevel@tonic-gate
53*7c478bd9Sstevel@tonic-gate# Pattern matching required to determine a global symbol.
54*7c478bd9Sstevel@tonic-gate$GlobWeak = qr{ ^(?:
55*7c478bd9Sstevel@tonic-gate	GLOB |
56*7c478bd9Sstevel@tonic-gate	WEAK
57*7c478bd9Sstevel@tonic-gate	)$
58*7c478bd9Sstevel@tonic-gate}x;
59*7c478bd9Sstevel@tonic-gate
60*7c478bd9Sstevel@tonic-gate# Pattern matching to determine link-editor specific symbols and those common
61*7c478bd9Sstevel@tonic-gate# to the compilation environment (ie. provided by all crt's).
62*7c478bd9Sstevel@tonic-gate$MultSyms = qr{ ^(?:
63*7c478bd9Sstevel@tonic-gate	 _DYNAMIC |
64*7c478bd9Sstevel@tonic-gate	 _GLOBAL_OFFSET_TABLE_ |
65*7c478bd9Sstevel@tonic-gate	 _PROCEDURE_LINKAGE_TABLE_ |
66*7c478bd9Sstevel@tonic-gate	 _etext |
67*7c478bd9Sstevel@tonic-gate	 _edata |
68*7c478bd9Sstevel@tonic-gate	 _end |
69*7c478bd9Sstevel@tonic-gate	 _init |
70*7c478bd9Sstevel@tonic-gate	 _fini |
71*7c478bd9Sstevel@tonic-gate	 _lib_version |			# Defined in values
72*7c478bd9Sstevel@tonic-gate	 __xpg4 |			# Defined in values
73*7c478bd9Sstevel@tonic-gate	 __xpg6				# Defined in values
74*7c478bd9Sstevel@tonic-gate	)$
75*7c478bd9Sstevel@tonic-gate}x;
76*7c478bd9Sstevel@tonic-gate
77*7c478bd9Sstevel@tonic-gate$CrtSyms = qr{ ^(?:
78*7c478bd9Sstevel@tonic-gate	 ___Argv |			# Defined in crt
79*7c478bd9Sstevel@tonic-gate	 __environ_lock |		# Defined in crt
80*7c478bd9Sstevel@tonic-gate	 _environ |			# Defined in crt
81*7c478bd9Sstevel@tonic-gate	 environ			# Defined in crt
82*7c478bd9Sstevel@tonic-gate	 )$
83*7c478bd9Sstevel@tonic-gate}x;
84*7c478bd9Sstevel@tonic-gate
85*7c478bd9Sstevel@tonic-gate# Pattern match to remove undefined, NOTY and versioning symbols.
86*7c478bd9Sstevel@tonic-gate$UndefSym = qr{ ^(?:
87*7c478bd9Sstevel@tonic-gate	UNDEF
88*7c478bd9Sstevel@tonic-gate	)$
89*7c478bd9Sstevel@tonic-gate}x;
90*7c478bd9Sstevel@tonic-gate
91*7c478bd9Sstevel@tonic-gate$IgnSyms = qr{ ^(?:
92*7c478bd9Sstevel@tonic-gate	NOTY |
93*7c478bd9Sstevel@tonic-gate	ABS
94*7c478bd9Sstevel@tonic-gate	)$
95*7c478bd9Sstevel@tonic-gate}x;
96*7c478bd9Sstevel@tonic-gate
97*7c478bd9Sstevel@tonic-gate# Symbol flags.
98*7c478bd9Sstevel@tonic-gate$Glob = 0x00001;	# symbol is global
99*7c478bd9Sstevel@tonic-gate$Intp = 0x00010;	# symbol originates for explicit interposer
100*7c478bd9Sstevel@tonic-gate$Dirc = 0x00020;	# symbol bound to directly
101*7c478bd9Sstevel@tonic-gate$Cpyr = 0x00040;	# symbol bound to copy-relocation reference
102*7c478bd9Sstevel@tonic-gate$Prot = 0x00080;	# symbol is protected (symbolic)
103*7c478bd9Sstevel@tonic-gate$Extn = 0x00100;	# symbol has been bound to from an external reference
104*7c478bd9Sstevel@tonic-gate$Self = 0x00200;	# symbol has been bound to from the same object
105*7c478bd9Sstevel@tonic-gate$Filt = 0x00400;	# symbol bound to a filtee
106*7c478bd9Sstevel@tonic-gate$Plta = 0x00800;	# symbol bound to executables plt address
107*7c478bd9Sstevel@tonic-gate$User = 0x01000;	# symbol binding originates from user (dlsym) request
108*7c478bd9Sstevel@tonic-gate$Func = 0x02000;	# symbol is of type function
109*7c478bd9Sstevel@tonic-gate$Objt = 0x04000;	# symbol is of type object
110*7c478bd9Sstevel@tonic-gate$Nodi = 0x08000;	# symbol prohibits direct binding
111*7c478bd9Sstevel@tonic-gate
112*7c478bd9Sstevel@tonic-gate$Osft = 0x10000;	# symbol is an standard object filter
113*7c478bd9Sstevel@tonic-gate$Oaft = 0x20000;	# symbol is an auxiliary object filter
114*7c478bd9Sstevel@tonic-gate$Ssft = 0x40000;	# symbol is a per-symbol standard filter
115*7c478bd9Sstevel@tonic-gate$Saft = 0x80000;	# symbol is a per-symbol auxilary filter
116*7c478bd9Sstevel@tonic-gate$Msft = 0xf0000;	# filter mask
117*7c478bd9Sstevel@tonic-gate
118*7c478bd9Sstevel@tonic-gate# Offsets into $Symbols{$SymName}{$Obj} array.
119*7c478bd9Sstevel@tonic-gate$ObjRef =	0;
120*7c478bd9Sstevel@tonic-gate$ObjFlag =	1;
121*7c478bd9Sstevel@tonic-gate$ObjSize =	2;
122*7c478bd9Sstevel@tonic-gate
123*7c478bd9Sstevel@tonic-gate
124*7c478bd9Sstevel@tonic-gate# Establish locale
125*7c478bd9Sstevel@tonic-gateuse POSIX qw(locale_h);
126*7c478bd9Sstevel@tonic-gateuse Sun::Solaris::Utils qw(textdomain gettext);
127*7c478bd9Sstevel@tonic-gate
128*7c478bd9Sstevel@tonic-gatesetlocale(LC_ALL, "");
129*7c478bd9Sstevel@tonic-gatetextdomain("SUNW_OST_SGS");
130*7c478bd9Sstevel@tonic-gate
131*7c478bd9Sstevel@tonic-gate# Establish a program name for any error diagnostics.
132*7c478bd9Sstevel@tonic-gate$Prog = basename($0);
133*7c478bd9Sstevel@tonic-gate
134*7c478bd9Sstevel@tonic-gatesub inappropriate {
135*7c478bd9Sstevel@tonic-gate	my ($Opt1, $Opt2, $Flag) = @_;
136*7c478bd9Sstevel@tonic-gate
137*7c478bd9Sstevel@tonic-gate	if ($Flag) {
138*7c478bd9Sstevel@tonic-gate	    printf STDERR
139*7c478bd9Sstevel@tonic-gate		gettext("%s: inappropriate use of %s with %s: %s ignored\n"),
140*7c478bd9Sstevel@tonic-gate		$Prog, $Opt1, $Opt2, $Opt1;
141*7c478bd9Sstevel@tonic-gate	} else {
142*7c478bd9Sstevel@tonic-gate	    printf STDERR
143*7c478bd9Sstevel@tonic-gate		gettext("%s: inappropriate use of %s without %s: %s ignored\n"),
144*7c478bd9Sstevel@tonic-gate		$Prog, $Opt1, $Opt2, $Opt1;
145*7c478bd9Sstevel@tonic-gate	}
146*7c478bd9Sstevel@tonic-gate}
147*7c478bd9Sstevel@tonic-gate
148*7c478bd9Sstevel@tonic-gate# Cleanup any temporary files on interruption
149*7c478bd9Sstevel@tonic-gatesub Cleanup {
150*7c478bd9Sstevel@tonic-gate	my ($Sig) = @_;
151*7c478bd9Sstevel@tonic-gate
152*7c478bd9Sstevel@tonic-gate	$SIG{$Sig} = 'IGNORE';
153*7c478bd9Sstevel@tonic-gate
154*7c478bd9Sstevel@tonic-gate	if ($DbgSeed ne "") {
155*7c478bd9Sstevel@tonic-gate		foreach my $File (<\Q${DbgSeed}\E.*>) {
156*7c478bd9Sstevel@tonic-gate			if ($File =~ /^\Q$DbgSeed\E\.\d+$/) {
157*7c478bd9Sstevel@tonic-gate				unlink($File);
158*7c478bd9Sstevel@tonic-gate			}
159*7c478bd9Sstevel@tonic-gate		}
160*7c478bd9Sstevel@tonic-gate	}
161*7c478bd9Sstevel@tonic-gate	exit 1;
162*7c478bd9Sstevel@tonic-gate}
163*7c478bd9Sstevel@tonic-gate
164*7c478bd9Sstevel@tonic-gate# Check that we have arguments.
165*7c478bd9Sstevel@tonic-gateif ((getopts('abCDd:imosv', \%opt) == 0) || ($#ARGV < 0)) {
166*7c478bd9Sstevel@tonic-gate	printf STDERR gettext("usage:\n");
167*7c478bd9Sstevel@tonic-gate	printf STDERR
168*7c478bd9Sstevel@tonic-gate	    gettext("    %s [-bCDsv] [-a | -i | -o ] file | dir ...\n"), $Prog;
169*7c478bd9Sstevel@tonic-gate	printf STDERR
170*7c478bd9Sstevel@tonic-gate	    gettext("    %s [-CDosv] [-m [-d mapdir]] file\n"), $Prog;
171*7c478bd9Sstevel@tonic-gate	print STDERR
172*7c478bd9Sstevel@tonic-gate	    gettext("\t[-a]     print diagnostics for all symbols\n");
173*7c478bd9Sstevel@tonic-gate	print STDERR
174*7c478bd9Sstevel@tonic-gate	    gettext("\t[-b]     print diagnostics for multiple-bound " .
175*7c478bd9Sstevel@tonic-gate		"symbols\n");
176*7c478bd9Sstevel@tonic-gate	print STDERR
177*7c478bd9Sstevel@tonic-gate	    gettext("\t[-C]     print demangled symbol names also\n");
178*7c478bd9Sstevel@tonic-gate	print STDERR
179*7c478bd9Sstevel@tonic-gate	    gettext("\t[-D]     read debugging information from \"file\"\n");
180*7c478bd9Sstevel@tonic-gate	print STDERR
181*7c478bd9Sstevel@tonic-gate	    gettext("\t[-d dir] create mapfiles in \"mapdir\"\n");
182*7c478bd9Sstevel@tonic-gate	print STDERR
183*7c478bd9Sstevel@tonic-gate	    gettext("\t[-i]     print interesting information (default)\n");
184*7c478bd9Sstevel@tonic-gate	print STDERR
185*7c478bd9Sstevel@tonic-gate	    gettext("\t[-m]     create mapfiles for interface requirements\n");
186*7c478bd9Sstevel@tonic-gate	print STDERR
187*7c478bd9Sstevel@tonic-gate	    gettext("\t[-o]     print overhead information\n");
188*7c478bd9Sstevel@tonic-gate	print STDERR
189*7c478bd9Sstevel@tonic-gate	    gettext("\t[-s]     save bindings information created by ldd(1)\n");
190*7c478bd9Sstevel@tonic-gate	print STDERR
191*7c478bd9Sstevel@tonic-gate	    gettext("\t[-v]     ignore versioned objects\n");
192*7c478bd9Sstevel@tonic-gate	exit 1;
193*7c478bd9Sstevel@tonic-gate} else {
194*7c478bd9Sstevel@tonic-gate	my ($Mult, $Error);
195*7c478bd9Sstevel@tonic-gate
196*7c478bd9Sstevel@tonic-gate	# Catch any incompatible argument usage.
197*7c478bd9Sstevel@tonic-gate	if ($opt{m}) {
198*7c478bd9Sstevel@tonic-gate		if ($opt{a}) {
199*7c478bd9Sstevel@tonic-gate			inappropriate("-a", "-m", 1);
200*7c478bd9Sstevel@tonic-gate			$opt{a} = 0;
201*7c478bd9Sstevel@tonic-gate		}
202*7c478bd9Sstevel@tonic-gate		if ($opt{i}) {
203*7c478bd9Sstevel@tonic-gate			inappropriate("-i", "-m", 1);
204*7c478bd9Sstevel@tonic-gate			$opt{i} = 0;
205*7c478bd9Sstevel@tonic-gate		}
206*7c478bd9Sstevel@tonic-gate	} else {
207*7c478bd9Sstevel@tonic-gate		if ($opt{d}) {
208*7c478bd9Sstevel@tonic-gate			inappropriate("-d", "-m", 0);
209*7c478bd9Sstevel@tonic-gate			$opt{d} = 0;
210*7c478bd9Sstevel@tonic-gate		}
211*7c478bd9Sstevel@tonic-gate	}
212*7c478bd9Sstevel@tonic-gate	if ($opt{a}) {
213*7c478bd9Sstevel@tonic-gate		if ($opt{o}) {
214*7c478bd9Sstevel@tonic-gate			inappropriate("-a", "-o", 1);
215*7c478bd9Sstevel@tonic-gate			$opt{o} = 0;
216*7c478bd9Sstevel@tonic-gate		}
217*7c478bd9Sstevel@tonic-gate		if ($opt{i}) {
218*7c478bd9Sstevel@tonic-gate			inappropriate("-a", "-i", 1);
219*7c478bd9Sstevel@tonic-gate			$opt{i} = 0;
220*7c478bd9Sstevel@tonic-gate		}
221*7c478bd9Sstevel@tonic-gate	}
222*7c478bd9Sstevel@tonic-gate	if ($opt{o} && $opt{i}) {
223*7c478bd9Sstevel@tonic-gate		inappropriate("-o", "-i", 1);
224*7c478bd9Sstevel@tonic-gate			$opt{i} = 0;
225*7c478bd9Sstevel@tonic-gate	}
226*7c478bd9Sstevel@tonic-gate
227*7c478bd9Sstevel@tonic-gate	# If -m is used, only one input file is applicable.
228*7c478bd9Sstevel@tonic-gate	if ($opt{m} && ($#ARGV != 0)) {
229*7c478bd9Sstevel@tonic-gate		printf STDERR gettext("%s: only one input file is allowed " .
230*7c478bd9Sstevel@tonic-gate		    "with the -m option\n"), $Prog;
231*7c478bd9Sstevel@tonic-gate		exit 1;
232*7c478bd9Sstevel@tonic-gate	}
233*7c478bd9Sstevel@tonic-gate
234*7c478bd9Sstevel@tonic-gate	# Insure any specified directory exists, or apply a default.
235*7c478bd9Sstevel@tonic-gate	if ($opt{d}) {
236*7c478bd9Sstevel@tonic-gate		# User specified directory - make sure it exists.
237*7c478bd9Sstevel@tonic-gate		if (! -d $opt{d}) {
238*7c478bd9Sstevel@tonic-gate			printf STDERR gettext("%s: %s is not a directory\n"),
239*7c478bd9Sstevel@tonic-gate			    $Prog, $opt{d};
240*7c478bd9Sstevel@tonic-gate			exit 1;
241*7c478bd9Sstevel@tonic-gate		}
242*7c478bd9Sstevel@tonic-gate		$DestDir = $opt{d};
243*7c478bd9Sstevel@tonic-gate	} else {
244*7c478bd9Sstevel@tonic-gate		$DestDir = ".";
245*7c478bd9Sstevel@tonic-gate	}
246*7c478bd9Sstevel@tonic-gate
247*7c478bd9Sstevel@tonic-gate	# Establish a temporary directory if necessary.
248*7c478bd9Sstevel@tonic-gate	if (!$opt{D}) {
249*7c478bd9Sstevel@tonic-gate		if (!($TmpDir = $ENV{TMPDIR}) || (! -d $TmpDir)) {
250*7c478bd9Sstevel@tonic-gate			$TmpDir = "/tmp";
251*7c478bd9Sstevel@tonic-gate		}
252*7c478bd9Sstevel@tonic-gate	}
253*7c478bd9Sstevel@tonic-gate
254*7c478bd9Sstevel@tonic-gate	# Establish any initial ldd(1) argument requirements.
255*7c478bd9Sstevel@tonic-gate	if ($LddArgs = $ENV{LARI_LDD_ARGS}) {
256*7c478bd9Sstevel@tonic-gate		$LddArgs = $LddArgs . ' -r -e LD_DEBUG=bindings,files,detail';
257*7c478bd9Sstevel@tonic-gate	} else {
258*7c478bd9Sstevel@tonic-gate		$LddArgs = '-r -e LD_DEBUG=bindings,files,detail';
259*7c478bd9Sstevel@tonic-gate	}
260*7c478bd9Sstevel@tonic-gate
261*7c478bd9Sstevel@tonic-gate	# If we've been asked to demangle symbols, make sure we can find the
262*7c478bd9Sstevel@tonic-gate	# demangler.
263*7c478bd9Sstevel@tonic-gate	if ($opt{C}) {
264*7c478bd9Sstevel@tonic-gate		my ($DemName) = `dem XXXX 2> /dev/null`;
265*7c478bd9Sstevel@tonic-gate		if (!$DemName) {
266*7c478bd9Sstevel@tonic-gate			printf STDERR gettext("%s: can not locate demangler: " .
267*7c478bd9Sstevel@tonic-gate			    "-C ignored\n"), $Prog;
268*7c478bd9Sstevel@tonic-gate			$opt{C} = 0;
269*7c478bd9Sstevel@tonic-gate		}
270*7c478bd9Sstevel@tonic-gate	}
271*7c478bd9Sstevel@tonic-gate
272*7c478bd9Sstevel@tonic-gate	# If -a or -o hasn't been specified, default to -i.
273*7c478bd9Sstevel@tonic-gate	if (!$opt{a} && !$opt{o}) {
274*7c478bd9Sstevel@tonic-gate		$opt{i} = 1;
275*7c478bd9Sstevel@tonic-gate	}
276*7c478bd9Sstevel@tonic-gate
277*7c478bd9Sstevel@tonic-gate	# Determine whether we have a multiple input files.
278*7c478bd9Sstevel@tonic-gate	if ($#ARGV == 0) {
279*7c478bd9Sstevel@tonic-gate		$Mult = 0;
280*7c478bd9Sstevel@tonic-gate	} else {
281*7c478bd9Sstevel@tonic-gate		$Mult = 1;
282*7c478bd9Sstevel@tonic-gate	}
283*7c478bd9Sstevel@tonic-gate
284*7c478bd9Sstevel@tonic-gate	# Determine what platform we're running on - some inappropriate
285*7c478bd9Sstevel@tonic-gate	# platform specific dependencies are better skipped.
286*7c478bd9Sstevel@tonic-gate	chomp($Platform = `uname -i`);
287*7c478bd9Sstevel@tonic-gate
288*7c478bd9Sstevel@tonic-gate	# Establish signal handlers
289*7c478bd9Sstevel@tonic-gate	$SIG{INT} = \&Cleanup;
290*7c478bd9Sstevel@tonic-gate	$SIG{QUIT} = \&Cleanup;
291*7c478bd9Sstevel@tonic-gate
292*7c478bd9Sstevel@tonic-gate	$DbgSeed = "";
293*7c478bd9Sstevel@tonic-gate
294*7c478bd9Sstevel@tonic-gate	# For each argument determine if we're dealing with a file or directory.
295*7c478bd9Sstevel@tonic-gate	$Error = 0;
296*7c478bd9Sstevel@tonic-gate	foreach my $Arg (@ARGV) {
297*7c478bd9Sstevel@tonic-gate		if (!stat($Arg)) {
298*7c478bd9Sstevel@tonic-gate			printf STDERR gettext("%s: %s: unable to stat file\n"),
299*7c478bd9Sstevel@tonic-gate			    $Prog, $Arg;
300*7c478bd9Sstevel@tonic-gate			$Error = 1;
301*7c478bd9Sstevel@tonic-gate			next;
302*7c478bd9Sstevel@tonic-gate		}
303*7c478bd9Sstevel@tonic-gate
304*7c478bd9Sstevel@tonic-gate		# Process simple files.
305*7c478bd9Sstevel@tonic-gate		if (-f _) {
306*7c478bd9Sstevel@tonic-gate			if (!-r _) {
307*7c478bd9Sstevel@tonic-gate				printf STDERR gettext("%s: %s: unable to " .
308*7c478bd9Sstevel@tonic-gate				   "read file\n"), $Prog, $Arg;
309*7c478bd9Sstevel@tonic-gate				$Error = 1;
310*7c478bd9Sstevel@tonic-gate				next;
311*7c478bd9Sstevel@tonic-gate			}
312*7c478bd9Sstevel@tonic-gate			if (!$opt{D}) {
313*7c478bd9Sstevel@tonic-gate				if (ProcFile($Arg, $Mult, 1) == 0) {
314*7c478bd9Sstevel@tonic-gate					$Error = 1;
315*7c478bd9Sstevel@tonic-gate				}
316*7c478bd9Sstevel@tonic-gate			} else {
317*7c478bd9Sstevel@tonic-gate				# If the -D option is specified, read the
318*7c478bd9Sstevel@tonic-gate				# bindings debugging information from the
319*7c478bd9Sstevel@tonic-gate				# specified file.
320*7c478bd9Sstevel@tonic-gate				if ($Mult) {
321*7c478bd9Sstevel@tonic-gate					print STDOUT "$Arg:\n";
322*7c478bd9Sstevel@tonic-gate				}
323*7c478bd9Sstevel@tonic-gate				ProcBindings($Arg, $Mult, $Arg);
324*7c478bd9Sstevel@tonic-gate			}
325*7c478bd9Sstevel@tonic-gate			next;
326*7c478bd9Sstevel@tonic-gate		}
327*7c478bd9Sstevel@tonic-gate
328*7c478bd9Sstevel@tonic-gate		# Process directories.
329*7c478bd9Sstevel@tonic-gate		if (-d _) {
330*7c478bd9Sstevel@tonic-gate			ProcDir($Arg);
331*7c478bd9Sstevel@tonic-gate			next;
332*7c478bd9Sstevel@tonic-gate		}
333*7c478bd9Sstevel@tonic-gate
334*7c478bd9Sstevel@tonic-gate		printf STDERR gettext("%s: %s: is not a file or directory\n"),
335*7c478bd9Sstevel@tonic-gate		    $Prog, $Arg;
336*7c478bd9Sstevel@tonic-gate		$Error = 1;
337*7c478bd9Sstevel@tonic-gate	}
338*7c478bd9Sstevel@tonic-gate	exit $Error;
339*7c478bd9Sstevel@tonic-gate}
340*7c478bd9Sstevel@tonic-gate
341*7c478bd9Sstevel@tonic-gatesub ProcDir {
342*7c478bd9Sstevel@tonic-gate	my ($Dir) = @_;
343*7c478bd9Sstevel@tonic-gate	my ($File);
344*7c478bd9Sstevel@tonic-gate
345*7c478bd9Sstevel@tonic-gate	# Open the directory and read each entry, omit "." and "..".  Sorting
346*7c478bd9Sstevel@tonic-gate	# the directory listing makes analyzing different source hierarchies
347*7c478bd9Sstevel@tonic-gate	# easier.
348*7c478bd9Sstevel@tonic-gate	if (opendir(DIR, $Dir)) {
349*7c478bd9Sstevel@tonic-gate		foreach my $Entry (sort(readdir(DIR))) {
350*7c478bd9Sstevel@tonic-gate			if (($Entry eq '.') || ($Entry eq '..')) {
351*7c478bd9Sstevel@tonic-gate				next;
352*7c478bd9Sstevel@tonic-gate			}
353*7c478bd9Sstevel@tonic-gate
354*7c478bd9Sstevel@tonic-gate			# If we're decending into a platform directory, ignore
355*7c478bd9Sstevel@tonic-gate			# any inappropriate platform specific files.  These
356*7c478bd9Sstevel@tonic-gate			# files can have dependencies that in turn bring in the
357*7c478bd9Sstevel@tonic-gate			# appropriate platform specific file, resulting in more
358*7c478bd9Sstevel@tonic-gate			# than one dependency offering the same interfaces.  In
359*7c478bd9Sstevel@tonic-gate			# practice, the non-appropriate platform specific file
360*7c478bd9Sstevel@tonic-gate			# wouldn't be loaded with a process.
361*7c478bd9Sstevel@tonic-gate			if (($Dir =~ /\/platform$/) &&
362*7c478bd9Sstevel@tonic-gate			    ($Entry !~ /^$Platform$/)) {
363*7c478bd9Sstevel@tonic-gate				next;
364*7c478bd9Sstevel@tonic-gate			}
365*7c478bd9Sstevel@tonic-gate
366*7c478bd9Sstevel@tonic-gate			$File = "$Dir/$Entry";
367*7c478bd9Sstevel@tonic-gate			if (!lstat($File)) {
368*7c478bd9Sstevel@tonic-gate				next;
369*7c478bd9Sstevel@tonic-gate			}
370*7c478bd9Sstevel@tonic-gate			# Ignore symlinks.
371*7c478bd9Sstevel@tonic-gate			if (-l _) {
372*7c478bd9Sstevel@tonic-gate				next;
373*7c478bd9Sstevel@tonic-gate			}
374*7c478bd9Sstevel@tonic-gate
375*7c478bd9Sstevel@tonic-gate			# Descend into, and process any directories.
376*7c478bd9Sstevel@tonic-gate			if (-d _) {
377*7c478bd9Sstevel@tonic-gate				ProcDir($File);
378*7c478bd9Sstevel@tonic-gate				next;
379*7c478bd9Sstevel@tonic-gate			}
380*7c478bd9Sstevel@tonic-gate
381*7c478bd9Sstevel@tonic-gate			# Process any standard files.
382*7c478bd9Sstevel@tonic-gate			if (-f _ && -r _) {
383*7c478bd9Sstevel@tonic-gate				ProcFile($File, 1, 0);
384*7c478bd9Sstevel@tonic-gate				next;
385*7c478bd9Sstevel@tonic-gate
386*7c478bd9Sstevel@tonic-gate			}
387*7c478bd9Sstevel@tonic-gate		}
388*7c478bd9Sstevel@tonic-gate		closedir(DIR);
389*7c478bd9Sstevel@tonic-gate	}
390*7c478bd9Sstevel@tonic-gate}
391*7c478bd9Sstevel@tonic-gate
392*7c478bd9Sstevel@tonic-gate# Process a file.  If the file was explicitly defined on the command-line, and
393*7c478bd9Sstevel@tonic-gate# an error occurs, tell the user.  Otherwise, this file probably came about from
394*7c478bd9Sstevel@tonic-gate# scanning a directory, in which case just skip it and move on.
395*7c478bd9Sstevel@tonic-gatesub ProcFile {
396*7c478bd9Sstevel@tonic-gate	my ($File, $Mult, $CmdLine) = @_;
397*7c478bd9Sstevel@tonic-gate	my (@Ldd, $NoFound, $DbgFile, @DbgGlob, $Type);
398*7c478bd9Sstevel@tonic-gate
399*7c478bd9Sstevel@tonic-gate	$Type = `LC_ALL=C file '$File' 2>&1`;
400*7c478bd9Sstevel@tonic-gate	if (($Type !~ /dynamically linked/) || ($Type =~ /Sun demand paged/)) {
401*7c478bd9Sstevel@tonic-gate		if ($CmdLine) {
402*7c478bd9Sstevel@tonic-gate			printf STDERR gettext("%s: %s: is an invalid file " .
403*7c478bd9Sstevel@tonic-gate			    "type\n"), $Prog, $File;
404*7c478bd9Sstevel@tonic-gate		}
405*7c478bd9Sstevel@tonic-gate		return 0;
406*7c478bd9Sstevel@tonic-gate	}
407*7c478bd9Sstevel@tonic-gate
408*7c478bd9Sstevel@tonic-gate	# Create a temporary filename for capturing binding information.
409*7c478bd9Sstevel@tonic-gate	$DbgSeed = basename($File);
410*7c478bd9Sstevel@tonic-gate	$DbgSeed = "$TmpDir/lari.dbg.$$.$DbgSeed";
411*7c478bd9Sstevel@tonic-gate
412*7c478bd9Sstevel@tonic-gate	# Exercise the file under ldd(1), capturing all the bindings.
413*7c478bd9Sstevel@tonic-gate	@Ldd = split(/\n/,
414*7c478bd9Sstevel@tonic-gate	    `LC_ALL=C ldd $LddArgs -e LD_DEBUG_OUTPUT='$DbgSeed' '$File' 2>&1`);
415*7c478bd9Sstevel@tonic-gate
416*7c478bd9Sstevel@tonic-gate	# If ldd isn't -e capable we'll get a usage message.  The -e option was
417*7c478bd9Sstevel@tonic-gate	# introduced in Solaris 9 and related patches.  Also, make sure the user
418*7c478bd9Sstevel@tonic-gate	# sees any ldd errors.
419*7c478bd9Sstevel@tonic-gate	$NoFound = 0;
420*7c478bd9Sstevel@tonic-gate	for my $Line (@Ldd) {
421*7c478bd9Sstevel@tonic-gate		if ($Line =~ /^usage: ldd/) {
422*7c478bd9Sstevel@tonic-gate			printf STDERR gettext("%s: ldd: does not support -e, " .
423*7c478bd9Sstevel@tonic-gate			    "unable to capture bindings output\n"), $Prog;
424*7c478bd9Sstevel@tonic-gate			exit 1;
425*7c478bd9Sstevel@tonic-gate		}
426*7c478bd9Sstevel@tonic-gate		if ($Line =~ /not found/) {
427*7c478bd9Sstevel@tonic-gate			$NoFound = 1;
428*7c478bd9Sstevel@tonic-gate			last;
429*7c478bd9Sstevel@tonic-gate		}
430*7c478bd9Sstevel@tonic-gate	}
431*7c478bd9Sstevel@tonic-gate
432*7c478bd9Sstevel@tonic-gate	# The runtime linker will have appended a process id to the debug file.
433*7c478bd9Sstevel@tonic-gate	# As we have to intuit the name, make sure there is only one debug
434*7c478bd9Sstevel@tonic-gate	# file match, otherwise there must be some clutter in the output
435*7c478bd9Sstevel@tonic-gate	# directory that is going to mess up our analysis.
436*7c478bd9Sstevel@tonic-gate	foreach my $Match (<\Q${DbgSeed}\E.*>) {
437*7c478bd9Sstevel@tonic-gate		if ($Match =~ /^\Q$DbgSeed\E\.\d+$/) {
438*7c478bd9Sstevel@tonic-gate			push(@DbgGlob, $Match);
439*7c478bd9Sstevel@tonic-gate		}
440*7c478bd9Sstevel@tonic-gate	}
441*7c478bd9Sstevel@tonic-gate	if (@DbgGlob == 0) {
442*7c478bd9Sstevel@tonic-gate		# If there is no debug file, bail.  This can occur if the file
443*7c478bd9Sstevel@tonic-gate		# being processed is secure.
444*7c478bd9Sstevel@tonic-gate		if ($CmdLine) {
445*7c478bd9Sstevel@tonic-gate			printf STDERR gettext("%s: %s: unable to capture " .
446*7c478bd9Sstevel@tonic-gate			    "bindings output - possible secure application?\n"),
447*7c478bd9Sstevel@tonic-gate			    $Prog, $File;
448*7c478bd9Sstevel@tonic-gate		}
449*7c478bd9Sstevel@tonic-gate		return 0;
450*7c478bd9Sstevel@tonic-gate	} elsif (@DbgGlob > 1) {
451*7c478bd9Sstevel@tonic-gate		# Too many debug files found.
452*7c478bd9Sstevel@tonic-gate		if ($CmdLine) {
453*7c478bd9Sstevel@tonic-gate			printf STDERR gettext("%s: %s: multiple bindings " .
454*7c478bd9Sstevel@tonic-gate			    "output files exist: %s: clean up temporary " .
455*7c478bd9Sstevel@tonic-gate			    "directory\n"), $Prog, $File, $DbgSeed;
456*7c478bd9Sstevel@tonic-gate		}
457*7c478bd9Sstevel@tonic-gate		return 0;
458*7c478bd9Sstevel@tonic-gate	} else {
459*7c478bd9Sstevel@tonic-gate		$DbgFile = $DbgGlob[0];
460*7c478bd9Sstevel@tonic-gate	}
461*7c478bd9Sstevel@tonic-gate
462*7c478bd9Sstevel@tonic-gate	# Ok, we're ready to process the bindings information.  Print a header
463*7c478bd9Sstevel@tonic-gate	# if necessary, and if there were any ldd(1) errors push some of them
464*7c478bd9Sstevel@tonic-gate	# out before any bindings information.  Limit the output, as it can
465*7c478bd9Sstevel@tonic-gate	# sometimes be excessive.  If there are errors, the bindings information
466*7c478bd9Sstevel@tonic-gate	# is likely to be incomplete.
467*7c478bd9Sstevel@tonic-gate	if ($Mult) {
468*7c478bd9Sstevel@tonic-gate		print STDOUT "$File:\n";
469*7c478bd9Sstevel@tonic-gate	}
470*7c478bd9Sstevel@tonic-gate	if ($NoFound) {
471*7c478bd9Sstevel@tonic-gate		my ($Cnt) = 4;
472*7c478bd9Sstevel@tonic-gate
473*7c478bd9Sstevel@tonic-gate		for my $Line (@Ldd) {
474*7c478bd9Sstevel@tonic-gate			if ($Line =~ /not found/) {
475*7c478bd9Sstevel@tonic-gate				print STDOUT "$Line\n";
476*7c478bd9Sstevel@tonic-gate				$Cnt--;
477*7c478bd9Sstevel@tonic-gate			}
478*7c478bd9Sstevel@tonic-gate			if ($Cnt == 0) {
479*7c478bd9Sstevel@tonic-gate				print STDOUT gettext("\tcontinued ...\n");
480*7c478bd9Sstevel@tonic-gate				last;
481*7c478bd9Sstevel@tonic-gate			}
482*7c478bd9Sstevel@tonic-gate		}
483*7c478bd9Sstevel@tonic-gate	}
484*7c478bd9Sstevel@tonic-gate
485*7c478bd9Sstevel@tonic-gate	# If the user wants the original debugging file left behind, rename it
486*7c478bd9Sstevel@tonic-gate	# so that it doesn't get re-read by another instance of lari processing
487*7c478bd9Sstevel@tonic-gate	# this file.
488*7c478bd9Sstevel@tonic-gate	if ($opt{s}) {
489*7c478bd9Sstevel@tonic-gate		rename($DbgFile, $DbgSeed);
490*7c478bd9Sstevel@tonic-gate		$DbgFile = $DbgSeed;
491*7c478bd9Sstevel@tonic-gate		printf STDOUT gettext("%s: %s: bindings information " .
492*7c478bd9Sstevel@tonic-gate		    "saved as: %s\n"), $Prog, $File, $DbgFile;
493*7c478bd9Sstevel@tonic-gate	}
494*7c478bd9Sstevel@tonic-gate
495*7c478bd9Sstevel@tonic-gate	ProcBindings($File, $Mult, $DbgFile);
496*7c478bd9Sstevel@tonic-gate
497*7c478bd9Sstevel@tonic-gate	# Now that we've finished with the debugging file, nuke it if necessary.
498*7c478bd9Sstevel@tonic-gate	if (!$opt{s}) {
499*7c478bd9Sstevel@tonic-gate		unlink($DbgFile);
500*7c478bd9Sstevel@tonic-gate	}
501*7c478bd9Sstevel@tonic-gate	$DbgSeed = "";
502*7c478bd9Sstevel@tonic-gate	return 1;
503*7c478bd9Sstevel@tonic-gate}
504*7c478bd9Sstevel@tonic-gate
505*7c478bd9Sstevel@tonic-gatesub ProcBindings {
506*7c478bd9Sstevel@tonic-gate	my ($File, $Mult, $DbgFile) = @_;
507*7c478bd9Sstevel@tonic-gate	my (%Filtees, $FileHandle);
508*7c478bd9Sstevel@tonic-gate
509*7c478bd9Sstevel@tonic-gate	# Reinitialize our arrays when we're dealing with multiple files.
510*7c478bd9Sstevel@tonic-gate	if ($Mult) {
511*7c478bd9Sstevel@tonic-gate		%Symbols = ();
512*7c478bd9Sstevel@tonic-gate		%Objects = ();
513*7c478bd9Sstevel@tonic-gate		%Versioned = ();
514*7c478bd9Sstevel@tonic-gate	}
515*7c478bd9Sstevel@tonic-gate
516*7c478bd9Sstevel@tonic-gate	# As debugging output can be significant, read a line at a time.
517*7c478bd9Sstevel@tonic-gate	open($FileHandle, "<$DbgFile");
518*7c478bd9Sstevel@tonic-gate	while (defined(my $Line = <$FileHandle>)) {
519*7c478bd9Sstevel@tonic-gate		chomp($Line);
520*7c478bd9Sstevel@tonic-gate
521*7c478bd9Sstevel@tonic-gate		# If we find a relationship between a filter and filtee, save
522*7c478bd9Sstevel@tonic-gate		# it, we'll come back to this once we've gathered everybodies
523*7c478bd9Sstevel@tonic-gate		# symbols.
524*7c478bd9Sstevel@tonic-gate		if ($Line =~ /;  filtered by /) {
525*7c478bd9Sstevel@tonic-gate			my ($Filtee) = $Line;
526*7c478bd9Sstevel@tonic-gate			my ($Filter) = $Line;
527*7c478bd9Sstevel@tonic-gate
528*7c478bd9Sstevel@tonic-gate			# Separate the filter and filtee names, ignore the
529*7c478bd9Sstevel@tonic-gate			# runtime linker.
530*7c478bd9Sstevel@tonic-gate			$Filtee =~ s/^.*: file=(.*);  filtered by .*/$1/;
531*7c478bd9Sstevel@tonic-gate			if ($Filtee =~ $Rtld) {
532*7c478bd9Sstevel@tonic-gate				next;
533*7c478bd9Sstevel@tonic-gate			}
534*7c478bd9Sstevel@tonic-gate			$Filter =~ s/^.*;  filtered by //;
535*7c478bd9Sstevel@tonic-gate			$Filtees{$Filtee}{$Filter} = 1;
536*7c478bd9Sstevel@tonic-gate			next;
537*7c478bd9Sstevel@tonic-gate		}
538*7c478bd9Sstevel@tonic-gate
539*7c478bd9Sstevel@tonic-gate		# If we find a configuration alternative, determine whether it
540*7c478bd9Sstevel@tonic-gate		# is for one of our filtees, and if so record it.
541*7c478bd9Sstevel@tonic-gate		if ($Line =~ / configuration alternate found:/) {
542*7c478bd9Sstevel@tonic-gate			my ($Orig) = $Line;
543*7c478bd9Sstevel@tonic-gate			my ($Altr) = $Line;
544*7c478bd9Sstevel@tonic-gate
545*7c478bd9Sstevel@tonic-gate			# Separate the original and alternative names.
546*7c478bd9Sstevel@tonic-gate			$Orig =~ s/^.*: file=(.*)  .*$/$1/;
547*7c478bd9Sstevel@tonic-gate			$Altr =~ s/^.* configuration alternate found: (.*)$/$1/;
548*7c478bd9Sstevel@tonic-gate
549*7c478bd9Sstevel@tonic-gate			for my $Filtee (keys(%Filtees)) {
550*7c478bd9Sstevel@tonic-gate				if ($Filtee ne $Orig) {
551*7c478bd9Sstevel@tonic-gate					next;
552*7c478bd9Sstevel@tonic-gate				}
553*7c478bd9Sstevel@tonic-gate				for my $Filter (keys(%{$Filtees{$Filtee}})) {
554*7c478bd9Sstevel@tonic-gate					$Filtees{$Altr}{$Filter} = 1;
555*7c478bd9Sstevel@tonic-gate				}
556*7c478bd9Sstevel@tonic-gate			}
557*7c478bd9Sstevel@tonic-gate			next;
558*7c478bd9Sstevel@tonic-gate		}
559*7c478bd9Sstevel@tonic-gate
560*7c478bd9Sstevel@tonic-gate		# Collect the symbols from any file analyzed.
561*7c478bd9Sstevel@tonic-gate		if ($Line =~ /^.*: file=(.*);  analyzing .*/) {
562*7c478bd9Sstevel@tonic-gate			GetAllSymbols($1);
563*7c478bd9Sstevel@tonic-gate			next;
564*7c478bd9Sstevel@tonic-gate		}
565*7c478bd9Sstevel@tonic-gate
566*7c478bd9Sstevel@tonic-gate		# Process any symbolic relocations that bind to a file.
567*7c478bd9Sstevel@tonic-gate		if ($Line =~ /: binding file=.* to file=/) {
568*7c478bd9Sstevel@tonic-gate			my ($RefFile, $DstFile, $SymName);
569*7c478bd9Sstevel@tonic-gate			my (@Syms, $Found, @Fields);
570*7c478bd9Sstevel@tonic-gate			my ($BndInfo) = 0;
571*7c478bd9Sstevel@tonic-gate			my ($Offset) = 1;
572*7c478bd9Sstevel@tonic-gate			my ($Dlsym) = 0;
573*7c478bd9Sstevel@tonic-gate			my ($Detail) = 0;
574*7c478bd9Sstevel@tonic-gate
575*7c478bd9Sstevel@tonic-gate			# For greatest flexibility, split the line into fields
576*7c478bd9Sstevel@tonic-gate			# and walk each field until we find what we need.
577*7c478bd9Sstevel@tonic-gate			@Fields = split(' ', $Line);
578*7c478bd9Sstevel@tonic-gate
579*7c478bd9Sstevel@tonic-gate			# The referencing file, "... binding file=".*".
580*7c478bd9Sstevel@tonic-gate			while ($Fields[$Offset]) {
581*7c478bd9Sstevel@tonic-gate				if ($Fields[$Offset] =~ /^file=(.*)/) {
582*7c478bd9Sstevel@tonic-gate					$RefFile = $1;
583*7c478bd9Sstevel@tonic-gate					$Offset++;
584*7c478bd9Sstevel@tonic-gate					last;
585*7c478bd9Sstevel@tonic-gate				}
586*7c478bd9Sstevel@tonic-gate				$Offset++;
587*7c478bd9Sstevel@tonic-gate			}
588*7c478bd9Sstevel@tonic-gate			# The referencing offset, typically this is the address
589*7c478bd9Sstevel@tonic-gate			# of the reference, "(0x1234...)", but in the case of a
590*7c478bd9Sstevel@tonic-gate			# user lookup it's the string "(dlsym)".  If we don't
591*7c478bd9Sstevel@tonic-gate			# find this offset information we've been given a debug
592*7c478bd9Sstevel@tonic-gate			# file that didn't user the "datail" token, in which case
593*7c478bd9Sstevel@tonic-gate			# we're not getting all the information we need.
594*7c478bd9Sstevel@tonic-gate			if ($Fields[$Offset] =~ /^\((.*)\)/) {
595*7c478bd9Sstevel@tonic-gate				if ($1 eq 'dlsym') {
596*7c478bd9Sstevel@tonic-gate					$Dlsym = 1;
597*7c478bd9Sstevel@tonic-gate				}
598*7c478bd9Sstevel@tonic-gate				$Detail = 1;
599*7c478bd9Sstevel@tonic-gate				$Offset++;
600*7c478bd9Sstevel@tonic-gate			}
601*7c478bd9Sstevel@tonic-gate			# The destination file, "... to file=".*".
602*7c478bd9Sstevel@tonic-gate			while ($Fields[$Offset]) {
603*7c478bd9Sstevel@tonic-gate				if ($Fields[$Offset] =~ /^file=(.*)/) {
604*7c478bd9Sstevel@tonic-gate					$DstFile = $1;
605*7c478bd9Sstevel@tonic-gate					$Offset++;
606*7c478bd9Sstevel@tonic-gate					last;
607*7c478bd9Sstevel@tonic-gate				}
608*7c478bd9Sstevel@tonic-gate				$Offset++;
609*7c478bd9Sstevel@tonic-gate			}
610*7c478bd9Sstevel@tonic-gate			# The symbol being bound, "... symbol `.*' ...".
611*7c478bd9Sstevel@tonic-gate			while ($Fields[$Offset]) {
612*7c478bd9Sstevel@tonic-gate				if ($Fields[$Offset] =~ /^\`(.*)\'$/) {
613*7c478bd9Sstevel@tonic-gate					$SymName = $1;
614*7c478bd9Sstevel@tonic-gate					$Offset++;
615*7c478bd9Sstevel@tonic-gate					last;
616*7c478bd9Sstevel@tonic-gate				}
617*7c478bd9Sstevel@tonic-gate				$Offset++;
618*7c478bd9Sstevel@tonic-gate			}
619*7c478bd9Sstevel@tonic-gate			# Possible trailing binding info, "... (direct,.*)$".
620*7c478bd9Sstevel@tonic-gate			while ($Fields[$Offset]) {
621*7c478bd9Sstevel@tonic-gate				if ($Fields[$Offset] =~ /^\((.*)\)$/) {
622*7c478bd9Sstevel@tonic-gate					$BndInfo = $1;
623*7c478bd9Sstevel@tonic-gate					$Offset++;
624*7c478bd9Sstevel@tonic-gate					last;
625*7c478bd9Sstevel@tonic-gate				}
626*7c478bd9Sstevel@tonic-gate				$Offset++;
627*7c478bd9Sstevel@tonic-gate			}
628*7c478bd9Sstevel@tonic-gate
629*7c478bd9Sstevel@tonic-gate			if ($Detail == 0) {
630*7c478bd9Sstevel@tonic-gate				printf STDERR gettext("%s: %s: debug file " .
631*7c478bd9Sstevel@tonic-gate				    "does not contain `detail' information\n"),
632*7c478bd9Sstevel@tonic-gate				    $Prog, $DbgFile;
633*7c478bd9Sstevel@tonic-gate				return;
634*7c478bd9Sstevel@tonic-gate			}
635*7c478bd9Sstevel@tonic-gate
636*7c478bd9Sstevel@tonic-gate			# Collect the symbols from each object.
637*7c478bd9Sstevel@tonic-gate			GetAllSymbols($RefFile);
638*7c478bd9Sstevel@tonic-gate			GetAllSymbols($DstFile);
639*7c478bd9Sstevel@tonic-gate
640*7c478bd9Sstevel@tonic-gate			# Identify that this definition has been bound to.
641*7c478bd9Sstevel@tonic-gate			$Symbols{$SymName}{$DstFile}[$ObjRef]++;
642*7c478bd9Sstevel@tonic-gate			if ($RefFile eq $DstFile) {
643*7c478bd9Sstevel@tonic-gate				# If the reference binds to a definition within
644*7c478bd9Sstevel@tonic-gate				# the same file this symbol may be a candidate
645*7c478bd9Sstevel@tonic-gate				# for reducing to local.
646*7c478bd9Sstevel@tonic-gate				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Self;
647*7c478bd9Sstevel@tonic-gate				$Objects{$DstFile}{$SymName} |= $Self;
648*7c478bd9Sstevel@tonic-gate			} else {
649*7c478bd9Sstevel@tonic-gate				# This symbol is required to satisfy an external
650*7c478bd9Sstevel@tonic-gate				# reference.
651*7c478bd9Sstevel@tonic-gate				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Extn;
652*7c478bd9Sstevel@tonic-gate				$Objects{$DstFile}{$SymName} |= $Extn;
653*7c478bd9Sstevel@tonic-gate			}
654*7c478bd9Sstevel@tonic-gate
655*7c478bd9Sstevel@tonic-gate			# Assign any other state indicated by the binding info
656*7c478bd9Sstevel@tonic-gate			# associated with the diagnostic output.
657*7c478bd9Sstevel@tonic-gate			if (!$BndInfo) {
658*7c478bd9Sstevel@tonic-gate				next;
659*7c478bd9Sstevel@tonic-gate			}
660*7c478bd9Sstevel@tonic-gate
661*7c478bd9Sstevel@tonic-gate			if ($BndInfo =~ /direct/) {
662*7c478bd9Sstevel@tonic-gate				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Dirc;
663*7c478bd9Sstevel@tonic-gate				$Objects{$DstFile}{$SymName} |= $Dirc;
664*7c478bd9Sstevel@tonic-gate			}
665*7c478bd9Sstevel@tonic-gate			if ($BndInfo =~ /copy-ref/) {
666*7c478bd9Sstevel@tonic-gate				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Cpyr;
667*7c478bd9Sstevel@tonic-gate				$Objects{$DstFile}{$SymName} |= $Cpyr;
668*7c478bd9Sstevel@tonic-gate			}
669*7c478bd9Sstevel@tonic-gate			if ($BndInfo =~ /filtee/) {
670*7c478bd9Sstevel@tonic-gate				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Filt;
671*7c478bd9Sstevel@tonic-gate				$Objects{$DstFile}{$SymName} |= $Filt;
672*7c478bd9Sstevel@tonic-gate			}
673*7c478bd9Sstevel@tonic-gate			if ($BndInfo =~ /interpose/) {
674*7c478bd9Sstevel@tonic-gate				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Intp;
675*7c478bd9Sstevel@tonic-gate				$Objects{$DstFile}{$SymName} |= $Intp;
676*7c478bd9Sstevel@tonic-gate			}
677*7c478bd9Sstevel@tonic-gate			if ($BndInfo =~ /plt-addr/) {
678*7c478bd9Sstevel@tonic-gate				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Plta;
679*7c478bd9Sstevel@tonic-gate				$Objects{$DstFile}{$SymName} |= $Plta;
680*7c478bd9Sstevel@tonic-gate			}
681*7c478bd9Sstevel@tonic-gate			if ($Dlsym) {
682*7c478bd9Sstevel@tonic-gate				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $User;
683*7c478bd9Sstevel@tonic-gate				$Objects{$DstFile}{$SymName} |= $User;
684*7c478bd9Sstevel@tonic-gate			}
685*7c478bd9Sstevel@tonic-gate		}
686*7c478bd9Sstevel@tonic-gate	}
687*7c478bd9Sstevel@tonic-gate	close($FileHandle);
688*7c478bd9Sstevel@tonic-gate
689*7c478bd9Sstevel@tonic-gate	# Now that we've processed all objects, complete any auxiliary filtee
690*7c478bd9Sstevel@tonic-gate	# tagging.  For each filtee, determine which of the symbols it exports
691*7c478bd9Sstevel@tonic-gate	# are also defined in its filters.  If a filtee is bound to, the
692*7c478bd9Sstevel@tonic-gate	# runtime linkers diagnostics will indicate a filtee binding.  However,
693*7c478bd9Sstevel@tonic-gate	# some of the filtee symbols may not be bound to, so here we mark them
694*7c478bd9Sstevel@tonic-gate	# all so as to remove them from any interesting output.
695*7c478bd9Sstevel@tonic-gate	for my $Filtee (keys(%Filtees)) {
696*7c478bd9Sstevel@tonic-gate
697*7c478bd9Sstevel@tonic-gate		# Standard filters aren't captured at all, as nothing can bind
698*7c478bd9Sstevel@tonic-gate		# to them.
699*7c478bd9Sstevel@tonic-gate		if (!exists($Objects{$Filtee})) {
700*7c478bd9Sstevel@tonic-gate			next;
701*7c478bd9Sstevel@tonic-gate		}
702*7c478bd9Sstevel@tonic-gate
703*7c478bd9Sstevel@tonic-gate		# Determine what symbols this filtee offers.
704*7c478bd9Sstevel@tonic-gate		foreach my $SymName (keys(%{$Objects{$Filtee}})) {
705*7c478bd9Sstevel@tonic-gate
706*7c478bd9Sstevel@tonic-gate			# Ignore the usual reserved stuff.
707*7c478bd9Sstevel@tonic-gate			if (!$opt{a} && (($SymName =~ $MultSyms) ||
708*7c478bd9Sstevel@tonic-gate			    ($SymName =~ $CrtSyms))) {
709*7c478bd9Sstevel@tonic-gate				next;
710*7c478bd9Sstevel@tonic-gate			}
711*7c478bd9Sstevel@tonic-gate
712*7c478bd9Sstevel@tonic-gate			# Determine whether this symbol exists in our filter.
713*7c478bd9Sstevel@tonic-gate			for my $Filter (keys(%{$Filtees{$Filtee}})) {
714*7c478bd9Sstevel@tonic-gate				if (!$Symbols{$SymName}{$Filter}) {
715*7c478bd9Sstevel@tonic-gate					next;
716*7c478bd9Sstevel@tonic-gate				}
717*7c478bd9Sstevel@tonic-gate				if (!($Symbols{$SymName}{$Filter}[$ObjFlag] &
718*7c478bd9Sstevel@tonic-gate				    $Msft)) {
719*7c478bd9Sstevel@tonic-gate					next;
720*7c478bd9Sstevel@tonic-gate				}
721*7c478bd9Sstevel@tonic-gate				$Symbols{$SymName}{$Filtee}[$ObjFlag] |= $Filt;
722*7c478bd9Sstevel@tonic-gate			}
723*7c478bd9Sstevel@tonic-gate		}
724*7c478bd9Sstevel@tonic-gate	}
725*7c478bd9Sstevel@tonic-gate
726*7c478bd9Sstevel@tonic-gate	# Process objects and their symbols as required.
727*7c478bd9Sstevel@tonic-gate	if ($opt{m}) {
728*7c478bd9Sstevel@tonic-gate		# If we're creating a mapfile, traverse each object we've
729*7c478bd9Sstevel@tonic-gate		# collected.
730*7c478bd9Sstevel@tonic-gate		foreach my $Obj (keys(%Objects)) {
731*7c478bd9Sstevel@tonic-gate			my ($File, $Path);
732*7c478bd9Sstevel@tonic-gate
733*7c478bd9Sstevel@tonic-gate			# Skip any objects that should be ignored
734*7c478bd9Sstevel@tonic-gate			if ($Obj =~ $Rtld) {
735*7c478bd9Sstevel@tonic-gate				next;
736*7c478bd9Sstevel@tonic-gate			}
737*7c478bd9Sstevel@tonic-gate
738*7c478bd9Sstevel@tonic-gate			# Skip any versioned objects if required.
739*7c478bd9Sstevel@tonic-gate			if ($opt{v} && $Versioned{$Obj}) {
740*7c478bd9Sstevel@tonic-gate				next;
741*7c478bd9Sstevel@tonic-gate			}
742*7c478bd9Sstevel@tonic-gate
743*7c478bd9Sstevel@tonic-gate			# Open the mapfile if required.
744*7c478bd9Sstevel@tonic-gate			$File = basename($Obj);
745*7c478bd9Sstevel@tonic-gate			$Path = "$DestDir/mapfile-$File";
746*7c478bd9Sstevel@tonic-gate			if (!open(MAPOUT, "> $Path")) {
747*7c478bd9Sstevel@tonic-gate				printf STDERR gettext("%s: %s: open failed:" .
748*7c478bd9Sstevel@tonic-gate				    "%s\n"), $Prog, $Path, $!;
749*7c478bd9Sstevel@tonic-gate				exit 1;
750*7c478bd9Sstevel@tonic-gate			}
751*7c478bd9Sstevel@tonic-gate
752*7c478bd9Sstevel@tonic-gate			# Establish the mapfile preamble.
753*7c478bd9Sstevel@tonic-gate			print MAPOUT "#\n# Interface Definition mapfile for:\n";
754*7c478bd9Sstevel@tonic-gate			print MAPOUT "#\tDynamic Object: $Obj\n";
755*7c478bd9Sstevel@tonic-gate			print MAPOUT "#\tProcess:        $File\n#\n\n";
756*7c478bd9Sstevel@tonic-gate
757*7c478bd9Sstevel@tonic-gate			# Process each global symbol.
758*7c478bd9Sstevel@tonic-gate			print MAPOUT "$File {\n\tglobal:\n";
759*7c478bd9Sstevel@tonic-gate
760*7c478bd9Sstevel@tonic-gate			foreach my $SymName (sort(keys(%{$Objects{$Obj}}))) {
761*7c478bd9Sstevel@tonic-gate				my ($Flag) = $Objects{$Obj}{$SymName};
762*7c478bd9Sstevel@tonic-gate
763*7c478bd9Sstevel@tonic-gate				# For the first pass we're only interested in
764*7c478bd9Sstevel@tonic-gate				# symbols that have been bound to from an
765*7c478bd9Sstevel@tonic-gate				# external object, or must be global to enable
766*7c478bd9Sstevel@tonic-gate				# a binding to an interposing definition.
767*7c478bd9Sstevel@tonic-gate				# Skip bindings to ourself as these are
768*7c478bd9Sstevel@tonic-gate				# candidates for demoting to local.
769*7c478bd9Sstevel@tonic-gate				if (!($Flag & ($Extn | $Intp))) {
770*7c478bd9Sstevel@tonic-gate					next;
771*7c478bd9Sstevel@tonic-gate				}
772*7c478bd9Sstevel@tonic-gate				if (($Flag & ($Extn | $Self)) == $Self) {
773*7c478bd9Sstevel@tonic-gate					next;
774*7c478bd9Sstevel@tonic-gate				}
775*7c478bd9Sstevel@tonic-gate
776*7c478bd9Sstevel@tonic-gate				# Add the demangled name as a comment if
777*7c478bd9Sstevel@tonic-gate				# required.
778*7c478bd9Sstevel@tonic-gate				if ($opt{C}) {
779*7c478bd9Sstevel@tonic-gate					my ($DemName) = Demangle($SymName);
780*7c478bd9Sstevel@tonic-gate
781*7c478bd9Sstevel@tonic-gate					if ($DemName ne "") {
782*7c478bd9Sstevel@tonic-gate						print MAPOUT "\t\t#$DemName\n";
783*7c478bd9Sstevel@tonic-gate					}
784*7c478bd9Sstevel@tonic-gate				}
785*7c478bd9Sstevel@tonic-gate				print MAPOUT "\t\t$SymName;\n";
786*7c478bd9Sstevel@tonic-gate			}
787*7c478bd9Sstevel@tonic-gate
788*7c478bd9Sstevel@tonic-gate			# Process each local demotion.
789*7c478bd9Sstevel@tonic-gate			print MAPOUT "\tlocal:\n";
790*7c478bd9Sstevel@tonic-gate
791*7c478bd9Sstevel@tonic-gate			if ($opt{o}) {
792*7c478bd9Sstevel@tonic-gate				foreach my $SymName
793*7c478bd9Sstevel@tonic-gate				    (sort(keys(%{$Objects{$Obj}}))) {
794*7c478bd9Sstevel@tonic-gate					my ($Flag) = $Objects{$Obj}{$SymName};
795*7c478bd9Sstevel@tonic-gate
796*7c478bd9Sstevel@tonic-gate					# For this pass we're only interested
797*7c478bd9Sstevel@tonic-gate					# in symbol definitions that haven't
798*7c478bd9Sstevel@tonic-gate					# been bound to, or have only been
799*7c478bd9Sstevel@tonic-gate					# bound to from the same object.
800*7c478bd9Sstevel@tonic-gate					if ($Flag & $Extn) {
801*7c478bd9Sstevel@tonic-gate						next;
802*7c478bd9Sstevel@tonic-gate					}
803*7c478bd9Sstevel@tonic-gate
804*7c478bd9Sstevel@tonic-gate					# Add the demangled name as a comment if
805*7c478bd9Sstevel@tonic-gate					# required.
806*7c478bd9Sstevel@tonic-gate					if ($opt{C}) {
807*7c478bd9Sstevel@tonic-gate						my ($DemName) =
808*7c478bd9Sstevel@tonic-gate						    Demangle($SymName);
809*7c478bd9Sstevel@tonic-gate
810*7c478bd9Sstevel@tonic-gate						if ($DemName ne "") {
811*7c478bd9Sstevel@tonic-gate							print MAPOUT
812*7c478bd9Sstevel@tonic-gate							    "\t\t#$DemName\n";
813*7c478bd9Sstevel@tonic-gate						}
814*7c478bd9Sstevel@tonic-gate					}
815*7c478bd9Sstevel@tonic-gate					print MAPOUT "\t\t$SymName;\n";
816*7c478bd9Sstevel@tonic-gate				}
817*7c478bd9Sstevel@tonic-gate			}
818*7c478bd9Sstevel@tonic-gate
819*7c478bd9Sstevel@tonic-gate			# Capture everything else as local.
820*7c478bd9Sstevel@tonic-gate			print MAPOUT "\t\t\*;\n};\n";
821*7c478bd9Sstevel@tonic-gate			close MAPOUT;
822*7c478bd9Sstevel@tonic-gate		}
823*7c478bd9Sstevel@tonic-gate
824*7c478bd9Sstevel@tonic-gate	} else {
825*7c478bd9Sstevel@tonic-gate		# If we're gathering information regarding the symbols used by
826*7c478bd9Sstevel@tonic-gate		# the process, automatically sort any standard output using the
827*7c478bd9Sstevel@tonic-gate		# symbol name.
828*7c478bd9Sstevel@tonic-gate		if (!open(SORT, "| sort +1")) {
829*7c478bd9Sstevel@tonic-gate			printf STDERR gettext("%s: fork failed: %s\n"),
830*7c478bd9Sstevel@tonic-gate			    $Prog, $!;
831*7c478bd9Sstevel@tonic-gate			exit 1;
832*7c478bd9Sstevel@tonic-gate		}
833*7c478bd9Sstevel@tonic-gate
834*7c478bd9Sstevel@tonic-gate		foreach my $SymName (keys(%Symbols)) {
835*7c478bd9Sstevel@tonic-gate			my ($Cnt);
836*7c478bd9Sstevel@tonic-gate
837*7c478bd9Sstevel@tonic-gate			# If we're looking for interesting symbols, inspect
838*7c478bd9Sstevel@tonic-gate			# each definition of each symbol.  If one is found to
839*7c478bd9Sstevel@tonic-gate			# be interesting, the whole family are printed.
840*7c478bd9Sstevel@tonic-gate			if (($Cnt = Interesting($SymName)) == 0) {
841*7c478bd9Sstevel@tonic-gate				next;
842*7c478bd9Sstevel@tonic-gate			}
843*7c478bd9Sstevel@tonic-gate
844*7c478bd9Sstevel@tonic-gate			# We've found something interesting, or all symbols
845*7c478bd9Sstevel@tonic-gate			# should be output.  List all objects that define this
846*7c478bd9Sstevel@tonic-gate			# symbol.
847*7c478bd9Sstevel@tonic-gate			foreach my $Obj (keys(%{$Symbols{$SymName}})) {
848*7c478bd9Sstevel@tonic-gate				my ($DemName, $Type);
849*7c478bd9Sstevel@tonic-gate				my ($Flag) = $Symbols{$SymName}{$Obj}[$ObjFlag];
850*7c478bd9Sstevel@tonic-gate				my ($Str) = "$Cnt:";
851*7c478bd9Sstevel@tonic-gate
852*7c478bd9Sstevel@tonic-gate				# Do we just want overhead symbols.  Consider
853*7c478bd9Sstevel@tonic-gate				# copy-relocations, and plt address binding,
854*7c478bd9Sstevel@tonic-gate				# as overhead too.
855*7c478bd9Sstevel@tonic-gate				if ($opt{o} && (($Flag &
856*7c478bd9Sstevel@tonic-gate				    ($Extn | $Cpyr | $Plta)) == $Extn)) {
857*7c478bd9Sstevel@tonic-gate					next;
858*7c478bd9Sstevel@tonic-gate				}
859*7c478bd9Sstevel@tonic-gate
860*7c478bd9Sstevel@tonic-gate				# Do we just want all symbols that have been
861*7c478bd9Sstevel@tonic-gate				# bound to.
862*7c478bd9Sstevel@tonic-gate				if (($opt{a} || $opt{o}) && $opt{b} &&
863*7c478bd9Sstevel@tonic-gate				    (($Flag & ($Extn | $Self | $Prot)) == 0)) {
864*7c478bd9Sstevel@tonic-gate					next;
865*7c478bd9Sstevel@tonic-gate				}
866*7c478bd9Sstevel@tonic-gate
867*7c478bd9Sstevel@tonic-gate				# If we haven't been asked for all symbols, only
868*7c478bd9Sstevel@tonic-gate				# print those reserved symbols that have been
869*7c478bd9Sstevel@tonic-gate				# bound to, as the number of reserved symbols
870*7c478bd9Sstevel@tonic-gate				# can be quite excessive.
871*7c478bd9Sstevel@tonic-gate				if (!$opt{a} && ((($SymName =~ $MultSyms) &&
872*7c478bd9Sstevel@tonic-gate				    (($Flag & ($Extn | $Self)) == 0)) ||
873*7c478bd9Sstevel@tonic-gate				    (($SymName =~ $CrtSyms) && (($Flag &
874*7c478bd9Sstevel@tonic-gate				    ($Extn | $Self | $Prot)) == 0)))) {
875*7c478bd9Sstevel@tonic-gate					next;
876*7c478bd9Sstevel@tonic-gate				}
877*7c478bd9Sstevel@tonic-gate
878*7c478bd9Sstevel@tonic-gate				# Skip any versioned objects if required.
879*7c478bd9Sstevel@tonic-gate				if ($opt{v} && $Versioned{$Obj}) {
880*7c478bd9Sstevel@tonic-gate					next;
881*7c478bd9Sstevel@tonic-gate				}
882*7c478bd9Sstevel@tonic-gate
883*7c478bd9Sstevel@tonic-gate				# Display this symbol.
884*7c478bd9Sstevel@tonic-gate				if ($Symbols{$SymName}{$Obj}[$ObjRef]) {
885*7c478bd9Sstevel@tonic-gate					$Str = $Str .
886*7c478bd9Sstevel@tonic-gate					    $Symbols{$SymName}{$Obj}[$ObjRef];
887*7c478bd9Sstevel@tonic-gate				} else {
888*7c478bd9Sstevel@tonic-gate					$Str = $Str . '0';
889*7c478bd9Sstevel@tonic-gate				}
890*7c478bd9Sstevel@tonic-gate
891*7c478bd9Sstevel@tonic-gate				# Has the symbol been bound to externally
892*7c478bd9Sstevel@tonic-gate				if ($Flag & $Extn) {
893*7c478bd9Sstevel@tonic-gate					$Str = $Str . 'E';
894*7c478bd9Sstevel@tonic-gate				}
895*7c478bd9Sstevel@tonic-gate				# Has the symbol been bound to from the same
896*7c478bd9Sstevel@tonic-gate				# object.
897*7c478bd9Sstevel@tonic-gate				if ($Flag & $Self) {
898*7c478bd9Sstevel@tonic-gate					$Str = $Str . 'S';
899*7c478bd9Sstevel@tonic-gate				}
900*7c478bd9Sstevel@tonic-gate				# Has the symbol been bound to directly.
901*7c478bd9Sstevel@tonic-gate				if ($Flag & $Dirc) {
902*7c478bd9Sstevel@tonic-gate					$Str = $Str . 'D';
903*7c478bd9Sstevel@tonic-gate				}
904*7c478bd9Sstevel@tonic-gate				# Does this symbol originate for an explicit
905*7c478bd9Sstevel@tonic-gate				# interposer.
906*7c478bd9Sstevel@tonic-gate				if ($Flag & $Intp) {
907*7c478bd9Sstevel@tonic-gate					$Str = $Str . 'I';
908*7c478bd9Sstevel@tonic-gate				}
909*7c478bd9Sstevel@tonic-gate				# Is this symbol the reference data of a copy
910*7c478bd9Sstevel@tonic-gate				# relocation.
911*7c478bd9Sstevel@tonic-gate				if ($Flag & $Cpyr) {
912*7c478bd9Sstevel@tonic-gate					$Str = $Str . 'C';
913*7c478bd9Sstevel@tonic-gate				}
914*7c478bd9Sstevel@tonic-gate				# Is this symbol part of filtee.
915*7c478bd9Sstevel@tonic-gate				if ($Flag & $Filt) {
916*7c478bd9Sstevel@tonic-gate					$Str = $Str . 'F';
917*7c478bd9Sstevel@tonic-gate				}
918*7c478bd9Sstevel@tonic-gate				# Is this symbol protected (in which case there
919*7c478bd9Sstevel@tonic-gate				# may be a symbolic binding within the same
920*7c478bd9Sstevel@tonic-gate				# object to this symbol).
921*7c478bd9Sstevel@tonic-gate				if ($Flag & $Prot) {
922*7c478bd9Sstevel@tonic-gate					$Str = $Str . 'P';
923*7c478bd9Sstevel@tonic-gate				}
924*7c478bd9Sstevel@tonic-gate				# Is this symbol an executables .plt address.
925*7c478bd9Sstevel@tonic-gate				if ($Flag & $Plta) {
926*7c478bd9Sstevel@tonic-gate					$Str = $Str . 'A';
927*7c478bd9Sstevel@tonic-gate				}
928*7c478bd9Sstevel@tonic-gate				# Does this binding originate from a user
929*7c478bd9Sstevel@tonic-gate				# (dlsym) request.
930*7c478bd9Sstevel@tonic-gate				if ($Flag & $User) {
931*7c478bd9Sstevel@tonic-gate					$Str = $Str . 'U';
932*7c478bd9Sstevel@tonic-gate				}
933*7c478bd9Sstevel@tonic-gate				# Does this definition redirect the binding.
934*7c478bd9Sstevel@tonic-gate				if ($Flag & $Msft) {
935*7c478bd9Sstevel@tonic-gate					$Str = $Str . 'R';
936*7c478bd9Sstevel@tonic-gate				}
937*7c478bd9Sstevel@tonic-gate				# Does this definition explicity define no
938*7c478bd9Sstevel@tonic-gate				# direct binding.
939*7c478bd9Sstevel@tonic-gate				if ($Flag & $Nodi) {
940*7c478bd9Sstevel@tonic-gate					$Str = $Str . 'N';
941*7c478bd9Sstevel@tonic-gate				}
942*7c478bd9Sstevel@tonic-gate
943*7c478bd9Sstevel@tonic-gate				# Determine whether this is a function or a data
944*7c478bd9Sstevel@tonic-gate				# object.  For the latter, display the symbol
945*7c478bd9Sstevel@tonic-gate				# size.  Otherwise, the symbol is a reserved
946*7c478bd9Sstevel@tonic-gate				# label, and is left untyped.
947*7c478bd9Sstevel@tonic-gate				if ($Flag & $Func) {
948*7c478bd9Sstevel@tonic-gate					$Type = '()';
949*7c478bd9Sstevel@tonic-gate				} elsif ($Flag & $Objt) {
950*7c478bd9Sstevel@tonic-gate					$Type = '[' .
951*7c478bd9Sstevel@tonic-gate					    $Symbols{$SymName}{$Obj}[$ObjSize] .
952*7c478bd9Sstevel@tonic-gate					']';
953*7c478bd9Sstevel@tonic-gate				} else {
954*7c478bd9Sstevel@tonic-gate					$Type = "";
955*7c478bd9Sstevel@tonic-gate				}
956*7c478bd9Sstevel@tonic-gate
957*7c478bd9Sstevel@tonic-gate				# Demangle the symbol name if desired.
958*7c478bd9Sstevel@tonic-gate				$DemName = Demangle($SymName);
959*7c478bd9Sstevel@tonic-gate
960*7c478bd9Sstevel@tonic-gate				if ($Mult) {
961*7c478bd9Sstevel@tonic-gate					print SORT "  [$Str]: " .
962*7c478bd9Sstevel@tonic-gate					    "$SymName$Type$DemName: $Obj\n";
963*7c478bd9Sstevel@tonic-gate				} else {
964*7c478bd9Sstevel@tonic-gate					print SORT "[$Str]: " .
965*7c478bd9Sstevel@tonic-gate					    "$SymName$Type$DemName: $Obj\n";
966*7c478bd9Sstevel@tonic-gate				}
967*7c478bd9Sstevel@tonic-gate			}
968*7c478bd9Sstevel@tonic-gate		}
969*7c478bd9Sstevel@tonic-gate		close SORT;
970*7c478bd9Sstevel@tonic-gate	}
971*7c478bd9Sstevel@tonic-gate}
972*7c478bd9Sstevel@tonic-gate
973*7c478bd9Sstevel@tonic-gate# Heuristics to determine whether a symbol binding is interesting.  In most
974*7c478bd9Sstevel@tonic-gate# applications there can be a large amount of symbol binding information to
975*7c478bd9Sstevel@tonic-gate# wade through.  The most typical binding, to a single definition, probably
976*7c478bd9Sstevel@tonic-gate# isn't interesting or the cause of unexpected behavior.  Here, we try and
977*7c478bd9Sstevel@tonic-gate# determine those bindings that may can cause unexpected behavior.
978*7c478bd9Sstevel@tonic-gate#
979*7c478bd9Sstevel@tonic-gate# Note, this routine is actually called for all symbols so that their count
980*7c478bd9Sstevel@tonic-gate# can be calculated in one place.
981*7c478bd9Sstevel@tonic-gatesub Interesting
982*7c478bd9Sstevel@tonic-gate{
983*7c478bd9Sstevel@tonic-gate	my ($SymName) = @_;
984*7c478bd9Sstevel@tonic-gate	my ($ObjCnt, $GFlags, $BndCnt, $FltCnt, $NodiCnt, $RdirCnt, $ExRef);
985*7c478bd9Sstevel@tonic-gate
986*7c478bd9Sstevel@tonic-gate	# Scan all definitions of this symbol, thus determining the definition
987*7c478bd9Sstevel@tonic-gate	# count, the number of filters, redirections, executable references
988*7c478bd9Sstevel@tonic-gate	# (copy-relocations, or plt addresses), no-direct bindings, and the
989*7c478bd9Sstevel@tonic-gate	# number of definitions that have been bound to.
990*7c478bd9Sstevel@tonic-gate	$ObjCnt = $GFlags = $BndCnt = $FltCnt =
991*7c478bd9Sstevel@tonic-gate		$NodiCnt = $RdirCnt = $ExRef = 0;
992*7c478bd9Sstevel@tonic-gate	foreach my $Obj (keys(%{$Symbols{$SymName}})) {
993*7c478bd9Sstevel@tonic-gate		my ($Flag) = $Symbols{$SymName}{$Obj}[$ObjFlag];
994*7c478bd9Sstevel@tonic-gate
995*7c478bd9Sstevel@tonic-gate		# Ignore standard filters when determining the symbol count, as
996*7c478bd9Sstevel@tonic-gate		# a standard filter can never be bound to.
997*7c478bd9Sstevel@tonic-gate		if (($Flag & ($Osft | $Ssft)) == 0) {
998*7c478bd9Sstevel@tonic-gate			$ObjCnt++;
999*7c478bd9Sstevel@tonic-gate		}
1000*7c478bd9Sstevel@tonic-gate
1001*7c478bd9Sstevel@tonic-gate		$GFlags |= $Flag;
1002*7c478bd9Sstevel@tonic-gate		if ($Flag & $Filt) {
1003*7c478bd9Sstevel@tonic-gate			$FltCnt++;
1004*7c478bd9Sstevel@tonic-gate		}
1005*7c478bd9Sstevel@tonic-gate		if ($Flag & $Nodi) {
1006*7c478bd9Sstevel@tonic-gate			$NodiCnt++;
1007*7c478bd9Sstevel@tonic-gate		}
1008*7c478bd9Sstevel@tonic-gate		if ($Flag & ($Cpyr | $Plta)) {
1009*7c478bd9Sstevel@tonic-gate			$ExRef++;
1010*7c478bd9Sstevel@tonic-gate		}
1011*7c478bd9Sstevel@tonic-gate		if ($Flag & $Msft) {
1012*7c478bd9Sstevel@tonic-gate			$RdirCnt++;
1013*7c478bd9Sstevel@tonic-gate		}
1014*7c478bd9Sstevel@tonic-gate
1015*7c478bd9Sstevel@tonic-gate		# Ignore bindings to undefined .plts, and copy-relocation
1016*7c478bd9Sstevel@tonic-gate		# references.  These are implementation details, rather than
1017*7c478bd9Sstevel@tonic-gate		# a truly interesting multiple-binding.  If a symbol is tagged
1018*7c478bd9Sstevel@tonic-gate		# as protected, count it as having bound to itself, even though
1019*7c478bd9Sstevel@tonic-gate		# we can't tell if it's really been used.
1020*7c478bd9Sstevel@tonic-gate		if (($Flag & ($Self | $Extn | $Prot)) &&
1021*7c478bd9Sstevel@tonic-gate		    (($Flag & ($Plta | $Cpyr)) == 0)) {
1022*7c478bd9Sstevel@tonic-gate			$BndCnt++;
1023*7c478bd9Sstevel@tonic-gate		}
1024*7c478bd9Sstevel@tonic-gate	}
1025*7c478bd9Sstevel@tonic-gate
1026*7c478bd9Sstevel@tonic-gate	# If we want all symbols, return the count.
1027*7c478bd9Sstevel@tonic-gate	if (!$opt{i}) {
1028*7c478bd9Sstevel@tonic-gate		return $ObjCnt;
1029*7c478bd9Sstevel@tonic-gate	}
1030*7c478bd9Sstevel@tonic-gate
1031*7c478bd9Sstevel@tonic-gate	# Single instance symbol definitions aren't very interesting.
1032*7c478bd9Sstevel@tonic-gate	if ($ObjCnt == 1) {
1033*7c478bd9Sstevel@tonic-gate		return 0;
1034*7c478bd9Sstevel@tonic-gate	}
1035*7c478bd9Sstevel@tonic-gate
1036*7c478bd9Sstevel@tonic-gate	# Traverse each symbol definition looking for the following:
1037*7c478bd9Sstevel@tonic-gate	#
1038*7c478bd9Sstevel@tonic-gate	#   .	Multiple symbols are bound to externally.
1039*7c478bd9Sstevel@tonic-gate	#   .	A symbol is bound to externally, and possibly symbolically.
1040*7c478bd9Sstevel@tonic-gate	#
1041*7c478bd9Sstevel@tonic-gate	# Two symbol bindings are acceptable in some cases, and thus aren't
1042*7c478bd9Sstevel@tonic-gate	# interesting:
1043*7c478bd9Sstevel@tonic-gate	#
1044*7c478bd9Sstevel@tonic-gate	#   .	Copy relocations.  Here, the executable binds to a shared object
1045*7c478bd9Sstevel@tonic-gate	#	to access the data definition, which is then copied to the
1046*7c478bd9Sstevel@tonic-gate	#	executable.  All other references should then bind to the copied
1047*7c478bd9Sstevel@tonic-gate	#	data.
1048*7c478bd9Sstevel@tonic-gate	#   .	Non-plt relocations to functions that are referenced by the
1049*7c478bd9Sstevel@tonic-gate	#	executable will bind to the .plt in the executable.  This
1050*7c478bd9Sstevel@tonic-gate	#	provides for address comparison calculations (although plainly
1051*7c478bd9Sstevel@tonic-gate	#	an overhead).
1052*7c478bd9Sstevel@tonic-gate	#
1053*7c478bd9Sstevel@tonic-gate	# Multiple symbol bindings are acceptable in some cases, and thus aren't
1054*7c478bd9Sstevel@tonic-gate	# interesting:
1055*7c478bd9Sstevel@tonic-gate	#
1056*7c478bd9Sstevel@tonic-gate	#   .	Filtees.  Multiple filtees may exist for one filter.
1057*7c478bd9Sstevel@tonic-gate	#
1058*7c478bd9Sstevel@tonic-gate	if ((($ObjCnt == 2) && ($GFlags & ($Cpyr | $Plta))) ||
1059*7c478bd9Sstevel@tonic-gate	    ($ObjCnt == ($FltCnt + 1))) {
1060*7c478bd9Sstevel@tonic-gate		return 0;
1061*7c478bd9Sstevel@tonic-gate	}
1062*7c478bd9Sstevel@tonic-gate
1063*7c478bd9Sstevel@tonic-gate	# If we're only interested in multiply-bound symbols.
1064*7c478bd9Sstevel@tonic-gate	if (($opt{b} || ($SymName =~ $MultSyms) || ($SymName =~ $CrtSyms)) &&
1065*7c478bd9Sstevel@tonic-gate	    ($BndCnt < 2)) {
1066*7c478bd9Sstevel@tonic-gate		return (0);
1067*7c478bd9Sstevel@tonic-gate	}
1068*7c478bd9Sstevel@tonic-gate
1069*7c478bd9Sstevel@tonic-gate	# Multiple instances of a definition, where all but one are filter
1070*7c478bd9Sstevel@tonic-gate	# references and/or copy relocations, are also uninteresting.
1071*7c478bd9Sstevel@tonic-gate	# Effectively, only one symbol is providing the final binding.
1072*7c478bd9Sstevel@tonic-gate	if (($FltCnt && $RdirCnt) &&
1073*7c478bd9Sstevel@tonic-gate	    (($FltCnt + $RdirCnt + $ExRef) == $ObjCnt)) {
1074*7c478bd9Sstevel@tonic-gate		return (0);
1075*7c478bd9Sstevel@tonic-gate	}
1076*7c478bd9Sstevel@tonic-gate
1077*7c478bd9Sstevel@tonic-gate	# Multiple instances of explicitly defined no-direct binding symbols
1078*7c478bd9Sstevel@tonic-gate	# are known to occur, and their no-binding definition indicates they
1079*7c478bd9Sstevel@tonic-gate	# are expected and accounted for.  Thus, these aren't interesting.
1080*7c478bd9Sstevel@tonic-gate	if (($ExRef + $NodiCnt) == $ObjCnt) {
1081*7c478bd9Sstevel@tonic-gate		return (0);
1082*7c478bd9Sstevel@tonic-gate	}
1083*7c478bd9Sstevel@tonic-gate
1084*7c478bd9Sstevel@tonic-gate	# We have an interesting symbol, returns its count.
1085*7c478bd9Sstevel@tonic-gate	return $ObjCnt;
1086*7c478bd9Sstevel@tonic-gate}
1087*7c478bd9Sstevel@tonic-gate
1088*7c478bd9Sstevel@tonic-gate# Obtain the global symbol definitions of an object and determine whether the
1089*7c478bd9Sstevel@tonic-gate# object has been versioned.
1090*7c478bd9Sstevel@tonic-gatesub GetAllSymbols {
1091*7c478bd9Sstevel@tonic-gate	my ($Obj) = @_;
1092*7c478bd9Sstevel@tonic-gate	my (@Elfd, @Elfs, @Elfr, $Type, $Exec, $FileHandle);
1093*7c478bd9Sstevel@tonic-gate	my (%AddrToName, %NameToAddr);
1094*7c478bd9Sstevel@tonic-gate	my ($Vers) = 0;
1095*7c478bd9Sstevel@tonic-gate	my ($Symb) = 0;
1096*7c478bd9Sstevel@tonic-gate	my ($Copy) = 0;
1097*7c478bd9Sstevel@tonic-gate	my ($Interpose) = 0;
1098*7c478bd9Sstevel@tonic-gate	my ($Fltr) = 0;
1099*7c478bd9Sstevel@tonic-gate
1100*7c478bd9Sstevel@tonic-gate	# Determine whether we've already retrieved this object's symbols.
1101*7c478bd9Sstevel@tonic-gate	# Also, ignore the runtime linker, it's on a separate link-map, and
1102*7c478bd9Sstevel@tonic-gate	# except for the filtee symbols that might be bound via libdl, is
1103*7c478bd9Sstevel@tonic-gate	# uninteresting.
1104*7c478bd9Sstevel@tonic-gate	if (($Objects{$Obj}) || ($Obj =~ $Rtld)) {
1105*7c478bd9Sstevel@tonic-gate		return;
1106*7c478bd9Sstevel@tonic-gate	}
1107*7c478bd9Sstevel@tonic-gate
1108*7c478bd9Sstevel@tonic-gate	# Get the dynamic information.
1109*7c478bd9Sstevel@tonic-gate	@Elfd = split(/\n/, `LC_ALL=C elfdump -d '$Obj' 2> /dev/null`);
1110*7c478bd9Sstevel@tonic-gate
1111*7c478bd9Sstevel@tonic-gate	# If there's no information, it's possible we've been given a debug
1112*7c478bd9Sstevel@tonic-gate	# output file and are processing it from a location from which the
1113*7c478bd9Sstevel@tonic-gate	# dependencies specified in the debug file aren't accessible.
1114*7c478bd9Sstevel@tonic-gate	if (!@Elfd) {
1115*7c478bd9Sstevel@tonic-gate		printf STDERR gettext("%s: %s: unable to process ELF file\n"),
1116*7c478bd9Sstevel@tonic-gate		    $Prog, $Obj;
1117*7c478bd9Sstevel@tonic-gate
1118*7c478bd9Sstevel@tonic-gate		# Add the file to our list, so that we don't create the same
1119*7c478bd9Sstevel@tonic-gate		# message again.  Processing should continue so that we can
1120*7c478bd9Sstevel@tonic-gate		# flush out as many error messages as possible.
1121*7c478bd9Sstevel@tonic-gate		$Objects{$Obj}{"DoesNotExist"} = 0;
1122*7c478bd9Sstevel@tonic-gate		return;
1123*7c478bd9Sstevel@tonic-gate	}
1124*7c478bd9Sstevel@tonic-gate
1125*7c478bd9Sstevel@tonic-gate	# If we're processing a filter there's no need to save any symbols, as
1126*7c478bd9Sstevel@tonic-gate	# no bindings will occur to this object.
1127*7c478bd9Sstevel@tonic-gate	#
1128*7c478bd9Sstevel@tonic-gate	# Determine whether we've got a symbolicly bound object.  With newer
1129*7c478bd9Sstevel@tonic-gate	# linkers all symbols will be marked as protected ("P"), but with older
1130*7c478bd9Sstevel@tonic-gate	# linkers this state could only be intuited from the symbolic dynamic
1131*7c478bd9Sstevel@tonic-gate	# tag.
1132*7c478bd9Sstevel@tonic-gate	foreach my $Line (@Elfd) {
1133*7c478bd9Sstevel@tonic-gate		my (@Fields);
1134*7c478bd9Sstevel@tonic-gate		@Fields = split(' ', $Line);
1135*7c478bd9Sstevel@tonic-gate
1136*7c478bd9Sstevel@tonic-gate		# Determine if the FILTER tag is set.
1137*7c478bd9Sstevel@tonic-gate		if ($#Fields == 3) {
1138*7c478bd9Sstevel@tonic-gate			if ($Fields[1] eq "FILTER") {
1139*7c478bd9Sstevel@tonic-gate				$Fltr |= $Osft;
1140*7c478bd9Sstevel@tonic-gate				next;
1141*7c478bd9Sstevel@tonic-gate			}
1142*7c478bd9Sstevel@tonic-gate			if ($Fields[1] eq "AUXILIARY") {
1143*7c478bd9Sstevel@tonic-gate				$Fltr |= $Oaft;
1144*7c478bd9Sstevel@tonic-gate				next;
1145*7c478bd9Sstevel@tonic-gate			}
1146*7c478bd9Sstevel@tonic-gate			next;
1147*7c478bd9Sstevel@tonic-gate		}
1148*7c478bd9Sstevel@tonic-gate
1149*7c478bd9Sstevel@tonic-gate		# We're only interested in the FLAGS entry.
1150*7c478bd9Sstevel@tonic-gate		if (($#Fields < 4) || ($Fields[1] !~ "^FLAGS")) {
1151*7c478bd9Sstevel@tonic-gate			next;
1152*7c478bd9Sstevel@tonic-gate		}
1153*7c478bd9Sstevel@tonic-gate		if (($Fields[1] eq "FLAGS") && ($Line =~ " SYMBOLIC ")) {
1154*7c478bd9Sstevel@tonic-gate			$Symb = 1;
1155*7c478bd9Sstevel@tonic-gate			next;
1156*7c478bd9Sstevel@tonic-gate		}
1157*7c478bd9Sstevel@tonic-gate		if (($Fields[1] eq "FLAGS_1") && ($Line =~ " INTERPOSE ")) {
1158*7c478bd9Sstevel@tonic-gate			$Interpose = 1;
1159*7c478bd9Sstevel@tonic-gate		}
1160*7c478bd9Sstevel@tonic-gate	}
1161*7c478bd9Sstevel@tonic-gate
1162*7c478bd9Sstevel@tonic-gate	# If this file is a dynamic executable, determine if this object has
1163*7c478bd9Sstevel@tonic-gate	# any copy relocations so that any associated bindings can be labeled
1164*7c478bd9Sstevel@tonic-gate	# more meaningfully.
1165*7c478bd9Sstevel@tonic-gate	$Type = `LC_ALL=C file '$Obj'`;
1166*7c478bd9Sstevel@tonic-gate	if ($Type =~ /executable/) {
1167*7c478bd9Sstevel@tonic-gate		$Exec = 1;
1168*7c478bd9Sstevel@tonic-gate		# Obtain any copy relocations.
1169*7c478bd9Sstevel@tonic-gate		@Elfr = split(/\n/, `LC_ALL=C elfdump -r '$Obj' 2>&1`);
1170*7c478bd9Sstevel@tonic-gate
1171*7c478bd9Sstevel@tonic-gate		foreach my $Rel (@Elfr) {
1172*7c478bd9Sstevel@tonic-gate			my ($SymName, @Fields);
1173*7c478bd9Sstevel@tonic-gate
1174*7c478bd9Sstevel@tonic-gate			if ($Rel !~ /^\s+R_\S+_COPY /) {
1175*7c478bd9Sstevel@tonic-gate				next;
1176*7c478bd9Sstevel@tonic-gate			}
1177*7c478bd9Sstevel@tonic-gate			@Fields = split(' ', $Rel);
1178*7c478bd9Sstevel@tonic-gate			if ($Fields[0] eq 'R_SPARC_COPY') {
1179*7c478bd9Sstevel@tonic-gate				$SymName = $Fields[4];
1180*7c478bd9Sstevel@tonic-gate			} elsif ($Fields[0] eq 'R_386_COPY') {
1181*7c478bd9Sstevel@tonic-gate				$SymName = $Fields[3];
1182*7c478bd9Sstevel@tonic-gate			} else {
1183*7c478bd9Sstevel@tonic-gate				next;
1184*7c478bd9Sstevel@tonic-gate			}
1185*7c478bd9Sstevel@tonic-gate
1186*7c478bd9Sstevel@tonic-gate			$Symbols{$SymName}{$Obj}[$ObjFlag] |= $Cpyr;
1187*7c478bd9Sstevel@tonic-gate			$Objects{$Obj}{$SymName} |= $Cpyr;
1188*7c478bd9Sstevel@tonic-gate			$Copy = 1;
1189*7c478bd9Sstevel@tonic-gate		}
1190*7c478bd9Sstevel@tonic-gate	} else {
1191*7c478bd9Sstevel@tonic-gate		$Exec = 0;
1192*7c478bd9Sstevel@tonic-gate	}
1193*7c478bd9Sstevel@tonic-gate
1194*7c478bd9Sstevel@tonic-gate	# Obtain the dynamic symbol table for this object.  Symbol tables can
1195*7c478bd9Sstevel@tonic-gate	# be quite large, so open the elfump command through a pipe.
1196*7c478bd9Sstevel@tonic-gate	open($FileHandle, "LC_ALL=C elfdump -sN.dynsym '$Obj' 2> /dev/null |");
1197*7c478bd9Sstevel@tonic-gate
1198*7c478bd9Sstevel@tonic-gate	# Now process all symbols.
1199*7c478bd9Sstevel@tonic-gate	while (defined(my $Line = <$FileHandle>)) {
1200*7c478bd9Sstevel@tonic-gate		chomp($Line);
1201*7c478bd9Sstevel@tonic-gate
1202*7c478bd9Sstevel@tonic-gate		my (@Fields) = split(' ', $Line);
1203*7c478bd9Sstevel@tonic-gate		my ($Flags);
1204*7c478bd9Sstevel@tonic-gate
1205*7c478bd9Sstevel@tonic-gate		# We're only interested in defined non-reserved symbol entries.
1206*7c478bd9Sstevel@tonic-gate		# Note, ABS and NOTY symbols of non-zero size have been known to
1207*7c478bd9Sstevel@tonic-gate		# occur, so capture them.
1208*7c478bd9Sstevel@tonic-gate		if (($#Fields < 8) || ($Fields[4] !~ $GlobWeak) ||
1209*7c478bd9Sstevel@tonic-gate		    ($Fields[7] =~ $UndefSym) || (!$opt{a} &&
1210*7c478bd9Sstevel@tonic-gate		    ($Fields[7] =~ $IgnSyms) && (oct($Fields[2]) eq 0))) {
1211*7c478bd9Sstevel@tonic-gate			next;
1212*7c478bd9Sstevel@tonic-gate		}
1213*7c478bd9Sstevel@tonic-gate
1214*7c478bd9Sstevel@tonic-gate		# If we're found copy relocations, save the address and names
1215*7c478bd9Sstevel@tonic-gate		# of any OBJT definitions, together with the copy symbol.
1216*7c478bd9Sstevel@tonic-gate		if ($Copy && ($Fields[3] eq 'OBJT')) {
1217*7c478bd9Sstevel@tonic-gate			push(@{$AddrToName{$Fields[1]}}, $Fields[8]);
1218*7c478bd9Sstevel@tonic-gate		}
1219*7c478bd9Sstevel@tonic-gate		if (($Symbols{$Fields[8]}{$Obj}) &&
1220*7c478bd9Sstevel@tonic-gate		    ($Symbols{$Fields[8]}{$Obj}[$ObjFlag] & $Cpyr)) {
1221*7c478bd9Sstevel@tonic-gate			$NameToAddr{$Fields[8]} = $Fields[1];
1222*7c478bd9Sstevel@tonic-gate		}
1223*7c478bd9Sstevel@tonic-gate
1224*7c478bd9Sstevel@tonic-gate		# If the symbol visibility is protected, this is an internal
1225*7c478bd9Sstevel@tonic-gate		# symbolic binding (NOTE, an INTERNAL visibility for a global
1226*7c478bd9Sstevel@tonic-gate		# symbol is invalid, but for a while ld(1) was setting this
1227*7c478bd9Sstevel@tonic-gate		# attribute mistakenly for protected).
1228*7c478bd9Sstevel@tonic-gate		# If this is a dynamic executable, mark its symbols as protected
1229*7c478bd9Sstevel@tonic-gate		# (they can't be interposed on any more than symbols defined
1230*7c478bd9Sstevel@tonic-gate		# protected within shared objects).
1231*7c478bd9Sstevel@tonic-gate		$Flags = $Glob | $Fltr;
1232*7c478bd9Sstevel@tonic-gate		if (($Fields[5] =~ /^[IP]$/) || $Symb || $Exec) {
1233*7c478bd9Sstevel@tonic-gate			$Flags |= $Prot;
1234*7c478bd9Sstevel@tonic-gate		}
1235*7c478bd9Sstevel@tonic-gate
1236*7c478bd9Sstevel@tonic-gate		# If this object is marked as an interposer, tag each symbol.
1237*7c478bd9Sstevel@tonic-gate		if ($Interpose) {
1238*7c478bd9Sstevel@tonic-gate			$Flags |= $Intp;
1239*7c478bd9Sstevel@tonic-gate		}
1240*7c478bd9Sstevel@tonic-gate
1241*7c478bd9Sstevel@tonic-gate		# Identify the symbol as a function or data type, and for the
1242*7c478bd9Sstevel@tonic-gate		# latter, capture the symbol size.  Ignore the standard
1243*7c478bd9Sstevel@tonic-gate		# symbolic labels, as we don't want to type them.
1244*7c478bd9Sstevel@tonic-gate		if ($Fields[8] !~ $MultSyms) {
1245*7c478bd9Sstevel@tonic-gate			if ($Fields[3] =~ /^FUNC$/) {
1246*7c478bd9Sstevel@tonic-gate				$Flags |= $Func;
1247*7c478bd9Sstevel@tonic-gate			} elsif ($Fields[3] =~ /^OBJT$/) {
1248*7c478bd9Sstevel@tonic-gate				my ($Size) = $Fields[2];
1249*7c478bd9Sstevel@tonic-gate
1250*7c478bd9Sstevel@tonic-gate				if (oct($Size) eq 0) {
1251*7c478bd9Sstevel@tonic-gate					$Size = "0";
1252*7c478bd9Sstevel@tonic-gate				} else {
1253*7c478bd9Sstevel@tonic-gate					$Size =~ s/0x0*/0x/;
1254*7c478bd9Sstevel@tonic-gate				}
1255*7c478bd9Sstevel@tonic-gate				$Flags |= $Objt;
1256*7c478bd9Sstevel@tonic-gate				$Symbols{$Fields[8]}{$Obj}[$ObjSize] = $Size;
1257*7c478bd9Sstevel@tonic-gate			}
1258*7c478bd9Sstevel@tonic-gate		}
1259*7c478bd9Sstevel@tonic-gate
1260*7c478bd9Sstevel@tonic-gate		$Symbols{$Fields[8]}{$Obj}[$ObjFlag] |= $Flags;
1261*7c478bd9Sstevel@tonic-gate		$Objects{$Obj}{$Fields[8]} |= $Flags;
1262*7c478bd9Sstevel@tonic-gate
1263*7c478bd9Sstevel@tonic-gate		# If the version field is non-null this object has already been
1264*7c478bd9Sstevel@tonic-gate		# versioned.
1265*7c478bd9Sstevel@tonic-gate		if (($Vers == 0) && ($Fields[6] ne '0')) {
1266*7c478bd9Sstevel@tonic-gate			$Versioned{$Obj} = 1;
1267*7c478bd9Sstevel@tonic-gate			$Vers = 1;
1268*7c478bd9Sstevel@tonic-gate		}
1269*7c478bd9Sstevel@tonic-gate	}
1270*7c478bd9Sstevel@tonic-gate	close($FileHandle);
1271*7c478bd9Sstevel@tonic-gate
1272*7c478bd9Sstevel@tonic-gate	# Obtain any symbol information table for this object.  Symbol tables can
1273*7c478bd9Sstevel@tonic-gate	# be quite large, so open the elfump command through a pipe.
1274*7c478bd9Sstevel@tonic-gate	open($FileHandle, "LC_ALL=C elfdump -y '$Obj' 2> /dev/null |");
1275*7c478bd9Sstevel@tonic-gate
1276*7c478bd9Sstevel@tonic-gate	# Now process all symbols.
1277*7c478bd9Sstevel@tonic-gate	while (defined(my $Line = <$FileHandle>)) {
1278*7c478bd9Sstevel@tonic-gate		chomp($Line);
1279*7c478bd9Sstevel@tonic-gate
1280*7c478bd9Sstevel@tonic-gate		my (@Fields) = split(' ', $Line);
1281*7c478bd9Sstevel@tonic-gate		my ($Flags) = 0;
1282*7c478bd9Sstevel@tonic-gate
1283*7c478bd9Sstevel@tonic-gate		# Binding attributes are in the second column.
1284*7c478bd9Sstevel@tonic-gate		if ($#Fields < 1) {
1285*7c478bd9Sstevel@tonic-gate			next;
1286*7c478bd9Sstevel@tonic-gate		}
1287*7c478bd9Sstevel@tonic-gate		if ($Fields[1] =~ /N/) {
1288*7c478bd9Sstevel@tonic-gate			$Flags |= $Nodi
1289*7c478bd9Sstevel@tonic-gate		}
1290*7c478bd9Sstevel@tonic-gate		if ($Fields[1] =~ /F/) {
1291*7c478bd9Sstevel@tonic-gate			$Flags |= $Ssft;
1292*7c478bd9Sstevel@tonic-gate		}
1293*7c478bd9Sstevel@tonic-gate		if ($Fields[1] =~ /A/) {
1294*7c478bd9Sstevel@tonic-gate			$Flags |= $Saft;
1295*7c478bd9Sstevel@tonic-gate		}
1296*7c478bd9Sstevel@tonic-gate
1297*7c478bd9Sstevel@tonic-gate		# Determine the symbol name based upon the number of fields.
1298*7c478bd9Sstevel@tonic-gate		if ($Flags && $Symbols{$Fields[$#Fields]}{$Obj}) {
1299*7c478bd9Sstevel@tonic-gate			$Symbols{$Fields[$#Fields]}{$Obj}[$ObjFlag] |= $Flags;
1300*7c478bd9Sstevel@tonic-gate			$Objects{$Obj}{$Fields[$#Fields]} |= $Flags;
1301*7c478bd9Sstevel@tonic-gate		}
1302*7c478bd9Sstevel@tonic-gate	}
1303*7c478bd9Sstevel@tonic-gate	close($FileHandle);
1304*7c478bd9Sstevel@tonic-gate
1305*7c478bd9Sstevel@tonic-gate	# If this symbol has already been marked as a copy-relocation reference,
1306*7c478bd9Sstevel@tonic-gate	# see if this symbol has any aliases, which should also be marked.
1307*7c478bd9Sstevel@tonic-gate	if ($Copy) {
1308*7c478bd9Sstevel@tonic-gate		foreach my $SymName (keys(%NameToAddr)) {
1309*7c478bd9Sstevel@tonic-gate			my ($Addr) = $NameToAddr{$SymName};
1310*7c478bd9Sstevel@tonic-gate
1311*7c478bd9Sstevel@tonic-gate			# Determine all symbols that have the same address.
1312*7c478bd9Sstevel@tonic-gate			foreach my $AliasName (@{$AddrToName{$Addr}}) {
1313*7c478bd9Sstevel@tonic-gate				if ($SymName eq $AliasName) {
1314*7c478bd9Sstevel@tonic-gate					next;
1315*7c478bd9Sstevel@tonic-gate				}
1316*7c478bd9Sstevel@tonic-gate				$Symbols{$AliasName}{$Obj}[$ObjFlag] |= $Cpyr;
1317*7c478bd9Sstevel@tonic-gate				$Objects{$Obj}{$AliasName} |= $Cpyr;
1318*7c478bd9Sstevel@tonic-gate			}
1319*7c478bd9Sstevel@tonic-gate		}
1320*7c478bd9Sstevel@tonic-gate	}
1321*7c478bd9Sstevel@tonic-gate}
1322*7c478bd9Sstevel@tonic-gate
1323*7c478bd9Sstevel@tonic-gate# Demangle a symbol name if required.
1324*7c478bd9Sstevel@tonic-gatesub Demangle
1325*7c478bd9Sstevel@tonic-gate{
1326*7c478bd9Sstevel@tonic-gate	my ($SymName) = @_;
1327*7c478bd9Sstevel@tonic-gate	my ($DemName);
1328*7c478bd9Sstevel@tonic-gate
1329*7c478bd9Sstevel@tonic-gate	if ($opt{C}) {
1330*7c478bd9Sstevel@tonic-gate		my (@Dem);
1331*7c478bd9Sstevel@tonic-gate
1332*7c478bd9Sstevel@tonic-gate		# Determine if we've already demangled this name.
1333*7c478bd9Sstevel@tonic-gate		if (exists($DemSyms{$SymName})) {
1334*7c478bd9Sstevel@tonic-gate			return $DemSyms{$SymName};
1335*7c478bd9Sstevel@tonic-gate		}
1336*7c478bd9Sstevel@tonic-gate
1337*7c478bd9Sstevel@tonic-gate		@Dem = split(/\n/, `dem '$SymName'`);
1338*7c478bd9Sstevel@tonic-gate		foreach my $Line (@Dem) {
1339*7c478bd9Sstevel@tonic-gate			my (@Fields) = split(' ', $Line);
1340*7c478bd9Sstevel@tonic-gate
1341*7c478bd9Sstevel@tonic-gate			if (($#Fields < 2) || ($Fields[1] ne '==') ||
1342*7c478bd9Sstevel@tonic-gate			    ($Fields[0] eq $Fields[2])) {
1343*7c478bd9Sstevel@tonic-gate				next;
1344*7c478bd9Sstevel@tonic-gate			}
1345*7c478bd9Sstevel@tonic-gate			$DemName = $Line;
1346*7c478bd9Sstevel@tonic-gate			$DemName =~ s/.*== (.*)$/ \[$1]/;
1347*7c478bd9Sstevel@tonic-gate			$DemSyms{$SymName} = $DemName;
1348*7c478bd9Sstevel@tonic-gate			return($DemName);
1349*7c478bd9Sstevel@tonic-gate		}
1350*7c478bd9Sstevel@tonic-gate	}
1351*7c478bd9Sstevel@tonic-gate	$DemSyms{$SymName} = "";
1352*7c478bd9Sstevel@tonic-gate	return("");
1353*7c478bd9Sstevel@tonic-gate}
1354