xref: /onnv-gate/usr/src/cmd/abi/spectrans/spec2trace/interceptor.c (revision 2775:892d346f56a9)
1*2775Sraf /*
2*2775Sraf  * CDDL HEADER START
3*2775Sraf  *
4*2775Sraf  * The contents of this file are subject to the terms of the
5*2775Sraf  * Common Development and Distribution License, Version 1.0 only
6*2775Sraf  * (the "License").  You may not use this file except in compliance
7*2775Sraf  * with the License.
8*2775Sraf  *
9*2775Sraf  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*2775Sraf  * or http://www.opensolaris.org/os/licensing.
11*2775Sraf  * See the License for the specific language governing permissions
12*2775Sraf  * and limitations under the License.
13*2775Sraf  *
14*2775Sraf  * When distributing Covered Code, include this CDDL HEADER in each
15*2775Sraf  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*2775Sraf  * If applicable, add the following below this CDDL HEADER, with the
17*2775Sraf  * fields enclosed by brackets "[]" replaced with your own identifying
18*2775Sraf  * information: Portions Copyright [yyyy] [name of copyright owner]
19*2775Sraf  *
20*2775Sraf  * CDDL HEADER END
21*2775Sraf  */
22*2775Sraf /*
23*2775Sraf  * Copyright (c) 1997-2000 by Sun Microsystems, Inc.
24*2775Sraf  * All rights reserved.
25*2775Sraf  */
26*2775Sraf 
27*2775Sraf #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*2775Sraf 
29*2775Sraf /*
30*2775Sraf  * interceptor.c -- a functional decomposition of generate.c,
31*2775Sraf  *	the code generator for apptrace
32*2775Sraf  */
33*2775Sraf 
34*2775Sraf #include <stdio.h>
35*2775Sraf #include <stdlib.h>
36*2775Sraf #include <string.h>
37*2775Sraf #include <unistd.h>
38*2775Sraf #include <sys/types.h>
39*2775Sraf #include "parser.h"
40*2775Sraf #include "trace.h"
41*2775Sraf #include "util.h"
42*2775Sraf #include "db.h"
43*2775Sraf #include "symtab.h"
44*2775Sraf #include "io.h"
45*2775Sraf #include "bindings.h"
46*2775Sraf #include "printfuncs.h"
47*2775Sraf #include "errlog.h"
48*2775Sraf #include "parseproto.h"
49*2775Sraf 
50*2775Sraf static void generate_i_declarations(char *, int, char *);
51*2775Sraf static void generate_i_preamble(ENTRY *);
52*2775Sraf static void generate_i_call();
53*2775Sraf static int  generate_i_bindings(int);
54*2775Sraf static void generate_i_postamble(ENTRY *, int, char *, char *);
55*2775Sraf static void generate_i_evaluations(ENTRY *);
56*2775Sraf static void generate_i_prints(ENTRY *, char *, char *);
57*2775Sraf static void generate_i_closedown(char *, int);
58*2775Sraf static void generate_i_live_vars(ENTRY *);
59*2775Sraf static void generate_return_printf(int);
60*2775Sraf static char *variables_get_errorname(void);
61*2775Sraf 
62*2775Sraf /*
63*2775Sraf  * generate_interceptor -- make code for an individual interceptor, written
64*2775Sraf  *	as an output grammar
65*2775Sraf  */
66*2775Sraf void
generate_interceptor(ENTRY * function)67*2775Sraf generate_interceptor(ENTRY *function)
68*2775Sraf {
69*2775Sraf 	char	*prototype = symtab_get_prototype(),
70*2775Sraf 		*library_name = db_get_current_library(),
71*2775Sraf 		*function_name,
72*2775Sraf 		*error_name;
73*2775Sraf 	int	void_func;
74*2775Sraf 
75*2775Sraf 	errlog(BEGIN, "generate_interceptor() {");
76*2775Sraf 
77*2775Sraf 	/* Check for required information. */
78*2775Sraf 	if (validity_of(function) == NO) {
79*2775Sraf 		symtab_set_skip(YES);
80*2775Sraf 		errlog(WARNING|INPUT, "No prototype for interface, "
81*2775Sraf 			"it will be skipped");
82*2775Sraf 		errlog(END, "}");
83*2775Sraf 		return;
84*2775Sraf 	}
85*2775Sraf 
86*2775Sraf 	/* Collect things we'll use more than once. */
87*2775Sraf 	function_name = name_of(function);
88*2775Sraf 
89*2775Sraf 	error_name = variables_get_errorname();
90*2775Sraf 
91*2775Sraf 	void_func = is_void(function);
92*2775Sraf 
93*2775Sraf 	/*
94*2775Sraf 	 * Emit "artificial" prototype here so that if there's a
95*2775Sraf 	 * disagreement between it and the prototype contained in the
96*2775Sraf 	 * declaring header, the compiler will flag it.
97*2775Sraf 	 * First #undef the function to make sure the prototype in the header
98*2775Sraf 	 * is exposed and to avoid breaking the artificial prototype if it's
99*2775Sraf 	 * not.
100*2775Sraf 	 */
101*2775Sraf 	{
102*2775Sraf 		decl_t *dp;
103*2775Sraf 		char *buf;
104*2775Sraf 		char const *err;
105*2775Sraf 		size_t s;
106*2775Sraf 
107*2775Sraf 		s = strlen(prototype) + 2;
108*2775Sraf 		buf = malloc(s);
109*2775Sraf 		if (buf == NULL)
110*2775Sraf 			abort();
111*2775Sraf 		(void) strcpy(buf, prototype);
112*2775Sraf 		buf[s - 2] = ';';
113*2775Sraf 		buf[s - 1] = '\0';
114*2775Sraf 
115*2775Sraf 		err = decl_Parse(buf, &dp);
116*2775Sraf 		if (err != NULL)
117*2775Sraf 			errlog(FATAL, "\"%s\", line %d: %s: %s",
118*2775Sraf 			    symtab_get_filename(), line_of(function),
119*2775Sraf 			    err, prototype);
120*2775Sraf 
121*2775Sraf 		/* generate the mapfile entry */
122*2775Sraf 		(void) fprintf(Mapfp, "\t__abi_%s;\n", decl_GetName(dp));
123*2775Sraf 
124*2775Sraf 		(void) decl_ToString(buf, DTS_DECL, dp, function_name);
125*2775Sraf 		(void) fprintf(Bodyfp, "#line %d \"%s\"\n",
126*2775Sraf 		    line_of(function), symtab_get_filename());
127*2775Sraf 		(void) fprintf(Bodyfp, "#undef %s\n", function_name);
128*2775Sraf 		(void) fprintf(Bodyfp, "extern %s;\n", buf);
129*2775Sraf 
130*2775Sraf 		(void) fprintf(Bodyfp, "static %s\n{\n", prototype);
131*2775Sraf 
132*2775Sraf 		(void) decl_ToString(buf, DTS_RET, dp, "_return");
133*2775Sraf 		generate_i_declarations(error_name, void_func, buf);
134*2775Sraf 		decl_Destroy(dp);
135*2775Sraf 		free(buf);
136*2775Sraf 	}
137*2775Sraf 
138*2775Sraf 	generate_i_preamble(function);
139*2775Sraf 	generate_i_call(function, void_func, library_name, error_name);
140*2775Sraf 	generate_i_postamble(function, void_func, error_name, library_name);
141*2775Sraf 
142*2775Sraf 	errlog(END, "}");
143*2775Sraf }
144*2775Sraf 
145*2775Sraf /*
146*2775Sraf  * print_function_signature -- print the line defining the function, without
147*2775Sraf  *      an ``extern'' prefix or either a ``;'' or ''{'' suffix.
148*2775Sraf  */
149*2775Sraf void
print_function_signature(char * xtype,char * name,char * formals)150*2775Sraf print_function_signature(char *xtype, char *name, char *formals)
151*2775Sraf {
152*2775Sraf 	char	buffer[MAXLINE];
153*2775Sraf 
154*2775Sraf 	(void) snprintf(buffer, sizeof (buffer), "%s", name);
155*2775Sraf 	(void) fprintf(Bodyfp,  xtype, buffer);
156*2775Sraf 	if (strstr(xtype, "(*") == NULL) {
157*2775Sraf 		(void) fprintf(Bodyfp,  "(%s)", formals);
158*2775Sraf 	}
159*2775Sraf }
160*2775Sraf 
161*2775Sraf 
162*2775Sraf /*
163*2775Sraf  * generate_i_declarations -- generate the declarations which
164*2775Sraf  *      are local to the interceptor function itself.
165*2775Sraf  */
166*2775Sraf static void
generate_i_declarations(char * errname,int voidfunc,char * ret_str)167*2775Sraf generate_i_declarations(char *errname, int voidfunc, char *ret_str)
168*2775Sraf {
169*2775Sraf 
170*2775Sraf 	errlog(BEGIN, "generate_i_declarations() {");
171*2775Sraf 	if (*errname != NULL) {
172*2775Sraf 		/* Create locals for errno-type variable, */
173*2775Sraf 		(void) fprintf(Bodyfp,
174*2775Sraf 		    "    int saved_errvar = %s;\n", errname);
175*2775Sraf 		(void) fprintf(Bodyfp,  "    int functions_errvar;\n");
176*2775Sraf 	}
177*2775Sraf 
178*2775Sraf 	if (need_exception_binding()) {
179*2775Sraf 		/* Create a local for that. */
180*2775Sraf 		(void) fprintf(Bodyfp,  "    int exception = 0;\n");
181*2775Sraf 	}
182*2775Sraf 	if (! voidfunc) {
183*2775Sraf 		/* Create a return value. */
184*2775Sraf 		(void) fprintf(Bodyfp,  "    %s;\n", ret_str);
185*2775Sraf 	}
186*2775Sraf 	(void) fprintf(Bodyfp, "    sigset_t omask;\n");
187*2775Sraf 	(void) putc('\n', Bodyfp);
188*2775Sraf 	errlog(END, "}");
189*2775Sraf }
190*2775Sraf 
191*2775Sraf 
192*2775Sraf /*
193*2775Sraf  * generate_i_preamble -- do the actions which must occur
194*2775Sraf  *      before the call.
195*2775Sraf  */
196*2775Sraf static void
generate_i_preamble(ENTRY * function)197*2775Sraf generate_i_preamble(ENTRY *function)
198*2775Sraf {
199*2775Sraf 	errlog(BEGIN, "generate_i_preamble() {");
200*2775Sraf 	generate_i_live_vars(function); /* Deferred. */
201*2775Sraf 
202*2775Sraf 	if (symtab_get_nonreturn() == YES) {
203*2775Sraf 		/* Make things safe for printing */
204*2775Sraf 		(void) fprintf(Bodyfp,
205*2775Sraf 		    "    abilock(&omask);\n");
206*2775Sraf 		/* Print all the args in terse format. */
207*2775Sraf 		generate_printf(function);
208*2775Sraf 		(void) fputs("    putc('\\n', ABISTREAM);\n\n", Bodyfp);
209*2775Sraf 		/* unlock stdio */
210*2775Sraf 		(void) fprintf(Bodyfp,
211*2775Sraf 		    "    abiunlock(&omask);\n");
212*2775Sraf 	}
213*2775Sraf 
214*2775Sraf 	errlog(END, "}");
215*2775Sraf }
216*2775Sraf 
217*2775Sraf /*
218*2775Sraf  * generate_i_call -- implement the save/call/restore cycle
219*2775Sraf  */
220*2775Sraf static void
generate_i_call(ENTRY * function,int void_func,char * library_name,char * error_name)221*2775Sraf generate_i_call(
222*2775Sraf 	ENTRY	*function,
223*2775Sraf 	int	void_func,
224*2775Sraf 	char	*library_name,
225*2775Sraf 	char	*error_name)
226*2775Sraf {
227*2775Sraf 	char	*function_name = name_of(function),
228*2775Sraf 		*function_cast = symtab_get_cast(),
229*2775Sraf 		*actual_args = symtab_get_actuals();
230*2775Sraf 
231*2775Sraf 	errlog(BEGIN, "generate_i_call() {");
232*2775Sraf 	/* Zero the error variable. */
233*2775Sraf 	if (*error_name != NULL) {
234*2775Sraf 		(void) fprintf(Bodyfp,  "    %s = 0;\n", error_name);
235*2775Sraf 	}
236*2775Sraf 
237*2775Sraf 	/* Then print the call itself. */
238*2775Sraf 	if (void_func) {
239*2775Sraf 		(void) fprintf(Bodyfp,
240*2775Sraf 		    "    (void) ABI_CALL_REAL(%s, %s, %s)(%s);\n",
241*2775Sraf 		    library_name, function_name, function_cast, actual_args);
242*2775Sraf 	} else {
243*2775Sraf 		(void) fprintf(Bodyfp,
244*2775Sraf 		    "    _return = ABI_CALL_REAL(%s, %s, %s)(%s);\n",
245*2775Sraf 		    library_name, function_name, function_cast, actual_args);
246*2775Sraf 	}
247*2775Sraf 
248*2775Sraf 	/* Then set the local copy of the error variable. */
249*2775Sraf 	if (*error_name != NULL) {
250*2775Sraf 		(void) fprintf(Bodyfp,
251*2775Sraf 		    "    functions_errvar = %s;\n", error_name);
252*2775Sraf 	}
253*2775Sraf 	(void) putc('\n', Bodyfp);
254*2775Sraf 
255*2775Sraf 	/* Make things safe for printing */
256*2775Sraf 	(void) fprintf(Bodyfp,
257*2775Sraf 	    "    abilock(&omask);\n");
258*2775Sraf 
259*2775Sraf 	errlog(END, "}");
260*2775Sraf }
261*2775Sraf 
262*2775Sraf /*
263*2775Sraf  * generate_i_postamble -- do all the things which come
264*2775Sraf  *      after the call.  In the case of apptrace, this is most of the work.
265*2775Sraf  */
266*2775Sraf static void
generate_i_postamble(ENTRY * function,int void_func,char * error_name,char * library_name)267*2775Sraf generate_i_postamble(ENTRY *function, int void_func,
268*2775Sraf     char *error_name, char *library_name)
269*2775Sraf {
270*2775Sraf 	errlog(BEGIN, "generate_i_postamble() {");
271*2775Sraf 	if (symtab_get_nonreturn() == NO) {
272*2775Sraf 		/* Print all the args in terse format. */
273*2775Sraf 		generate_printf(function);
274*2775Sraf 	}
275*2775Sraf 
276*2775Sraf 	/* If it isn't supposed to return, and actually ends up here, */
277*2775Sraf 	/* we'd better be prepared to print all sorts of diagnostic stuff */
278*2775Sraf 	(void) putc('\n', Bodyfp);
279*2775Sraf 	if (generate_i_bindings(void_func) == YES) {
280*2775Sraf 		generate_return_printf(void_func);
281*2775Sraf 	}
282*2775Sraf 
283*2775Sraf 	generate_i_prints(function, library_name, name_of(function));
284*2775Sraf 	generate_i_evaluations(function); /* Deferred */
285*2775Sraf 	generate_i_closedown(error_name, void_func);
286*2775Sraf 	errlog(END, "}");
287*2775Sraf }
288*2775Sraf 
289*2775Sraf /*
290*2775Sraf  * generate_i_bindings -- see about success and failure, so we can decide
291*2775Sraf  *      what to do next.
292*2775Sraf  */
293*2775Sraf static int
generate_i_bindings(int void_func)294*2775Sraf generate_i_bindings(int void_func)
295*2775Sraf {
296*2775Sraf 	ENTRY   *e;
297*2775Sraf 	char *exception;
298*2775Sraf 
299*2775Sraf 	exception  = ((e = symtab_get_exception()) != NULL)?
300*2775Sraf 	    (name_of(e)? name_of(e): ""): "";
301*2775Sraf 
302*2775Sraf 	errlog(BEGIN, "generate_i_bindings() {");
303*2775Sraf 	if (void_func && bindings_exist()) {
304*2775Sraf 		/* To become a warning, as there are spec errors! TBD */
305*2775Sraf 		errlog(FATAL, "exception bindings found in a "
306*2775Sraf 			"void function");
307*2775Sraf 	} else if (void_func || need_bindings(exception) == NO) {
308*2775Sraf 		(void) fprintf(Bodyfp,
309*2775Sraf 		    "    (void) putc('\\n', ABISTREAM);\n");
310*2775Sraf 		(void) putc('\n', Bodyfp);
311*2775Sraf 		errlog(END, "}");
312*2775Sraf 		return (NO);
313*2775Sraf 	} else {
314*2775Sraf 		/*
315*2775Sraf 		 * Then there is a return value, so we try to
316*2775Sraf 		 * generate exception bindings
317*2775Sraf 		 * and code to print errno on exception.
318*2775Sraf 		 */
319*2775Sraf 		if ((generate_bindings(exception)) != ANTONYMS) {
320*2775Sraf 			/* Generate code to cross-evaluate them. */
321*2775Sraf 			(void) fprintf(Bodyfp,
322*2775Sraf 			    "    if (!exception) {\n");
323*2775Sraf 			errlog(END, "}");
324*2775Sraf 			return (YES);
325*2775Sraf 		}
326*2775Sraf 	}
327*2775Sraf 
328*2775Sraf 	/* should not get here */
329*2775Sraf 	errlog(END, "}");
330*2775Sraf 	return (NO);
331*2775Sraf }
332*2775Sraf 
333*2775Sraf /*
334*2775Sraf  * generate_return_printf -- print the return value and end the line
335*2775Sraf  */
336*2775Sraf static void
generate_return_printf(int void_func)337*2775Sraf generate_return_printf(int void_func)
338*2775Sraf {
339*2775Sraf 	errlog(BEGIN, "generate_return_printf() {");
340*2775Sraf 	if (void_func) {
341*2775Sraf 		(void) fprintf(Bodyfp,  "    putc('\\n', ABISTREAM);\n");
342*2775Sraf 		errlog(END, "}");
343*2775Sraf 		return;
344*2775Sraf 	}
345*2775Sraf 	/* If its a non-void function there are bindings. */
346*2775Sraf 	(void) fprintf(Bodyfp,
347*2775Sraf 	    "\t/* Just end the line */\n"
348*2775Sraf 	    "\tputc('\\n', ABISTREAM);\n"
349*2775Sraf 	    "    }\n"
350*2775Sraf 	    "    else {\n"
351*2775Sraf 	    "        fprintf(ABISTREAM, \"%%s%%d (%%s)\\n\", errnostr, "
352*2775Sraf 	    "functions_errvar, strerror((int)functions_errvar));\n"
353*2775Sraf 	    "    }\n\n");
354*2775Sraf 	errlog(END, "}");
355*2775Sraf }
356*2775Sraf 
357*2775Sraf /*
358*2775Sraf  * generate_i_prints -- if we're doing the verbose stuff,
359*2775Sraf  *      generate verbose printouts of the variables.
360*2775Sraf  */
361*2775Sraf static void
generate_i_prints(ENTRY * function,char * lib,char * func)362*2775Sraf generate_i_prints(ENTRY *function, char *lib, char *func)
363*2775Sraf {
364*2775Sraf 	ENTRY   *e;
365*2775Sraf 
366*2775Sraf 	errlog(BEGIN, "generate_i_prints() {");
367*2775Sraf 	if ((e = symtab_get_first_arg()) != NULL || !is_void(e)) {
368*2775Sraf 		/* Then we have to generate code for verbose reports. */
369*2775Sraf 		(void) fprintf(Bodyfp,  "    if (ABI_VFLAG(%s, %s) != 0) {\n",
370*2775Sraf 			lib, func);
371*2775Sraf 		generate_printfunc_calls(function);
372*2775Sraf 		(void) fprintf(Bodyfp,  "    }\n");
373*2775Sraf 	}
374*2775Sraf 	(void) putc('\n', Bodyfp);
375*2775Sraf 	errlog(END, "}");
376*2775Sraf }
377*2775Sraf 
378*2775Sraf /*
379*2775Sraf  * generate_i_closedown -- restore error variables and return.
380*2775Sraf  */
381*2775Sraf static void
generate_i_closedown(char * error_name,int void_func)382*2775Sraf generate_i_closedown(char *error_name, int void_func)
383*2775Sraf {
384*2775Sraf 	errlog(BEGIN, "generate_i_closedown() {");
385*2775Sraf 
386*2775Sraf 	/* unlock stdio */
387*2775Sraf 	(void) fprintf(Bodyfp,
388*2775Sraf 	    "    abiunlock(&omask);\n");
389*2775Sraf 
390*2775Sraf 	if (*error_name != NULL) {
391*2775Sraf 		/* Restore error variables. */
392*2775Sraf 		(void) fprintf(Bodyfp,
393*2775Sraf 		    "    %s = (functions_errvar == 0)? "
394*2775Sraf 		    "            saved_errvar: functions_errvar;\n",
395*2775Sraf 		    error_name);
396*2775Sraf 	}
397*2775Sraf 
398*2775Sraf 	/* And return. */
399*2775Sraf 	(void) fprintf(Bodyfp,
400*2775Sraf 	    "    return%s;\n",
401*2775Sraf 	    (void_func)? "": " _return");
402*2775Sraf 	(void) fprintf(Bodyfp,  "}\n");
403*2775Sraf 	(void) putc('\n', Bodyfp);
404*2775Sraf 	errlog(END, "}");
405*2775Sraf }
406*2775Sraf 
407*2775Sraf 
408*2775Sraf /*
409*2775Sraf  * generate_i_live_vars -- generate temps for any ``out''
410*2775Sraf  *	or ``inout'' variables in the function.  Deferred.
411*2775Sraf  */
412*2775Sraf /*ARGSUSED*/
413*2775Sraf static void
generate_i_live_vars(ENTRY * function)414*2775Sraf generate_i_live_vars(ENTRY *function)
415*2775Sraf {
416*2775Sraf 	errlog(BEGIN, "generate_i_live_vars() {");
417*2775Sraf 	errlog(END, "}");
418*2775Sraf }
419*2775Sraf 
420*2775Sraf /*
421*2775Sraf  * generate_i_evaluations -- generate evaluations for
422*2775Sraf  *	all the expressions. Deferred.
423*2775Sraf  */
424*2775Sraf /*ARGSUSED*/
425*2775Sraf static void
generate_i_evaluations(ENTRY * function)426*2775Sraf generate_i_evaluations(ENTRY *function)
427*2775Sraf {
428*2775Sraf 	errlog(BEGIN, "generate_i_evaluations() {");
429*2775Sraf 	errlog(END, "}");
430*2775Sraf }
431*2775Sraf 
432*2775Sraf 
433*2775Sraf static char *
variables_get_errorname(void)434*2775Sraf variables_get_errorname(void)
435*2775Sraf {
436*2775Sraf 	return ("ABI_ERRNO");
437*2775Sraf }
438