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
generate_interceptor(ENTRY * function)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
print_function_signature(char * xtype,char * name,char * formals)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
generate_i_declarations(char * errname,int voidfunc,char * ret_str)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
generate_i_preamble(ENTRY * function)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
generate_i_call(ENTRY * function,int void_func,char * library_name,char * error_name)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
generate_i_postamble(ENTRY * function,int void_func,char * error_name,char * library_name)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
generate_i_bindings(int void_func)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
generate_return_printf(int void_func)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
generate_i_prints(ENTRY * function,char * lib,char * func)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
generate_i_closedown(char * error_name,int void_func)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
generate_i_live_vars(ENTRY * function)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
generate_i_evaluations(ENTRY * function)426 generate_i_evaluations(ENTRY *function)
427 {
428 errlog(BEGIN, "generate_i_evaluations() {");
429 errlog(END, "}");
430 }
431
432
433 static char *
variables_get_errorname(void)434 variables_get_errorname(void)
435 {
436 return ("ABI_ERRNO");
437 }
438