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