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