Example #1
0
static void
dt_idcook_regs(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap)
{
	dtrace_typeinfo_t dtt;
	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
	char n[DT_TYPE_NAMELEN];

	if (argc != 1) {
		xyerror(D_PROTO_LEN, "%s[ ] prototype mismatch: %d arg%s"
		    "passed, 1 expected\n", idp->di_name,
		    argc, argc == 1 ? " " : "s ");
	}

	if (ap->dn_kind != DT_NODE_INT) {
		xyerror(D_PROTO_ARG, "%s[ ] argument #1 is incompatible with "
		    "prototype:\n\tprototype: %s\n\t argument: %s\n",
		    idp->di_name, "integer constant",
		    dt_type_name(ap->dn_ctfp, ap->dn_type, n, sizeof (n)));
	}

	if ((ap->dn_flags & DT_NF_SIGNED) && (int64_t)ap->dn_value < 0) {
		xyerror(D_REGS_IDX, "index %lld is out of range for array %s\n",
		    (longlong_t)ap->dn_value, idp->di_name);
	}

	if (dt_type_lookup("uint64_t", &dtt) == -1) {
		xyerror(D_UNKNOWN, "failed to resolve type of %s: %s\n",
		    idp->di_name, dtrace_errmsg(dtp, dtrace_errno(dtp)));
	}

	idp->di_ctfp = dtt.dtt_ctfp;
	idp->di_type = dtt.dtt_type;

	dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
}
Example #2
0
static void
dt_pragma_option(const char *prname, dt_node_t *dnp)
{
	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
	char *opt, *val;

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

	if (dnp->dn_list != NULL) {
		xyerror(D_PRAGMA_MALFORM,
		    "superfluous arguments specified for #pragma %s\n", prname);
	}

	opt = alloca(strlen(dnp->dn_string) + 1);
	(void) strcpy(opt, dnp->dn_string);

	if ((val = strchr(opt, '=')) != NULL)
		*val++ = '\0';

	if (dtrace_setopt(dtp, opt, val) == -1) {
		if (val == NULL) {
			xyerror(D_PRAGMA_OPTSET,
			    "failed to set option '%s': %s\n", opt,
			    dtrace_errmsg(dtp, dtrace_errno(dtp)));
		} else {
			xyerror(D_PRAGMA_OPTSET,
			    "failed to set option '%s' to '%s': %s\n",
			    opt, val, dtrace_errmsg(dtp, dtrace_errno(dtp)));
		}
	}
}
Example #3
0
static dt_decl_t *
dt_decl_check(dt_decl_t *ddp)
{
	if (ddp->dd_kind == CTF_K_UNKNOWN)
		return (ddp); /* nothing to check if the type is not yet set */

	if (ddp->dd_name != NULL && strcmp(ddp->dd_name, "char") == 0 &&
	    (ddp->dd_attr & (DT_DA_SHORT | DT_DA_LONG | DT_DA_LONGLONG))) {
		xyerror(D_DECL_CHARATTR, "invalid type declaration: short and "
		    "long may not be used with char type\n");
	}

	if (ddp->dd_name != NULL && strcmp(ddp->dd_name, "void") == 0 &&
	    (ddp->dd_attr & (DT_DA_SHORT | DT_DA_LONG | DT_DA_LONGLONG |
	    (DT_DA_SIGNED | DT_DA_UNSIGNED)))) {
		xyerror(D_DECL_VOIDATTR, "invalid type declaration: attributes "
		    "may not be used with void type\n");
	}

	if (ddp->dd_kind != CTF_K_INTEGER &&
	    (ddp->dd_attr & (DT_DA_SIGNED | DT_DA_UNSIGNED))) {
		xyerror(D_DECL_SIGNINT, "invalid type declaration: signed and "
		    "unsigned may only be used with integer type\n");
	}

	if (ddp->dd_kind != CTF_K_INTEGER && ddp->dd_kind != CTF_K_FLOAT &&
	    (ddp->dd_attr & (DT_DA_LONG | DT_DA_LONGLONG))) {
		xyerror(D_DECL_LONGINT, "invalid type declaration: long and "
		    "long long may only be used with integer or "
		    "floating-point type\n");
	}

	return (ddp);
}
Example #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;

	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);
	}
}
Example #5
0
/*
 * Common code for cooking an identifier that uses a typed signature list (we
 * use this for associative arrays and functions).  If the argument list is
 * of the same length and types, then return the return type.  Otherwise
 * print an appropriate compiler error message and abort the compile.
 */
static void
dt_idcook_sign(dt_node_t *dnp, dt_ident_t *idp,
    int argc, dt_node_t *args, const char *prefix, const char *suffix)
{
	dt_idsig_t *isp = idp->di_data;
	int i, compat, mismatch, arglimit, iskey;

	char n1[DT_TYPE_NAMELEN];
	char n2[DT_TYPE_NAMELEN];

	iskey = idp->di_kind == DT_IDENT_ARRAY || idp->di_kind == DT_IDENT_AGG;

	if (isp->dis_varargs >= 0) {
		mismatch = argc < isp->dis_varargs;
		arglimit = isp->dis_varargs;
	} else if (isp->dis_optargs >= 0) {
		mismatch = (argc < isp->dis_optargs || argc > isp->dis_argc);
		arglimit = argc;
	} else {
		mismatch = argc != isp->dis_argc;
		arglimit = isp->dis_argc;
	}

	if (mismatch) {
		xyerror(D_PROTO_LEN, "%s%s%s prototype mismatch: %d %s%s"
		    "passed, %s%d expected\n", prefix, idp->di_name, suffix,
		    argc, iskey ? "key" : "arg", argc == 1 ? " " : "s ",
		    isp->dis_optargs >= 0 ? "at least " : "",
		    isp->dis_optargs >= 0 ? isp->dis_optargs : arglimit);
	}

	for (i = 0; i < arglimit; i++, args = args->dn_list) {
		if (isp->dis_args[i].dn_ctfp != NULL)
			compat = dt_node_is_argcompat(&isp->dis_args[i], args);
		else
			compat = 1; /* "@" matches any type */

		if (!compat) {
			xyerror(D_PROTO_ARG,
			    "%s%s%s %s #%d is incompatible with "
			    "prototype:\n\tprototype: %s\n\t%9s: %s\n",
			    prefix, idp->di_name, suffix,
			    iskey ? "key" : "argument", i + 1,
			    dt_node_type_name(&isp->dis_args[i], n1,
			    sizeof (n1)),
			    iskey ? "key" : "argument",
			    dt_node_type_name(args, n2, sizeof (n2)));
		}
	}

	dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
}
Example #6
0
/*
 * The #pragma error directive can be followed by any list of tokens, which we
 * just concatenate and print as part of our error message.
 */
static void
dt_pragma_error(const char *prname, dt_node_t *dnp)
{
	dt_node_t *enp;
	size_t n = 0;
	char *s;

	for (enp = dnp; enp != NULL; enp = enp->dn_list) {
		if (enp->dn_kind == DT_NODE_IDENT ||
		    enp->dn_kind == DT_NODE_STRING)
			n += strlen(enp->dn_string) + 1;
	}

	s = alloca(n + 1);
	s[0] = '\0';

	for (enp = dnp; enp != NULL; enp = enp->dn_list) {
		if (enp->dn_kind == DT_NODE_IDENT ||
		    enp->dn_kind == DT_NODE_STRING) {
			(void) strcat(s, enp->dn_string);
			(void) strcat(s, " ");
		}
	}

	xyerror(D_PRAGERR, "#%s: %s\n", prname, s);
}
Example #7
0
/*
 * Cook an associative array identifier.  If this is the first time we are
 * cooking this array, create its signature based on the argument list.
 * Otherwise validate the argument list against the existing signature.
 */
static void
dt_idcook_assc(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
{
	if (idp->di_data == NULL) {
		dt_idsig_t *isp = idp->di_data = malloc(sizeof (dt_idsig_t));
		char n[DT_TYPE_NAMELEN];
		int i;

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

		isp->dis_varargs = -1;
		isp->dis_optargs = -1;
		isp->dis_argc = argc;
		isp->dis_args = NULL;
		isp->dis_auxinfo = 0;

		if (argc != 0 && (isp->dis_args = calloc(argc,
		    sizeof (dt_node_t))) == NULL) {
			idp->di_data = NULL;
			free(isp);
			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
		}

		/*
		 * If this identifier has not been explicitly declared earlier,
		 * set the identifier's base type to be our special type <DYN>.
		 * If this ident is an aggregation, it will remain as is.  If
		 * this ident is an associative array, it will be reassigned
		 * based on the result type of the first assignment statement.
		 */
		if (!(idp->di_flags & DT_IDFLG_DECL)) {
			idp->di_ctfp = DT_DYN_CTFP(yypcb->pcb_hdl);
			idp->di_type = DT_DYN_TYPE(yypcb->pcb_hdl);
		}

		for (i = 0; i < argc; i++, args = args->dn_list) {
			if (dt_node_is_dynamic(args) || dt_node_is_void(args)) {
				xyerror(D_KEY_TYPE, "%s expression may not be "
				    "used as %s index: key #%d\n",
				    dt_node_type_name(args, n, sizeof (n)),
				    dt_idkind_name(idp->di_kind), i + 1);
			}

			dt_node_type_propagate(args, &isp->dis_args[i]);
			isp->dis_args[i].dn_list = &isp->dis_args[i + 1];
		}

		if (argc != 0)
			isp->dis_args[argc - 1].dn_list = NULL;

		dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);

	} else {
		dt_idcook_sign(dnp, idp, argc, args,
		    idp->di_kind == DT_IDENT_AGG ? "@" : "", "[ ]");
	}
}
Example #8
0
/*
 * The #pragma binding directive can be used to reset the version binding
 * on a global identifier or inline definition.  If the identifier is already
 * defined, we can just change di_vers.  If not, we insert the pragma into a
 * hash table of the current pcb's deferred pragmas for later processing.
 */
static void
dt_pragma_binding(const char *prname, dt_node_t *dnp)
{
	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
	dt_version_t vers;
	const char *name;
	dt_ident_t *idp;

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

	if (dt_version_str2num(dnp->dn_string, &vers) == -1) {
		xyerror(D_PRAGMA_INVAL, "invalid version string "
		    "specified by #pragma %s\n", prname);
	}

	name = dnp->dn_list->dn_string;
	idp = dt_idstack_lookup(&yypcb->pcb_globals, name);

	if (idp != 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_vers = vers;
		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_PRAGBN, 0, 0,
	    _dtrace_defattr, vers, &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;
}
Example #9
0
dt_decl_t *
dt_decl_pop_param(char **idp)
{
	dt_scope_t *dsp = &yypcb->pcb_dstack;

	if (dsp->ds_class != DT_DC_DEFAULT && dsp->ds_class != DT_DC_REGISTER) {
		xyerror(D_DECL_PARMCLASS, "inappropriate storage class "
		    "for function or associative array parameter\n");
	}

	if (idp != NULL && dt_decl_top() != NULL) {
		*idp = dsp->ds_ident;
		dsp->ds_ident = NULL;
	}

	return (dt_decl_pop());
}
Example #10
0
static void
dt_as_undef(const dt_ident_t *idp, uint_t offset)
{
	const char *kind, *mark = (idp->di_flags & DT_IDFLG_USER) ? "``" : "`";
	const dtrace_syminfo_t *dts = idp->di_data;

	if (idp->di_flags & DT_IDFLG_USER)
		kind = "user";
	else if (idp->di_flags & DT_IDFLG_PRIM)
		kind = "primary kernel";
	else
		kind = "loadable kernel";

	yylineno = idp->di_lineno;

	xyerror(D_ASRELO, "relocation remains against %s symbol %s%s%s (offset "
	    "0x%x)\n", kind, dts->dts_object, mark, dts->dts_name, offset);
}
Example #11
0
/*
 * The #line directive is used to reset the input line number and to optionally
 * note the file name for use in error messages.  Sun cpp(1) also produces a
 * third integer token after the filename which is one of the following:
 *
 * 0 - line change has nothing to do with an #include file
 * 1 - line change because we just entered a #include file
 * 2 - line change because we just exited a #include file
 *
 * We use these state tokens to adjust pcb_idepth, which in turn controls
 * whether type lookups access the global type space or not.
 */
static void
dt_pragma_line(const char *prname, dt_node_t *dnp)
{
	dt_node_t *fnp = dnp ? dnp->dn_list : NULL;
	dt_node_t *inp = fnp ? fnp->dn_list : NULL;

	if ((dnp == NULL || dnp->dn_kind != DT_NODE_INT) ||
	    (fnp != NULL && fnp->dn_kind != DT_NODE_STRING) ||
	    (inp != NULL && inp->dn_kind != DT_NODE_INT)) {
		xyerror(D_PRAGMA_MALFORM, "malformed #%s "
		    "<line> [ [\"file\"] state ]\n", prname);
	}

	/*
	 * If a file is specified, free any old pcb_filetag and swap fnp's
	 * dn_string into pcb_filetag as the new filename for error messages.
	 */
	if (fnp != NULL) {
		if (yypcb->pcb_filetag != NULL)
			free(yypcb->pcb_filetag);

		/*
		 * This is not pretty, but is a necessary evil until we either
		 * write "dpp" or get a useful standalone cpp from DevPro.  If
		 * the filename begins with /dev/fd, we know it's the master
		 * input file (see dt_preproc() in dt_cc.c), so just clear the
		 * dt_filetag pointer so error messages refer to the main file.
		 */
		if (strncmp(fnp->dn_string, "/dev/fd/", 8) != 0) {
			yypcb->pcb_filetag = fnp->dn_string;
			fnp->dn_string = NULL;
		} else
			yypcb->pcb_filetag = NULL;
	}

	if (inp != NULL) {
		if (inp->dn_value == 1)
			yypcb->pcb_idepth++;
		else if (inp->dn_value == 2 && yypcb->pcb_idepth != 0)
			yypcb->pcb_idepth--;
	}

	yylineno = dnp->dn_value;
}
Example #12
0
dt_decl_t *
dt_decl_ident(char *name)
{
	dt_scope_t *dsp = &yypcb->pcb_dstack;
	dt_decl_t *ddp = dsp->ds_decl;

	if (dsp->ds_ident != NULL) {
		free(name);
		xyerror(D_DECL_IDENT, "old-style declaration or "
		    "incorrect type specified\n");
	}

	dsp->ds_ident = name;

	if (ddp == NULL)
		ddp = dt_decl_push(dt_decl_alloc(CTF_K_UNKNOWN, NULL));

	return (ddp);
}
Example #13
0
/*ARGSUSED*/
static void
dt_idcook_type(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
{
	if (idp->di_type == CTF_ERR) {
		dtrace_hdl_t *dtp = yypcb->pcb_hdl;
		dtrace_typeinfo_t dtt;

		if (dt_type_lookup(idp->di_iarg, &dtt) == -1) {
			xyerror(D_UNKNOWN,
			    "failed to resolve type %s for identifier %s: %s\n",
			    (const char *)idp->di_iarg, idp->di_name,
			    dtrace_errmsg(dtp, dtrace_errno(dtp)));
		}

		idp->di_ctfp = dtt.dtt_ctfp;
		idp->di_type = dtt.dtt_type;
	}

	dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
}
Example #14
0
static void 
dt_pragma_depends_finddep(dtrace_hdl_t *dtp, const char *lname, char *lib,
    size_t len)
{
	dt_dirpath_t *dirp;
	struct stat sbuf;
	int found = 0;

	for (dirp = dt_list_next(&dtp->dt_lib_path); dirp != NULL;
	    dirp = dt_list_next(dirp)) {
		(void) snprintf(lib, len, "%s/%s", dirp->dir_path, lname);

		if (stat(lib, &sbuf) == 0) {
			found = 1;
			break;
		}
	}

	if (!found)
		xyerror(D_PRAGMA_DEPEND,
		    "failed to find dependency in libpath: %s", lname);
}
Example #15
0
/*
 * Lookup the dynamic translator type tag for the specified probe argument and
 * assign the type to the specified node.  If the type is not yet defined, add
 * it to the "D" module's type container as a typedef for an unknown type.
 */
dt_node_t *
dt_probe_tag(dt_probe_t *prp, uint_t argn, dt_node_t *dnp)
{
	dtrace_hdl_t *dtp = prp->pr_pvp->pv_hdl;
	dtrace_typeinfo_t dtt;
	size_t len;
	char *tag;

	len = snprintf(NULL, 0, "__dtrace_%s___%s_arg%u",
	    prp->pr_pvp->pv_desc.dtvd_name, prp->pr_name, argn);

	tag = alloca(len + 1);

	(void) snprintf(tag, len + 1, "__dtrace_%s___%s_arg%u",
	    prp->pr_pvp->pv_desc.dtvd_name, prp->pr_name, argn);

	if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_DDEFS, tag, &dtt) != 0) {
		dtt.dtt_object = DTRACE_OBJ_DDEFS;
		dtt.dtt_ctfp = DT_DYN_CTFP(dtp);
		dtt.dtt_type = ctf_add_typedef(DT_DYN_CTFP(dtp),
		    CTF_ADD_ROOT, tag, DT_DYN_TYPE(dtp));

		if (dtt.dtt_type == CTF_ERR ||
		    ctf_update(dtt.dtt_ctfp) == CTF_ERR) {
			xyerror(D_UNKNOWN, "cannot define type %s: %s\n",
			    tag, ctf_errmsg(ctf_errno(dtt.dtt_ctfp)));
		}
	}

	bzero(dnp, sizeof (dt_node_t));
	dnp->dn_kind = DT_NODE_TYPE;

	dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
	dt_node_attr_assign(dnp, _dtrace_defattr);

	return (dnp);
}
Example #16
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;
}
Example #17
0
/*
 * Process a control line #directive by looking up the directive name in our
 * lookup table and invoking the corresponding function with the token list.
 * According to K&R[A12.9], we silently ignore null directive lines.
 */
void
dt_pragma(dt_node_t *pnp)
{
	const struct dt_pragmadesc *dpd;
	dt_node_t *dnp;
	int kind = DT_PRAGMA_DIR;

	for (dnp = pnp; dnp != NULL; dnp = dnp->dn_list) {
		if (dnp->dn_kind == DT_NODE_INT) {
			dt_pragma_line("line", dnp);
			break;
		}

		if (dnp->dn_kind != DT_NODE_IDENT)
			xyerror(D_PRAGCTL_INVAL, "invalid control directive\n");

		if (kind == DT_PRAGMA_DIR &&
		    strcmp(dnp->dn_string, "pragma") == 0) {
			kind = DT_PRAGMA_SUB;
			continue;
		}

		if (kind == DT_PRAGMA_SUB &&
		    strcmp(dnp->dn_string, "D") == 0) {
			kind = DT_PRAGMA_DCP;
			continue;
		}

		for (dpd = dt_pragmas; dpd->dpd_name != NULL; dpd++) {
			if (dpd->dpd_kind <= kind &&
			    strcmp(dpd->dpd_name, dnp->dn_string) == 0)
				break;
		}

		yylineno--; /* since we've already seen \n */

		if (dpd->dpd_name != NULL) {
			dpd->dpd_func(dpd->dpd_name, dnp->dn_list);
			yylineno++;
			break;
		}

		switch (kind) {
		case DT_PRAGMA_DIR:
			xyerror(D_PRAGCTL_INVAL, "invalid control directive: "
			    "#%s\n", dnp->dn_string);
			/*NOTREACHED*/
		case DT_PRAGMA_SUB:
			break; /* K&R[A12.8] says to ignore unknown pragmas */
		case DT_PRAGMA_DCP:
		default:
			xyerror(D_PRAGMA_INVAL, "invalid D pragma: %s\n",
			    dnp->dn_string);
		}

		yylineno++;
		break;
	}

	dt_node_list_free(&pnp);
}
Example #18
0
/*
 * Cook a reference to the dynamically typed args[] array.  We verify that the
 * reference is using a single integer constant, and then construct a new ident
 * representing the appropriate type or translation specifically for this node.
 */
static void
dt_idcook_args(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap)
{
	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
	dt_probe_t *prp = yypcb->pcb_probe;

	dt_node_t tag, *nnp, *xnp;
	dt_xlator_t *dxp;
	dt_ident_t *xidp;

	char n1[DT_TYPE_NAMELEN];
	char n2[DT_TYPE_NAMELEN];

	if (argc != 1) {
		xyerror(D_PROTO_LEN, "%s[ ] prototype mismatch: %d arg%s"
		    "passed, 1 expected\n", idp->di_name, argc,
		    argc == 1 ? " " : "s ");
	}

	if (ap->dn_kind != DT_NODE_INT) {
		xyerror(D_PROTO_ARG, "%s[ ] argument #1 is incompatible with "
		    "prototype:\n\tprototype: %s\n\t argument: %s\n",
		    idp->di_name, "integer constant",
		    dt_type_name(ap->dn_ctfp, ap->dn_type, n1, sizeof (n1)));
	}

	if (yypcb->pcb_pdesc == NULL) {
		xyerror(D_ARGS_NONE, "%s[ ] may not be referenced outside "
		    "of a probe clause\n", idp->di_name);
	}

	if (prp == NULL) {
		xyerror(D_ARGS_MULTI,
		    "%s[ ] may not be referenced because probe description %s "
		    "matches an unstable set of probes\n", idp->di_name,
		    dtrace_desc2str(yypcb->pcb_pdesc, n1, sizeof (n1)));
	}

	if (ap->dn_value >= prp->pr_argc) {
		xyerror(D_ARGS_IDX, "index %lld is out of range for %s %s[ ]\n",
		    (longlong_t)ap->dn_value, dtrace_desc2str(yypcb->pcb_pdesc,
		    n1, sizeof (n1)), idp->di_name);
	}

	/*
	 * Look up the native and translated argument types for the probe.
	 * If no translation is needed, these will be the same underlying node.
	 * If translation is needed, look up the appropriate translator.  Once
	 * we have the appropriate node, create a new dt_ident_t for this node,
	 * assign it the appropriate attributes, and set the type of 'dnp'.
	 */
	xnp = prp->pr_xargv[ap->dn_value];
	nnp = prp->pr_nargv[prp->pr_mapping[ap->dn_value]];

	if (xnp->dn_type == CTF_ERR) {
		xyerror(D_ARGS_TYPE, "failed to resolve translated type for "
		    "%s[%lld]\n", idp->di_name, (longlong_t)ap->dn_value);
	}

	if (nnp->dn_type == CTF_ERR) {
		xyerror(D_ARGS_TYPE, "failed to resolve native type for "
		    "%s[%lld]\n", idp->di_name, (longlong_t)ap->dn_value);
	}

	if (dtp->dt_xlatemode == DT_XL_STATIC && (
	    nnp == xnp || dt_node_is_argcompat(nnp, xnp))) {
		dnp->dn_ident = dt_ident_create(idp->di_name, idp->di_kind,
		    idp->di_flags | DT_IDFLG_ORPHAN, idp->di_id, idp->di_attr,
		    idp->di_vers, idp->di_ops, idp->di_iarg, idp->di_gen);

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

		dt_node_type_assign(dnp,
		    prp->pr_argv[ap->dn_value].dtt_ctfp,
		    prp->pr_argv[ap->dn_value].dtt_type);

	} else if ((dxp = dt_xlator_lookup(dtp,
	    nnp, xnp, DT_XLATE_FUZZY)) != NULL || (
	    dxp = dt_xlator_lookup(dtp, dt_probe_tag(prp, ap->dn_value, &tag),
	    xnp, DT_XLATE_EXACT | DT_XLATE_EXTERN)) != NULL) {

		xidp = dt_xlator_ident(dxp, xnp->dn_ctfp, xnp->dn_type);

		dnp->dn_ident = dt_ident_create(idp->di_name, xidp->di_kind,
		    xidp->di_flags | DT_IDFLG_ORPHAN, idp->di_id, idp->di_attr,
		    idp->di_vers, idp->di_ops, idp->di_iarg, idp->di_gen);

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

		if (dt_xlator_dynamic(dxp))
			dxp->dx_arg = (int)ap->dn_value;

		/*
		 * Propagate relevant members from the translator's internal
		 * dt_ident_t.  This code must be kept in sync with the state
		 * that is initialized for idents in dt_xlator_create().
		 */
		dnp->dn_ident->di_data = xidp->di_data;
		dnp->dn_ident->di_ctfp = xidp->di_ctfp;
		dnp->dn_ident->di_type = xidp->di_type;

		dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp));

	} else {
		xyerror(D_ARGS_XLATOR, "translator for %s[%lld] from %s to %s "
		    "is not defined\n", idp->di_name, (longlong_t)ap->dn_value,
		    dt_node_type_name(nnp, n1, sizeof (n1)),
		    dt_node_type_name(xnp, n2, sizeof (n2)));
	}

	assert(dnp->dn_ident->di_flags & DT_IDFLG_ORPHAN);
	assert(dnp->dn_ident->di_id == idp->di_id);
}
Example #19
0
/*
 * Cook a function call.  If this is the first time we are cooking this
 * identifier, create its type signature based on predefined prototype stored
 * in di_iarg.  We then validate the argument list against this signature.
 */
static void
dt_idcook_func(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
{
	if (idp->di_data == NULL) {
		dtrace_hdl_t *dtp = yypcb->pcb_hdl;
		dtrace_typeinfo_t dtt;
		dt_idsig_t *isp;
		char *s, *p1, *p2;
		int i = 0;

		assert(idp->di_iarg != NULL);
		s = alloca(strlen(idp->di_iarg) + 1);
		(void) strcpy(s, idp->di_iarg);

		if ((p2 = strrchr(s, ')')) != NULL)
			*p2 = '\0'; /* mark end of parameter list string */

		if ((p1 = strchr(s, '(')) != NULL)
			*p1++ = '\0'; /* mark end of return type string */

		if (p1 == NULL || p2 == NULL) {
			xyerror(D_UNKNOWN, "internal error: malformed entry "
			    "for built-in function %s\n", idp->di_name);
		}

		for (p2 = p1; *p2 != '\0'; p2++) {
			if (!isspace(*p2)) {
				i++;
				break;
			}
		}

		for (p2 = strchr(p2, ','); p2++ != NULL; i++)
			p2 = strchr(p2, ',');

		/*
		 * We first allocate a new ident signature structure with the
		 * appropriate number of argument entries, and then look up
		 * the return type and store its CTF data in di_ctfp/type.
		 */
		if ((isp = idp->di_data = malloc(sizeof (dt_idsig_t))) == NULL)
			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);

		isp->dis_varargs = -1;
		isp->dis_optargs = -1;
		isp->dis_argc = i;
		isp->dis_args = NULL;
		isp->dis_auxinfo = 0;

		if (i != 0 && (isp->dis_args = calloc(i,
		    sizeof (dt_node_t))) == NULL) {
			idp->di_data = NULL;
			free(isp);
			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
		}

		if (dt_type_lookup(s, &dtt) == -1) {
			xyerror(D_UNKNOWN, "failed to resolve type of %s (%s):"
			    " %s\n", idp->di_name, s,
			    dtrace_errmsg(dtp, dtrace_errno(dtp)));
		}

		if (idp->di_kind == DT_IDENT_AGGFUNC) {
			idp->di_ctfp = DT_DYN_CTFP(dtp);
			idp->di_type = DT_DYN_TYPE(dtp);
		} else {
			idp->di_ctfp = dtt.dtt_ctfp;
			idp->di_type = dtt.dtt_type;
		}

		/*
		 * For each comma-delimited parameter in the prototype string,
		 * we look up the corresponding type and store its CTF data in
		 * the corresponding location in dis_args[].  We also recognize
		 * the special type string "@" to indicate that the specified
		 * parameter may be a D expression of *any* type (represented
		 * as a dis_args[] element with ctfp = NULL, type == CTF_ERR).
		 * If a varargs "..." is present, we record the argument index
		 * in dis_varargs for the benefit of dt_idcook_sign(), above.
		 * If the type of an argument is enclosed in square brackets
		 * (e.g. "[int]"), the argument is considered optional:  the
		 * argument may be absent, but if it is present, it must be of
		 * the specified type.  Note that varargs may not optional,
		 * optional arguments may not follow varargs, and non-optional
		 * arguments may not follow optional arguments.
		 */
		for (i = 0; i < isp->dis_argc; i++, p1 = p2) {
			while (isspace(*p1))
				p1++; /* skip leading whitespace */

			if ((p2 = strchr(p1, ',')) == NULL)
				p2 = p1 + strlen(p1);
			else
				*p2++ = '\0';

			if (strcmp(p1, "@") == 0 || strcmp(p1, "...") == 0) {
				isp->dis_args[i].dn_ctfp = NULL;
				isp->dis_args[i].dn_type = CTF_ERR;
				if (*p1 == '.')
					isp->dis_varargs = i;
				continue;
			}

			if (*p1 == '[' && p1[strlen(p1) - 1] == ']') {
				if (isp->dis_varargs != -1) {
					xyerror(D_UNKNOWN, "optional arg#%d "
					    "may not follow variable arg#%d\n",
					    i + 1, isp->dis_varargs + 1);
				}

				if (isp->dis_optargs == -1)
					isp->dis_optargs = i;

				p1[strlen(p1) - 1] = '\0';
				p1++;
			} else if (isp->dis_optargs != -1) {
				xyerror(D_UNKNOWN, "required arg#%d may not "
				    "follow optional arg#%d\n", i + 1,
				    isp->dis_optargs + 1);
			}

			if (dt_type_lookup(p1, &dtt) == -1) {
				xyerror(D_UNKNOWN, "failed to resolve type of "
				    "%s arg#%d (%s): %s\n", idp->di_name, i + 1,
				    p1, dtrace_errmsg(dtp, dtrace_errno(dtp)));
			}

			dt_node_type_assign(&isp->dis_args[i],
			    dtt.dtt_ctfp, dtt.dtt_type);
		}
	}

	dt_idcook_sign(dnp, idp, argc, args, "", "( )");
}
Example #20
0
dtrace_difo_t *
dt_as(dt_pcb_t *pcb)
{
	dtrace_hdl_t *dtp = pcb->pcb_hdl;
	dt_irlist_t *dlp = &pcb->pcb_ir;
	uint_t *labels = NULL;
	dt_irnode_t *dip;
	dtrace_difo_t *dp;
	dt_ident_t *idp;

	size_t n = 0;
	uint_t i;

	uint_t kmask, kbits, umask, ubits;
	uint_t krel = 0, urel = 0, xlrefs = 0;

	/*
	 * Select bitmasks based upon the desired symbol linking policy.  We
	 * test (di_extern->di_flags & xmask) == xbits to determine if the
	 * symbol should have a relocation entry generated in the loop below.
	 *
	 * DT_LINK_KERNEL = kernel symbols static, user symbols dynamic
	 * DT_LINK_PRIMARY = primary kernel symbols static, others dynamic
	 * DT_LINK_DYNAMIC = all symbols dynamic
	 * DT_LINK_STATIC = all symbols static
	 *
	 * By 'static' we mean that we use the symbol's value at compile-time
	 * in the final DIF.  By 'dynamic' we mean that we create a relocation
	 * table entry for the symbol's value so it can be relocated later.
	 */
	switch (dtp->dt_linkmode) {
	case DT_LINK_KERNEL:
		kmask = 0;
		kbits = -1u;
		umask = DT_IDFLG_USER;
		ubits = DT_IDFLG_USER;
		break;
	case DT_LINK_PRIMARY:
		kmask = DT_IDFLG_USER | DT_IDFLG_PRIM;
		kbits = 0;
		umask = DT_IDFLG_USER;
		ubits = DT_IDFLG_USER;
		break;
	case DT_LINK_DYNAMIC:
		kmask = DT_IDFLG_USER;
		kbits = 0;
		umask = DT_IDFLG_USER;
		ubits = DT_IDFLG_USER;
		break;
	case DT_LINK_STATIC:
		kmask = umask = 0;
		kbits = ubits = -1u;
		break;
	default:
		xyerror(D_UNKNOWN, "internal error -- invalid link mode %u\n",
		    dtp->dt_linkmode);
	}

	assert(pcb->pcb_difo == NULL);
	pcb->pcb_difo = dt_zalloc(dtp, sizeof (dtrace_difo_t));

	if ((dp = pcb->pcb_difo) == NULL)
		longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);

	dp->dtdo_buf = dt_alloc(dtp, sizeof (dif_instr_t) * dlp->dl_len);

	if (dp->dtdo_buf == NULL)
		longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);

	if ((labels = dt_alloc(dtp, sizeof (uint_t) * dlp->dl_label)) == NULL)
		longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);

	/*
	 * Make an initial pass through the instruction list, filling in the
	 * instruction buffer with valid instructions and skipping labeled nops.
	 * While doing this, we also fill in our labels[] translation table
	 * and we count up the number of relocation table entries we will need.
	 */
	for (i = 0, dip = dlp->dl_list; dip != NULL; dip = dip->di_next) {
		if (dip->di_label != DT_LBL_NONE)
			labels[dip->di_label] = i;

		if (dip->di_label == DT_LBL_NONE ||
		    dip->di_instr != DIF_INSTR_NOP)
			dp->dtdo_buf[i++] = dip->di_instr;

		if (dip->di_extern == NULL)
			continue; /* no external references needed */

		switch (DIF_INSTR_OP(dip->di_instr)) {
		case DIF_OP_SETX:
			idp = dip->di_extern;
			if ((idp->di_flags & kmask) == kbits)
				krel++;
			else if ((idp->di_flags & umask) == ubits)
				urel++;
			break;
		case DIF_OP_XLATE:
		case DIF_OP_XLARG:
			xlrefs++;
			break;
		default:
			xyerror(D_UNKNOWN, "unexpected assembler relocation "
			    "for opcode 0x%x\n", DIF_INSTR_OP(dip->di_instr));
		}
	}

	assert(i == dlp->dl_len);
	dp->dtdo_len = dlp->dl_len;

	/*
	 * Make a second pass through the instructions, relocating each branch
	 * label to the index of the final instruction in the buffer and noting
	 * any other instruction-specific DIFO flags such as dtdo_destructive.
	 */
	for (i = 0; i < dp->dtdo_len; i++) {
		dif_instr_t instr = dp->dtdo_buf[i];
		uint_t op = DIF_INSTR_OP(instr);

		if (op == DIF_OP_CALL) {
			if (DIF_INSTR_SUBR(instr) == DIF_SUBR_COPYOUT ||
			    DIF_INSTR_SUBR(instr) == DIF_SUBR_COPYOUTSTR)
				dp->dtdo_destructive = 1;
			continue;
		}

		if (op >= DIF_OP_BA && op <= DIF_OP_BLEU) {
			assert(DIF_INSTR_LABEL(instr) < dlp->dl_label);
			dp->dtdo_buf[i] = DIF_INSTR_BRANCH(op,
			    labels[DIF_INSTR_LABEL(instr)]);
		}
	}

	dt_free(dtp, labels);
	pcb->pcb_asvidx = 0;

	/*
	 * Allocate memory for the appropriate number of variable records and
	 * then fill in each variable record.  As we populate the variable
	 * table we insert the corresponding variable names into the strtab.
	 */
	(void) dt_idhash_iter(dtp->dt_tls, dt_countvar, &n);
	(void) dt_idhash_iter(dtp->dt_globals, dt_countvar, &n);
	(void) dt_idhash_iter(pcb->pcb_locals, dt_countvar, &n);

	if (n != 0) {
		dp->dtdo_vartab = dt_alloc(dtp, n * sizeof (dtrace_difv_t));
		dp->dtdo_varlen = (uint32_t)n;

		if (dp->dtdo_vartab == NULL)
			longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);

		(void) dt_idhash_iter(dtp->dt_tls, dt_copyvar, pcb);
		(void) dt_idhash_iter(dtp->dt_globals, dt_copyvar, pcb);
		(void) dt_idhash_iter(pcb->pcb_locals, dt_copyvar, pcb);
	}

	/*
	 * Allocate memory for the appropriate number of relocation table
	 * entries based upon our kernel and user counts from the first pass.
	 */
	if (krel != 0) {
		dp->dtdo_kreltab = dt_alloc(dtp,
		    krel * sizeof (dof_relodesc_t));
		dp->dtdo_krelen = krel;

		if (dp->dtdo_kreltab == NULL)
			longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
	}

	if (urel != 0) {
		dp->dtdo_ureltab = dt_alloc(dtp,
		    urel * sizeof (dof_relodesc_t));
		dp->dtdo_urelen = urel;

		if (dp->dtdo_ureltab == NULL)
			longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
	}

	if (xlrefs != 0) {
		dp->dtdo_xlmtab = dt_zalloc(dtp, sizeof (dt_node_t *) * xlrefs);
		dp->dtdo_xlmlen = xlrefs;

		if (dp->dtdo_xlmtab == NULL)
			longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
	}

	/*
	 * If any relocations are needed, make another pass through the
	 * instruction list and fill in the relocation table entries.
	 */
	if (krel + urel + xlrefs != 0) {
		uint_t knodef = pcb->pcb_cflags & DTRACE_C_KNODEF;
		uint_t unodef = pcb->pcb_cflags & DTRACE_C_UNODEF;

		dof_relodesc_t *krp = dp->dtdo_kreltab;
		dof_relodesc_t *urp = dp->dtdo_ureltab;
		dt_node_t **xlp = dp->dtdo_xlmtab;

		i = 0; /* dtdo_buf[] index */

		for (dip = dlp->dl_list; dip != NULL; dip = dip->di_next) {
			dof_relodesc_t *rp;
			ssize_t soff;
			uint_t nodef;

			if (dip->di_label != DT_LBL_NONE &&
			    dip->di_instr == DIF_INSTR_NOP)
				continue; /* skip label declarations */

			i++; /* advance dtdo_buf[] index */

			if (DIF_INSTR_OP(dip->di_instr) == DIF_OP_XLATE ||
			    DIF_INSTR_OP(dip->di_instr) == DIF_OP_XLARG) {
				assert(dp->dtdo_buf[i - 1] == dip->di_instr);
				dt_as_xlate(pcb, dp, i - 1, (uint_t)
				    (xlp++ - dp->dtdo_xlmtab), dip->di_extern);
				continue;
			}

			if ((idp = dip->di_extern) == NULL)
				continue; /* no relocation entry needed */

			if ((idp->di_flags & kmask) == kbits) {
				nodef = knodef;
				rp = krp++;
			} else if ((idp->di_flags & umask) == ubits) {
				nodef = unodef;
				rp = urp++;
			} else
				continue;

			if (!nodef)
				dt_as_undef(idp, i);

			assert(DIF_INSTR_OP(dip->di_instr) == DIF_OP_SETX);
			soff = dt_strtab_insert(pcb->pcb_strtab, idp->di_name);

			if (soff == -1L)
				longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
			if (soff > DIF_STROFF_MAX)
				longjmp(pcb->pcb_jmpbuf, EDT_STR2BIG);

			rp->dofr_name = (dof_stridx_t)soff;
			rp->dofr_type = DOF_RELO_SETX;
			rp->dofr_offset = DIF_INSTR_INTEGER(dip->di_instr) *
			    sizeof (uint64_t);
			rp->dofr_data = 0;
		}

		assert(krp == dp->dtdo_kreltab + dp->dtdo_krelen);
		assert(urp == dp->dtdo_ureltab + dp->dtdo_urelen);
		assert(xlp == dp->dtdo_xlmtab + dp->dtdo_xlmlen);
		assert(i == dp->dtdo_len);
	}

	/*
	 * Allocate memory for the compiled string table and then copy the
	 * chunks from the string table into the final string buffer.
	 */
	if ((n = dt_strtab_size(pcb->pcb_strtab)) != 0) {
		if ((dp->dtdo_strtab = dt_alloc(dtp, n)) == NULL)
			longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);

		(void) dt_strtab_write(pcb->pcb_strtab,
		    (dt_strtab_write_f *)dt_copystr, pcb);
		dp->dtdo_strlen = (uint32_t)n;
	}

	/*
	 * Allocate memory for the compiled integer table and then copy the
	 * integer constants from the table into the final integer buffer.
	 */
	if ((n = dt_inttab_size(pcb->pcb_inttab)) != 0) {
		if ((dp->dtdo_inttab = dt_alloc(dtp,
		    n * sizeof (uint64_t))) == NULL)
			longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);

		dt_inttab_write(pcb->pcb_inttab, dp->dtdo_inttab);
		dp->dtdo_intlen = (uint32_t)n;
	}

	/*
	 * Fill in the DIFO return type from the type associated with the
	 * node saved in pcb_dret, and then clear pcb_difo and pcb_dret
	 * now that the assembler has completed successfully.
	 */
	dt_node_diftype(dtp, pcb->pcb_dret, &dp->dtdo_rtype);
	pcb->pcb_difo = NULL;
	pcb->pcb_dret = NULL;

	if (pcb->pcb_cflags & DTRACE_C_DIFV)
		dt_dis(dp, stderr);

	return (dp);
}
Example #21
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);
	}
}