1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1997-2001 by Sun Microsystems, Inc.
24*7c478bd9Sstevel@tonic-gate  * All rights reserved.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  *
31*7c478bd9Sstevel@tonic-gate  * trace.c -- a  simple translator from spec source to c source for
32*7c478bd9Sstevel@tonic-gate  *	a apptrace interposer library.  This file implements the
33*7c478bd9Sstevel@tonic-gate  *	(interface to) the front end. Other files implement the middle
34*7c478bd9Sstevel@tonic-gate  *	and databases, and generate.c implements the back end.
35*7c478bd9Sstevel@tonic-gate  *
36*7c478bd9Sstevel@tonic-gate  */
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate #include <stdio.h>
39*7c478bd9Sstevel@tonic-gate #include <errno.h>
40*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
42*7c478bd9Sstevel@tonic-gate #include <time.h>
43*7c478bd9Sstevel@tonic-gate #include <string.h>
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate #include "parser.h"
46*7c478bd9Sstevel@tonic-gate #include "trace.h"
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate #include "util.h"
49*7c478bd9Sstevel@tonic-gate #include "db.h"
50*7c478bd9Sstevel@tonic-gate #include "symtab.h"
51*7c478bd9Sstevel@tonic-gate #include "io.h"
52*7c478bd9Sstevel@tonic-gate #include "printfuncs.h"
53*7c478bd9Sstevel@tonic-gate #include "errlog.h"
54*7c478bd9Sstevel@tonic-gate #include "parseproto.h"
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate static int  Verbose;
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate /* File globals. This would be better as a class. */
59*7c478bd9Sstevel@tonic-gate /* The first four (commented out) of these enums are defined in parser.h */
60*7c478bd9Sstevel@tonic-gate enum {
61*7c478bd9Sstevel@tonic-gate 	/* XLATOR_KW_NOTFOUND = 0, */
62*7c478bd9Sstevel@tonic-gate 	/* XLATOR_KW_FUNC, */
63*7c478bd9Sstevel@tonic-gate 	/* XLATOR_KW_DATA */
64*7c478bd9Sstevel@tonic-gate 	/* XLATOR_KW_END */
65*7c478bd9Sstevel@tonic-gate 	XLATOR_KW_EXCP = 4,
66*7c478bd9Sstevel@tonic-gate 	XLATOR_KW_DECL,
67*7c478bd9Sstevel@tonic-gate 	XLATOR_KW_INCL,
68*7c478bd9Sstevel@tonic-gate 	XLATOR_KW_ERRNO,
69*7c478bd9Sstevel@tonic-gate 	XLATOR_KW_ERRVAL,
70*7c478bd9Sstevel@tonic-gate 	XLATOR_KW_ARCH,
71*7c478bd9Sstevel@tonic-gate 	XLATOR_KW_WEAK
72*7c478bd9Sstevel@tonic-gate };
73*7c478bd9Sstevel@tonic-gate #define	FIRST_TOKEN 4	/* Must match the first token in the above enum */
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate static xlator_keyword_t Keywords[] = {
76*7c478bd9Sstevel@tonic-gate 	{ "exception", XLATOR_KW_EXCP },
77*7c478bd9Sstevel@tonic-gate 	{ "declaration", XLATOR_KW_DECL },
78*7c478bd9Sstevel@tonic-gate 	{ "include", XLATOR_KW_INCL },
79*7c478bd9Sstevel@tonic-gate 	{ "errno", XLATOR_KW_ERRNO },
80*7c478bd9Sstevel@tonic-gate 	{ "errval", XLATOR_KW_ERRVAL},
81*7c478bd9Sstevel@tonic-gate 	{ "arch", XLATOR_KW_ARCH},
82*7c478bd9Sstevel@tonic-gate 	{ "weak", XLATOR_KW_WEAK},
83*7c478bd9Sstevel@tonic-gate 	{ "weakfor", XLATOR_KW_WEAK},
84*7c478bd9Sstevel@tonic-gate 	{ "alias", XLATOR_KW_WEAK},
85*7c478bd9Sstevel@tonic-gate 	{ NULL, XLATOR_KW_NOTFOUND }
86*7c478bd9Sstevel@tonic-gate };
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate static struct stats_t {
89*7c478bd9Sstevel@tonic-gate 	int	libraries,
90*7c478bd9Sstevel@tonic-gate 		files,
91*7c478bd9Sstevel@tonic-gate 		interfaces,
92*7c478bd9Sstevel@tonic-gate 		lines;
93*7c478bd9Sstevel@tonic-gate 	int	errors,
94*7c478bd9Sstevel@tonic-gate 		warnings,
95*7c478bd9Sstevel@tonic-gate 		skips;
96*7c478bd9Sstevel@tonic-gate 	time_t	start,
97*7c478bd9Sstevel@tonic-gate 		end;
98*7c478bd9Sstevel@tonic-gate } Statistics;
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate #define	LINE	(m.mi_line_number-(m.mi_nlines-1))
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate static void stats_init(void);
103*7c478bd9Sstevel@tonic-gate static void stats_report(void);
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate static int collect_binding(int const, char *, int);
106*7c478bd9Sstevel@tonic-gate static int collect_prototype(char *, int, int);
107*7c478bd9Sstevel@tonic-gate static int collect_include(char *, int);
108*7c478bd9Sstevel@tonic-gate static int collect_errval(char *, int);
109*7c478bd9Sstevel@tonic-gate static int collect_arch(char *);
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate static void generate_includes(void);
112*7c478bd9Sstevel@tonic-gate static void generate_init(void);
113*7c478bd9Sstevel@tonic-gate static void generate_interface(void);
114*7c478bd9Sstevel@tonic-gate static void generate_closedown(void);
115*7c478bd9Sstevel@tonic-gate static int generate_aux_file();
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate /* Local (static) parsing functions. */
118*7c478bd9Sstevel@tonic-gate static char *to_actual();
119*7c478bd9Sstevel@tonic-gate static int to_basetype(char *);
120*7c478bd9Sstevel@tonic-gate static char *de_const(char *);
121*7c478bd9Sstevel@tonic-gate static char *strpqcpy(char *, char *, char *);
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate /*
124*7c478bd9Sstevel@tonic-gate  * xlator_init -- initialize translator, called at startup-time
125*7c478bd9Sstevel@tonic-gate  *	with a struct translator_info of information the translator
126*7c478bd9Sstevel@tonic-gate  *	might need, returning a list of ``interesting'' spec keywords
127*7c478bd9Sstevel@tonic-gate  *	for the front end to select and pass to the back end translator.
128*7c478bd9Sstevel@tonic-gate  *
129*7c478bd9Sstevel@tonic-gate  */
130*7c478bd9Sstevel@tonic-gate xlator_keyword_t *
131*7c478bd9Sstevel@tonic-gate xlator_init(const Translator_info *t_info)
132*7c478bd9Sstevel@tonic-gate {
133*7c478bd9Sstevel@tonic-gate 	int	i;
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "xlator_init() {");
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate 	/* Save interesting parameters. */
138*7c478bd9Sstevel@tonic-gate 	stats_init();
139*7c478bd9Sstevel@tonic-gate 	db_set_source_directory(".");
140*7c478bd9Sstevel@tonic-gate 	db_set_target_directory(".");
141*7c478bd9Sstevel@tonic-gate 	Verbose = t_info->ti_verbosity;
142*7c478bd9Sstevel@tonic-gate 	seterrseverity(Verbose); /* Ditto. */
143*7c478bd9Sstevel@tonic-gate 	db_set_output_file(t_info->ti_output_file);
144*7c478bd9Sstevel@tonic-gate 	db_set_arch(t_info->ti_arch);
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate 	/* Display passed argument and return value. */
147*7c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "Keywords[] = {");
148*7c478bd9Sstevel@tonic-gate 	for (i = 0; Keywords[i].key != NULL; i++) {
149*7c478bd9Sstevel@tonic-gate 		errlog(VERBOSE, "    \"%s\", ", Keywords[i].key);
150*7c478bd9Sstevel@tonic-gate 	}
151*7c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "    (char *) NULL");
152*7c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "};");
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
155*7c478bd9Sstevel@tonic-gate 	return (Keywords);
156*7c478bd9Sstevel@tonic-gate }
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate /*
159*7c478bd9Sstevel@tonic-gate  * xlator_startlib -- called on starting a new library, so back end
160*7c478bd9Sstevel@tonic-gate  *	translator can decide to change output file/directory if desired.
161*7c478bd9Sstevel@tonic-gate  */
162*7c478bd9Sstevel@tonic-gate int
163*7c478bd9Sstevel@tonic-gate xlator_startlib(char const *libname)
164*7c478bd9Sstevel@tonic-gate {
165*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "xlator_startlib() ");
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	Statistics.libraries++;
168*7c478bd9Sstevel@tonic-gate 	db_set_current_library(libname);
169*7c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "now in library \"%s\"", libname);
170*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
171*7c478bd9Sstevel@tonic-gate 	return (SUCCESS_RC);
172*7c478bd9Sstevel@tonic-gate }
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate /*
175*7c478bd9Sstevel@tonic-gate  * xlator_startfile -- ditto, called on starting each new spec file in the
176*7c478bd9Sstevel@tonic-gate  *	specified library.
177*7c478bd9Sstevel@tonic-gate  */
178*7c478bd9Sstevel@tonic-gate int
179*7c478bd9Sstevel@tonic-gate xlator_startfile(char const *filename)
180*7c478bd9Sstevel@tonic-gate {
181*7c478bd9Sstevel@tonic-gate 	int	rc = SUCCESS_RC;
182*7c478bd9Sstevel@tonic-gate 	char	infile[MAXLINE],
183*7c478bd9Sstevel@tonic-gate 		outfile[MAXLINE],
184*7c478bd9Sstevel@tonic-gate 		*lib = db_get_current_library();
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 	seterrline(0, filename, "", "");
187*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "xlator_startfile() {");
188*7c478bd9Sstevel@tonic-gate 	Statistics.files++;
189*7c478bd9Sstevel@tonic-gate 	db_set_current_file(filename);
190*7c478bd9Sstevel@tonic-gate 	errlog(TRACING, "now in file \"%s\" in lib \"%s\"",
191*7c478bd9Sstevel@tonic-gate 		filename, lib);
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 	/* Generate filenames. */
194*7c478bd9Sstevel@tonic-gate 	(void) snprintf(infile, sizeof (infile), "%s", filename);
195*7c478bd9Sstevel@tonic-gate 	(void) snprintf(outfile, sizeof (outfile), "%s.c",
196*7c478bd9Sstevel@tonic-gate 		db_get_output_file());
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 	/* Open .c file. */
199*7c478bd9Sstevel@tonic-gate 	if (open_code_file() == NO) {
200*7c478bd9Sstevel@tonic-gate 		rc = ERROR_RC;
201*7c478bd9Sstevel@tonic-gate 	}
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	generate_init(); /* Write stuff to the c file. */
204*7c478bd9Sstevel@tonic-gate 	symtab_clear_includes(); /* Clear out the per-file data. */
205*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
206*7c478bd9Sstevel@tonic-gate 	return (rc);
207*7c478bd9Sstevel@tonic-gate }
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate /*
210*7c478bd9Sstevel@tonic-gate  * xlator_start_if -- tritto, called on starting each new
211*7c478bd9Sstevel@tonic-gate  *	interface in the spec file.
212*7c478bd9Sstevel@tonic-gate  */
213*7c478bd9Sstevel@tonic-gate int
214*7c478bd9Sstevel@tonic-gate xlator_start_if(const Meta_info m, int const token, char *value)
215*7c478bd9Sstevel@tonic-gate {
216*7c478bd9Sstevel@tonic-gate 	char ifname[BUFSIZ];
217*7c478bd9Sstevel@tonic-gate 	char *kw;
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 	switch (token) {
220*7c478bd9Sstevel@tonic-gate 	case XLATOR_KW_FUNC:
221*7c478bd9Sstevel@tonic-gate 		kw = "Function";
222*7c478bd9Sstevel@tonic-gate 		break;
223*7c478bd9Sstevel@tonic-gate 	case XLATOR_KW_DATA:
224*7c478bd9Sstevel@tonic-gate 		kw = "Data";
225*7c478bd9Sstevel@tonic-gate 		break;
226*7c478bd9Sstevel@tonic-gate 	default:
227*7c478bd9Sstevel@tonic-gate 		/* This should never happen */
228*7c478bd9Sstevel@tonic-gate 		errlog(ERROR,
229*7c478bd9Sstevel@tonic-gate 		    "\"%s\", line %d: Implementation error! "
230*7c478bd9Sstevel@tonic-gate 		    "Please file a bug\n", __FILE__, __LINE__);
231*7c478bd9Sstevel@tonic-gate 		return (XLATOR_FATAL);
232*7c478bd9Sstevel@tonic-gate 	}
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	seterrline(LINE, m.mi_filename, kw, value);
235*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "xlator_start_if() {");
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate /*
238*7c478bd9Sstevel@tonic-gate  * XXX Note whether interface is function or data in some state data item.
239*7c478bd9Sstevel@tonic-gate  * We'll need it later when writing interceptors.
240*7c478bd9Sstevel@tonic-gate  */
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	Statistics.interfaces++;
243*7c478bd9Sstevel@tonic-gate 	(void) strpqcpy(ifname, value, nextsep2(value));
244*7c478bd9Sstevel@tonic-gate 	if (*ifname == '\0') {
245*7c478bd9Sstevel@tonic-gate 		errlog(INPUT|ERROR|FATAL,
246*7c478bd9Sstevel@tonic-gate 		    "missing argument in \"%s\" line", kw);
247*7c478bd9Sstevel@tonic-gate 	}
248*7c478bd9Sstevel@tonic-gate 	db_set_current_interface(ifname);
249*7c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "interface='%s'", value);
250*7c478bd9Sstevel@tonic-gate 	if (token == XLATOR_KW_DATA) {
251*7c478bd9Sstevel@tonic-gate 		Statistics.skips++;
252*7c478bd9Sstevel@tonic-gate 		errlog(VERBOSE, "telling front end to skip '%s'", value);
253*7c478bd9Sstevel@tonic-gate 		errlog(END, "}");
254*7c478bd9Sstevel@tonic-gate 		return (SKIP_RC); /* Tell front end to skip it for us. */
255*7c478bd9Sstevel@tonic-gate 	}
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	errlog(TRACING, "now in interface \"%s\"", value);
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 	symtab_new_function(m.mi_line_number, m.mi_filename);
260*7c478bd9Sstevel@tonic-gate 		/* Also cleans junk out of symbol table. */
261*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
262*7c478bd9Sstevel@tonic-gate 	return (SUCCESS_RC);
263*7c478bd9Sstevel@tonic-gate }
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate /*
266*7c478bd9Sstevel@tonic-gate  * xlator_take_kvpair -- the primary call: collect a datum provide by the
267*7c478bd9Sstevel@tonic-gate  *	front-end wrapper.
268*7c478bd9Sstevel@tonic-gate  */
269*7c478bd9Sstevel@tonic-gate int
270*7c478bd9Sstevel@tonic-gate xlator_take_kvpair(Meta_info m, int const token, char *value)
271*7c478bd9Sstevel@tonic-gate {
272*7c478bd9Sstevel@tonic-gate 	int retval;
273*7c478bd9Sstevel@tonic-gate 	char *key = Keywords[token-FIRST_TOKEN].key;
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 	int line = LINE; /* TBD */
276*7c478bd9Sstevel@tonic-gate 	symtab_set_filename(m.mi_filename);
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	value = strnormalize(value);
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 	seterrline(line, m.mi_filename, key, value);
281*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "xlator_take_kvpair() {");
282*7c478bd9Sstevel@tonic-gate 	Statistics.lines++;
283*7c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "key='%s', value='%s'",
284*7c478bd9Sstevel@tonic-gate 	    (key) ? key : "<nil>",
285*7c478bd9Sstevel@tonic-gate 	    (value) ? value : "<nil>");
286*7c478bd9Sstevel@tonic-gate 	switch (token) {
287*7c478bd9Sstevel@tonic-gate 	case XLATOR_KW_DECL:
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 	/*
290*7c478bd9Sstevel@tonic-gate 	 * XXX Check state item to see that it is a function,
291*7c478bd9Sstevel@tonic-gate 	 * else do not emit interceptor
292*7c478bd9Sstevel@tonic-gate 	 */
293*7c478bd9Sstevel@tonic-gate 		symtab_clear_function(); /* Always use last one. */
294*7c478bd9Sstevel@tonic-gate 		errlog(END, "}");
295*7c478bd9Sstevel@tonic-gate 		retval = collect_prototype(value, line, m.mi_ext_cnt);
296*7c478bd9Sstevel@tonic-gate 		break;
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 	case XLATOR_KW_INCL:
299*7c478bd9Sstevel@tonic-gate 		errlog(END, "}"); /* Use union of all includes. */
300*7c478bd9Sstevel@tonic-gate 		retval = collect_include(value, line);
301*7c478bd9Sstevel@tonic-gate 		if (retval == ERROR_RC) {
302*7c478bd9Sstevel@tonic-gate 			errlog(FATAL|INPUT, "Bad include line in spec file");
303*7c478bd9Sstevel@tonic-gate 		}
304*7c478bd9Sstevel@tonic-gate 		break;
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 	case XLATOR_KW_EXCP:
307*7c478bd9Sstevel@tonic-gate 		symtab_clear_exception(); /* Always use last. */
308*7c478bd9Sstevel@tonic-gate 		retval = collect_binding(token, value, line);
309*7c478bd9Sstevel@tonic-gate 		break;
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	case XLATOR_KW_ERRNO:
312*7c478bd9Sstevel@tonic-gate 		symtab_clear_errval(); /* Always use last. */
313*7c478bd9Sstevel@tonic-gate 		retval = collect_errval("errno", line);
314*7c478bd9Sstevel@tonic-gate 		break;
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	case XLATOR_KW_ERRVAL:
317*7c478bd9Sstevel@tonic-gate 		symtab_clear_errval(); /* Always use last. */
318*7c478bd9Sstevel@tonic-gate 		retval =  collect_errval(value, line);
319*7c478bd9Sstevel@tonic-gate 		break;
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	case XLATOR_KW_ARCH:
322*7c478bd9Sstevel@tonic-gate 		retval = collect_arch(value);
323*7c478bd9Sstevel@tonic-gate 		break;
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 	case XLATOR_KW_WEAK:
326*7c478bd9Sstevel@tonic-gate 		if (m.mi_extended == 1) {
327*7c478bd9Sstevel@tonic-gate 			errlog(ERROR, "\"%s\", line %d: "
328*7c478bd9Sstevel@tonic-gate 			    "Warning: Cannot use extends with a weak "
329*7c478bd9Sstevel@tonic-gate 			    "interface",
330*7c478bd9Sstevel@tonic-gate 			    m.mi_filename,
331*7c478bd9Sstevel@tonic-gate 			    m.mi_line_number);
332*7c478bd9Sstevel@tonic-gate 		}
333*7c478bd9Sstevel@tonic-gate 		retval = SUCCESS_RC;
334*7c478bd9Sstevel@tonic-gate 		break;
335*7c478bd9Sstevel@tonic-gate 	default:
336*7c478bd9Sstevel@tonic-gate 		retval = ERROR_RC;
337*7c478bd9Sstevel@tonic-gate 	}
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 	return (retval);
342*7c478bd9Sstevel@tonic-gate }
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate /*
345*7c478bd9Sstevel@tonic-gate  * xlator_end_if -- called at the end of the interface, to trigger
346*7c478bd9Sstevel@tonic-gate  *	per-interface processing now entire thing has been seen.
347*7c478bd9Sstevel@tonic-gate  */
348*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
349*7c478bd9Sstevel@tonic-gate int
350*7c478bd9Sstevel@tonic-gate xlator_end_if(const Meta_info m, char const *value)
351*7c478bd9Sstevel@tonic-gate {
352*7c478bd9Sstevel@tonic-gate 	seterrline(LINE, m.mi_filename, "end", value);
353*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "xlator_end_if() {");
354*7c478bd9Sstevel@tonic-gate 	if (symtab_get_skip() == YES) {
355*7c478bd9Sstevel@tonic-gate 		symtab_set_skip(NO);
356*7c478bd9Sstevel@tonic-gate 		Statistics.skips++;
357*7c478bd9Sstevel@tonic-gate 	} else {
358*7c478bd9Sstevel@tonic-gate 		generate_interface();
359*7c478bd9Sstevel@tonic-gate 	}
360*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
361*7c478bd9Sstevel@tonic-gate 	return (SUCCESS_RC);
362*7c478bd9Sstevel@tonic-gate }
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate /*
365*7c478bd9Sstevel@tonic-gate  * xlator_endfile -- called at the end of the file, to trigger per-file
366*7c478bd9Sstevel@tonic-gate  * processing.
367*7c478bd9Sstevel@tonic-gate  */
368*7c478bd9Sstevel@tonic-gate int
369*7c478bd9Sstevel@tonic-gate xlator_endfile(void)
370*7c478bd9Sstevel@tonic-gate {
371*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "xlator_endfile() {");
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	generate_closedown();
374*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
375*7c478bd9Sstevel@tonic-gate 	return ((commit_code_file() == YES)? SUCCESS_RC: ERROR_RC);
376*7c478bd9Sstevel@tonic-gate }
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate /*
379*7c478bd9Sstevel@tonic-gate  * xlator_endlib -- ditto, at the end of the library.
380*7c478bd9Sstevel@tonic-gate  */
381*7c478bd9Sstevel@tonic-gate int
382*7c478bd9Sstevel@tonic-gate xlator_endlib(void)
383*7c478bd9Sstevel@tonic-gate {
384*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "xlator_endlib() {");
385*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
386*7c478bd9Sstevel@tonic-gate 	return (SUCCESS_RC);
387*7c478bd9Sstevel@tonic-gate }
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate /*
390*7c478bd9Sstevel@tonic-gate  * xlator_end -- the end of the processing, called so translator
391*7c478bd9Sstevel@tonic-gate  *	can do cleanup, write makefiles, etc.
392*7c478bd9Sstevel@tonic-gate  */
393*7c478bd9Sstevel@tonic-gate int
394*7c478bd9Sstevel@tonic-gate xlator_end(void)
395*7c478bd9Sstevel@tonic-gate {
396*7c478bd9Sstevel@tonic-gate 	int	rc = SUCCESS_RC;
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "xlator_end() {");
399*7c478bd9Sstevel@tonic-gate 	rc += !generate_aux_file();
400*7c478bd9Sstevel@tonic-gate 	stats_report();
401*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
402*7c478bd9Sstevel@tonic-gate 	return (rc);
403*7c478bd9Sstevel@tonic-gate }
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate /*
407*7c478bd9Sstevel@tonic-gate ** utilities for this layer/phase only.
408*7c478bd9Sstevel@tonic-gate */
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate /*
411*7c478bd9Sstevel@tonic-gate  * stats_init -- note what time it is...
412*7c478bd9Sstevel@tonic-gate  */
413*7c478bd9Sstevel@tonic-gate static void
414*7c478bd9Sstevel@tonic-gate stats_init(void)
415*7c478bd9Sstevel@tonic-gate {
416*7c478bd9Sstevel@tonic-gate 	Statistics.start = time(NULL);
417*7c478bd9Sstevel@tonic-gate }
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate /*
420*7c478bd9Sstevel@tonic-gate  * stats_report -- say how much we just did
421*7c478bd9Sstevel@tonic-gate  */
422*7c478bd9Sstevel@tonic-gate #define	max(a, b) (a > b)? a: b
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate static void
425*7c478bd9Sstevel@tonic-gate stats_report(void)
426*7c478bd9Sstevel@tonic-gate {
427*7c478bd9Sstevel@tonic-gate 	double	seconds;
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	Statistics.end = time(NULL);
430*7c478bd9Sstevel@tonic-gate 	seconds = difftime(Statistics.end, Statistics.start);
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate 	switch (Verbose) {
433*7c478bd9Sstevel@tonic-gate 	default:
434*7c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
435*7c478bd9Sstevel@tonic-gate 	case 1:
436*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "Statistics:\n"
437*7c478bd9Sstevel@tonic-gate 		    "    %d libraries\n    %d files\n"
438*7c478bd9Sstevel@tonic-gate 		    "    %d interfaces\n    %d lines\n"
439*7c478bd9Sstevel@tonic-gate 		    "    %d errors\n    %d warnings\n"
440*7c478bd9Sstevel@tonic-gate 		    "    %d skips\n"
441*7c478bd9Sstevel@tonic-gate 		    "in %.0f seconds, at %.1f lines/minute.\n",
442*7c478bd9Sstevel@tonic-gate 		    Statistics.libraries, Statistics.files,
443*7c478bd9Sstevel@tonic-gate 		    Statistics.interfaces, Statistics.lines,
444*7c478bd9Sstevel@tonic-gate 		    Statistics.errors, Statistics.warnings,
445*7c478bd9Sstevel@tonic-gate 		    Statistics.skips,
446*7c478bd9Sstevel@tonic-gate 		    seconds, Statistics.lines*60.0/seconds);
447*7c478bd9Sstevel@tonic-gate 		break;
448*7c478bd9Sstevel@tonic-gate 	case 0:
449*7c478bd9Sstevel@tonic-gate 		if (Statistics.errors != 0 || Statistics.warnings != 0) {
450*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
451*7c478bd9Sstevel@tonic-gate 			    "spec2trace: %d errors %d warnings.\n",
452*7c478bd9Sstevel@tonic-gate 			    Statistics.errors, Statistics.warnings);
453*7c478bd9Sstevel@tonic-gate 		}
454*7c478bd9Sstevel@tonic-gate 		break;
455*7c478bd9Sstevel@tonic-gate 	}
456*7c478bd9Sstevel@tonic-gate }
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate /*
460*7c478bd9Sstevel@tonic-gate  * Tiny stats class...
461*7c478bd9Sstevel@tonic-gate  */
462*7c478bd9Sstevel@tonic-gate void
463*7c478bd9Sstevel@tonic-gate stats_add_warning(void)
464*7c478bd9Sstevel@tonic-gate {
465*7c478bd9Sstevel@tonic-gate 	Statistics.warnings++;
466*7c478bd9Sstevel@tonic-gate }
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate void
469*7c478bd9Sstevel@tonic-gate stats_add_error(void)
470*7c478bd9Sstevel@tonic-gate {
471*7c478bd9Sstevel@tonic-gate 	Statistics.errors++;
472*7c478bd9Sstevel@tonic-gate }
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate /*
475*7c478bd9Sstevel@tonic-gate  * collect_includes -- collect a global list of include files,
476*7c478bd9Sstevel@tonic-gate  *	converting the comma- or space-separated input list into a
477*7c478bd9Sstevel@tonic-gate  *	structure for the database to store.
478*7c478bd9Sstevel@tonic-gate  *	As this can cause problems will ill-structured
479*7c478bd9Sstevel@tonic-gate  *	files, there is a mechanism to allow exclusion of
480*7c478bd9Sstevel@tonic-gate  *	certain files, (or certain combinations).  At
481*7c478bd9Sstevel@tonic-gate  *	the moment, the mechanism is TBD, as is the second arg.
482*7c478bd9Sstevel@tonic-gate  */
483*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
484*7c478bd9Sstevel@tonic-gate int
485*7c478bd9Sstevel@tonic-gate collect_include(char *p, int line)
486*7c478bd9Sstevel@tonic-gate {
487*7c478bd9Sstevel@tonic-gate 	char	*include;
488*7c478bd9Sstevel@tonic-gate 	int	len;
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "collect_include() {");
491*7c478bd9Sstevel@tonic-gate 	if ((include = strtok(p, ", ")) != NULL) {
492*7c478bd9Sstevel@tonic-gate 		for (; include != NULL; include = strtok(NULL, ", ")) {
493*7c478bd9Sstevel@tonic-gate 			include  = skipb(include);
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 			/*
496*7c478bd9Sstevel@tonic-gate 			 * Make sure the include file's name
497*7c478bd9Sstevel@tonic-gate 			 * has legitimate C syntax - i.e. it's in double
498*7c478bd9Sstevel@tonic-gate 			 * quotes or angle brackets.
499*7c478bd9Sstevel@tonic-gate 			 */
500*7c478bd9Sstevel@tonic-gate 			if (*include != '"' && *include != '<')
501*7c478bd9Sstevel@tonic-gate 				return (ERROR_RC);
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate 			len = strlen(include);
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate 			if (include[len-1] != '"' && include[len-1] != '>')
506*7c478bd9Sstevel@tonic-gate 				return (ERROR_RC);
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 			/*
509*7c478bd9Sstevel@tonic-gate 			 * If include filename syntax is OK, add it to
510*7c478bd9Sstevel@tonic-gate 			 * the list
511*7c478bd9Sstevel@tonic-gate 			 */
512*7c478bd9Sstevel@tonic-gate 			symtab_add_includes(include);
513*7c478bd9Sstevel@tonic-gate 		}
514*7c478bd9Sstevel@tonic-gate 	}
515*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
516*7c478bd9Sstevel@tonic-gate 	return (SUCCESS_RC);
517*7c478bd9Sstevel@tonic-gate }
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate /*
520*7c478bd9Sstevel@tonic-gate  * collect_binding -- take a binding and stuff it into the database
521*7c478bd9Sstevel@tonic-gate  *	in canonical form (with the word return in it).
522*7c478bd9Sstevel@tonic-gate  */
523*7c478bd9Sstevel@tonic-gate int
524*7c478bd9Sstevel@tonic-gate collect_binding(int const token, char *value, int line)
525*7c478bd9Sstevel@tonic-gate {
526*7c478bd9Sstevel@tonic-gate 	char	*file = db_get_current_file();
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "collect_binding() {");
529*7c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "name=\"%s\", value=\"%s\", line=%d\n",
530*7c478bd9Sstevel@tonic-gate 	    Keywords[token-FIRST_TOKEN].key, value, line);
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 	if (token == XLATOR_KW_EXCP) {
533*7c478bd9Sstevel@tonic-gate 		symtab_set_exception(value, line, file);
534*7c478bd9Sstevel@tonic-gate 	} else {
535*7c478bd9Sstevel@tonic-gate 		errlog(FATAL|INPUT, "programmer error: impossible binding.");
536*7c478bd9Sstevel@tonic-gate 	}
537*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
538*7c478bd9Sstevel@tonic-gate 	return (SUCCESS_RC);
539*7c478bd9Sstevel@tonic-gate }
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate /*
542*7c478bd9Sstevel@tonic-gate  * collect_errval -- collect the error variable name (only)
543*7c478bd9Sstevel@tonic-gate  *	from the line.  This is expected to be the first
544*7c478bd9Sstevel@tonic-gate  *	or only thing in a space- or comma-separated list.
545*7c478bd9Sstevel@tonic-gate  *	Collecting errno/errval possible value is left TBD.
546*7c478bd9Sstevel@tonic-gate  */
547*7c478bd9Sstevel@tonic-gate int
548*7c478bd9Sstevel@tonic-gate collect_errval(char *p, int line)
549*7c478bd9Sstevel@tonic-gate {
550*7c478bd9Sstevel@tonic-gate 	char	*name;
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "collect_errval() {");
553*7c478bd9Sstevel@tonic-gate 	name = strtok(p, " \t\n\r");
554*7c478bd9Sstevel@tonic-gate 	symtab_set_errval(name, line, db_get_current_file(), "int", "int", 0);
555*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
556*7c478bd9Sstevel@tonic-gate 	return (SUCCESS_RC);
557*7c478bd9Sstevel@tonic-gate }
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate /*
560*7c478bd9Sstevel@tonic-gate  * collect_arch -- collect architecture.
561*7c478bd9Sstevel@tonic-gate  */
562*7c478bd9Sstevel@tonic-gate int
563*7c478bd9Sstevel@tonic-gate collect_arch(char *value)
564*7c478bd9Sstevel@tonic-gate {
565*7c478bd9Sstevel@tonic-gate 	char const	*arch = db_get_arch();
566*7c478bd9Sstevel@tonic-gate 	char	*buf, *p;
567*7c478bd9Sstevel@tonic-gate 	char	*t;
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "collect_arch() {");
570*7c478bd9Sstevel@tonic-gate 	if (value == 0 || *value == '\0')
571*7c478bd9Sstevel@tonic-gate 		errlog(FATAL|INPUT, "No architectures defined in ARCH line");
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 	if ((buf = strdup(value)) == NULL)
574*7c478bd9Sstevel@tonic-gate 		errlog(FATAL, "Could not allocate memory in ARCH directive");
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 	t = buf;
577*7c478bd9Sstevel@tonic-gate 	while ((p = strtok(t, " \r\t\n")) != NULL) {
578*7c478bd9Sstevel@tonic-gate 		if (strcmp(p, arch) == 0 || strcmp(p, "all") == 0)
579*7c478bd9Sstevel@tonic-gate 			goto cleanup;
580*7c478bd9Sstevel@tonic-gate 		t = NULL;
581*7c478bd9Sstevel@tonic-gate 	}
582*7c478bd9Sstevel@tonic-gate 	symtab_set_skip(YES);
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate cleanup:
585*7c478bd9Sstevel@tonic-gate 	free(buf);
586*7c478bd9Sstevel@tonic-gate 	return (SUCCESS_RC);
587*7c478bd9Sstevel@tonic-gate }
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate /*
590*7c478bd9Sstevel@tonic-gate  * de_const -- get rid of const meta-types. This is actually a
591*7c478bd9Sstevel@tonic-gate  *	dodge to avoid writing a base-type function early in the
592*7c478bd9Sstevel@tonic-gate  *	process. This may turn into to_basetype() or to_primitivetype().
593*7c478bd9Sstevel@tonic-gate  */
594*7c478bd9Sstevel@tonic-gate static char *
595*7c478bd9Sstevel@tonic-gate de_const(char *type)
596*7c478bd9Sstevel@tonic-gate {
597*7c478bd9Sstevel@tonic-gate 	char *p, *q;
598*7c478bd9Sstevel@tonic-gate 	int i;
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	p = skipb(type);
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 	q = strstr(type, "const");
603*7c478bd9Sstevel@tonic-gate 	if (q > p) {
604*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < 5; i++) {
605*7c478bd9Sstevel@tonic-gate 			*q++ = '\0';
606*7c478bd9Sstevel@tonic-gate 		}
607*7c478bd9Sstevel@tonic-gate 		(void) sprintf(type, "%s%s", strnormalize(p), q);
608*7c478bd9Sstevel@tonic-gate 		return (type);
609*7c478bd9Sstevel@tonic-gate 	} else if (p == q) {
610*7c478bd9Sstevel@tonic-gate 		return (skipb(nextsep(p)));
611*7c478bd9Sstevel@tonic-gate 	} else {
612*7c478bd9Sstevel@tonic-gate 		return (type);
613*7c478bd9Sstevel@tonic-gate 	}
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate }
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate /*
618*7c478bd9Sstevel@tonic-gate  * to_basetype -- convert a C type declaration into its base type and return
619*7c478bd9Sstevel@tonic-gate  * 	the number of levels of indirection.
620*7c478bd9Sstevel@tonic-gate  *	Destructive and eats ``const''.
621*7c478bd9Sstevel@tonic-gate  */
622*7c478bd9Sstevel@tonic-gate static int
623*7c478bd9Sstevel@tonic-gate to_basetype(char *str)
624*7c478bd9Sstevel@tonic-gate {
625*7c478bd9Sstevel@tonic-gate 	char	*p = str,
626*7c478bd9Sstevel@tonic-gate 		buffer[MAXLINE+1],
627*7c478bd9Sstevel@tonic-gate 		*q = &buffer[0];
628*7c478bd9Sstevel@tonic-gate 	int	levels = 0;
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate 	assert(strlen(str) < MAXLINE, "string exceeded MAXLINE");
631*7c478bd9Sstevel@tonic-gate 	buffer[0] = NULL;
632*7c478bd9Sstevel@tonic-gate 	for (; *p != NULL; p++) {
633*7c478bd9Sstevel@tonic-gate 		switch (*p) {
634*7c478bd9Sstevel@tonic-gate 		case ' ': /* Convert spaces to single ' '. */
635*7c478bd9Sstevel@tonic-gate 			if (*(q-1) != ' ')
636*7c478bd9Sstevel@tonic-gate 				*q++ = ' ';
637*7c478bd9Sstevel@tonic-gate 			break;
638*7c478bd9Sstevel@tonic-gate 		case '*': /* Convert * to _P. */
639*7c478bd9Sstevel@tonic-gate 			if (*(q-1) != ' ')
640*7c478bd9Sstevel@tonic-gate 				*q++ = ' ';
641*7c478bd9Sstevel@tonic-gate 			levels++;
642*7c478bd9Sstevel@tonic-gate 			break;
643*7c478bd9Sstevel@tonic-gate 		case 'c': /* This might be a const */
644*7c478bd9Sstevel@tonic-gate 			if (strncmp(p, "const", 5) == 0) {
645*7c478bd9Sstevel@tonic-gate 				p += 4;
646*7c478bd9Sstevel@tonic-gate 			} else {
647*7c478bd9Sstevel@tonic-gate 				*q++ = *p;
648*7c478bd9Sstevel@tonic-gate 			}
649*7c478bd9Sstevel@tonic-gate 			break;
650*7c478bd9Sstevel@tonic-gate 		default:
651*7c478bd9Sstevel@tonic-gate 			/* Otherwise just copy. */
652*7c478bd9Sstevel@tonic-gate 			*q++ = *p;
653*7c478bd9Sstevel@tonic-gate 			break;
654*7c478bd9Sstevel@tonic-gate 		}
655*7c478bd9Sstevel@tonic-gate 		*q = NULL;
656*7c478bd9Sstevel@tonic-gate 	}
657*7c478bd9Sstevel@tonic-gate 	assert(q < &buffer[MAXLINE], "q fell off end of buffer");
658*7c478bd9Sstevel@tonic-gate 	q--;
659*7c478bd9Sstevel@tonic-gate 	while (*q == ' ') {
660*7c478bd9Sstevel@tonic-gate 		*q-- = NULL;
661*7c478bd9Sstevel@tonic-gate 	}
662*7c478bd9Sstevel@tonic-gate 	assert(strlen(buffer) < MAXLINE, "buffer length exceeded MAXLINE");
663*7c478bd9Sstevel@tonic-gate 	(void) strcpy(str, buffer);
664*7c478bd9Sstevel@tonic-gate 	return (levels);
665*7c478bd9Sstevel@tonic-gate }
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate /*
668*7c478bd9Sstevel@tonic-gate  * to_actual -- create an actual-argument list for use
669*7c478bd9Sstevel@tonic-gate  *	when calling the function.
670*7c478bd9Sstevel@tonic-gate  */
671*7c478bd9Sstevel@tonic-gate static char *
672*7c478bd9Sstevel@tonic-gate to_actual(void)
673*7c478bd9Sstevel@tonic-gate {
674*7c478bd9Sstevel@tonic-gate 	ENTRY	*p;
675*7c478bd9Sstevel@tonic-gate 	static char buffer[MAXLINE+1];
676*7c478bd9Sstevel@tonic-gate 	int	n;
677*7c478bd9Sstevel@tonic-gate 
678*7c478bd9Sstevel@tonic-gate 	*buffer = NULL;
679*7c478bd9Sstevel@tonic-gate 	if ((p = symtab_get_first_arg()) != NULL) {
680*7c478bd9Sstevel@tonic-gate 		n = MAXLINE - snprintf(buffer, MAXLINE, "%s", name_of(p));
681*7c478bd9Sstevel@tonic-gate 		for (p = symtab_get_next_arg(); p != NULL;
682*7c478bd9Sstevel@tonic-gate 						p = symtab_get_next_arg()) {
683*7c478bd9Sstevel@tonic-gate 			if (*name_of(p) != NULL)
684*7c478bd9Sstevel@tonic-gate 				n -= snprintf(strend(buffer), n,
685*7c478bd9Sstevel@tonic-gate 					", %s", name_of(p));
686*7c478bd9Sstevel@tonic-gate 		}
687*7c478bd9Sstevel@tonic-gate 	}
688*7c478bd9Sstevel@tonic-gate 	return (buffer);
689*7c478bd9Sstevel@tonic-gate }
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate /*
692*7c478bd9Sstevel@tonic-gate  * strpqcpy -- string copy that takes whatever begins with p and ends
693*7c478bd9Sstevel@tonic-gate  *	just before q.
694*7c478bd9Sstevel@tonic-gate  */
695*7c478bd9Sstevel@tonic-gate static char *
696*7c478bd9Sstevel@tonic-gate strpqcpy(char *target, char *p, char *q)
697*7c478bd9Sstevel@tonic-gate {
698*7c478bd9Sstevel@tonic-gate 	char	saved;
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate 	saved = *q;
701*7c478bd9Sstevel@tonic-gate 	*q = NULL;
702*7c478bd9Sstevel@tonic-gate 	(void) strcpy(target, p);
703*7c478bd9Sstevel@tonic-gate 	*q = saved;
704*7c478bd9Sstevel@tonic-gate 	return (target);
705*7c478bd9Sstevel@tonic-gate }
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate #ifndef lint
708*7c478bd9Sstevel@tonic-gate int
709*7c478bd9Sstevel@tonic-gate breakpoint(void)
710*7c478bd9Sstevel@tonic-gate {
711*7c478bd9Sstevel@tonic-gate 	return (0);
712*7c478bd9Sstevel@tonic-gate }
713*7c478bd9Sstevel@tonic-gate #endif
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate int
717*7c478bd9Sstevel@tonic-gate collect_prototype(char *p, int line, int extcnt)
718*7c478bd9Sstevel@tonic-gate {
719*7c478bd9Sstevel@tonic-gate 	char	f_type[BUFSIZ];	/* The function. */
720*7c478bd9Sstevel@tonic-gate 	char	f_basetype[BUFSIZ];
721*7c478bd9Sstevel@tonic-gate 	char	f_name[BUFSIZ];
722*7c478bd9Sstevel@tonic-gate 	char	a_name[BUFSIZ];	/* The arguments. */
723*7c478bd9Sstevel@tonic-gate 	char	a_basetype[BUFSIZ];
724*7c478bd9Sstevel@tonic-gate 	char	a_type[BUFSIZ];
725*7c478bd9Sstevel@tonic-gate 	char	*file = db_get_current_file();
726*7c478bd9Sstevel@tonic-gate 	char	*interface = db_get_current_interface();
727*7c478bd9Sstevel@tonic-gate 	char	*q;
728*7c478bd9Sstevel@tonic-gate 	char const *parse_err;
729*7c478bd9Sstevel@tonic-gate 	char	tmp_proto[BUFSIZ], buf[BUFSIZ];
730*7c478bd9Sstevel@tonic-gate 	decl_t	*pp, *funargs;
731*7c478bd9Sstevel@tonic-gate 	type_t	*tp;
732*7c478bd9Sstevel@tonic-gate 	int	levels, a_levels;
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate 	tmp_proto[BUFSIZ-1] = 0;
735*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "collect_prototype() {");
736*7c478bd9Sstevel@tonic-gate 	if (p[strlen(p)-1] != ';')
737*7c478bd9Sstevel@tonic-gate 		(void) snprintf(tmp_proto, BUFSIZ, "%s;", p);
738*7c478bd9Sstevel@tonic-gate 	else
739*7c478bd9Sstevel@tonic-gate 		(void) snprintf(tmp_proto, BUFSIZ, "%s", p);
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 	/* save prototype in symbol table */
742*7c478bd9Sstevel@tonic-gate 	symtab_set_prototype(p);
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "parsing prototype: %s\n", tmp_proto);
745*7c478bd9Sstevel@tonic-gate 
746*7c478bd9Sstevel@tonic-gate 	/* Parse Prototype */
747*7c478bd9Sstevel@tonic-gate 	if ((parse_err = decl_Parse(tmp_proto, &pp)) != NULL) {
748*7c478bd9Sstevel@tonic-gate 		errlog(FATAL|INPUT, "bad prototype: %s\n\t%s\n", parse_err, p);
749*7c478bd9Sstevel@tonic-gate 	}
750*7c478bd9Sstevel@tonic-gate 
751*7c478bd9Sstevel@tonic-gate 	if (extcnt == 0) {
752*7c478bd9Sstevel@tonic-gate 		char *dname = decl_GetName(pp);
753*7c478bd9Sstevel@tonic-gate 		if (strcmp(interface, dname) != 0)
754*7c478bd9Sstevel@tonic-gate 			errlog(FATAL|INPUT, "function and declaration"
755*7c478bd9Sstevel@tonic-gate 			    " name mismatch\nfunction name = %s,"
756*7c478bd9Sstevel@tonic-gate 			    " declaration name = %s\n", interface,
757*7c478bd9Sstevel@tonic-gate 			    dname);
758*7c478bd9Sstevel@tonic-gate 	}
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate 	tp = decl_GetType(pp);
761*7c478bd9Sstevel@tonic-gate 
762*7c478bd9Sstevel@tonic-gate 	if (type_IsPtrFun(tp)) {
763*7c478bd9Sstevel@tonic-gate 		errlog(FATAL|INPUT, "function %s is declared as a data item"
764*7c478bd9Sstevel@tonic-gate 		    " (pointer to function)\n", interface);
765*7c478bd9Sstevel@tonic-gate 	} else if (!type_IsFunction(tp)) {
766*7c478bd9Sstevel@tonic-gate 		errlog(FATAL|INPUT, "function %s is declared as a data item",
767*7c478bd9Sstevel@tonic-gate 		    interface);
768*7c478bd9Sstevel@tonic-gate 	}
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate 	if (type_IsVarargs(tp)) {
771*7c478bd9Sstevel@tonic-gate 		symtab_set_skip(YES);
772*7c478bd9Sstevel@tonic-gate 		decl_Destroy(pp);
773*7c478bd9Sstevel@tonic-gate 		return (SUCCESS_RC);
774*7c478bd9Sstevel@tonic-gate 	}
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 	decl_GetTraceInfo(pp, f_type, f_basetype, &funargs);
777*7c478bd9Sstevel@tonic-gate 	(void) sprintf(buf, "%s", strnormalize(f_type));
778*7c478bd9Sstevel@tonic-gate 	(void) strcpy(f_type, buf);
779*7c478bd9Sstevel@tonic-gate 	(void) sprintf(buf, "%s", strnormalize(f_basetype));
780*7c478bd9Sstevel@tonic-gate 	(void) strcpy(f_basetype, buf);
781*7c478bd9Sstevel@tonic-gate 	levels = to_basetype(f_basetype);
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate 	/* get interface name from 'Begin' line */
784*7c478bd9Sstevel@tonic-gate 	(void) strpqcpy(f_name, interface, nextsep(interface));
785*7c478bd9Sstevel@tonic-gate 	(void) decl_SetName(pp, f_name);
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate 	errlog(VERBOSE, "f_name=%s, f_basetype=%s, f_type=%s\n",
788*7c478bd9Sstevel@tonic-gate 		f_name, f_basetype, f_type);
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 	symtab_set_function(f_name, line, file, f_type, f_basetype, levels);
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	db_add_print_types(f_basetype,
793*7c478bd9Sstevel@tonic-gate 	    (q = de_const(type_of(symtab_get_function()))));
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate 	symtab_add_print_types(f_basetype, q);
796*7c478bd9Sstevel@tonic-gate 
797*7c478bd9Sstevel@tonic-gate 	/* args list */
798*7c478bd9Sstevel@tonic-gate 	while (funargs) {
799*7c478bd9Sstevel@tonic-gate 		(void) snprintf(a_type, BUFSIZ, "%s ",
800*7c478bd9Sstevel@tonic-gate 			strnormalize(declspec_ToString(buf, funargs->d_ds)));
801*7c478bd9Sstevel@tonic-gate 		(void) snprintf(a_basetype, BUFSIZ, "%s",
802*7c478bd9Sstevel@tonic-gate 			strnormalize(de_const(declspec_ToString(buf,
803*7c478bd9Sstevel@tonic-gate 			funargs->d_ds))));
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate 		tp = funargs->d_type;
806*7c478bd9Sstevel@tonic-gate 
807*7c478bd9Sstevel@tonic-gate 		for (a_levels = 0; tp; ) {
808*7c478bd9Sstevel@tonic-gate 			if (tp->t_dt == DD_PTR || tp->t_dt == DD_ARY) {
809*7c478bd9Sstevel@tonic-gate 				(void) strcat(a_type, "*");
810*7c478bd9Sstevel@tonic-gate 				a_levels++;
811*7c478bd9Sstevel@tonic-gate 			}
812*7c478bd9Sstevel@tonic-gate 			tp = tp->t_next;
813*7c478bd9Sstevel@tonic-gate 		}
814*7c478bd9Sstevel@tonic-gate 
815*7c478bd9Sstevel@tonic-gate 		/*
816*7c478bd9Sstevel@tonic-gate 		 * XXX: This is a hack to work around bug in yacc parser
817*7c478bd9Sstevel@tonic-gate 		 *  "int foo(void)" prototypes get interpreted as having 1
818*7c478bd9Sstevel@tonic-gate 		 *  argument with the d_name of the argument being NULL.
819*7c478bd9Sstevel@tonic-gate 		 */
820*7c478bd9Sstevel@tonic-gate 		if (funargs->d_name) {
821*7c478bd9Sstevel@tonic-gate 			(void) snprintf(a_name, 20, "%s", funargs->d_name);
822*7c478bd9Sstevel@tonic-gate 
823*7c478bd9Sstevel@tonic-gate 			errlog(VERBOSE,
824*7c478bd9Sstevel@tonic-gate 			    "a_name = %s, a_basetype = %s, a_type = %s\n",
825*7c478bd9Sstevel@tonic-gate 			    a_name, a_basetype, a_type);
826*7c478bd9Sstevel@tonic-gate 
827*7c478bd9Sstevel@tonic-gate 			symtab_add_args(a_name, line, file,
828*7c478bd9Sstevel@tonic-gate 			    a_type, a_basetype, a_levels);
829*7c478bd9Sstevel@tonic-gate 			db_add_print_types(a_basetype,
830*7c478bd9Sstevel@tonic-gate 			    q = de_const(type_of(symtab_get_last_arg())));
831*7c478bd9Sstevel@tonic-gate 			symtab_add_print_types(a_basetype, q);
832*7c478bd9Sstevel@tonic-gate 		}
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 		funargs = funargs->d_next;
835*7c478bd9Sstevel@tonic-gate 	}
836*7c478bd9Sstevel@tonic-gate 	symtab_set_formals(decl_ToFormal(pp));
837*7c478bd9Sstevel@tonic-gate 	symtab_set_actuals(to_actual());
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 	symtab_set_cast(decl_ToString(buf, DTS_CAST, pp, NULL));
840*7c478bd9Sstevel@tonic-gate 
841*7c478bd9Sstevel@tonic-gate 	decl_Destroy(pp);
842*7c478bd9Sstevel@tonic-gate 
843*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
844*7c478bd9Sstevel@tonic-gate 	return (SUCCESS_RC);
845*7c478bd9Sstevel@tonic-gate }
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate 
848*7c478bd9Sstevel@tonic-gate /*
849*7c478bd9Sstevel@tonic-gate  * generators
850*7c478bd9Sstevel@tonic-gate  */
851*7c478bd9Sstevel@tonic-gate 
852*7c478bd9Sstevel@tonic-gate /*
853*7c478bd9Sstevel@tonic-gate  * generate_init -- prime the code generator as required.
854*7c478bd9Sstevel@tonic-gate  */
855*7c478bd9Sstevel@tonic-gate static void
856*7c478bd9Sstevel@tonic-gate generate_init(void)
857*7c478bd9Sstevel@tonic-gate {
858*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "generate_init() {");
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate 	(void) fprintf(Headfp,
861*7c478bd9Sstevel@tonic-gate 	    "/*\n"
862*7c478bd9Sstevel@tonic-gate 	    " * Generated by spec2trace %s: do not edit this file.\n */\n\n",
863*7c478bd9Sstevel@tonic-gate 	    TRACE_VERSION);
864*7c478bd9Sstevel@tonic-gate 
865*7c478bd9Sstevel@tonic-gate 	(void) fprintf(Headfp,
866*7c478bd9Sstevel@tonic-gate 	    "#ifndef true\n"
867*7c478bd9Sstevel@tonic-gate 	    "#define\ttrue 1\n"
868*7c478bd9Sstevel@tonic-gate 	    "#define\tfalse 0\n"
869*7c478bd9Sstevel@tonic-gate 	    "#endif\n\n"
870*7c478bd9Sstevel@tonic-gate 	    "static char const *oparen = \"(\";\n"
871*7c478bd9Sstevel@tonic-gate 	    "static char const *retstr = \"  return = \";\n"
872*7c478bd9Sstevel@tonic-gate 	    "static char const *errnostr = \" errno = \";\n"
873*7c478bd9Sstevel@tonic-gate 	    "static char const *nilstr = \"<nil>\";\n"
874*7c478bd9Sstevel@tonic-gate 	    "\n");
875*7c478bd9Sstevel@tonic-gate 
876*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
877*7c478bd9Sstevel@tonic-gate }
878*7c478bd9Sstevel@tonic-gate 
879*7c478bd9Sstevel@tonic-gate 
880*7c478bd9Sstevel@tonic-gate /*
881*7c478bd9Sstevel@tonic-gate  * generate_interface -- call the two main parts of the per-interface
882*7c478bd9Sstevel@tonic-gate  *	code generation.
883*7c478bd9Sstevel@tonic-gate  */
884*7c478bd9Sstevel@tonic-gate static void
885*7c478bd9Sstevel@tonic-gate generate_interface(void)
886*7c478bd9Sstevel@tonic-gate {
887*7c478bd9Sstevel@tonic-gate 	ENTRY	*function = symtab_get_function();
888*7c478bd9Sstevel@tonic-gate 
889*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "generate_interface() {");
890*7c478bd9Sstevel@tonic-gate 	/* Check for required information. */
891*7c478bd9Sstevel@tonic-gate 	if (validity_of(function) == NO) {
892*7c478bd9Sstevel@tonic-gate 		symtab_set_skip(YES);
893*7c478bd9Sstevel@tonic-gate 		errlog(WARNING|INPUT, "no prototype for interface "
894*7c478bd9Sstevel@tonic-gate 			"it will be skipped");
895*7c478bd9Sstevel@tonic-gate 		errlog(END, "}");
896*7c478bd9Sstevel@tonic-gate 		return;
897*7c478bd9Sstevel@tonic-gate 	}
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 	/* Generate the current interface 's print-functions declarations. */
900*7c478bd9Sstevel@tonic-gate 	generate_print_declarations(Bodyfp);
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate 	/* Generate the linkage part (a function and a struct */
903*7c478bd9Sstevel@tonic-gate 	generate_linkage(function);
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 	/* Generate the actual interceptor. */
906*7c478bd9Sstevel@tonic-gate 	generate_interceptor(function);
907*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
908*7c478bd9Sstevel@tonic-gate }
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate 
911*7c478bd9Sstevel@tonic-gate /*
912*7c478bd9Sstevel@tonic-gate  * generate_closedown -- produce includes.
913*7c478bd9Sstevel@tonic-gate  */
914*7c478bd9Sstevel@tonic-gate static void
915*7c478bd9Sstevel@tonic-gate generate_closedown(void)
916*7c478bd9Sstevel@tonic-gate {
917*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "generate_closedown() {");
918*7c478bd9Sstevel@tonic-gate 
919*7c478bd9Sstevel@tonic-gate 	/* Print includes to primary file. */
920*7c478bd9Sstevel@tonic-gate 	generate_includes();
921*7c478bd9Sstevel@tonic-gate 	(void) putc('\n', Headfp);
922*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
923*7c478bd9Sstevel@tonic-gate }
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate /*
926*7c478bd9Sstevel@tonic-gate  * generate_aux_file -- generate one additional .pf file with
927*7c478bd9Sstevel@tonic-gate  *	print-function pointers.
928*7c478bd9Sstevel@tonic-gate  */
929*7c478bd9Sstevel@tonic-gate static int
930*7c478bd9Sstevel@tonic-gate generate_aux_file(void)
931*7c478bd9Sstevel@tonic-gate {
932*7c478bd9Sstevel@tonic-gate 	FILE	*fp;
933*7c478bd9Sstevel@tonic-gate 	char	pathname[MAXLINE];
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "generate_aux_file() {");
936*7c478bd9Sstevel@tonic-gate 	/* Open file */
937*7c478bd9Sstevel@tonic-gate 	(void) snprintf(pathname, sizeof (pathname), "%s.pf",
938*7c478bd9Sstevel@tonic-gate 		db_get_output_file());
939*7c478bd9Sstevel@tonic-gate 	errlog(TRACING,  "output file = '%s'", pathname);
940*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(pathname, "w")) == NULL) {
941*7c478bd9Sstevel@tonic-gate 		errlog(FATAL, "%s: %s", pathname, strerror(errno));
942*7c478bd9Sstevel@tonic-gate 	}
943*7c478bd9Sstevel@tonic-gate 
944*7c478bd9Sstevel@tonic-gate 	/*
945*7c478bd9Sstevel@tonic-gate 	 * Declare and initialize all print function pointers to null.
946*7c478bd9Sstevel@tonic-gate 	 * Some spec files result in nothing being put into the .pf
947*7c478bd9Sstevel@tonic-gate 	 * file.  We must create the file since make(1) does not cope
948*7c478bd9Sstevel@tonic-gate 	 * well with absent files that it expects to have built.  So
949*7c478bd9Sstevel@tonic-gate 	 * now the build gets empty compilation unit warnings...  So
950*7c478bd9Sstevel@tonic-gate 	 * we unconditionally create a static pointer.
951*7c478bd9Sstevel@tonic-gate 	 */
952*7c478bd9Sstevel@tonic-gate 	(void) fprintf(fp,
953*7c478bd9Sstevel@tonic-gate 	    "/* Do not edit this file: it is a generated one. */\n\n"
954*7c478bd9Sstevel@tonic-gate 	    "static char const *__abi_place_holder;\n\n");
955*7c478bd9Sstevel@tonic-gate 
956*7c478bd9Sstevel@tonic-gate 	generate_print_definitions(fp);
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 	/* Close file */
959*7c478bd9Sstevel@tonic-gate 	if (fclose(fp) != 0) {
960*7c478bd9Sstevel@tonic-gate 		errlog(FATAL, "fclose %s: %s", pathname, strerror(errno));
961*7c478bd9Sstevel@tonic-gate 	}
962*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
963*7c478bd9Sstevel@tonic-gate 	return (YES);
964*7c478bd9Sstevel@tonic-gate }
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 
967*7c478bd9Sstevel@tonic-gate 
968*7c478bd9Sstevel@tonic-gate /*
969*7c478bd9Sstevel@tonic-gate  * generate_includes -- generate #includes to Headfp
970*7c478bd9Sstevel@tonic-gate  */
971*7c478bd9Sstevel@tonic-gate static void
972*7c478bd9Sstevel@tonic-gate generate_includes(void)
973*7c478bd9Sstevel@tonic-gate {
974*7c478bd9Sstevel@tonic-gate 	char	*include;
975*7c478bd9Sstevel@tonic-gate 
976*7c478bd9Sstevel@tonic-gate 	errlog(BEGIN, "generate_includes() {");
977*7c478bd9Sstevel@tonic-gate 	errlog(TRACING,  "includes=");
978*7c478bd9Sstevel@tonic-gate 	for (include = symtab_get_first_include(); include != NULL;
979*7c478bd9Sstevel@tonic-gate 	    include = symtab_get_next_include())
980*7c478bd9Sstevel@tonic-gate 		(void) fprintf(Headfp, "#include %s\n", include);
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate 	(void) fprintf(Headfp, "\n#include <stdio.h>\n"
983*7c478bd9Sstevel@tonic-gate 	    "#include <dlfcn.h>\n"
984*7c478bd9Sstevel@tonic-gate 	    "#include <apptrace.h>\n\n");
985*7c478bd9Sstevel@tonic-gate 
986*7c478bd9Sstevel@tonic-gate 	errlog(TRACING,  "\n");
987*7c478bd9Sstevel@tonic-gate 	errlog(END, "}");
988*7c478bd9Sstevel@tonic-gate }
989