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 #include <alloca.h>
34
35 #include <dt_impl.h>
36 #include <dt_program.h>
37 #include <dt_printf.h>
38 #include <dt_provider.h>
39
40 dtrace_prog_t *
dt_program_create(dtrace_hdl_t * dtp)41 dt_program_create(dtrace_hdl_t *dtp)
42 {
43 dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));
44
45 if (pgp != NULL) {
46 dt_list_append(&dtp->dt_programs, pgp);
47 } else {
48 (void) dt_set_errno(dtp, EDT_NOMEM);
49 return (NULL);
50 }
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
dt_program_destroy(dtrace_hdl_t * dtp,dtrace_prog_t * pgp)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
dtrace_program_info(dtrace_hdl_t * dtp,dtrace_prog_t * pgp,dtrace_proginfo_t * pip)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
dtrace_program_exec(dtrace_hdl_t * dtp,dtrace_prog_t * pgp,dtrace_proginfo_t * pip)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 case EBUSY:
177 err = EDT_ENABLING_ERR;
178 break;
179 default:
180 err = errno;
181 }
182
183 return (dt_set_errno(dtp, err));
184 }
185
186 if (pip != NULL)
187 pip->dpi_matches += n;
188
189 return (0);
190 }
191
192 static void
dt_ecbdesc_hold(dtrace_ecbdesc_t * edp)193 dt_ecbdesc_hold(dtrace_ecbdesc_t *edp)
194 {
195 edp->dted_refcnt++;
196 }
197
198 void
dt_ecbdesc_release(dtrace_hdl_t * dtp,dtrace_ecbdesc_t * edp)199 dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
200 {
201 if (--edp->dted_refcnt > 0)
202 return;
203
204 dt_difo_free(dtp, edp->dted_pred.dtpdd_difo);
205 assert(edp->dted_action == NULL);
206 dt_free(dtp, edp);
207 }
208
209 dtrace_ecbdesc_t *
dt_ecbdesc_create(dtrace_hdl_t * dtp,const dtrace_probedesc_t * pdp)210 dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
211 {
212 dtrace_ecbdesc_t *edp;
213
214 if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) {
215 (void) dt_set_errno(dtp, EDT_NOMEM);
216 return (NULL);
217 }
218
219 edp->dted_probe = *pdp;
220 dt_ecbdesc_hold(edp);
221 return (edp);
222 }
223
224 dtrace_stmtdesc_t *
dtrace_stmt_create(dtrace_hdl_t * dtp,dtrace_ecbdesc_t * edp)225 dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
226 {
227 dtrace_stmtdesc_t *sdp;
228
229 if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL)
230 return (NULL);
231
232 dt_ecbdesc_hold(edp);
233 sdp->dtsd_ecbdesc = edp;
234 sdp->dtsd_descattr = _dtrace_defattr;
235 sdp->dtsd_stmtattr = _dtrace_defattr;
236
237 return (sdp);
238 }
239
240 dtrace_actdesc_t *
dtrace_stmt_action(dtrace_hdl_t * dtp,dtrace_stmtdesc_t * sdp)241 dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
242 {
243 dtrace_actdesc_t *new;
244 dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
245
246 if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL)
247 return (NULL);
248
249 if (sdp->dtsd_action_last != NULL) {
250 assert(sdp->dtsd_action != NULL);
251 assert(sdp->dtsd_action_last->dtad_next == NULL);
252 sdp->dtsd_action_last->dtad_next = new;
253 } else {
254 dtrace_actdesc_t *ap = edp->dted_action;
255
256 assert(sdp->dtsd_action == NULL);
257 sdp->dtsd_action = new;
258
259 while (ap != NULL && ap->dtad_next != NULL)
260 ap = ap->dtad_next;
261
262 if (ap == NULL)
263 edp->dted_action = new;
264 else
265 ap->dtad_next = new;
266 }
267
268 sdp->dtsd_action_last = new;
269 bzero(new, sizeof (dtrace_actdesc_t));
270 new->dtad_uarg = (uintptr_t)sdp;
271
272 return (new);
273 }
274
275 int
dtrace_stmt_add(dtrace_hdl_t * dtp,dtrace_prog_t * pgp,dtrace_stmtdesc_t * sdp)276 dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp)
277 {
278 dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t));
279
280 if (stp == NULL)
281 return (-1); /* errno is set for us */
282
283 dt_list_append(&pgp->dp_stmts, stp);
284 stp->ds_desc = sdp;
285
286 return (0);
287 }
288
289 int
dtrace_stmt_iter(dtrace_hdl_t * dtp,dtrace_prog_t * pgp,dtrace_stmt_f * func,void * data)290 dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
291 dtrace_stmt_f *func, void *data)
292 {
293 dt_stmt_t *stp, *next;
294 int status = 0;
295
296 for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
297 next = dt_list_next(stp);
298 if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0)
299 break;
300 }
301
302 return (status);
303 }
304
305 void
dtrace_stmt_destroy(dtrace_hdl_t * dtp,dtrace_stmtdesc_t * sdp)306 dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
307 {
308 dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
309
310 /*
311 * We need to remove any actions that we have on this ECB, and
312 * remove our hold on the ECB itself.
313 */
314 if (sdp->dtsd_action != NULL) {
315 dtrace_actdesc_t *last = sdp->dtsd_action_last;
316 dtrace_actdesc_t *ap, *next;
317
318 assert(last != NULL);
319
320 for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
321 if (ap == sdp->dtsd_action)
322 break;
323
324 if (ap->dtad_next == sdp->dtsd_action)
325 break;
326 }
327
328 assert(ap != NULL);
329
330 if (ap == edp->dted_action)
331 edp->dted_action = last->dtad_next;
332 else
333 ap->dtad_next = last->dtad_next;
334
335 /*
336 * We have now removed our action list from its ECB; we can
337 * safely destroy the list.
338 */
339 last->dtad_next = NULL;
340
341 for (ap = sdp->dtsd_action; ap != NULL; ap = next) {
342 assert(ap->dtad_uarg == (uintptr_t)sdp);
343 dt_difo_free(dtp, ap->dtad_difo);
344 next = ap->dtad_next;
345 dt_free(dtp, ap);
346 }
347 }
348
349 if (sdp->dtsd_fmtdata != NULL)
350 dt_printf_destroy(sdp->dtsd_fmtdata);
351 dt_free(dtp, sdp->dtsd_strdata);
352
353 dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
354 dt_free(dtp, sdp);
355 }
356
357 typedef struct dt_header_info {
358 dtrace_hdl_t *dthi_dtp; /* consumer handle */
359 FILE *dthi_out; /* output file */
360 char *dthi_pmname; /* provider macro name */
361 char *dthi_pfname; /* provider function name */
362 int dthi_empty; /* should we generate empty macros */
363 } dt_header_info_t;
364
365 static void
dt_header_fmt_macro(char * buf,const char * str)366 dt_header_fmt_macro(char *buf, const char *str)
367 {
368 for (;;) {
369 if (islower(*str)) {
370 *buf++ = *str++ + 'A' - 'a';
371 } else if (*str == '-') {
372 *buf++ = '_';
373 str++;
374 } else if (*str == '.') {
375 *buf++ = '_';
376 str++;
377 } else if ((*buf++ = *str++) == '\0') {
378 break;
379 }
380 }
381 }
382
383 static void
dt_header_fmt_func(char * buf,const char * str)384 dt_header_fmt_func(char *buf, const char *str)
385 {
386 for (;;) {
387 if (*str == '-') {
388 *buf++ = '_';
389 *buf++ = '_';
390 str++;
391 } else if ((*buf++ = *str++) == '\0') {
392 break;
393 }
394 }
395 }
396
397 /*ARGSUSED*/
398 static int
dt_header_decl(dt_idhash_t * dhp,dt_ident_t * idp,void * data)399 dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
400 {
401 dt_header_info_t *infop = data;
402 dtrace_hdl_t *dtp = infop->dthi_dtp;
403 dt_probe_t *prp = idp->di_data;
404 dt_node_t *dnp;
405 char buf[DT_TYPE_NAMELEN];
406 char *fname;
407 const char *p;
408 int i;
409
410 p = prp->pr_name;
411 for (i = 0; (p = strchr(p, '-')) != NULL; i++)
412 p++;
413
414 fname = alloca(strlen(prp->pr_name) + 1 + i);
415 dt_header_fmt_func(fname, prp->pr_name);
416
417 if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(",
418 infop->dthi_pfname, fname) < 0)
419 return (dt_set_errno(dtp, errno));
420
421 for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) {
422 if (fprintf(infop->dthi_out, "%s",
423 ctf_type_name(dnp->dn_ctfp, dnp->dn_type,
424 buf, sizeof (buf))) < 0)
425 return (dt_set_errno(dtp, errno));
426
427 if (i + 1 != prp->pr_nargc &&
428 fprintf(infop->dthi_out, ", ") < 0)
429 return (dt_set_errno(dtp, errno));
430 }
431
432 if (i == 0 && fprintf(infop->dthi_out, "void") < 0)
433 return (dt_set_errno(dtp, errno));
434
435 if (fprintf(infop->dthi_out, ");\n") < 0)
436 return (dt_set_errno(dtp, errno));
437
438 if (fprintf(infop->dthi_out,
439 "#ifndef\t__sparc\n"
440 "extern int __dtraceenabled_%s___%s(void);\n"
441 "#else\n"
442 "extern int __dtraceenabled_%s___%s(long);\n"
443 "#endif\n",
444 infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0)
445 return (dt_set_errno(dtp, errno));
446
447 return (0);
448 }
449
450 /*ARGSUSED*/
451 static int
dt_header_probe(dt_idhash_t * dhp,dt_ident_t * idp,void * data)452 dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
453 {
454 dt_header_info_t *infop = data;
455 dtrace_hdl_t *dtp = infop->dthi_dtp;
456 dt_probe_t *prp = idp->di_data;
457 char *mname, *fname;
458 const char *p;
459 int i;
460
461 p = prp->pr_name;
462 for (i = 0; (p = strchr(p, '-')) != NULL; i++)
463 p++;
464
465 mname = alloca(strlen(prp->pr_name) + 1);
466 dt_header_fmt_macro(mname, prp->pr_name);
467
468 fname = alloca(strlen(prp->pr_name) + 1 + i);
469 dt_header_fmt_func(fname, prp->pr_name);
470
471 if (fprintf(infop->dthi_out, "#define\t%s_%s(",
472 infop->dthi_pmname, mname) < 0)
473 return (dt_set_errno(dtp, errno));
474
475 for (i = 0; i < prp->pr_nargc; i++) {
476 if (fprintf(infop->dthi_out, "arg%d", i) < 0)
477 return (dt_set_errno(dtp, errno));
478
479 if (i + 1 != prp->pr_nargc &&
480 fprintf(infop->dthi_out, ", ") < 0)
481 return (dt_set_errno(dtp, errno));
482 }
483
484 if (!infop->dthi_empty) {
485 if (fprintf(infop->dthi_out, ") \\\n\t") < 0)
486 return (dt_set_errno(dtp, errno));
487
488 if (fprintf(infop->dthi_out, "__dtrace_%s___%s(",
489 infop->dthi_pfname, fname) < 0)
490 return (dt_set_errno(dtp, errno));
491
492 for (i = 0; i < prp->pr_nargc; i++) {
493 if (fprintf(infop->dthi_out, "arg%d", i) < 0)
494 return (dt_set_errno(dtp, errno));
495
496 if (i + 1 != prp->pr_nargc &&
497 fprintf(infop->dthi_out, ", ") < 0)
498 return (dt_set_errno(dtp, errno));
499 }
500 }
501
502 if (fprintf(infop->dthi_out, ")\n") < 0)
503 return (dt_set_errno(dtp, errno));
504
505 if (!infop->dthi_empty) {
506 if (fprintf(infop->dthi_out,
507 "#ifndef\t__sparc\n"
508 "#define\t%s_%s_ENABLED() \\\n"
509 "\t__dtraceenabled_%s___%s()\n"
510 "#else\n"
511 "#define\t%s_%s_ENABLED() \\\n"
512 "\t__dtraceenabled_%s___%s(0)\n"
513 "#endif\n",
514 infop->dthi_pmname, mname,
515 infop->dthi_pfname, fname,
516 infop->dthi_pmname, mname,
517 infop->dthi_pfname, fname) < 0)
518 return (dt_set_errno(dtp, errno));
519
520 } else {
521 if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n",
522 infop->dthi_pmname, mname) < 0)
523 return (dt_set_errno(dtp, errno));
524 }
525
526 return (0);
527 }
528
529 static int
dt_header_provider(dtrace_hdl_t * dtp,dt_provider_t * pvp,FILE * out)530 dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out)
531 {
532 dt_header_info_t info;
533 const char *p;
534 int i;
535
536 if (pvp->pv_flags & DT_PROVIDER_IMPL)
537 return (0);
538
539 /*
540 * Count the instances of the '-' character since we'll need to double
541 * those up.
542 */
543 p = pvp->pv_desc.dtvd_name;
544 for (i = 0; (p = strchr(p, '-')) != NULL; i++)
545 p++;
546
547 info.dthi_dtp = dtp;
548 info.dthi_out = out;
549 info.dthi_empty = 0;
550
551 info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1);
552 dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name);
553
554 info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i);
555 dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name);
556
557 if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0)
558 return (dt_set_errno(dtp, errno));
559
560 if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
561 return (-1); /* dt_errno is set for us */
562 if (fprintf(out, "\n\n") < 0)
563 return (dt_set_errno(dtp, errno));
564 if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0)
565 return (-1); /* dt_errno is set for us */
566
567 if (fprintf(out, "\n#else\n\n") < 0)
568 return (dt_set_errno(dtp, errno));
569
570 info.dthi_empty = 1;
571
572 if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
573 return (-1); /* dt_errno is set for us */
574
575 if (fprintf(out, "\n#endif\n\n") < 0)
576 return (dt_set_errno(dtp, errno));
577
578 return (0);
579 }
580
581 int
dtrace_program_header(dtrace_hdl_t * dtp,FILE * out,const char * fname)582 dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)
583 {
584 dt_provider_t *pvp;
585 char *mfname, *p;
586
587 if (fname != NULL) {
588 if ((p = strrchr(fname, '/')) != NULL)
589 fname = p + 1;
590
591 mfname = alloca(strlen(fname) + 1);
592 dt_header_fmt_macro(mfname, fname);
593 if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n",
594 mfname, mfname) < 0)
595 return (dt_set_errno(dtp, errno));
596 }
597
598 if (fprintf(out, "#include <unistd.h>\n\n") < 0)
599 return (-1);
600
601 if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
602 return (-1);
603
604 for (pvp = dt_list_next(&dtp->dt_provlist);
605 pvp != NULL; pvp = dt_list_next(pvp)) {
606 if (dt_header_provider(dtp, pvp, out) != 0)
607 return (-1); /* dt_errno is set for us */
608 }
609
610 if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0)
611 return (dt_set_errno(dtp, errno));
612
613 if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0)
614 return (dt_set_errno(dtp, errno));
615
616 return (0);
617 }
618