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