Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.c
39563 views
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 *
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
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
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
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
198
dt_ecbdesc_hold(dtrace_ecbdesc_t *edp)
199
{
200
edp->dted_refcnt++;
201
}
202
203
void
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 *
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 *
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 *
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
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
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
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
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
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
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
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
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
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
628