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