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