Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <unistd.h>
     30 #include <strings.h>
     31 #include <stdlib.h>
     32 #include <errno.h>
     33 #include <assert.h>
     34 #include <ctype.h>
     35 #include <alloca.h>
     36 
     37 #include <dt_impl.h>
     38 #include <dt_program.h>
     39 #include <dt_printf.h>
     40 #include <dt_provider.h>
     41 
     42 dtrace_prog_t *
     43 dt_program_create(dtrace_hdl_t *dtp)
     44 {
     45 	dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));
     46 
     47 	if (pgp != NULL)
     48 		dt_list_append(&dtp->dt_programs, pgp);
     49 	else
     50 		(void) dt_set_errno(dtp, EDT_NOMEM);
     51 
     52 	/*
     53 	 * By default, programs start with DOF version 1 so that output files
     54 	 * containing DOF are backward compatible. If a program requires new
     55 	 * DOF features, the version is increased as needed.
     56 	 */
     57 	pgp->dp_dofversion = DOF_VERSION_1;
     58 
     59 	return (pgp);
     60 }
     61 
     62 void
     63 dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp)
     64 {
     65 	dt_stmt_t *stp, *next;
     66 	uint_t i;
     67 
     68 	for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
     69 		next = dt_list_next(stp);
     70 		dtrace_stmt_destroy(dtp, stp->ds_desc);
     71 		dt_free(dtp, stp);
     72 	}
     73 
     74 	for (i = 0; i < pgp->dp_xrefslen; i++)
     75 		dt_free(dtp, pgp->dp_xrefs[i]);
     76 
     77 	dt_free(dtp, pgp->dp_xrefs);
     78 	dt_list_delete(&dtp->dt_programs, pgp);
     79 	dt_free(dtp, pgp);
     80 }
     81 
     82 /*ARGSUSED*/
     83 void
     84 dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
     85     dtrace_proginfo_t *pip)
     86 {
     87 	dt_stmt_t *stp;
     88 	dtrace_actdesc_t *ap;
     89 	dtrace_ecbdesc_t *last = NULL;
     90 
     91 	if (pip == NULL)
     92 		return;
     93 
     94 	bzero(pip, sizeof (dtrace_proginfo_t));
     95 
     96 	if (dt_list_next(&pgp->dp_stmts) != NULL) {
     97 		pip->dpi_descattr = _dtrace_maxattr;
     98 		pip->dpi_stmtattr = _dtrace_maxattr;
     99 	} else {
    100 		pip->dpi_descattr = _dtrace_defattr;
    101 		pip->dpi_stmtattr = _dtrace_defattr;
    102 	}
    103 
    104 	for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) {
    105 		dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc;
    106 
    107 		if (edp == last)
    108 			continue;
    109 		last = edp;
    110 
    111 		pip->dpi_descattr =
    112 		    dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr);
    113 
    114 		pip->dpi_stmtattr =
    115 		    dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr);
    116 
    117 		/*
    118 		 * If there aren't any actions, account for the fact that
    119 		 * recording the epid will generate a record.
    120 		 */
    121 		if (edp->dted_action == NULL)
    122 			pip->dpi_recgens++;
    123 
    124 		for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
    125 			if (ap->dtad_kind == DTRACEACT_SPECULATE) {
    126 				pip->dpi_speculations++;
    127 				continue;
    128 			}
    129 
    130 			if (DTRACEACT_ISAGG(ap->dtad_kind)) {
    131 				pip->dpi_recgens -= ap->dtad_arg;
    132 				pip->dpi_aggregates++;
    133 				continue;
    134 			}
    135 
    136 			if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind))
    137 				continue;
    138 
    139 			if (ap->dtad_kind == DTRACEACT_DIFEXPR &&
    140 			    ap->dtad_difo->dtdo_rtype.dtdt_kind ==
    141 			    DIF_TYPE_CTF &&
    142 			    ap->dtad_difo->dtdo_rtype.dtdt_size == 0)
    143 				continue;
    144 
    145 			pip->dpi_recgens++;
    146 		}
    147 	}
    148 }
    149 
    150 int
    151 dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
    152     dtrace_proginfo_t *pip)
    153 {
    154 	void *dof;
    155 	int n, err;
    156 
    157 	dtrace_program_info(dtp, pgp, pip);
    158 
    159 	if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)
    160 		return (-1);
    161 
    162 	n = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof);
    163 	dtrace_dof_destroy(dtp, dof);
    164 
    165 	if (n == -1) {
    166 		switch (errno) {
    167 		case EINVAL:
    168 			err = EDT_DIFINVAL;
    169 			break;
    170 		case EFAULT:
    171 			err = EDT_DIFFAULT;
    172 			break;
    173 		case E2BIG:
    174 			err = EDT_DIFSIZE;
    175 			break;
    176 		default:
    177 			err = errno;
    178 		}
    179 
    180 		return (dt_set_errno(dtp, err));
    181 	}
    182 
    183 	if (pip != NULL)
    184 		pip->dpi_matches += n;
    185 
    186 	return (0);
    187 }
    188 
    189 static void
    190 dt_ecbdesc_hold(dtrace_ecbdesc_t *edp)
    191 {
    192 	edp->dted_refcnt++;
    193 }
    194 
    195 void
    196 dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
    197 {
    198 	if (--edp->dted_refcnt > 0)
    199 		return;
    200 
    201 	dt_difo_free(dtp, edp->dted_pred.dtpdd_difo);
    202 	assert(edp->dted_action == NULL);
    203 	dt_free(dtp, edp);
    204 }
    205 
    206 dtrace_ecbdesc_t *
    207 dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
    208 {
    209 	dtrace_ecbdesc_t *edp;
    210 
    211 	if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) {
    212 		(void) dt_set_errno(dtp, EDT_NOMEM);
    213 		return (NULL);
    214 	}
    215 
    216 	edp->dted_probe = *pdp;
    217 	dt_ecbdesc_hold(edp);
    218 	return (edp);
    219 }
    220 
    221 dtrace_stmtdesc_t *
    222 dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
    223 {
    224 	dtrace_stmtdesc_t *sdp;
    225 
    226 	if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL)
    227 		return (NULL);
    228 
    229 	dt_ecbdesc_hold(edp);
    230 	sdp->dtsd_ecbdesc = edp;
    231 	sdp->dtsd_descattr = _dtrace_defattr;
    232 	sdp->dtsd_stmtattr = _dtrace_defattr;
    233 
    234 	return (sdp);
    235 }
    236 
    237 dtrace_actdesc_t *
    238 dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
    239 {
    240 	dtrace_actdesc_t *new;
    241 	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
    242 
    243 	if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL)
    244 		return (NULL);
    245 
    246 	if (sdp->dtsd_action_last != NULL) {
    247 		assert(sdp->dtsd_action != NULL);
    248 		assert(sdp->dtsd_action_last->dtad_next == NULL);
    249 		sdp->dtsd_action_last->dtad_next = new;
    250 	} else {
    251 		dtrace_actdesc_t *ap = edp->dted_action;
    252 
    253 		assert(sdp->dtsd_action == NULL);
    254 		sdp->dtsd_action = new;
    255 
    256 		while (ap != NULL && ap->dtad_next != NULL)
    257 			ap = ap->dtad_next;
    258 
    259 		if (ap == NULL)
    260 			edp->dted_action = new;
    261 		else
    262 			ap->dtad_next = new;
    263 	}
    264 
    265 	sdp->dtsd_action_last = new;
    266 	bzero(new, sizeof (dtrace_actdesc_t));
    267 	new->dtad_uarg = (uintptr_t)sdp;
    268 
    269 	return (new);
    270 }
    271 
    272 int
    273 dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp)
    274 {
    275 	dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t));
    276 
    277 	if (stp == NULL)
    278 		return (-1); /* errno is set for us */
    279 
    280 	dt_list_append(&pgp->dp_stmts, stp);
    281 	stp->ds_desc = sdp;
    282 
    283 	return (0);
    284 }
    285 
    286 int
    287 dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
    288     dtrace_stmt_f *func, void *data)
    289 {
    290 	dt_stmt_t *stp, *next;
    291 	int status = 0;
    292 
    293 	for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
    294 		next = dt_list_next(stp);
    295 		if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0)
    296 			break;
    297 	}
    298 
    299 	return (status);
    300 }
    301 
    302 void
    303 dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
    304 {
    305 	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
    306 
    307 	/*
    308 	 * We need to remove any actions that we have on this ECB, and
    309 	 * remove our hold on the ECB itself.
    310 	 */
    311 	if (sdp->dtsd_action != NULL) {
    312 		dtrace_actdesc_t *last = sdp->dtsd_action_last;
    313 		dtrace_actdesc_t *ap, *next;
    314 
    315 		assert(last != NULL);
    316 
    317 		for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
    318 			if (ap == sdp->dtsd_action)
    319 				break;
    320 
    321 			if (ap->dtad_next == sdp->dtsd_action)
    322 				break;
    323 		}
    324 
    325 		assert(ap != NULL);
    326 
    327 		if (ap == edp->dted_action)
    328 			edp->dted_action = last->dtad_next;
    329 		else
    330 			ap->dtad_next = last->dtad_next;
    331 
    332 		/*
    333 		 * We have now removed our action list from its ECB; we can
    334 		 * safely destroy the list.
    335 		 */
    336 		last->dtad_next = NULL;
    337 
    338 		for (ap = sdp->dtsd_action; ap != NULL; ap = next) {
    339 			assert(ap->dtad_uarg == (uintptr_t)sdp);
    340 			dt_difo_free(dtp, ap->dtad_difo);
    341 			next = ap->dtad_next;
    342 			dt_free(dtp, ap);
    343 		}
    344 	}
    345 
    346 	if (sdp->dtsd_fmtdata != NULL)
    347 		dt_printf_destroy(sdp->dtsd_fmtdata);
    348 
    349 	dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
    350 	dt_free(dtp, sdp);
    351 }
    352 
    353 typedef struct dt_header_info {
    354 	dtrace_hdl_t *dthi_dtp;	/* consumer handle */
    355 	FILE *dthi_out;		/* output file */
    356 	char *dthi_pmname;	/* provider macro name */
    357 	char *dthi_pfname;	/* provider function name */
    358 	int dthi_empty;		/* should we generate empty macros */
    359 } dt_header_info_t;
    360 
    361 static void
    362 dt_header_fmt_macro(char *buf, const char *str)
    363 {
    364 	for (;;) {
    365 		if (islower(*str)) {
    366 			*buf++ = *str++ + 'A' - 'a';
    367 		} else if (*str == '-') {
    368 			*buf++ = '_';
    369 			str++;
    370 		} else if (*str == '.') {
    371 			*buf++ = '_';
    372 			str++;
    373 		} else if ((*buf++ = *str++) == '\0') {
    374 			break;
    375 		}
    376 	}
    377 }
    378 
    379 static void
    380 dt_header_fmt_func(char *buf, const char *str)
    381 {
    382 	for (;;) {
    383 		if (*str == '-') {
    384 			*buf++ = '_';
    385 			*buf++ = '_';
    386 			str++;
    387 		} else if ((*buf++ = *str++) == '\0') {
    388 			break;
    389 		}
    390 	}
    391 }
    392 
    393 /*ARGSUSED*/
    394 static int
    395 dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
    396 {
    397 	dt_header_info_t *infop = data;
    398 	dtrace_hdl_t *dtp = infop->dthi_dtp;
    399 	dt_probe_t *prp = idp->di_data;
    400 	dt_node_t *dnp;
    401 	char buf[DT_TYPE_NAMELEN];
    402 	char *fname;
    403 	const char *p;
    404 	int i;
    405 
    406 	p = prp->pr_name;
    407 	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
    408 		p++;
    409 
    410 	fname = alloca(strlen(prp->pr_name) + 1 + i);
    411 	dt_header_fmt_func(fname, prp->pr_name);
    412 
    413 	if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(",
    414 	    infop->dthi_pfname, fname) < 0)
    415 		return (dt_set_errno(dtp, errno));
    416 
    417 	for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) {
    418 		if (fprintf(infop->dthi_out, "%s",
    419 		    ctf_type_name(dnp->dn_ctfp, dnp->dn_type,
    420 		    buf, sizeof (buf))) < 0)
    421 			return (dt_set_errno(dtp, errno));
    422 
    423 		if (i + 1 != prp->pr_nargc &&
    424 		    fprintf(infop->dthi_out, ", ") < 0)
    425 			return (dt_set_errno(dtp, errno));
    426 	}
    427 
    428 	if (i == 0 && fprintf(infop->dthi_out, "void") < 0)
    429 		return (dt_set_errno(dtp, errno));
    430 
    431 	if (fprintf(infop->dthi_out, ");\n") < 0)
    432 		return (dt_set_errno(dtp, errno));
    433 
    434 	if (fprintf(infop->dthi_out,
    435 	    "#ifndef\t__sparc\n"
    436 	    "extern int __dtraceenabled_%s___%s(void);\n"
    437 	    "#else\n"
    438 	    "extern int __dtraceenabled_%s___%s(long);\n"
    439 	    "#endif\n",
    440 	    infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0)
    441 		return (dt_set_errno(dtp, errno));
    442 
    443 	return (0);
    444 }
    445 
    446 /*ARGSUSED*/
    447 static int
    448 dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
    449 {
    450 	dt_header_info_t *infop = data;
    451 	dtrace_hdl_t *dtp = infop->dthi_dtp;
    452 	dt_probe_t *prp = idp->di_data;
    453 	char *mname, *fname;
    454 	const char *p;
    455 	int i;
    456 
    457 	p = prp->pr_name;
    458 	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
    459 		p++;
    460 
    461 	mname = alloca(strlen(prp->pr_name) + 1);
    462 	dt_header_fmt_macro(mname, prp->pr_name);
    463 
    464 	fname = alloca(strlen(prp->pr_name) + 1 + i);
    465 	dt_header_fmt_func(fname, prp->pr_name);
    466 
    467 	if (fprintf(infop->dthi_out, "#define\t%s_%s(",
    468 	    infop->dthi_pmname, mname) < 0)
    469 		return (dt_set_errno(dtp, errno));
    470 
    471 	for (i = 0; i < prp->pr_nargc; i++) {
    472 		if (fprintf(infop->dthi_out, "arg%d", i) < 0)
    473 			return (dt_set_errno(dtp, errno));
    474 
    475 		if (i + 1 != prp->pr_nargc &&
    476 		    fprintf(infop->dthi_out, ", ") < 0)
    477 			return (dt_set_errno(dtp, errno));
    478 	}
    479 
    480 	if (!infop->dthi_empty) {
    481 		if (fprintf(infop->dthi_out, ") \\\n\t") < 0)
    482 			return (dt_set_errno(dtp, errno));
    483 
    484 		if (fprintf(infop->dthi_out, "__dtrace_%s___%s(",
    485 		    infop->dthi_pfname, fname) < 0)
    486 			return (dt_set_errno(dtp, errno));
    487 
    488 		for (i = 0; i < prp->pr_nargc; i++) {
    489 			if (fprintf(infop->dthi_out, "arg%d", i) < 0)
    490 				return (dt_set_errno(dtp, errno));
    491 
    492 			if (i + 1 != prp->pr_nargc &&
    493 			    fprintf(infop->dthi_out, ", ") < 0)
    494 				return (dt_set_errno(dtp, errno));
    495 		}
    496 	}
    497 
    498 	if (fprintf(infop->dthi_out, ")\n") < 0)
    499 		return (dt_set_errno(dtp, errno));
    500 
    501 	if (!infop->dthi_empty) {
    502 		if (fprintf(infop->dthi_out,
    503 		    "#ifndef\t__sparc\n"
    504 		    "#define\t%s_%s_ENABLED() \\\n"
    505 		    "\t__dtraceenabled_%s___%s()\n"
    506 		    "#else\n"
    507 		    "#define\t%s_%s_ENABLED() \\\n"
    508 		    "\t__dtraceenabled_%s___%s(0)\n"
    509 		    "#endif\n",
    510 		    infop->dthi_pmname, mname,
    511 		    infop->dthi_pfname, fname,
    512 		    infop->dthi_pmname, mname,
    513 		    infop->dthi_pfname, fname) < 0)
    514 			return (dt_set_errno(dtp, errno));
    515 
    516 	} else {
    517 		if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n",
    518 		    infop->dthi_pmname, mname) < 0)
    519 			return (dt_set_errno(dtp, errno));
    520 	}
    521 
    522 	return (0);
    523 }
    524 
    525 static int
    526 dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out)
    527 {
    528 	dt_header_info_t info;
    529 	const char *p;
    530 	int i;
    531 
    532 	if (pvp->pv_flags & DT_PROVIDER_IMPL)
    533 		return (0);
    534 
    535 	/*
    536 	 * Count the instances of the '-' character since we'll need to double
    537 	 * those up.
    538 	 */
    539 	p = pvp->pv_desc.dtvd_name;
    540 	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
    541 		p++;
    542 
    543 	info.dthi_dtp = dtp;
    544 	info.dthi_out = out;
    545 	info.dthi_empty = 0;
    546 
    547 	info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1);
    548 	dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name);
    549 
    550 	info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i);
    551 	dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name);
    552 
    553 	if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0)
    554 		return (dt_set_errno(dtp, errno));
    555 
    556 	if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
    557 		return (-1); /* dt_errno is set for us */
    558 	if (fprintf(out, "\n\n") < 0)
    559 		return (dt_set_errno(dtp, errno));
    560 	if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0)
    561 		return (-1); /* dt_errno is set for us */
    562 
    563 	if (fprintf(out, "\n#else\n\n") < 0)
    564 		return (dt_set_errno(dtp, errno));
    565 
    566 	info.dthi_empty = 1;
    567 
    568 	if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
    569 		return (-1); /* dt_errno is set for us */
    570 
    571 	if (fprintf(out, "\n#endif\n\n") < 0)
    572 		return (dt_set_errno(dtp, errno));
    573 
    574 	return (0);
    575 }
    576 
    577 int
    578 dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)
    579 {
    580 	dt_provider_t *pvp;
    581 	char *mfname, *p;
    582 
    583 	if (fname != NULL) {
    584 		if ((p = strrchr(fname, '/')) != NULL)
    585 			fname = p + 1;
    586 
    587 		mfname = alloca(strlen(fname) + 1);
    588 		dt_header_fmt_macro(mfname, fname);
    589 		if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n",
    590 		    mfname, mfname) < 0)
    591 			return (dt_set_errno(dtp, errno));
    592 	}
    593 
    594 	if (fprintf(out, "#include <unistd.h>\n\n") < 0)
    595 		return (-1);
    596 
    597 	if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
    598 		return (-1);
    599 
    600 	for (pvp = dt_list_next(&dtp->dt_provlist);
    601 	    pvp != NULL; pvp = dt_list_next(pvp)) {
    602 		if (dt_header_provider(dtp, pvp, out) != 0)
    603 			return (-1); /* dt_errno is set for us */
    604 	}
    605 
    606 	if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0)
    607 		return (dt_set_errno(dtp, errno));
    608 
    609 	if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0)
    610 		return (dt_set_errno(dtp, errno));
    611 
    612 	return (0);
    613 }
    614