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