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 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 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 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 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 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 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 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 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 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 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 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 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 * 434*753d2d2eSraf variables_get_errorname(void) 435*753d2d2eSraf { 436*753d2d2eSraf return ("ABI_ERRNO"); 437*753d2d2eSraf } 438