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