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