summaryrefslogtreecommitdiff
path: root/usr/src/tools/scripts/onbld_elfmod.pm
diff options
context:
space:
mode:
authorAli Bahrami <Ali.Bahrami@Sun.COM>2009-08-20 16:09:41 -0600
committerAli Bahrami <Ali.Bahrami@Sun.COM>2009-08-20 16:09:41 -0600
commit75ce41a57ff334bd8fe2cb9ed51eea835892f944 (patch)
treeb51a5ec778af45592b2d789d302c0bccbeaafed6 /usr/src/tools/scripts/onbld_elfmod.pm
parentf8cb811f5f2909e15e8d1f21f046ac459d0640e5 (diff)
downloadillumos-gate-75ce41a57ff334bd8fe2cb9ed51eea835892f944.tar.gz
6866605 SUNWonbld ELF analysis tools need overhaul
Diffstat (limited to 'usr/src/tools/scripts/onbld_elfmod.pm')
-rw-r--r--usr/src/tools/scripts/onbld_elfmod.pm333
1 files changed, 333 insertions, 0 deletions
diff --git a/usr/src/tools/scripts/onbld_elfmod.pm b/usr/src/tools/scripts/onbld_elfmod.pm
new file mode 100644
index 0000000000..7754cf9012
--- /dev/null
+++ b/usr/src/tools/scripts/onbld_elfmod.pm
@@ -0,0 +1,333 @@
+package onbld_elfmod;
+
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (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
+# or http://www.opensolaris.org/os/licensing.
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# This perl module contains code shared between the ELF analysis
+# tools found in this directory: find_elf, check_rtime, interface_check,
+# and interface_cmp.
+#
+
+use strict;
+use File::Basename;
+
+## GetLine(FileHandleRef, LineNumRef)
+#
+# Read the next non-empty line from the given file handle reference
+# and return it.
+#
+# entry:
+# FileHandleRef - Reference to open file handle to read from
+# LineNumRef - Reference to integer to increment as lines are input
+#
+sub GetLine {
+ my ($fh, $LineNum) = @_;
+ my $ret_line = '';
+ my $line;
+ my $cont = 1;
+
+ while ($cont && ($line = <$fh>)) {
+ $$LineNum++;
+ chomp $line;
+
+ # A backslash at the end of the line indicates that the
+ # following line is a continuation of this line if the
+ # backslash is the only character on the line, or if it is
+ # preceded by a space.
+ next if ($line eq '\\');
+ $cont = ($line =~ s/\s+\\$//);
+
+ # The # character starts a comment if it is the first
+ # character on the line, or if it is preceeded by a space.
+ if ($line =~ /^\#/) {
+ $cont = 1;
+ next;
+ }
+ $line =~ s/\s+\#.*$//; # Strip Comments
+ $line =~ s/\s*$//; # Trailing whitespace
+
+ if ($line !~ /^\s*$/) { # Non-empty string
+ $line =~ s/^\s+//; # Leading whitespace
+ if ($ret_line eq '') {
+ $ret_line = $line;
+ } else {
+ $ret_line = "$ret_line $line";
+ }
+ }
+
+ # If our result string is still null, act as if a
+ # continuation is present and read another line.
+ $cont = 1 if ($ret_line eq '');
+ }
+
+ # The above loop won't exit while $ret_line is a null string
+ # unless the read failed, so return undef() in that case.
+ # Otherwise, use the value in $ret_line.
+ return ($ret_line ne '') ? $ret_line : undef();
+}
+
+
+## LoadExceptionsToEXRE(name)
+#
+# Locate the exceptions file and process its contents. This function can be
+# used by any program with exception files that consist of a single
+# verb, followed by a single regular expression:
+#
+# VERB regex
+#
+# For each such verb, the global level of the main:: namespace must
+# have a variable named $EXRE_verb. The $EXRE_ prefix must only be used
+# for these variables, and not for any other. The caller must define these
+# variables, but leave them undefined.
+#
+# entry:
+# Any variables in the main:: global symbol table starting with
+# the prefix 'EXRE_xxx' are taken to represent the regular expression
+# for the exception named xxx.
+#
+# name - Name of script (i.e. 'check_rtime')
+# $main::opt{e} - Calling program must accept a '-e' option
+# that allows the user to specify an exception file
+# to use, and the value of that option must be found
+# in $main::opt{e}.
+#
+# exit:
+# The $main::EXRE_xxx variables are updated to contain any regular
+# expressions specified by the exception file. If a given exception
+# is not encountered, its variable is not modified.
+#
+# note:
+# We expand strings of the form MACH(dir) to match the given
+# directory as well as any 64-bit architecture subdirectory that
+# might be present (i.e. amd64, sparcv9).
+#
+sub LoadExceptionsToEXRE {
+ my $name = $_[0];
+ my $file;
+ my $Line;
+ my $LineNum = 0;
+ my $err = 0;
+ my %except_names = ();
+ my %except_re = ();
+
+ # Examine the main global symbol table and find all variables
+ # named EXRE_xxx. By convention established for this program,
+ # all such variables contain the regular expression for the
+ # exception named xxx.
+ foreach my $entry (keys %main::) {
+ $except_names{$entry} = 1 if $entry =~ /^EXRE_/;
+ }
+
+ # Locate the exception file
+ FILE: {
+ # If -e is specified, that file must be used
+ if ($main::opt{e}) {
+ $file = $main::opt{e};
+ last FILE;
+ }
+
+ # If this is an activated workspace, use the exception
+ # file found in the exceptions_list directory.
+ if (defined($ENV{CODEMGR_WS})) {
+ $file = "$ENV{CODEMGR_WS}/exception_lists/$name";
+ last FILE if (-f $file);
+ }
+
+ # As a final backstop, the SUNWonbld package provides a
+ # copy of the exception file. This can be useful if we
+ # are being used with an older workspace.
+ #
+ # This script is installed in the SUNWonbld bin directory,
+ # while the exception file is in etc/exception_lists. Find
+ # it relative to the script location given by $0.
+ $file = dirname($0) . "/../etc/exception_lists/$name";
+ last FILE if (-f $file);
+
+ # No exception file was found.
+ return;
+ }
+
+ open (EFILE, $file) ||
+ die "$name: unable to open exceptions file: $file";
+ while ($Line = onbld_elfmod::GetLine(\*EFILE, \$LineNum)) {
+ # Expand MACH()
+ $Line =~ s/MACH\(([^)]+)\)/$1(\/amd64|\/sparcv9)?/;
+
+ # %except_re is a hash indexed by regular expression variable
+ # name, with a value that contains the corresponding regular
+ # expression string. If we recognize an exception verb, add
+ # it to %except_re.
+ if ($Line =~ /^\s*([^\s]+)\s+(.*)$/i) {
+ my $verb = $1;
+ my $re = $2;
+
+ $verb =~ tr/A-Z/a-z/;
+ $verb = "EXRE_$verb";
+ if ($except_names{$verb}) {
+ if (defined($except_re{$verb})) {
+ $except_re{$verb} .= '|' . $re;
+ } else {
+ $except_re{$verb} = $re;
+ }
+ }
+ next;
+ }
+
+ $err++;
+ printf(STDERR "$file: Unrecognized option: ".
+ "line $LineNum: $Line\n");
+ }
+ close EFILE;
+
+ # Every exception that we encountered in the file exists
+ # in %except_re. Compile them and assign the results into the
+ # global symbol of the same name.
+ #
+ # Note that this leaves the global symbols for unused exceptions
+ # untouched, and therefore, undefined. All users of these variables
+ # are required to test them with defined() before using them.
+ foreach my $verb (sort keys %except_names) {
+ next if !defined($except_re{$verb});
+
+ # Turn off strict refs so that we can do a symbolic
+ # indirection to set the global variable of the name given
+ # by verb in the main namespace. 'strict' is lexically scoped,
+ # so its influence is limited to this enclosing block.
+ no strict 'refs';
+ ${"main::$verb"} = qr/$except_re{$verb}/;
+ }
+
+ exit 1 if ($err != 0);
+}
+
+
+## OutMsg(FileHandleRef, Ttl, obj, msg)
+## OutMsg2(FileHandleRef, Ttl, old_obj, new_obj, msg)
+#
+# Create an output message, either a one-liner (under -o) or preceded by the
+# files relative pathname as a title.
+#
+# OutMsg() is used when issuing a message about a single object.
+#
+# OutMsg2() is for when the message involves an old and new instance
+# of the same object. If old_obj and new_obj are the same, as is usually
+# the case, then the output is the same as generated by OutMsg(). If they
+# differ, as can happen when the new object has changed names, and has been
+# found via an alias, both the old and new names are shown.
+#
+# entry:
+# FileHandleRef - File handle to output file
+# Ttl - Reference to variable containing the number of times
+# this function has been called for the current object.
+# obj - For OutMsg, the path for the current object
+# old_obj, new_obj - For OutMsg2, the names of the "old" and "new"
+# objects.
+# msg - Message to output
+#
+# $main::opt{o} - Calling program must accept a '-o' option
+# that allows the user to specify "one-line-mode',
+# and the value of that option must be found
+# in $main::opt{o}.
+#
+sub OutMsg {
+ my($fh, $Ttl, $obj, $msg) = @_;
+
+ if ($main::opt{o}) {
+ print $fh "$obj: $msg\n";
+ } else {
+ print $fh "==== $obj ====\n" if ($$Ttl++ eq 0);
+ print $fh "\t$msg\n";
+ }
+}
+
+sub OutMsg2 {
+ my ($fh, $Ttl, $old_obj, $new_obj, $msg) = @_;
+
+ # If old and new are the same, give it to OutMsg()
+ if ($old_obj eq $new_obj) {
+ OutMsg($fh, $Ttl, $old_obj, $msg);
+ return;
+ }
+
+ if ($main::opt{o}) {
+ print "old $old_obj: new $new_obj: $msg\n";
+ } else {
+ print "==== old: $old_obj / new: $new_obj ====\n"
+ if ($$Ttl++ eq 0);
+ print "\t$msg\n";
+ }
+}
+
+
+## header(FileHandleRef, ScriptPath, Argv)
+#
+# Generate a header for the top of generated output, including a copyright
+# and CDDL, such that the file will pass ON copyright/CDDL rules if it is
+# checked into the repository.
+#
+# entry:
+# FileHandleRef - File handle reference to output text to
+# ScriptPath - Value of $0 from caller, giving path to running script
+# Argv - Reference to array containing @ARGV from caller.
+#
+# note:
+# We assume that the calling script contains a value CDDL block.
+#
+sub Header {
+
+ my ($fh, $ScriptPath, $Argv) = @_;
+ my $year = 1900 + (localtime())[5];
+
+ print $fh "#\n";
+ print $fh "# Copyright $year Sun Microsystems, Inc. ",
+ "All rights reserved.\n";
+ print $fh "# Use is subject to license terms.\n#\n";
+
+ # The CDDL text is copied from this script, the path to which is
+ # assigned to $0 by the Perl interpreter.
+ if (open(CDDL, $ScriptPath)) {
+ my $out = 0;
+ my $Line;
+
+ while ($Line = <CDDL>) {
+ $out = 1 if ($Line =~ /^\# CDDL HEADER START/);
+
+ print $fh $Line if $out;
+ last if ($Line =~ /^\# CDDL HEADER END/);
+ }
+ print $fh "#\n\n";
+ close CDDL;
+ }
+
+ print $fh '# Date: ', scalar(localtime()), "\n";
+ $ScriptPath =~ s/^.*\///;
+ $ScriptPath =~ s/\.pl$//;
+ print $fh "# Command: $ScriptPath ", join(' ', @$Argv), "\n\n";
+}
+
+# Perl modules pulled in via 'require' must return an exit status.
+1;