1#!/bin/perl
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License, Version 1.0 only
7# (the "License").  You may not use this file except in compliance
8# with the License.
9#
10# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11# or http://www.opensolaris.org/os/licensing.
12# See the License for the specific language governing permissions
13# and limitations under the License.
14#
15# When distributing Covered Code, include this CDDL HEADER in each
16# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17# If applicable, add the following below this CDDL HEADER, with the
18# fields enclosed by brackets "[]" replaced with your own identifying
19# information: Portions Copyright [yyyy] [name of copyright owner]
20#
21# CDDL HEADER END
22#
23#
24# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
25# Use is subject to license terms.
26#
27# ident	"%Z%%M%	%I%	%E% SMI"
28#
29
30#
31# ctfstabs requires an object file with CTF data, and a file containing
32# directives which indicate the types and members for which offsets are to
33# be generated.  The developer provides a single input file containing both
34# the #include directives used to generate the object file as well as the
35# offset directives.  This script automates the splitting of the master file,
36# the generation of the object file, the invocation of ctfstabs, and cleanup.
37#
38
39use strict;
40use warnings;
41use File::Basename;
42use Getopt::Std;
43use POSIX qw(:sys_wait_h);
44
45# Globals.
46our $PROGNAME = basename($0);
47our ($CTmp, $OTmp, $GenTmp, $GenPPTmp, $Keep, $Verbose);
48
49sub usage {
50	print STDERR "Usage: $PROGNAME [-k] [-s ctfstabs] [-r ctfconvert] ",
51	  "compiler [options]\n";
52	print STDERR "  NOTE: compiler options must enable stabs or DWARF as ",
53	  "appropriate\n";
54	exit(2);
55}
56
57sub cleanup {
58	return if ($Keep);
59
60	unlink($CTmp) if (-f $CTmp);
61	unlink($OTmp) if (-f $OTmp);
62	unlink($GenTmp) if (-f $GenTmp);
63	unlink($GenPPTmp) if (-f $GenPPTmp);
64}
65
66sub bail {
67	print STDERR "$PROGNAME: ", join(" ", @_), "\n";
68	cleanup();
69	exit(1);
70}
71
72
73sub findprog {
74	my ($arg, $name, $default) = @_;
75
76	if (defined $arg) {
77		return ($arg);
78	} elsif (defined $ENV{$name}) {
79		return ($ENV{$name});
80	} else {
81		return ($default);
82	}
83}
84
85sub runit {
86	my (@argv) = @_;
87	my $rc;
88
89	if ($Verbose) {
90		print STDERR "+ @argv\n";
91	}
92	if ((my $rc = system(@argv)) == -1) {
93		bail("Failed to execute $argv[0]: $!");
94	} elsif (WIFEXITED($rc)) {
95		$_ = WEXITSTATUS($rc);
96		if ($_ == 0) {
97			return;
98		} else {
99			bail("$argv[0] failed with status $_");
100		}
101	} elsif (WSIGNALLED($rc)) {
102		$_ = WTERMSIG($rc);
103		# WCOREDUMP isn't a POSIX macro, do it the non-portable way.
104		if ($rc & 0x80) {
105			bail("$argv[0] failed with signal $_ (core dumped)");
106		} else {
107			bail("$argv[0] failed with signal $_");
108		}
109	}
110}
111
112#
113# Main.
114#
115
116my %opts;
117getopts("kr:s:v", \%opts) || usage();
118usage() if (@ARGV < 1);
119
120my $ctfstabs = findprog($opts{"s"}, "CTFSTABS", "ctfstabs");
121my $ctfconvert = findprog($opts{"r"}, "CTFCONVERT", "ctfconvert");
122
123$Keep = $opts{k};
124$Verbose = $opts{k} || $opts{v};
125my ($cc, @cflags) = @ARGV;
126
127$CTmp = "ctfstabs.tmp.$$.c";		# The C file used to generate CTF
128$OTmp = "ctfstabs.tmp.$$.o";		# Object file with CTF
129$GenTmp = "ctfstabs.tmp.$$.gen.c";	# genassym directives
130$GenPPTmp = "ctfstabs.tmp.$$.genpp";	# Post-processed genassym directives
131
132my ($cfile, $genfile);
133open($cfile, '>', $CTmp) || bail("failed to create $CTmp: $!");
134open($genfile, '>', $GenTmp) || bail("failed to create $GenTmp: $!");
135
136if ($Verbose) {
137	print STDERR "Splitting from stdin to $CTmp and $GenTmp\n";
138}
139
140while (<STDIN>) {
141	# #includes go to the C file.  All other preprocessor directives
142	# go to both the C file and the offsets input file.  Anything
143	# that's not a preprocessor directive goes into the offsets input
144	# file.  Also strip comments from the genfile, as they can confuse
145	# the preprocessor.
146	if (/^#include/) {
147		print $cfile $_;
148	} elsif (/^#/) {
149		print $cfile $_;
150		print $genfile $_;
151	} elsif (/^\\#/) {
152		print $genfile $_;
153	} elsif (!/^\\/) {
154		print $genfile $_;
155	}
156}
157close($cfile) || bail("can't close $CTmp: $!");
158close($genfile) || bail("can't close $GenTmp: $!");
159
160# Compile the C file.
161runit($cc, @cflags, '-c', '-o', $OTmp, $CTmp);
162
163# Convert the debugging information to CTF.
164runit($ctfconvert, '-l', 'ctfstabs', $OTmp);
165
166# Run ctfstabs on the resulting mess.
167runit($cc, @cflags, "-P", "-o", "$GenPPTmp", $GenTmp);
168runit($ctfstabs, "-t", "genassym", "-i", $GenPPTmp, $OTmp);
169
170cleanup();
171
172exit (0);
173