10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*5478Sjhaslam * Common Development and Distribution License (the "License"). 6*5478Sjhaslam * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*5478Sjhaslam * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 28*5478Sjhaslam #include <assert.h> 290Sstevel@tonic-gate #include <strings.h> 300Sstevel@tonic-gate #include <alloca.h> 310Sstevel@tonic-gate #include <stdlib.h> 320Sstevel@tonic-gate #include <stdio.h> 330Sstevel@tonic-gate 340Sstevel@tonic-gate #include <dt_parser.h> 350Sstevel@tonic-gate #include <dt_impl.h> 360Sstevel@tonic-gate #include <dt_provider.h> 370Sstevel@tonic-gate #include <dt_module.h> 380Sstevel@tonic-gate 390Sstevel@tonic-gate /* 400Sstevel@tonic-gate * This callback function is installed in a given identifier hash to search for 410Sstevel@tonic-gate * and apply deferred pragmas that are pending for a given new identifier name. 420Sstevel@tonic-gate * Multiple pragmas may be pending for a given name; we processs all of them. 430Sstevel@tonic-gate */ 440Sstevel@tonic-gate /*ARGSUSED*/ 450Sstevel@tonic-gate static void 460Sstevel@tonic-gate dt_pragma_apply(dt_idhash_t *dhp, dt_ident_t *idp) 470Sstevel@tonic-gate { 480Sstevel@tonic-gate dt_idhash_t *php; 490Sstevel@tonic-gate dt_ident_t *pdp; 500Sstevel@tonic-gate 510Sstevel@tonic-gate if ((php = yypcb->pcb_pragmas) == NULL) 520Sstevel@tonic-gate return; /* no pragmas pending for current compilation pass */ 530Sstevel@tonic-gate 540Sstevel@tonic-gate while ((pdp = dt_idhash_lookup(php, idp->di_name)) != NULL) { 550Sstevel@tonic-gate switch (pdp->di_kind) { 560Sstevel@tonic-gate case DT_IDENT_PRAGAT: 570Sstevel@tonic-gate idp->di_attr = pdp->di_attr; 580Sstevel@tonic-gate break; 590Sstevel@tonic-gate case DT_IDENT_PRAGBN: 600Sstevel@tonic-gate idp->di_vers = pdp->di_vers; 610Sstevel@tonic-gate break; 620Sstevel@tonic-gate } 630Sstevel@tonic-gate dt_idhash_delete(php, pdp); 640Sstevel@tonic-gate } 650Sstevel@tonic-gate } 660Sstevel@tonic-gate 670Sstevel@tonic-gate /* 680Sstevel@tonic-gate * The #pragma attributes directive can be used to reset stability attributes 690Sstevel@tonic-gate * on a global identifier or inline definition. If the identifier is already 700Sstevel@tonic-gate * defined, we can just change di_attr. If not, we insert the pragma into a 710Sstevel@tonic-gate * hash table of the current pcb's deferred pragmas for later processing. 720Sstevel@tonic-gate */ 730Sstevel@tonic-gate static void 740Sstevel@tonic-gate dt_pragma_attributes(const char *prname, dt_node_t *dnp) 750Sstevel@tonic-gate { 760Sstevel@tonic-gate dtrace_hdl_t *dtp = yypcb->pcb_hdl; 770Sstevel@tonic-gate dtrace_attribute_t attr, *a; 780Sstevel@tonic-gate dt_provider_t *pvp; 790Sstevel@tonic-gate const char *name, *part; 800Sstevel@tonic-gate dt_ident_t *idp; 810Sstevel@tonic-gate 820Sstevel@tonic-gate if (dnp == NULL || dnp->dn_kind != DT_NODE_IDENT || 830Sstevel@tonic-gate dnp->dn_list == NULL || dnp->dn_list->dn_kind != DT_NODE_IDENT) { 840Sstevel@tonic-gate xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s " 850Sstevel@tonic-gate "<attributes> <ident>\n", prname); 860Sstevel@tonic-gate } 870Sstevel@tonic-gate 880Sstevel@tonic-gate if (dtrace_str2attr(dnp->dn_string, &attr) == -1) { 890Sstevel@tonic-gate xyerror(D_PRAGMA_INVAL, "invalid attributes " 900Sstevel@tonic-gate "specified by #pragma %s\n", prname); 910Sstevel@tonic-gate } 920Sstevel@tonic-gate 930Sstevel@tonic-gate dnp = dnp->dn_list; 940Sstevel@tonic-gate name = dnp->dn_string; 950Sstevel@tonic-gate 960Sstevel@tonic-gate if (strcmp(name, "provider") == 0) { 970Sstevel@tonic-gate dnp = dnp->dn_list; 980Sstevel@tonic-gate name = dnp->dn_string; 990Sstevel@tonic-gate 1000Sstevel@tonic-gate dnp = dnp->dn_list; 1010Sstevel@tonic-gate part = dnp->dn_string; 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate if ((pvp = dt_provider_lookup(dtp, name)) != NULL) { 1040Sstevel@tonic-gate if (strcmp(part, "provider") == 0) { 1050Sstevel@tonic-gate a = &pvp->pv_desc.dtvd_attr.dtpa_provider; 1060Sstevel@tonic-gate } else if (strcmp(part, "module") == 0) { 1070Sstevel@tonic-gate a = &pvp->pv_desc.dtvd_attr.dtpa_mod; 1080Sstevel@tonic-gate } else if (strcmp(part, "function") == 0) { 1090Sstevel@tonic-gate a = &pvp->pv_desc.dtvd_attr.dtpa_func; 1100Sstevel@tonic-gate } else if (strcmp(part, "name") == 0) { 1110Sstevel@tonic-gate a = &pvp->pv_desc.dtvd_attr.dtpa_name; 1120Sstevel@tonic-gate } else if (strcmp(part, "args") == 0) { 1130Sstevel@tonic-gate a = &pvp->pv_desc.dtvd_attr.dtpa_args; 1140Sstevel@tonic-gate } else { 1150Sstevel@tonic-gate xyerror(D_PRAGMA_INVAL, "invalid component " 1160Sstevel@tonic-gate "\"%s\" in attribute #pragma " 1170Sstevel@tonic-gate "for provider %s\n", name, part); 1180Sstevel@tonic-gate } 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate *a = attr; 1210Sstevel@tonic-gate return; 1220Sstevel@tonic-gate } 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate } else if ((idp = dt_idstack_lookup( 1250Sstevel@tonic-gate &yypcb->pcb_globals, name)) != NULL) { 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate if (idp->di_gen != dtp->dt_gen) { 1280Sstevel@tonic-gate xyerror(D_PRAGMA_SCOPE, "#pragma %s cannot modify " 1290Sstevel@tonic-gate "entity defined outside program scope\n", prname); 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate idp->di_attr = attr; 1330Sstevel@tonic-gate return; 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate if (yypcb->pcb_pragmas == NULL && (yypcb->pcb_pragmas = 1370Sstevel@tonic-gate dt_idhash_create("pragma", NULL, 0, 0)) == NULL) 1380Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate idp = dt_idhash_insert(yypcb->pcb_pragmas, name, DT_IDENT_PRAGAT, 0, 0, 1410Sstevel@tonic-gate attr, 0, &dt_idops_thaw, (void *)prname, dtp->dt_gen); 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate if (idp == NULL) 1440Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate if (dtp->dt_globals->dh_defer == NULL) 1470Sstevel@tonic-gate dtp->dt_globals->dh_defer = &dt_pragma_apply; 1480Sstevel@tonic-gate } 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate /* 1510Sstevel@tonic-gate * The #pragma binding directive can be used to reset the version binding 1520Sstevel@tonic-gate * on a global identifier or inline definition. If the identifier is already 1530Sstevel@tonic-gate * defined, we can just change di_vers. If not, we insert the pragma into a 1540Sstevel@tonic-gate * hash table of the current pcb's deferred pragmas for later processing. 1550Sstevel@tonic-gate */ 1560Sstevel@tonic-gate static void 1570Sstevel@tonic-gate dt_pragma_binding(const char *prname, dt_node_t *dnp) 1580Sstevel@tonic-gate { 1590Sstevel@tonic-gate dtrace_hdl_t *dtp = yypcb->pcb_hdl; 1600Sstevel@tonic-gate dt_version_t vers; 1610Sstevel@tonic-gate const char *name; 1620Sstevel@tonic-gate dt_ident_t *idp; 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate if (dnp == NULL || dnp->dn_kind != DT_NODE_STRING || 1650Sstevel@tonic-gate dnp->dn_list == NULL || dnp->dn_list->dn_kind != DT_NODE_IDENT) { 1660Sstevel@tonic-gate xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s " 1670Sstevel@tonic-gate "\"version\" <ident>\n", prname); 1680Sstevel@tonic-gate } 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate if (dt_version_str2num(dnp->dn_string, &vers) == -1) { 1710Sstevel@tonic-gate xyerror(D_PRAGMA_INVAL, "invalid version string " 1720Sstevel@tonic-gate "specified by #pragma %s\n", prname); 1730Sstevel@tonic-gate } 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate name = dnp->dn_list->dn_string; 1760Sstevel@tonic-gate idp = dt_idstack_lookup(&yypcb->pcb_globals, name); 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate if (idp != NULL) { 1790Sstevel@tonic-gate if (idp->di_gen != dtp->dt_gen) { 1800Sstevel@tonic-gate xyerror(D_PRAGMA_SCOPE, "#pragma %s cannot modify " 1810Sstevel@tonic-gate "entity defined outside program scope\n", prname); 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate idp->di_vers = vers; 1840Sstevel@tonic-gate return; 1850Sstevel@tonic-gate } 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate if (yypcb->pcb_pragmas == NULL && (yypcb->pcb_pragmas = 1880Sstevel@tonic-gate dt_idhash_create("pragma", NULL, 0, 0)) == NULL) 1890Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate idp = dt_idhash_insert(yypcb->pcb_pragmas, name, DT_IDENT_PRAGBN, 0, 0, 1920Sstevel@tonic-gate _dtrace_defattr, vers, &dt_idops_thaw, (void *)prname, dtp->dt_gen); 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate if (idp == NULL) 1950Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate if (dtp->dt_globals->dh_defer == NULL) 1980Sstevel@tonic-gate dtp->dt_globals->dh_defer = &dt_pragma_apply; 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate /* 2020Sstevel@tonic-gate * The #pragma depends_on directive can be used to express a dependency on a 203*5478Sjhaslam * module, provider or library which if not present will cause processing to 204*5478Sjhaslam * abort. 2050Sstevel@tonic-gate */ 2060Sstevel@tonic-gate static void 2070Sstevel@tonic-gate dt_pragma_depends(const char *prname, dt_node_t *cnp) 2080Sstevel@tonic-gate { 2090Sstevel@tonic-gate dtrace_hdl_t *dtp = yypcb->pcb_hdl; 2100Sstevel@tonic-gate dt_node_t *nnp = cnp ? cnp->dn_list : NULL; 2110Sstevel@tonic-gate int found; 212*5478Sjhaslam dt_lib_depend_t *dld; 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate if (cnp == NULL || nnp == NULL || 2150Sstevel@tonic-gate cnp->dn_kind != DT_NODE_IDENT || nnp->dn_kind != DT_NODE_IDENT) { 2160Sstevel@tonic-gate xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s " 2170Sstevel@tonic-gate "<class> <name>\n", prname); 2180Sstevel@tonic-gate } 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate if (strcmp(cnp->dn_string, "provider") == 0) 2210Sstevel@tonic-gate found = dt_provider_lookup(dtp, nnp->dn_string) != NULL; 2220Sstevel@tonic-gate else if (strcmp(cnp->dn_string, "module") == 0) { 2230Sstevel@tonic-gate dt_module_t *mp = dt_module_lookup_by_name(dtp, nnp->dn_string); 2240Sstevel@tonic-gate found = mp != NULL && dt_module_getctf(dtp, mp) != NULL; 225*5478Sjhaslam } else if (strcmp(cnp->dn_string, "library") == 0) { 226*5478Sjhaslam 227*5478Sjhaslam /* 228*5478Sjhaslam * We have the file we are working on in dtp->dt_filetag 229*5478Sjhaslam * so find that node and add the dependency in. 230*5478Sjhaslam */ 231*5478Sjhaslam if (yypcb->pcb_cflags & DTRACE_C_CTL) { 232*5478Sjhaslam char lib[MAXPATHLEN]; 233*5478Sjhaslam 234*5478Sjhaslam dld = dt_lib_depend_lookup(&dtp->dt_lib_dep, 235*5478Sjhaslam dtp->dt_filetag); 236*5478Sjhaslam assert(dld != NULL); 237*5478Sjhaslam 238*5478Sjhaslam (void) snprintf(lib, MAXPATHLEN, "%s%s", 239*5478Sjhaslam dld->dtld_libpath, nnp->dn_string); 240*5478Sjhaslam if ((dt_lib_depend_add(dtp, &dld->dtld_dependencies, 241*5478Sjhaslam lib)) != 0) { 242*5478Sjhaslam xyerror(D_PRAGMA_DEPEND, 243*5478Sjhaslam "failed to add dependency %s:%s\n", 244*5478Sjhaslam lib, 245*5478Sjhaslam dtrace_errmsg(dtp, dtrace_errno(dtp))); 246*5478Sjhaslam } 247*5478Sjhaslam } 248*5478Sjhaslam found = 1; 2490Sstevel@tonic-gate } else { 2500Sstevel@tonic-gate xyerror(D_PRAGMA_INVAL, "invalid class %s " 2510Sstevel@tonic-gate "specified by #pragma %s\n", cnp->dn_string, prname); 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate if (!found) { 2550Sstevel@tonic-gate xyerror(D_PRAGMA_DEPEND, "program requires %s %s\n", 2560Sstevel@tonic-gate cnp->dn_string, nnp->dn_string); 2570Sstevel@tonic-gate } 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate /* 2610Sstevel@tonic-gate * The #pragma error directive can be followed by any list of tokens, which we 2620Sstevel@tonic-gate * just concatenate and print as part of our error message. 2630Sstevel@tonic-gate */ 2640Sstevel@tonic-gate static void 2650Sstevel@tonic-gate dt_pragma_error(const char *prname, dt_node_t *dnp) 2660Sstevel@tonic-gate { 2670Sstevel@tonic-gate dt_node_t *enp; 2680Sstevel@tonic-gate size_t n = 0; 2690Sstevel@tonic-gate char *s; 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate for (enp = dnp; enp != NULL; enp = enp->dn_list) { 2720Sstevel@tonic-gate if (enp->dn_kind == DT_NODE_IDENT || 2730Sstevel@tonic-gate enp->dn_kind == DT_NODE_STRING) 2740Sstevel@tonic-gate n += strlen(enp->dn_string) + 1; 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate s = alloca(n + 1); 2780Sstevel@tonic-gate s[0] = '\0'; 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate for (enp = dnp; enp != NULL; enp = enp->dn_list) { 2810Sstevel@tonic-gate if (enp->dn_kind == DT_NODE_IDENT || 2820Sstevel@tonic-gate enp->dn_kind == DT_NODE_STRING) { 2830Sstevel@tonic-gate (void) strcat(s, enp->dn_string); 2840Sstevel@tonic-gate (void) strcat(s, " "); 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate xyerror(D_PRAGERR, "#%s: %s\n", prname, s); 2890Sstevel@tonic-gate } 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate /*ARGSUSED*/ 2920Sstevel@tonic-gate static void 2930Sstevel@tonic-gate dt_pragma_ident(const char *prname, dt_node_t *dnp) 2940Sstevel@tonic-gate { 2950Sstevel@tonic-gate /* ignore any #ident or #pragma ident lines */ 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate static void 2990Sstevel@tonic-gate dt_pragma_option(const char *prname, dt_node_t *dnp) 3000Sstevel@tonic-gate { 3010Sstevel@tonic-gate dtrace_hdl_t *dtp = yypcb->pcb_hdl; 3020Sstevel@tonic-gate char *opt, *val; 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate if (dnp == NULL || dnp->dn_kind != DT_NODE_IDENT) { 3050Sstevel@tonic-gate xyerror(D_PRAGMA_MALFORM, 3060Sstevel@tonic-gate "malformed #pragma %s <option>=<val>\n", prname); 3070Sstevel@tonic-gate } 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate if (dnp->dn_list != NULL) { 3100Sstevel@tonic-gate xyerror(D_PRAGMA_MALFORM, 3110Sstevel@tonic-gate "superfluous arguments specified for #pragma %s\n", prname); 3120Sstevel@tonic-gate } 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate opt = alloca(strlen(dnp->dn_string) + 1); 3150Sstevel@tonic-gate (void) strcpy(opt, dnp->dn_string); 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate if ((val = strchr(opt, '=')) != NULL) 3180Sstevel@tonic-gate *val++ = '\0'; 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate if (dtrace_setopt(dtp, opt, val) == -1) { 3210Sstevel@tonic-gate if (val == NULL) { 3220Sstevel@tonic-gate xyerror(D_PRAGMA_OPTSET, 3230Sstevel@tonic-gate "failed to set option '%s': %s\n", opt, 3240Sstevel@tonic-gate dtrace_errmsg(dtp, dtrace_errno(dtp))); 3250Sstevel@tonic-gate } else { 3260Sstevel@tonic-gate xyerror(D_PRAGMA_OPTSET, 3270Sstevel@tonic-gate "failed to set option '%s' to '%s': %s\n", 3280Sstevel@tonic-gate opt, val, dtrace_errmsg(dtp, dtrace_errno(dtp))); 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate /* 3340Sstevel@tonic-gate * The #line directive is used to reset the input line number and to optionally 3350Sstevel@tonic-gate * note the file name for use in error messages. Sun cpp(1) also produces a 3360Sstevel@tonic-gate * third integer token after the filename which is one of the following: 3370Sstevel@tonic-gate * 3380Sstevel@tonic-gate * 0 - line change has nothing to do with an #include file 3390Sstevel@tonic-gate * 1 - line change because we just entered a #include file 3400Sstevel@tonic-gate * 2 - line change because we just exited a #include file 3410Sstevel@tonic-gate * 3420Sstevel@tonic-gate * We use these state tokens to adjust pcb_idepth, which in turn controls 3430Sstevel@tonic-gate * whether type lookups access the global type space or not. 3440Sstevel@tonic-gate */ 3450Sstevel@tonic-gate static void 3460Sstevel@tonic-gate dt_pragma_line(const char *prname, dt_node_t *dnp) 3470Sstevel@tonic-gate { 3480Sstevel@tonic-gate dt_node_t *fnp = dnp ? dnp->dn_list : NULL; 3490Sstevel@tonic-gate dt_node_t *inp = fnp ? fnp->dn_list : NULL; 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate if ((dnp == NULL || dnp->dn_kind != DT_NODE_INT) || 3520Sstevel@tonic-gate (fnp != NULL && fnp->dn_kind != DT_NODE_STRING) || 3530Sstevel@tonic-gate (inp != NULL && inp->dn_kind != DT_NODE_INT)) { 3540Sstevel@tonic-gate xyerror(D_PRAGMA_MALFORM, "malformed #%s " 3550Sstevel@tonic-gate "<line> [ [\"file\"] state ]\n", prname); 3560Sstevel@tonic-gate } 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate /* 3590Sstevel@tonic-gate * If a file is specified, free any old pcb_filetag and swap fnp's 3600Sstevel@tonic-gate * dn_string into pcb_filetag as the new filename for error messages. 3610Sstevel@tonic-gate */ 3620Sstevel@tonic-gate if (fnp != NULL) { 3630Sstevel@tonic-gate if (yypcb->pcb_filetag != NULL) 3640Sstevel@tonic-gate free(yypcb->pcb_filetag); 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate /* 3670Sstevel@tonic-gate * This is not pretty, but is a necessary evil until we either 3680Sstevel@tonic-gate * write "dpp" or get a useful standalone cpp from DevPro. If 3690Sstevel@tonic-gate * the filename begins with /dev/fd, we know it's the master 3700Sstevel@tonic-gate * input file (see dt_preproc() in dt_cc.c), so just clear the 3710Sstevel@tonic-gate * dt_filetag pointer so error messages refer to the main file. 3720Sstevel@tonic-gate */ 3730Sstevel@tonic-gate if (strncmp(fnp->dn_string, "/dev/fd/", 8) != 0) { 3740Sstevel@tonic-gate yypcb->pcb_filetag = fnp->dn_string; 3750Sstevel@tonic-gate fnp->dn_string = NULL; 3760Sstevel@tonic-gate } else 3770Sstevel@tonic-gate yypcb->pcb_filetag = NULL; 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate if (inp != NULL) { 3810Sstevel@tonic-gate if (inp->dn_value == 1) 3820Sstevel@tonic-gate yypcb->pcb_idepth++; 3830Sstevel@tonic-gate else if (inp->dn_value == 2 && yypcb->pcb_idepth != 0) 3840Sstevel@tonic-gate yypcb->pcb_idepth--; 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate yylineno = dnp->dn_value; 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate /* 3910Sstevel@tonic-gate * D compiler pragma types range from control directives to common pragmas to 3920Sstevel@tonic-gate * D custom pragmas, in order of specificity. Similar to gcc, we use #pragma D 3930Sstevel@tonic-gate * as a special prefix for our pragmas so they can be used in mixed headers. 3940Sstevel@tonic-gate */ 3950Sstevel@tonic-gate #define DT_PRAGMA_DIR 0 /* pragma directive may be used after naked # */ 3960Sstevel@tonic-gate #define DT_PRAGMA_SUB 1 /* pragma directive may be used after #pragma */ 3970Sstevel@tonic-gate #define DT_PRAGMA_DCP 2 /* pragma may only be used after #pragma D */ 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate static const struct dt_pragmadesc { 4000Sstevel@tonic-gate const char *dpd_name; 4010Sstevel@tonic-gate void (*dpd_func)(const char *, dt_node_t *); 4020Sstevel@tonic-gate int dpd_kind; 4030Sstevel@tonic-gate } dt_pragmas[] = { 4040Sstevel@tonic-gate { "attributes", dt_pragma_attributes, DT_PRAGMA_DCP }, 4050Sstevel@tonic-gate { "binding", dt_pragma_binding, DT_PRAGMA_DCP }, 4060Sstevel@tonic-gate { "depends_on", dt_pragma_depends, DT_PRAGMA_DCP }, 4070Sstevel@tonic-gate { "error", dt_pragma_error, DT_PRAGMA_DIR }, 4080Sstevel@tonic-gate { "ident", dt_pragma_ident, DT_PRAGMA_DIR }, 4090Sstevel@tonic-gate { "line", dt_pragma_line, DT_PRAGMA_DIR }, 4100Sstevel@tonic-gate { "option", dt_pragma_option, DT_PRAGMA_DCP }, 4110Sstevel@tonic-gate { NULL, NULL } 4120Sstevel@tonic-gate }; 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate /* 4150Sstevel@tonic-gate * Process a control line #directive by looking up the directive name in our 4160Sstevel@tonic-gate * lookup table and invoking the corresponding function with the token list. 4170Sstevel@tonic-gate * According to K&R[A12.9], we silently ignore null directive lines. 4180Sstevel@tonic-gate */ 4190Sstevel@tonic-gate void 4200Sstevel@tonic-gate dt_pragma(dt_node_t *pnp) 4210Sstevel@tonic-gate { 4220Sstevel@tonic-gate const struct dt_pragmadesc *dpd; 4230Sstevel@tonic-gate dt_node_t *dnp; 4240Sstevel@tonic-gate int kind = DT_PRAGMA_DIR; 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate for (dnp = pnp; dnp != NULL; dnp = dnp->dn_list) { 4270Sstevel@tonic-gate if (dnp->dn_kind == DT_NODE_INT) { 4280Sstevel@tonic-gate dt_pragma_line("line", dnp); 4290Sstevel@tonic-gate break; 4300Sstevel@tonic-gate } 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate if (dnp->dn_kind != DT_NODE_IDENT) 4330Sstevel@tonic-gate xyerror(D_PRAGCTL_INVAL, "invalid control directive\n"); 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate if (kind == DT_PRAGMA_DIR && 4360Sstevel@tonic-gate strcmp(dnp->dn_string, "pragma") == 0) { 4370Sstevel@tonic-gate kind = DT_PRAGMA_SUB; 4380Sstevel@tonic-gate continue; 4390Sstevel@tonic-gate } 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate if (kind == DT_PRAGMA_SUB && 4420Sstevel@tonic-gate strcmp(dnp->dn_string, "D") == 0) { 4430Sstevel@tonic-gate kind = DT_PRAGMA_DCP; 4440Sstevel@tonic-gate continue; 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate for (dpd = dt_pragmas; dpd->dpd_name != NULL; dpd++) { 4480Sstevel@tonic-gate if (dpd->dpd_kind <= kind && 4490Sstevel@tonic-gate strcmp(dpd->dpd_name, dnp->dn_string) == 0) 4500Sstevel@tonic-gate break; 4510Sstevel@tonic-gate } 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate yylineno--; /* since we've already seen \n */ 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate if (dpd->dpd_name != NULL) { 4560Sstevel@tonic-gate dpd->dpd_func(dpd->dpd_name, dnp->dn_list); 4570Sstevel@tonic-gate yylineno++; 4580Sstevel@tonic-gate break; 4590Sstevel@tonic-gate } 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate switch (kind) { 4620Sstevel@tonic-gate case DT_PRAGMA_DIR: 4630Sstevel@tonic-gate xyerror(D_PRAGCTL_INVAL, "invalid control directive: " 4640Sstevel@tonic-gate "#%s\n", dnp->dn_string); 4650Sstevel@tonic-gate /*NOTREACHED*/ 4660Sstevel@tonic-gate case DT_PRAGMA_SUB: 4670Sstevel@tonic-gate break; /* K&R[A12.8] says to ignore unknown pragmas */ 4680Sstevel@tonic-gate case DT_PRAGMA_DCP: 4690Sstevel@tonic-gate default: 4700Sstevel@tonic-gate xyerror(D_PRAGMA_INVAL, "invalid D pragma: %s\n", 4710Sstevel@tonic-gate dnp->dn_string); 4720Sstevel@tonic-gate } 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate yylineno++; 4750Sstevel@tonic-gate break; 4760Sstevel@tonic-gate } 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate dt_node_list_free(&pnp); 4790Sstevel@tonic-gate } 480