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