xref: /onnv-gate/usr/src/cmd/abi/appcert/scripts/symreport.pl (revision 0:68f95e015346)
1*0Sstevel@tonic-gate#!/usr/perl5/bin/perl -w
2*0Sstevel@tonic-gate#
3*0Sstevel@tonic-gate# CDDL HEADER START
4*0Sstevel@tonic-gate#
5*0Sstevel@tonic-gate# The contents of this file are subject to the terms of the
6*0Sstevel@tonic-gate# Common Development and Distribution License, Version 1.0 only
7*0Sstevel@tonic-gate# (the "License").  You may not use this file except in compliance
8*0Sstevel@tonic-gate# with the License.
9*0Sstevel@tonic-gate#
10*0Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11*0Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing.
12*0Sstevel@tonic-gate# See the License for the specific language governing permissions
13*0Sstevel@tonic-gate# and limitations under the License.
14*0Sstevel@tonic-gate#
15*0Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each
16*0Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17*0Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the
18*0Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying
19*0Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner]
20*0Sstevel@tonic-gate#
21*0Sstevel@tonic-gate# CDDL HEADER END
22*0Sstevel@tonic-gate#
23*0Sstevel@tonic-gate#
24*0Sstevel@tonic-gate# Copyright (c) 1996-2000 by Sun Microsystems, Inc.
25*0Sstevel@tonic-gate# All rights reserved.
26*0Sstevel@tonic-gate#
27*0Sstevel@tonic-gate#ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate#
29*0Sstevel@tonic-gate
30*0Sstevel@tonic-gate#
31*0Sstevel@tonic-gate# This utility program reads the symcheck output of each binary and
32*0Sstevel@tonic-gate# creates additional output for then and an overall report.
33*0Sstevel@tonic-gate#
34*0Sstevel@tonic-gate
35*0Sstevel@tonic-gaterequire 5.005;
36*0Sstevel@tonic-gateuse strict;
37*0Sstevel@tonic-gateuse locale;
38*0Sstevel@tonic-gateuse POSIX qw(locale_h);
39*0Sstevel@tonic-gateuse Sun::Solaris::Utils qw(textdomain gettext);
40*0Sstevel@tonic-gateuse File::Basename;
41*0Sstevel@tonic-gateuse File::Path;
42*0Sstevel@tonic-gate
43*0Sstevel@tonic-gateuse lib qw(/usr/lib/abi/appcert);
44*0Sstevel@tonic-gateuse AppcertUtil;
45*0Sstevel@tonic-gate
46*0Sstevel@tonic-gatesetlocale(LC_ALL, "");
47*0Sstevel@tonic-gatetextdomain(TEXT_DOMAIN);
48*0Sstevel@tonic-gate
49*0Sstevel@tonic-gateuse vars qw(
50*0Sstevel@tonic-gate	$tmp_report_dir
51*0Sstevel@tonic-gate	$misc_check_databases_loaded_ok
52*0Sstevel@tonic-gate	%result_list_hash
53*0Sstevel@tonic-gate	%result_msg
54*0Sstevel@tonic-gate	%warnings_found
55*0Sstevel@tonic-gate);
56*0Sstevel@tonic-gate
57*0Sstevel@tonic-gateset_clean_up_exit_routine(\&clean_up_exit);
58*0Sstevel@tonic-gate
59*0Sstevel@tonic-gateimport_vars_from_environment();
60*0Sstevel@tonic-gate
61*0Sstevel@tonic-gatesignals('on', \&interrupted);
62*0Sstevel@tonic-gate
63*0Sstevel@tonic-gateset_working_dir();
64*0Sstevel@tonic-gate
65*0Sstevel@tonic-gategenerate_reports();
66*0Sstevel@tonic-gate
67*0Sstevel@tonic-gateclean_up();
68*0Sstevel@tonic-gate
69*0Sstevel@tonic-gateexit 0;
70*0Sstevel@tonic-gate
71*0Sstevel@tonic-gate#
72*0Sstevel@tonic-gate# working_dir has been imported by import_vars_from_environment()
73*0Sstevel@tonic-gate# A sanity check is performed here to make sure it exists.
74*0Sstevel@tonic-gate#
75*0Sstevel@tonic-gatesub set_working_dir
76*0Sstevel@tonic-gate{
77*0Sstevel@tonic-gate	if (! defined($working_dir) || ! -d $working_dir) {
78*0Sstevel@tonic-gate		exiter("$command_name: " . sprintf(gettext(
79*0Sstevel@tonic-gate		    "cannot locate working directory: %s\n"), $working_dir));
80*0Sstevel@tonic-gate	}
81*0Sstevel@tonic-gate}
82*0Sstevel@tonic-gate
83*0Sstevel@tonic-gate#
84*0Sstevel@tonic-gate# Called when interrupted by user.
85*0Sstevel@tonic-gate#
86*0Sstevel@tonic-gatesub interrupted
87*0Sstevel@tonic-gate{
88*0Sstevel@tonic-gate	$SIG{$_[0]} = 'DEFAULT';
89*0Sstevel@tonic-gate	signals('off');
90*0Sstevel@tonic-gate	clean_up_exit(1);
91*0Sstevel@tonic-gate}
92*0Sstevel@tonic-gate
93*0Sstevel@tonic-gate#
94*0Sstevel@tonic-gate# Does the cleanup and then exit with return code $rc.  Note: The
95*0Sstevel@tonic-gate# utility routine exiter() will call this routine.
96*0Sstevel@tonic-gate#
97*0Sstevel@tonic-gatesub clean_up_exit
98*0Sstevel@tonic-gate{
99*0Sstevel@tonic-gate	my ($rc) = @_;
100*0Sstevel@tonic-gate	$rc = 0 unless ($rc);
101*0Sstevel@tonic-gate
102*0Sstevel@tonic-gate	clean_up();
103*0Sstevel@tonic-gate	exit $rc;
104*0Sstevel@tonic-gate}
105*0Sstevel@tonic-gate
106*0Sstevel@tonic-gate#
107*0Sstevel@tonic-gate# General cleanup activities are placed here. There may not be an
108*0Sstevel@tonic-gate# immediate exit after this cleanup.
109*0Sstevel@tonic-gate#
110*0Sstevel@tonic-gatesub clean_up
111*0Sstevel@tonic-gate{
112*0Sstevel@tonic-gate	if (defined($tmp_report_dir) && -d $tmp_report_dir) {
113*0Sstevel@tonic-gate		rmtree($tmp_report_dir);
114*0Sstevel@tonic-gate	}
115*0Sstevel@tonic-gate}
116*0Sstevel@tonic-gate
117*0Sstevel@tonic-gate#
118*0Sstevel@tonic-gate# Top level routine for generating the additional reports.
119*0Sstevel@tonic-gate#
120*0Sstevel@tonic-gatesub generate_reports
121*0Sstevel@tonic-gate{
122*0Sstevel@tonic-gate	# Make a tmp dir for the reporting work.
123*0Sstevel@tonic-gate	$tmp_report_dir = create_tmp_dir($tmp_dir);
124*0Sstevel@tonic-gate
125*0Sstevel@tonic-gate	if (! -d $tmp_report_dir) {
126*0Sstevel@tonic-gate		exiter(nocreatedir($tmp_report_dir, $!));
127*0Sstevel@tonic-gate	}
128*0Sstevel@tonic-gate
129*0Sstevel@tonic-gate	pmsg("\n");
130*0Sstevel@tonic-gate	print_line();
131*0Sstevel@tonic-gate
132*0Sstevel@tonic-gate	my ($dir, $path_to_object);
133*0Sstevel@tonic-gate
134*0Sstevel@tonic-gate	#
135*0Sstevel@tonic-gate	# Loop over each object item in the working_dir.
136*0Sstevel@tonic-gate	#  - $dir will be each one of these object directories.
137*0Sstevel@tonic-gate	#  - $path_to_object will be the corresponding actual path
138*0Sstevel@tonic-gate	#    to the the binary to be profiled.
139*0Sstevel@tonic-gate	# Output will be placed down in $dir, e.g. "$dir/report"
140*0Sstevel@tonic-gate	#
141*0Sstevel@tonic-gate
142*0Sstevel@tonic-gate	while (defined($dir = next_dir_name())) {
143*0Sstevel@tonic-gate
144*0Sstevel@tonic-gate		# Map object output dir to actual path of the object:
145*0Sstevel@tonic-gate		$path_to_object = dir_name_to_path($dir);
146*0Sstevel@tonic-gate
147*0Sstevel@tonic-gate		# Make a report for it:
148*0Sstevel@tonic-gate		report_object($path_to_object, $dir);
149*0Sstevel@tonic-gate	}
150*0Sstevel@tonic-gate
151*0Sstevel@tonic-gate	my $type;
152*0Sstevel@tonic-gate	foreach $type (keys(%result_list_hash)) {
153*0Sstevel@tonic-gate		$result_list_hash{$type} =~ s/\|+$//;
154*0Sstevel@tonic-gate	}
155*0Sstevel@tonic-gate
156*0Sstevel@tonic-gate	print_report();
157*0Sstevel@tonic-gate	my $tout;
158*0Sstevel@tonic-gate	$tout = gettext(
159*0Sstevel@tonic-gate	    "Additional output regarding private symbols usage and other\n" .
160*0Sstevel@tonic-gate	    "data is in the directory:\n");
161*0Sstevel@tonic-gate
162*0Sstevel@tonic-gate	$tout .= "\n   $working_dir\n\n";
163*0Sstevel@tonic-gate
164*0Sstevel@tonic-gate	$tout .= gettext(
165*0Sstevel@tonic-gate	    "see the appcert documentation for more information.\n");
166*0Sstevel@tonic-gate
167*0Sstevel@tonic-gate	pmsg("%s", $tout);
168*0Sstevel@tonic-gate
169*0Sstevel@tonic-gate	clean_up();	# Remove any tmp directories and files.
170*0Sstevel@tonic-gate}
171*0Sstevel@tonic-gate
172*0Sstevel@tonic-gate#
173*0Sstevel@tonic-gate# Examines the symcheck output for a given binary object recording and
174*0Sstevel@tonic-gate# reporting and problems found.  Generates additional reports and
175*0Sstevel@tonic-gate# summaries.
176*0Sstevel@tonic-gate#
177*0Sstevel@tonic-gatesub report_object
178*0Sstevel@tonic-gate{
179*0Sstevel@tonic-gate	my ($object, $dir) = @_;
180*0Sstevel@tonic-gate
181*0Sstevel@tonic-gate	my (%problems);
182*0Sstevel@tonic-gate
183*0Sstevel@tonic-gate	my $problems_file = "$dir/check.problems";
184*0Sstevel@tonic-gate
185*0Sstevel@tonic-gate	my $problems_fh = do { local *FH; *FH };
186*0Sstevel@tonic-gate	open($problems_fh, "<$problems_file") ||
187*0Sstevel@tonic-gate	    exiter(nofile($problems_file, $!));
188*0Sstevel@tonic-gate
189*0Sstevel@tonic-gate	# We need the "warning" msgs and text from the Misc Checks loaded:
190*0Sstevel@tonic-gate	if (! defined($misc_check_databases_loaded_ok)) {
191*0Sstevel@tonic-gate		$misc_check_databases_loaded_ok = load_misc_check_databases();
192*0Sstevel@tonic-gate	}
193*0Sstevel@tonic-gate
194*0Sstevel@tonic-gate	my ($prob, $incomp, $c, $w);
195*0Sstevel@tonic-gate	my $problem_count = 0;
196*0Sstevel@tonic-gate	my $incomplete_count = 0;
197*0Sstevel@tonic-gate	my $line_count = 0;
198*0Sstevel@tonic-gate
199*0Sstevel@tonic-gate	while (<$problems_fh>) {
200*0Sstevel@tonic-gate		chomp;
201*0Sstevel@tonic-gate		$prob = 1;
202*0Sstevel@tonic-gate		$incomp = 0;
203*0Sstevel@tonic-gate		$line_count++;
204*0Sstevel@tonic-gate
205*0Sstevel@tonic-gate		if (/^DYNAMIC: PRIVATE_SYMBOL_USE\s+(\d*)/) {
206*0Sstevel@tonic-gate			$problems{'private_syms'} += $1;
207*0Sstevel@tonic-gate		} elsif (/^DYNAMIC: UNBOUND_SYMBOL_USE\s+(\d*)/) {
208*0Sstevel@tonic-gate			$problems{'unbound_syms'} += $1;
209*0Sstevel@tonic-gate			$incomp = 1;
210*0Sstevel@tonic-gate		} elsif (/^DYNAMIC: UNRECOGNIZED_SYMBOL_USE\s+(\d*)/) {
211*0Sstevel@tonic-gate			$problems{'unrecognized_syms'} += $1;
212*0Sstevel@tonic-gate			$incomp = 1;
213*0Sstevel@tonic-gate		} elsif (/^DYNAMIC: NO_DYNAMIC_BINDINGS_FOUND\s*(.*)$/) {
214*0Sstevel@tonic-gate			$problems{'no_dynamic_bindings'} .= "$1, ";
215*0Sstevel@tonic-gate			$incomp = 1;
216*0Sstevel@tonic-gate		} elsif (/^STATIC: LINKED_ARCHIVE\s+(.*)$/) {
217*0Sstevel@tonic-gate			$problems{'static_linking'} .= "$1, ";
218*0Sstevel@tonic-gate		} elsif (/^STATIC: COMPLETELY_STATIC/) {
219*0Sstevel@tonic-gate			$problems{'completely_static'}++;
220*0Sstevel@tonic-gate		} elsif (/^MISC: REMOVED_SCOPED_SYMBOLS:\s+(.*)$/) {
221*0Sstevel@tonic-gate			$problems{'scoped_symbols'} .= "$1, ";
222*0Sstevel@tonic-gate		} elsif (/^MISC: WARNING:\s+(INCOMPLETE\S+)/) {
223*0Sstevel@tonic-gate			$problems{'warnings'} .= "$1|";
224*0Sstevel@tonic-gate			$incomp = 1;
225*0Sstevel@tonic-gate		} elsif (/^MISC: WARNING:\s+(.*)$/) {
226*0Sstevel@tonic-gate			$problems{'warnings'} .= "$1|";
227*0Sstevel@tonic-gate		} else {
228*0Sstevel@tonic-gate			$prob = 0;
229*0Sstevel@tonic-gate		}
230*0Sstevel@tonic-gate		$problem_count += $prob;
231*0Sstevel@tonic-gate		$incomplete_count += $incomp;
232*0Sstevel@tonic-gate	}
233*0Sstevel@tonic-gate	close($problems_fh);
234*0Sstevel@tonic-gate
235*0Sstevel@tonic-gate	if ($line_count == 0) {
236*0Sstevel@tonic-gate		# No problems at all, leave a comment message:
237*0Sstevel@tonic-gate		open($problems_fh, ">$problems_file") ||
238*0Sstevel@tonic-gate		    exiter(nofile($problems_file, $!));
239*0Sstevel@tonic-gate		print $problems_fh "# NO_PROBLEMS_DETECTED\n";
240*0Sstevel@tonic-gate		close($problems_fh);
241*0Sstevel@tonic-gate	}
242*0Sstevel@tonic-gate
243*0Sstevel@tonic-gate	if ($problem_count == 0) {
244*0Sstevel@tonic-gate		$result_list_hash{'passed'} .= "$object|";
245*0Sstevel@tonic-gate		return;
246*0Sstevel@tonic-gate	}
247*0Sstevel@tonic-gate
248*0Sstevel@tonic-gate	if ($incomplete_count == $problem_count) {
249*0Sstevel@tonic-gate		$result_list_hash{'incomplete'} .= "$object|";
250*0Sstevel@tonic-gate	} else {
251*0Sstevel@tonic-gate		$result_list_hash{'failed'} .= "$object|";
252*0Sstevel@tonic-gate	}
253*0Sstevel@tonic-gate
254*0Sstevel@tonic-gate	my $m;
255*0Sstevel@tonic-gate
256*0Sstevel@tonic-gate	if ($m = $problems{'private_syms'}) {
257*0Sstevel@tonic-gate		$result_list_hash{'private_syms'} .= "$object|";
258*0Sstevel@tonic-gate		$result_msg{$object} .= "$m " .
259*0Sstevel@tonic-gate		    gettext("private symbols") . "; ";
260*0Sstevel@tonic-gate	}
261*0Sstevel@tonic-gate
262*0Sstevel@tonic-gate	if ($m = $problems{'unbound_syms'}) {
263*0Sstevel@tonic-gate		$result_list_hash{'unbound_syms'} .= "$object|";
264*0Sstevel@tonic-gate		$result_msg{$object} .= "$m " .
265*0Sstevel@tonic-gate		    gettext("unbound symbols") . "; ";
266*0Sstevel@tonic-gate
267*0Sstevel@tonic-gate		# add this case to the warnings output at end of report.
268*0Sstevel@tonic-gate		my $tag  = 'unbound symbols';
269*0Sstevel@tonic-gate		$warnings_found{$tag} .= "$object|";
270*0Sstevel@tonic-gate
271*0Sstevel@tonic-gate		if (! exists($warnings_desc{$tag})) {
272*0Sstevel@tonic-gate			my $desc = gettext("unbound symbols");
273*0Sstevel@tonic-gate			$warnings_desc{$tag} = $desc;
274*0Sstevel@tonic-gate		}
275*0Sstevel@tonic-gate	}
276*0Sstevel@tonic-gate
277*0Sstevel@tonic-gate	if ($m = $problems{'unrecognized_syms'}) {
278*0Sstevel@tonic-gate		$result_list_hash{'unrecognized_syms'} .= "$object|";
279*0Sstevel@tonic-gate		$result_msg{$object} .= "$m " .
280*0Sstevel@tonic-gate		    gettext("unrecognized symbols") . "; ";
281*0Sstevel@tonic-gate
282*0Sstevel@tonic-gate		# Add this case to the warnings output at end of report.
283*0Sstevel@tonic-gate		my $tag  = 'unrecognized symbols';
284*0Sstevel@tonic-gate		$warnings_found{$tag} .= "$object|";
285*0Sstevel@tonic-gate
286*0Sstevel@tonic-gate		if (! exists($warnings_desc{$tag})) {
287*0Sstevel@tonic-gate			my $desc = gettext("unrecognized symbols");
288*0Sstevel@tonic-gate			$warnings_desc{$tag} = $desc;
289*0Sstevel@tonic-gate		}
290*0Sstevel@tonic-gate	}
291*0Sstevel@tonic-gate
292*0Sstevel@tonic-gate	if ($m = $problems{'static_linking'}) {
293*0Sstevel@tonic-gate		$result_list_hash{'static_linking'} .= "$object|";
294*0Sstevel@tonic-gate		$m =~ s/,\s*$//;
295*0Sstevel@tonic-gate		$result_msg{$object} .= sprintf(gettext(
296*0Sstevel@tonic-gate		    "statically linked with %s"), $m) . "; ";
297*0Sstevel@tonic-gate
298*0Sstevel@tonic-gate		# Add this case to the warnings output at end of report.
299*0Sstevel@tonic-gate		my $tag  = 'statically linked';
300*0Sstevel@tonic-gate		$warnings_found{$tag} .= "$object|";
301*0Sstevel@tonic-gate
302*0Sstevel@tonic-gate		if (! exists($warnings_desc{$tag})) {
303*0Sstevel@tonic-gate			my $desc =
304*0Sstevel@tonic-gate			    gettext("static linking of Solaris libraries");
305*0Sstevel@tonic-gate			$warnings_desc{$tag} = $desc;
306*0Sstevel@tonic-gate		}
307*0Sstevel@tonic-gate	}
308*0Sstevel@tonic-gate
309*0Sstevel@tonic-gate	if ($problems{'completely_static'}) {
310*0Sstevel@tonic-gate		$result_list_hash{'completely_static'} .= "$object|";
311*0Sstevel@tonic-gate		$result_msg{$object} .=
312*0Sstevel@tonic-gate		    gettext("completely statically linked") . "; ";
313*0Sstevel@tonic-gate
314*0Sstevel@tonic-gate		# Add this case to the warnings output.
315*0Sstevel@tonic-gate		my $tag  = gettext("completely statically linked");
316*0Sstevel@tonic-gate		$warnings_found{$tag} .= "$object|";
317*0Sstevel@tonic-gate
318*0Sstevel@tonic-gate		my $desc =
319*0Sstevel@tonic-gate		    gettext("complete static linking of Solaris libraries");
320*0Sstevel@tonic-gate		if (! exists($warnings_desc{$tag})) {
321*0Sstevel@tonic-gate			$warnings_desc{$tag} = $desc;
322*0Sstevel@tonic-gate		}
323*0Sstevel@tonic-gate
324*0Sstevel@tonic-gate	} elsif ($m = $problems{'no_dynamic_bindings'}) {
325*0Sstevel@tonic-gate		#
326*0Sstevel@tonic-gate		# Note we skip this error if it is completely static.
327*0Sstevel@tonic-gate		# The app could technically be SUID as well.
328*0Sstevel@tonic-gate		#
329*0Sstevel@tonic-gate
330*0Sstevel@tonic-gate		$result_list_hash{'no_dynamic_bindings'} .= "$object|";
331*0Sstevel@tonic-gate		$m =~ s/,\s*$//;
332*0Sstevel@tonic-gate		$m = " : $m";
333*0Sstevel@tonic-gate		$m =~ s/ : NO_SYMBOL_BINDINGS_FOUND//;
334*0Sstevel@tonic-gate		$m =~ s/^ :/:/;
335*0Sstevel@tonic-gate		$result_msg{$object} .=
336*0Sstevel@tonic-gate		    gettext("no bindings found") . "$m; ";
337*0Sstevel@tonic-gate	}
338*0Sstevel@tonic-gate
339*0Sstevel@tonic-gate	if ($m = $problems{'scoped_symbols'}) {
340*0Sstevel@tonic-gate		$m =~ s/[,\s]*$//;
341*0Sstevel@tonic-gate		$result_list_hash{'scoped_symbols'} .= "$object|";
342*0Sstevel@tonic-gate		$c = scalar(my @a = split(' ', $m));
343*0Sstevel@tonic-gate
344*0Sstevel@tonic-gate		$result_msg{$object} .= "$c " .
345*0Sstevel@tonic-gate		    gettext("demoted (removed) private symbols") . ": $m; ";
346*0Sstevel@tonic-gate
347*0Sstevel@tonic-gate		# Add this case to the warnings output.
348*0Sstevel@tonic-gate		my $tag  = 'scoped symbols';
349*0Sstevel@tonic-gate		$warnings_found{$tag} .= "$object|";
350*0Sstevel@tonic-gate
351*0Sstevel@tonic-gate		my $desc = gettext(
352*0Sstevel@tonic-gate		    "dependency on demoted (removed) private Solaris symbols");
353*0Sstevel@tonic-gate		if (! exists($warnings_desc{$tag})) {
354*0Sstevel@tonic-gate			$warnings_desc{$tag} = $desc;
355*0Sstevel@tonic-gate		}
356*0Sstevel@tonic-gate	}
357*0Sstevel@tonic-gate
358*0Sstevel@tonic-gate	if ($m = $problems{'warnings'}) {
359*0Sstevel@tonic-gate		foreach $w (split(/\|/, $m)) {
360*0Sstevel@tonic-gate			next if ($w =~ /^\s*$/);
361*0Sstevel@tonic-gate
362*0Sstevel@tonic-gate			$c = $w;
363*0Sstevel@tonic-gate			if (defined($warnings_desc{$c})) {
364*0Sstevel@tonic-gate				$c = $warnings_desc{$c};
365*0Sstevel@tonic-gate				$c = gettext($c);
366*0Sstevel@tonic-gate			}
367*0Sstevel@tonic-gate			$c =~ s/;//g;
368*0Sstevel@tonic-gate			$result_msg{$object} .= "$c; ";
369*0Sstevel@tonic-gate			$warnings_found{$w} .= "$object|";
370*0Sstevel@tonic-gate		}
371*0Sstevel@tonic-gate	}
372*0Sstevel@tonic-gate
373*0Sstevel@tonic-gate	$result_msg{$object} =~ s/;\s+$//;
374*0Sstevel@tonic-gate}
375*0Sstevel@tonic-gate
376*0Sstevel@tonic-gate#
377*0Sstevel@tonic-gate# Create the top level roll-up report.
378*0Sstevel@tonic-gate#
379*0Sstevel@tonic-gatesub print_report
380*0Sstevel@tonic-gate{
381*0Sstevel@tonic-gate	# Count the number of passed, failed and total binary objects:
382*0Sstevel@tonic-gate	my(@a);
383*0Sstevel@tonic-gate	my($r_passed, $r_incomp, $r_failed);
384*0Sstevel@tonic-gate	if (exists($result_list_hash{'passed'})) {
385*0Sstevel@tonic-gate		$r_passed = $result_list_hash{'passed'};
386*0Sstevel@tonic-gate	} else {
387*0Sstevel@tonic-gate		$r_passed = '';
388*0Sstevel@tonic-gate	}
389*0Sstevel@tonic-gate	if (exists($result_list_hash{'incomplete'})) {
390*0Sstevel@tonic-gate		$r_incomp = $result_list_hash{'incomplete'};
391*0Sstevel@tonic-gate	} else {
392*0Sstevel@tonic-gate		$r_incomp = '';
393*0Sstevel@tonic-gate	}
394*0Sstevel@tonic-gate	if (exists($result_list_hash{'failed'})) {
395*0Sstevel@tonic-gate		$r_failed = $result_list_hash{'failed'};
396*0Sstevel@tonic-gate	} else {
397*0Sstevel@tonic-gate		$r_failed = '';
398*0Sstevel@tonic-gate	}
399*0Sstevel@tonic-gate	my $n_passed = scalar(@a = split(/\|/, $r_passed));
400*0Sstevel@tonic-gate	my $n_incomp = scalar(@a = split(/\|/, $r_incomp));
401*0Sstevel@tonic-gate	my $n_failed = scalar(@a = split(/\|/, $r_failed));
402*0Sstevel@tonic-gate	my $n_checked = $n_passed + $n_incomp + $n_failed;
403*0Sstevel@tonic-gate
404*0Sstevel@tonic-gate	my ($summary_result, $msg, $output, $object);
405*0Sstevel@tonic-gate
406*0Sstevel@tonic-gate
407*0Sstevel@tonic-gate	if ($n_checked == 0) {
408*0Sstevel@tonic-gate		$summary_result = $text{'Summary_Result_None_Checked'};
409*0Sstevel@tonic-gate	} elsif ($n_failed > 0) {
410*0Sstevel@tonic-gate		$summary_result = $text{'Summary_Result_Some_Failed'};
411*0Sstevel@tonic-gate	} elsif ($n_incomp > 0) {
412*0Sstevel@tonic-gate		$summary_result = $text{'Summary_Result_Some_Incomplete'};
413*0Sstevel@tonic-gate	} else {
414*0Sstevel@tonic-gate		$summary_result = $text{'Summary_Result_All_Passed'};
415*0Sstevel@tonic-gate	}
416*0Sstevel@tonic-gate
417*0Sstevel@tonic-gate	# place the info in problem count file:
418*0Sstevel@tonic-gate	my $cnt_file = "$working_dir/ProblemCount";
419*0Sstevel@tonic-gate	my $pcount_fh = do { local *FH; *FH };
420*0Sstevel@tonic-gate	if (! open($pcount_fh, ">$cnt_file")) {
421*0Sstevel@tonic-gate		exiter(nofile($cnt_file, $!));
422*0Sstevel@tonic-gate	}
423*0Sstevel@tonic-gate
424*0Sstevel@tonic-gate	print $pcount_fh "$n_failed / $n_checked binary_objects_had_problems\n";
425*0Sstevel@tonic-gate	print $pcount_fh
426*0Sstevel@tonic-gate	    "$n_incomp / $n_checked could_not_be_completely_checked\n";
427*0Sstevel@tonic-gate
428*0Sstevel@tonic-gate	print $pcount_fh "NO_PROBLEMS_LIST: $r_passed\n";
429*0Sstevel@tonic-gate	print $pcount_fh "INCOMPLETE_LIST: $r_incomp\n";
430*0Sstevel@tonic-gate	print $pcount_fh "PROBLEMS_LIST: $r_failed\n";
431*0Sstevel@tonic-gate	close($pcount_fh);
432*0Sstevel@tonic-gate
433*0Sstevel@tonic-gate	#
434*0Sstevel@tonic-gate	# Set the overall result code.
435*0Sstevel@tonic-gate	# This is used to communicate back to the appcert script to
436*0Sstevel@tonic-gate	# indicate how it should exit(). The string must start with the
437*0Sstevel@tonic-gate	# exit number, after which a message may follow.
438*0Sstevel@tonic-gate	#
439*0Sstevel@tonic-gate
440*0Sstevel@tonic-gate	if ($n_checked == 0) {
441*0Sstevel@tonic-gate		overall_result_code("3 => nothing_checked");
442*0Sstevel@tonic-gate	} elsif ($n_failed > 0) {
443*0Sstevel@tonic-gate		overall_result_code("2 => some_problems_detected($n_failed)");
444*0Sstevel@tonic-gate	} elsif ($n_incomp > 0) {
445*0Sstevel@tonic-gate		overall_result_code("1 => " .
446*0Sstevel@tonic-gate		    "some_binaries_incompletely_checked($n_incomp)");
447*0Sstevel@tonic-gate	} else {
448*0Sstevel@tonic-gate		overall_result_code("0 => no_problems_detected");
449*0Sstevel@tonic-gate	}
450*0Sstevel@tonic-gate
451*0Sstevel@tonic-gate	my ($sp0, $sp, $sf, $si);	# PASS & FAIL spacing tags.
452*0Sstevel@tonic-gate	$sp0 = '   ';
453*0Sstevel@tonic-gate	if ($batch_report) {
454*0Sstevel@tonic-gate		$sp = 'PASS ';
455*0Sstevel@tonic-gate		$sf = 'FAIL ';
456*0Sstevel@tonic-gate		$si = 'INC  ';
457*0Sstevel@tonic-gate	} else {
458*0Sstevel@tonic-gate		$sp = $sp0;
459*0Sstevel@tonic-gate		$sf = $sp0;
460*0Sstevel@tonic-gate		$si = $sp0;
461*0Sstevel@tonic-gate	}
462*0Sstevel@tonic-gate
463*0Sstevel@tonic-gate
464*0Sstevel@tonic-gate	$msg = sprintf(gettext("Summary: %s"), $summary_result) . "\n\n";
465*0Sstevel@tonic-gate	my $format = gettext("A total of %d binary objects were examined.");
466*0Sstevel@tonic-gate	$msg .= sprintf($format, $n_checked) . "\n\n\n";
467*0Sstevel@tonic-gate	$output .= $msg;
468*0Sstevel@tonic-gate
469*0Sstevel@tonic-gate	my $fmt1 = gettext(
470*0Sstevel@tonic-gate	    "The following (%d of %d) components had no problems detected:");
471*0Sstevel@tonic-gate
472*0Sstevel@tonic-gate	if ($n_passed > 0) {
473*0Sstevel@tonic-gate		$output .= sprintf($fmt1, $n_passed, $n_checked);
474*0Sstevel@tonic-gate		$output .= "\n\n";
475*0Sstevel@tonic-gate
476*0Sstevel@tonic-gate		foreach $object (split(/\|/, $r_passed)) {
477*0Sstevel@tonic-gate			$output .= "${sp}$object\n";
478*0Sstevel@tonic-gate		}
479*0Sstevel@tonic-gate		$output .= "\n";
480*0Sstevel@tonic-gate	}
481*0Sstevel@tonic-gate
482*0Sstevel@tonic-gate	my $fmt2 = gettext(
483*0Sstevel@tonic-gate	    "The following (%d of %d) components had no problems detected,\n" .
484*0Sstevel@tonic-gate	    "   but could not be completely checked:");
485*0Sstevel@tonic-gate
486*0Sstevel@tonic-gate	if ($n_incomp > 0) {
487*0Sstevel@tonic-gate		$output .= sprintf($fmt2, $n_incomp, $n_checked);
488*0Sstevel@tonic-gate		$output .= "\n\n";
489*0Sstevel@tonic-gate
490*0Sstevel@tonic-gate		foreach $object (split(/\|/, $r_incomp)) {
491*0Sstevel@tonic-gate			$msg = $result_msg{$object};
492*0Sstevel@tonic-gate			$output .= "${si}$object\t($msg)\n";
493*0Sstevel@tonic-gate		}
494*0Sstevel@tonic-gate		$output .= "\n";
495*0Sstevel@tonic-gate	}
496*0Sstevel@tonic-gate
497*0Sstevel@tonic-gate	my $fmt3 = gettext(
498*0Sstevel@tonic-gate	    "The following (%d of %d) components have potential " .
499*0Sstevel@tonic-gate	    "stability problems:");
500*0Sstevel@tonic-gate	if ($n_failed > 0) {
501*0Sstevel@tonic-gate		$output .= sprintf($fmt3, $n_failed, $n_checked);
502*0Sstevel@tonic-gate		$output .= "\n\n";
503*0Sstevel@tonic-gate
504*0Sstevel@tonic-gate		foreach $object (split(/\|/, $r_failed)) {
505*0Sstevel@tonic-gate			$msg = $result_msg{$object};
506*0Sstevel@tonic-gate			$output .= "${sf}$object\t($msg)\n";
507*0Sstevel@tonic-gate		}
508*0Sstevel@tonic-gate		$output .= "\n";
509*0Sstevel@tonic-gate	}
510*0Sstevel@tonic-gate
511*0Sstevel@tonic-gate	$output .= "\n" . get_summary();
512*0Sstevel@tonic-gate
513*0Sstevel@tonic-gate	$output .= "\n" . get_warnings();
514*0Sstevel@tonic-gate
515*0Sstevel@tonic-gate	my $report_file = "$working_dir/Report";
516*0Sstevel@tonic-gate	my $report_fh = do { local *FH; *FH };
517*0Sstevel@tonic-gate	open($report_fh, ">$report_file") ||
518*0Sstevel@tonic-gate	    exiter(nofile($report_file, $!));
519*0Sstevel@tonic-gate
520*0Sstevel@tonic-gate	print $report_fh $output;
521*0Sstevel@tonic-gate	close($report_fh);
522*0Sstevel@tonic-gate	system($cmd_more, $report_file);
523*0Sstevel@tonic-gate}
524*0Sstevel@tonic-gate
525*0Sstevel@tonic-gate#
526*0Sstevel@tonic-gate# Collects all of the warnings issued for the binaries that were
527*0Sstevel@tonic-gate# checked.  Returns the warning text that will go into the roll-up
528*0Sstevel@tonic-gate# report.
529*0Sstevel@tonic-gate#
530*0Sstevel@tonic-gatesub get_warnings
531*0Sstevel@tonic-gate{
532*0Sstevel@tonic-gate	my ($w, $c, $output, $count);
533*0Sstevel@tonic-gate
534*0Sstevel@tonic-gate	if (! %warnings_found) {
535*0Sstevel@tonic-gate		return '';	# appends null string to output text
536*0Sstevel@tonic-gate	}
537*0Sstevel@tonic-gate
538*0Sstevel@tonic-gate	$output = gettext("Summary of various warnings:") . "\n\n";
539*0Sstevel@tonic-gate	my(@a);
540*0Sstevel@tonic-gate	foreach $w (keys(%warnings_found)) {
541*0Sstevel@tonic-gate		$warnings_found{$w} =~ s/\|+$//;
542*0Sstevel@tonic-gate		$count = scalar(@a = split(/\|/, $warnings_found{$w}));
543*0Sstevel@tonic-gate		$c = $w;
544*0Sstevel@tonic-gate		if (defined($warnings_desc{$c})) {
545*0Sstevel@tonic-gate			$c = $warnings_desc{$c};
546*0Sstevel@tonic-gate		}
547*0Sstevel@tonic-gate		$c = gettext($c);
548*0Sstevel@tonic-gate		$output .= " - $c  " . sprintf(gettext(
549*0Sstevel@tonic-gate		    "(%d binaries)\n"), $count);
550*0Sstevel@tonic-gate		$output .= "\n";
551*0Sstevel@tonic-gate
552*0Sstevel@tonic-gate	}
553*0Sstevel@tonic-gate	$output .= "\n";
554*0Sstevel@tonic-gate
555*0Sstevel@tonic-gate	return $output;
556*0Sstevel@tonic-gate}
557*0Sstevel@tonic-gate
558*0Sstevel@tonic-gate#
559*0Sstevel@tonic-gate# Computes the summary information for each binary object that was
560*0Sstevel@tonic-gate# checked.  Returns the text that will go into the roll-up report.
561*0Sstevel@tonic-gate#
562*0Sstevel@tonic-gatesub get_summary
563*0Sstevel@tonic-gate{
564*0Sstevel@tonic-gate	my ($dir, $file);
565*0Sstevel@tonic-gate	my (%lib_private, %libsym_private);
566*0Sstevel@tonic-gate	my (%libapp, %libapp_private);
567*0Sstevel@tonic-gate
568*0Sstevel@tonic-gate	my ($bin, $arch, $direct, $lib, $class, $sym);
569*0Sstevel@tonic-gate
570*0Sstevel@tonic-gate	while (defined($dir = next_dir_name())) {
571*0Sstevel@tonic-gate
572*0Sstevel@tonic-gate		# This is where the public symbol list is:
573*0Sstevel@tonic-gate		$file = "$dir/check.dynamic.public";
574*0Sstevel@tonic-gate
575*0Sstevel@tonic-gate		my %app_public;
576*0Sstevel@tonic-gate		my %app_sym_public;
577*0Sstevel@tonic-gate		my %app_private;
578*0Sstevel@tonic-gate		my %app_sym_private;
579*0Sstevel@tonic-gate
580*0Sstevel@tonic-gate		if (-s $file) {
581*0Sstevel@tonic-gate			my $publics_fh = do { local *FH; *FH };
582*0Sstevel@tonic-gate			open($publics_fh, "<$file") ||
583*0Sstevel@tonic-gate			    exiter(nofile($file, $!));
584*0Sstevel@tonic-gate
585*0Sstevel@tonic-gate			while (<$publics_fh>) {
586*0Sstevel@tonic-gate				next if (/^\s*#/);
587*0Sstevel@tonic-gate				chomp;
588*0Sstevel@tonic-gate				($bin, $arch, $direct, $lib, $class, $sym) =
589*0Sstevel@tonic-gate				    split(/\|/, $_);
590*0Sstevel@tonic-gate
591*0Sstevel@tonic-gate				$libapp{"$lib|$bin"}++;
592*0Sstevel@tonic-gate
593*0Sstevel@tonic-gate				$app_public{$lib}++;
594*0Sstevel@tonic-gate				$app_sym_public{"$lib|$sym"}++;
595*0Sstevel@tonic-gate			}
596*0Sstevel@tonic-gate			close($publics_fh);
597*0Sstevel@tonic-gate		}
598*0Sstevel@tonic-gate
599*0Sstevel@tonic-gate		# This is where the private symbol list is:
600*0Sstevel@tonic-gate		$file = "$dir/check.dynamic.private";
601*0Sstevel@tonic-gate
602*0Sstevel@tonic-gate		if (-s $file) {
603*0Sstevel@tonic-gate			my $privates_fh = do { local *FH; *FH };
604*0Sstevel@tonic-gate			open($privates_fh, "<$file") ||
605*0Sstevel@tonic-gate			    exiter(nofile($file, $!));
606*0Sstevel@tonic-gate
607*0Sstevel@tonic-gate			while (<$privates_fh>) {
608*0Sstevel@tonic-gate				next if (/^\s*#/);
609*0Sstevel@tonic-gate				chomp;
610*0Sstevel@tonic-gate				($bin, $arch, $direct, $lib, $class, $sym) =
611*0Sstevel@tonic-gate				    split(/\|/, $_);
612*0Sstevel@tonic-gate
613*0Sstevel@tonic-gate				$lib_private{$lib}++;
614*0Sstevel@tonic-gate				$libsym_private{"$lib|$sym"}++;
615*0Sstevel@tonic-gate				$libapp_private{"$lib|$bin"}++;
616*0Sstevel@tonic-gate				$libapp{"$lib|$bin"}++;
617*0Sstevel@tonic-gate
618*0Sstevel@tonic-gate				$app_private{$lib}++;
619*0Sstevel@tonic-gate				$app_sym_private{"$lib|$sym"}++;
620*0Sstevel@tonic-gate			}
621*0Sstevel@tonic-gate			close($privates_fh);
622*0Sstevel@tonic-gate		}
623*0Sstevel@tonic-gate
624*0Sstevel@tonic-gate		write_app_summary($dir, \%app_public, \%app_sym_public,
625*0Sstevel@tonic-gate		    \%app_private, \%app_sym_private);
626*0Sstevel@tonic-gate	}
627*0Sstevel@tonic-gate
628*0Sstevel@tonic-gate	my ($app_total, $app_private_total);
629*0Sstevel@tonic-gate	my ($key, $lib2, $app2, $sym2);
630*0Sstevel@tonic-gate	my $val;
631*0Sstevel@tonic-gate	my $text;
632*0Sstevel@tonic-gate
633*0Sstevel@tonic-gate	foreach $lib (sort(keys(%lib_private))) {
634*0Sstevel@tonic-gate
635*0Sstevel@tonic-gate		$app_total = 0;
636*0Sstevel@tonic-gate		foreach $key (keys(%libapp)) {
637*0Sstevel@tonic-gate			($lib2, $app2) = split(/\|/, $key);
638*0Sstevel@tonic-gate			$app_total++ if ($lib eq $lib2);
639*0Sstevel@tonic-gate		}
640*0Sstevel@tonic-gate
641*0Sstevel@tonic-gate		$app_private_total = 0;
642*0Sstevel@tonic-gate		foreach $key (keys(%libapp_private)) {
643*0Sstevel@tonic-gate			($lib2, $app2) = split(/\|/, $key);
644*0Sstevel@tonic-gate			$app_private_total++ if ($lib eq $lib2);
645*0Sstevel@tonic-gate		}
646*0Sstevel@tonic-gate
647*0Sstevel@tonic-gate		my @list;
648*0Sstevel@tonic-gate		while (($key, $val) =  each(%libsym_private)) {
649*0Sstevel@tonic-gate			($lib2, $sym2) = split(/\|/, $key);
650*0Sstevel@tonic-gate			next unless ($lib eq $lib2);
651*0Sstevel@tonic-gate			push(@list, "$sym2 $val");
652*0Sstevel@tonic-gate
653*0Sstevel@tonic-gate		}
654*0Sstevel@tonic-gate
655*0Sstevel@tonic-gate		$text .= private_format($lib, $app_total,
656*0Sstevel@tonic-gate		    $app_private_total, @list);
657*0Sstevel@tonic-gate	}
658*0Sstevel@tonic-gate
659*0Sstevel@tonic-gate	if (! defined($text)) {
660*0Sstevel@tonic-gate		return '';	# appends null string to output report.
661*0Sstevel@tonic-gate	}
662*0Sstevel@tonic-gate	return $text;
663*0Sstevel@tonic-gate}
664*0Sstevel@tonic-gate
665*0Sstevel@tonic-gate#
666*0Sstevel@tonic-gate# Given the symbols and counts of private symbols used by all binaries
667*0Sstevel@tonic-gate# that were checked, returns a pretty-printed format table of the
668*0Sstevel@tonic-gate# symbols. This text goes into the roll-up report and the summary.dynamic
669*0Sstevel@tonic-gate# file.
670*0Sstevel@tonic-gate#
671*0Sstevel@tonic-gatesub private_format
672*0Sstevel@tonic-gate{
673*0Sstevel@tonic-gate	my ($lib, $tot, $priv, @list) = @_;
674*0Sstevel@tonic-gate
675*0Sstevel@tonic-gate	my (@sorted) = sort_on_count(@list);
676*0Sstevel@tonic-gate	my $formatted = list_format('  ', @sorted);
677*0Sstevel@tonic-gate
678*0Sstevel@tonic-gate	my $text;
679*0Sstevel@tonic-gate	my $libbase = basename($lib);
680*0Sstevel@tonic-gate
681*0Sstevel@tonic-gate	$text = sprintf(gettext(
682*0Sstevel@tonic-gate	    "Summary of Private symbol use in %s\n"), $lib);
683*0Sstevel@tonic-gate	my $fmt =
684*0Sstevel@tonic-gate	    gettext("%d binaries used %s, %d of these used private symbols");
685*0Sstevel@tonic-gate	$text .= sprintf($fmt, $tot, $libbase, $priv);
686*0Sstevel@tonic-gate	$text .= "\n\n$formatted\n";
687*0Sstevel@tonic-gate
688*0Sstevel@tonic-gate	return $text;
689*0Sstevel@tonic-gate}
690*0Sstevel@tonic-gate
691*0Sstevel@tonic-gate#
692*0Sstevel@tonic-gate# Given the public/private symbol and library usage information for a
693*0Sstevel@tonic-gate# binary object, creates an output file with this information formatted
694*0Sstevel@tonic-gate# in tables.
695*0Sstevel@tonic-gate#
696*0Sstevel@tonic-gatesub write_app_summary
697*0Sstevel@tonic-gate{
698*0Sstevel@tonic-gate	my ($dir, $public, $sym_public, $private, $sym_private) = @_;
699*0Sstevel@tonic-gate
700*0Sstevel@tonic-gate	my $outfile = "$dir/summary.dynamic";
701*0Sstevel@tonic-gate
702*0Sstevel@tonic-gate	my $summary_fh = do { local *FH; *FH };
703*0Sstevel@tonic-gate	open($summary_fh, ">$outfile") ||
704*0Sstevel@tonic-gate	    exiter(nofile($outfile, $!));
705*0Sstevel@tonic-gate
706*0Sstevel@tonic-gate	my $path_to_object = dir_name_to_path($dir);
707*0Sstevel@tonic-gate
708*0Sstevel@tonic-gate
709*0Sstevel@tonic-gate	my ($tmp1, $tmp2, $tmp3);
710*0Sstevel@tonic-gate
711*0Sstevel@tonic-gate	$tmp1 = gettext("ABI SYMBOL USAGE SUMMARY REPORT");
712*0Sstevel@tonic-gate	$tmp2 = '*' x length($tmp1);
713*0Sstevel@tonic-gate
714*0Sstevel@tonic-gate	print $summary_fh "$tmp2\n$tmp1\n$tmp2\n\n";
715*0Sstevel@tonic-gate
716*0Sstevel@tonic-gate	print $summary_fh "  ", sprintf(gettext(
717*0Sstevel@tonic-gate	    "Binary Object: %s\n"), $path_to_object);
718*0Sstevel@tonic-gate
719*0Sstevel@tonic-gate	my $uname_a = `$cmd_uname -a`;
720*0Sstevel@tonic-gate	print $summary_fh "  ", sprintf(gettext("System: %s\n"), $uname_a);
721*0Sstevel@tonic-gate
722*0Sstevel@tonic-gate	$tmp1 = gettext("References to shared objects in the Solaris ABI");
723*0Sstevel@tonic-gate	$tmp2 = '*' x length($tmp1);
724*0Sstevel@tonic-gate
725*0Sstevel@tonic-gate	print $summary_fh "$tmp2\n$tmp1\n$tmp2\n\n";
726*0Sstevel@tonic-gate
727*0Sstevel@tonic-gate
728*0Sstevel@tonic-gate	my (%libs, $lib, $maxlen, $len);
729*0Sstevel@tonic-gate	$maxlen = 0;
730*0Sstevel@tonic-gate
731*0Sstevel@tonic-gate	foreach $lib (keys(%$public), keys(%$private)) {
732*0Sstevel@tonic-gate		$len = length($lib);
733*0Sstevel@tonic-gate		$maxlen = $len if ($len > $maxlen);
734*0Sstevel@tonic-gate		$libs{$lib} = 1;
735*0Sstevel@tonic-gate	}
736*0Sstevel@tonic-gate
737*0Sstevel@tonic-gate	if (! %libs) {
738*0Sstevel@tonic-gate		my $str = gettext(
739*0Sstevel@tonic-gate		"  NONE FOUND. Possible explanations:\n" .
740*0Sstevel@tonic-gate		"    - the dynamic profiling failed, see ldd(1), ld.so.1(1)\n" .
741*0Sstevel@tonic-gate		"    - the object is SUID or SGID\n" .
742*0Sstevel@tonic-gate		"    - the object is completely statically linked.\n"
743*0Sstevel@tonic-gate		);
744*0Sstevel@tonic-gate		print $summary_fh $str, "\n";
745*0Sstevel@tonic-gate		close($summary_fh);
746*0Sstevel@tonic-gate		return;
747*0Sstevel@tonic-gate	}
748*0Sstevel@tonic-gate
749*0Sstevel@tonic-gate	foreach $lib (sort(keys(%libs))) {
750*0Sstevel@tonic-gate		print $summary_fh "  $lib\n";
751*0Sstevel@tonic-gate	}
752*0Sstevel@tonic-gate	print $summary_fh "\n";
753*0Sstevel@tonic-gate
754*0Sstevel@tonic-gate	my ($len1, $len2, $len3);
755*0Sstevel@tonic-gate	my $heading = '  ' . gettext("Library");
756*0Sstevel@tonic-gate	$heading .= ' ' x ($maxlen + 6 - length($heading));
757*0Sstevel@tonic-gate	$len1 = length($heading) - 2;
758*0Sstevel@tonic-gate	my $public_str = gettext("Public");
759*0Sstevel@tonic-gate	$len2 = length($public_str);
760*0Sstevel@tonic-gate	my $private_str = gettext("Private");
761*0Sstevel@tonic-gate	$len3 = length("  $private_str");
762*0Sstevel@tonic-gate	$heading .= "$public_str  $private_str";
763*0Sstevel@tonic-gate	$tmp3 = $heading;
764*0Sstevel@tonic-gate	$tmp3 =~ s/\S/-/g;
765*0Sstevel@tonic-gate
766*0Sstevel@tonic-gate	$tmp1 = gettext("Symbol usage statistics (summary by shared object)");
767*0Sstevel@tonic-gate	$tmp2 = '*' x length($tmp1);
768*0Sstevel@tonic-gate
769*0Sstevel@tonic-gate	print $summary_fh "$tmp2\n$tmp1\n$tmp2\n\n";
770*0Sstevel@tonic-gate	print $summary_fh "$heading\n";
771*0Sstevel@tonic-gate	print $summary_fh "$tmp3\n";
772*0Sstevel@tonic-gate
773*0Sstevel@tonic-gate	my ($pub, $priv, $str);
774*0Sstevel@tonic-gate	foreach $lib (sort(keys(%libs))) {
775*0Sstevel@tonic-gate		$pub  = $public->{$lib};
776*0Sstevel@tonic-gate		$priv = $private->{$lib};
777*0Sstevel@tonic-gate
778*0Sstevel@tonic-gate		$pub = 0 if (! defined($pub));
779*0Sstevel@tonic-gate		$priv = 0 if (! defined($priv));
780*0Sstevel@tonic-gate
781*0Sstevel@tonic-gate		$str = '  ';
782*0Sstevel@tonic-gate		$str .= sprintf("%-${len1}s", $lib);
783*0Sstevel@tonic-gate		$str .= sprintf("%${len2}s", $pub);
784*0Sstevel@tonic-gate		$str .= sprintf("%${len3}s", $priv);
785*0Sstevel@tonic-gate		print $summary_fh $str, "\n";
786*0Sstevel@tonic-gate	}
787*0Sstevel@tonic-gate	print $summary_fh "\n";
788*0Sstevel@tonic-gate
789*0Sstevel@tonic-gate	$tmp1 = gettext("Symbol usage (detailed inventory by shared object)");
790*0Sstevel@tonic-gate	$tmp2 = '*' x length($tmp1);
791*0Sstevel@tonic-gate
792*0Sstevel@tonic-gate	print $summary_fh "$tmp2\n$tmp1\n$tmp2\n\n";
793*0Sstevel@tonic-gate
794*0Sstevel@tonic-gate	my (@pub, @priv, $lib2, $sym2, $text, $key);
795*0Sstevel@tonic-gate	foreach $lib (sort(keys(%libs))) {
796*0Sstevel@tonic-gate		@pub  = ();
797*0Sstevel@tonic-gate		@priv = ();
798*0Sstevel@tonic-gate
799*0Sstevel@tonic-gate		foreach $key (keys(%$sym_public)) {
800*0Sstevel@tonic-gate			next unless (index($key, $lib) == 0);
801*0Sstevel@tonic-gate			($lib2, $sym2) = split(/\|/, $key, 2);
802*0Sstevel@tonic-gate			next unless ($lib2 eq $lib);
803*0Sstevel@tonic-gate			push(@pub, $sym2);
804*0Sstevel@tonic-gate		}
805*0Sstevel@tonic-gate		foreach $key (keys(%$sym_private)) {
806*0Sstevel@tonic-gate			next unless (index($key, $lib) == 0);
807*0Sstevel@tonic-gate			($lib2, $sym2) = split(/\|/, $key, 2);
808*0Sstevel@tonic-gate			next unless ($lib2 eq $lib);
809*0Sstevel@tonic-gate			push(@priv, $sym2);
810*0Sstevel@tonic-gate		}
811*0Sstevel@tonic-gate
812*0Sstevel@tonic-gate		next if (! @pub && ! @priv);
813*0Sstevel@tonic-gate
814*0Sstevel@tonic-gate		my $fmt = gettext("Symbols in %s Directly Referenced");
815*0Sstevel@tonic-gate		$text = sprintf($fmt, $lib);
816*0Sstevel@tonic-gate
817*0Sstevel@tonic-gate		if (@pub) {
818*0Sstevel@tonic-gate			$lib2 = scalar(@pub);
819*0Sstevel@tonic-gate			$text .= sprintf(gettext(
820*0Sstevel@tonic-gate			    "  %d public symbols are used:\n"), $lib2);
821*0Sstevel@tonic-gate			$text .= list_format('    ', sort(@pub));
822*0Sstevel@tonic-gate			$text .= "\n";
823*0Sstevel@tonic-gate		}
824*0Sstevel@tonic-gate		if (@priv) {
825*0Sstevel@tonic-gate			$lib2 = scalar(@priv);
826*0Sstevel@tonic-gate			$text .= sprintf(gettext(
827*0Sstevel@tonic-gate			    "  %d private symbols are used:\n"), $lib2);
828*0Sstevel@tonic-gate			$text .= list_format('    ', sort(@priv));
829*0Sstevel@tonic-gate			$text .= "\n";
830*0Sstevel@tonic-gate		}
831*0Sstevel@tonic-gate
832*0Sstevel@tonic-gate		print $summary_fh $text;
833*0Sstevel@tonic-gate	}
834*0Sstevel@tonic-gate	close($summary_fh);
835*0Sstevel@tonic-gate}
836