175ce41a5SAli Bahrami#!/usr/bin/perl -w
275ce41a5SAli Bahrami#
375ce41a5SAli Bahrami# CDDL HEADER START
475ce41a5SAli Bahrami#
575ce41a5SAli Bahrami# The contents of this file are subject to the terms of the
675ce41a5SAli Bahrami# Common Development and Distribution License (the "License").
775ce41a5SAli Bahrami# You may not use this file except in compliance with the License.
875ce41a5SAli Bahrami#
975ce41a5SAli Bahrami# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1075ce41a5SAli Bahrami# or http://www.opensolaris.org/os/licensing.
1175ce41a5SAli Bahrami# See the License for the specific language governing permissions
1275ce41a5SAli Bahrami# and limitations under the License.
1375ce41a5SAli Bahrami#
1475ce41a5SAli Bahrami# When distributing Covered Code, include this CDDL HEADER in each
1575ce41a5SAli Bahrami# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1675ce41a5SAli Bahrami# If applicable, add the following below this CDDL HEADER, with the
1775ce41a5SAli Bahrami# fields enclosed by brackets "[]" replaced with your own identifying
1875ce41a5SAli Bahrami# information: Portions Copyright [yyyy] [name of copyright owner]
1975ce41a5SAli Bahrami#
2075ce41a5SAli Bahrami# CDDL HEADER END
2175ce41a5SAli Bahrami#
2275ce41a5SAli Bahrami
2375ce41a5SAli Bahrami#
24*5253169eSAli Bahrami# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2575ce41a5SAli Bahrami#
2675ce41a5SAli Bahrami
2775ce41a5SAli Bahrami#
2875ce41a5SAli Bahrami# Check versioning information.
2975ce41a5SAli Bahrami#
3075ce41a5SAli Bahrami# This script descends a directory hierarchy inspecting ELF shared objects for
3175ce41a5SAli Bahrami# version definitions.  The general theme is to verify that common versioning
3275ce41a5SAli Bahrami# rules have been used to build these objects.
3375ce41a5SAli Bahrami#
3475ce41a5SAli Bahrami# As always, a number of components don't follow the rules, or require
3575ce41a5SAli Bahrami# special handling. An exceptions file is used to specify these cases.
3675ce41a5SAli Bahrami#
3775ce41a5SAli Bahrami# By default any file that has conditions that should be reported is first
3875ce41a5SAli Bahrami# listed and then each condition follows.  The -o (one-line) option produces a
3975ce41a5SAli Bahrami# more terse output which is better for sorting/diffing with "nightly".
4075ce41a5SAli Bahrami#
4175ce41a5SAli Bahrami# Besides the default operation of checking the files within a directory
4275ce41a5SAli Bahrami# hierarchy, a detailed analysis of each files versions can be created with the
4375ce41a5SAli Bahrami# -d option.  The database created is useful for auditing the difference between
4475ce41a5SAli Bahrami# different builds, and for thus monitoring that versioning changes are made in
4575ce41a5SAli Bahrami# a compatible manner.
4675ce41a5SAli Bahrami
4775ce41a5SAli Bahrami
4875ce41a5SAli Bahrami# Define all global variables (required for strict)
4975ce41a5SAli Bahramiuse vars  qw($Prog $Intfdir);
5075ce41a5SAli Bahramiuse vars  qw(%opt @SaveArgv $ErrFH $ObjCnt);
5175ce41a5SAli Bahrami
5275ce41a5SAli Bahrami
5375ce41a5SAli Bahrami# An exception file is used to specify regular expressions to match
5475ce41a5SAli Bahrami# objects. These directives specify special attributes of the object.
5575ce41a5SAli Bahrami# The regular expressions are read from the file and compiled into the
5675ce41a5SAli Bahrami# regular expression variables.
5775ce41a5SAli Bahrami#
5875ce41a5SAli Bahrami# The name of each regular expression variable is of the form
5975ce41a5SAli Bahrami#
6075ce41a5SAli Bahrami#	$EXRE_xxx
6175ce41a5SAli Bahrami#
6275ce41a5SAli Bahrami# where xxx is the name of the exception in lower case. For example,
6375ce41a5SAli Bahrami# the regular expression variable for PLUGINS is $EXRE_plugins.
6475ce41a5SAli Bahrami#
6575ce41a5SAli Bahrami# onbld_elfmod::LoadExceptionsToEXRE() depends on this naming convention
6675ce41a5SAli Bahrami# to initialize the regular expression variables, and to detect invalid
6775ce41a5SAli Bahrami# exception names.
6875ce41a5SAli Bahrami#
6975ce41a5SAli Bahrami# If a given exception is not used in the exception file, its regular
7075ce41a5SAli Bahrami# expression variable will be undefined. Users of these variables must
7175ce41a5SAli Bahrami# test the variable with defined() prior to use:
7275ce41a5SAli Bahrami#
7375ce41a5SAli Bahrami#	defined($EXRE_plugins) && ($foo =~ $EXRE_plugins)
7475ce41a5SAli Bahrami#
7575ce41a5SAli Bahrami# ----
7675ce41a5SAli Bahrami#
7775ce41a5SAli Bahrami# The exceptions are:
7875ce41a5SAli Bahrami#
7975ce41a5SAli Bahrami# NONSTD_VERNAME
8075ce41a5SAli Bahrami#	Objects are expected to use standard names for versions.
8175ce41a5SAli Bahrami#	This directive is used to relax that requirement.
8275ce41a5SAli Bahrami#
8375ce41a5SAli Bahrami# NOVERDEF
8475ce41a5SAli Bahrami#	Objects that are not required to have a versioned name. Note that
8575ce41a5SAli Bahrami#	PLUGINS objects are implicitly NOVERDEF, so this directive is
8675ce41a5SAli Bahrami#	for use with non-plugin objects.
8775ce41a5SAli Bahrami#
8875ce41a5SAli Bahrami# PLUGINS
8975ce41a5SAli Bahrami#	Plugin objects are not required to have a versioned name, and are
9075ce41a5SAli Bahrami#	not required to be internally versioned.
9175ce41a5SAli Bahrami#
9275ce41a5SAli Bahramiuse vars  qw($EXRE_nonstd_vername $EXRE_noverdef $EXRE_plugin);
9375ce41a5SAli Bahrami
9475ce41a5SAli Bahramiuse strict;
9575ce41a5SAli Bahrami
9675ce41a5SAli Bahramiuse POSIX qw(getenv);
9775ce41a5SAli Bahramiuse Getopt::Std;
9875ce41a5SAli Bahramiuse File::Basename;
9975ce41a5SAli Bahrami
10075ce41a5SAli Bahrami
10175ce41a5SAli Bahrami
10275ce41a5SAli Bahrami
10375ce41a5SAli Bahrami## ProcFile(BasePath, RelPath, Class, Type, Verdef, Alias)
10475ce41a5SAli Bahrami#
10575ce41a5SAli Bahrami# Investigate runtime attributes of a sharable object
10675ce41a5SAli Bahrami#
10775ce41a5SAli Bahrami# entry:
10875ce41a5SAli Bahrami#	BasePath - Base path from which relative paths are taken
10975ce41a5SAli Bahrami#	RelPath - Path of object taken relative to BasePath
11075ce41a5SAli Bahrami#	Class - ELFCLASS of object
11175ce41a5SAli Bahrami#	Type - ELF type of object
11275ce41a5SAli Bahrami#	Verdef - VERDEF if object defines versions, NOVERDEF otherwise
11375ce41a5SAli Bahrami#	Alias - Alias lines corresponding to the object, or an empty ('')
11475ce41a5SAli Bahrami#		string if there are no aliases.
11575ce41a5SAli Bahrami#
11675ce41a5SAli Bahramisub ProcFile {
11775ce41a5SAli Bahrami	my($BasePath, $RelPath, $Class, $Type, $Verdef, $Alias) = @_;
11875ce41a5SAli Bahrami
11975ce41a5SAli Bahrami	my($File, $FullPath, %Vers, $VersCnt, %TopVer);
12075ce41a5SAli Bahrami	my($Val, $Ttl, $NotPlugin);
12175ce41a5SAli Bahrami
12275ce41a5SAli Bahrami	$FullPath = "$BasePath/$RelPath";
12375ce41a5SAli Bahrami	@_ = split /\//, $RelPath;
12475ce41a5SAli Bahrami	$File = $_[$#_];
12575ce41a5SAli Bahrami
12675ce41a5SAli Bahrami	$Ttl = 0;
12775ce41a5SAli Bahrami
128*5253169eSAli Bahrami	# If this object is not a symlink, does not follow the runtime
129*5253169eSAli Bahrami	# versioned name convention, and it does not reside underneath
130*5253169eSAli Bahrami	# a directory identified as containing plugin objects intended
131*5253169eSAli Bahrami	# for use with dlopen() only, issue a warning.
132*5253169eSAli Bahrami	#
133*5253169eSAli Bahrami	# Note that it can only be a symlink if the user specified
134*5253169eSAli Bahrami	# a single file on the command line, because the use of
135*5253169eSAli Bahrami	# 'find_elf -a' is required for a symlink to be seen.
13675ce41a5SAli Bahrami	$NotPlugin = !defined($EXRE_plugin) || ($RelPath !~ $EXRE_plugin);
137*5253169eSAli Bahrami	if (($File !~ /\.so\./) && $NotPlugin && (! -l $FullPath)) {
13875ce41a5SAli Bahrami		onbld_elfmod::OutMsg($ErrFH, \$Ttl, $RelPath,
13975ce41a5SAli Bahrami		    "does not have a versioned name");
14075ce41a5SAli Bahrami	}
14175ce41a5SAli Bahrami
14275ce41a5SAli Bahrami	# If there are no versions in the file we're done.
14375ce41a5SAli Bahrami	if ($Verdef eq 'NOVERDEF') {
14475ce41a5SAli Bahrami	        # Report the lack of versioning, unless the object is
14575ce41a5SAli Bahrami	    	# a known plugin, or is explicitly exempt.
14675ce41a5SAli Bahrami		if ($NotPlugin &&
14775ce41a5SAli Bahrami		    (!defined($EXRE_noverdef) || ($RelPath !~ $EXRE_noverdef))) {
14875ce41a5SAli Bahrami			onbld_elfmod::OutMsg($ErrFH, \$Ttl, $RelPath,
14975ce41a5SAli Bahrami			    "no versions found");
15075ce41a5SAli Bahrami		}
15175ce41a5SAli Bahrami		return;
15275ce41a5SAli Bahrami	}
15375ce41a5SAli Bahrami
15475ce41a5SAli Bahrami	# Get a hash of the top versions in the inheritance chains.
15575ce41a5SAli Bahrami	%TopVer = ();
15675ce41a5SAli Bahrami	foreach my $Line (split(/\n/, `pvs -don $FullPath 2>&1`)) {
15775ce41a5SAli Bahrami		$Line =~ s/^.*-\s*(.*);/$1/;
15875ce41a5SAli Bahrami		$TopVer{$Line} = 1;
15975ce41a5SAli Bahrami	}
16075ce41a5SAli Bahrami
161*5253169eSAli Bahrami	# Determine the name used for the base version. It should match the
162*5253169eSAli Bahrami	# soname if the object has one, and the object basename otherwise.
163*5253169eSAli Bahrami	#
164*5253169eSAli Bahrami	# Note that elfedit writes an error to stderr if the object lacks an
165*5253169eSAli Bahrami	# soname, so we direct stderr to /dev/null.
166*5253169eSAli Bahrami	my $soname =
167*5253169eSAli Bahrami	    `elfedit -r -osimple -e 'dyn:value dt_soname' $FullPath 2>/dev/null`;
168*5253169eSAli Bahrami	if ($soname eq '') {
169*5253169eSAli Bahrami		$soname = $File;
170*5253169eSAli Bahrami	} else {
171*5253169eSAli Bahrami		chomp $soname;
172*5253169eSAli Bahrami	}
173*5253169eSAli Bahrami
17475ce41a5SAli Bahrami	# First determine what versions exist that offer interfaces.  pvs -dos
17575ce41a5SAli Bahrami	# will list these.  Note that other versions may exist, ones that
17675ce41a5SAli Bahrami	# don't offer interfaces ... we'll get to those next.
17775ce41a5SAli Bahrami	%Vers = ();
17875ce41a5SAli Bahrami	$VersCnt = 0;
179*5253169eSAli Bahrami	my %TopNumberedVers = ();
18075ce41a5SAli Bahrami	foreach my $Line (split(/\n/, `pvs -dos $FullPath 2>&1`)) {
18175ce41a5SAli Bahrami		my($Ver) = $Line;
18275ce41a5SAli Bahrami
18375ce41a5SAli Bahrami		$Ver =~ s/^.*-\t(.*): .*/$1/; 		# isolate version
18475ce41a5SAli Bahrami
18575ce41a5SAli Bahrami		# See if we've already caught this version name. We only look
18675ce41a5SAli Bahrami		# at each version once.
18775ce41a5SAli Bahrami		next if ($Vers{$Ver}) ;
18875ce41a5SAli Bahrami
18975ce41a5SAli Bahrami		# Note that the non-empty version has been seen
19075ce41a5SAli Bahrami		$Vers{$Ver} = 1;
19175ce41a5SAli Bahrami		$VersCnt++;
19275ce41a5SAli Bahrami
193*5253169eSAli Bahrami		# Identify the version type
194*5253169eSAli Bahrami		my @Cat = onbld_elfmod_vertype::Category($Ver, $soname);
195*5253169eSAli Bahrami
196*5253169eSAli Bahrami
197*5253169eSAli Bahrami		# Numbered public versions have the form
198*5253169eSAli Bahrami		#
199*5253169eSAli Bahrami		#	<prefix>major.minor[.micro]
200*5253169eSAli Bahrami		#
201*5253169eSAli Bahrami		# with 2 or three numeric values. We expect these versions to
202*5253169eSAli Bahrami		# use inheritance, so there should only be one top version for
203*5253169eSAli Bahrami		# each major number. It is possible, though rare, to have more
204*5253169eSAli Bahrami		# than one top version if the major numbers differ.
20575ce41a5SAli Bahrami		#
206*5253169eSAli Bahrami		# %TopNumberedVers uses the prefix and major number as the
207*5253169eSAli Bahrami		# key. Each key holds a reference to an array which contains
208*5253169eSAli Bahrami		# the top versions with the same prefix and major number.
209*5253169eSAli Bahrami		if ($Cat[0] eq 'NUMBERED') {
210*5253169eSAli Bahrami			push @{$TopNumberedVers{"$Cat[2]$Cat[3]"}}, $Ver
211*5253169eSAli Bahrami			    if $TopVer{$Ver};
21275ce41a5SAli Bahrami			next;
21375ce41a5SAli Bahrami		}
21475ce41a5SAli Bahrami
215*5253169eSAli Bahrami		# If it is a non-standard version, and there's not an
216*5253169eSAli Bahrami		# exception in place for it, report an error.
217*5253169eSAli Bahrami		if ($Cat[0] eq 'UNKNOWN') {
218*5253169eSAli Bahrami			if (!defined($EXRE_nonstd_vername) ||
219*5253169eSAli Bahrami			    ($RelPath !~ $EXRE_nonstd_vername)) {
220*5253169eSAli Bahrami				onbld_elfmod::OutMsg($ErrFH, \$Ttl, $RelPath,
221*5253169eSAli Bahrami				   "non-standard version name: $Ver");
222*5253169eSAli Bahrami			}
223*5253169eSAli Bahrami			next;
22475ce41a5SAli Bahrami		}
225*5253169eSAli Bahrami
226*5253169eSAli Bahrami		# If we are here, it is one of PLAIN, PRIVATE, or SONAME,
227*5253169eSAli Bahrami		# all of which we quietly accept.
22875ce41a5SAli Bahrami		next;
22975ce41a5SAli Bahrami	}
23075ce41a5SAli Bahrami
23175ce41a5SAli Bahrami	# If this file has been scoped, but not versioned (i.e., a mapfile was
23275ce41a5SAli Bahrami	# used to demote symbols but no version name was applied to the
23375ce41a5SAli Bahrami	# global interfaces) then it's another non-standard case.
23475ce41a5SAli Bahrami	if ($VersCnt eq 0) {
23575ce41a5SAli Bahrami		onbld_elfmod::OutMsg($ErrFH, \$Ttl, $RelPath,
23675ce41a5SAli Bahrami		    "scoped object contains no versions");
23775ce41a5SAli Bahrami		return;
23875ce41a5SAli Bahrami	}
23975ce41a5SAli Bahrami
240*5253169eSAli Bahrami	# If this file has multiple inheritance chains starting with the
241*5253169eSAli Bahrami	# same prefix and major number, that's wrong.
242*5253169eSAli Bahrami	foreach my $Ver (sort keys %TopNumberedVers) {
243*5253169eSAli Bahrami		if (scalar(@{$TopNumberedVers{$Ver}}) > 1) {
24475ce41a5SAli Bahrami			onbld_elfmod::OutMsg($ErrFH, \$Ttl, $RelPath,
24575ce41a5SAli Bahrami			    "multiple $Ver inheritance chains (missing " .
24675ce41a5SAli Bahrami			    "inheritance?): " .
247*5253169eSAli Bahrami			    join(', ', @{$TopNumberedVers{$Ver}}));
24875ce41a5SAli Bahrami		}
24975ce41a5SAli Bahrami	}
25075ce41a5SAli Bahrami
25175ce41a5SAli Bahrami
25275ce41a5SAli Bahrami	# Produce an interface description for the object.
25375ce41a5SAli Bahrami	# For each version, generate a VERSION declaration of the form:
25475ce41a5SAli Bahrami	#
25575ce41a5SAli Bahrami	#	[TOP_]VERSION  version  direct-count  total-count
25675ce41a5SAli Bahrami	#		symname1
25775ce41a5SAli Bahrami	#		symname2
25875ce41a5SAli Bahrami	#		...
25975ce41a5SAli Bahrami	#
260*5253169eSAli Bahrami	# We suppress base and private versions from this output.
261*5253169eSAli Bahrami	# Everything else goes in, whether it's a version we recognize
262*5253169eSAli Bahrami	# or not. If an object only has base or private versions, we do
263*5253169eSAli Bahrami	# not produce an interface description for that object.
26475ce41a5SAli Bahrami	#
26575ce41a5SAli Bahrami	if ($opt{i}) {
26675ce41a5SAli Bahrami		my $header_done = 0;
26775ce41a5SAli Bahrami
26875ce41a5SAli Bahrami		# The use of 'pvs -v' is to identify the BASE version
26975ce41a5SAli Bahrami		foreach my $Line (split(/\n/, `pvs -dv $FullPath 2>&1`)) {
27075ce41a5SAli Bahrami			# Skip base version
27175ce41a5SAli Bahrami			next if ($Line =~ /\[BASE\]/);
27275ce41a5SAli Bahrami
27375ce41a5SAli Bahrami			# Directly inherited versions follow the version name
27475ce41a5SAli Bahrami			# in a comma separated list within {} brackets. Capture
27575ce41a5SAli Bahrami			# that information, for use with our VERSION line.
27675ce41a5SAli Bahrami			my $InheritVers = ($Line =~ /(\{.*\});$/) ? "\t$1" : '';
27775ce41a5SAli Bahrami
278*5253169eSAli Bahrami			# Extract the version name
27975ce41a5SAli Bahrami			$Line =~ s/^\s*([^;: ]*).*/$1/;
28075ce41a5SAli Bahrami
281*5253169eSAli Bahrami			# Skip version if it is in the SONAME or PRIVATE
282*5253169eSAli Bahrami			# categories.
283*5253169eSAli Bahrami			#
284*5253169eSAli Bahrami			# The above test for BASE should have caught the
285*5253169eSAli Bahrami			# SONAME already, but older versions of pvs have a
286*5253169eSAli Bahrami			# bug that prevents them from printing [BASE] on
287*5253169eSAli Bahrami			# the base version. In order to solidify things even
288*5253169eSAli Bahrami			# more, we also exclude versions that end with
289*5253169eSAli Bahrami			# a '.so.*' suffix.
290*5253169eSAli Bahrami			my @Cat = onbld_elfmod_vertype::Category($Line, $soname);
291*5253169eSAli Bahrami			if (($Cat[0] eq 'SONAME') ||
292*5253169eSAli Bahrami			    ($Cat[0] eq 'PRIVATE') ||
293*5253169eSAli Bahrami			    ($Line =~ /\.so\.\d+$/)) {
294*5253169eSAli Bahrami			    next;
295*5253169eSAli Bahrami			}
29675ce41a5SAli Bahrami
29775ce41a5SAli Bahrami			# We want to output the symbols in sorted order, so
29875ce41a5SAli Bahrami			# we gather them first, and then sort the results.
29975ce41a5SAli Bahrami			# An array would suffice, but we have observed objects
30075ce41a5SAli Bahrami			# with odd inheritance chains in which the same
30175ce41a5SAli Bahrami			# sub-version gets inherited more than once, leading
30275ce41a5SAli Bahrami			# to the same symbol showing up more than once. Using
30375ce41a5SAli Bahrami			# a hash instead of an array thins out the duplicates.
30475ce41a5SAli Bahrami			my %Syms = ();
30575ce41a5SAli Bahrami			my $symitem = $opt{I} ? 'NEW' : 'SYMBOL';
30675ce41a5SAli Bahrami			my $version_cnt = 0;
30775ce41a5SAli Bahrami			foreach my $Sym
30875ce41a5SAli Bahrami			    (split(/\n/, `pvs -ds -N $Line $FullPath 2>&1`)) {
30975ce41a5SAli Bahrami				if ($Sym =~ /:$/) {
31075ce41a5SAli Bahrami					$version_cnt++;
31175ce41a5SAli Bahrami					# If this is an inherited sub-version,
31275ce41a5SAli Bahrami					# we don't need to continue unless
31375ce41a5SAli Bahrami					# generating output in -I mode.
31475ce41a5SAli Bahrami					if ($version_cnt >= 2) {
31575ce41a5SAli Bahrami						last if !$opt{I};
31675ce41a5SAli Bahrami						$symitem = 'INHERIT';
31775ce41a5SAli Bahrami					}
31875ce41a5SAli Bahrami					next;
31975ce41a5SAli Bahrami				}
32075ce41a5SAli Bahrami				$Sym =~ s/[ \t]*(.*);$/$1/;
32175ce41a5SAli Bahrami				$Sym =~ s/ .*$//;	# remove any data size
32275ce41a5SAli Bahrami				$Syms{$Sym} = $symitem;
32375ce41a5SAli Bahrami			}
32475ce41a5SAli Bahrami
32575ce41a5SAli Bahrami			if (!$header_done) {
32675ce41a5SAli Bahrami				print INTFILE "\n" if !$opt{h} && ($ObjCnt != 0);
32775ce41a5SAli Bahrami				$ObjCnt++;
32875ce41a5SAli Bahrami				print INTFILE "OBJECT\t$RelPath\n";
32975ce41a5SAli Bahrami				print INTFILE "CLASS\tELFCLASS$Class\n";
33075ce41a5SAli Bahrami				print INTFILE "TYPE\tET_$Type\n";
33175ce41a5SAli Bahrami				print INTFILE $Alias if ($Alias ne '');
33275ce41a5SAli Bahrami				$header_done = 1;
33375ce41a5SAli Bahrami			}
33475ce41a5SAli Bahrami
33575ce41a5SAli Bahrami			my $item = $TopVer{$Line} ? 'TOP_VERSION' : 'VERSION';
33675ce41a5SAli Bahrami			print INTFILE "$item\t$Line$InheritVers\n";
33775ce41a5SAli Bahrami
33875ce41a5SAli Bahrami			# Output symbols in sorted order
33975ce41a5SAli Bahrami			foreach my $Sym (sort keys %Syms) {
34075ce41a5SAli Bahrami				print INTFILE "\t$Syms{$Sym}\t$Sym\n";
34175ce41a5SAli Bahrami			}
34275ce41a5SAli Bahrami		}
34375ce41a5SAli Bahrami	}
34475ce41a5SAli Bahrami}
34575ce41a5SAli Bahrami
34675ce41a5SAli Bahrami## ProcFindElf(file)
34775ce41a5SAli Bahrami#
34875ce41a5SAli Bahrami# Open the specified file, which must be produced by "find_elf -r",
34975ce41a5SAli Bahrami# and process the files it describes.
35075ce41a5SAli Bahramisub ProcFindElf {
35175ce41a5SAli Bahrami	my $file = $_[0];
35275ce41a5SAli Bahrami	my $line;
35375ce41a5SAli Bahrami	my $LineNum = 0;
35475ce41a5SAli Bahrami	my $prefix;
35575ce41a5SAli Bahrami	my @ObjList = ();
35675ce41a5SAli Bahrami	my %ObjToAlias = ();
35775ce41a5SAli Bahrami
35875ce41a5SAli Bahrami	open(FIND_ELF, $file) || die "$Prog: Unable to open $file";
35975ce41a5SAli Bahrami
36075ce41a5SAli Bahrami	# This script requires relative paths, created by the 'find_elf -r'
36175ce41a5SAli Bahrami	# option. When this is done, the first non-comment line will always
36275ce41a5SAli Bahrami	# be PREFIX. Obtain that line, or issue a fatal error.
36375ce41a5SAli Bahrami	while ($line = onbld_elfmod::GetLine(\*FIND_ELF, \$LineNum)) {
36475ce41a5SAli Bahrami		if ($line =~ /^PREFIX\s+(.*)$/) {
36575ce41a5SAli Bahrami			$prefix = $1;
36675ce41a5SAli Bahrami			last;
36775ce41a5SAli Bahrami		}
36875ce41a5SAli Bahrami
36975ce41a5SAli Bahrami		die "$file: PREFIX expected on line $LineNum\n";
37075ce41a5SAli Bahrami	}
37175ce41a5SAli Bahrami
37275ce41a5SAli Bahrami
37375ce41a5SAli Bahrami	# Process the remainder of the file.
37475ce41a5SAli Bahrami	while ($line = onbld_elfmod::GetLine(\*FIND_ELF, \$LineNum)) {
37575ce41a5SAli Bahrami		if ($line =~ /^OBJECT\s/i) {
37675ce41a5SAli Bahrami			push @ObjList, $line;
37775ce41a5SAli Bahrami			next;
37875ce41a5SAli Bahrami		}
37975ce41a5SAli Bahrami
38075ce41a5SAli Bahrami		if ($line =~ /^ALIAS\s/i) {
38175ce41a5SAli Bahrami			my ($item, $obj, $alias) = split(/\s+/, $line, 3);
38275ce41a5SAli Bahrami			my $str = "ALIAS\t$alias\n";
38375ce41a5SAli Bahrami
38475ce41a5SAli Bahrami			if (defined($ObjToAlias{$obj})) {
38575ce41a5SAli Bahrami				$ObjToAlias{$obj} .= $str;
38675ce41a5SAli Bahrami			} else {
38775ce41a5SAli Bahrami				$ObjToAlias{$obj} = $str;
38875ce41a5SAli Bahrami			}
38975ce41a5SAli Bahrami		}
39075ce41a5SAli Bahrami	}
39175ce41a5SAli Bahrami
39275ce41a5SAli Bahrami	foreach $line (@ObjList) {
39375ce41a5SAli Bahrami		my ($item, $class, $type, $verdef, $obj) =
39475ce41a5SAli Bahrami		    split(/\s+/, $line, 5);
39575ce41a5SAli Bahrami
39675ce41a5SAli Bahrami		my $alias = defined($ObjToAlias{$obj}) ? $ObjToAlias{$obj} : '';
39775ce41a5SAli Bahrami
39875ce41a5SAli Bahrami		# We are only interested in sharable objects. We may see
39975ce41a5SAli Bahrami		# other file types if processing a list of objects
40075ce41a5SAli Bahrami		# supplied via the -f option.
40175ce41a5SAli Bahrami		next if ($type ne 'DYN');
40275ce41a5SAli Bahrami
40375ce41a5SAli Bahrami		ProcFile($prefix, $obj, $class, $type, $verdef, $alias);
40475ce41a5SAli Bahrami	}
40575ce41a5SAli Bahrami
40675ce41a5SAli Bahrami	close FIND_ELF;
40775ce41a5SAli Bahrami}
40875ce41a5SAli Bahrami
40975ce41a5SAli Bahrami
41075ce41a5SAli Bahrami# -----------------------------------------------------------------------------
41175ce41a5SAli Bahrami
41275ce41a5SAli Bahrami# Establish a program name for any error diagnostics.
41375ce41a5SAli Bahramichomp($Prog = `basename $0`);
41475ce41a5SAli Bahrami
41575ce41a5SAli Bahrami# Check that we have arguments.
41675ce41a5SAli Bahrami@SaveArgv = @ARGV;
417*5253169eSAli Bahramiif ((getopts('c:E:e:f:hIi:ow:', \%opt) == 0) || (!$opt{f} && ($#ARGV == -1))) {
418*5253169eSAli Bahrami	print "usage: $Prog [-hIo] [-c vtype_mod] [-E errfile] [-e exfile]\n";
419*5253169eSAli Bahrami	print "\t\t[-f listfile] [-i intffile] [-w outdir] file | dir, ...\n";
42075ce41a5SAli Bahrami	print "\n";
421*5253169eSAli Bahrami	print "\t[-c vtype_mod]\tsupply alternative version category module\n";
42275ce41a5SAli Bahrami	print "\t[-E errfile]\tdirect error output to file\n";
42375ce41a5SAli Bahrami	print "\t[-e exfile]\texceptions file\n";
42475ce41a5SAli Bahrami	print "\t[-f listfile]\tuse file list produced by find_elf -r\n";
425*5253169eSAli Bahrami	print "\t[-h]\t\tdo not produce a CDDL/Copyright header comment\n";
426*5253169eSAli Bahrami	print "\t[-I]\t\tExpand inheritance in -i output (debugging)\n";
42775ce41a5SAli Bahrami	print "\t[-i intffile]\tcreate interface description output file\n";
42875ce41a5SAli Bahrami	print "\t[-o]\t\tproduce one-liner output (prefixed with pathname)\n";
42975ce41a5SAli Bahrami	print "\t[-w outdir]\tinterpret all files relative to given directory\n";
43075ce41a5SAli Bahrami	exit 1;
43175ce41a5SAli Bahrami}
43275ce41a5SAli Bahrami
433*5253169eSAli Bahrami# We depend on the onbld_elfmod and onbld_elfmod_vertype perl modules.
434*5253169eSAli Bahrami# Both modules are maintained in the same directory as this script,
435*5253169eSAli Bahrami# and are installed in ../lib/perl. Use the local one if present,
436*5253169eSAli Bahrami# and the installed one otherwise.
437*5253169eSAli Bahrami#
438*5253169eSAli Bahrami# The caller is allowed to supply an alternative implementation for
439*5253169eSAli Bahrami# onbld_elfmod_vertype via the -c option. In this case, the alternative
440*5253169eSAli Bahrami# implementation is expected to provide the same interface as the standard
441*5253169eSAli Bahrami# copy, and is loaded instead.
442*5253169eSAli Bahrami#
443*5253169eSAli Bahramimy $moddir = my $vermoddir = dirname($0);
444*5253169eSAli Bahrami$moddir = "$moddir/../lib/perl" if ! -f "$moddir/onbld_elfmod.pm";
445*5253169eSAli Bahramirequire "$moddir/onbld_elfmod.pm";
446*5253169eSAli Bahramiif ($opt{c}) {
447*5253169eSAli Bahrami	require "$opt{c}";
448*5253169eSAli Bahrami} else {
449*5253169eSAli Bahrami	$vermoddir = "$vermoddir/../lib/perl"
450*5253169eSAli Bahrami	    if ! -f "$vermoddir/onbld_elfmod_vertype.pm";
451*5253169eSAli Bahrami	require "$vermoddir/onbld_elfmod_vertype.pm";
452*5253169eSAli Bahrami}
453*5253169eSAli Bahrami
45475ce41a5SAli Bahrami# If -w, change working directory to given location
45575ce41a5SAli Bahrami!$opt{w} || chdir($opt{w}) || die "$Prog: can't cd to $opt{w}";
45675ce41a5SAli Bahrami
45775ce41a5SAli Bahrami
45875ce41a5SAli Bahrami# Error messages go to stdout unless -E is specified. $ErrFH is a
45975ce41a5SAli Bahrami# file handle reference that points at the file handle where error messages
46075ce41a5SAli Bahrami# are sent.
46175ce41a5SAli Bahramiif ($opt{E}) {
46275ce41a5SAli Bahrami	open(ERROR, ">$opt{E}") || die "$Prog: open failed: $opt{E}";
46375ce41a5SAli Bahrami	$ErrFH = \*ERROR;
46475ce41a5SAli Bahrami} else {
46575ce41a5SAli Bahrami	$ErrFH = \*STDOUT;
46675ce41a5SAli Bahrami}
46775ce41a5SAli Bahrami
46875ce41a5SAli Bahrami# Locate and process the exceptions file
46975ce41a5SAli Bahramionbld_elfmod::LoadExceptionsToEXRE('interface_check');
47075ce41a5SAli Bahrami
47175ce41a5SAli Bahrami# If creating an interface description output file, prepare it for use
47275ce41a5SAli Bahramiif ($opt{i}) {
47375ce41a5SAli Bahrami	open (INTFILE, ">$opt{i}") ||
47475ce41a5SAli Bahrami	    die "$Prog: Unable to create file: $opt{i}";
47575ce41a5SAli Bahrami
47675ce41a5SAli Bahrami	# Generate the output header
47775ce41a5SAli Bahrami	onbld_elfmod::Header(\*INTFILE, $0, \@SaveArgv) if !$opt{h};;
47875ce41a5SAli Bahrami}
47975ce41a5SAli Bahrami
48075ce41a5SAli Bahrami# Number of OBJECTs output to INTFILE
48175ce41a5SAli Bahrami$ObjCnt = 0;
48275ce41a5SAli Bahrami
48375ce41a5SAli Bahrami# If we were passed a file previously produced by 'find_elf -r', use it.
48475ce41a5SAli BahramiProcFindElf($opt{f}) if $opt{f};
48575ce41a5SAli Bahrami
486*5253169eSAli Bahrami# Process each argument: Run find_elf to find the files given by
487*5253169eSAli Bahrami# $Arg. If the argument is a regular file (not a directory) then disable
488*5253169eSAli Bahrami# find_elf's alias checking so that the file is processed whether or not
489*5253169eSAli Bahrami# it is a symlink.
49075ce41a5SAli Bahramiforeach my $Arg (@ARGV) {
491*5253169eSAli Bahrami	my $flag_a = (-d $Arg) ? '' : '-a';
492*5253169eSAli Bahrami	ProcFindElf("find_elf -frs $flag_a $Arg|");
49375ce41a5SAli Bahrami}
49475ce41a5SAli Bahrami
49575ce41a5SAli Bahrami# Close any working output files.
49675ce41a5SAli Bahramiclose INTFILE if $opt{i};
49775ce41a5SAli Bahramiclose ERROR if $opt{E};
49875ce41a5SAli Bahrami
49975ce41a5SAli Bahramiexit 0;
500