16ff6d951SJohn Birrell /*
26ff6d951SJohn Birrell * CDDL HEADER START
36ff6d951SJohn Birrell *
46ff6d951SJohn Birrell * The contents of this file are subject to the terms of the
56ff6d951SJohn Birrell * Common Development and Distribution License (the "License").
66ff6d951SJohn Birrell * You may not use this file except in compliance with the License.
76ff6d951SJohn Birrell *
86ff6d951SJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96ff6d951SJohn Birrell * or http://www.opensolaris.org/os/licensing.
106ff6d951SJohn Birrell * See the License for the specific language governing permissions
116ff6d951SJohn Birrell * and limitations under the License.
126ff6d951SJohn Birrell *
136ff6d951SJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each
146ff6d951SJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156ff6d951SJohn Birrell * If applicable, add the following below this CDDL HEADER, with the
166ff6d951SJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying
176ff6d951SJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner]
186ff6d951SJohn Birrell *
196ff6d951SJohn Birrell * CDDL HEADER END
206ff6d951SJohn Birrell */
21cccc7d47SJohn Birrell
226ff6d951SJohn Birrell /*
23cccc7d47SJohn Birrell * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24694a0093SPedro F. Giffuni * Copyright (c) 2011, Joyent Inc. All rights reserved.
256ff6d951SJohn Birrell */
266ff6d951SJohn Birrell
276ff6d951SJohn Birrell #pragma ident "%Z%%M% %I% %E% SMI"
286ff6d951SJohn Birrell
296ff6d951SJohn Birrell #include <assert.h>
306ff6d951SJohn Birrell #include <strings.h>
31bc96366cSSteven Hartland #ifdef illumos
326ff6d951SJohn Birrell #include <alloca.h>
33cccc7d47SJohn Birrell #endif
34694a0093SPedro F. Giffuni #include <fcntl.h>
356ff6d951SJohn Birrell #include <stdlib.h>
366ff6d951SJohn Birrell #include <stdio.h>
376ff6d951SJohn Birrell
38694a0093SPedro F. Giffuni #include <sys/types.h>
394ddb46f6SXin LI #include <sys/sysctl.h>
40694a0093SPedro F. Giffuni #include <sys/stat.h>
41694a0093SPedro F. Giffuni
426ff6d951SJohn Birrell #include <dt_parser.h>
436ff6d951SJohn Birrell #include <dt_impl.h>
446ff6d951SJohn Birrell #include <dt_provider.h>
456ff6d951SJohn Birrell #include <dt_module.h>
466ff6d951SJohn Birrell
476ff6d951SJohn Birrell /*
486ff6d951SJohn Birrell * This callback function is installed in a given identifier hash to search for
496ff6d951SJohn Birrell * and apply deferred pragmas that are pending for a given new identifier name.
506ff6d951SJohn Birrell * Multiple pragmas may be pending for a given name; we processs all of them.
516ff6d951SJohn Birrell */
526ff6d951SJohn Birrell /*ARGSUSED*/
536ff6d951SJohn Birrell static void
dt_pragma_apply(dt_idhash_t * dhp,dt_ident_t * idp)546ff6d951SJohn Birrell dt_pragma_apply(dt_idhash_t *dhp, dt_ident_t *idp)
556ff6d951SJohn Birrell {
566ff6d951SJohn Birrell dt_idhash_t *php;
576ff6d951SJohn Birrell dt_ident_t *pdp;
586ff6d951SJohn Birrell
596ff6d951SJohn Birrell if ((php = yypcb->pcb_pragmas) == NULL)
606ff6d951SJohn Birrell return; /* no pragmas pending for current compilation pass */
616ff6d951SJohn Birrell
626ff6d951SJohn Birrell while ((pdp = dt_idhash_lookup(php, idp->di_name)) != NULL) {
636ff6d951SJohn Birrell switch (pdp->di_kind) {
646ff6d951SJohn Birrell case DT_IDENT_PRAGAT:
656ff6d951SJohn Birrell idp->di_attr = pdp->di_attr;
666ff6d951SJohn Birrell break;
676ff6d951SJohn Birrell case DT_IDENT_PRAGBN:
686ff6d951SJohn Birrell idp->di_vers = pdp->di_vers;
696ff6d951SJohn Birrell break;
706ff6d951SJohn Birrell }
716ff6d951SJohn Birrell dt_idhash_delete(php, pdp);
726ff6d951SJohn Birrell }
736ff6d951SJohn Birrell }
746ff6d951SJohn Birrell
756ff6d951SJohn Birrell /*
766ff6d951SJohn Birrell * The #pragma attributes directive can be used to reset stability attributes
776ff6d951SJohn Birrell * on a global identifier or inline definition. If the identifier is already
786ff6d951SJohn Birrell * defined, we can just change di_attr. If not, we insert the pragma into a
796ff6d951SJohn Birrell * hash table of the current pcb's deferred pragmas for later processing.
806ff6d951SJohn Birrell */
816ff6d951SJohn Birrell static void
dt_pragma_attributes(const char * prname,dt_node_t * dnp)826ff6d951SJohn Birrell dt_pragma_attributes(const char *prname, dt_node_t *dnp)
836ff6d951SJohn Birrell {
846ff6d951SJohn Birrell dtrace_hdl_t *dtp = yypcb->pcb_hdl;
856ff6d951SJohn Birrell dtrace_attribute_t attr, *a;
866ff6d951SJohn Birrell dt_provider_t *pvp;
876ff6d951SJohn Birrell const char *name, *part;
886ff6d951SJohn Birrell dt_ident_t *idp;
896ff6d951SJohn Birrell
906ff6d951SJohn Birrell if (dnp == NULL || dnp->dn_kind != DT_NODE_IDENT ||
916ff6d951SJohn Birrell dnp->dn_list == NULL || dnp->dn_list->dn_kind != DT_NODE_IDENT) {
926ff6d951SJohn Birrell xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s "
936ff6d951SJohn Birrell "<attributes> <ident>\n", prname);
946ff6d951SJohn Birrell }
956ff6d951SJohn Birrell
966ff6d951SJohn Birrell if (dtrace_str2attr(dnp->dn_string, &attr) == -1) {
976ff6d951SJohn Birrell xyerror(D_PRAGMA_INVAL, "invalid attributes "
986ff6d951SJohn Birrell "specified by #pragma %s\n", prname);
996ff6d951SJohn Birrell }
1006ff6d951SJohn Birrell
1016ff6d951SJohn Birrell dnp = dnp->dn_list;
1026ff6d951SJohn Birrell name = dnp->dn_string;
1036ff6d951SJohn Birrell
1046ff6d951SJohn Birrell if (strcmp(name, "provider") == 0) {
1056ff6d951SJohn Birrell dnp = dnp->dn_list;
1066ff6d951SJohn Birrell name = dnp->dn_string;
1076ff6d951SJohn Birrell
1086ff6d951SJohn Birrell dnp = dnp->dn_list;
1096ff6d951SJohn Birrell part = dnp->dn_string;
1106ff6d951SJohn Birrell
1116ff6d951SJohn Birrell if ((pvp = dt_provider_lookup(dtp, name)) != NULL) {
1126ff6d951SJohn Birrell if (strcmp(part, "provider") == 0) {
1136ff6d951SJohn Birrell a = &pvp->pv_desc.dtvd_attr.dtpa_provider;
1146ff6d951SJohn Birrell } else if (strcmp(part, "module") == 0) {
1156ff6d951SJohn Birrell a = &pvp->pv_desc.dtvd_attr.dtpa_mod;
1166ff6d951SJohn Birrell } else if (strcmp(part, "function") == 0) {
1176ff6d951SJohn Birrell a = &pvp->pv_desc.dtvd_attr.dtpa_func;
1186ff6d951SJohn Birrell } else if (strcmp(part, "name") == 0) {
1196ff6d951SJohn Birrell a = &pvp->pv_desc.dtvd_attr.dtpa_name;
1206ff6d951SJohn Birrell } else if (strcmp(part, "args") == 0) {
1216ff6d951SJohn Birrell a = &pvp->pv_desc.dtvd_attr.dtpa_args;
1226ff6d951SJohn Birrell } else {
1236ff6d951SJohn Birrell xyerror(D_PRAGMA_INVAL, "invalid component "
1246ff6d951SJohn Birrell "\"%s\" in attribute #pragma "
1256ff6d951SJohn Birrell "for provider %s\n", name, part);
1266ff6d951SJohn Birrell }
1276ff6d951SJohn Birrell
1286ff6d951SJohn Birrell *a = attr;
1296ff6d951SJohn Birrell return;
1306ff6d951SJohn Birrell }
1316ff6d951SJohn Birrell
1326ff6d951SJohn Birrell } else if ((idp = dt_idstack_lookup(
1336ff6d951SJohn Birrell &yypcb->pcb_globals, name)) != NULL) {
1346ff6d951SJohn Birrell
1356ff6d951SJohn Birrell if (idp->di_gen != dtp->dt_gen) {
1366ff6d951SJohn Birrell xyerror(D_PRAGMA_SCOPE, "#pragma %s cannot modify "
1376ff6d951SJohn Birrell "entity defined outside program scope\n", prname);
1386ff6d951SJohn Birrell }
1396ff6d951SJohn Birrell
1406ff6d951SJohn Birrell idp->di_attr = attr;
1416ff6d951SJohn Birrell return;
1426ff6d951SJohn Birrell }
1436ff6d951SJohn Birrell
1446ff6d951SJohn Birrell if (yypcb->pcb_pragmas == NULL && (yypcb->pcb_pragmas =
1456ff6d951SJohn Birrell dt_idhash_create("pragma", NULL, 0, 0)) == NULL)
1466ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
1476ff6d951SJohn Birrell
1486ff6d951SJohn Birrell idp = dt_idhash_insert(yypcb->pcb_pragmas, name, DT_IDENT_PRAGAT, 0, 0,
1496ff6d951SJohn Birrell attr, 0, &dt_idops_thaw, (void *)prname, dtp->dt_gen);
1506ff6d951SJohn Birrell
1516ff6d951SJohn Birrell if (idp == NULL)
1526ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
1536ff6d951SJohn Birrell
1546ff6d951SJohn Birrell if (dtp->dt_globals->dh_defer == NULL)
1556ff6d951SJohn Birrell dtp->dt_globals->dh_defer = &dt_pragma_apply;
1566ff6d951SJohn Birrell }
1576ff6d951SJohn Birrell
1586ff6d951SJohn Birrell /*
1596ff6d951SJohn Birrell * The #pragma binding directive can be used to reset the version binding
1606ff6d951SJohn Birrell * on a global identifier or inline definition. If the identifier is already
1616ff6d951SJohn Birrell * defined, we can just change di_vers. If not, we insert the pragma into a
1626ff6d951SJohn Birrell * hash table of the current pcb's deferred pragmas for later processing.
1636ff6d951SJohn Birrell */
1646ff6d951SJohn Birrell static void
dt_pragma_binding(const char * prname,dt_node_t * dnp)1656ff6d951SJohn Birrell dt_pragma_binding(const char *prname, dt_node_t *dnp)
1666ff6d951SJohn Birrell {
1676ff6d951SJohn Birrell dtrace_hdl_t *dtp = yypcb->pcb_hdl;
1686ff6d951SJohn Birrell dt_version_t vers;
1696ff6d951SJohn Birrell const char *name;
1706ff6d951SJohn Birrell dt_ident_t *idp;
1716ff6d951SJohn Birrell
1726ff6d951SJohn Birrell if (dnp == NULL || dnp->dn_kind != DT_NODE_STRING ||
1736ff6d951SJohn Birrell dnp->dn_list == NULL || dnp->dn_list->dn_kind != DT_NODE_IDENT) {
1746ff6d951SJohn Birrell xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s "
1756ff6d951SJohn Birrell "\"version\" <ident>\n", prname);
1766ff6d951SJohn Birrell }
1776ff6d951SJohn Birrell
1786ff6d951SJohn Birrell if (dt_version_str2num(dnp->dn_string, &vers) == -1) {
1796ff6d951SJohn Birrell xyerror(D_PRAGMA_INVAL, "invalid version string "
1806ff6d951SJohn Birrell "specified by #pragma %s\n", prname);
1816ff6d951SJohn Birrell }
1826ff6d951SJohn Birrell
1836ff6d951SJohn Birrell name = dnp->dn_list->dn_string;
1846ff6d951SJohn Birrell idp = dt_idstack_lookup(&yypcb->pcb_globals, name);
1856ff6d951SJohn Birrell
1866ff6d951SJohn Birrell if (idp != NULL) {
1876ff6d951SJohn Birrell if (idp->di_gen != dtp->dt_gen) {
1886ff6d951SJohn Birrell xyerror(D_PRAGMA_SCOPE, "#pragma %s cannot modify "
1896ff6d951SJohn Birrell "entity defined outside program scope\n", prname);
1906ff6d951SJohn Birrell }
1916ff6d951SJohn Birrell idp->di_vers = vers;
1926ff6d951SJohn Birrell return;
1936ff6d951SJohn Birrell }
1946ff6d951SJohn Birrell
1956ff6d951SJohn Birrell if (yypcb->pcb_pragmas == NULL && (yypcb->pcb_pragmas =
1966ff6d951SJohn Birrell dt_idhash_create("pragma", NULL, 0, 0)) == NULL)
1976ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
1986ff6d951SJohn Birrell
1996ff6d951SJohn Birrell idp = dt_idhash_insert(yypcb->pcb_pragmas, name, DT_IDENT_PRAGBN, 0, 0,
2006ff6d951SJohn Birrell _dtrace_defattr, vers, &dt_idops_thaw, (void *)prname, dtp->dt_gen);
2016ff6d951SJohn Birrell
2026ff6d951SJohn Birrell if (idp == NULL)
2036ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
2046ff6d951SJohn Birrell
2056ff6d951SJohn Birrell if (dtp->dt_globals->dh_defer == NULL)
2066ff6d951SJohn Birrell dtp->dt_globals->dh_defer = &dt_pragma_apply;
2076ff6d951SJohn Birrell }
2086ff6d951SJohn Birrell
209694a0093SPedro F. Giffuni static void
dt_pragma_depends_finddep(dtrace_hdl_t * dtp,const char * lname,char * lib,size_t len)210694a0093SPedro F. Giffuni dt_pragma_depends_finddep(dtrace_hdl_t *dtp, const char *lname, char *lib,
211694a0093SPedro F. Giffuni size_t len)
212694a0093SPedro F. Giffuni {
213694a0093SPedro F. Giffuni dt_dirpath_t *dirp;
214694a0093SPedro F. Giffuni struct stat sbuf;
215694a0093SPedro F. Giffuni int found = 0;
216694a0093SPedro F. Giffuni
217694a0093SPedro F. Giffuni for (dirp = dt_list_next(&dtp->dt_lib_path); dirp != NULL;
218694a0093SPedro F. Giffuni dirp = dt_list_next(dirp)) {
219694a0093SPedro F. Giffuni (void) snprintf(lib, len, "%s/%s", dirp->dir_path, lname);
220694a0093SPedro F. Giffuni
221694a0093SPedro F. Giffuni if (stat(lib, &sbuf) == 0) {
222694a0093SPedro F. Giffuni found = 1;
223694a0093SPedro F. Giffuni break;
224694a0093SPedro F. Giffuni }
225694a0093SPedro F. Giffuni }
226694a0093SPedro F. Giffuni
227694a0093SPedro F. Giffuni if (!found)
228694a0093SPedro F. Giffuni xyerror(D_PRAGMA_DEPEND,
229694a0093SPedro F. Giffuni "failed to find dependency in libpath: %s", lname);
230694a0093SPedro F. Giffuni }
231694a0093SPedro F. Giffuni
2326ff6d951SJohn Birrell /*
2336ff6d951SJohn Birrell * The #pragma depends_on directive can be used to express a dependency on a
2346ff6d951SJohn Birrell * module, provider or library which if not present will cause processing to
2356ff6d951SJohn Birrell * abort.
2366ff6d951SJohn Birrell */
2376ff6d951SJohn Birrell static void
dt_pragma_depends(const char * prname,dt_node_t * cnp)2386ff6d951SJohn Birrell dt_pragma_depends(const char *prname, dt_node_t *cnp)
2396ff6d951SJohn Birrell {
2406ff6d951SJohn Birrell dtrace_hdl_t *dtp = yypcb->pcb_hdl;
2416ff6d951SJohn Birrell dt_node_t *nnp = cnp ? cnp->dn_list : NULL;
2426ff6d951SJohn Birrell int found;
2436ff6d951SJohn Birrell dt_lib_depend_t *dld;
244cccc7d47SJohn Birrell char lib[MAXPATHLEN];
24503a9b7c0SGeorge V. Neville-Neil size_t plen;
24603a9b7c0SGeorge V. Neville-Neil char *provs, *cpy, *tok;
2476ff6d951SJohn Birrell
2486ff6d951SJohn Birrell if (cnp == NULL || nnp == NULL ||
2496ff6d951SJohn Birrell cnp->dn_kind != DT_NODE_IDENT || nnp->dn_kind != DT_NODE_IDENT) {
2506ff6d951SJohn Birrell xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s "
2516ff6d951SJohn Birrell "<class> <name>\n", prname);
2526ff6d951SJohn Birrell }
2536ff6d951SJohn Birrell
25403a9b7c0SGeorge V. Neville-Neil if (strcmp(cnp->dn_string, "provider") == 0) {
25503a9b7c0SGeorge V. Neville-Neil /*
25603a9b7c0SGeorge V. Neville-Neil * First try to get the provider list using the
25703a9b7c0SGeorge V. Neville-Neil * debug.dtrace.providers sysctl, since that'll work even if
25803a9b7c0SGeorge V. Neville-Neil * we're not running as root.
25903a9b7c0SGeorge V. Neville-Neil */
26003a9b7c0SGeorge V. Neville-Neil provs = NULL;
26103a9b7c0SGeorge V. Neville-Neil if (sysctlbyname("debug.dtrace.providers", NULL, &plen, NULL, 0) ||
26203a9b7c0SGeorge V. Neville-Neil ((provs = dt_alloc(dtp, plen)) == NULL) ||
26303a9b7c0SGeorge V. Neville-Neil sysctlbyname("debug.dtrace.providers", provs, &plen, NULL, 0))
2646ff6d951SJohn Birrell found = dt_provider_lookup(dtp, nnp->dn_string) != NULL;
26503a9b7c0SGeorge V. Neville-Neil else {
26603a9b7c0SGeorge V. Neville-Neil found = B_FALSE;
26703a9b7c0SGeorge V. Neville-Neil for (cpy = provs; (tok = strsep(&cpy, " ")) != NULL; )
26803a9b7c0SGeorge V. Neville-Neil if (strcmp(tok, nnp->dn_string) == 0) {
26903a9b7c0SGeorge V. Neville-Neil found = B_TRUE;
27003a9b7c0SGeorge V. Neville-Neil break;
27103a9b7c0SGeorge V. Neville-Neil }
27203a9b7c0SGeorge V. Neville-Neil if (found == B_FALSE)
27303a9b7c0SGeorge V. Neville-Neil found = dt_provider_lookup(dtp,
27403a9b7c0SGeorge V. Neville-Neil nnp->dn_string) != NULL;
27503a9b7c0SGeorge V. Neville-Neil }
27603a9b7c0SGeorge V. Neville-Neil if (provs != NULL)
27703a9b7c0SGeorge V. Neville-Neil dt_free(dtp, provs);
27803a9b7c0SGeorge V. Neville-Neil } else if (strcmp(cnp->dn_string, "module") == 0) {
2796ff6d951SJohn Birrell dt_module_t *mp = dt_module_lookup_by_name(dtp, nnp->dn_string);
2806ff6d951SJohn Birrell found = mp != NULL && dt_module_getctf(dtp, mp) != NULL;
281*8436cb81SMark Johnston #ifdef __FreeBSD__
282*8436cb81SMark Johnston if (!found) {
283*8436cb81SMark Johnston dt_kmodule_t *dkmp = dt_kmodule_lookup(dtp,
284*8436cb81SMark Johnston nnp->dn_string);
285*8436cb81SMark Johnston found = dkmp != NULL &&
286*8436cb81SMark Johnston dt_module_getctf(dtp, dkmp->dkm_module) != NULL;
287*8436cb81SMark Johnston }
288*8436cb81SMark Johnston #endif
2896ff6d951SJohn Birrell } else if (strcmp(cnp->dn_string, "library") == 0) {
290cccc7d47SJohn Birrell if (yypcb->pcb_cflags & DTRACE_C_CTL) {
291cccc7d47SJohn Birrell assert(dtp->dt_filetag != NULL);
2926ff6d951SJohn Birrell
293694a0093SPedro F. Giffuni dt_pragma_depends_finddep(dtp, nnp->dn_string, lib,
294694a0093SPedro F. Giffuni sizeof (lib));
295694a0093SPedro F. Giffuni
296cccc7d47SJohn Birrell dld = dt_lib_depend_lookup(&dtp->dt_lib_dep,
297cccc7d47SJohn Birrell dtp->dt_filetag);
298cccc7d47SJohn Birrell assert(dld != NULL);
299cccc7d47SJohn Birrell
300cccc7d47SJohn Birrell if ((dt_lib_depend_add(dtp, &dld->dtld_dependencies,
301cccc7d47SJohn Birrell lib)) != 0) {
302cccc7d47SJohn Birrell xyerror(D_PRAGMA_DEPEND,
303cccc7d47SJohn Birrell "failed to add dependency %s:%s\n", lib,
304cccc7d47SJohn Birrell dtrace_errmsg(dtp, dtrace_errno(dtp)));
305cccc7d47SJohn Birrell }
306cccc7d47SJohn Birrell } else {
307cccc7d47SJohn Birrell /*
308cccc7d47SJohn Birrell * By this point we have already performed a topological
309cccc7d47SJohn Birrell * sort of the dependencies; we process this directive
310cccc7d47SJohn Birrell * as satisfied as long as the dependency was properly
311cccc7d47SJohn Birrell * loaded.
312cccc7d47SJohn Birrell */
313cccc7d47SJohn Birrell if (dtp->dt_filetag == NULL)
314cccc7d47SJohn Birrell xyerror(D_PRAGMA_DEPEND, "main program may "
315cccc7d47SJohn Birrell "not explicitly depend on a library");
31620594ebfSJohn Birrell
3176ff6d951SJohn Birrell dld = dt_lib_depend_lookup(&dtp->dt_lib_dep,
3186ff6d951SJohn Birrell dtp->dt_filetag);
3196ff6d951SJohn Birrell assert(dld != NULL);
3206ff6d951SJohn Birrell
321694a0093SPedro F. Giffuni dt_pragma_depends_finddep(dtp, nnp->dn_string, lib,
322694a0093SPedro F. Giffuni sizeof (lib));
323cccc7d47SJohn Birrell dld = dt_lib_depend_lookup(&dtp->dt_lib_dep_sorted,
324cccc7d47SJohn Birrell lib);
325cccc7d47SJohn Birrell assert(dld != NULL);
326cccc7d47SJohn Birrell
327cccc7d47SJohn Birrell if (!dld->dtld_loaded)
328cccc7d47SJohn Birrell xyerror(D_PRAGMA_DEPEND, "program requires "
329cccc7d47SJohn Birrell "library \"%s\" which failed to load",
330cccc7d47SJohn Birrell lib);
3316ff6d951SJohn Birrell }
332cccc7d47SJohn Birrell
333cccc7d47SJohn Birrell found = B_TRUE;
3346ff6d951SJohn Birrell } else {
3356ff6d951SJohn Birrell xyerror(D_PRAGMA_INVAL, "invalid class %s "
3366ff6d951SJohn Birrell "specified by #pragma %s\n", cnp->dn_string, prname);
3376ff6d951SJohn Birrell }
3386ff6d951SJohn Birrell
3396ff6d951SJohn Birrell if (!found) {
3406ff6d951SJohn Birrell xyerror(D_PRAGMA_DEPEND, "program requires %s %s\n",
3416ff6d951SJohn Birrell cnp->dn_string, nnp->dn_string);
3426ff6d951SJohn Birrell }
3436ff6d951SJohn Birrell }
3446ff6d951SJohn Birrell
3456ff6d951SJohn Birrell /*
3466ff6d951SJohn Birrell * The #pragma error directive can be followed by any list of tokens, which we
3476ff6d951SJohn Birrell * just concatenate and print as part of our error message.
3486ff6d951SJohn Birrell */
3496ff6d951SJohn Birrell static void
dt_pragma_error(const char * prname,dt_node_t * dnp)3506ff6d951SJohn Birrell dt_pragma_error(const char *prname, dt_node_t *dnp)
3516ff6d951SJohn Birrell {
3526ff6d951SJohn Birrell dt_node_t *enp;
3536ff6d951SJohn Birrell size_t n = 0;
3546ff6d951SJohn Birrell char *s;
3556ff6d951SJohn Birrell
3566ff6d951SJohn Birrell for (enp = dnp; enp != NULL; enp = enp->dn_list) {
3576ff6d951SJohn Birrell if (enp->dn_kind == DT_NODE_IDENT ||
3586ff6d951SJohn Birrell enp->dn_kind == DT_NODE_STRING)
3596ff6d951SJohn Birrell n += strlen(enp->dn_string) + 1;
3606ff6d951SJohn Birrell }
3616ff6d951SJohn Birrell
3626ff6d951SJohn Birrell s = alloca(n + 1);
3636ff6d951SJohn Birrell s[0] = '\0';
3646ff6d951SJohn Birrell
3656ff6d951SJohn Birrell for (enp = dnp; enp != NULL; enp = enp->dn_list) {
3666ff6d951SJohn Birrell if (enp->dn_kind == DT_NODE_IDENT ||
3676ff6d951SJohn Birrell enp->dn_kind == DT_NODE_STRING) {
3686ff6d951SJohn Birrell (void) strcat(s, enp->dn_string);
3696ff6d951SJohn Birrell (void) strcat(s, " ");
3706ff6d951SJohn Birrell }
3716ff6d951SJohn Birrell }
3726ff6d951SJohn Birrell
3736ff6d951SJohn Birrell xyerror(D_PRAGERR, "#%s: %s\n", prname, s);
3746ff6d951SJohn Birrell }
3756ff6d951SJohn Birrell
3766ff6d951SJohn Birrell /*ARGSUSED*/
3776ff6d951SJohn Birrell static void
dt_pragma_ident(const char * prname,dt_node_t * dnp)3786ff6d951SJohn Birrell dt_pragma_ident(const char *prname, dt_node_t *dnp)
3796ff6d951SJohn Birrell {
3806ff6d951SJohn Birrell /* ignore any #ident or #pragma ident lines */
3816ff6d951SJohn Birrell }
3826ff6d951SJohn Birrell
3836ff6d951SJohn Birrell static void
dt_pragma_option(const char * prname,dt_node_t * dnp)3846ff6d951SJohn Birrell dt_pragma_option(const char *prname, dt_node_t *dnp)
3856ff6d951SJohn Birrell {
3866ff6d951SJohn Birrell dtrace_hdl_t *dtp = yypcb->pcb_hdl;
3876ff6d951SJohn Birrell char *opt, *val;
3886ff6d951SJohn Birrell
3896ff6d951SJohn Birrell if (dnp == NULL || dnp->dn_kind != DT_NODE_IDENT) {
3906ff6d951SJohn Birrell xyerror(D_PRAGMA_MALFORM,
3916ff6d951SJohn Birrell "malformed #pragma %s <option>=<val>\n", prname);
3926ff6d951SJohn Birrell }
3936ff6d951SJohn Birrell
3946ff6d951SJohn Birrell if (dnp->dn_list != NULL) {
3956ff6d951SJohn Birrell xyerror(D_PRAGMA_MALFORM,
3966ff6d951SJohn Birrell "superfluous arguments specified for #pragma %s\n", prname);
3976ff6d951SJohn Birrell }
3986ff6d951SJohn Birrell
3996ff6d951SJohn Birrell opt = alloca(strlen(dnp->dn_string) + 1);
4006ff6d951SJohn Birrell (void) strcpy(opt, dnp->dn_string);
4016ff6d951SJohn Birrell
4026ff6d951SJohn Birrell if ((val = strchr(opt, '=')) != NULL)
4036ff6d951SJohn Birrell *val++ = '\0';
4046ff6d951SJohn Birrell
4056ff6d951SJohn Birrell if (dtrace_setopt(dtp, opt, val) == -1) {
4066ff6d951SJohn Birrell if (val == NULL) {
4076ff6d951SJohn Birrell xyerror(D_PRAGMA_OPTSET,
4086ff6d951SJohn Birrell "failed to set option '%s': %s\n", opt,
4096ff6d951SJohn Birrell dtrace_errmsg(dtp, dtrace_errno(dtp)));
4106ff6d951SJohn Birrell } else {
4116ff6d951SJohn Birrell xyerror(D_PRAGMA_OPTSET,
4126ff6d951SJohn Birrell "failed to set option '%s' to '%s': %s\n",
4136ff6d951SJohn Birrell opt, val, dtrace_errmsg(dtp, dtrace_errno(dtp)));
4146ff6d951SJohn Birrell }
4156ff6d951SJohn Birrell }
4166ff6d951SJohn Birrell }
4176ff6d951SJohn Birrell
4186ff6d951SJohn Birrell /*
4196ff6d951SJohn Birrell * The #line directive is used to reset the input line number and to optionally
4206ff6d951SJohn Birrell * note the file name for use in error messages. Sun cpp(1) also produces a
4216ff6d951SJohn Birrell * third integer token after the filename which is one of the following:
4226ff6d951SJohn Birrell *
4236ff6d951SJohn Birrell * 0 - line change has nothing to do with an #include file
4246ff6d951SJohn Birrell * 1 - line change because we just entered a #include file
4256ff6d951SJohn Birrell * 2 - line change because we just exited a #include file
4266ff6d951SJohn Birrell *
4276ff6d951SJohn Birrell * We use these state tokens to adjust pcb_idepth, which in turn controls
4286ff6d951SJohn Birrell * whether type lookups access the global type space or not.
4296ff6d951SJohn Birrell */
4306ff6d951SJohn Birrell static void
dt_pragma_line(const char * prname,dt_node_t * dnp)4316ff6d951SJohn Birrell dt_pragma_line(const char *prname, dt_node_t *dnp)
4326ff6d951SJohn Birrell {
4336ff6d951SJohn Birrell dt_node_t *fnp = dnp ? dnp->dn_list : NULL;
4346ff6d951SJohn Birrell dt_node_t *inp = fnp ? fnp->dn_list : NULL;
4356ff6d951SJohn Birrell
4366ff6d951SJohn Birrell if ((dnp == NULL || dnp->dn_kind != DT_NODE_INT) ||
4376ff6d951SJohn Birrell (fnp != NULL && fnp->dn_kind != DT_NODE_STRING) ||
4386ff6d951SJohn Birrell (inp != NULL && inp->dn_kind != DT_NODE_INT)) {
4396ff6d951SJohn Birrell xyerror(D_PRAGMA_MALFORM, "malformed #%s "
4406ff6d951SJohn Birrell "<line> [ [\"file\"] state ]\n", prname);
4416ff6d951SJohn Birrell }
4426ff6d951SJohn Birrell
4436ff6d951SJohn Birrell /*
4446ff6d951SJohn Birrell * If a file is specified, free any old pcb_filetag and swap fnp's
4456ff6d951SJohn Birrell * dn_string into pcb_filetag as the new filename for error messages.
4466ff6d951SJohn Birrell */
4476ff6d951SJohn Birrell if (fnp != NULL) {
4486ff6d951SJohn Birrell if (yypcb->pcb_filetag != NULL)
4496ff6d951SJohn Birrell free(yypcb->pcb_filetag);
4506ff6d951SJohn Birrell
4516ff6d951SJohn Birrell /*
4526ff6d951SJohn Birrell * This is not pretty, but is a necessary evil until we either
4536ff6d951SJohn Birrell * write "dpp" or get a useful standalone cpp from DevPro. If
4546ff6d951SJohn Birrell * the filename begins with /dev/fd, we know it's the master
4556ff6d951SJohn Birrell * input file (see dt_preproc() in dt_cc.c), so just clear the
4566ff6d951SJohn Birrell * dt_filetag pointer so error messages refer to the main file.
4576ff6d951SJohn Birrell */
4586ff6d951SJohn Birrell if (strncmp(fnp->dn_string, "/dev/fd/", 8) != 0) {
4596ff6d951SJohn Birrell yypcb->pcb_filetag = fnp->dn_string;
4606ff6d951SJohn Birrell fnp->dn_string = NULL;
4616ff6d951SJohn Birrell } else
4626ff6d951SJohn Birrell yypcb->pcb_filetag = NULL;
4636ff6d951SJohn Birrell }
4646ff6d951SJohn Birrell
4656ff6d951SJohn Birrell if (inp != NULL) {
4666ff6d951SJohn Birrell if (inp->dn_value == 1)
4676ff6d951SJohn Birrell yypcb->pcb_idepth++;
4686ff6d951SJohn Birrell else if (inp->dn_value == 2 && yypcb->pcb_idepth != 0)
4696ff6d951SJohn Birrell yypcb->pcb_idepth--;
4706ff6d951SJohn Birrell }
4716ff6d951SJohn Birrell
4726ff6d951SJohn Birrell yylineno = dnp->dn_value;
4736ff6d951SJohn Birrell }
4746ff6d951SJohn Birrell
4756ff6d951SJohn Birrell /*
4766ff6d951SJohn Birrell * D compiler pragma types range from control directives to common pragmas to
4776ff6d951SJohn Birrell * D custom pragmas, in order of specificity. Similar to gcc, we use #pragma D
4786ff6d951SJohn Birrell * as a special prefix for our pragmas so they can be used in mixed headers.
4796ff6d951SJohn Birrell */
4806ff6d951SJohn Birrell #define DT_PRAGMA_DIR 0 /* pragma directive may be used after naked # */
4816ff6d951SJohn Birrell #define DT_PRAGMA_SUB 1 /* pragma directive may be used after #pragma */
4826ff6d951SJohn Birrell #define DT_PRAGMA_DCP 2 /* pragma may only be used after #pragma D */
4836ff6d951SJohn Birrell
4846ff6d951SJohn Birrell static const struct dt_pragmadesc {
4856ff6d951SJohn Birrell const char *dpd_name;
4866ff6d951SJohn Birrell void (*dpd_func)(const char *, dt_node_t *);
4876ff6d951SJohn Birrell int dpd_kind;
4886ff6d951SJohn Birrell } dt_pragmas[] = {
4896ff6d951SJohn Birrell { "attributes", dt_pragma_attributes, DT_PRAGMA_DCP },
4906ff6d951SJohn Birrell { "binding", dt_pragma_binding, DT_PRAGMA_DCP },
4916ff6d951SJohn Birrell { "depends_on", dt_pragma_depends, DT_PRAGMA_DCP },
4926ff6d951SJohn Birrell { "error", dt_pragma_error, DT_PRAGMA_DIR },
4936ff6d951SJohn Birrell { "ident", dt_pragma_ident, DT_PRAGMA_DIR },
4946ff6d951SJohn Birrell { "line", dt_pragma_line, DT_PRAGMA_DIR },
4956ff6d951SJohn Birrell { "option", dt_pragma_option, DT_PRAGMA_DCP },
4966ff6d951SJohn Birrell { NULL, NULL }
4976ff6d951SJohn Birrell };
4986ff6d951SJohn Birrell
4996ff6d951SJohn Birrell /*
5006ff6d951SJohn Birrell * Process a control line #directive by looking up the directive name in our
5016ff6d951SJohn Birrell * lookup table and invoking the corresponding function with the token list.
5026ff6d951SJohn Birrell * According to K&R[A12.9], we silently ignore null directive lines.
5036ff6d951SJohn Birrell */
5046ff6d951SJohn Birrell void
dt_pragma(dt_node_t * pnp)5056ff6d951SJohn Birrell dt_pragma(dt_node_t *pnp)
5066ff6d951SJohn Birrell {
5076ff6d951SJohn Birrell const struct dt_pragmadesc *dpd;
5086ff6d951SJohn Birrell dt_node_t *dnp;
5096ff6d951SJohn Birrell int kind = DT_PRAGMA_DIR;
5106ff6d951SJohn Birrell
5116ff6d951SJohn Birrell for (dnp = pnp; dnp != NULL; dnp = dnp->dn_list) {
5126ff6d951SJohn Birrell if (dnp->dn_kind == DT_NODE_INT) {
5136ff6d951SJohn Birrell dt_pragma_line("line", dnp);
5146ff6d951SJohn Birrell break;
5156ff6d951SJohn Birrell }
5166ff6d951SJohn Birrell
5176ff6d951SJohn Birrell if (dnp->dn_kind != DT_NODE_IDENT)
5186ff6d951SJohn Birrell xyerror(D_PRAGCTL_INVAL, "invalid control directive\n");
5196ff6d951SJohn Birrell
5206ff6d951SJohn Birrell if (kind == DT_PRAGMA_DIR &&
5216ff6d951SJohn Birrell strcmp(dnp->dn_string, "pragma") == 0) {
5226ff6d951SJohn Birrell kind = DT_PRAGMA_SUB;
5236ff6d951SJohn Birrell continue;
5246ff6d951SJohn Birrell }
5256ff6d951SJohn Birrell
5266ff6d951SJohn Birrell if (kind == DT_PRAGMA_SUB &&
5276ff6d951SJohn Birrell strcmp(dnp->dn_string, "D") == 0) {
5286ff6d951SJohn Birrell kind = DT_PRAGMA_DCP;
5296ff6d951SJohn Birrell continue;
5306ff6d951SJohn Birrell }
5316ff6d951SJohn Birrell
5326ff6d951SJohn Birrell for (dpd = dt_pragmas; dpd->dpd_name != NULL; dpd++) {
5336ff6d951SJohn Birrell if (dpd->dpd_kind <= kind &&
5346ff6d951SJohn Birrell strcmp(dpd->dpd_name, dnp->dn_string) == 0)
5356ff6d951SJohn Birrell break;
5366ff6d951SJohn Birrell }
5376ff6d951SJohn Birrell
5386ff6d951SJohn Birrell yylineno--; /* since we've already seen \n */
5396ff6d951SJohn Birrell
5406ff6d951SJohn Birrell if (dpd->dpd_name != NULL) {
5416ff6d951SJohn Birrell dpd->dpd_func(dpd->dpd_name, dnp->dn_list);
5426ff6d951SJohn Birrell yylineno++;
5436ff6d951SJohn Birrell break;
5446ff6d951SJohn Birrell }
5456ff6d951SJohn Birrell
5466ff6d951SJohn Birrell switch (kind) {
5476ff6d951SJohn Birrell case DT_PRAGMA_DIR:
5486ff6d951SJohn Birrell xyerror(D_PRAGCTL_INVAL, "invalid control directive: "
5496ff6d951SJohn Birrell "#%s\n", dnp->dn_string);
5506ff6d951SJohn Birrell /*NOTREACHED*/
5516ff6d951SJohn Birrell case DT_PRAGMA_SUB:
5526ff6d951SJohn Birrell break; /* K&R[A12.8] says to ignore unknown pragmas */
5536ff6d951SJohn Birrell case DT_PRAGMA_DCP:
5546ff6d951SJohn Birrell default:
5556ff6d951SJohn Birrell xyerror(D_PRAGMA_INVAL, "invalid D pragma: %s\n",
5566ff6d951SJohn Birrell dnp->dn_string);
5576ff6d951SJohn Birrell }
5586ff6d951SJohn Birrell
5596ff6d951SJohn Birrell yylineno++;
5606ff6d951SJohn Birrell break;
5616ff6d951SJohn Birrell }
5626ff6d951SJohn Birrell
5636ff6d951SJohn Birrell dt_node_list_free(&pnp);
5646ff6d951SJohn Birrell }
565