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