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