xref: /titanic_44/usr/src/tools/scripts/interface_check.pl (revision 75ce41a57ff334bd8fe2cb9ed51eea835892f944)
1*75ce41a5SAli Bahrami#!/usr/bin/perl -w
2*75ce41a5SAli Bahrami#
3*75ce41a5SAli Bahrami# CDDL HEADER START
4*75ce41a5SAli Bahrami#
5*75ce41a5SAli Bahrami# The contents of this file are subject to the terms of the
6*75ce41a5SAli Bahrami# Common Development and Distribution License (the "License").
7*75ce41a5SAli Bahrami# You may not use this file except in compliance with the License.
8*75ce41a5SAli Bahrami#
9*75ce41a5SAli Bahrami# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*75ce41a5SAli Bahrami# or http://www.opensolaris.org/os/licensing.
11*75ce41a5SAli Bahrami# See the License for the specific language governing permissions
12*75ce41a5SAli Bahrami# and limitations under the License.
13*75ce41a5SAli Bahrami#
14*75ce41a5SAli Bahrami# When distributing Covered Code, include this CDDL HEADER in each
15*75ce41a5SAli Bahrami# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*75ce41a5SAli Bahrami# If applicable, add the following below this CDDL HEADER, with the
17*75ce41a5SAli Bahrami# fields enclosed by brackets "[]" replaced with your own identifying
18*75ce41a5SAli Bahrami# information: Portions Copyright [yyyy] [name of copyright owner]
19*75ce41a5SAli Bahrami#
20*75ce41a5SAli Bahrami# CDDL HEADER END
21*75ce41a5SAli Bahrami#
22*75ce41a5SAli Bahrami
23*75ce41a5SAli Bahrami#
24*75ce41a5SAli Bahrami# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
25*75ce41a5SAli Bahrami# Use is subject to license terms.
26*75ce41a5SAli Bahrami#
27*75ce41a5SAli Bahrami
28*75ce41a5SAli Bahrami#
29*75ce41a5SAli Bahrami# Check versioning information.
30*75ce41a5SAli Bahrami#
31*75ce41a5SAli Bahrami# This script descends a directory hierarchy inspecting ELF shared objects for
32*75ce41a5SAli Bahrami# version definitions.  The general theme is to verify that common versioning
33*75ce41a5SAli Bahrami# rules have been used to build these objects.
34*75ce41a5SAli Bahrami#
35*75ce41a5SAli Bahrami# As always, a number of components don't follow the rules, or require
36*75ce41a5SAli Bahrami# special handling. An exceptions file is used to specify these cases.
37*75ce41a5SAli Bahrami#
38*75ce41a5SAli Bahrami# By default any file that has conditions that should be reported is first
39*75ce41a5SAli Bahrami# listed and then each condition follows.  The -o (one-line) option produces a
40*75ce41a5SAli Bahrami# more terse output which is better for sorting/diffing with "nightly".
41*75ce41a5SAli Bahrami#
42*75ce41a5SAli Bahrami# Besides the default operation of checking the files within a directory
43*75ce41a5SAli Bahrami# hierarchy, a detailed analysis of each files versions can be created with the
44*75ce41a5SAli Bahrami# -d option.  The database created is useful for auditing the difference between
45*75ce41a5SAli Bahrami# different builds, and for thus monitoring that versioning changes are made in
46*75ce41a5SAli Bahrami# a compatible manner.
47*75ce41a5SAli Bahrami
48*75ce41a5SAli Bahrami
49*75ce41a5SAli Bahrami# Define all global variables (required for strict)
50*75ce41a5SAli Bahramiuse vars  qw($Prog $Intfdir);
51*75ce41a5SAli Bahramiuse vars  qw(%opt @SaveArgv $ErrFH $ObjCnt);
52*75ce41a5SAli Bahrami
53*75ce41a5SAli Bahrami
54*75ce41a5SAli Bahrami# An exception file is used to specify regular expressions to match
55*75ce41a5SAli Bahrami# objects. These directives specify special attributes of the object.
56*75ce41a5SAli Bahrami# The regular expressions are read from the file and compiled into the
57*75ce41a5SAli Bahrami# regular expression variables.
58*75ce41a5SAli Bahrami#
59*75ce41a5SAli Bahrami# The name of each regular expression variable is of the form
60*75ce41a5SAli Bahrami#
61*75ce41a5SAli Bahrami#	$EXRE_xxx
62*75ce41a5SAli Bahrami#
63*75ce41a5SAli Bahrami# where xxx is the name of the exception in lower case. For example,
64*75ce41a5SAli Bahrami# the regular expression variable for PLUGINS is $EXRE_plugins.
65*75ce41a5SAli Bahrami#
66*75ce41a5SAli Bahrami# onbld_elfmod::LoadExceptionsToEXRE() depends on this naming convention
67*75ce41a5SAli Bahrami# to initialize the regular expression variables, and to detect invalid
68*75ce41a5SAli Bahrami# exception names.
69*75ce41a5SAli Bahrami#
70*75ce41a5SAli Bahrami# If a given exception is not used in the exception file, its regular
71*75ce41a5SAli Bahrami# expression variable will be undefined. Users of these variables must
72*75ce41a5SAli Bahrami# test the variable with defined() prior to use:
73*75ce41a5SAli Bahrami#
74*75ce41a5SAli Bahrami#	defined($EXRE_plugins) && ($foo =~ $EXRE_plugins)
75*75ce41a5SAli Bahrami#
76*75ce41a5SAli Bahrami# ----
77*75ce41a5SAli Bahrami#
78*75ce41a5SAli Bahrami# The exceptions are:
79*75ce41a5SAli Bahrami#
80*75ce41a5SAli Bahrami# NONSTD_VERNAME
81*75ce41a5SAli Bahrami#	Objects are expected to use standard names for versions.
82*75ce41a5SAli Bahrami#	This directive is used to relax that requirement.
83*75ce41a5SAli Bahrami#
84*75ce41a5SAli Bahrami# NOVERDEF
85*75ce41a5SAli Bahrami#	Objects that are not required to have a versioned name. Note that
86*75ce41a5SAli Bahrami#	PLUGINS objects are implicitly NOVERDEF, so this directive is
87*75ce41a5SAli Bahrami#	for use with non-plugin objects.
88*75ce41a5SAli Bahrami#
89*75ce41a5SAli Bahrami# PLUGINS
90*75ce41a5SAli Bahrami#	Plugin objects are not required to have a versioned name, and are
91*75ce41a5SAli Bahrami#	not required to be internally versioned.
92*75ce41a5SAli Bahrami#
93*75ce41a5SAli Bahramiuse vars  qw($EXRE_nonstd_vername $EXRE_noverdef $EXRE_plugin);
94*75ce41a5SAli Bahrami
95*75ce41a5SAli Bahramiuse strict;
96*75ce41a5SAli Bahrami
97*75ce41a5SAli Bahramiuse POSIX qw(getenv);
98*75ce41a5SAli Bahramiuse Getopt::Std;
99*75ce41a5SAli Bahramiuse File::Basename;
100*75ce41a5SAli Bahrami
101*75ce41a5SAli Bahrami
102*75ce41a5SAli Bahrami
103*75ce41a5SAli Bahrami
104*75ce41a5SAli Bahrami## ProcFile(BasePath, RelPath, Class, Type, Verdef, Alias)
105*75ce41a5SAli Bahrami#
106*75ce41a5SAli Bahrami# Investigate runtime attributes of a sharable object
107*75ce41a5SAli Bahrami#
108*75ce41a5SAli Bahrami# entry:
109*75ce41a5SAli Bahrami#	BasePath - Base path from which relative paths are taken
110*75ce41a5SAli Bahrami#	RelPath - Path of object taken relative to BasePath
111*75ce41a5SAli Bahrami#	Class - ELFCLASS of object
112*75ce41a5SAli Bahrami#	Type - ELF type of object
113*75ce41a5SAli Bahrami#	Verdef - VERDEF if object defines versions, NOVERDEF otherwise
114*75ce41a5SAli Bahrami#	Alias - Alias lines corresponding to the object, or an empty ('')
115*75ce41a5SAli Bahrami#		string if there are no aliases.
116*75ce41a5SAli Bahrami#
117*75ce41a5SAli Bahramisub ProcFile {
118*75ce41a5SAli Bahrami	my($BasePath, $RelPath, $Class, $Type, $Verdef, $Alias) = @_;
119*75ce41a5SAli Bahrami
120*75ce41a5SAli Bahrami	my($File, $FullPath, %Vers, $VersCnt, %TopVer);
121*75ce41a5SAli Bahrami	my($Val, $Ttl, $NotPlugin);
122*75ce41a5SAli Bahrami
123*75ce41a5SAli Bahrami	$FullPath = "$BasePath/$RelPath";
124*75ce41a5SAli Bahrami	@_ = split /\//, $RelPath;
125*75ce41a5SAli Bahrami	$File = $_[$#_];
126*75ce41a5SAli Bahrami
127*75ce41a5SAli Bahrami	$Ttl = 0;
128*75ce41a5SAli Bahrami
129*75ce41a5SAli Bahrami	# If this object does not follow the runtime versioned name convention,
130*75ce41a5SAli Bahrami	# and it does not reside underneath a directory identified as
131*75ce41a5SAli Bahrami	# containing plugin objects intended for use with dlopen() only,
132*75ce41a5SAli Bahrami	# issue a warning.
133*75ce41a5SAli Bahrami	$NotPlugin = !defined($EXRE_plugin) || ($RelPath !~ $EXRE_plugin);
134*75ce41a5SAli Bahrami	if (($File !~ /\.so\./) && $NotPlugin) {
135*75ce41a5SAli Bahrami		onbld_elfmod::OutMsg($ErrFH, \$Ttl, $RelPath,
136*75ce41a5SAli Bahrami		    "does not have a versioned name");
137*75ce41a5SAli Bahrami	}
138*75ce41a5SAli Bahrami
139*75ce41a5SAli Bahrami	# If there are no versions in the file we're done.
140*75ce41a5SAli Bahrami	if ($Verdef eq 'NOVERDEF') {
141*75ce41a5SAli Bahrami	        # Report the lack of versioning, unless the object is
142*75ce41a5SAli Bahrami	    	# a known plugin, or is explicitly exempt.
143*75ce41a5SAli Bahrami		if ($NotPlugin &&
144*75ce41a5SAli Bahrami		    (!defined($EXRE_noverdef) || ($RelPath !~ $EXRE_noverdef))) {
145*75ce41a5SAli Bahrami			onbld_elfmod::OutMsg($ErrFH, \$Ttl, $RelPath,
146*75ce41a5SAli Bahrami			    "no versions found");
147*75ce41a5SAli Bahrami		}
148*75ce41a5SAli Bahrami		return;
149*75ce41a5SAli Bahrami	}
150*75ce41a5SAli Bahrami
151*75ce41a5SAli Bahrami	# Get a hash of the top versions in the inheritance chains.
152*75ce41a5SAli Bahrami	%TopVer = ();
153*75ce41a5SAli Bahrami	foreach my $Line (split(/\n/, `pvs -don $FullPath 2>&1`)) {
154*75ce41a5SAli Bahrami		$Line =~ s/^.*-\s*(.*);/$1/;
155*75ce41a5SAli Bahrami		$TopVer{$Line} = 1;
156*75ce41a5SAli Bahrami	}
157*75ce41a5SAli Bahrami
158*75ce41a5SAli Bahrami	# First determine what versions exist that offer interfaces.  pvs -dos
159*75ce41a5SAli Bahrami	# will list these.  Note that other versions may exist, ones that
160*75ce41a5SAli Bahrami	# don't offer interfaces ... we'll get to those next.
161*75ce41a5SAli Bahrami	%Vers = ();
162*75ce41a5SAli Bahrami	$VersCnt = 0;
163*75ce41a5SAli Bahrami	my %TopSUNWVers = ();
164*75ce41a5SAli Bahrami	foreach my $Line (split(/\n/, `pvs -dos $FullPath 2>&1`)) {
165*75ce41a5SAli Bahrami		my($Ver) = $Line;
166*75ce41a5SAli Bahrami
167*75ce41a5SAli Bahrami		$Ver =~ s/^.*-\t(.*): .*/$1/; 		# isolate version
168*75ce41a5SAli Bahrami
169*75ce41a5SAli Bahrami		# See if we've already caught this version name. We only look
170*75ce41a5SAli Bahrami		# at each version once.
171*75ce41a5SAli Bahrami		next if ($Vers{$Ver}) ;
172*75ce41a5SAli Bahrami
173*75ce41a5SAli Bahrami		# Note that the non-empty version has been seen
174*75ce41a5SAli Bahrami		$Vers{$Ver} = 1;
175*75ce41a5SAli Bahrami		$VersCnt++;
176*75ce41a5SAli Bahrami
177*75ce41a5SAli Bahrami		# We expect the public SUNW_major.minor.micro versions to use
178*75ce41a5SAli Bahrami		# inheritance, so there should only be one top version for
179*75ce41a5SAli Bahrami		# each major number. It is possible, though rare, to have
180*75ce41a5SAli Bahrami		# more than one top version if the major numbers differ.
181*75ce41a5SAli Bahrami		#
182*75ce41a5SAli Bahrami		# %TopSUNWVers uses the major name as the key, with each
183*75ce41a5SAli Bahrami		# value yielding an array reference to the top versions for
184*75ce41a5SAli Bahrami		# that major number.
185*75ce41a5SAli Bahrami		if ($Ver =~ /^(SUNW_[0-9]+)[0-9.]+$/) {
186*75ce41a5SAli Bahrami			push @{$TopSUNWVers{$1}}, $Ver if $TopVer{$Ver};
187*75ce41a5SAli Bahrami			next;
188*75ce41a5SAli Bahrami		}
189*75ce41a5SAli Bahrami
190*75ce41a5SAli Bahrami		# Having already handled SUNW_ public versions above, is it
191*75ce41a5SAli Bahrami		# a different version name that we recognise?
192*75ce41a5SAli Bahrami		#
193*75ce41a5SAli Bahrami		# Along with the standard version names, each object exports
194*75ce41a5SAli Bahrami		# a "base" version which contains the linker generated symbols
195*75ce41a5SAli Bahrami		# _etext, _edata, etc., and is named using the objects SONAME.
196*75ce41a5SAli Bahrami		# This name should typically match the file name.
197*75ce41a5SAli Bahrami		next if (($Ver =~ /^SYSVABI_1.[23]$/) ||
198*75ce41a5SAli Bahrami		    ($Ver =~ /^SISCD_2.3[ab]*$/) ||
199*75ce41a5SAli Bahrami		    ($Ver =~ /^SUNWprivate(_[0-9.]+)?$/) ||
200*75ce41a5SAli Bahrami		    ($Ver =~ /$File/));
201*75ce41a5SAli Bahrami
202*75ce41a5SAli Bahrami		# If we get here, it's a non-standard version.
203*75ce41a5SAli Bahrami		if (!defined($EXRE_nonstd_vername) ||
204*75ce41a5SAli Bahrami		    ($RelPath !~ $EXRE_nonstd_vername)) {
205*75ce41a5SAli Bahrami			onbld_elfmod::OutMsg($ErrFH, \$Ttl, $RelPath,
206*75ce41a5SAli Bahrami			   "non-standard version name: $Ver");
207*75ce41a5SAli Bahrami		}
208*75ce41a5SAli Bahrami		next;
209*75ce41a5SAli Bahrami	}
210*75ce41a5SAli Bahrami
211*75ce41a5SAli Bahrami	# If this file has been scoped, but not versioned (i.e., a mapfile was
212*75ce41a5SAli Bahrami	# used to demote symbols but no version name was applied to the
213*75ce41a5SAli Bahrami	# global interfaces) then it's another non-standard case.
214*75ce41a5SAli Bahrami	if ($VersCnt eq 0) {
215*75ce41a5SAli Bahrami		onbld_elfmod::OutMsg($ErrFH, \$Ttl, $RelPath,
216*75ce41a5SAli Bahrami		    "scoped object contains no versions");
217*75ce41a5SAli Bahrami		return;
218*75ce41a5SAli Bahrami	}
219*75ce41a5SAli Bahrami
220*75ce41a5SAli Bahrami	# If this file has multiple inheritance chains with the public
221*75ce41a5SAli Bahrami	# SUNW_ name, that's wrong.
222*75ce41a5SAli Bahrami	foreach my $Ver (sort keys %TopSUNWVers) {
223*75ce41a5SAli Bahrami		if (scalar(@{$TopSUNWVers{$Ver}}) > 1) {
224*75ce41a5SAli Bahrami			onbld_elfmod::OutMsg($ErrFH, \$Ttl, $RelPath,
225*75ce41a5SAli Bahrami			    "multiple $Ver inheritance chains (missing " .
226*75ce41a5SAli Bahrami			    "inheritance?): " .
227*75ce41a5SAli Bahrami			    join(', ', @{$TopSUNWVers{$Ver}}));
228*75ce41a5SAli Bahrami		}
229*75ce41a5SAli Bahrami	}
230*75ce41a5SAli Bahrami
231*75ce41a5SAli Bahrami
232*75ce41a5SAli Bahrami	# Produce an interface description for the object.
233*75ce41a5SAli Bahrami	# For each version, generate a VERSION declaration of the form:
234*75ce41a5SAli Bahrami	#
235*75ce41a5SAli Bahrami	#	[TOP_]VERSION  version  direct-count  total-count
236*75ce41a5SAli Bahrami	#		symname1
237*75ce41a5SAli Bahrami	#		symname2
238*75ce41a5SAli Bahrami	#		...
239*75ce41a5SAli Bahrami	#
240*75ce41a5SAli Bahrami	# There are two types of version that we suppress from this
241*75ce41a5SAli Bahrami	# output:
242*75ce41a5SAli Bahrami	#
243*75ce41a5SAli Bahrami	# 	BASE
244*75ce41a5SAli Bahrami	#	The "base" version is used to hold symbols that must be
245*75ce41a5SAli Bahrami	#	public, but which are not part of the versioning interface
246*75ce41a5SAli Bahrami	#	(_end, _GLOBAL_OFFSET_TABLE_, _PROCEDURE_LINKAGE_TABLE_, etc).
247*75ce41a5SAli Bahrami	#
248*75ce41a5SAli Bahrami	#	Private
249*75ce41a5SAli Bahrami	#	Any version with "private" in its name is skipped. We
250*75ce41a5SAli Bahrami	#	expect these to be SUNWprivate, but are extra lenient in
251*75ce41a5SAli Bahrami	#	what we accept.
252*75ce41a5SAli Bahrami	#
253*75ce41a5SAli Bahrami	# If an object only has base or private versions, we do not produce
254*75ce41a5SAli Bahrami	# an interface description for that object.
255*75ce41a5SAli Bahrami	#
256*75ce41a5SAli Bahrami	if ($opt{i}) {
257*75ce41a5SAli Bahrami		my $header_done = 0;
258*75ce41a5SAli Bahrami
259*75ce41a5SAli Bahrami		# The use of 'pvs -v' is to identify the BASE version
260*75ce41a5SAli Bahrami		foreach my $Line (split(/\n/, `pvs -dv $FullPath 2>&1`)) {
261*75ce41a5SAli Bahrami			# Skip base version
262*75ce41a5SAli Bahrami			next if ($Line =~ /\[BASE\]/);
263*75ce41a5SAli Bahrami
264*75ce41a5SAli Bahrami			# Skip private versions
265*75ce41a5SAli Bahrami			next if ($Line =~ /private/i);
266*75ce41a5SAli Bahrami
267*75ce41a5SAli Bahrami			# Directly inherited versions follow the version name
268*75ce41a5SAli Bahrami			# in a comma separated list within {} brackets. Capture
269*75ce41a5SAli Bahrami			# that information, for use with our VERSION line.
270*75ce41a5SAli Bahrami			my $InheritVers = ($Line =~ /(\{.*\});$/) ? "\t$1" : '';
271*75ce41a5SAli Bahrami
272*75ce41a5SAli Bahrami			$Line =~ s/^\s*([^;: ]*).*/$1/;
273*75ce41a5SAli Bahrami
274*75ce41a5SAli Bahrami			# Older versions of pvs have a bug that prevents
275*75ce41a5SAli Bahrami			# them from printing [BASE] on the base version.
276*75ce41a5SAli Bahrami			# Work around this by excluding versions that end
277*75ce41a5SAli Bahrami			# with a '.so.*' suffix.
278*75ce41a5SAli Bahrami			# SONAME of the object.
279*75ce41a5SAli Bahrami			next if $Line =~ /\.so\.\d+$/;
280*75ce41a5SAli Bahrami
281*75ce41a5SAli Bahrami			# We want to output the symbols in sorted order, so
282*75ce41a5SAli Bahrami			# we gather them first, and then sort the results.
283*75ce41a5SAli Bahrami			# An array would suffice, but we have observed objects
284*75ce41a5SAli Bahrami			# with odd inheritance chains in which the same
285*75ce41a5SAli Bahrami			# sub-version gets inherited more than once, leading
286*75ce41a5SAli Bahrami			# to the same symbol showing up more than once. Using
287*75ce41a5SAli Bahrami			# a hash instead of an array thins out the duplicates.
288*75ce41a5SAli Bahrami			my %Syms = ();
289*75ce41a5SAli Bahrami			my $symitem = $opt{I} ? 'NEW' : 'SYMBOL';
290*75ce41a5SAli Bahrami			my $version_cnt = 0;
291*75ce41a5SAli Bahrami			foreach my $Sym
292*75ce41a5SAli Bahrami			    (split(/\n/, `pvs -ds -N $Line $FullPath 2>&1`)) {
293*75ce41a5SAli Bahrami				if ($Sym =~ /:$/) {
294*75ce41a5SAli Bahrami					$version_cnt++;
295*75ce41a5SAli Bahrami					# If this is an inherited sub-version,
296*75ce41a5SAli Bahrami					# we don't need to continue unless
297*75ce41a5SAli Bahrami					# generating output in -I mode.
298*75ce41a5SAli Bahrami					if ($version_cnt >= 2) {
299*75ce41a5SAli Bahrami						last if !$opt{I};
300*75ce41a5SAli Bahrami						$symitem = 'INHERIT';
301*75ce41a5SAli Bahrami					}
302*75ce41a5SAli Bahrami					next;
303*75ce41a5SAli Bahrami				}
304*75ce41a5SAli Bahrami				$Sym =~ s/[ \t]*(.*);$/$1/;
305*75ce41a5SAli Bahrami				$Sym =~ s/ .*$//;	# remove any data size
306*75ce41a5SAli Bahrami				$Syms{$Sym} = $symitem;
307*75ce41a5SAli Bahrami			}
308*75ce41a5SAli Bahrami
309*75ce41a5SAli Bahrami			if (!$header_done) {
310*75ce41a5SAli Bahrami				print INTFILE "\n" if !$opt{h} && ($ObjCnt != 0);
311*75ce41a5SAli Bahrami				$ObjCnt++;
312*75ce41a5SAli Bahrami				print INTFILE "OBJECT\t$RelPath\n";
313*75ce41a5SAli Bahrami				print INTFILE "CLASS\tELFCLASS$Class\n";
314*75ce41a5SAli Bahrami				print INTFILE "TYPE\tET_$Type\n";
315*75ce41a5SAli Bahrami				print INTFILE $Alias if ($Alias ne '');
316*75ce41a5SAli Bahrami				$header_done = 1;
317*75ce41a5SAli Bahrami			}
318*75ce41a5SAli Bahrami
319*75ce41a5SAli Bahrami			my $item = $TopVer{$Line} ? 'TOP_VERSION' : 'VERSION';
320*75ce41a5SAli Bahrami			print INTFILE "$item\t$Line$InheritVers\n";
321*75ce41a5SAli Bahrami
322*75ce41a5SAli Bahrami			# Output symbols in sorted order
323*75ce41a5SAli Bahrami			foreach my $Sym (sort keys %Syms) {
324*75ce41a5SAli Bahrami				print INTFILE "\t$Syms{$Sym}\t$Sym\n";
325*75ce41a5SAli Bahrami			}
326*75ce41a5SAli Bahrami		}
327*75ce41a5SAli Bahrami	}
328*75ce41a5SAli Bahrami}
329*75ce41a5SAli Bahrami
330*75ce41a5SAli Bahrami## ProcFindElf(file)
331*75ce41a5SAli Bahrami#
332*75ce41a5SAli Bahrami# Open the specified file, which must be produced by "find_elf -r",
333*75ce41a5SAli Bahrami# and process the files it describes.
334*75ce41a5SAli Bahramisub ProcFindElf {
335*75ce41a5SAli Bahrami	my $file = $_[0];
336*75ce41a5SAli Bahrami	my $line;
337*75ce41a5SAli Bahrami	my $LineNum = 0;
338*75ce41a5SAli Bahrami	my $prefix;
339*75ce41a5SAli Bahrami	my @ObjList = ();
340*75ce41a5SAli Bahrami	my %ObjToAlias = ();
341*75ce41a5SAli Bahrami
342*75ce41a5SAli Bahrami	open(FIND_ELF, $file) || die "$Prog: Unable to open $file";
343*75ce41a5SAli Bahrami
344*75ce41a5SAli Bahrami	# This script requires relative paths, created by the 'find_elf -r'
345*75ce41a5SAli Bahrami	# option. When this is done, the first non-comment line will always
346*75ce41a5SAli Bahrami	# be PREFIX. Obtain that line, or issue a fatal error.
347*75ce41a5SAli Bahrami	while ($line = onbld_elfmod::GetLine(\*FIND_ELF, \$LineNum)) {
348*75ce41a5SAli Bahrami		if ($line =~ /^PREFIX\s+(.*)$/) {
349*75ce41a5SAli Bahrami			$prefix = $1;
350*75ce41a5SAli Bahrami			last;
351*75ce41a5SAli Bahrami		}
352*75ce41a5SAli Bahrami
353*75ce41a5SAli Bahrami		die "$file: PREFIX expected on line $LineNum\n";
354*75ce41a5SAli Bahrami	}
355*75ce41a5SAli Bahrami
356*75ce41a5SAli Bahrami
357*75ce41a5SAli Bahrami	# Process the remainder of the file.
358*75ce41a5SAli Bahrami	while ($line = onbld_elfmod::GetLine(\*FIND_ELF, \$LineNum)) {
359*75ce41a5SAli Bahrami		if ($line =~ /^OBJECT\s/i) {
360*75ce41a5SAli Bahrami			push @ObjList, $line;
361*75ce41a5SAli Bahrami			next;
362*75ce41a5SAli Bahrami		}
363*75ce41a5SAli Bahrami
364*75ce41a5SAli Bahrami		if ($line =~ /^ALIAS\s/i) {
365*75ce41a5SAli Bahrami			my ($item, $obj, $alias) = split(/\s+/, $line, 3);
366*75ce41a5SAli Bahrami			my $str = "ALIAS\t$alias\n";
367*75ce41a5SAli Bahrami
368*75ce41a5SAli Bahrami			if (defined($ObjToAlias{$obj})) {
369*75ce41a5SAli Bahrami				$ObjToAlias{$obj} .= $str;
370*75ce41a5SAli Bahrami			} else {
371*75ce41a5SAli Bahrami				$ObjToAlias{$obj} = $str;
372*75ce41a5SAli Bahrami			}
373*75ce41a5SAli Bahrami		}
374*75ce41a5SAli Bahrami	}
375*75ce41a5SAli Bahrami
376*75ce41a5SAli Bahrami	foreach $line (@ObjList) {
377*75ce41a5SAli Bahrami		my ($item, $class, $type, $verdef, $obj) =
378*75ce41a5SAli Bahrami		    split(/\s+/, $line, 5);
379*75ce41a5SAli Bahrami
380*75ce41a5SAli Bahrami		my $alias = defined($ObjToAlias{$obj}) ? $ObjToAlias{$obj} : '';
381*75ce41a5SAli Bahrami
382*75ce41a5SAli Bahrami		# We are only interested in sharable objects. We may see
383*75ce41a5SAli Bahrami		# other file types if processing a list of objects
384*75ce41a5SAli Bahrami		# supplied via the -f option.
385*75ce41a5SAli Bahrami		next if ($type ne 'DYN');
386*75ce41a5SAli Bahrami
387*75ce41a5SAli Bahrami		ProcFile($prefix, $obj, $class, $type, $verdef, $alias);
388*75ce41a5SAli Bahrami	}
389*75ce41a5SAli Bahrami
390*75ce41a5SAli Bahrami	close FIND_ELF;
391*75ce41a5SAli Bahrami}
392*75ce41a5SAli Bahrami
393*75ce41a5SAli Bahrami
394*75ce41a5SAli Bahrami# -----------------------------------------------------------------------------
395*75ce41a5SAli Bahrami
396*75ce41a5SAli Bahrami# Establish a program name for any error diagnostics.
397*75ce41a5SAli Bahramichomp($Prog = `basename $0`);
398*75ce41a5SAli Bahrami
399*75ce41a5SAli Bahrami# The onbld_elfmod package is maintained in the same directory as this
400*75ce41a5SAli Bahrami# script, and is installed in ../lib/perl. Use the local one if present,
401*75ce41a5SAli Bahrami# and the installed one otherwise.
402*75ce41a5SAli Bahramimy $moddir = dirname($0);
403*75ce41a5SAli Bahrami$moddir = "$moddir/../lib/perl" if ! -f "$moddir/onbld_elfmod.pm";
404*75ce41a5SAli Bahramirequire "$moddir/onbld_elfmod.pm";
405*75ce41a5SAli Bahrami
406*75ce41a5SAli Bahrami# Check that we have arguments.
407*75ce41a5SAli Bahrami@SaveArgv = @ARGV;
408*75ce41a5SAli Bahramiif ((getopts('E:e:f:hIi:ow:', \%opt) == 0) || (!$opt{f} && ($#ARGV == -1))) {
409*75ce41a5SAli Bahrami	print "usage: $Prog [-hIo] [-E errfile] [-e exfile] [-f listfile]\n";
410*75ce41a5SAli Bahrami	print "\t\t[-i intffile] [-w outdir] file | dir, ...\n";
411*75ce41a5SAli Bahrami	print "\n";
412*75ce41a5SAli Bahrami	print "\t[-E errfile]\tdirect error output to file\n";
413*75ce41a5SAli Bahrami	print "\t[-e exfile]\texceptions file\n";
414*75ce41a5SAli Bahrami	print "\t[-f listfile]\tuse file list produced by find_elf -r\n";
415*75ce41a5SAli Bahrami	print "\t[-h]\tdo not produce a CDDL/Copyright header comment\n";
416*75ce41a5SAli Bahrami	print "\t[-I]\tExpand inheritance in -i output (debugging)\n";
417*75ce41a5SAli Bahrami	print "\t[-i intffile]\tcreate interface description output file\n";
418*75ce41a5SAli Bahrami	print "\t[-o]\t\tproduce one-liner output (prefixed with pathname)\n";
419*75ce41a5SAli Bahrami	print "\t[-w outdir]\tinterpret all files relative to given directory\n";
420*75ce41a5SAli Bahrami	exit 1;
421*75ce41a5SAli Bahrami}
422*75ce41a5SAli Bahrami
423*75ce41a5SAli Bahrami# If -w, change working directory to given location
424*75ce41a5SAli Bahrami!$opt{w} || chdir($opt{w}) || die "$Prog: can't cd to $opt{w}";
425*75ce41a5SAli Bahrami
426*75ce41a5SAli Bahrami
427*75ce41a5SAli Bahrami# Error messages go to stdout unless -E is specified. $ErrFH is a
428*75ce41a5SAli Bahrami# file handle reference that points at the file handle where error messages
429*75ce41a5SAli Bahrami# are sent.
430*75ce41a5SAli Bahramiif ($opt{E}) {
431*75ce41a5SAli Bahrami	open(ERROR, ">$opt{E}") || die "$Prog: open failed: $opt{E}";
432*75ce41a5SAli Bahrami	$ErrFH = \*ERROR;
433*75ce41a5SAli Bahrami} else {
434*75ce41a5SAli Bahrami	$ErrFH = \*STDOUT;
435*75ce41a5SAli Bahrami}
436*75ce41a5SAli Bahrami
437*75ce41a5SAli Bahrami# Locate and process the exceptions file
438*75ce41a5SAli Bahramionbld_elfmod::LoadExceptionsToEXRE('interface_check');
439*75ce41a5SAli Bahrami
440*75ce41a5SAli Bahrami# If creating an interface description output file, prepare it for use
441*75ce41a5SAli Bahramiif ($opt{i}) {
442*75ce41a5SAli Bahrami	open (INTFILE, ">$opt{i}") ||
443*75ce41a5SAli Bahrami	    die "$Prog: Unable to create file: $opt{i}";
444*75ce41a5SAli Bahrami
445*75ce41a5SAli Bahrami	# Generate the output header
446*75ce41a5SAli Bahrami	onbld_elfmod::Header(\*INTFILE, $0, \@SaveArgv) if !$opt{h};;
447*75ce41a5SAli Bahrami}
448*75ce41a5SAli Bahrami
449*75ce41a5SAli Bahrami# Number of OBJECTs output to INTFILE
450*75ce41a5SAli Bahrami$ObjCnt = 0;
451*75ce41a5SAli Bahrami
452*75ce41a5SAli Bahrami# If we were passed a file previously produced by 'find_elf -r', use it.
453*75ce41a5SAli BahramiProcFindElf($opt{f}) if $opt{f};
454*75ce41a5SAli Bahrami
455*75ce41a5SAli Bahrami# Process each argument
456*75ce41a5SAli Bahramiforeach my $Arg (@ARGV) {
457*75ce41a5SAli Bahrami	# Run find_elf to find the files given by $Arg and process them
458*75ce41a5SAli Bahrami	ProcFindElf("find_elf -frs $Arg|");
459*75ce41a5SAli Bahrami}
460*75ce41a5SAli Bahrami
461*75ce41a5SAli Bahrami# Close any working output files.
462*75ce41a5SAli Bahramiclose INTFILE if $opt{i};
463*75ce41a5SAli Bahramiclose ERROR if $opt{E};
464*75ce41a5SAli Bahrami
465*75ce41a5SAli Bahramiexit 0;
466