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-2001 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * 31 * trace.c -- a simple translator from spec source to c source for 32 * a apptrace interposer library. This file implements the 33 * (interface to) the front end. Other files implement the middle 34 * and databases, and generate.c implements the back end. 35 * 36 */ 37 38 #include <stdio.h> 39 #include <errno.h> 40 #include <stdlib.h> 41 #include <sys/types.h> 42 #include <time.h> 43 #include <string.h> 44 45 #include "parser.h" 46 #include "trace.h" 47 48 #include "util.h" 49 #include "db.h" 50 #include "symtab.h" 51 #include "io.h" 52 #include "printfuncs.h" 53 #include "errlog.h" 54 #include "parseproto.h" 55 56 static int Verbose; 57 58 /* File globals. This would be better as a class. */ 59 /* The first four (commented out) of these enums are defined in parser.h */ 60 enum { 61 /* XLATOR_KW_NOTFOUND = 0, */ 62 /* XLATOR_KW_FUNC, */ 63 /* XLATOR_KW_DATA */ 64 /* XLATOR_KW_END */ 65 XLATOR_KW_EXCP = 4, 66 XLATOR_KW_DECL, 67 XLATOR_KW_INCL, 68 XLATOR_KW_ERRNO, 69 XLATOR_KW_ERRVAL, 70 XLATOR_KW_ARCH, 71 XLATOR_KW_WEAK 72 }; 73 #define FIRST_TOKEN 4 /* Must match the first token in the above enum */ 74 75 static xlator_keyword_t Keywords[] = { 76 { "exception", XLATOR_KW_EXCP }, 77 { "declaration", XLATOR_KW_DECL }, 78 { "include", XLATOR_KW_INCL }, 79 { "errno", XLATOR_KW_ERRNO }, 80 { "errval", XLATOR_KW_ERRVAL}, 81 { "arch", XLATOR_KW_ARCH}, 82 { "weak", XLATOR_KW_WEAK}, 83 { "weakfor", XLATOR_KW_WEAK}, 84 { "alias", XLATOR_KW_WEAK}, 85 { NULL, XLATOR_KW_NOTFOUND } 86 }; 87 88 static struct stats_t { 89 int libraries, 90 files, 91 interfaces, 92 lines; 93 int errors, 94 warnings, 95 skips; 96 time_t start, 97 end; 98 } Statistics; 99 100 #define LINE (m.mi_line_number-(m.mi_nlines-1)) 101 102 static void stats_init(void); 103 static void stats_report(void); 104 105 static int collect_binding(int const, char *, int); 106 static int collect_prototype(char *, int, int); 107 static int collect_include(char *, int); 108 static int collect_errval(char *, int); 109 static int collect_arch(char *); 110 111 static void generate_includes(void); 112 static void generate_init(void); 113 static void generate_interface(void); 114 static void generate_closedown(void); 115 static int generate_aux_file(); 116 117 /* Local (static) parsing functions. */ 118 static char *to_actual(); 119 static int to_basetype(char *); 120 static char *de_const(char *); 121 static char *strpqcpy(char *, char *, char *); 122 123 /* 124 * xlator_init -- initialize translator, called at startup-time 125 * with a struct translator_info of information the translator 126 * might need, returning a list of ``interesting'' spec keywords 127 * for the front end to select and pass to the back end translator. 128 * 129 */ 130 xlator_keyword_t * 131 xlator_init(const Translator_info *t_info) 132 { 133 int i; 134 135 errlog(BEGIN, "xlator_init() {"); 136 137 /* Save interesting parameters. */ 138 stats_init(); 139 db_set_source_directory("."); 140 db_set_target_directory("."); 141 Verbose = t_info->ti_verbosity; 142 seterrseverity(Verbose); /* Ditto. */ 143 db_set_output_file(t_info->ti_output_file); 144 db_set_arch(t_info->ti_arch); 145 146 /* Display passed argument and return value. */ 147 errlog(VERBOSE, "Keywords[] = {"); 148 for (i = 0; Keywords[i].key != NULL; i++) { 149 errlog(VERBOSE, " \"%s\", ", Keywords[i].key); 150 } 151 errlog(VERBOSE, " (char *) NULL"); 152 errlog(VERBOSE, "};"); 153 154 errlog(END, "}"); 155 return (Keywords); 156 } 157 158 /* 159 * xlator_startlib -- called on starting a new library, so back end 160 * translator can decide to change output file/directory if desired. 161 */ 162 int 163 xlator_startlib(char const *libname) 164 { 165 errlog(BEGIN, "xlator_startlib() "); 166 167 Statistics.libraries++; 168 db_set_current_library(libname); 169 errlog(VERBOSE, "now in library \"%s\"", libname); 170 errlog(END, "}"); 171 return (SUCCESS_RC); 172 } 173 174 /* 175 * xlator_startfile -- ditto, called on starting each new spec file in the 176 * specified library. 177 */ 178 int 179 xlator_startfile(char const *filename) 180 { 181 int rc = SUCCESS_RC; 182 char infile[MAXLINE], 183 outfile[MAXLINE], 184 *lib = db_get_current_library(); 185 186 seterrline(0, filename, "", ""); 187 errlog(BEGIN, "xlator_startfile() {"); 188 Statistics.files++; 189 db_set_current_file(filename); 190 errlog(TRACING, "now in file \"%s\" in lib \"%s\"", 191 filename, lib); 192 193 /* Generate filenames. */ 194 (void) snprintf(infile, sizeof (infile), "%s", filename); 195 (void) snprintf(outfile, sizeof (outfile), "%s.c", 196 db_get_output_file()); 197 198 /* Open .c file. */ 199 if (open_code_file() == NO) { 200 rc = ERROR_RC; 201 } 202 203 generate_init(); /* Write stuff to the c file. */ 204 symtab_clear_includes(); /* Clear out the per-file data. */ 205 errlog(END, "}"); 206 return (rc); 207 } 208 209 /* 210 * xlator_start_if -- tritto, called on starting each new 211 * interface in the spec file. 212 */ 213 int 214 xlator_start_if(const Meta_info m, int const token, char *value) 215 { 216 char ifname[BUFSIZ]; 217 char *kw; 218 219 switch (token) { 220 case XLATOR_KW_FUNC: 221 kw = "Function"; 222 break; 223 case XLATOR_KW_DATA: 224 kw = "Data"; 225 break; 226 default: 227 /* This should never happen */ 228 errlog(ERROR, 229 "\"%s\", line %d: Implementation error! " 230 "Please file a bug\n", __FILE__, __LINE__); 231 return (XLATOR_FATAL); 232 } 233 234 seterrline(LINE, m.mi_filename, kw, value); 235 errlog(BEGIN, "xlator_start_if() {"); 236 237 /* 238 * XXX Note whether interface is function or data in some state data item. 239 * We'll need it later when writing interceptors. 240 */ 241 242 Statistics.interfaces++; 243 (void) strpqcpy(ifname, value, nextsep2(value)); 244 if (*ifname == '\0') { 245 errlog(INPUT|ERROR|FATAL, 246 "missing argument in \"%s\" line", kw); 247 } 248 db_set_current_interface(ifname); 249 errlog(VERBOSE, "interface='%s'", value); 250 if (token == XLATOR_KW_DATA) { 251 Statistics.skips++; 252 errlog(VERBOSE, "telling front end to skip '%s'", value); 253 errlog(END, "}"); 254 return (SKIP_RC); /* Tell front end to skip it for us. */ 255 } 256 257 errlog(TRACING, "now in interface \"%s\"", value); 258 259 symtab_new_function(m.mi_line_number, m.mi_filename); 260 /* Also cleans junk out of symbol table. */ 261 errlog(END, "}"); 262 return (SUCCESS_RC); 263 } 264 265 /* 266 * xlator_take_kvpair -- the primary call: collect a datum provide by the 267 * front-end wrapper. 268 */ 269 int 270 xlator_take_kvpair(Meta_info m, int const token, char *value) 271 { 272 int retval; 273 char *key = Keywords[token-FIRST_TOKEN].key; 274 275 int line = LINE; /* TBD */ 276 symtab_set_filename(m.mi_filename); 277 278 value = strnormalize(value); 279 280 seterrline(line, m.mi_filename, key, value); 281 errlog(BEGIN, "xlator_take_kvpair() {"); 282 Statistics.lines++; 283 errlog(VERBOSE, "key='%s', value='%s'", 284 (key) ? key : "<nil>", 285 (value) ? value : "<nil>"); 286 switch (token) { 287 case XLATOR_KW_DECL: 288 289 /* 290 * XXX Check state item to see that it is a function, 291 * else do not emit interceptor 292 */ 293 symtab_clear_function(); /* Always use last one. */ 294 errlog(END, "}"); 295 retval = collect_prototype(value, line, m.mi_ext_cnt); 296 break; 297 298 case XLATOR_KW_INCL: 299 errlog(END, "}"); /* Use union of all includes. */ 300 retval = collect_include(value, line); 301 if (retval == ERROR_RC) { 302 errlog(FATAL|INPUT, "Bad include line in spec file"); 303 } 304 break; 305 306 case XLATOR_KW_EXCP: 307 symtab_clear_exception(); /* Always use last. */ 308 retval = collect_binding(token, value, line); 309 break; 310 311 case XLATOR_KW_ERRNO: 312 symtab_clear_errval(); /* Always use last. */ 313 retval = collect_errval("errno", line); 314 break; 315 316 case XLATOR_KW_ERRVAL: 317 symtab_clear_errval(); /* Always use last. */ 318 retval = collect_errval(value, line); 319 break; 320 321 case XLATOR_KW_ARCH: 322 retval = collect_arch(value); 323 break; 324 325 case XLATOR_KW_WEAK: 326 if (m.mi_extended == 1) { 327 errlog(ERROR, "\"%s\", line %d: " 328 "Warning: Cannot use extends with a weak " 329 "interface", 330 m.mi_filename, 331 m.mi_line_number); 332 } 333 retval = SUCCESS_RC; 334 break; 335 default: 336 retval = ERROR_RC; 337 } 338 339 errlog(END, "}"); 340 341 return (retval); 342 } 343 344 /* 345 * xlator_end_if -- called at the end of the interface, to trigger 346 * per-interface processing now entire thing has been seen. 347 */ 348 /*ARGSUSED*/ 349 int 350 xlator_end_if(const Meta_info m, char const *value) 351 { 352 seterrline(LINE, m.mi_filename, "end", value); 353 errlog(BEGIN, "xlator_end_if() {"); 354 if (symtab_get_skip() == YES) { 355 symtab_set_skip(NO); 356 Statistics.skips++; 357 } else { 358 generate_interface(); 359 } 360 errlog(END, "}"); 361 return (SUCCESS_RC); 362 } 363 364 /* 365 * xlator_endfile -- called at the end of the file, to trigger per-file 366 * processing. 367 */ 368 int 369 xlator_endfile(void) 370 { 371 errlog(BEGIN, "xlator_endfile() {"); 372 373 generate_closedown(); 374 errlog(END, "}"); 375 return ((commit_code_file() == YES)? SUCCESS_RC: ERROR_RC); 376 } 377 378 /* 379 * xlator_endlib -- ditto, at the end of the library. 380 */ 381 int 382 xlator_endlib(void) 383 { 384 errlog(BEGIN, "xlator_endlib() {"); 385 errlog(END, "}"); 386 return (SUCCESS_RC); 387 } 388 389 /* 390 * xlator_end -- the end of the processing, called so translator 391 * can do cleanup, write makefiles, etc. 392 */ 393 int 394 xlator_end(void) 395 { 396 int rc = SUCCESS_RC; 397 398 errlog(BEGIN, "xlator_end() {"); 399 rc += !generate_aux_file(); 400 stats_report(); 401 errlog(END, "}"); 402 return (rc); 403 } 404 405 406 /* 407 ** utilities for this layer/phase only. 408 */ 409 410 /* 411 * stats_init -- note what time it is... 412 */ 413 static void 414 stats_init(void) 415 { 416 Statistics.start = time(NULL); 417 } 418 419 /* 420 * stats_report -- say how much we just did 421 */ 422 #define max(a, b) (a > b)? a: b 423 424 static void 425 stats_report(void) 426 { 427 double seconds; 428 429 Statistics.end = time(NULL); 430 seconds = difftime(Statistics.end, Statistics.start); 431 432 switch (Verbose) { 433 default: 434 /*FALLTHROUGH*/ 435 case 1: 436 (void) fprintf(stderr, "Statistics:\n" 437 " %d libraries\n %d files\n" 438 " %d interfaces\n %d lines\n" 439 " %d errors\n %d warnings\n" 440 " %d skips\n" 441 "in %.0f seconds, at %.1f lines/minute.\n", 442 Statistics.libraries, Statistics.files, 443 Statistics.interfaces, Statistics.lines, 444 Statistics.errors, Statistics.warnings, 445 Statistics.skips, 446 seconds, Statistics.lines*60.0/seconds); 447 break; 448 case 0: 449 if (Statistics.errors != 0 || Statistics.warnings != 0) { 450 (void) fprintf(stderr, 451 "spec2trace: %d errors %d warnings.\n", 452 Statistics.errors, Statistics.warnings); 453 } 454 break; 455 } 456 } 457 458 459 /* 460 * Tiny stats class... 461 */ 462 void 463 stats_add_warning(void) 464 { 465 Statistics.warnings++; 466 } 467 468 void 469 stats_add_error(void) 470 { 471 Statistics.errors++; 472 } 473 474 /* 475 * collect_includes -- collect a global list of include files, 476 * converting the comma- or space-separated input list into a 477 * structure for the database to store. 478 * As this can cause problems will ill-structured 479 * files, there is a mechanism to allow exclusion of 480 * certain files, (or certain combinations). At 481 * the moment, the mechanism is TBD, as is the second arg. 482 */ 483 /*ARGSUSED1*/ 484 int 485 collect_include(char *p, int line) 486 { 487 char *include; 488 int len; 489 490 errlog(BEGIN, "collect_include() {"); 491 if ((include = strtok(p, ", ")) != NULL) { 492 for (; include != NULL; include = strtok(NULL, ", ")) { 493 include = skipb(include); 494 495 /* 496 * Make sure the include file's name 497 * has legitimate C syntax - i.e. it's in double 498 * quotes or angle brackets. 499 */ 500 if (*include != '"' && *include != '<') 501 return (ERROR_RC); 502 503 len = strlen(include); 504 505 if (include[len-1] != '"' && include[len-1] != '>') 506 return (ERROR_RC); 507 508 /* 509 * If include filename syntax is OK, add it to 510 * the list 511 */ 512 symtab_add_includes(include); 513 } 514 } 515 errlog(END, "}"); 516 return (SUCCESS_RC); 517 } 518 519 /* 520 * collect_binding -- take a binding and stuff it into the database 521 * in canonical form (with the word return in it). 522 */ 523 int 524 collect_binding(int const token, char *value, int line) 525 { 526 char *file = db_get_current_file(); 527 528 errlog(BEGIN, "collect_binding() {"); 529 errlog(VERBOSE, "name=\"%s\", value=\"%s\", line=%d\n", 530 Keywords[token-FIRST_TOKEN].key, value, line); 531 532 if (token == XLATOR_KW_EXCP) { 533 symtab_set_exception(value, line, file); 534 } else { 535 errlog(FATAL|INPUT, "programmer error: impossible binding."); 536 } 537 errlog(END, "}"); 538 return (SUCCESS_RC); 539 } 540 541 /* 542 * collect_errval -- collect the error variable name (only) 543 * from the line. This is expected to be the first 544 * or only thing in a space- or comma-separated list. 545 * Collecting errno/errval possible value is left TBD. 546 */ 547 int 548 collect_errval(char *p, int line) 549 { 550 char *name; 551 552 errlog(BEGIN, "collect_errval() {"); 553 name = strtok(p, " \t\n\r"); 554 symtab_set_errval(name, line, db_get_current_file(), "int", "int", 0); 555 errlog(END, "}"); 556 return (SUCCESS_RC); 557 } 558 559 /* 560 * collect_arch -- collect architecture. 561 */ 562 int 563 collect_arch(char *value) 564 { 565 char const *arch = db_get_arch(); 566 char *buf, *p; 567 char *t; 568 569 errlog(BEGIN, "collect_arch() {"); 570 if (value == 0 || *value == '\0') 571 errlog(FATAL|INPUT, "No architectures defined in ARCH line"); 572 573 if ((buf = strdup(value)) == NULL) 574 errlog(FATAL, "Could not allocate memory in ARCH directive"); 575 576 t = buf; 577 while ((p = strtok(t, " \r\t\n")) != NULL) { 578 if (strcmp(p, arch) == 0 || strcmp(p, "all") == 0) 579 goto cleanup; 580 t = NULL; 581 } 582 symtab_set_skip(YES); 583 584 cleanup: 585 free(buf); 586 return (SUCCESS_RC); 587 } 588 589 /* 590 * de_const -- get rid of const meta-types. This is actually a 591 * dodge to avoid writing a base-type function early in the 592 * process. This may turn into to_basetype() or to_primitivetype(). 593 */ 594 static char * 595 de_const(char *type) 596 { 597 char *p, *q; 598 int i; 599 600 p = skipb(type); 601 602 q = strstr(type, "const"); 603 if (q > p) { 604 for (i = 0; i < 5; i++) { 605 *q++ = '\0'; 606 } 607 (void) sprintf(type, "%s%s", strnormalize(p), q); 608 return (type); 609 } else if (p == q) { 610 return (skipb(nextsep(p))); 611 } else { 612 return (type); 613 } 614 615 } 616 617 /* 618 * to_basetype -- convert a C type declaration into its base type and return 619 * the number of levels of indirection. 620 * Destructive and eats ``const''. 621 */ 622 static int 623 to_basetype(char *str) 624 { 625 char *p = str, 626 buffer[MAXLINE+1], 627 *q = &buffer[0]; 628 int levels = 0; 629 630 assert(strlen(str) < MAXLINE, "string exceeded MAXLINE"); 631 buffer[0] = NULL; 632 for (; *p != NULL; p++) { 633 switch (*p) { 634 case ' ': /* Convert spaces to single ' '. */ 635 if (*(q-1) != ' ') 636 *q++ = ' '; 637 break; 638 case '*': /* Convert * to _P. */ 639 if (*(q-1) != ' ') 640 *q++ = ' '; 641 levels++; 642 break; 643 case 'c': /* This might be a const */ 644 if (strncmp(p, "const", 5) == 0) { 645 p += 4; 646 } else { 647 *q++ = *p; 648 } 649 break; 650 default: 651 /* Otherwise just copy. */ 652 *q++ = *p; 653 break; 654 } 655 *q = NULL; 656 } 657 assert(q < &buffer[MAXLINE], "q fell off end of buffer"); 658 q--; 659 while (*q == ' ') { 660 *q-- = NULL; 661 } 662 assert(strlen(buffer) < MAXLINE, "buffer length exceeded MAXLINE"); 663 (void) strcpy(str, buffer); 664 return (levels); 665 } 666 667 /* 668 * to_actual -- create an actual-argument list for use 669 * when calling the function. 670 */ 671 static char * 672 to_actual(void) 673 { 674 ENTRY *p; 675 static char buffer[MAXLINE+1]; 676 int n; 677 678 *buffer = NULL; 679 if ((p = symtab_get_first_arg()) != NULL) { 680 n = MAXLINE - snprintf(buffer, MAXLINE, "%s", name_of(p)); 681 for (p = symtab_get_next_arg(); p != NULL; 682 p = symtab_get_next_arg()) { 683 if (*name_of(p) != NULL) 684 n -= snprintf(strend(buffer), n, 685 ", %s", name_of(p)); 686 } 687 } 688 return (buffer); 689 } 690 691 /* 692 * strpqcpy -- string copy that takes whatever begins with p and ends 693 * just before q. 694 */ 695 static char * 696 strpqcpy(char *target, char *p, char *q) 697 { 698 char saved; 699 700 saved = *q; 701 *q = NULL; 702 (void) strcpy(target, p); 703 *q = saved; 704 return (target); 705 } 706 707 #ifndef lint 708 int 709 breakpoint(void) 710 { 711 return (0); 712 } 713 #endif 714 715 716 int 717 collect_prototype(char *p, int line, int extcnt) 718 { 719 char f_type[BUFSIZ]; /* The function. */ 720 char f_basetype[BUFSIZ]; 721 char f_name[BUFSIZ]; 722 char a_name[BUFSIZ]; /* The arguments. */ 723 char a_basetype[BUFSIZ]; 724 char a_type[BUFSIZ]; 725 char *file = db_get_current_file(); 726 char *interface = db_get_current_interface(); 727 char *q; 728 char const *parse_err; 729 char tmp_proto[BUFSIZ], buf[BUFSIZ]; 730 decl_t *pp, *funargs; 731 type_t *tp; 732 int levels, a_levels; 733 734 tmp_proto[BUFSIZ-1] = 0; 735 errlog(BEGIN, "collect_prototype() {"); 736 if (p[strlen(p)-1] != ';') 737 (void) snprintf(tmp_proto, BUFSIZ, "%s;", p); 738 else 739 (void) snprintf(tmp_proto, BUFSIZ, "%s", p); 740 741 /* save prototype in symbol table */ 742 symtab_set_prototype(p); 743 744 errlog(VERBOSE, "parsing prototype: %s\n", tmp_proto); 745 746 /* Parse Prototype */ 747 if ((parse_err = decl_Parse(tmp_proto, &pp)) != NULL) { 748 errlog(FATAL|INPUT, "bad prototype: %s\n\t%s\n", parse_err, p); 749 } 750 751 if (extcnt == 0) { 752 char *dname = decl_GetName(pp); 753 if (strcmp(interface, dname) != 0) 754 errlog(FATAL|INPUT, "function and declaration" 755 " name mismatch\nfunction name = %s," 756 " declaration name = %s\n", interface, 757 dname); 758 } 759 760 tp = decl_GetType(pp); 761 762 if (type_IsPtrFun(tp)) { 763 errlog(FATAL|INPUT, "function %s is declared as a data item" 764 " (pointer to function)\n", interface); 765 } else if (!type_IsFunction(tp)) { 766 errlog(FATAL|INPUT, "function %s is declared as a data item", 767 interface); 768 } 769 770 if (type_IsVarargs(tp)) { 771 symtab_set_skip(YES); 772 decl_Destroy(pp); 773 return (SUCCESS_RC); 774 } 775 776 decl_GetTraceInfo(pp, f_type, f_basetype, &funargs); 777 (void) sprintf(buf, "%s", strnormalize(f_type)); 778 (void) strcpy(f_type, buf); 779 (void) sprintf(buf, "%s", strnormalize(f_basetype)); 780 (void) strcpy(f_basetype, buf); 781 levels = to_basetype(f_basetype); 782 783 /* get interface name from 'Begin' line */ 784 (void) strpqcpy(f_name, interface, nextsep(interface)); 785 (void) decl_SetName(pp, f_name); 786 787 errlog(VERBOSE, "f_name=%s, f_basetype=%s, f_type=%s\n", 788 f_name, f_basetype, f_type); 789 790 symtab_set_function(f_name, line, file, f_type, f_basetype, levels); 791 792 db_add_print_types(f_basetype, 793 (q = de_const(type_of(symtab_get_function())))); 794 795 symtab_add_print_types(f_basetype, q); 796 797 /* args list */ 798 while (funargs) { 799 (void) snprintf(a_type, BUFSIZ, "%s ", 800 strnormalize(declspec_ToString(buf, funargs->d_ds))); 801 (void) snprintf(a_basetype, BUFSIZ, "%s", 802 strnormalize(de_const(declspec_ToString(buf, 803 funargs->d_ds)))); 804 805 tp = funargs->d_type; 806 807 for (a_levels = 0; tp; ) { 808 if (tp->t_dt == DD_PTR || tp->t_dt == DD_ARY) { 809 (void) strcat(a_type, "*"); 810 a_levels++; 811 } 812 tp = tp->t_next; 813 } 814 815 /* 816 * XXX: This is a hack to work around bug in yacc parser 817 * "int foo(void)" prototypes get interpreted as having 1 818 * argument with the d_name of the argument being NULL. 819 */ 820 if (funargs->d_name) { 821 (void) snprintf(a_name, 20, "%s", funargs->d_name); 822 823 errlog(VERBOSE, 824 "a_name = %s, a_basetype = %s, a_type = %s\n", 825 a_name, a_basetype, a_type); 826 827 symtab_add_args(a_name, line, file, 828 a_type, a_basetype, a_levels); 829 db_add_print_types(a_basetype, 830 q = de_const(type_of(symtab_get_last_arg()))); 831 symtab_add_print_types(a_basetype, q); 832 } 833 834 funargs = funargs->d_next; 835 } 836 symtab_set_formals(decl_ToFormal(pp)); 837 symtab_set_actuals(to_actual()); 838 839 symtab_set_cast(decl_ToString(buf, DTS_CAST, pp, NULL)); 840 841 decl_Destroy(pp); 842 843 errlog(END, "}"); 844 return (SUCCESS_RC); 845 } 846 847 848 /* 849 * generators 850 */ 851 852 /* 853 * generate_init -- prime the code generator as required. 854 */ 855 static void 856 generate_init(void) 857 { 858 errlog(BEGIN, "generate_init() {"); 859 860 (void) fprintf(Headfp, 861 "/*\n" 862 " * Generated by spec2trace %s: do not edit this file.\n */\n\n", 863 TRACE_VERSION); 864 865 (void) fprintf(Headfp, 866 "#ifndef true\n" 867 "#define\ttrue 1\n" 868 "#define\tfalse 0\n" 869 "#endif\n\n" 870 "static char const *oparen = \"(\";\n" 871 "static char const *retstr = \" return = \";\n" 872 "static char const *errnostr = \" errno = \";\n" 873 "static char const *nilstr = \"<nil>\";\n" 874 "\n"); 875 876 errlog(END, "}"); 877 } 878 879 880 /* 881 * generate_interface -- call the two main parts of the per-interface 882 * code generation. 883 */ 884 static void 885 generate_interface(void) 886 { 887 ENTRY *function = symtab_get_function(); 888 889 errlog(BEGIN, "generate_interface() {"); 890 /* Check for required information. */ 891 if (validity_of(function) == NO) { 892 symtab_set_skip(YES); 893 errlog(WARNING|INPUT, "no prototype for interface " 894 "it will be skipped"); 895 errlog(END, "}"); 896 return; 897 } 898 899 /* Generate the current interface 's print-functions declarations. */ 900 generate_print_declarations(Bodyfp); 901 902 /* Generate the linkage part (a function and a struct */ 903 generate_linkage(function); 904 905 /* Generate the actual interceptor. */ 906 generate_interceptor(function); 907 errlog(END, "}"); 908 } 909 910 911 /* 912 * generate_closedown -- produce includes. 913 */ 914 static void 915 generate_closedown(void) 916 { 917 errlog(BEGIN, "generate_closedown() {"); 918 919 /* Print includes to primary file. */ 920 generate_includes(); 921 (void) putc('\n', Headfp); 922 errlog(END, "}"); 923 } 924 925 /* 926 * generate_aux_file -- generate one additional .pf file with 927 * print-function pointers. 928 */ 929 static int 930 generate_aux_file(void) 931 { 932 FILE *fp; 933 char pathname[MAXLINE]; 934 935 errlog(BEGIN, "generate_aux_file() {"); 936 /* Open file */ 937 (void) snprintf(pathname, sizeof (pathname), "%s.pf", 938 db_get_output_file()); 939 errlog(TRACING, "output file = '%s'", pathname); 940 if ((fp = fopen(pathname, "w")) == NULL) { 941 errlog(FATAL, "%s: %s", pathname, strerror(errno)); 942 } 943 944 /* 945 * Declare and initialize all print function pointers to null. 946 * Some spec files result in nothing being put into the .pf 947 * file. We must create the file since make(1) does not cope 948 * well with absent files that it expects to have built. So 949 * now the build gets empty compilation unit warnings... So 950 * we unconditionally create a static pointer. 951 */ 952 (void) fprintf(fp, 953 "/* Do not edit this file: it is a generated one. */\n\n" 954 "static char const *__abi_place_holder;\n\n"); 955 956 generate_print_definitions(fp); 957 958 /* Close file */ 959 if (fclose(fp) != 0) { 960 errlog(FATAL, "fclose %s: %s", pathname, strerror(errno)); 961 } 962 errlog(END, "}"); 963 return (YES); 964 } 965 966 967 968 /* 969 * generate_includes -- generate #includes to Headfp 970 */ 971 static void 972 generate_includes(void) 973 { 974 char *include; 975 976 errlog(BEGIN, "generate_includes() {"); 977 errlog(TRACING, "includes="); 978 for (include = symtab_get_first_include(); include != NULL; 979 include = symtab_get_next_include()) 980 (void) fprintf(Headfp, "#include %s\n", include); 981 982 (void) fprintf(Headfp, "\n#include <stdio.h>\n" 983 "#include <dlfcn.h>\n" 984 "#include <apptrace.h>\n\n"); 985 986 errlog(TRACING, "\n"); 987 errlog(END, "}"); 988 } 989