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