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 *
xlator_init(const Translator_info * t_info)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
xlator_startlib(char const * libname)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
xlator_startfile(char const * filename)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
xlator_start_if(const Meta_info m,int const token,char * value)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
xlator_take_kvpair(Meta_info m,int const token,char * value)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
xlator_end_if(const Meta_info m,char const * value)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
xlator_endfile(void)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
xlator_endlib(void)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
xlator_end(void)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
stats_init(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
stats_report(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
stats_add_warning(void)461 stats_add_warning(void)
462 {
463 Statistics.warnings++;
464 }
465
466 void
stats_add_error(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
collect_include(char * p,int line)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
collect_binding(int const token,char * value,int line)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
collect_errval(char * p,int line)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
collect_arch(char * value)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 *
de_const(char * type)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
to_basetype(char * str)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 *
to_actual(void)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 *
strpqcpy(char * target,char * p,char * q)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
breakpoint(void)707 breakpoint(void)
708 {
709 return (0);
710 }
711 #endif
712
713
714 int
collect_prototype(char * p,int line,int extcnt)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
generate_init(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
generate_interface(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
generate_closedown(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
generate_aux_file(void)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
generate_includes(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