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