1*75ce41a5SAli Bahramipackage onbld_elfmod; 2*75ce41a5SAli Bahrami 3*75ce41a5SAli Bahrami# 4*75ce41a5SAli Bahrami# CDDL HEADER START 5*75ce41a5SAli Bahrami# 6*75ce41a5SAli Bahrami# The contents of this file are subject to the terms of the 7*75ce41a5SAli Bahrami# Common Development and Distribution License (the "License"). 8*75ce41a5SAli Bahrami# You may not use this file except in compliance with the License. 9*75ce41a5SAli Bahrami# 10*75ce41a5SAli Bahrami# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 11*75ce41a5SAli Bahrami# or http://www.opensolaris.org/os/licensing. 12*75ce41a5SAli Bahrami# See the License for the specific language governing permissions 13*75ce41a5SAli Bahrami# and limitations under the License. 14*75ce41a5SAli Bahrami# 15*75ce41a5SAli Bahrami# When distributing Covered Code, include this CDDL HEADER in each 16*75ce41a5SAli Bahrami# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 17*75ce41a5SAli Bahrami# If applicable, add the following below this CDDL HEADER, with the 18*75ce41a5SAli Bahrami# fields enclosed by brackets "[]" replaced with your own identifying 19*75ce41a5SAli Bahrami# information: Portions Copyright [yyyy] [name of copyright owner] 20*75ce41a5SAli Bahrami# 21*75ce41a5SAli Bahrami# CDDL HEADER END 22*75ce41a5SAli Bahrami# 23*75ce41a5SAli Bahrami 24*75ce41a5SAli Bahrami# 25*75ce41a5SAli Bahrami# Copyright 2009 Sun Microsystems, Inc. All rights reserved. 26*75ce41a5SAli Bahrami# Use is subject to license terms. 27*75ce41a5SAli Bahrami# 28*75ce41a5SAli Bahrami 29*75ce41a5SAli Bahrami# 30*75ce41a5SAli Bahrami# This perl module contains code shared between the ELF analysis 31*75ce41a5SAli Bahrami# tools found in this directory: find_elf, check_rtime, interface_check, 32*75ce41a5SAli Bahrami# and interface_cmp. 33*75ce41a5SAli Bahrami# 34*75ce41a5SAli Bahrami 35*75ce41a5SAli Bahramiuse strict; 36*75ce41a5SAli Bahramiuse File::Basename; 37*75ce41a5SAli Bahrami 38*75ce41a5SAli Bahrami## GetLine(FileHandleRef, LineNumRef) 39*75ce41a5SAli Bahrami# 40*75ce41a5SAli Bahrami# Read the next non-empty line from the given file handle reference 41*75ce41a5SAli Bahrami# and return it. 42*75ce41a5SAli Bahrami# 43*75ce41a5SAli Bahrami# entry: 44*75ce41a5SAli Bahrami# FileHandleRef - Reference to open file handle to read from 45*75ce41a5SAli Bahrami# LineNumRef - Reference to integer to increment as lines are input 46*75ce41a5SAli Bahrami# 47*75ce41a5SAli Bahramisub GetLine { 48*75ce41a5SAli Bahrami my ($fh, $LineNum) = @_; 49*75ce41a5SAli Bahrami my $ret_line = ''; 50*75ce41a5SAli Bahrami my $line; 51*75ce41a5SAli Bahrami my $cont = 1; 52*75ce41a5SAli Bahrami 53*75ce41a5SAli Bahrami while ($cont && ($line = <$fh>)) { 54*75ce41a5SAli Bahrami $$LineNum++; 55*75ce41a5SAli Bahrami chomp $line; 56*75ce41a5SAli Bahrami 57*75ce41a5SAli Bahrami # A backslash at the end of the line indicates that the 58*75ce41a5SAli Bahrami # following line is a continuation of this line if the 59*75ce41a5SAli Bahrami # backslash is the only character on the line, or if it is 60*75ce41a5SAli Bahrami # preceded by a space. 61*75ce41a5SAli Bahrami next if ($line eq '\\'); 62*75ce41a5SAli Bahrami $cont = ($line =~ s/\s+\\$//); 63*75ce41a5SAli Bahrami 64*75ce41a5SAli Bahrami # The # character starts a comment if it is the first 65*75ce41a5SAli Bahrami # character on the line, or if it is preceeded by a space. 66*75ce41a5SAli Bahrami if ($line =~ /^\#/) { 67*75ce41a5SAli Bahrami $cont = 1; 68*75ce41a5SAli Bahrami next; 69*75ce41a5SAli Bahrami } 70*75ce41a5SAli Bahrami $line =~ s/\s+\#.*$//; # Strip Comments 71*75ce41a5SAli Bahrami $line =~ s/\s*$//; # Trailing whitespace 72*75ce41a5SAli Bahrami 73*75ce41a5SAli Bahrami if ($line !~ /^\s*$/) { # Non-empty string 74*75ce41a5SAli Bahrami $line =~ s/^\s+//; # Leading whitespace 75*75ce41a5SAli Bahrami if ($ret_line eq '') { 76*75ce41a5SAli Bahrami $ret_line = $line; 77*75ce41a5SAli Bahrami } else { 78*75ce41a5SAli Bahrami $ret_line = "$ret_line $line"; 79*75ce41a5SAli Bahrami } 80*75ce41a5SAli Bahrami } 81*75ce41a5SAli Bahrami 82*75ce41a5SAli Bahrami # If our result string is still null, act as if a 83*75ce41a5SAli Bahrami # continuation is present and read another line. 84*75ce41a5SAli Bahrami $cont = 1 if ($ret_line eq ''); 85*75ce41a5SAli Bahrami } 86*75ce41a5SAli Bahrami 87*75ce41a5SAli Bahrami # The above loop won't exit while $ret_line is a null string 88*75ce41a5SAli Bahrami # unless the read failed, so return undef() in that case. 89*75ce41a5SAli Bahrami # Otherwise, use the value in $ret_line. 90*75ce41a5SAli Bahrami return ($ret_line ne '') ? $ret_line : undef(); 91*75ce41a5SAli Bahrami} 92*75ce41a5SAli Bahrami 93*75ce41a5SAli Bahrami 94*75ce41a5SAli Bahrami## LoadExceptionsToEXRE(name) 95*75ce41a5SAli Bahrami# 96*75ce41a5SAli Bahrami# Locate the exceptions file and process its contents. This function can be 97*75ce41a5SAli Bahrami# used by any program with exception files that consist of a single 98*75ce41a5SAli Bahrami# verb, followed by a single regular expression: 99*75ce41a5SAli Bahrami# 100*75ce41a5SAli Bahrami# VERB regex 101*75ce41a5SAli Bahrami# 102*75ce41a5SAli Bahrami# For each such verb, the global level of the main:: namespace must 103*75ce41a5SAli Bahrami# have a variable named $EXRE_verb. The $EXRE_ prefix must only be used 104*75ce41a5SAli Bahrami# for these variables, and not for any other. The caller must define these 105*75ce41a5SAli Bahrami# variables, but leave them undefined. 106*75ce41a5SAli Bahrami# 107*75ce41a5SAli Bahrami# entry: 108*75ce41a5SAli Bahrami# Any variables in the main:: global symbol table starting with 109*75ce41a5SAli Bahrami# the prefix 'EXRE_xxx' are taken to represent the regular expression 110*75ce41a5SAli Bahrami# for the exception named xxx. 111*75ce41a5SAli Bahrami# 112*75ce41a5SAli Bahrami# name - Name of script (i.e. 'check_rtime') 113*75ce41a5SAli Bahrami# $main::opt{e} - Calling program must accept a '-e' option 114*75ce41a5SAli Bahrami# that allows the user to specify an exception file 115*75ce41a5SAli Bahrami# to use, and the value of that option must be found 116*75ce41a5SAli Bahrami# in $main::opt{e}. 117*75ce41a5SAli Bahrami# 118*75ce41a5SAli Bahrami# exit: 119*75ce41a5SAli Bahrami# The $main::EXRE_xxx variables are updated to contain any regular 120*75ce41a5SAli Bahrami# expressions specified by the exception file. If a given exception 121*75ce41a5SAli Bahrami# is not encountered, its variable is not modified. 122*75ce41a5SAli Bahrami# 123*75ce41a5SAli Bahrami# note: 124*75ce41a5SAli Bahrami# We expand strings of the form MACH(dir) to match the given 125*75ce41a5SAli Bahrami# directory as well as any 64-bit architecture subdirectory that 126*75ce41a5SAli Bahrami# might be present (i.e. amd64, sparcv9). 127*75ce41a5SAli Bahrami# 128*75ce41a5SAli Bahramisub LoadExceptionsToEXRE { 129*75ce41a5SAli Bahrami my $name = $_[0]; 130*75ce41a5SAli Bahrami my $file; 131*75ce41a5SAli Bahrami my $Line; 132*75ce41a5SAli Bahrami my $LineNum = 0; 133*75ce41a5SAli Bahrami my $err = 0; 134*75ce41a5SAli Bahrami my %except_names = (); 135*75ce41a5SAli Bahrami my %except_re = (); 136*75ce41a5SAli Bahrami 137*75ce41a5SAli Bahrami # Examine the main global symbol table and find all variables 138*75ce41a5SAli Bahrami # named EXRE_xxx. By convention established for this program, 139*75ce41a5SAli Bahrami # all such variables contain the regular expression for the 140*75ce41a5SAli Bahrami # exception named xxx. 141*75ce41a5SAli Bahrami foreach my $entry (keys %main::) { 142*75ce41a5SAli Bahrami $except_names{$entry} = 1 if $entry =~ /^EXRE_/; 143*75ce41a5SAli Bahrami } 144*75ce41a5SAli Bahrami 145*75ce41a5SAli Bahrami # Locate the exception file 146*75ce41a5SAli Bahrami FILE: { 147*75ce41a5SAli Bahrami # If -e is specified, that file must be used 148*75ce41a5SAli Bahrami if ($main::opt{e}) { 149*75ce41a5SAli Bahrami $file = $main::opt{e}; 150*75ce41a5SAli Bahrami last FILE; 151*75ce41a5SAli Bahrami } 152*75ce41a5SAli Bahrami 153*75ce41a5SAli Bahrami # If this is an activated workspace, use the exception 154*75ce41a5SAli Bahrami # file found in the exceptions_list directory. 155*75ce41a5SAli Bahrami if (defined($ENV{CODEMGR_WS})) { 156*75ce41a5SAli Bahrami $file = "$ENV{CODEMGR_WS}/exception_lists/$name"; 157*75ce41a5SAli Bahrami last FILE if (-f $file); 158*75ce41a5SAli Bahrami } 159*75ce41a5SAli Bahrami 160*75ce41a5SAli Bahrami # As a final backstop, the SUNWonbld package provides a 161*75ce41a5SAli Bahrami # copy of the exception file. This can be useful if we 162*75ce41a5SAli Bahrami # are being used with an older workspace. 163*75ce41a5SAli Bahrami # 164*75ce41a5SAli Bahrami # This script is installed in the SUNWonbld bin directory, 165*75ce41a5SAli Bahrami # while the exception file is in etc/exception_lists. Find 166*75ce41a5SAli Bahrami # it relative to the script location given by $0. 167*75ce41a5SAli Bahrami $file = dirname($0) . "/../etc/exception_lists/$name"; 168*75ce41a5SAli Bahrami last FILE if (-f $file); 169*75ce41a5SAli Bahrami 170*75ce41a5SAli Bahrami # No exception file was found. 171*75ce41a5SAli Bahrami return; 172*75ce41a5SAli Bahrami } 173*75ce41a5SAli Bahrami 174*75ce41a5SAli Bahrami open (EFILE, $file) || 175*75ce41a5SAli Bahrami die "$name: unable to open exceptions file: $file"; 176*75ce41a5SAli Bahrami while ($Line = onbld_elfmod::GetLine(\*EFILE, \$LineNum)) { 177*75ce41a5SAli Bahrami # Expand MACH() 178*75ce41a5SAli Bahrami $Line =~ s/MACH\(([^)]+)\)/$1(\/amd64|\/sparcv9)?/; 179*75ce41a5SAli Bahrami 180*75ce41a5SAli Bahrami # %except_re is a hash indexed by regular expression variable 181*75ce41a5SAli Bahrami # name, with a value that contains the corresponding regular 182*75ce41a5SAli Bahrami # expression string. If we recognize an exception verb, add 183*75ce41a5SAli Bahrami # it to %except_re. 184*75ce41a5SAli Bahrami if ($Line =~ /^\s*([^\s]+)\s+(.*)$/i) { 185*75ce41a5SAli Bahrami my $verb = $1; 186*75ce41a5SAli Bahrami my $re = $2; 187*75ce41a5SAli Bahrami 188*75ce41a5SAli Bahrami $verb =~ tr/A-Z/a-z/; 189*75ce41a5SAli Bahrami $verb = "EXRE_$verb"; 190*75ce41a5SAli Bahrami if ($except_names{$verb}) { 191*75ce41a5SAli Bahrami if (defined($except_re{$verb})) { 192*75ce41a5SAli Bahrami $except_re{$verb} .= '|' . $re; 193*75ce41a5SAli Bahrami } else { 194*75ce41a5SAli Bahrami $except_re{$verb} = $re; 195*75ce41a5SAli Bahrami } 196*75ce41a5SAli Bahrami } 197*75ce41a5SAli Bahrami next; 198*75ce41a5SAli Bahrami } 199*75ce41a5SAli Bahrami 200*75ce41a5SAli Bahrami $err++; 201*75ce41a5SAli Bahrami printf(STDERR "$file: Unrecognized option: ". 202*75ce41a5SAli Bahrami "line $LineNum: $Line\n"); 203*75ce41a5SAli Bahrami } 204*75ce41a5SAli Bahrami close EFILE; 205*75ce41a5SAli Bahrami 206*75ce41a5SAli Bahrami # Every exception that we encountered in the file exists 207*75ce41a5SAli Bahrami # in %except_re. Compile them and assign the results into the 208*75ce41a5SAli Bahrami # global symbol of the same name. 209*75ce41a5SAli Bahrami # 210*75ce41a5SAli Bahrami # Note that this leaves the global symbols for unused exceptions 211*75ce41a5SAli Bahrami # untouched, and therefore, undefined. All users of these variables 212*75ce41a5SAli Bahrami # are required to test them with defined() before using them. 213*75ce41a5SAli Bahrami foreach my $verb (sort keys %except_names) { 214*75ce41a5SAli Bahrami next if !defined($except_re{$verb}); 215*75ce41a5SAli Bahrami 216*75ce41a5SAli Bahrami # Turn off strict refs so that we can do a symbolic 217*75ce41a5SAli Bahrami # indirection to set the global variable of the name given 218*75ce41a5SAli Bahrami # by verb in the main namespace. 'strict' is lexically scoped, 219*75ce41a5SAli Bahrami # so its influence is limited to this enclosing block. 220*75ce41a5SAli Bahrami no strict 'refs'; 221*75ce41a5SAli Bahrami ${"main::$verb"} = qr/$except_re{$verb}/; 222*75ce41a5SAli Bahrami } 223*75ce41a5SAli Bahrami 224*75ce41a5SAli Bahrami exit 1 if ($err != 0); 225*75ce41a5SAli Bahrami} 226*75ce41a5SAli Bahrami 227*75ce41a5SAli Bahrami 228*75ce41a5SAli Bahrami## OutMsg(FileHandleRef, Ttl, obj, msg) 229*75ce41a5SAli Bahrami## OutMsg2(FileHandleRef, Ttl, old_obj, new_obj, msg) 230*75ce41a5SAli Bahrami# 231*75ce41a5SAli Bahrami# Create an output message, either a one-liner (under -o) or preceded by the 232*75ce41a5SAli Bahrami# files relative pathname as a title. 233*75ce41a5SAli Bahrami# 234*75ce41a5SAli Bahrami# OutMsg() is used when issuing a message about a single object. 235*75ce41a5SAli Bahrami# 236*75ce41a5SAli Bahrami# OutMsg2() is for when the message involves an old and new instance 237*75ce41a5SAli Bahrami# of the same object. If old_obj and new_obj are the same, as is usually 238*75ce41a5SAli Bahrami# the case, then the output is the same as generated by OutMsg(). If they 239*75ce41a5SAli Bahrami# differ, as can happen when the new object has changed names, and has been 240*75ce41a5SAli Bahrami# found via an alias, both the old and new names are shown. 241*75ce41a5SAli Bahrami# 242*75ce41a5SAli Bahrami# entry: 243*75ce41a5SAli Bahrami# FileHandleRef - File handle to output file 244*75ce41a5SAli Bahrami# Ttl - Reference to variable containing the number of times 245*75ce41a5SAli Bahrami# this function has been called for the current object. 246*75ce41a5SAli Bahrami# obj - For OutMsg, the path for the current object 247*75ce41a5SAli Bahrami# old_obj, new_obj - For OutMsg2, the names of the "old" and "new" 248*75ce41a5SAli Bahrami# objects. 249*75ce41a5SAli Bahrami# msg - Message to output 250*75ce41a5SAli Bahrami# 251*75ce41a5SAli Bahrami# $main::opt{o} - Calling program must accept a '-o' option 252*75ce41a5SAli Bahrami# that allows the user to specify "one-line-mode', 253*75ce41a5SAli Bahrami# and the value of that option must be found 254*75ce41a5SAli Bahrami# in $main::opt{o}. 255*75ce41a5SAli Bahrami# 256*75ce41a5SAli Bahramisub OutMsg { 257*75ce41a5SAli Bahrami my($fh, $Ttl, $obj, $msg) = @_; 258*75ce41a5SAli Bahrami 259*75ce41a5SAli Bahrami if ($main::opt{o}) { 260*75ce41a5SAli Bahrami print $fh "$obj: $msg\n"; 261*75ce41a5SAli Bahrami } else { 262*75ce41a5SAli Bahrami print $fh "==== $obj ====\n" if ($$Ttl++ eq 0); 263*75ce41a5SAli Bahrami print $fh "\t$msg\n"; 264*75ce41a5SAli Bahrami } 265*75ce41a5SAli Bahrami} 266*75ce41a5SAli Bahrami 267*75ce41a5SAli Bahramisub OutMsg2 { 268*75ce41a5SAli Bahrami my ($fh, $Ttl, $old_obj, $new_obj, $msg) = @_; 269*75ce41a5SAli Bahrami 270*75ce41a5SAli Bahrami # If old and new are the same, give it to OutMsg() 271*75ce41a5SAli Bahrami if ($old_obj eq $new_obj) { 272*75ce41a5SAli Bahrami OutMsg($fh, $Ttl, $old_obj, $msg); 273*75ce41a5SAli Bahrami return; 274*75ce41a5SAli Bahrami } 275*75ce41a5SAli Bahrami 276*75ce41a5SAli Bahrami if ($main::opt{o}) { 277*75ce41a5SAli Bahrami print "old $old_obj: new $new_obj: $msg\n"; 278*75ce41a5SAli Bahrami } else { 279*75ce41a5SAli Bahrami print "==== old: $old_obj / new: $new_obj ====\n" 280*75ce41a5SAli Bahrami if ($$Ttl++ eq 0); 281*75ce41a5SAli Bahrami print "\t$msg\n"; 282*75ce41a5SAli Bahrami } 283*75ce41a5SAli Bahrami} 284*75ce41a5SAli Bahrami 285*75ce41a5SAli Bahrami 286*75ce41a5SAli Bahrami## header(FileHandleRef, ScriptPath, Argv) 287*75ce41a5SAli Bahrami# 288*75ce41a5SAli Bahrami# Generate a header for the top of generated output, including a copyright 289*75ce41a5SAli Bahrami# and CDDL, such that the file will pass ON copyright/CDDL rules if it is 290*75ce41a5SAli Bahrami# checked into the repository. 291*75ce41a5SAli Bahrami# 292*75ce41a5SAli Bahrami# entry: 293*75ce41a5SAli Bahrami# FileHandleRef - File handle reference to output text to 294*75ce41a5SAli Bahrami# ScriptPath - Value of $0 from caller, giving path to running script 295*75ce41a5SAli Bahrami# Argv - Reference to array containing @ARGV from caller. 296*75ce41a5SAli Bahrami# 297*75ce41a5SAli Bahrami# note: 298*75ce41a5SAli Bahrami# We assume that the calling script contains a value CDDL block. 299*75ce41a5SAli Bahrami# 300*75ce41a5SAli Bahramisub Header { 301*75ce41a5SAli Bahrami 302*75ce41a5SAli Bahrami my ($fh, $ScriptPath, $Argv) = @_; 303*75ce41a5SAli Bahrami my $year = 1900 + (localtime())[5]; 304*75ce41a5SAli Bahrami 305*75ce41a5SAli Bahrami print $fh "#\n"; 306*75ce41a5SAli Bahrami print $fh "# Copyright $year Sun Microsystems, Inc. ", 307*75ce41a5SAli Bahrami "All rights reserved.\n"; 308*75ce41a5SAli Bahrami print $fh "# Use is subject to license terms.\n#\n"; 309*75ce41a5SAli Bahrami 310*75ce41a5SAli Bahrami # The CDDL text is copied from this script, the path to which is 311*75ce41a5SAli Bahrami # assigned to $0 by the Perl interpreter. 312*75ce41a5SAli Bahrami if (open(CDDL, $ScriptPath)) { 313*75ce41a5SAli Bahrami my $out = 0; 314*75ce41a5SAli Bahrami my $Line; 315*75ce41a5SAli Bahrami 316*75ce41a5SAli Bahrami while ($Line = <CDDL>) { 317*75ce41a5SAli Bahrami $out = 1 if ($Line =~ /^\# CDDL HEADER START/); 318*75ce41a5SAli Bahrami 319*75ce41a5SAli Bahrami print $fh $Line if $out; 320*75ce41a5SAli Bahrami last if ($Line =~ /^\# CDDL HEADER END/); 321*75ce41a5SAli Bahrami } 322*75ce41a5SAli Bahrami print $fh "#\n\n"; 323*75ce41a5SAli Bahrami close CDDL; 324*75ce41a5SAli Bahrami } 325*75ce41a5SAli Bahrami 326*75ce41a5SAli Bahrami print $fh '# Date: ', scalar(localtime()), "\n"; 327*75ce41a5SAli Bahrami $ScriptPath =~ s/^.*\///; 328*75ce41a5SAli Bahrami $ScriptPath =~ s/\.pl$//; 329*75ce41a5SAli Bahrami print $fh "# Command: $ScriptPath ", join(' ', @$Argv), "\n\n"; 330*75ce41a5SAli Bahrami} 331*75ce41a5SAli Bahrami 332*75ce41a5SAli Bahrami# Perl modules pulled in via 'require' must return an exit status. 333*75ce41a5SAli Bahrami1; 334