xref: /illumos-gate/usr/src/cmd/abi/appcert/scripts/symcheck.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# ident	"%Z%%M%	%I%	%E% SMI"
25*7c478bd9Sstevel@tonic-gate#
26*7c478bd9Sstevel@tonic-gate# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
27*7c478bd9Sstevel@tonic-gate# Use is subject to license terms.
28*7c478bd9Sstevel@tonic-gate#
29*7c478bd9Sstevel@tonic-gate
30*7c478bd9Sstevel@tonic-gate#
31*7c478bd9Sstevel@tonic-gate# This utility program loads the unstable behavior databases, then reads
32*7c478bd9Sstevel@tonic-gate# the symprof output for each binary, and record any detected unstable
33*7c478bd9Sstevel@tonic-gate# behavior in the binary's output directory.
34*7c478bd9Sstevel@tonic-gate#
35*7c478bd9Sstevel@tonic-gate
36*7c478bd9Sstevel@tonic-gaterequire 5.005;
37*7c478bd9Sstevel@tonic-gateuse strict;
38*7c478bd9Sstevel@tonic-gateuse locale;
39*7c478bd9Sstevel@tonic-gateuse POSIX qw(locale_h);
40*7c478bd9Sstevel@tonic-gateuse Sun::Solaris::Utils qw(textdomain gettext);
41*7c478bd9Sstevel@tonic-gateuse File::Basename;
42*7c478bd9Sstevel@tonic-gateuse File::Path;
43*7c478bd9Sstevel@tonic-gate
44*7c478bd9Sstevel@tonic-gateuse lib qw(/usr/lib/abi/appcert);
45*7c478bd9Sstevel@tonic-gateuse AppcertUtil;
46*7c478bd9Sstevel@tonic-gate
47*7c478bd9Sstevel@tonic-gatesetlocale(LC_ALL, "");
48*7c478bd9Sstevel@tonic-gatetextdomain(TEXT_DOMAIN);
49*7c478bd9Sstevel@tonic-gate
50*7c478bd9Sstevel@tonic-gateuse vars qw(
51*7c478bd9Sstevel@tonic-gate	$LIBC
52*7c478bd9Sstevel@tonic-gate	$tmp_check_dir
53*7c478bd9Sstevel@tonic-gate	$binaries_checked_count
54*7c478bd9Sstevel@tonic-gate	$misc_check_databases_loaded_ok
55*7c478bd9Sstevel@tonic-gate	%load_model_default
56*7c478bd9Sstevel@tonic-gate	%load_error
57*7c478bd9Sstevel@tonic-gate	%model_loaded
58*7c478bd9Sstevel@tonic-gate	%model
59*7c478bd9Sstevel@tonic-gate	%is_system_library_cache
60*7c478bd9Sstevel@tonic-gate);
61*7c478bd9Sstevel@tonic-gate
62*7c478bd9Sstevel@tonic-gateset_clean_up_exit_routine(\&clean_up_exit);
63*7c478bd9Sstevel@tonic-gate
64*7c478bd9Sstevel@tonic-gateinitialize_variables();
65*7c478bd9Sstevel@tonic-gate
66*7c478bd9Sstevel@tonic-gateimport_vars_from_environment();
67*7c478bd9Sstevel@tonic-gate
68*7c478bd9Sstevel@tonic-gatesignals('on', \&interrupted);
69*7c478bd9Sstevel@tonic-gate
70*7c478bd9Sstevel@tonic-gateset_working_dir();
71*7c478bd9Sstevel@tonic-gate
72*7c478bd9Sstevel@tonic-gateload_model_index();
73*7c478bd9Sstevel@tonic-gate
74*7c478bd9Sstevel@tonic-gatecheck_objects();
75*7c478bd9Sstevel@tonic-gate
76*7c478bd9Sstevel@tonic-gateclean_up();
77*7c478bd9Sstevel@tonic-gate
78*7c478bd9Sstevel@tonic-gateexit 0;
79*7c478bd9Sstevel@tonic-gate
80*7c478bd9Sstevel@tonic-gate#
81*7c478bd9Sstevel@tonic-gate# Set up any variables.
82*7c478bd9Sstevel@tonic-gate#
83*7c478bd9Sstevel@tonic-gatesub initialize_variables
84*7c478bd9Sstevel@tonic-gate{
85*7c478bd9Sstevel@tonic-gate	# Here is what we call libc:
86*7c478bd9Sstevel@tonic-gate	$LIBC = '/usr/lib/libc.so.1';
87*7c478bd9Sstevel@tonic-gate}
88*7c478bd9Sstevel@tonic-gate
89*7c478bd9Sstevel@tonic-gate#
90*7c478bd9Sstevel@tonic-gate# working_dir has been imported by import_vars_from_environment()
91*7c478bd9Sstevel@tonic-gate# A sanity check is performed here to make sure it exists.
92*7c478bd9Sstevel@tonic-gate#
93*7c478bd9Sstevel@tonic-gatesub set_working_dir
94*7c478bd9Sstevel@tonic-gate{
95*7c478bd9Sstevel@tonic-gate	if (! defined($working_dir) || ! -d $working_dir) {
96*7c478bd9Sstevel@tonic-gate		exiter("$command_name: " . sprintf(gettext(
97*7c478bd9Sstevel@tonic-gate		    "cannot locate working directory: %s\n"), $working_dir));
98*7c478bd9Sstevel@tonic-gate	}
99*7c478bd9Sstevel@tonic-gate}
100*7c478bd9Sstevel@tonic-gate
101*7c478bd9Sstevel@tonic-gate#
102*7c478bd9Sstevel@tonic-gate# Called when interrupted by a signal.
103*7c478bd9Sstevel@tonic-gate#
104*7c478bd9Sstevel@tonic-gatesub interrupted
105*7c478bd9Sstevel@tonic-gate{
106*7c478bd9Sstevel@tonic-gate	$SIG{$_[0]} = 'DEFAULT';
107*7c478bd9Sstevel@tonic-gate	signals('off');
108*7c478bd9Sstevel@tonic-gate	clean_up_exit(1);
109*7c478bd9Sstevel@tonic-gate}
110*7c478bd9Sstevel@tonic-gate
111*7c478bd9Sstevel@tonic-gate#
112*7c478bd9Sstevel@tonic-gate# Does the cleanup then exit with return code $rc.  Note: The utility
113*7c478bd9Sstevel@tonic-gate# routine exiter() will call this routine.
114*7c478bd9Sstevel@tonic-gate#
115*7c478bd9Sstevel@tonic-gatesub clean_up_exit
116*7c478bd9Sstevel@tonic-gate{
117*7c478bd9Sstevel@tonic-gate	my ($rc) = @_;
118*7c478bd9Sstevel@tonic-gate	$rc = 0 unless ($rc);
119*7c478bd9Sstevel@tonic-gate
120*7c478bd9Sstevel@tonic-gate	clean_up();
121*7c478bd9Sstevel@tonic-gate	exit $rc;
122*7c478bd9Sstevel@tonic-gate}
123*7c478bd9Sstevel@tonic-gate
124*7c478bd9Sstevel@tonic-gate#
125*7c478bd9Sstevel@tonic-gate# General cleanup activities are placed here.  There may not be an
126*7c478bd9Sstevel@tonic-gate# immediate exit after this cleanup.
127*7c478bd9Sstevel@tonic-gate#
128*7c478bd9Sstevel@tonic-gatesub clean_up
129*7c478bd9Sstevel@tonic-gate{
130*7c478bd9Sstevel@tonic-gate	if (defined($tmp_check_dir) && -d $tmp_check_dir) {
131*7c478bd9Sstevel@tonic-gate		rmtree($tmp_check_dir);
132*7c478bd9Sstevel@tonic-gate	}
133*7c478bd9Sstevel@tonic-gate}
134*7c478bd9Sstevel@tonic-gate
135*7c478bd9Sstevel@tonic-gate#
136*7c478bd9Sstevel@tonic-gate# Top level routine to initialize databases and then loop over the
137*7c478bd9Sstevel@tonic-gate# objects and call the checking routines on each one.
138*7c478bd9Sstevel@tonic-gate#
139*7c478bd9Sstevel@tonic-gatesub check_objects
140*7c478bd9Sstevel@tonic-gate{
141*7c478bd9Sstevel@tonic-gate	# Make a tmp dir for the checking work.
142*7c478bd9Sstevel@tonic-gate	$tmp_check_dir = create_tmp_dir($tmp_dir);
143*7c478bd9Sstevel@tonic-gate
144*7c478bd9Sstevel@tonic-gate	if (! -d $tmp_check_dir) {
145*7c478bd9Sstevel@tonic-gate		exiter(nocreatedir($tmp_check_dir, $!));
146*7c478bd9Sstevel@tonic-gate	}
147*7c478bd9Sstevel@tonic-gate
148*7c478bd9Sstevel@tonic-gate	emsg("\n" . gettext(
149*7c478bd9Sstevel@tonic-gate	    "checking binary objects for unstable practices") . " ...\n\n");
150*7c478bd9Sstevel@tonic-gate
151*7c478bd9Sstevel@tonic-gate	my ($dir, $path_to_object);
152*7c478bd9Sstevel@tonic-gate
153*7c478bd9Sstevel@tonic-gate	#
154*7c478bd9Sstevel@tonic-gate	# Loop over each object item in the working_dir.
155*7c478bd9Sstevel@tonic-gate	#  - $dir will be each one of these object directories.
156*7c478bd9Sstevel@tonic-gate	#  - $path_to_object will be the corresponding actual path
157*7c478bd9Sstevel@tonic-gate	#    to the the binary to be checked.
158*7c478bd9Sstevel@tonic-gate	# Output will be placed down in $dir, e.g. "$dir/check.foo"
159*7c478bd9Sstevel@tonic-gate	#
160*7c478bd9Sstevel@tonic-gate
161*7c478bd9Sstevel@tonic-gate	$binaries_checked_count = 0;
162*7c478bd9Sstevel@tonic-gate
163*7c478bd9Sstevel@tonic-gate	#
164*7c478bd9Sstevel@tonic-gate	# We need to load the Misc Databases to get any modifications to
165*7c478bd9Sstevel@tonic-gate	# the symbol database. E.g. gethostname should be public.
166*7c478bd9Sstevel@tonic-gate	#
167*7c478bd9Sstevel@tonic-gate	$misc_check_databases_loaded_ok = load_misc_check_databases();
168*7c478bd9Sstevel@tonic-gate
169*7c478bd9Sstevel@tonic-gate	while (defined($dir = next_dir_name())) {
170*7c478bd9Sstevel@tonic-gate
171*7c478bd9Sstevel@tonic-gate		# Map object output dir to actual path of the object:
172*7c478bd9Sstevel@tonic-gate		$path_to_object = dir_name_to_path($dir);
173*7c478bd9Sstevel@tonic-gate
174*7c478bd9Sstevel@tonic-gate		if (! -f $path_to_object) {
175*7c478bd9Sstevel@tonic-gate			exiter(nopathexist($path_to_object, $!));
176*7c478bd9Sstevel@tonic-gate		}
177*7c478bd9Sstevel@tonic-gate
178*7c478bd9Sstevel@tonic-gate		# Check it:
179*7c478bd9Sstevel@tonic-gate		emsg(gettext("checking: %s\n"), $path_to_object);
180*7c478bd9Sstevel@tonic-gate
181*7c478bd9Sstevel@tonic-gate		static_check_object($path_to_object, $dir);
182*7c478bd9Sstevel@tonic-gate		dynamic_check_object($path_to_object, $dir);
183*7c478bd9Sstevel@tonic-gate	}
184*7c478bd9Sstevel@tonic-gate
185*7c478bd9Sstevel@tonic-gate	if ($binaries_checked_count == 0) {
186*7c478bd9Sstevel@tonic-gate		exiter("$command_name: " . gettext(
187*7c478bd9Sstevel@tonic-gate		    "no binary objects where checked."));
188*7c478bd9Sstevel@tonic-gate	}
189*7c478bd9Sstevel@tonic-gate
190*7c478bd9Sstevel@tonic-gate	# Do additional heuristic checks of unstable behavior:
191*7c478bd9Sstevel@tonic-gate	perform_misc_checks();
192*7c478bd9Sstevel@tonic-gate
193*7c478bd9Sstevel@tonic-gate	clean_up();	# Remove any tmp dirs and files.
194*7c478bd9Sstevel@tonic-gate}
195*7c478bd9Sstevel@tonic-gate
196*7c478bd9Sstevel@tonic-gate#
197*7c478bd9Sstevel@tonic-gate# Reads in the static profile (i.e. the symbols exported by bin in
198*7c478bd9Sstevel@tonic-gate# .text section) and calls the static archive checking routine.
199*7c478bd9Sstevel@tonic-gate#
200*7c478bd9Sstevel@tonic-gatesub static_check_object
201*7c478bd9Sstevel@tonic-gate{
202*7c478bd9Sstevel@tonic-gate	my ($path_to_object, $dir) = @_;
203*7c478bd9Sstevel@tonic-gate
204*7c478bd9Sstevel@tonic-gate	# The profile output file created by static_profile() in symprof.
205*7c478bd9Sstevel@tonic-gate
206*7c478bd9Sstevel@tonic-gate	my $profile_file = "$dir/profile.static";
207*7c478bd9Sstevel@tonic-gate
208*7c478bd9Sstevel@tonic-gate	my $err_fmt = gettext(
209*7c478bd9Sstevel@tonic-gate	    "binary object %s has no static profile: %s: %s\n");
210*7c478bd9Sstevel@tonic-gate	if (! -f $profile_file) {
211*7c478bd9Sstevel@tonic-gate		emsg("$command_name: " . $err_fmt, $path_to_object,
212*7c478bd9Sstevel@tonic-gate		    $profile_file, $!);
213*7c478bd9Sstevel@tonic-gate		return 0;
214*7c478bd9Sstevel@tonic-gate	}
215*7c478bd9Sstevel@tonic-gate
216*7c478bd9Sstevel@tonic-gate	my $profile_fh = do { local *FH; *FH };
217*7c478bd9Sstevel@tonic-gate	if (! open($profile_fh, "<$profile_file")) {
218*7c478bd9Sstevel@tonic-gate		exiter(nofile($profile_file, $!));
219*7c478bd9Sstevel@tonic-gate	}
220*7c478bd9Sstevel@tonic-gate
221*7c478bd9Sstevel@tonic-gate	my ($profile, $lib, $lib2, $base, %libs_needed);
222*7c478bd9Sstevel@tonic-gate
223*7c478bd9Sstevel@tonic-gate	my $completely_statically_linked = 0;
224*7c478bd9Sstevel@tonic-gate
225*7c478bd9Sstevel@tonic-gate	while (<$profile_fh>) {
226*7c478bd9Sstevel@tonic-gate		$profile .= $_;
227*7c478bd9Sstevel@tonic-gate		if (/^\s*#dtneeded:\s*(.*)$/) {
228*7c478bd9Sstevel@tonic-gate			#
229*7c478bd9Sstevel@tonic-gate			# record the bare name, e.g. "libc" of the
230*7c478bd9Sstevel@tonic-gate			# (direct) dtneededs.
231*7c478bd9Sstevel@tonic-gate			#
232*7c478bd9Sstevel@tonic-gate			foreach $lib (split(/\s+/, $1)) {
233*7c478bd9Sstevel@tonic-gate				next if ($lib eq '');
234*7c478bd9Sstevel@tonic-gate				$base = $lib;
235*7c478bd9Sstevel@tonic-gate				# record it as libc.so.1 -> libc
236*7c478bd9Sstevel@tonic-gate				$base =~ s/\.so\..*$//;
237*7c478bd9Sstevel@tonic-gate				$base =~ s/\.so$//;
238*7c478bd9Sstevel@tonic-gate				$libs_needed{$base} = $lib;
239*7c478bd9Sstevel@tonic-gate				$libs_needed{basename($base)} = $lib;
240*7c478bd9Sstevel@tonic-gate			}
241*7c478bd9Sstevel@tonic-gate		} elsif (/^\s*#SKIPPED_TEST:\s+STATICALLY_LINKED/) {
242*7c478bd9Sstevel@tonic-gate			#
243*7c478bd9Sstevel@tonic-gate			# Record statical linking if it takes place
244*7c478bd9Sstevel@tonic-gate			# since it indicates to skip the test.
245*7c478bd9Sstevel@tonic-gate			#
246*7c478bd9Sstevel@tonic-gate			$completely_statically_linked = 1;
247*7c478bd9Sstevel@tonic-gate		}
248*7c478bd9Sstevel@tonic-gate	}
249*7c478bd9Sstevel@tonic-gate	close($profile_fh);
250*7c478bd9Sstevel@tonic-gate
251*7c478bd9Sstevel@tonic-gate	my $problems = "$dir/check.problems";
252*7c478bd9Sstevel@tonic-gate
253*7c478bd9Sstevel@tonic-gate	my $problems_fh = do { local *FH; *FH };
254*7c478bd9Sstevel@tonic-gate	if (! open($problems_fh, ">>$problems")) {
255*7c478bd9Sstevel@tonic-gate		exiter(nofile($problems, $!));
256*7c478bd9Sstevel@tonic-gate	}
257*7c478bd9Sstevel@tonic-gate
258*7c478bd9Sstevel@tonic-gate	if ($completely_statically_linked) {
259*7c478bd9Sstevel@tonic-gate		print $problems_fh "STATIC: COMPLETELY_STATIC"  . "\n";
260*7c478bd9Sstevel@tonic-gate	}
261*7c478bd9Sstevel@tonic-gate
262*7c478bd9Sstevel@tonic-gate	my (%saw_lib);
263*7c478bd9Sstevel@tonic-gate	if (! defined($profile)) {
264*7c478bd9Sstevel@tonic-gate		close($problems_fh);
265*7c478bd9Sstevel@tonic-gate		return;
266*7c478bd9Sstevel@tonic-gate	}
267*7c478bd9Sstevel@tonic-gate	foreach $lib (lib_static_check($profile)) {
268*7c478bd9Sstevel@tonic-gate		#
269*7c478bd9Sstevel@tonic-gate		# lib_static_check returns a list of statically linked
270*7c478bd9Sstevel@tonic-gate		# libraries, however to be on the safe side we will skip
271*7c478bd9Sstevel@tonic-gate		# false positives our dtneeded's show they are really
272*7c478bd9Sstevel@tonic-gate		# dynamically linked in.
273*7c478bd9Sstevel@tonic-gate		#
274*7c478bd9Sstevel@tonic-gate
275*7c478bd9Sstevel@tonic-gate		next if ($libs_needed{$lib});
276*7c478bd9Sstevel@tonic-gate		next if ($libs_needed{basename($lib)});
277*7c478bd9Sstevel@tonic-gate		next if ($saw_lib{basename($lib)}++);
278*7c478bd9Sstevel@tonic-gate
279*7c478bd9Sstevel@tonic-gate		$lib2 = $lib;
280*7c478bd9Sstevel@tonic-gate		$lib2 =~ s/\.a$//;
281*7c478bd9Sstevel@tonic-gate		next if ($libs_needed{$lib2});
282*7c478bd9Sstevel@tonic-gate		next if ($libs_needed{basename($lib2)});
283*7c478bd9Sstevel@tonic-gate
284*7c478bd9Sstevel@tonic-gate		# Otherwise, record in the problems file:
285*7c478bd9Sstevel@tonic-gate		print $problems_fh "STATIC: LINKED_ARCHIVE $lib" . "\n";
286*7c478bd9Sstevel@tonic-gate	}
287*7c478bd9Sstevel@tonic-gate	close($problems_fh);
288*7c478bd9Sstevel@tonic-gate}
289*7c478bd9Sstevel@tonic-gate
290*7c478bd9Sstevel@tonic-gate#
291*7c478bd9Sstevel@tonic-gate# Takes as input the static profile (e.g. the .text symbols) and returns
292*7c478bd9Sstevel@tonic-gate# a list of suspected statically linked Solaris archive libraries.
293*7c478bd9Sstevel@tonic-gate#
294*7c478bd9Sstevel@tonic-gatesub lib_static_check
295*7c478bd9Sstevel@tonic-gate{
296*7c478bd9Sstevel@tonic-gate	my ($profile) = @_;
297*7c478bd9Sstevel@tonic-gate
298*7c478bd9Sstevel@tonic-gate	my ($line, $area, $extent, $type, $sym, $obj);
299*7c478bd9Sstevel@tonic-gate
300*7c478bd9Sstevel@tonic-gate	my (%symbols);
301*7c478bd9Sstevel@tonic-gate
302*7c478bd9Sstevel@tonic-gate	#
303*7c478bd9Sstevel@tonic-gate	# Working on lines like:
304*7c478bd9Sstevel@tonic-gate	# /bin/ftp|TEXT|GLOB|FUNC|glob
305*7c478bd9Sstevel@tonic-gate	# /bin/ftp|TEXT|GLOB|FUNC|help
306*7c478bd9Sstevel@tonic-gate	#
307*7c478bd9Sstevel@tonic-gate
308*7c478bd9Sstevel@tonic-gate	# First record all the symbols in the TEXT area:
309*7c478bd9Sstevel@tonic-gate
310*7c478bd9Sstevel@tonic-gate	foreach $line (split(/\n/, $profile)) {
311*7c478bd9Sstevel@tonic-gate		next unless ($line =~ /\bTEXT\b/);
312*7c478bd9Sstevel@tonic-gate		($obj, $area, $extent, $type, $sym) = split(/\|/, $line);
313*7c478bd9Sstevel@tonic-gate
314*7c478bd9Sstevel@tonic-gate		$symbols{$sym} = 1;
315*7c478bd9Sstevel@tonic-gate	}
316*7c478bd9Sstevel@tonic-gate
317*7c478bd9Sstevel@tonic-gate	my (@static_libs);
318*7c478bd9Sstevel@tonic-gate
319*7c478bd9Sstevel@tonic-gate	# Next, check against the library heuristics for static linking:
320*7c478bd9Sstevel@tonic-gate
321*7c478bd9Sstevel@tonic-gate	# libc.a:
322*7c478bd9Sstevel@tonic-gate
323*7c478bd9Sstevel@tonic-gate	if (exists($symbols{'_exit'})) {
324*7c478bd9Sstevel@tonic-gate		push(@static_libs, "/usr/lib/libc.a");
325*7c478bd9Sstevel@tonic-gate	}
326*7c478bd9Sstevel@tonic-gate
327*7c478bd9Sstevel@tonic-gate	# libsocket.a:
328*7c478bd9Sstevel@tonic-gate
329*7c478bd9Sstevel@tonic-gate	if (exists($symbols{'socket'}) && exists($symbols{'_socket'}) &&
330*7c478bd9Sstevel@tonic-gate	    exists($symbols{'bind'}) && exists($symbols{'_bind'}) &&
331*7c478bd9Sstevel@tonic-gate	    exists($symbols{'connect'}) && exists($symbols{'_connect'})) {
332*7c478bd9Sstevel@tonic-gate			push(@static_libs, "/usr/lib/libsocket.a");
333*7c478bd9Sstevel@tonic-gate	}
334*7c478bd9Sstevel@tonic-gate
335*7c478bd9Sstevel@tonic-gate	# libnsl.a:
336*7c478bd9Sstevel@tonic-gate
337*7c478bd9Sstevel@tonic-gate	if (exists($symbols{'_xti_bind'}) && exists($symbols{'_xti_connect'}) &&
338*7c478bd9Sstevel@tonic-gate	    exists($symbols{'_tx_bind'}) && exists($symbols{'_tx_connect'})) {
339*7c478bd9Sstevel@tonic-gate			push(@static_libs, "/usr/lib/libnsl.a");
340*7c478bd9Sstevel@tonic-gate	}
341*7c478bd9Sstevel@tonic-gate
342*7c478bd9Sstevel@tonic-gate	return @static_libs;
343*7c478bd9Sstevel@tonic-gate}
344*7c478bd9Sstevel@tonic-gate
345*7c478bd9Sstevel@tonic-gate#
346*7c478bd9Sstevel@tonic-gate# Reads in the dynamic profile from the object's output directory.
347*7c478bd9Sstevel@tonic-gate# Loads any needed public/private Solaris library symbol models.
348*7c478bd9Sstevel@tonic-gate# Records unstable use of any private Solaris symbols in the object's
349*7c478bd9Sstevel@tonic-gate# output directory.
350*7c478bd9Sstevel@tonic-gate#
351*7c478bd9Sstevel@tonic-gatesub dynamic_check_object
352*7c478bd9Sstevel@tonic-gate{
353*7c478bd9Sstevel@tonic-gate	my ($path_to_object, $dir) = @_;
354*7c478bd9Sstevel@tonic-gate
355*7c478bd9Sstevel@tonic-gate	# Location of the dynamic profile output:
356*7c478bd9Sstevel@tonic-gate	my $profile_file = "$dir/profile.dynamic";
357*7c478bd9Sstevel@tonic-gate
358*7c478bd9Sstevel@tonic-gate	my $err_fmt = gettext(
359*7c478bd9Sstevel@tonic-gate	    "binary object %s has no dynamic profile: %s: %s\n");
360*7c478bd9Sstevel@tonic-gate	if (! -f $profile_file) {
361*7c478bd9Sstevel@tonic-gate		emsg("$command_name: " . $err_fmt, $path_to_object,
362*7c478bd9Sstevel@tonic-gate		    $profile_file, $!);
363*7c478bd9Sstevel@tonic-gate		return 0;
364*7c478bd9Sstevel@tonic-gate	}
365*7c478bd9Sstevel@tonic-gate
366*7c478bd9Sstevel@tonic-gate	my $profile_fh = do { local *FH; *FH };
367*7c478bd9Sstevel@tonic-gate	if (! open($profile_fh, "<$profile_file")) {
368*7c478bd9Sstevel@tonic-gate		exiter(nofile($profile_file, $!));
369*7c478bd9Sstevel@tonic-gate	}
370*7c478bd9Sstevel@tonic-gate
371*7c478bd9Sstevel@tonic-gate	$binaries_checked_count++;
372*7c478bd9Sstevel@tonic-gate
373*7c478bd9Sstevel@tonic-gate	#
374*7c478bd9Sstevel@tonic-gate	# Variables to hold temporary items:
375*7c478bd9Sstevel@tonic-gate	#
376*7c478bd9Sstevel@tonic-gate	# %library_list will be a hash of "to" libraries we need to load.
377*7c478bd9Sstevel@tonic-gate	# @symbol_list will be an array of the "lib|sym" pairs.
378*7c478bd9Sstevel@tonic-gate	#
379*7c478bd9Sstevel@tonic-gate
380*7c478bd9Sstevel@tonic-gate	my (%library_list, @symbol_list, @unbound_list);
381*7c478bd9Sstevel@tonic-gate	my ($to, $sym, $from, $binary, $line);
382*7c478bd9Sstevel@tonic-gate
383*7c478bd9Sstevel@tonic-gate	my ($to_is_sys_lib, $from_is_sys_lib);
384*7c478bd9Sstevel@tonic-gate
385*7c478bd9Sstevel@tonic-gate	#
386*7c478bd9Sstevel@tonic-gate	# profile lines look like:
387*7c478bd9Sstevel@tonic-gate	# /bin/ftp|*DIRECT*|libsocket.so.1|socket
388*7c478bd9Sstevel@tonic-gate	# /bin/ftp|libnsl.so.1|libc.so.1|mutex_lock
389*7c478bd9Sstevel@tonic-gate	#
390*7c478bd9Sstevel@tonic-gate	# or:
391*7c478bd9Sstevel@tonic-gate	#
392*7c478bd9Sstevel@tonic-gate	# /bin/ftp|*DIRECT*|/usr/lib/libsocket.so.1|socket
393*7c478bd9Sstevel@tonic-gate	# /bin/ftp|/usr/lib/libnsl.so.1|/usr/lib/libc.so.1|mutex_lock
394*7c478bd9Sstevel@tonic-gate	#
395*7c478bd9Sstevel@tonic-gate
396*7c478bd9Sstevel@tonic-gate	my ($abi, $type, $wordsize, $endian, $e_machine) =
397*7c478bd9Sstevel@tonic-gate	    bin_type($path_to_object);
398*7c478bd9Sstevel@tonic-gate
399*7c478bd9Sstevel@tonic-gate	#
400*7c478bd9Sstevel@tonic-gate	# Setting abi to 'any' will allow continuation when
401*7c478bd9Sstevel@tonic-gate	# we encounter an abi we do not recognize.
402*7c478bd9Sstevel@tonic-gate	#
403*7c478bd9Sstevel@tonic-gate	if (! defined($abi) || $abi eq 'unknown') {
404*7c478bd9Sstevel@tonic-gate		$abi = 'any';
405*7c478bd9Sstevel@tonic-gate	} else {
406*7c478bd9Sstevel@tonic-gate		#
407*7c478bd9Sstevel@tonic-gate		# Always try to load libc.  This will be used for symbol
408*7c478bd9Sstevel@tonic-gate		# migration to libc checks.
409*7c478bd9Sstevel@tonic-gate		#
410*7c478bd9Sstevel@tonic-gate		if (! exists($load_model_default{$abi})) {
411*7c478bd9Sstevel@tonic-gate			load_model($LIBC, $abi);
412*7c478bd9Sstevel@tonic-gate		}
413*7c478bd9Sstevel@tonic-gate		$load_model_default{$abi} = 1;
414*7c478bd9Sstevel@tonic-gate	}
415*7c478bd9Sstevel@tonic-gate
416*7c478bd9Sstevel@tonic-gate	my $dynamic_bindings_count = 0;
417*7c478bd9Sstevel@tonic-gate	my $no_bindings_msg;
418*7c478bd9Sstevel@tonic-gate
419*7c478bd9Sstevel@tonic-gate	while (<$profile_fh>) {
420*7c478bd9Sstevel@tonic-gate		chomp;
421*7c478bd9Sstevel@tonic-gate
422*7c478bd9Sstevel@tonic-gate		if (/^\s*#/) {
423*7c478bd9Sstevel@tonic-gate		    if (/NO_BINDINGS_FOUND\s*(.*)$/) {
424*7c478bd9Sstevel@tonic-gate			my $msg = $1;
425*7c478bd9Sstevel@tonic-gate			if ($msg =~ /^\s*$/) {
426*7c478bd9Sstevel@tonic-gate				$no_bindings_msg = 'NO_SYMBOL_BINDINGS_FOUND';
427*7c478bd9Sstevel@tonic-gate			} else {
428*7c478bd9Sstevel@tonic-gate				$no_bindings_msg = $msg;
429*7c478bd9Sstevel@tonic-gate			}
430*7c478bd9Sstevel@tonic-gate		    }
431*7c478bd9Sstevel@tonic-gate		    next;
432*7c478bd9Sstevel@tonic-gate		}
433*7c478bd9Sstevel@tonic-gate
434*7c478bd9Sstevel@tonic-gate		($binary, $from, $to, $sym) = split(/\|/, $_, 4);
435*7c478bd9Sstevel@tonic-gate
436*7c478bd9Sstevel@tonic-gate		$dynamic_bindings_count++;
437*7c478bd9Sstevel@tonic-gate
438*7c478bd9Sstevel@tonic-gate		# Skip the checking of reverse calls:
439*7c478bd9Sstevel@tonic-gate		next if ($from eq "*REVERSE*");
440*7c478bd9Sstevel@tonic-gate
441*7c478bd9Sstevel@tonic-gate		# Skip the checking of special symbols:
442*7c478bd9Sstevel@tonic-gate		next if (exists($skip_symbols{$sym}));
443*7c478bd9Sstevel@tonic-gate
444*7c478bd9Sstevel@tonic-gate		# Accumulate unbounds, but otherwise skip them:
445*7c478bd9Sstevel@tonic-gate		if ($to eq "*UNBOUND*") {
446*7c478bd9Sstevel@tonic-gate			push(@unbound_list, "$from|$sym");
447*7c478bd9Sstevel@tonic-gate			next;
448*7c478bd9Sstevel@tonic-gate		}
449*7c478bd9Sstevel@tonic-gate
450*7c478bd9Sstevel@tonic-gate		# Record if the "to" object is a system library:
451*7c478bd9Sstevel@tonic-gate		$to_is_sys_lib = is_system_library($to, $abi);
452*7c478bd9Sstevel@tonic-gate
453*7c478bd9Sstevel@tonic-gate		if ($from eq "*DIRECT*") {
454*7c478bd9Sstevel@tonic-gate			$from_is_sys_lib = 0;
455*7c478bd9Sstevel@tonic-gate		} else {
456*7c478bd9Sstevel@tonic-gate			#
457*7c478bd9Sstevel@tonic-gate			# Otherwise we may check its calls. See if it is
458*7c478bd9Sstevel@tonic-gate			# a system lib:
459*7c478bd9Sstevel@tonic-gate			#
460*7c478bd9Sstevel@tonic-gate			$from_is_sys_lib = is_system_library($from, $abi);
461*7c478bd9Sstevel@tonic-gate		}
462*7c478bd9Sstevel@tonic-gate
463*7c478bd9Sstevel@tonic-gate		#
464*7c478bd9Sstevel@tonic-gate		# We will pass judgement on *DIRECT* calls and indirect
465*7c478bd9Sstevel@tonic-gate		# calls from a library we do not recognize.
466*7c478bd9Sstevel@tonic-gate		#
467*7c478bd9Sstevel@tonic-gate		if ($from_is_sys_lib) {
468*7c478bd9Sstevel@tonic-gate			next;
469*7c478bd9Sstevel@tonic-gate		}
470*7c478bd9Sstevel@tonic-gate		if (! $to_is_sys_lib) {
471*7c478bd9Sstevel@tonic-gate			# Call to a middleware or supporting library.
472*7c478bd9Sstevel@tonic-gate			next;
473*7c478bd9Sstevel@tonic-gate		}
474*7c478bd9Sstevel@tonic-gate
475*7c478bd9Sstevel@tonic-gate		$library_list{$to} = 1;
476*7c478bd9Sstevel@tonic-gate		push(@symbol_list, "$from|$to|$abi|$sym");
477*7c478bd9Sstevel@tonic-gate	}
478*7c478bd9Sstevel@tonic-gate
479*7c478bd9Sstevel@tonic-gate	close($profile_fh);
480*7c478bd9Sstevel@tonic-gate
481*7c478bd9Sstevel@tonic-gate	my $file;
482*7c478bd9Sstevel@tonic-gate
483*7c478bd9Sstevel@tonic-gate	my $problems_fh = do { local *FH; *FH };
484*7c478bd9Sstevel@tonic-gate	if ($dynamic_bindings_count == 0 && defined($no_bindings_msg)) {
485*7c478bd9Sstevel@tonic-gate		$file = "$dir/check.problems";
486*7c478bd9Sstevel@tonic-gate
487*7c478bd9Sstevel@tonic-gate		if (! open($problems_fh, ">>$file")) {
488*7c478bd9Sstevel@tonic-gate			exiter(nofile($file, $!));
489*7c478bd9Sstevel@tonic-gate		}
490*7c478bd9Sstevel@tonic-gate
491*7c478bd9Sstevel@tonic-gate		print $problems_fh "DYNAMIC: NO_DYNAMIC_BINDINGS_FOUND" .
492*7c478bd9Sstevel@tonic-gate		    " $no_bindings_msg\n";
493*7c478bd9Sstevel@tonic-gate		close($problems_fh);
494*7c478bd9Sstevel@tonic-gate		return;
495*7c478bd9Sstevel@tonic-gate	}
496*7c478bd9Sstevel@tonic-gate
497*7c478bd9Sstevel@tonic-gate	my ($lib, $str);
498*7c478bd9Sstevel@tonic-gate
499*7c478bd9Sstevel@tonic-gate	$file = "$dir/check.dynamic.abi_models";
500*7c478bd9Sstevel@tonic-gate	my $model_info_fh = do { local *FH; *FH };
501*7c478bd9Sstevel@tonic-gate	if (! open($model_info_fh, ">$file")) {
502*7c478bd9Sstevel@tonic-gate		exiter(nofile($file, $!));
503*7c478bd9Sstevel@tonic-gate	}
504*7c478bd9Sstevel@tonic-gate
505*7c478bd9Sstevel@tonic-gate	# Load all the needed library models:
506*7c478bd9Sstevel@tonic-gate	my ($s1, $s2);
507*7c478bd9Sstevel@tonic-gate	$s1 = ",NO_PUBLIC/PRIVATE_MODEL_FOUND-SKIPPING_CHECK_FOR_THIS_LIBRARY";
508*7c478bd9Sstevel@tonic-gate	$s2 = "ERROR_LOADING_PUBLIC/PRIVATE_MODEL";
509*7c478bd9Sstevel@tonic-gate
510*7c478bd9Sstevel@tonic-gate	foreach $lib (keys %library_list) {
511*7c478bd9Sstevel@tonic-gate		if (! load_model($lib, $abi) && ! $load_error{"$lib|$abi"}) {
512*7c478bd9Sstevel@tonic-gate			$load_error{"$lib|$abi"} = 1;
513*7c478bd9Sstevel@tonic-gate		}
514*7c478bd9Sstevel@tonic-gate		$str = $model_loaded{"$lib|$abi"};
515*7c478bd9Sstevel@tonic-gate		if ($str eq '__FAILED__') {
516*7c478bd9Sstevel@tonic-gate			$str .= $s1;
517*7c478bd9Sstevel@tonic-gate		} elsif (! $str) {
518*7c478bd9Sstevel@tonic-gate			$str = $s2;
519*7c478bd9Sstevel@tonic-gate		}
520*7c478bd9Sstevel@tonic-gate		print $model_info_fh "$lib:$str\n";
521*7c478bd9Sstevel@tonic-gate	}
522*7c478bd9Sstevel@tonic-gate	close($model_info_fh);
523*7c478bd9Sstevel@tonic-gate
524*7c478bd9Sstevel@tonic-gate	my ($lib_abi_sym, $class, %result_list);
525*7c478bd9Sstevel@tonic-gate
526*7c478bd9Sstevel@tonic-gate	my ($l, $a, $s);
527*7c478bd9Sstevel@tonic-gate	foreach $lib_abi_sym (@symbol_list) {
528*7c478bd9Sstevel@tonic-gate
529*7c478bd9Sstevel@tonic-gate		($from, $lib_abi_sym) = split(/\|/, $lib_abi_sym, 2);
530*7c478bd9Sstevel@tonic-gate
531*7c478bd9Sstevel@tonic-gate		($l, $a, $s) = split(/\|/, $lib_abi_sym);
532*7c478bd9Sstevel@tonic-gate
533*7c478bd9Sstevel@tonic-gate		if (! exists($model{$lib_abi_sym})) {
534*7c478bd9Sstevel@tonic-gate			#
535*7c478bd9Sstevel@tonic-gate			# Check the library.  If it is not in
536*7c478bd9Sstevel@tonic-gate			# model_loaded, then we claim it is not a
537*7c478bd9Sstevel@tonic-gate			# library we are interested in.
538*7c478bd9Sstevel@tonic-gate			#
539*7c478bd9Sstevel@tonic-gate			next if (! exists($model_loaded{"$l|$a"}));
540*7c478bd9Sstevel@tonic-gate			next if ($model_loaded{"$l|$a"} eq '__FAILED__');
541*7c478bd9Sstevel@tonic-gate
542*7c478bd9Sstevel@tonic-gate			# it is an unrecognized symbol:
543*7c478bd9Sstevel@tonic-gate			$result_list{'unrecognized'} .=
544*7c478bd9Sstevel@tonic-gate			    "$from|$lib_abi_sym" . "\n";
545*7c478bd9Sstevel@tonic-gate			next;
546*7c478bd9Sstevel@tonic-gate		}
547*7c478bd9Sstevel@tonic-gate
548*7c478bd9Sstevel@tonic-gate		# N.B. $lib_abi_sym and $l may have been altered above.
549*7c478bd9Sstevel@tonic-gate		$class = $model{$lib_abi_sym};
550*7c478bd9Sstevel@tonic-gate		$line = "$path_to_object|$a|$from|$l|$class|$s" . "\n";
551*7c478bd9Sstevel@tonic-gate
552*7c478bd9Sstevel@tonic-gate		if ($class !~ /^(public|private|unclassified)$/) {
553*7c478bd9Sstevel@tonic-gate			exiter("$command_name" . sprintf(gettext(
554*7c478bd9Sstevel@tonic-gate			    "unrecognized symbol class: %s"), $class));
555*7c478bd9Sstevel@tonic-gate		}
556*7c478bd9Sstevel@tonic-gate
557*7c478bd9Sstevel@tonic-gate		$result_list{$class} .= $line;
558*7c478bd9Sstevel@tonic-gate	}
559*7c478bd9Sstevel@tonic-gate
560*7c478bd9Sstevel@tonic-gate	if (@unbound_list) {
561*7c478bd9Sstevel@tonic-gate		my $ldd_file = "$dir/profile.dynamic.ldd";
562*7c478bd9Sstevel@tonic-gate		my $tmp;
563*7c478bd9Sstevel@tonic-gate		if (-f $ldd_file) {
564*7c478bd9Sstevel@tonic-gate			my $ldd_info_fh = do { local *FH; *FH };
565*7c478bd9Sstevel@tonic-gate			if (! open($ldd_info_fh, "<$ldd_file")) {
566*7c478bd9Sstevel@tonic-gate				exiter(nofile($ldd_file, $!));
567*7c478bd9Sstevel@tonic-gate			}
568*7c478bd9Sstevel@tonic-gate			while (<$ldd_info_fh>) {
569*7c478bd9Sstevel@tonic-gate				$tmp .= '# ' . $_ if (/not\s+found/);
570*7c478bd9Sstevel@tonic-gate			}
571*7c478bd9Sstevel@tonic-gate			close($ldd_info_fh);
572*7c478bd9Sstevel@tonic-gate		}
573*7c478bd9Sstevel@tonic-gate		if (defined($tmp)) {
574*7c478bd9Sstevel@tonic-gate			$result_list{'unbound'} = $tmp;
575*7c478bd9Sstevel@tonic-gate		}
576*7c478bd9Sstevel@tonic-gate		$result_list{'unbound'} .= join("\n", @unbound_list) . "\n";
577*7c478bd9Sstevel@tonic-gate	}
578*7c478bd9Sstevel@tonic-gate
579*7c478bd9Sstevel@tonic-gate	my $count;
580*7c478bd9Sstevel@tonic-gate
581*7c478bd9Sstevel@tonic-gate	my @classes = qw(private public unbound unclassified unrecognized);
582*7c478bd9Sstevel@tonic-gate
583*7c478bd9Sstevel@tonic-gate	foreach $class (@classes) {
584*7c478bd9Sstevel@tonic-gate
585*7c478bd9Sstevel@tonic-gate		next if (! exists($result_list{$class}));
586*7c478bd9Sstevel@tonic-gate
587*7c478bd9Sstevel@tonic-gate		$file = "$dir/check.dynamic.$class";
588*7c478bd9Sstevel@tonic-gate
589*7c478bd9Sstevel@tonic-gate		my $outfile_fh = do { local *FH; *FH };
590*7c478bd9Sstevel@tonic-gate		if (! open($outfile_fh, ">$file")) {
591*7c478bd9Sstevel@tonic-gate			exiter(nofile($file, $!));
592*7c478bd9Sstevel@tonic-gate		}
593*7c478bd9Sstevel@tonic-gate		if ($class eq 'private') {
594*7c478bd9Sstevel@tonic-gate			print $outfile_fh
595*7c478bd9Sstevel@tonic-gate			    $text{'Message_Private_Symbols_Check_Outfile'};
596*7c478bd9Sstevel@tonic-gate		} elsif ($class eq 'public') {
597*7c478bd9Sstevel@tonic-gate			print $outfile_fh
598*7c478bd9Sstevel@tonic-gate			    $text{'Message_Public_Symbols_Check_Outfile'};
599*7c478bd9Sstevel@tonic-gate		}
600*7c478bd9Sstevel@tonic-gate		print $outfile_fh $result_list{$class};
601*7c478bd9Sstevel@tonic-gate		close($outfile_fh);
602*7c478bd9Sstevel@tonic-gate	}
603*7c478bd9Sstevel@tonic-gate
604*7c478bd9Sstevel@tonic-gate	$file = "$dir/check.problems";
605*7c478bd9Sstevel@tonic-gate
606*7c478bd9Sstevel@tonic-gate	if (! open($problems_fh, ">>$file")) {
607*7c478bd9Sstevel@tonic-gate		exiter(nofile($file, $!));
608*7c478bd9Sstevel@tonic-gate	}
609*7c478bd9Sstevel@tonic-gate
610*7c478bd9Sstevel@tonic-gate	if (exists($result_list{'private'})) {
611*7c478bd9Sstevel@tonic-gate		$count = scalar(my @a = split(/\n/, $result_list{'private'}));
612*7c478bd9Sstevel@tonic-gate		print $problems_fh "DYNAMIC: PRIVATE_SYMBOL_USE $count\n";
613*7c478bd9Sstevel@tonic-gate	}
614*7c478bd9Sstevel@tonic-gate	if (exists($result_list{'unbound'})) {
615*7c478bd9Sstevel@tonic-gate		$count = scalar(@unbound_list);
616*7c478bd9Sstevel@tonic-gate		print $problems_fh "DYNAMIC: UNBOUND_SYMBOL_USE $count\n";
617*7c478bd9Sstevel@tonic-gate	}
618*7c478bd9Sstevel@tonic-gate	if (exists($result_list{'unrecognized'})) {
619*7c478bd9Sstevel@tonic-gate		$count =
620*7c478bd9Sstevel@tonic-gate		    scalar(my @a = split(/\n/, $result_list{'unrecognized'}));
621*7c478bd9Sstevel@tonic-gate		print $problems_fh "DYNAMIC: UNRECOGNIZED_SYMBOL_USE $count\n";
622*7c478bd9Sstevel@tonic-gate	}
623*7c478bd9Sstevel@tonic-gate
624*7c478bd9Sstevel@tonic-gate	close($problems_fh);
625*7c478bd9Sstevel@tonic-gate}
626*7c478bd9Sstevel@tonic-gate
627*7c478bd9Sstevel@tonic-gate#
628*7c478bd9Sstevel@tonic-gate# Loads a system model for a library on demand.
629*7c478bd9Sstevel@tonic-gate#
630*7c478bd9Sstevel@tonic-gate# Input is a library to load and the architecture ABI.
631*7c478bd9Sstevel@tonic-gate#
632*7c478bd9Sstevel@tonic-gate# On successful completion, 1 is returned and the associative array:
633*7c478bd9Sstevel@tonic-gate#
634*7c478bd9Sstevel@tonic-gate#	%model{"$library|$abi|$symbol"} = {public,private}
635*7c478bd9Sstevel@tonic-gate#
636*7c478bd9Sstevel@tonic-gate#	is set.
637*7c478bd9Sstevel@tonic-gate#
638*7c478bd9Sstevel@tonic-gatesub load_model
639*7c478bd9Sstevel@tonic-gate{
640*7c478bd9Sstevel@tonic-gate	#
641*7c478bd9Sstevel@tonic-gate	# Returns 1 if the model was successfully loaded, or returns 0
642*7c478bd9Sstevel@tonic-gate	# if it was not.
643*7c478bd9Sstevel@tonic-gate	#
644*7c478bd9Sstevel@tonic-gate
645*7c478bd9Sstevel@tonic-gate	my ($library, $abi) = @_;
646*7c478bd9Sstevel@tonic-gate
647*7c478bd9Sstevel@tonic-gate	#
648*7c478bd9Sstevel@tonic-gate	# This %model_loaded hash records the following states:
649*7c478bd9Sstevel@tonic-gate	#    <string>	Method by which successfully loaded.
650*7c478bd9Sstevel@tonic-gate	#    __FAILED__	Failed to loaded successfully.
651*7c478bd9Sstevel@tonic-gate	#    undef      Have not tried to load yet.
652*7c478bd9Sstevel@tonic-gate	#
653*7c478bd9Sstevel@tonic-gate	if (exists($model_loaded{"$library|$abi"})) {
654*7c478bd9Sstevel@tonic-gate		if ($model_loaded{"$library|$abi"} eq '__FAILED__') {
655*7c478bd9Sstevel@tonic-gate			return 0;
656*7c478bd9Sstevel@tonic-gate		} elsif ($model_loaded{"$library|$abi"}) {
657*7c478bd9Sstevel@tonic-gate			return 1;
658*7c478bd9Sstevel@tonic-gate		}
659*7c478bd9Sstevel@tonic-gate	}
660*7c478bd9Sstevel@tonic-gate
661*7c478bd9Sstevel@tonic-gate	my ($loaded, $ok);
662*7c478bd9Sstevel@tonic-gate
663*7c478bd9Sstevel@tonic-gate	$loaded = 1 if (load_model_versioned_lib($library, $abi));
664*7c478bd9Sstevel@tonic-gate
665*7c478bd9Sstevel@tonic-gate	# Record the result so we do not have to repeat the above:
666*7c478bd9Sstevel@tonic-gate
667*7c478bd9Sstevel@tonic-gate	if ($loaded) {
668*7c478bd9Sstevel@tonic-gate		$ok = "OK";
669*7c478bd9Sstevel@tonic-gate		my $tweaks = load_tweaks($library, $abi);
670*7c478bd9Sstevel@tonic-gate		$ok .= ",Model_Tweaks\[$tweaks\]" if ($tweaks);
671*7c478bd9Sstevel@tonic-gate		$model_loaded{"$library|$abi"} = $ok;
672*7c478bd9Sstevel@tonic-gate	} else {
673*7c478bd9Sstevel@tonic-gate		$model_loaded{"$library|$abi"} = '__FAILED__';
674*7c478bd9Sstevel@tonic-gate	}
675*7c478bd9Sstevel@tonic-gate
676*7c478bd9Sstevel@tonic-gate	return $loaded;
677*7c478bd9Sstevel@tonic-gate}
678*7c478bd9Sstevel@tonic-gate
679*7c478bd9Sstevel@tonic-gate#
680*7c478bd9Sstevel@tonic-gate# Routine to load into %model any special modifications to the Solaris
681*7c478bd9Sstevel@tonic-gate# symbol Models kept in the etc.* file.
682*7c478bd9Sstevel@tonic-gate#
683*7c478bd9Sstevel@tonic-gatesub load_tweaks
684*7c478bd9Sstevel@tonic-gate{
685*7c478bd9Sstevel@tonic-gate	my ($lib, $abi) = @_;
686*7c478bd9Sstevel@tonic-gate
687*7c478bd9Sstevel@tonic-gate	my $key;
688*7c478bd9Sstevel@tonic-gate	if (exists($model_tweak{$lib}) && $model_tweak{$lib}) {
689*7c478bd9Sstevel@tonic-gate		$key = $lib;
690*7c478bd9Sstevel@tonic-gate	} else {
691*7c478bd9Sstevel@tonic-gate		#
692*7c478bd9Sstevel@tonic-gate		# check device/inode record so as to not get tricked by
693*7c478bd9Sstevel@tonic-gate		# symlinks.
694*7c478bd9Sstevel@tonic-gate		#
695*7c478bd9Sstevel@tonic-gate		my ($device, $inode) = (stat($lib))[0,1];
696*7c478bd9Sstevel@tonic-gate		if (! defined($device) || ! defined($inode)) {
697*7c478bd9Sstevel@tonic-gate			return 0;
698*7c478bd9Sstevel@tonic-gate		}
699*7c478bd9Sstevel@tonic-gate		$key = "$device/$inode";
700*7c478bd9Sstevel@tonic-gate		if (! exists($model_tweak{$key}) || ! $model_tweak{$key}) {
701*7c478bd9Sstevel@tonic-gate			return 0;
702*7c478bd9Sstevel@tonic-gate		}
703*7c478bd9Sstevel@tonic-gate		#
704*7c478bd9Sstevel@tonic-gate		# device/inode $key is recorded, so continue along
705*7c478bd9Sstevel@tonic-gate		# using it below in the model_tweak lookup.
706*7c478bd9Sstevel@tonic-gate		#
707*7c478bd9Sstevel@tonic-gate	}
708*7c478bd9Sstevel@tonic-gate
709*7c478bd9Sstevel@tonic-gate	#
710*7c478bd9Sstevel@tonic-gate	# etc line looks like:
711*7c478bd9Sstevel@tonic-gate	# MODEL_TWEAK|/usr/lib/libnsl.so.1|sparc,i386|gethostname|public
712*7c478bd9Sstevel@tonic-gate	# value looks like:
713*7c478bd9Sstevel@tonic-gate	# gethostname|sparc,i386|public
714*7c478bd9Sstevel@tonic-gate	#
715*7c478bd9Sstevel@tonic-gate
716*7c478bd9Sstevel@tonic-gate	my ($case, $abis, $sym, $class, $count);
717*7c478bd9Sstevel@tonic-gate
718*7c478bd9Sstevel@tonic-gate	$count = 0;
719*7c478bd9Sstevel@tonic-gate	foreach $case (split(/,/, $model_tweak{$key})) {
720*7c478bd9Sstevel@tonic-gate		($sym, $abis, $class) = split(/\|/, $case);
721*7c478bd9Sstevel@tonic-gate		if ($abis eq '*' || ($abis =~ /\b${abi}\b/)) {
722*7c478bd9Sstevel@tonic-gate			$model{"$lib|$abi|$sym"} = $class;
723*7c478bd9Sstevel@tonic-gate			$count++;
724*7c478bd9Sstevel@tonic-gate		}
725*7c478bd9Sstevel@tonic-gate	}
726*7c478bd9Sstevel@tonic-gate
727*7c478bd9Sstevel@tonic-gate	return $count;
728*7c478bd9Sstevel@tonic-gate}
729*7c478bd9Sstevel@tonic-gate
730*7c478bd9Sstevel@tonic-gate#
731*7c478bd9Sstevel@tonic-gate# Determine the public/private symbol model for a versioned Solaris
732*7c478bd9Sstevel@tonic-gate# library. Returns 0 if no model could be extracted, otherwise returns a
733*7c478bd9Sstevel@tonic-gate# string detailing the model loading.
734*7c478bd9Sstevel@tonic-gate#
735*7c478bd9Sstevel@tonic-gatesub load_model_versioned_lib
736*7c478bd9Sstevel@tonic-gate{
737*7c478bd9Sstevel@tonic-gate	my ($library, $abi) = @_;
738*7c478bd9Sstevel@tonic-gate
739*7c478bd9Sstevel@tonic-gate	#
740*7c478bd9Sstevel@tonic-gate	# This subroutine runs pvs -dos directly on the Solaris shared
741*7c478bd9Sstevel@tonic-gate	# object, and parses data that looks like this:
742*7c478bd9Sstevel@tonic-gate	#
743*7c478bd9Sstevel@tonic-gate	# % pvs -dos /usr/lib/libsocket.so.1
744*7c478bd9Sstevel@tonic-gate	# ...
745*7c478bd9Sstevel@tonic-gate	# /usr/lib/libsocket.so.1 -       SUNW_1.1: __xnet_sendmsg;
746*7c478bd9Sstevel@tonic-gate	# ...
747*7c478bd9Sstevel@tonic-gate	# /usr/lib/libsocket.so.1 -       SISCD_2.3: connect;
748*7c478bd9Sstevel@tonic-gate	# ...
749*7c478bd9Sstevel@tonic-gate	# /usr/lib/libsocket.so.1 -       SUNWprivate_1.2: getnetmaskbyaddr;
750*7c478bd9Sstevel@tonic-gate	#
751*7c478bd9Sstevel@tonic-gate	# Note that data types look like:
752*7c478bd9Sstevel@tonic-gate	# /usr/lib/libc.so.1 -    SUNWprivate_1.1: __environ_lock (24);
753*7c478bd9Sstevel@tonic-gate	#
754*7c478bd9Sstevel@tonic-gate	# we discard the size.
755*7c478bd9Sstevel@tonic-gate	#
756*7c478bd9Sstevel@tonic-gate	# On successful completion 1, is returned and the hash:
757*7c478bd9Sstevel@tonic-gate	#
758*7c478bd9Sstevel@tonic-gate	#	%model{"$library|$abi|$symbol"} = {public,private}
759*7c478bd9Sstevel@tonic-gate	#
760*7c478bd9Sstevel@tonic-gate	# is set.
761*7c478bd9Sstevel@tonic-gate	#
762*7c478bd9Sstevel@tonic-gate
763*7c478bd9Sstevel@tonic-gate	# library must be a full path and exist:
764*7c478bd9Sstevel@tonic-gate	if (! -f $library) {
765*7c478bd9Sstevel@tonic-gate		return 0;
766*7c478bd9Sstevel@tonic-gate	}
767*7c478bd9Sstevel@tonic-gate
768*7c478bd9Sstevel@tonic-gate	my ($rc, $output, $output_syslib);
769*7c478bd9Sstevel@tonic-gate
770*7c478bd9Sstevel@tonic-gate	#
771*7c478bd9Sstevel@tonic-gate	# quote character should never happen in normal use, but if it
772*7c478bd9Sstevel@tonic-gate	# did it will foul up the pvs commands below, so we return
773*7c478bd9Sstevel@tonic-gate	# early.
774*7c478bd9Sstevel@tonic-gate	#
775*7c478bd9Sstevel@tonic-gate	if ($library =~ /'/) {
776*7c478bd9Sstevel@tonic-gate		return 0;
777*7c478bd9Sstevel@tonic-gate	}
778*7c478bd9Sstevel@tonic-gate
779*7c478bd9Sstevel@tonic-gate	#
780*7c478bd9Sstevel@tonic-gate	# Get the entire list of symbols:
781*7c478bd9Sstevel@tonic-gate	# note that $library does not contain a single-quote.
782*7c478bd9Sstevel@tonic-gate	#
783*7c478bd9Sstevel@tonic-gate	c_locale(1);
784*7c478bd9Sstevel@tonic-gate	$output = `$cmd_pvs -dos '$library' 2>/dev/null`;
785*7c478bd9Sstevel@tonic-gate	$rc = $?;
786*7c478bd9Sstevel@tonic-gate	c_locale(0);
787*7c478bd9Sstevel@tonic-gate
788*7c478bd9Sstevel@tonic-gate	if ($rc != 0 || ($output =~ /^[\s\n]*$/)) {
789*7c478bd9Sstevel@tonic-gate		# It is not versioned, so get out.
790*7c478bd9Sstevel@tonic-gate		return 0;
791*7c478bd9Sstevel@tonic-gate	}
792*7c478bd9Sstevel@tonic-gate
793*7c478bd9Sstevel@tonic-gate	# Library is versioned with something from this point on.
794*7c478bd9Sstevel@tonic-gate
795*7c478bd9Sstevel@tonic-gate	my ($line, $libtmp, $j1, $j2, $version, $symbol, $class);
796*7c478bd9Sstevel@tonic-gate	my ($count, $public_count, $private_count);
797*7c478bd9Sstevel@tonic-gate	my (%versions);
798*7c478bd9Sstevel@tonic-gate	my $libbase = basename($library);
799*7c478bd9Sstevel@tonic-gate
800*7c478bd9Sstevel@tonic-gate	$count = 0;
801*7c478bd9Sstevel@tonic-gate	$public_count = 0;
802*7c478bd9Sstevel@tonic-gate	$private_count = 0;
803*7c478bd9Sstevel@tonic-gate
804*7c478bd9Sstevel@tonic-gate	my $is_system_lib = is_system_library($library, $abi);
805*7c478bd9Sstevel@tonic-gate
806*7c478bd9Sstevel@tonic-gate	my (@defs, $def);
807*7c478bd9Sstevel@tonic-gate	if (defined($is_system_lib)) {
808*7c478bd9Sstevel@tonic-gate		foreach $def (split(/:/, $is_system_lib)) {
809*7c478bd9Sstevel@tonic-gate			next if ($def =~ /^FILE=/);
810*7c478bd9Sstevel@tonic-gate			next if ($def =~ /^-$/);
811*7c478bd9Sstevel@tonic-gate			push(@defs, $def);
812*7c478bd9Sstevel@tonic-gate		}
813*7c478bd9Sstevel@tonic-gate		if (@defs == 1) {
814*7c478bd9Sstevel@tonic-gate			$is_system_lib = $defs[0];
815*7c478bd9Sstevel@tonic-gate		}
816*7c478bd9Sstevel@tonic-gate	}
817*7c478bd9Sstevel@tonic-gate
818*7c478bd9Sstevel@tonic-gate	my (@version_heads, $vers, $default_class);
819*7c478bd9Sstevel@tonic-gate	if (defined($is_system_lib) && $is_system_lib ne 'NO_PUBLIC_SYMS') {
820*7c478bd9Sstevel@tonic-gate		#
821*7c478bd9Sstevel@tonic-gate		# It is a versioned system library.  Extract the public
822*7c478bd9Sstevel@tonic-gate		# symbols version head end(s)
823*7c478bd9Sstevel@tonic-gate		#
824*7c478bd9Sstevel@tonic-gate		if ($is_system_lib =~ /^PUBLIC=(.*)$/) {
825*7c478bd9Sstevel@tonic-gate			@version_heads = split(/,/, $1);
826*7c478bd9Sstevel@tonic-gate		} else {
827*7c478bd9Sstevel@tonic-gate			push(@version_heads, $is_system_lib);
828*7c478bd9Sstevel@tonic-gate		}
829*7c478bd9Sstevel@tonic-gate
830*7c478bd9Sstevel@tonic-gate		#
831*7c478bd9Sstevel@tonic-gate		# Rerun pvs again to extract the symbols associated with
832*7c478bd9Sstevel@tonic-gate		# the *public* inheritance chain(s).
833*7c478bd9Sstevel@tonic-gate		#
834*7c478bd9Sstevel@tonic-gate		c_locale(1);
835*7c478bd9Sstevel@tonic-gate		foreach $vers (@version_heads) {
836*7c478bd9Sstevel@tonic-gate			# something is wrong if $vers has a quote
837*7c478bd9Sstevel@tonic-gate			$vers =~ s/'//g;
838*7c478bd9Sstevel@tonic-gate
839*7c478bd9Sstevel@tonic-gate			# $library has been screened for single quotes earlier.
840*7c478bd9Sstevel@tonic-gate			$output_syslib .=
841*7c478bd9Sstevel@tonic-gate			    `$cmd_pvs -dos -N '$vers' '$library' 2>/dev/null`;
842*7c478bd9Sstevel@tonic-gate		}
843*7c478bd9Sstevel@tonic-gate		c_locale(0);
844*7c478bd9Sstevel@tonic-gate	}
845*7c478bd9Sstevel@tonic-gate
846*7c478bd9Sstevel@tonic-gate
847*7c478bd9Sstevel@tonic-gate	if (defined($output_syslib) && ($output_syslib !~ /^[\s\n]*$/)) {
848*7c478bd9Sstevel@tonic-gate		#
849*7c478bd9Sstevel@tonic-gate		# If non-empty there are some public symbols sets.
850*7c478bd9Sstevel@tonic-gate		# First, mark everything private:
851*7c478bd9Sstevel@tonic-gate		#
852*7c478bd9Sstevel@tonic-gate		$output = "DEFAULT_CLASS=private\n" . $output;
853*7c478bd9Sstevel@tonic-gate		# then overwrite the public ones:
854*7c478bd9Sstevel@tonic-gate		$output .= "DEFAULT_CLASS=public\n"  . $output_syslib;
855*7c478bd9Sstevel@tonic-gate	} elsif (defined($is_system_lib) &&
856*7c478bd9Sstevel@tonic-gate	    $is_system_lib eq 'NO_PUBLIC_SYMS') {
857*7c478bd9Sstevel@tonic-gate		# Everything is private:
858*7c478bd9Sstevel@tonic-gate		$output = "DEFAULT_CLASS=private\n" . $output;
859*7c478bd9Sstevel@tonic-gate	} else {
860*7c478bd9Sstevel@tonic-gate		#
861*7c478bd9Sstevel@tonic-gate		# assume public, the override will occur when version
862*7c478bd9Sstevel@tonic-gate		# string matches /private/i. This is for 3rd party
863*7c478bd9Sstevel@tonic-gate		# libraries.
864*7c478bd9Sstevel@tonic-gate		#
865*7c478bd9Sstevel@tonic-gate		$output = "DEFAULT_CLASS=public\n" . $output;
866*7c478bd9Sstevel@tonic-gate	}
867*7c478bd9Sstevel@tonic-gate
868*7c478bd9Sstevel@tonic-gate	foreach $line (split(/\n/, $output)) {
869*7c478bd9Sstevel@tonic-gate		$line = trim($line);
870*7c478bd9Sstevel@tonic-gate		if ($line =~ /^DEFAULT_CLASS=(.*)$/) {
871*7c478bd9Sstevel@tonic-gate			$default_class = $1;
872*7c478bd9Sstevel@tonic-gate			next;
873*7c478bd9Sstevel@tonic-gate		}
874*7c478bd9Sstevel@tonic-gate		($libtmp, $j1, $version, $symbol, $j2) = split(/\s+/, $line);
875*7c478bd9Sstevel@tonic-gate
876*7c478bd9Sstevel@tonic-gate		$symbol  =~ s/;*$//;
877*7c478bd9Sstevel@tonic-gate		$version =~ s/:*$//;
878*7c478bd9Sstevel@tonic-gate
879*7c478bd9Sstevel@tonic-gate		next if ($symbol =~ /^\s*$/);
880*7c478bd9Sstevel@tonic-gate		next if ($version eq $libbase);	# see example output above
881*7c478bd9Sstevel@tonic-gate
882*7c478bd9Sstevel@tonic-gate		$versions{$version}++;
883*7c478bd9Sstevel@tonic-gate
884*7c478bd9Sstevel@tonic-gate		$class = $default_class;
885*7c478bd9Sstevel@tonic-gate
886*7c478bd9Sstevel@tonic-gate		if (! $output_syslib && ($version =~ /private/i)) {
887*7c478bd9Sstevel@tonic-gate			$class = 'private';
888*7c478bd9Sstevel@tonic-gate		}
889*7c478bd9Sstevel@tonic-gate
890*7c478bd9Sstevel@tonic-gate		if ($class eq 'private') {
891*7c478bd9Sstevel@tonic-gate			$private_count++;
892*7c478bd9Sstevel@tonic-gate		} else {
893*7c478bd9Sstevel@tonic-gate			if ($output_syslib) {
894*7c478bd9Sstevel@tonic-gate				# remove the double counting of this version:
895*7c478bd9Sstevel@tonic-gate				$versions{$version}--;
896*7c478bd9Sstevel@tonic-gate				$private_count--;
897*7c478bd9Sstevel@tonic-gate				$count--;
898*7c478bd9Sstevel@tonic-gate			}
899*7c478bd9Sstevel@tonic-gate			$public_count++;
900*7c478bd9Sstevel@tonic-gate		}
901*7c478bd9Sstevel@tonic-gate
902*7c478bd9Sstevel@tonic-gate		$model{"$library|$abi|$symbol"} = $class;
903*7c478bd9Sstevel@tonic-gate		$count++;
904*7c478bd9Sstevel@tonic-gate	}
905*7c478bd9Sstevel@tonic-gate
906*7c478bd9Sstevel@tonic-gate	if (! $count) {
907*7c478bd9Sstevel@tonic-gate		return 0;
908*7c478bd9Sstevel@tonic-gate	}
909*7c478bd9Sstevel@tonic-gate
910*7c478bd9Sstevel@tonic-gate	# Construct the info string:
911*7c478bd9Sstevel@tonic-gate	$libtmp = "load_model_versioned_lib,$library,$abi:";
912*7c478bd9Sstevel@tonic-gate	foreach $version (sort(keys(%versions))) {
913*7c478bd9Sstevel@tonic-gate		$libtmp .= "$version\[$versions{$version}\],";
914*7c478bd9Sstevel@tonic-gate	}
915*7c478bd9Sstevel@tonic-gate	$libtmp .=
916*7c478bd9Sstevel@tonic-gate	    "\[${count}symbols=${public_count}public+${private_count}private\]";
917*7c478bd9Sstevel@tonic-gate	return $libtmp;
918*7c478bd9Sstevel@tonic-gate}
919*7c478bd9Sstevel@tonic-gate
920*7c478bd9Sstevel@tonic-gate#
921*7c478bd9Sstevel@tonic-gate# Returns a non-empty string if the $path_to_library is recognized as a
922*7c478bd9Sstevel@tonic-gate# System (i.e. Solaris) ABI library for given abi.  Returns undef
923*7c478bd9Sstevel@tonic-gate# otherwise.  The returned string will either be the public symbol version
924*7c478bd9Sstevel@tonic-gate# name(s), "NO_PUBLIC_SYMS" if all symbols are private, or "-" if there
925*7c478bd9Sstevel@tonic-gate# is no versioning at all.
926*7c478bd9Sstevel@tonic-gate#
927*7c478bd9Sstevel@tonic-gatesub is_system_library
928*7c478bd9Sstevel@tonic-gate{
929*7c478bd9Sstevel@tonic-gate	my ($path_to_library, $abi) = @_;
930*7c478bd9Sstevel@tonic-gate
931*7c478bd9Sstevel@tonic-gate	if (exists($is_system_library_cache{"$path_to_library|$abi"})) {
932*7c478bd9Sstevel@tonic-gate		return $is_system_library_cache{"$path_to_library|$abi"};
933*7c478bd9Sstevel@tonic-gate	}
934*7c478bd9Sstevel@tonic-gate
935*7c478bd9Sstevel@tonic-gate	my ($dir, $def, $key);
936*7c478bd9Sstevel@tonic-gate
937*7c478bd9Sstevel@tonic-gate	my ($device, $inode) = (stat($path_to_library))[0,1];
938*7c478bd9Sstevel@tonic-gate	foreach $dir (@lib_index_loaded) {
939*7c478bd9Sstevel@tonic-gate
940*7c478bd9Sstevel@tonic-gate		$key = "$dir|$path_to_library|$abi";
941*7c478bd9Sstevel@tonic-gate		$def = $lib_index_definition{$key};
942*7c478bd9Sstevel@tonic-gate		if (defined($device) && defined($inode) && ! defined($def)) {
943*7c478bd9Sstevel@tonic-gate			# try inode lookup (chases down unexpected symlinks)
944*7c478bd9Sstevel@tonic-gate			$key = "$dir|$device/$inode|$abi";
945*7c478bd9Sstevel@tonic-gate			$def = $lib_index_definition{$key};
946*7c478bd9Sstevel@tonic-gate		}
947*7c478bd9Sstevel@tonic-gate		last if (defined($def));
948*7c478bd9Sstevel@tonic-gate	}
949*7c478bd9Sstevel@tonic-gate	if (!defined($def) && $path_to_library !~ /'/) {
950*7c478bd9Sstevel@tonic-gate		#
951*7c478bd9Sstevel@tonic-gate		# we skip the case $path_to_library containing
952*7c478bd9Sstevel@tonic-gate		# a single quote, so the cmd argument is protected.
953*7c478bd9Sstevel@tonic-gate		#
954*7c478bd9Sstevel@tonic-gate		my $tmp = `$cmd_pvs -dn '$path_to_library' 2>/dev/null`;
955*7c478bd9Sstevel@tonic-gate		if ($tmp =~ /\b(SUNW[^;]*);/) {
956*7c478bd9Sstevel@tonic-gate			$def = $1;
957*7c478bd9Sstevel@tonic-gate		}
958*7c478bd9Sstevel@tonic-gate	}
959*7c478bd9Sstevel@tonic-gate
960*7c478bd9Sstevel@tonic-gate	$is_system_library_cache{"$path_to_library|$abi"} = $def;
961*7c478bd9Sstevel@tonic-gate
962*7c478bd9Sstevel@tonic-gate	return $def;
963*7c478bd9Sstevel@tonic-gate}
964*7c478bd9Sstevel@tonic-gate
965*7c478bd9Sstevel@tonic-gate#
966*7c478bd9Sstevel@tonic-gate# Loop over each object item in the working_dir.
967*7c478bd9Sstevel@tonic-gate#  - $dir will be each one of these object directories.
968*7c478bd9Sstevel@tonic-gate#  - $path_to_object will be the corresponding actual path
969*7c478bd9Sstevel@tonic-gate#    to the the binary to be checked.
970*7c478bd9Sstevel@tonic-gate# Output will usually be placed down in $dir, e.g. "$dir/check.foo"
971*7c478bd9Sstevel@tonic-gate#
972*7c478bd9Sstevel@tonic-gatesub perform_misc_checks
973*7c478bd9Sstevel@tonic-gate{
974*7c478bd9Sstevel@tonic-gate	my ($dir, $path_to_object);
975*7c478bd9Sstevel@tonic-gate
976*7c478bd9Sstevel@tonic-gate	if (! $misc_check_databases_loaded_ok) {
977*7c478bd9Sstevel@tonic-gate		#
978*7c478bd9Sstevel@tonic-gate		# The load was attempted in check_objects() There is no
979*7c478bd9Sstevel@tonic-gate		# point in continuing if that loading failed.
980*7c478bd9Sstevel@tonic-gate		#
981*7c478bd9Sstevel@tonic-gate		return;
982*7c478bd9Sstevel@tonic-gate	}
983*7c478bd9Sstevel@tonic-gate
984*7c478bd9Sstevel@tonic-gate	emsg("\n" . gettext(
985*7c478bd9Sstevel@tonic-gate	    "performing miscellaneous checks") . " ...\n\n");
986*7c478bd9Sstevel@tonic-gate
987*7c478bd9Sstevel@tonic-gate	while (defined($dir = next_dir_name())) {
988*7c478bd9Sstevel@tonic-gate
989*7c478bd9Sstevel@tonic-gate		# Map object output dir to actual path of the object:
990*7c478bd9Sstevel@tonic-gate		$path_to_object = dir_name_to_path($dir);
991*7c478bd9Sstevel@tonic-gate
992*7c478bd9Sstevel@tonic-gate		if (! -f $path_to_object) {
993*7c478bd9Sstevel@tonic-gate			exiter(nopathexist($path_to_object, $!));
994*7c478bd9Sstevel@tonic-gate		}
995*7c478bd9Sstevel@tonic-gate
996*7c478bd9Sstevel@tonic-gate		# Check it:
997*7c478bd9Sstevel@tonic-gate		misc_check($path_to_object, $dir);
998*7c478bd9Sstevel@tonic-gate	}
999*7c478bd9Sstevel@tonic-gate}
1000*7c478bd9Sstevel@tonic-gate
1001*7c478bd9Sstevel@tonic-gate#
1002*7c478bd9Sstevel@tonic-gate# Routine to perform the misc. checks on a given binary object.  Records
1003*7c478bd9Sstevel@tonic-gate# the findings in object's output directory.
1004*7c478bd9Sstevel@tonic-gate#
1005*7c478bd9Sstevel@tonic-gatesub misc_check
1006*7c478bd9Sstevel@tonic-gate{
1007*7c478bd9Sstevel@tonic-gate	my ($path_to_object, $dir) = @_;
1008*7c478bd9Sstevel@tonic-gate
1009*7c478bd9Sstevel@tonic-gate	# Load the entire dynamic profile for this object:
1010*7c478bd9Sstevel@tonic-gate
1011*7c478bd9Sstevel@tonic-gate	my (@profile, @profile_short, %direct_syms, $file);
1012*7c478bd9Sstevel@tonic-gate	my $tmp;
1013*7c478bd9Sstevel@tonic-gate
1014*7c478bd9Sstevel@tonic-gate	$file = "$dir/profile.dynamic";
1015*7c478bd9Sstevel@tonic-gate
1016*7c478bd9Sstevel@tonic-gate	my ($app, $caller, $lib, $base, $sym);
1017*7c478bd9Sstevel@tonic-gate	my ($libsymcaller, $cnt, %sawlib);
1018*7c478bd9Sstevel@tonic-gate	if (-f $file) {
1019*7c478bd9Sstevel@tonic-gate		my $prof_fh = do { local *FH; *FH };
1020*7c478bd9Sstevel@tonic-gate		if (! open($prof_fh, "<$file")) {
1021*7c478bd9Sstevel@tonic-gate			exiter(nofile($file, $!));
1022*7c478bd9Sstevel@tonic-gate		}
1023*7c478bd9Sstevel@tonic-gate		$cnt = 0;
1024*7c478bd9Sstevel@tonic-gate		while (<$prof_fh>) {
1025*7c478bd9Sstevel@tonic-gate			next if (/^\s*#/);
1026*7c478bd9Sstevel@tonic-gate			next if (/^\s*$/);
1027*7c478bd9Sstevel@tonic-gate			chomp;
1028*7c478bd9Sstevel@tonic-gate			($app, $caller, $lib, $sym) = split(/\|/, $_, 4);
1029*7c478bd9Sstevel@tonic-gate
1030*7c478bd9Sstevel@tonic-gate			# Skip the checking of special symbols:
1031*7c478bd9Sstevel@tonic-gate			next if (exists($skip_symbols{$sym}));
1032*7c478bd9Sstevel@tonic-gate
1033*7c478bd9Sstevel@tonic-gate			push(@profile, "$lib|$sym|$caller");
1034*7c478bd9Sstevel@tonic-gate
1035*7c478bd9Sstevel@tonic-gate			#
1036*7c478bd9Sstevel@tonic-gate			# We collect in @profile_short up to 10
1037*7c478bd9Sstevel@tonic-gate			# lib-sym-caller triples where all the libs are
1038*7c478bd9Sstevel@tonic-gate			# distinct.  This is used to speed up some
1039*7c478bd9Sstevel@tonic-gate			# loops over the profile below: when we catch
1040*7c478bd9Sstevel@tonic-gate			# the lib-matching checks early in the loop we
1041*7c478bd9Sstevel@tonic-gate			# can exclude those checks from the remainder
1042*7c478bd9Sstevel@tonic-gate			# of the loop.  Since a profile may involve
1043*7c478bd9Sstevel@tonic-gate			# 1000's of symbols this can be a savings.
1044*7c478bd9Sstevel@tonic-gate			#
1045*7c478bd9Sstevel@tonic-gate			if ($cnt < 10 && ! exists($sawlib{$lib})) {
1046*7c478bd9Sstevel@tonic-gate				push(@profile_short, "$lib|$sym|$caller");
1047*7c478bd9Sstevel@tonic-gate				$sawlib{$lib} = 1;
1048*7c478bd9Sstevel@tonic-gate				$cnt++;
1049*7c478bd9Sstevel@tonic-gate			}
1050*7c478bd9Sstevel@tonic-gate		}
1051*7c478bd9Sstevel@tonic-gate		close($prof_fh);
1052*7c478bd9Sstevel@tonic-gate	}
1053*7c478bd9Sstevel@tonic-gate	#
1054*7c478bd9Sstevel@tonic-gate	# Misc Check #1:
1055*7c478bd9Sstevel@tonic-gate	# Go through dynamic profile looking for scoped local symbols:
1056*7c478bd9Sstevel@tonic-gate	#
1057*7c478bd9Sstevel@tonic-gate
1058*7c478bd9Sstevel@tonic-gate	my (%all_neededs, %lib_not_found);
1059*7c478bd9Sstevel@tonic-gate	my ($scoped_list, $scoped_msg);
1060*7c478bd9Sstevel@tonic-gate	my ($sc_rel, $sc_lib, $sc_sym, $sc_val);
1061*7c478bd9Sstevel@tonic-gate
1062*7c478bd9Sstevel@tonic-gate	%all_neededs = all_ldd_neededs($path_to_object);
1063*7c478bd9Sstevel@tonic-gate	my ($key, $key_trim);
1064*7c478bd9Sstevel@tonic-gate	foreach $key (keys(%all_neededs)) {
1065*7c478bd9Sstevel@tonic-gate		$key_trim = basename($key);
1066*7c478bd9Sstevel@tonic-gate		$all_neededs{$key_trim} = $all_neededs{$key};
1067*7c478bd9Sstevel@tonic-gate		if ($all_neededs{$key} =~ /file not found/) {
1068*7c478bd9Sstevel@tonic-gate			# %lib_not_found will be used below in check #2
1069*7c478bd9Sstevel@tonic-gate			$lib_not_found{$key}++;
1070*7c478bd9Sstevel@tonic-gate			$lib_not_found{$key_trim}++;
1071*7c478bd9Sstevel@tonic-gate		}
1072*7c478bd9Sstevel@tonic-gate	}
1073*7c478bd9Sstevel@tonic-gate
1074*7c478bd9Sstevel@tonic-gate	# We will need the abi of the object:
1075*7c478bd9Sstevel@tonic-gate	my $abi;
1076*7c478bd9Sstevel@tonic-gate	($abi) = bin_type($path_to_object);
1077*7c478bd9Sstevel@tonic-gate	if ($abi eq '' || ($abi =~ /^(unknown|any)$/)) {
1078*7c478bd9Sstevel@tonic-gate		if ($uname_p =~ /sparc/i) {
1079*7c478bd9Sstevel@tonic-gate			$abi = 'sparc';
1080*7c478bd9Sstevel@tonic-gate		} else {
1081*7c478bd9Sstevel@tonic-gate			$abi = 'i386';
1082*7c478bd9Sstevel@tonic-gate		}
1083*7c478bd9Sstevel@tonic-gate	}
1084*7c478bd9Sstevel@tonic-gate
1085*7c478bd9Sstevel@tonic-gate	foreach $libsymcaller (@profile) {
1086*7c478bd9Sstevel@tonic-gate		next unless ($libsymcaller =~ /\*DIRECT\*$/);
1087*7c478bd9Sstevel@tonic-gate
1088*7c478bd9Sstevel@tonic-gate		($lib, $sym, $caller) = split(/\|/, $libsymcaller, 3);
1089*7c478bd9Sstevel@tonic-gate
1090*7c478bd9Sstevel@tonic-gate		#
1091*7c478bd9Sstevel@tonic-gate		# Record direct symbols to improve our %wskip list used
1092*7c478bd9Sstevel@tonic-gate		# to speed up loops over symbols.
1093*7c478bd9Sstevel@tonic-gate		#
1094*7c478bd9Sstevel@tonic-gate		$direct_syms{$sym} = 1;
1095*7c478bd9Sstevel@tonic-gate		next unless (exists($scoped_symbol_all{$sym}));
1096*7c478bd9Sstevel@tonic-gate
1097*7c478bd9Sstevel@tonic-gate		$base = basename($lib);
1098*7c478bd9Sstevel@tonic-gate
1099*7c478bd9Sstevel@tonic-gate		#
1100*7c478bd9Sstevel@tonic-gate		# We only worry if a scoped call is a direct one.  This
1101*7c478bd9Sstevel@tonic-gate		# assumes the user's support shared objects are also
1102*7c478bd9Sstevel@tonic-gate		# checked by appcert.
1103*7c478bd9Sstevel@tonic-gate		#
1104*7c478bd9Sstevel@tonic-gate
1105*7c478bd9Sstevel@tonic-gate		if (exists($scoped_symbol{"$lib|$sym"}) ||
1106*7c478bd9Sstevel@tonic-gate		    exists($scoped_symbol{"$base|$sym"})) {
1107*7c478bd9Sstevel@tonic-gate			#
1108*7c478bd9Sstevel@tonic-gate			# This one is for checking on releases BEFORE
1109*7c478bd9Sstevel@tonic-gate			# the scoping actually occurred.
1110*7c478bd9Sstevel@tonic-gate			#
1111*7c478bd9Sstevel@tonic-gate			$scoped_msg  .= "$base:$sym ";
1112*7c478bd9Sstevel@tonic-gate			$scoped_list .= "$path_to_object|$caller|$lib|$sym\n";
1113*7c478bd9Sstevel@tonic-gate
1114*7c478bd9Sstevel@tonic-gate		} elsif ($lib eq '*UNBOUND*' &&
1115*7c478bd9Sstevel@tonic-gate		    exists($scoped_symbol_all{$sym})) {
1116*7c478bd9Sstevel@tonic-gate			#
1117*7c478bd9Sstevel@tonic-gate			# This one is for checking on releases AFTER the
1118*7c478bd9Sstevel@tonic-gate			# scoping.
1119*7c478bd9Sstevel@tonic-gate			#
1120*7c478bd9Sstevel@tonic-gate			# Assume these type of unbounds are deprecated
1121*7c478bd9Sstevel@tonic-gate			# if found in scoped_symbol_all. Double check it
1122*7c478bd9Sstevel@tonic-gate			# is in the all-needed-libs though:
1123*7c478bd9Sstevel@tonic-gate			#
1124*7c478bd9Sstevel@tonic-gate
1125*7c478bd9Sstevel@tonic-gate			if (defined($sc_sym) &&
1126*7c478bd9Sstevel@tonic-gate			    exists($model{"$LIBC|$abi|$sc_sym"})) {
1127*7c478bd9Sstevel@tonic-gate				next;
1128*7c478bd9Sstevel@tonic-gate			}
1129*7c478bd9Sstevel@tonic-gate
1130*7c478bd9Sstevel@tonic-gate			foreach $sc_val (split(/,/, $scoped_symbol_all{$sym})) {
1131*7c478bd9Sstevel@tonic-gate				($sc_rel, $sc_lib, $sc_sym) =
1132*7c478bd9Sstevel@tonic-gate				    split(/\|/, $sc_val);
1133*7c478bd9Sstevel@tonic-gate
1134*7c478bd9Sstevel@tonic-gate				#
1135*7c478bd9Sstevel@tonic-gate				# The general scoping that occurred for
1136*7c478bd9Sstevel@tonic-gate				# ld.so.1 makes the current heuristic
1137*7c478bd9Sstevel@tonic-gate				# somewhat less accurate. Unboundedness
1138*7c478bd9Sstevel@tonic-gate				# from other means has too good a chance
1139*7c478bd9Sstevel@tonic-gate				# of overlapping with the ld.so.1
1140*7c478bd9Sstevel@tonic-gate				# scoping. Note that the app likely does
1141*7c478bd9Sstevel@tonic-gate				# NOT have ld.so.1 in its neededs, but
1142*7c478bd9Sstevel@tonic-gate				# we still skip this case.
1143*7c478bd9Sstevel@tonic-gate				#
1144*7c478bd9Sstevel@tonic-gate
1145*7c478bd9Sstevel@tonic-gate				next if ($sc_lib eq 'ld.so.1');
1146*7c478bd9Sstevel@tonic-gate
1147*7c478bd9Sstevel@tonic-gate				if ($all_neededs{$sc_lib}) {
1148*7c478bd9Sstevel@tonic-gate					# note that $lib is '*UNBOUND*'
1149*7c478bd9Sstevel@tonic-gate					$scoped_msg  .= "<unbound>:$sym ";
1150*7c478bd9Sstevel@tonic-gate					$scoped_list .=
1151*7c478bd9Sstevel@tonic-gate					"$path_to_object|$caller|$lib|$sym\n";
1152*7c478bd9Sstevel@tonic-gate				}
1153*7c478bd9Sstevel@tonic-gate			}
1154*7c478bd9Sstevel@tonic-gate		}
1155*7c478bd9Sstevel@tonic-gate	}
1156*7c478bd9Sstevel@tonic-gate
1157*7c478bd9Sstevel@tonic-gate	if (defined($scoped_msg)) {
1158*7c478bd9Sstevel@tonic-gate		my $problems = "$dir/check.problems";
1159*7c478bd9Sstevel@tonic-gate
1160*7c478bd9Sstevel@tonic-gate		# problems will be appended to the file:
1161*7c478bd9Sstevel@tonic-gate		my $problems_fh = do { local *FH; *FH };
1162*7c478bd9Sstevel@tonic-gate		if (! open($problems_fh, ">>$problems")) {
1163*7c478bd9Sstevel@tonic-gate			exiter(nofile($problems, $!));
1164*7c478bd9Sstevel@tonic-gate		}
1165*7c478bd9Sstevel@tonic-gate		print $problems_fh
1166*7c478bd9Sstevel@tonic-gate		    "MISC: REMOVED_SCOPED_SYMBOLS: $scoped_msg\n";
1167*7c478bd9Sstevel@tonic-gate		close($problems_fh);
1168*7c478bd9Sstevel@tonic-gate
1169*7c478bd9Sstevel@tonic-gate		$problems = "$dir/check.demoted_symbols";
1170*7c478bd9Sstevel@tonic-gate
1171*7c478bd9Sstevel@tonic-gate		# problems will be appended to the file:
1172*7c478bd9Sstevel@tonic-gate		my $check_fh = do { local *FH; *FH };
1173*7c478bd9Sstevel@tonic-gate		if (! open($check_fh, ">>$problems")) {
1174*7c478bd9Sstevel@tonic-gate			exiter(nofile($problems, $!));
1175*7c478bd9Sstevel@tonic-gate		}
1176*7c478bd9Sstevel@tonic-gate		print $check_fh $scoped_list;
1177*7c478bd9Sstevel@tonic-gate		close($check_fh);
1178*7c478bd9Sstevel@tonic-gate	}
1179*7c478bd9Sstevel@tonic-gate
1180*7c478bd9Sstevel@tonic-gate	#
1181*7c478bd9Sstevel@tonic-gate	# Misc Check #2
1182*7c478bd9Sstevel@tonic-gate	# Go through dynamic profile looking for special warnings.
1183*7c478bd9Sstevel@tonic-gate	#
1184*7c478bd9Sstevel@tonic-gate
1185*7c478bd9Sstevel@tonic-gate	my (%warnings, %wskip);
1186*7c478bd9Sstevel@tonic-gate	my (%lib_star, %sym_star, %caller_star);
1187*7c478bd9Sstevel@tonic-gate	my ($tag, $tag0, $sub, $res);
1188*7c478bd9Sstevel@tonic-gate
1189*7c478bd9Sstevel@tonic-gate	while (($tag, $sub) = each(%warnings_match)) {
1190*7c478bd9Sstevel@tonic-gate		next if (! $sub);
1191*7c478bd9Sstevel@tonic-gate
1192*7c478bd9Sstevel@tonic-gate		$res = &{$sub}($path_to_object);
1193*7c478bd9Sstevel@tonic-gate		$warnings{$tag} = 1 if ($res);
1194*7c478bd9Sstevel@tonic-gate	}
1195*7c478bd9Sstevel@tonic-gate
1196*7c478bd9Sstevel@tonic-gate	my $warnings_bind_has_non_direct = 0;
1197*7c478bd9Sstevel@tonic-gate
1198*7c478bd9Sstevel@tonic-gate	while (($tag0, $tmp) =  each(%warnings_bind)) {
1199*7c478bd9Sstevel@tonic-gate		($lib, $sym, $caller) = split(/\|/, $tmp, 3);
1200*7c478bd9Sstevel@tonic-gate		$lib_star{$tag0}	= 1 if ($lib eq '*');
1201*7c478bd9Sstevel@tonic-gate		$sym_star{$tag0}	= 1 if ($sym eq '*');
1202*7c478bd9Sstevel@tonic-gate		$caller_star{$tag0}	= 1 if ($caller eq '*');
1203*7c478bd9Sstevel@tonic-gate		if ($lib ne '*' && $lib !~ m,/, && ! $all_neededs{$lib}) {
1204*7c478bd9Sstevel@tonic-gate			# it can never match:
1205*7c478bd9Sstevel@tonic-gate			$wskip{$tag0} = 1;
1206*7c478bd9Sstevel@tonic-gate		}
1207*7c478bd9Sstevel@tonic-gate		if ($caller ne '*DIRECT*') {
1208*7c478bd9Sstevel@tonic-gate			# this will be used to speed up the *DIRECT* only case:
1209*7c478bd9Sstevel@tonic-gate			$warnings_bind_has_non_direct = 1;
1210*7c478bd9Sstevel@tonic-gate		} elsif ($sym ne '*' && ! $direct_syms{$sym}) {
1211*7c478bd9Sstevel@tonic-gate			# it can never match:
1212*7c478bd9Sstevel@tonic-gate			$wskip{$tag0} = 1;
1213*7c478bd9Sstevel@tonic-gate		}
1214*7c478bd9Sstevel@tonic-gate	}
1215*7c478bd9Sstevel@tonic-gate
1216*7c478bd9Sstevel@tonic-gate	foreach $lib (keys(%lib_not_found)) {
1217*7c478bd9Sstevel@tonic-gate		#
1218*7c478bd9Sstevel@tonic-gate		# add a placeholder symbol in %profile to indicate
1219*7c478bd9Sstevel@tonic-gate		# $lib is on dtneeded, but wasn't found. This will
1220*7c478bd9Sstevel@tonic-gate		# match a $sym = '*' warnings_bind misc check:
1221*7c478bd9Sstevel@tonic-gate		#
1222*7c478bd9Sstevel@tonic-gate		push(@profile,
1223*7c478bd9Sstevel@tonic-gate		    "$lib|__ldd_indicated_file_not_found__|*DIRECT*");
1224*7c478bd9Sstevel@tonic-gate	}
1225*7c478bd9Sstevel@tonic-gate
1226*7c478bd9Sstevel@tonic-gate	my ($l_t, $s_t, $c_t, $match_t);
1227*7c478bd9Sstevel@tonic-gate
1228*7c478bd9Sstevel@tonic-gate	my (@tag_list, @tag_list2, $new_tags);
1229*7c478bd9Sstevel@tonic-gate	#
1230*7c478bd9Sstevel@tonic-gate	# create a list of tags excluding the ones we know will be
1231*7c478bd9Sstevel@tonic-gate	# skipped in the $libsymcaller loop below.
1232*7c478bd9Sstevel@tonic-gate	#
1233*7c478bd9Sstevel@tonic-gate	foreach $tag0 (keys(%warnings_bind)) {
1234*7c478bd9Sstevel@tonic-gate		next if ($wskip{$tag0});
1235*7c478bd9Sstevel@tonic-gate		push(@tag_list, $tag0);
1236*7c478bd9Sstevel@tonic-gate	}
1237*7c478bd9Sstevel@tonic-gate
1238*7c478bd9Sstevel@tonic-gate	#
1239*7c478bd9Sstevel@tonic-gate	# we loop over @profile_short first, these will give us up to
1240*7c478bd9Sstevel@tonic-gate	# 10 different libraries early to help us shrink @tag_list
1241*7c478bd9Sstevel@tonic-gate	# as we go through the profile.
1242*7c478bd9Sstevel@tonic-gate	#
1243*7c478bd9Sstevel@tonic-gate	foreach $libsymcaller (@profile_short, @profile) {
1244*7c478bd9Sstevel@tonic-gate		@tag_list = @tag_list2 if ($new_tags);
1245*7c478bd9Sstevel@tonic-gate		last if (! @tag_list);
1246*7c478bd9Sstevel@tonic-gate
1247*7c478bd9Sstevel@tonic-gate		($lib, $sym, $caller) = split(/\|/, $libsymcaller, 3);
1248*7c478bd9Sstevel@tonic-gate
1249*7c478bd9Sstevel@tonic-gate		if (! $warnings_bind_has_non_direct && $caller ne '*DIRECT*') {
1250*7c478bd9Sstevel@tonic-gate			next;
1251*7c478bd9Sstevel@tonic-gate		}
1252*7c478bd9Sstevel@tonic-gate
1253*7c478bd9Sstevel@tonic-gate		$base = basename($lib);
1254*7c478bd9Sstevel@tonic-gate		$new_tags = 0;
1255*7c478bd9Sstevel@tonic-gate
1256*7c478bd9Sstevel@tonic-gate		foreach $tag0 (@tag_list) {
1257*7c478bd9Sstevel@tonic-gate
1258*7c478bd9Sstevel@tonic-gate			# try to get out early:
1259*7c478bd9Sstevel@tonic-gate			next if ($wskip{$tag0});
1260*7c478bd9Sstevel@tonic-gate
1261*7c478bd9Sstevel@tonic-gate			($tag, $tmp) = split(/\|/, $tag0, 2);
1262*7c478bd9Sstevel@tonic-gate			# try to get out early:
1263*7c478bd9Sstevel@tonic-gate			next if ($warnings{$tag});
1264*7c478bd9Sstevel@tonic-gate
1265*7c478bd9Sstevel@tonic-gate			$match_t = $warnings_bind{$tag0};
1266*7c478bd9Sstevel@tonic-gate
1267*7c478bd9Sstevel@tonic-gate			$l_t = $lib;
1268*7c478bd9Sstevel@tonic-gate			$s_t = $sym;
1269*7c478bd9Sstevel@tonic-gate			$c_t = $caller;
1270*7c478bd9Sstevel@tonic-gate
1271*7c478bd9Sstevel@tonic-gate			$l_t = '*' if ($lib_star{$tag0});
1272*7c478bd9Sstevel@tonic-gate			$s_t = '*' if ($sym_star{$tag0});
1273*7c478bd9Sstevel@tonic-gate			$c_t = '*' if ($caller_star{$tag0});
1274*7c478bd9Sstevel@tonic-gate
1275*7c478bd9Sstevel@tonic-gate			if ("$l_t|$s_t|$c_t" eq $match_t ||
1276*7c478bd9Sstevel@tonic-gate			    "$base|$s_t|$c_t" eq $match_t) {
1277*7c478bd9Sstevel@tonic-gate				$warnings{$tag} = 1;
1278*7c478bd9Sstevel@tonic-gate				$wskip{$tag0} = 1;
1279*7c478bd9Sstevel@tonic-gate
1280*7c478bd9Sstevel@tonic-gate				# shorten tag list:
1281*7c478bd9Sstevel@tonic-gate				my (@t, $tg, $tg2, $tp);
1282*7c478bd9Sstevel@tonic-gate				foreach $tg (@tag_list) {
1283*7c478bd9Sstevel@tonic-gate					next if ($tg eq $tag0);
1284*7c478bd9Sstevel@tonic-gate					($tg2, $tp) = split(/\|/, $tg, 2);
1285*7c478bd9Sstevel@tonic-gate					next if ($tg2 eq $tag);
1286*7c478bd9Sstevel@tonic-gate					push(@t, $tg);
1287*7c478bd9Sstevel@tonic-gate				}
1288*7c478bd9Sstevel@tonic-gate				@tag_list2 = @t;
1289*7c478bd9Sstevel@tonic-gate				$new_tags = 1;
1290*7c478bd9Sstevel@tonic-gate			}
1291*7c478bd9Sstevel@tonic-gate		}
1292*7c478bd9Sstevel@tonic-gate	}
1293*7c478bd9Sstevel@tonic-gate
1294*7c478bd9Sstevel@tonic-gate	if (%warnings) {
1295*7c478bd9Sstevel@tonic-gate		my $problems = "$dir/check.problems";
1296*7c478bd9Sstevel@tonic-gate
1297*7c478bd9Sstevel@tonic-gate		# append problems to the file:
1298*7c478bd9Sstevel@tonic-gate		my $problems_fh = do { local *FH; *FH };
1299*7c478bd9Sstevel@tonic-gate		if (! open($problems_fh, ">>$problems")) {
1300*7c478bd9Sstevel@tonic-gate			exiter(nofile($problems, $!));
1301*7c478bd9Sstevel@tonic-gate		}
1302*7c478bd9Sstevel@tonic-gate
1303*7c478bd9Sstevel@tonic-gate		my $tag;
1304*7c478bd9Sstevel@tonic-gate		foreach $tag (keys(%warnings)) {
1305*7c478bd9Sstevel@tonic-gate			print $problems_fh "MISC: WARNING: $tag\n";
1306*7c478bd9Sstevel@tonic-gate		}
1307*7c478bd9Sstevel@tonic-gate		close($problems_fh);
1308*7c478bd9Sstevel@tonic-gate	}
1309*7c478bd9Sstevel@tonic-gate}
1310