#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License, Version 1.0 only
# (the "License"). You may not use this file except in compliance
# with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 1996-2000 by Sun Microsystems, Inc.
# All rights reserved.
#
#ident "%Z%%M% %I% %E% SMI"
#
#
# This utility program reads the symcheck output of each binary and
# creates additional output for then and an overall report.
#
require 5.005;
use strict;
use locale;
use AppcertUtil;
use vars qw(
);
clean_up();
exit 0;
#
# working_dir has been imported by import_vars_from_environment()
# A sanity check is performed here to make sure it exists.
#
sub set_working_dir
{
if (! defined($working_dir) || ! -d $working_dir) {
"cannot locate working directory: %s\n"), $working_dir));
}
}
#
# Called when interrupted by user.
#
sub interrupted
{
signals('off');
clean_up_exit(1);
}
#
# Does the cleanup and then exit with return code $rc. Note: The
# utility routine exiter() will call this routine.
#
sub clean_up_exit
{
my ($rc) = @_;
clean_up();
exit $rc;
}
#
# General cleanup activities are placed here. There may not be an
# immediate exit after this cleanup.
#
sub clean_up
{
if (defined($tmp_report_dir) && -d $tmp_report_dir) {
}
}
#
# Top level routine for generating the additional reports.
#
sub generate_reports
{
# Make a tmp dir for the reporting work.
if (! -d $tmp_report_dir) {
}
pmsg("\n");
print_line();
my ($dir, $path_to_object);
#
# Loop over each object item in the working_dir.
# - $dir will be each one of these object directories.
# - $path_to_object will be the corresponding actual path
# to the the binary to be profiled.
#
while (defined($dir = next_dir_name())) {
# Map object output dir to actual path of the object:
# Make a report for it:
}
my $type;
foreach $type (keys(%result_list_hash)) {
$result_list_hash{$type} =~ s/\|+$//;
}
print_report();
my $tout;
"Additional output regarding private symbols usage and other\n" .
"data is in the directory:\n");
$tout .= "\n $working_dir\n\n";
"see the appcert documentation for more information.\n");
clean_up(); # Remove any tmp directories and files.
}
#
# Examines the symcheck output for a given binary object recording and
# reporting and problems found. Generates additional reports and
# summaries.
#
sub report_object
{
my (%problems);
my $problems_file = "$dir/check.problems";
open($problems_fh, "<$problems_file") ||
# We need the "warning" msgs and text from the Misc Checks loaded:
if (! defined($misc_check_databases_loaded_ok)) {
}
my $problem_count = 0;
my $incomplete_count = 0;
my $line_count = 0;
while (<$problems_fh>) {
chomp;
$prob = 1;
$incomp = 0;
$line_count++;
if (/^DYNAMIC: PRIVATE_SYMBOL_USE\s+(\d*)/) {
} elsif (/^DYNAMIC: UNBOUND_SYMBOL_USE\s+(\d*)/) {
$incomp = 1;
} elsif (/^DYNAMIC: UNRECOGNIZED_SYMBOL_USE\s+(\d*)/) {
$incomp = 1;
} elsif (/^DYNAMIC: NO_DYNAMIC_BINDINGS_FOUND\s*(.*)$/) {
$incomp = 1;
} elsif (/^STATIC: LINKED_ARCHIVE\s+(.*)$/) {
} elsif (/^STATIC: COMPLETELY_STATIC/) {
$problems{'completely_static'}++;
} elsif (/^MISC: REMOVED_SCOPED_SYMBOLS:\s+(.*)$/) {
$incomp = 1;
} else {
$prob = 0;
}
$problem_count += $prob;
$incomplete_count += $incomp;
}
close($problems_fh);
if ($line_count == 0) {
# No problems at all, leave a comment message:
open($problems_fh, ">$problems_file") ||
print $problems_fh "# NO_PROBLEMS_DETECTED\n";
close($problems_fh);
}
if ($problem_count == 0) {
return;
}
if ($incomplete_count == $problem_count) {
} else {
}
my $m;
if ($m = $problems{'private_syms'}) {
}
if ($m = $problems{'unbound_syms'}) {
# add this case to the warnings output at end of report.
my $tag = 'unbound symbols';
if (! exists($warnings_desc{$tag})) {
}
}
if ($m = $problems{'unrecognized_syms'}) {
# Add this case to the warnings output at end of report.
my $tag = 'unrecognized symbols';
if (! exists($warnings_desc{$tag})) {
}
}
if ($m = $problems{'static_linking'}) {
$m =~ s/,\s*$//;
"statically linked with %s"), $m) . "; ";
# Add this case to the warnings output at end of report.
my $tag = 'statically linked';
if (! exists($warnings_desc{$tag})) {
my $desc =
gettext("static linking of Solaris libraries");
}
}
if ($problems{'completely_static'}) {
$result_msg{$object} .=
# Add this case to the warnings output.
my $desc =
gettext("complete static linking of Solaris libraries");
if (! exists($warnings_desc{$tag})) {
}
} elsif ($m = $problems{'no_dynamic_bindings'}) {
#
# Note we skip this error if it is completely static.
# The app could technically be SUID as well.
#
$m =~ s/,\s*$//;
$m = " : $m";
$m =~ s/ : NO_SYMBOL_BINDINGS_FOUND//;
$m =~ s/^ :/:/;
$result_msg{$object} .=
}
if ($m = $problems{'scoped_symbols'}) {
$m =~ s/[,\s]*$//;
$c = scalar(my @a = split(' ', $m));
# Add this case to the warnings output.
my $tag = 'scoped symbols';
"dependency on demoted (removed) private Solaris symbols");
if (! exists($warnings_desc{$tag})) {
}
}
if ($m = $problems{'warnings'}) {
foreach $w (split(/\|/, $m)) {
next if ($w =~ /^\s*$/);
$c = $w;
if (defined($warnings_desc{$c})) {
$c = $warnings_desc{$c};
$c = gettext($c);
}
$c =~ s/;//g;
$warnings_found{$w} .= "$object|";
}
}
$result_msg{$object} =~ s/;\s+$//;
}
#
# Create the top level roll-up report.
#
sub print_report
{
# Count the number of passed, failed and total binary objects:
my(@a);
if (exists($result_list_hash{'passed'})) {
} else {
$r_passed = '';
}
if (exists($result_list_hash{'incomplete'})) {
} else {
$r_incomp = '';
}
if (exists($result_list_hash{'failed'})) {
} else {
$r_failed = '';
}
if ($n_checked == 0) {
} elsif ($n_failed > 0) {
} elsif ($n_incomp > 0) {
} else {
}
# place the info in problem count file:
my $cnt_file = "$working_dir/ProblemCount";
if (! open($pcount_fh, ">$cnt_file")) {
}
print $pcount_fh "$n_failed / $n_checked binary_objects_had_problems\n";
print $pcount_fh
"$n_incomp / $n_checked could_not_be_completely_checked\n";
print $pcount_fh "NO_PROBLEMS_LIST: $r_passed\n";
print $pcount_fh "INCOMPLETE_LIST: $r_incomp\n";
print $pcount_fh "PROBLEMS_LIST: $r_failed\n";
close($pcount_fh);
#
# Set the overall result code.
# This is used to communicate back to the appcert script to
# indicate how it should exit(). The string must start with the
# exit number, after which a message may follow.
#
if ($n_checked == 0) {
overall_result_code("3 => nothing_checked");
} elsif ($n_failed > 0) {
overall_result_code("2 => some_problems_detected($n_failed)");
} elsif ($n_incomp > 0) {
overall_result_code("1 => " .
"some_binaries_incompletely_checked($n_incomp)");
} else {
overall_result_code("0 => no_problems_detected");
}
$sp0 = ' ';
if ($batch_report) {
$sp = 'PASS ';
$sf = 'FAIL ';
$si = 'INC ';
} else {
}
"The following (%d of %d) components had no problems detected:");
if ($n_passed > 0) {
$output .= "\n\n";
$output .= "${sp}$object\n";
}
$output .= "\n";
}
"The following (%d of %d) components had no problems detected,\n" .
" but could not be completely checked:");
if ($n_incomp > 0) {
$output .= "\n\n";
$output .= "${si}$object\t($msg)\n";
}
$output .= "\n";
}
"The following (%d of %d) components have potential " .
"stability problems:");
if ($n_failed > 0) {
$output .= "\n\n";
$output .= "${sf}$object\t($msg)\n";
}
$output .= "\n";
}
my $report_file = "$working_dir/Report";
open($report_fh, ">$report_file") ||
close($report_fh);
system($cmd_more, $report_file);
}
#
# Collects all of the warnings issued for the binaries that were
# checked. Returns the warning text that will go into the roll-up
# report.
#
sub get_warnings
{
if (! %warnings_found) {
return ''; # appends null string to output text
}
my(@a);
foreach $w (keys(%warnings_found)) {
$warnings_found{$w} =~ s/\|+$//;
$count = scalar(@a = split(/\|/, $warnings_found{$w}));
$c = $w;
if (defined($warnings_desc{$c})) {
$c = $warnings_desc{$c};
}
$c = gettext($c);
"(%d binaries)\n"), $count);
$output .= "\n";
}
$output .= "\n";
return $output;
}
#
# Computes the summary information for each binary object that was
# checked. Returns the text that will go into the roll-up report.
#
sub get_summary
{
my (%lib_private, %libsym_private);
my (%libapp, %libapp_private);
while (defined($dir = next_dir_name())) {
# This is where the public symbol list is:
$file = "$dir/check.dynamic.public";
my %app_public;
my %app_sym_public;
my %app_private;
my %app_sym_private;
if (-s $file) {
open($publics_fh, "<$file") ||
while (<$publics_fh>) {
next if (/^\s*#/);
chomp;
split(/\|/, $_);
$libapp{"$lib|$bin"}++;
$app_public{$lib}++;
$app_sym_public{"$lib|$sym"}++;
}
close($publics_fh);
}
# This is where the private symbol list is:
$file = "$dir/check.dynamic.private";
if (-s $file) {
open($privates_fh, "<$file") ||
while (<$privates_fh>) {
next if (/^\s*#/);
chomp;
split(/\|/, $_);
$lib_private{$lib}++;
$libsym_private{"$lib|$sym"}++;
$libapp_private{"$lib|$bin"}++;
$libapp{"$lib|$bin"}++;
$app_private{$lib}++;
$app_sym_private{"$lib|$sym"}++;
}
close($privates_fh);
}
\%app_private, \%app_sym_private);
}
my ($app_total, $app_private_total);
my $val;
my $text;
foreach $lib (sort(keys(%lib_private))) {
$app_total = 0;
}
$app_private_total = 0;
foreach $key (keys(%libapp_private)) {
}
my @list;
push(@list, "$sym2 $val");
}
$app_private_total, @list);
}
if (! defined($text)) {
return ''; # appends null string to output report.
}
return $text;
}
#
# Given the symbols and counts of private symbols used by all binaries
# that were checked, returns a pretty-printed format table of the
# symbols. This text goes into the roll-up report and the summary.dynamic
# file.
#
sub private_format
{
my $text;
"Summary of Private symbol use in %s\n"), $lib);
my $fmt =
gettext("%d binaries used %s, %d of these used private symbols");
$text .= "\n\n$formatted\n";
return $text;
}
#
# binary object, creates an output file with this information formatted
# in tables.
#
{
my $outfile = "$dir/summary.dynamic";
open($summary_fh, ">$outfile") ||
print $summary_fh "$tmp2\n$tmp1\n$tmp2\n\n";
"Binary Object: %s\n"), $path_to_object);
print $summary_fh "$tmp2\n$tmp1\n$tmp2\n\n";
$maxlen = 0;
}
if (! %libs) {
" NONE FOUND. Possible explanations:\n" .
" - the dynamic profiling failed, see ldd(1), ld.so.1(1)\n" .
" - the object is SUID or SGID\n" .
" - the object is completely statically linked.\n"
);
close($summary_fh);
return;
}
print $summary_fh " $lib\n";
}
print $summary_fh "\n";
$len2 = length($public_str);
$len3 = length(" $private_str");
$heading .= "$public_str $private_str";
$tmp3 =~ s/\S/-/g;
print $summary_fh "$tmp2\n$tmp1\n$tmp2\n\n";
print $summary_fh "$heading\n";
print $summary_fh "$tmp3\n";
$str = ' ';
}
print $summary_fh "\n";
print $summary_fh "$tmp2\n$tmp1\n$tmp2\n\n";
@pub = ();
@priv = ();
foreach $key (keys(%$sym_public)) {
}
foreach $key (keys(%$sym_private)) {
}
if (@pub) {
" %d public symbols are used:\n"), $lib2);
$text .= "\n";
}
if (@priv) {
" %d private symbols are used:\n"), $lib2);
$text .= "\n";
}
print $summary_fh $text;
}
close($summary_fh);
}