xref: /titanic_51/usr/src/tools/scripts/onbld_elfmod.pm (revision 75ce41a57ff334bd8fe2cb9ed51eea835892f944)
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