1*6ff6d951SJohn Birrell /* 2*6ff6d951SJohn Birrell * CDDL HEADER START 3*6ff6d951SJohn Birrell * 4*6ff6d951SJohn Birrell * The contents of this file are subject to the terms of the 5*6ff6d951SJohn Birrell * Common Development and Distribution License (the "License"). 6*6ff6d951SJohn Birrell * You may not use this file except in compliance with the License. 7*6ff6d951SJohn Birrell * 8*6ff6d951SJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*6ff6d951SJohn Birrell * or http://www.opensolaris.org/os/licensing. 10*6ff6d951SJohn Birrell * See the License for the specific language governing permissions 11*6ff6d951SJohn Birrell * and limitations under the License. 12*6ff6d951SJohn Birrell * 13*6ff6d951SJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each 14*6ff6d951SJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*6ff6d951SJohn Birrell * If applicable, add the following below this CDDL HEADER, with the 16*6ff6d951SJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying 17*6ff6d951SJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner] 18*6ff6d951SJohn Birrell * 19*6ff6d951SJohn Birrell * CDDL HEADER END 20*6ff6d951SJohn Birrell */ 21*6ff6d951SJohn Birrell 22*6ff6d951SJohn Birrell /* 23*6ff6d951SJohn Birrell * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*6ff6d951SJohn Birrell * Use is subject to license terms. 25*6ff6d951SJohn Birrell */ 26*6ff6d951SJohn Birrell 27*6ff6d951SJohn Birrell #pragma ident "%Z%%M% %I% %E% SMI" 28*6ff6d951SJohn Birrell 29*6ff6d951SJohn Birrell #include <assert.h> 30*6ff6d951SJohn Birrell #include <strings.h> 31*6ff6d951SJohn Birrell #if defined(sun) 32*6ff6d951SJohn Birrell #include <alloca.h> 33*6ff6d951SJohn Birrell #endif 34*6ff6d951SJohn Birrell #include <stdlib.h> 35*6ff6d951SJohn Birrell #include <stdio.h> 36*6ff6d951SJohn Birrell 37*6ff6d951SJohn Birrell #include <dt_parser.h> 38*6ff6d951SJohn Birrell #include <dt_impl.h> 39*6ff6d951SJohn Birrell #include <dt_provider.h> 40*6ff6d951SJohn Birrell #include <dt_module.h> 41*6ff6d951SJohn Birrell 42*6ff6d951SJohn Birrell /* 43*6ff6d951SJohn Birrell * This callback function is installed in a given identifier hash to search for 44*6ff6d951SJohn Birrell * and apply deferred pragmas that are pending for a given new identifier name. 45*6ff6d951SJohn Birrell * Multiple pragmas may be pending for a given name; we processs all of them. 46*6ff6d951SJohn Birrell */ 47*6ff6d951SJohn Birrell /*ARGSUSED*/ 48*6ff6d951SJohn Birrell static void 49*6ff6d951SJohn Birrell dt_pragma_apply(dt_idhash_t *dhp, dt_ident_t *idp) 50*6ff6d951SJohn Birrell { 51*6ff6d951SJohn Birrell dt_idhash_t *php; 52*6ff6d951SJohn Birrell dt_ident_t *pdp; 53*6ff6d951SJohn Birrell 54*6ff6d951SJohn Birrell if ((php = yypcb->pcb_pragmas) == NULL) 55*6ff6d951SJohn Birrell return; /* no pragmas pending for current compilation pass */ 56*6ff6d951SJohn Birrell 57*6ff6d951SJohn Birrell while ((pdp = dt_idhash_lookup(php, idp->di_name)) != NULL) { 58*6ff6d951SJohn Birrell switch (pdp->di_kind) { 59*6ff6d951SJohn Birrell case DT_IDENT_PRAGAT: 60*6ff6d951SJohn Birrell idp->di_attr = pdp->di_attr; 61*6ff6d951SJohn Birrell break; 62*6ff6d951SJohn Birrell case DT_IDENT_PRAGBN: 63*6ff6d951SJohn Birrell idp->di_vers = pdp->di_vers; 64*6ff6d951SJohn Birrell break; 65*6ff6d951SJohn Birrell } 66*6ff6d951SJohn Birrell dt_idhash_delete(php, pdp); 67*6ff6d951SJohn Birrell } 68*6ff6d951SJohn Birrell } 69*6ff6d951SJohn Birrell 70*6ff6d951SJohn Birrell /* 71*6ff6d951SJohn Birrell * The #pragma attributes directive can be used to reset stability attributes 72*6ff6d951SJohn Birrell * on a global identifier or inline definition. If the identifier is already 73*6ff6d951SJohn Birrell * defined, we can just change di_attr. If not, we insert the pragma into a 74*6ff6d951SJohn Birrell * hash table of the current pcb's deferred pragmas for later processing. 75*6ff6d951SJohn Birrell */ 76*6ff6d951SJohn Birrell static void 77*6ff6d951SJohn Birrell dt_pragma_attributes(const char *prname, dt_node_t *dnp) 78*6ff6d951SJohn Birrell { 79*6ff6d951SJohn Birrell dtrace_hdl_t *dtp = yypcb->pcb_hdl; 80*6ff6d951SJohn Birrell dtrace_attribute_t attr, *a; 81*6ff6d951SJohn Birrell dt_provider_t *pvp; 82*6ff6d951SJohn Birrell const char *name, *part; 83*6ff6d951SJohn Birrell dt_ident_t *idp; 84*6ff6d951SJohn Birrell 85*6ff6d951SJohn Birrell if (dnp == NULL || dnp->dn_kind != DT_NODE_IDENT || 86*6ff6d951SJohn Birrell dnp->dn_list == NULL || dnp->dn_list->dn_kind != DT_NODE_IDENT) { 87*6ff6d951SJohn Birrell xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s " 88*6ff6d951SJohn Birrell "<attributes> <ident>\n", prname); 89*6ff6d951SJohn Birrell } 90*6ff6d951SJohn Birrell 91*6ff6d951SJohn Birrell if (dtrace_str2attr(dnp->dn_string, &attr) == -1) { 92*6ff6d951SJohn Birrell xyerror(D_PRAGMA_INVAL, "invalid attributes " 93*6ff6d951SJohn Birrell "specified by #pragma %s\n", prname); 94*6ff6d951SJohn Birrell } 95*6ff6d951SJohn Birrell 96*6ff6d951SJohn Birrell dnp = dnp->dn_list; 97*6ff6d951SJohn Birrell name = dnp->dn_string; 98*6ff6d951SJohn Birrell 99*6ff6d951SJohn Birrell if (strcmp(name, "provider") == 0) { 100*6ff6d951SJohn Birrell dnp = dnp->dn_list; 101*6ff6d951SJohn Birrell name = dnp->dn_string; 102*6ff6d951SJohn Birrell 103*6ff6d951SJohn Birrell dnp = dnp->dn_list; 104*6ff6d951SJohn Birrell part = dnp->dn_string; 105*6ff6d951SJohn Birrell 106*6ff6d951SJohn Birrell if ((pvp = dt_provider_lookup(dtp, name)) != NULL) { 107*6ff6d951SJohn Birrell if (strcmp(part, "provider") == 0) { 108*6ff6d951SJohn Birrell a = &pvp->pv_desc.dtvd_attr.dtpa_provider; 109*6ff6d951SJohn Birrell } else if (strcmp(part, "module") == 0) { 110*6ff6d951SJohn Birrell a = &pvp->pv_desc.dtvd_attr.dtpa_mod; 111*6ff6d951SJohn Birrell } else if (strcmp(part, "function") == 0) { 112*6ff6d951SJohn Birrell a = &pvp->pv_desc.dtvd_attr.dtpa_func; 113*6ff6d951SJohn Birrell } else if (strcmp(part, "name") == 0) { 114*6ff6d951SJohn Birrell a = &pvp->pv_desc.dtvd_attr.dtpa_name; 115*6ff6d951SJohn Birrell } else if (strcmp(part, "args") == 0) { 116*6ff6d951SJohn Birrell a = &pvp->pv_desc.dtvd_attr.dtpa_args; 117*6ff6d951SJohn Birrell } else { 118*6ff6d951SJohn Birrell xyerror(D_PRAGMA_INVAL, "invalid component " 119*6ff6d951SJohn Birrell "\"%s\" in attribute #pragma " 120*6ff6d951SJohn Birrell "for provider %s\n", name, part); 121*6ff6d951SJohn Birrell } 122*6ff6d951SJohn Birrell 123*6ff6d951SJohn Birrell *a = attr; 124*6ff6d951SJohn Birrell return; 125*6ff6d951SJohn Birrell } 126*6ff6d951SJohn Birrell 127*6ff6d951SJohn Birrell } else if ((idp = dt_idstack_lookup( 128*6ff6d951SJohn Birrell &yypcb->pcb_globals, name)) != NULL) { 129*6ff6d951SJohn Birrell 130*6ff6d951SJohn Birrell if (idp->di_gen != dtp->dt_gen) { 131*6ff6d951SJohn Birrell xyerror(D_PRAGMA_SCOPE, "#pragma %s cannot modify " 132*6ff6d951SJohn Birrell "entity defined outside program scope\n", prname); 133*6ff6d951SJohn Birrell } 134*6ff6d951SJohn Birrell 135*6ff6d951SJohn Birrell idp->di_attr = attr; 136*6ff6d951SJohn Birrell return; 137*6ff6d951SJohn Birrell } 138*6ff6d951SJohn Birrell 139*6ff6d951SJohn Birrell if (yypcb->pcb_pragmas == NULL && (yypcb->pcb_pragmas = 140*6ff6d951SJohn Birrell dt_idhash_create("pragma", NULL, 0, 0)) == NULL) 141*6ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 142*6ff6d951SJohn Birrell 143*6ff6d951SJohn Birrell idp = dt_idhash_insert(yypcb->pcb_pragmas, name, DT_IDENT_PRAGAT, 0, 0, 144*6ff6d951SJohn Birrell attr, 0, &dt_idops_thaw, (void *)prname, dtp->dt_gen); 145*6ff6d951SJohn Birrell 146*6ff6d951SJohn Birrell if (idp == NULL) 147*6ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 148*6ff6d951SJohn Birrell 149*6ff6d951SJohn Birrell if (dtp->dt_globals->dh_defer == NULL) 150*6ff6d951SJohn Birrell dtp->dt_globals->dh_defer = &dt_pragma_apply; 151*6ff6d951SJohn Birrell } 152*6ff6d951SJohn Birrell 153*6ff6d951SJohn Birrell /* 154*6ff6d951SJohn Birrell * The #pragma binding directive can be used to reset the version binding 155*6ff6d951SJohn Birrell * on a global identifier or inline definition. If the identifier is already 156*6ff6d951SJohn Birrell * defined, we can just change di_vers. If not, we insert the pragma into a 157*6ff6d951SJohn Birrell * hash table of the current pcb's deferred pragmas for later processing. 158*6ff6d951SJohn Birrell */ 159*6ff6d951SJohn Birrell static void 160*6ff6d951SJohn Birrell dt_pragma_binding(const char *prname, dt_node_t *dnp) 161*6ff6d951SJohn Birrell { 162*6ff6d951SJohn Birrell dtrace_hdl_t *dtp = yypcb->pcb_hdl; 163*6ff6d951SJohn Birrell dt_version_t vers; 164*6ff6d951SJohn Birrell const char *name; 165*6ff6d951SJohn Birrell dt_ident_t *idp; 166*6ff6d951SJohn Birrell 167*6ff6d951SJohn Birrell if (dnp == NULL || dnp->dn_kind != DT_NODE_STRING || 168*6ff6d951SJohn Birrell dnp->dn_list == NULL || dnp->dn_list->dn_kind != DT_NODE_IDENT) { 169*6ff6d951SJohn Birrell xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s " 170*6ff6d951SJohn Birrell "\"version\" <ident>\n", prname); 171*6ff6d951SJohn Birrell } 172*6ff6d951SJohn Birrell 173*6ff6d951SJohn Birrell if (dt_version_str2num(dnp->dn_string, &vers) == -1) { 174*6ff6d951SJohn Birrell xyerror(D_PRAGMA_INVAL, "invalid version string " 175*6ff6d951SJohn Birrell "specified by #pragma %s\n", prname); 176*6ff6d951SJohn Birrell } 177*6ff6d951SJohn Birrell 178*6ff6d951SJohn Birrell name = dnp->dn_list->dn_string; 179*6ff6d951SJohn Birrell idp = dt_idstack_lookup(&yypcb->pcb_globals, name); 180*6ff6d951SJohn Birrell 181*6ff6d951SJohn Birrell if (idp != NULL) { 182*6ff6d951SJohn Birrell if (idp->di_gen != dtp->dt_gen) { 183*6ff6d951SJohn Birrell xyerror(D_PRAGMA_SCOPE, "#pragma %s cannot modify " 184*6ff6d951SJohn Birrell "entity defined outside program scope\n", prname); 185*6ff6d951SJohn Birrell } 186*6ff6d951SJohn Birrell idp->di_vers = vers; 187*6ff6d951SJohn Birrell return; 188*6ff6d951SJohn Birrell } 189*6ff6d951SJohn Birrell 190*6ff6d951SJohn Birrell if (yypcb->pcb_pragmas == NULL && (yypcb->pcb_pragmas = 191*6ff6d951SJohn Birrell dt_idhash_create("pragma", NULL, 0, 0)) == NULL) 192*6ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 193*6ff6d951SJohn Birrell 194*6ff6d951SJohn Birrell idp = dt_idhash_insert(yypcb->pcb_pragmas, name, DT_IDENT_PRAGBN, 0, 0, 195*6ff6d951SJohn Birrell _dtrace_defattr, vers, &dt_idops_thaw, (void *)prname, dtp->dt_gen); 196*6ff6d951SJohn Birrell 197*6ff6d951SJohn Birrell if (idp == NULL) 198*6ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 199*6ff6d951SJohn Birrell 200*6ff6d951SJohn Birrell if (dtp->dt_globals->dh_defer == NULL) 201*6ff6d951SJohn Birrell dtp->dt_globals->dh_defer = &dt_pragma_apply; 202*6ff6d951SJohn Birrell } 203*6ff6d951SJohn Birrell 204*6ff6d951SJohn Birrell /* 205*6ff6d951SJohn Birrell * The #pragma depends_on directive can be used to express a dependency on a 206*6ff6d951SJohn Birrell * module, provider or library which if not present will cause processing to 207*6ff6d951SJohn Birrell * abort. 208*6ff6d951SJohn Birrell */ 209*6ff6d951SJohn Birrell static void 210*6ff6d951SJohn Birrell dt_pragma_depends(const char *prname, dt_node_t *cnp) 211*6ff6d951SJohn Birrell { 212*6ff6d951SJohn Birrell dtrace_hdl_t *dtp = yypcb->pcb_hdl; 213*6ff6d951SJohn Birrell dt_node_t *nnp = cnp ? cnp->dn_list : NULL; 214*6ff6d951SJohn Birrell int found; 215*6ff6d951SJohn Birrell dt_lib_depend_t *dld; 216*6ff6d951SJohn Birrell char lib[MAXPATHLEN]; 217*6ff6d951SJohn Birrell 218*6ff6d951SJohn Birrell if (cnp == NULL || nnp == NULL || 219*6ff6d951SJohn Birrell cnp->dn_kind != DT_NODE_IDENT || nnp->dn_kind != DT_NODE_IDENT) { 220*6ff6d951SJohn Birrell xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s " 221*6ff6d951SJohn Birrell "<class> <name>\n", prname); 222*6ff6d951SJohn Birrell } 223*6ff6d951SJohn Birrell 224*6ff6d951SJohn Birrell if (strcmp(cnp->dn_string, "provider") == 0) 225*6ff6d951SJohn Birrell found = dt_provider_lookup(dtp, nnp->dn_string) != NULL; 226*6ff6d951SJohn Birrell else if (strcmp(cnp->dn_string, "module") == 0) { 227*6ff6d951SJohn Birrell dt_module_t *mp = dt_module_lookup_by_name(dtp, nnp->dn_string); 228*6ff6d951SJohn Birrell found = mp != NULL && dt_module_getctf(dtp, mp) != NULL; 229*6ff6d951SJohn Birrell } else if (strcmp(cnp->dn_string, "library") == 0) { 230*6ff6d951SJohn Birrell if (yypcb->pcb_cflags & DTRACE_C_CTL) { 231*6ff6d951SJohn Birrell assert(dtp->dt_filetag != NULL); 232*6ff6d951SJohn Birrell 233*6ff6d951SJohn Birrell /* 234*6ff6d951SJohn Birrell * We have the file we are working on in dtp->dt_filetag 235*6ff6d951SJohn Birrell * so find that node and add the dependency in. 236*6ff6d951SJohn Birrell */ 237*6ff6d951SJohn Birrell dld = dt_lib_depend_lookup(&dtp->dt_lib_dep, 238*6ff6d951SJohn Birrell dtp->dt_filetag); 239*6ff6d951SJohn Birrell assert(dld != NULL); 240*6ff6d951SJohn Birrell 241*6ff6d951SJohn Birrell (void) snprintf(lib, sizeof (lib), "%s%s", 242*6ff6d951SJohn Birrell dld->dtld_libpath, nnp->dn_string); 243*6ff6d951SJohn Birrell if ((dt_lib_depend_add(dtp, &dld->dtld_dependencies, 244*6ff6d951SJohn Birrell lib)) != 0) { 245*6ff6d951SJohn Birrell xyerror(D_PRAGMA_DEPEND, 246*6ff6d951SJohn Birrell "failed to add dependency %s:%s\n", lib, 247*6ff6d951SJohn Birrell dtrace_errmsg(dtp, dtrace_errno(dtp))); 248*6ff6d951SJohn Birrell } 249*6ff6d951SJohn Birrell } else { 250*6ff6d951SJohn Birrell /* 251*6ff6d951SJohn Birrell * By this point we have already performed a topological 252*6ff6d951SJohn Birrell * sort of the dependencies; we process this directive 253*6ff6d951SJohn Birrell * as satisfied as long as the dependency was properly 254*6ff6d951SJohn Birrell * loaded. 255*6ff6d951SJohn Birrell */ 256*6ff6d951SJohn Birrell if (dtp->dt_filetag == NULL) 257*6ff6d951SJohn Birrell xyerror(D_PRAGMA_DEPEND, "main program may " 258*6ff6d951SJohn Birrell "not explicitly depend on a library"); 259*6ff6d951SJohn Birrell 260*6ff6d951SJohn Birrell dld = dt_lib_depend_lookup(&dtp->dt_lib_dep, 261*6ff6d951SJohn Birrell dtp->dt_filetag); 262*6ff6d951SJohn Birrell assert(dld != NULL); 263*6ff6d951SJohn Birrell 264*6ff6d951SJohn Birrell (void) snprintf(lib, sizeof (lib), "%s%s", 265*6ff6d951SJohn Birrell dld->dtld_libpath, nnp->dn_string); 266*6ff6d951SJohn Birrell dld = dt_lib_depend_lookup(&dtp->dt_lib_dep_sorted, 267*6ff6d951SJohn Birrell lib); 268*6ff6d951SJohn Birrell assert(dld != NULL); 269*6ff6d951SJohn Birrell 270*6ff6d951SJohn Birrell if (!dld->dtld_loaded) 271*6ff6d951SJohn Birrell xyerror(D_PRAGMA_DEPEND, "program requires " 272*6ff6d951SJohn Birrell "library \"%s\" which failed to load", 273*6ff6d951SJohn Birrell lib); 274*6ff6d951SJohn Birrell } 275*6ff6d951SJohn Birrell 276*6ff6d951SJohn Birrell found = B_TRUE; 277*6ff6d951SJohn Birrell } else { 278*6ff6d951SJohn Birrell xyerror(D_PRAGMA_INVAL, "invalid class %s " 279*6ff6d951SJohn Birrell "specified by #pragma %s\n", cnp->dn_string, prname); 280*6ff6d951SJohn Birrell } 281*6ff6d951SJohn Birrell 282*6ff6d951SJohn Birrell if (!found) { 283*6ff6d951SJohn Birrell xyerror(D_PRAGMA_DEPEND, "program requires %s %s\n", 284*6ff6d951SJohn Birrell cnp->dn_string, nnp->dn_string); 285*6ff6d951SJohn Birrell } 286*6ff6d951SJohn Birrell } 287*6ff6d951SJohn Birrell 288*6ff6d951SJohn Birrell /* 289*6ff6d951SJohn Birrell * The #pragma error directive can be followed by any list of tokens, which we 290*6ff6d951SJohn Birrell * just concatenate and print as part of our error message. 291*6ff6d951SJohn Birrell */ 292*6ff6d951SJohn Birrell static void 293*6ff6d951SJohn Birrell dt_pragma_error(const char *prname, dt_node_t *dnp) 294*6ff6d951SJohn Birrell { 295*6ff6d951SJohn Birrell dt_node_t *enp; 296*6ff6d951SJohn Birrell size_t n = 0; 297*6ff6d951SJohn Birrell char *s; 298*6ff6d951SJohn Birrell 299*6ff6d951SJohn Birrell for (enp = dnp; enp != NULL; enp = enp->dn_list) { 300*6ff6d951SJohn Birrell if (enp->dn_kind == DT_NODE_IDENT || 301*6ff6d951SJohn Birrell enp->dn_kind == DT_NODE_STRING) 302*6ff6d951SJohn Birrell n += strlen(enp->dn_string) + 1; 303*6ff6d951SJohn Birrell } 304*6ff6d951SJohn Birrell 305*6ff6d951SJohn Birrell s = alloca(n + 1); 306*6ff6d951SJohn Birrell s[0] = '\0'; 307*6ff6d951SJohn Birrell 308*6ff6d951SJohn Birrell for (enp = dnp; enp != NULL; enp = enp->dn_list) { 309*6ff6d951SJohn Birrell if (enp->dn_kind == DT_NODE_IDENT || 310*6ff6d951SJohn Birrell enp->dn_kind == DT_NODE_STRING) { 311*6ff6d951SJohn Birrell (void) strcat(s, enp->dn_string); 312*6ff6d951SJohn Birrell (void) strcat(s, " "); 313*6ff6d951SJohn Birrell } 314*6ff6d951SJohn Birrell } 315*6ff6d951SJohn Birrell 316*6ff6d951SJohn Birrell xyerror(D_PRAGERR, "#%s: %s\n", prname, s); 317*6ff6d951SJohn Birrell } 318*6ff6d951SJohn Birrell 319*6ff6d951SJohn Birrell /*ARGSUSED*/ 320*6ff6d951SJohn Birrell static void 321*6ff6d951SJohn Birrell dt_pragma_ident(const char *prname, dt_node_t *dnp) 322*6ff6d951SJohn Birrell { 323*6ff6d951SJohn Birrell /* ignore any #ident or #pragma ident lines */ 324*6ff6d951SJohn Birrell } 325*6ff6d951SJohn Birrell 326*6ff6d951SJohn Birrell static void 327*6ff6d951SJohn Birrell dt_pragma_option(const char *prname, dt_node_t *dnp) 328*6ff6d951SJohn Birrell { 329*6ff6d951SJohn Birrell dtrace_hdl_t *dtp = yypcb->pcb_hdl; 330*6ff6d951SJohn Birrell char *opt, *val; 331*6ff6d951SJohn Birrell 332*6ff6d951SJohn Birrell if (dnp == NULL || dnp->dn_kind != DT_NODE_IDENT) { 333*6ff6d951SJohn Birrell xyerror(D_PRAGMA_MALFORM, 334*6ff6d951SJohn Birrell "malformed #pragma %s <option>=<val>\n", prname); 335*6ff6d951SJohn Birrell } 336*6ff6d951SJohn Birrell 337*6ff6d951SJohn Birrell if (dnp->dn_list != NULL) { 338*6ff6d951SJohn Birrell xyerror(D_PRAGMA_MALFORM, 339*6ff6d951SJohn Birrell "superfluous arguments specified for #pragma %s\n", prname); 340*6ff6d951SJohn Birrell } 341*6ff6d951SJohn Birrell 342*6ff6d951SJohn Birrell opt = alloca(strlen(dnp->dn_string) + 1); 343*6ff6d951SJohn Birrell (void) strcpy(opt, dnp->dn_string); 344*6ff6d951SJohn Birrell 345*6ff6d951SJohn Birrell if ((val = strchr(opt, '=')) != NULL) 346*6ff6d951SJohn Birrell *val++ = '\0'; 347*6ff6d951SJohn Birrell 348*6ff6d951SJohn Birrell if (dtrace_setopt(dtp, opt, val) == -1) { 349*6ff6d951SJohn Birrell if (val == NULL) { 350*6ff6d951SJohn Birrell xyerror(D_PRAGMA_OPTSET, 351*6ff6d951SJohn Birrell "failed to set option '%s': %s\n", opt, 352*6ff6d951SJohn Birrell dtrace_errmsg(dtp, dtrace_errno(dtp))); 353*6ff6d951SJohn Birrell } else { 354*6ff6d951SJohn Birrell xyerror(D_PRAGMA_OPTSET, 355*6ff6d951SJohn Birrell "failed to set option '%s' to '%s': %s\n", 356*6ff6d951SJohn Birrell opt, val, dtrace_errmsg(dtp, dtrace_errno(dtp))); 357*6ff6d951SJohn Birrell } 358*6ff6d951SJohn Birrell } 359*6ff6d951SJohn Birrell } 360*6ff6d951SJohn Birrell 361*6ff6d951SJohn Birrell /* 362*6ff6d951SJohn Birrell * The #line directive is used to reset the input line number and to optionally 363*6ff6d951SJohn Birrell * note the file name for use in error messages. Sun cpp(1) also produces a 364*6ff6d951SJohn Birrell * third integer token after the filename which is one of the following: 365*6ff6d951SJohn Birrell * 366*6ff6d951SJohn Birrell * 0 - line change has nothing to do with an #include file 367*6ff6d951SJohn Birrell * 1 - line change because we just entered a #include file 368*6ff6d951SJohn Birrell * 2 - line change because we just exited a #include file 369*6ff6d951SJohn Birrell * 370*6ff6d951SJohn Birrell * We use these state tokens to adjust pcb_idepth, which in turn controls 371*6ff6d951SJohn Birrell * whether type lookups access the global type space or not. 372*6ff6d951SJohn Birrell */ 373*6ff6d951SJohn Birrell static void 374*6ff6d951SJohn Birrell dt_pragma_line(const char *prname, dt_node_t *dnp) 375*6ff6d951SJohn Birrell { 376*6ff6d951SJohn Birrell dt_node_t *fnp = dnp ? dnp->dn_list : NULL; 377*6ff6d951SJohn Birrell dt_node_t *inp = fnp ? fnp->dn_list : NULL; 378*6ff6d951SJohn Birrell 379*6ff6d951SJohn Birrell if ((dnp == NULL || dnp->dn_kind != DT_NODE_INT) || 380*6ff6d951SJohn Birrell (fnp != NULL && fnp->dn_kind != DT_NODE_STRING) || 381*6ff6d951SJohn Birrell (inp != NULL && inp->dn_kind != DT_NODE_INT)) { 382*6ff6d951SJohn Birrell xyerror(D_PRAGMA_MALFORM, "malformed #%s " 383*6ff6d951SJohn Birrell "<line> [ [\"file\"] state ]\n", prname); 384*6ff6d951SJohn Birrell } 385*6ff6d951SJohn Birrell 386*6ff6d951SJohn Birrell /* 387*6ff6d951SJohn Birrell * If a file is specified, free any old pcb_filetag and swap fnp's 388*6ff6d951SJohn Birrell * dn_string into pcb_filetag as the new filename for error messages. 389*6ff6d951SJohn Birrell */ 390*6ff6d951SJohn Birrell if (fnp != NULL) { 391*6ff6d951SJohn Birrell if (yypcb->pcb_filetag != NULL) 392*6ff6d951SJohn Birrell free(yypcb->pcb_filetag); 393*6ff6d951SJohn Birrell 394*6ff6d951SJohn Birrell /* 395*6ff6d951SJohn Birrell * This is not pretty, but is a necessary evil until we either 396*6ff6d951SJohn Birrell * write "dpp" or get a useful standalone cpp from DevPro. If 397*6ff6d951SJohn Birrell * the filename begins with /dev/fd, we know it's the master 398*6ff6d951SJohn Birrell * input file (see dt_preproc() in dt_cc.c), so just clear the 399*6ff6d951SJohn Birrell * dt_filetag pointer so error messages refer to the main file. 400*6ff6d951SJohn Birrell */ 401*6ff6d951SJohn Birrell if (strncmp(fnp->dn_string, "/dev/fd/", 8) != 0) { 402*6ff6d951SJohn Birrell yypcb->pcb_filetag = fnp->dn_string; 403*6ff6d951SJohn Birrell fnp->dn_string = NULL; 404*6ff6d951SJohn Birrell } else 405*6ff6d951SJohn Birrell yypcb->pcb_filetag = NULL; 406*6ff6d951SJohn Birrell } 407*6ff6d951SJohn Birrell 408*6ff6d951SJohn Birrell if (inp != NULL) { 409*6ff6d951SJohn Birrell if (inp->dn_value == 1) 410*6ff6d951SJohn Birrell yypcb->pcb_idepth++; 411*6ff6d951SJohn Birrell else if (inp->dn_value == 2 && yypcb->pcb_idepth != 0) 412*6ff6d951SJohn Birrell yypcb->pcb_idepth--; 413*6ff6d951SJohn Birrell } 414*6ff6d951SJohn Birrell 415*6ff6d951SJohn Birrell yylineno = dnp->dn_value; 416*6ff6d951SJohn Birrell } 417*6ff6d951SJohn Birrell 418*6ff6d951SJohn Birrell /* 419*6ff6d951SJohn Birrell * D compiler pragma types range from control directives to common pragmas to 420*6ff6d951SJohn Birrell * D custom pragmas, in order of specificity. Similar to gcc, we use #pragma D 421*6ff6d951SJohn Birrell * as a special prefix for our pragmas so they can be used in mixed headers. 422*6ff6d951SJohn Birrell */ 423*6ff6d951SJohn Birrell #define DT_PRAGMA_DIR 0 /* pragma directive may be used after naked # */ 424*6ff6d951SJohn Birrell #define DT_PRAGMA_SUB 1 /* pragma directive may be used after #pragma */ 425*6ff6d951SJohn Birrell #define DT_PRAGMA_DCP 2 /* pragma may only be used after #pragma D */ 426*6ff6d951SJohn Birrell 427*6ff6d951SJohn Birrell static const struct dt_pragmadesc { 428*6ff6d951SJohn Birrell const char *dpd_name; 429*6ff6d951SJohn Birrell void (*dpd_func)(const char *, dt_node_t *); 430*6ff6d951SJohn Birrell int dpd_kind; 431*6ff6d951SJohn Birrell } dt_pragmas[] = { 432*6ff6d951SJohn Birrell { "attributes", dt_pragma_attributes, DT_PRAGMA_DCP }, 433*6ff6d951SJohn Birrell { "binding", dt_pragma_binding, DT_PRAGMA_DCP }, 434*6ff6d951SJohn Birrell { "depends_on", dt_pragma_depends, DT_PRAGMA_DCP }, 435*6ff6d951SJohn Birrell { "error", dt_pragma_error, DT_PRAGMA_DIR }, 436*6ff6d951SJohn Birrell { "ident", dt_pragma_ident, DT_PRAGMA_DIR }, 437*6ff6d951SJohn Birrell { "line", dt_pragma_line, DT_PRAGMA_DIR }, 438*6ff6d951SJohn Birrell { "option", dt_pragma_option, DT_PRAGMA_DCP }, 439*6ff6d951SJohn Birrell { NULL, NULL } 440*6ff6d951SJohn Birrell }; 441*6ff6d951SJohn Birrell 442*6ff6d951SJohn Birrell /* 443*6ff6d951SJohn Birrell * Process a control line #directive by looking up the directive name in our 444*6ff6d951SJohn Birrell * lookup table and invoking the corresponding function with the token list. 445*6ff6d951SJohn Birrell * According to K&R[A12.9], we silently ignore null directive lines. 446*6ff6d951SJohn Birrell */ 447*6ff6d951SJohn Birrell void 448*6ff6d951SJohn Birrell dt_pragma(dt_node_t *pnp) 449*6ff6d951SJohn Birrell { 450*6ff6d951SJohn Birrell const struct dt_pragmadesc *dpd; 451*6ff6d951SJohn Birrell dt_node_t *dnp; 452*6ff6d951SJohn Birrell int kind = DT_PRAGMA_DIR; 453*6ff6d951SJohn Birrell 454*6ff6d951SJohn Birrell for (dnp = pnp; dnp != NULL; dnp = dnp->dn_list) { 455*6ff6d951SJohn Birrell if (dnp->dn_kind == DT_NODE_INT) { 456*6ff6d951SJohn Birrell dt_pragma_line("line", dnp); 457*6ff6d951SJohn Birrell break; 458*6ff6d951SJohn Birrell } 459*6ff6d951SJohn Birrell 460*6ff6d951SJohn Birrell if (dnp->dn_kind != DT_NODE_IDENT) 461*6ff6d951SJohn Birrell xyerror(D_PRAGCTL_INVAL, "invalid control directive\n"); 462*6ff6d951SJohn Birrell 463*6ff6d951SJohn Birrell if (kind == DT_PRAGMA_DIR && 464*6ff6d951SJohn Birrell strcmp(dnp->dn_string, "pragma") == 0) { 465*6ff6d951SJohn Birrell kind = DT_PRAGMA_SUB; 466*6ff6d951SJohn Birrell continue; 467*6ff6d951SJohn Birrell } 468*6ff6d951SJohn Birrell 469*6ff6d951SJohn Birrell if (kind == DT_PRAGMA_SUB && 470*6ff6d951SJohn Birrell strcmp(dnp->dn_string, "D") == 0) { 471*6ff6d951SJohn Birrell kind = DT_PRAGMA_DCP; 472*6ff6d951SJohn Birrell continue; 473*6ff6d951SJohn Birrell } 474*6ff6d951SJohn Birrell 475*6ff6d951SJohn Birrell for (dpd = dt_pragmas; dpd->dpd_name != NULL; dpd++) { 476*6ff6d951SJohn Birrell if (dpd->dpd_kind <= kind && 477*6ff6d951SJohn Birrell strcmp(dpd->dpd_name, dnp->dn_string) == 0) 478*6ff6d951SJohn Birrell break; 479*6ff6d951SJohn Birrell } 480*6ff6d951SJohn Birrell 481*6ff6d951SJohn Birrell yylineno--; /* since we've already seen \n */ 482*6ff6d951SJohn Birrell 483*6ff6d951SJohn Birrell if (dpd->dpd_name != NULL) { 484*6ff6d951SJohn Birrell dpd->dpd_func(dpd->dpd_name, dnp->dn_list); 485*6ff6d951SJohn Birrell yylineno++; 486*6ff6d951SJohn Birrell break; 487*6ff6d951SJohn Birrell } 488*6ff6d951SJohn Birrell 489*6ff6d951SJohn Birrell switch (kind) { 490*6ff6d951SJohn Birrell case DT_PRAGMA_DIR: 491*6ff6d951SJohn Birrell xyerror(D_PRAGCTL_INVAL, "invalid control directive: " 492*6ff6d951SJohn Birrell "#%s\n", dnp->dn_string); 493*6ff6d951SJohn Birrell /*NOTREACHED*/ 494*6ff6d951SJohn Birrell case DT_PRAGMA_SUB: 495*6ff6d951SJohn Birrell break; /* K&R[A12.8] says to ignore unknown pragmas */ 496*6ff6d951SJohn Birrell case DT_PRAGMA_DCP: 497*6ff6d951SJohn Birrell default: 498*6ff6d951SJohn Birrell xyerror(D_PRAGMA_INVAL, "invalid D pragma: %s\n", 499*6ff6d951SJohn Birrell dnp->dn_string); 500*6ff6d951SJohn Birrell } 501*6ff6d951SJohn Birrell 502*6ff6d951SJohn Birrell yylineno++; 503*6ff6d951SJohn Birrell break; 504*6ff6d951SJohn Birrell } 505*6ff6d951SJohn Birrell 506*6ff6d951SJohn Birrell dt_node_list_free(&pnp); 507*6ff6d951SJohn Birrell } 508