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