Exemplo n.º 1
0
/*
 * The #pragma depends_on directive can be used to express a dependency on a
 * module, provider or library which if not present will cause processing to
 * abort.
 */
static void
dt_pragma_depends(const char *prname, dt_node_t *cnp)
{
	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
	dt_node_t *nnp = cnp ? cnp->dn_list : NULL;
	int found;
	dt_lib_depend_t *dld;

	if (cnp == NULL || nnp == NULL ||
	    cnp->dn_kind != DT_NODE_IDENT || nnp->dn_kind != DT_NODE_IDENT) {
		xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s "
		    "<class> <name>\n", prname);
	}

	if (strcmp(cnp->dn_string, "provider") == 0)
		found = dt_provider_lookup(dtp, nnp->dn_string) != NULL;
	else if (strcmp(cnp->dn_string, "module") == 0) {
		dt_module_t *mp = dt_module_lookup_by_name(dtp, nnp->dn_string);
		found = mp != NULL && dt_module_getctf(dtp, mp) != NULL;
	} else if (strcmp(cnp->dn_string, "library") == 0) {

		/*
		 * We have the file we are working on in dtp->dt_filetag
		 * so find that node and add the dependency in.
		 */
		if (yypcb->pcb_cflags & DTRACE_C_CTL) {
			char lib[MAXPATHLEN];

			dld = dt_lib_depend_lookup(&dtp->dt_lib_dep,
			    dtp->dt_filetag);
			assert(dld != NULL);

			(void) snprintf(lib, MAXPATHLEN, "%s%s",
			    dld->dtld_libpath, nnp->dn_string);
			if ((dt_lib_depend_add(dtp, &dld->dtld_dependencies,
			    lib)) != 0) {
				xyerror(D_PRAGMA_DEPEND,
				    "failed to add dependency %s:%s\n",
				    lib,
				    dtrace_errmsg(dtp, dtrace_errno(dtp)));
			}
		}
		found = 1;
	} else {
		xyerror(D_PRAGMA_INVAL, "invalid class %s "
		    "specified by #pragma %s\n", cnp->dn_string, prname);
	}

	if (!found) {
		xyerror(D_PRAGMA_DEPEND, "program requires %s %s\n",
		    cnp->dn_string, nnp->dn_string);
	}
}
Exemplo n.º 2
0
dt_probe_t *
dt_probe_info(dtrace_hdl_t *dtp,
    const dtrace_probedesc_t *pdp, dtrace_probeinfo_t *pip)
{
	int m_is_glob = pdp->dtpd_mod[0] == '\0' || strisglob(pdp->dtpd_mod);
	int f_is_glob = pdp->dtpd_func[0] == '\0' || strisglob(pdp->dtpd_func);
	int n_is_glob = pdp->dtpd_name[0] == '\0' || strisglob(pdp->dtpd_name);

	dt_probe_t *prp = NULL;
	const dtrace_pattr_t *pap;
	dt_provider_t *pvp;
	dt_ident_t *idp;

	/*
	 * Attempt to lookup the probe in our existing cache for this provider.
	 * If none is found and an explicit probe ID was specified, discover
	 * that specific probe and cache its description and arguments.
	 */
	if ((pvp = dt_provider_lookup(dtp, pdp->dtpd_provider)) != NULL) {
		size_t keylen = dt_probe_keylen(pdp);
		char *key = dt_probe_key(pdp, alloca(keylen));

		if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL)
			prp = idp->di_data;
		else if (pdp->dtpd_id != DTRACE_IDNONE)
			prp = dt_probe_discover(pvp, pdp);
	}

	/*
	 * If no probe was found in our cache, convert the caller's partial
	 * probe description into a fully-formed matching probe description by
	 * iterating over up to at most two probes that match 'pdp'.  We then
	 * call dt_probe_discover() on the resulting probe identifier.
	 */
	if (prp == NULL) {
		dtrace_probedesc_t pd;
		int m;

		bzero(&pd, sizeof (pd));
		pd.dtpd_id = DTRACE_IDNONE;

		/*
		 * Call dtrace_probe_iter() to find matching probes.  Our
		 * dt_probe_desc() callback will produce the following results:
		 *
		 * m < 0 dtrace_probe_iter() found zero matches (or failed).
		 * m > 0 dtrace_probe_iter() found more than one match.
		 * m = 0 dtrace_probe_iter() found exactly one match.
		 */
		if ((m = dtrace_probe_iter(dtp, pdp, dt_probe_desc, &pd)) < 0)
			return (NULL); /* dt_errno is set for us */

		if ((pvp = dt_provider_lookup(dtp, pd.dtpd_provider)) == NULL)
			return (NULL); /* dt_errno is set for us */

		/*
		 * If more than one probe was matched, then do not report probe
		 * information if either of the following conditions is true:
		 *
		 * (a) The Arguments Data stability of the matched provider is
		 *	less than Evolving.
		 *
		 * (b) Any description component that is at least Evolving is
		 *	empty or is specified using a globbing expression.
		 *
		 * These conditions imply that providers that provide Evolving
		 * or better Arguments Data stability must guarantee that all
		 * probes with identical field names in a field of Evolving or
		 * better Name stability have identical argument signatures.
		 */
		if (m > 0) {
			if (pvp->pv_desc.dtvd_attr.dtpa_args.dtat_data <
			    DTRACE_STABILITY_EVOLVING) {
				(void) dt_set_errno(dtp, EDT_UNSTABLE);
				return (NULL);
			}


			if (pvp->pv_desc.dtvd_attr.dtpa_mod.dtat_name >=
			    DTRACE_STABILITY_EVOLVING && m_is_glob) {
				(void) dt_set_errno(dtp, EDT_UNSTABLE);
				return (NULL);
			}

			if (pvp->pv_desc.dtvd_attr.dtpa_func.dtat_name >=
			    DTRACE_STABILITY_EVOLVING && f_is_glob) {
				(void) dt_set_errno(dtp, EDT_UNSTABLE);
				return (NULL);
			}

			if (pvp->pv_desc.dtvd_attr.dtpa_name.dtat_name >=
			    DTRACE_STABILITY_EVOLVING && n_is_glob) {
				(void) dt_set_errno(dtp, EDT_UNSTABLE);
				return (NULL);
			}
		}

		/*
		 * If we matched a probe exported by dtrace(7D), then discover
		 * the real attributes.  Otherwise grab the static declaration.
		 */
		if (pd.dtpd_id != DTRACE_IDNONE)
			prp = dt_probe_discover(pvp, &pd);
		else
			prp = dt_probe_lookup(pvp, pd.dtpd_name);

		if (prp == NULL)
			return (NULL); /* dt_errno is set for us */
	}

	assert(pvp != NULL && prp != NULL);

	/*
	 * Compute the probe description attributes by taking the minimum of
	 * the attributes of the specified fields.  If no provider is specified
	 * or a glob pattern is used for the provider, use Unstable attributes.
	 */
	if (pdp->dtpd_provider[0] == '\0' || strisglob(pdp->dtpd_provider))
		pap = &_dtrace_prvdesc;
	else
		pap = &pvp->pv_desc.dtvd_attr;

	pip->dtp_attr = pap->dtpa_provider;

	if (!m_is_glob)
		pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_mod);
	if (!f_is_glob)
		pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_func);
	if (!n_is_glob)
		pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_name);

	pip->dtp_arga = pap->dtpa_args;
	pip->dtp_argv = prp->pr_argv;
	pip->dtp_argc = prp->pr_argc;

	return (prp);
}
Exemplo n.º 3
0
/*
 * The #pragma attributes directive can be used to reset stability attributes
 * on a global identifier or inline definition.  If the identifier is already
 * defined, we can just change di_attr.  If not, we insert the pragma into a
 * hash table of the current pcb's deferred pragmas for later processing.
 */
static void
dt_pragma_attributes(const char *prname, dt_node_t *dnp)
{
	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
	dtrace_attribute_t attr, *a;
	dt_provider_t *pvp;
	const char *name, *part;
	dt_ident_t *idp;

	if (dnp == NULL || dnp->dn_kind != DT_NODE_IDENT ||
	    dnp->dn_list == NULL || dnp->dn_list->dn_kind != DT_NODE_IDENT) {
		xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s "
		    "<attributes> <ident>\n", prname);
	}

	if (dtrace_str2attr(dnp->dn_string, &attr) == -1) {
		xyerror(D_PRAGMA_INVAL, "invalid attributes "
		    "specified by #pragma %s\n", prname);
	}

	dnp = dnp->dn_list;
	name = dnp->dn_string;

	if (strcmp(name, "provider") == 0) {
		dnp = dnp->dn_list;
		name = dnp->dn_string;

		dnp = dnp->dn_list;
		part = dnp->dn_string;

		if ((pvp = dt_provider_lookup(dtp, name)) != NULL) {
			if (strcmp(part, "provider") == 0) {
				a = &pvp->pv_desc.dtvd_attr.dtpa_provider;
			} else if (strcmp(part, "module") == 0) {
				a = &pvp->pv_desc.dtvd_attr.dtpa_mod;
			} else if (strcmp(part, "function") == 0) {
				a = &pvp->pv_desc.dtvd_attr.dtpa_func;
			} else if (strcmp(part, "name") == 0) {
				a = &pvp->pv_desc.dtvd_attr.dtpa_name;
			} else if (strcmp(part, "args") == 0) {
				a = &pvp->pv_desc.dtvd_attr.dtpa_args;
			} else {
				xyerror(D_PRAGMA_INVAL, "invalid component "
				    "\"%s\" in attribute #pragma "
				    "for provider %s\n", name, part);
			}

			*a = attr;
			return;
		}

	} else if ((idp = dt_idstack_lookup(
	    &yypcb->pcb_globals, name)) != NULL) {

		if (idp->di_gen != dtp->dt_gen) {
			xyerror(D_PRAGMA_SCOPE, "#pragma %s cannot modify "
			    "entity defined outside program scope\n", prname);
		}

		idp->di_attr = attr;
		return;
	}

	if (yypcb->pcb_pragmas == NULL && (yypcb->pcb_pragmas =
	    dt_idhash_create("pragma", NULL, 0, 0)) == NULL)
		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);

	idp = dt_idhash_insert(yypcb->pcb_pragmas, name, DT_IDENT_PRAGAT, 0, 0,
	    attr, 0, &dt_idops_thaw, (void *)prname, dtp->dt_gen);

	if (idp == NULL)
		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);

	if (dtp->dt_globals->dh_defer == NULL)
		dtp->dt_globals->dh_defer = &dt_pragma_apply;
}
Exemplo n.º 4
0
/*
 * The #pragma depends_on directive can be used to express a dependency on a
 * module, provider or library which if not present will cause processing to
 * abort.
 */
static void
dt_pragma_depends(const char *prname, dt_node_t *cnp)
{
	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
	dt_node_t *nnp = cnp ? cnp->dn_list : NULL;
	int found;
	dt_lib_depend_t *dld;
	char lib[MAXPATHLEN];
	size_t plen;
	char *provs, *cpy, *tok;

	if (cnp == NULL || nnp == NULL ||
	    cnp->dn_kind != DT_NODE_IDENT || nnp->dn_kind != DT_NODE_IDENT) {
		xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s "
		    "<class> <name>\n", prname);
	}

	if (strcmp(cnp->dn_string, "provider") == 0) {
		/*
		 * First try to get the provider list using the
		 * debug.dtrace.providers sysctl, since that'll work even if
		 * we're not running as root.
		 */
		provs = NULL;
		if (sysctlbyname("debug.dtrace.providers", NULL, &plen, NULL, 0) ||
		    ((provs = dt_alloc(dtp, plen)) == NULL) ||
		    sysctlbyname("debug.dtrace.providers", provs, &plen, NULL, 0))
			found = dt_provider_lookup(dtp, nnp->dn_string) != NULL;
		else {
			found = B_FALSE;
			for (cpy = provs; (tok = strsep(&cpy, " ")) != NULL; )
				if (strcmp(tok, nnp->dn_string) == 0) {
					found = B_TRUE;
					break;
				}
			if (found == B_FALSE)
				found = dt_provider_lookup(dtp,
				    nnp->dn_string) != NULL;
		}
		if (provs != NULL)
			dt_free(dtp, provs);
	} else if (strcmp(cnp->dn_string, "module") == 0) {
		dt_module_t *mp = dt_module_lookup_by_name(dtp, nnp->dn_string);
		found = mp != NULL && dt_module_getctf(dtp, mp) != NULL;
	} else if (strcmp(cnp->dn_string, "library") == 0) {
		if (yypcb->pcb_cflags & DTRACE_C_CTL) {
			assert(dtp->dt_filetag != NULL);

			dt_pragma_depends_finddep(dtp, nnp->dn_string, lib,
			    sizeof (lib));

			dld = dt_lib_depend_lookup(&dtp->dt_lib_dep,
			    dtp->dt_filetag);
			assert(dld != NULL);

			if ((dt_lib_depend_add(dtp, &dld->dtld_dependencies,
			    lib)) != 0) {
				xyerror(D_PRAGMA_DEPEND,
				    "failed to add dependency %s:%s\n", lib,
				    dtrace_errmsg(dtp, dtrace_errno(dtp)));
			}
		} else {
			/*
			 * By this point we have already performed a topological
			 * sort of the dependencies; we process this directive
			 * as satisfied as long as the dependency was properly
			 * loaded.
			 */
			if (dtp->dt_filetag == NULL)
				xyerror(D_PRAGMA_DEPEND, "main program may "
				    "not explicitly depend on a library");

			dld = dt_lib_depend_lookup(&dtp->dt_lib_dep,
			    dtp->dt_filetag);
			assert(dld != NULL);

			dt_pragma_depends_finddep(dtp, nnp->dn_string, lib,
			    sizeof (lib));
			dld = dt_lib_depend_lookup(&dtp->dt_lib_dep_sorted,
			    lib);
			assert(dld != NULL);

			if (!dld->dtld_loaded)
				xyerror(D_PRAGMA_DEPEND, "program requires "
				    "library \"%s\" which failed to load",
				    lib);
		}

		found = B_TRUE;
	} else {
		xyerror(D_PRAGMA_INVAL, "invalid class %s "
		    "specified by #pragma %s\n", cnp->dn_string, prname);
	}

	if (!found) {
		xyerror(D_PRAGMA_DEPEND, "program requires %s %s\n",
		    cnp->dn_string, nnp->dn_string);
	}
}