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 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 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 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 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 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 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 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 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 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 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 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 426 generate_i_evaluations(ENTRY *function) 427 { 428 errlog(BEGIN, "generate_i_evaluations() {"); 429 errlog(END, "}"); 430 } 431 432 433 static char * 434 variables_get_errorname(void) 435 { 436 return ("ABI_ERRNO"); 437 } 438