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 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <sys/resource.h>
30 #include <sys/mman.h>
31 #include <sys/types.h>
32
33 #include <strings.h>
34 #include <signal.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <limits.h>
38 #include <alloca.h>
39 #include <errno.h>
40 #include <fcntl.h>
41
42 #include <dt_impl.h>
43 #include <dt_string.h>
44
45 static int
dt_opt_agg(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)46 dt_opt_agg(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
47 {
48 dt_aggregate_t *agp = &dtp->dt_aggregate;
49
50 if (arg != NULL)
51 return (dt_set_errno(dtp, EDT_BADOPTVAL));
52
53 agp->dtat_flags |= option;
54 return (0);
55 }
56
57 /*ARGSUSED*/
58 static int
dt_opt_amin(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)59 dt_opt_amin(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
60 {
61 char str[DTRACE_ATTR2STR_MAX];
62 dtrace_attribute_t attr;
63
64 if (arg == NULL || dtrace_str2attr(arg, &attr) == -1)
65 return (dt_set_errno(dtp, EDT_BADOPTVAL));
66
67 dt_dprintf("set compiler attribute minimum to %s\n",
68 dtrace_attr2str(attr, str, sizeof (str)));
69
70 if (dtp->dt_pcb != NULL) {
71 dtp->dt_pcb->pcb_cflags |= DTRACE_C_EATTR;
72 dtp->dt_pcb->pcb_amin = attr;
73 } else {
74 dtp->dt_cflags |= DTRACE_C_EATTR;
75 dtp->dt_amin = attr;
76 }
77
78 return (0);
79 }
80
81 static void
dt_coredump(void)82 dt_coredump(void)
83 {
84 const char msg[] = "libdtrace DEBUG: [ forcing coredump ]\n";
85
86 struct sigaction act;
87 struct rlimit lim;
88
89 (void) write(STDERR_FILENO, msg, sizeof (msg) - 1);
90
91 act.sa_handler = SIG_DFL;
92 act.sa_flags = 0;
93
94 (void) sigemptyset(&act.sa_mask);
95 (void) sigaction(SIGABRT, &act, NULL);
96
97 lim.rlim_cur = RLIM_INFINITY;
98 lim.rlim_max = RLIM_INFINITY;
99
100 (void) setrlimit(RLIMIT_CORE, &lim);
101 abort();
102 }
103
104 /*ARGSUSED*/
105 static int
dt_opt_core(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)106 dt_opt_core(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
107 {
108 static int enabled = 0;
109
110 if (arg != NULL)
111 return (dt_set_errno(dtp, EDT_BADOPTVAL));
112
113 if (enabled++ || atexit(dt_coredump) == 0)
114 return (0);
115
116 return (dt_set_errno(dtp, errno));
117 }
118
119 /*ARGSUSED*/
120 static int
dt_opt_cpp_hdrs(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)121 dt_opt_cpp_hdrs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
122 {
123 if (arg != NULL)
124 return (dt_set_errno(dtp, EDT_BADOPTVAL));
125
126 if (dtp->dt_pcb != NULL)
127 return (dt_set_errno(dtp, EDT_BADOPTCTX));
128
129 if (dt_cpp_add_arg(dtp, "-H") == NULL)
130 return (dt_set_errno(dtp, EDT_NOMEM));
131
132 return (0);
133 }
134
135 /*ARGSUSED*/
136 static int
dt_opt_cpp_path(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)137 dt_opt_cpp_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
138 {
139 char *cpp;
140
141 if (arg == NULL)
142 return (dt_set_errno(dtp, EDT_BADOPTVAL));
143
144 if (dtp->dt_pcb != NULL)
145 return (dt_set_errno(dtp, EDT_BADOPTCTX));
146
147 if ((cpp = strdup(arg)) == NULL)
148 return (dt_set_errno(dtp, EDT_NOMEM));
149
150 dtp->dt_cpp_argv[0] = (char *)strbasename(cpp);
151 free(dtp->dt_cpp_path);
152 dtp->dt_cpp_path = cpp;
153
154 return (0);
155 }
156
157 static int
dt_opt_cpp_opts(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)158 dt_opt_cpp_opts(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
159 {
160 char *buf;
161 size_t len;
162 const char *opt = (const char *)option;
163
164 if (opt == NULL || arg == NULL)
165 return (dt_set_errno(dtp, EDT_BADOPTVAL));
166
167 if (dtp->dt_pcb != NULL)
168 return (dt_set_errno(dtp, EDT_BADOPTCTX));
169
170 len = strlen(opt) + strlen(arg) + 1;
171 buf = alloca(len);
172
173 (void) strcpy(buf, opt);
174 (void) strcat(buf, arg);
175
176 if (dt_cpp_add_arg(dtp, buf) == NULL)
177 return (dt_set_errno(dtp, EDT_NOMEM));
178
179 return (0);
180 }
181
182 /*ARGSUSED*/
183 static int
dt_opt_ctypes(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)184 dt_opt_ctypes(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
185 {
186 int fd;
187
188 if (arg == NULL)
189 return (dt_set_errno(dtp, EDT_BADOPTVAL));
190
191 if ((fd = open64(arg, O_CREAT | O_WRONLY, 0666)) == -1)
192 return (dt_set_errno(dtp, errno));
193
194 (void) close(dtp->dt_cdefs_fd);
195 dtp->dt_cdefs_fd = fd;
196 return (0);
197 }
198
199 /*ARGSUSED*/
200 static int
dt_opt_droptags(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)201 dt_opt_droptags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
202 {
203 dtp->dt_droptags = 1;
204 return (0);
205 }
206
207 /*ARGSUSED*/
208 static int
dt_opt_dtypes(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)209 dt_opt_dtypes(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
210 {
211 int fd;
212
213 if (arg == NULL)
214 return (dt_set_errno(dtp, EDT_BADOPTVAL));
215
216 if ((fd = open64(arg, O_CREAT | O_WRONLY, 0666)) == -1)
217 return (dt_set_errno(dtp, errno));
218
219 (void) close(dtp->dt_ddefs_fd);
220 dtp->dt_ddefs_fd = fd;
221 return (0);
222 }
223
224 /*ARGSUSED*/
225 static int
dt_opt_debug(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)226 dt_opt_debug(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
227 {
228 if (arg != NULL)
229 return (dt_set_errno(dtp, EDT_BADOPTVAL));
230
231 _dtrace_debug = 1;
232 return (0);
233 }
234
235 /*ARGSUSED*/
236 static int
dt_opt_iregs(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)237 dt_opt_iregs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
238 {
239 int n;
240
241 if (arg == NULL || (n = atoi(arg)) <= 0)
242 return (dt_set_errno(dtp, EDT_BADOPTVAL));
243
244 dtp->dt_conf.dtc_difintregs = n;
245 return (0);
246 }
247
248 /*ARGSUSED*/
249 static int
dt_opt_lazyload(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)250 dt_opt_lazyload(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
251 {
252 dtp->dt_lazyload = 1;
253
254 return (0);
255 }
256
257 /*ARGSUSED*/
258 static int
dt_opt_ld_path(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)259 dt_opt_ld_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
260 {
261 char *ld;
262
263 if (arg == NULL)
264 return (dt_set_errno(dtp, EDT_BADOPTVAL));
265
266 if (dtp->dt_pcb != NULL)
267 return (dt_set_errno(dtp, EDT_BADOPTCTX));
268
269 if ((ld = strdup(arg)) == NULL)
270 return (dt_set_errno(dtp, EDT_NOMEM));
271
272 free(dtp->dt_ld_path);
273 dtp->dt_ld_path = ld;
274
275 return (0);
276 }
277
278 /*ARGSUSED*/
279 static int
dt_opt_libdir(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)280 dt_opt_libdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
281 {
282 dt_dirpath_t *dp;
283
284 if (arg == NULL)
285 return (dt_set_errno(dtp, EDT_BADOPTVAL));
286
287 if ((dp = malloc(sizeof (dt_dirpath_t))) == NULL ||
288 (dp->dir_path = strdup(arg)) == NULL) {
289 free(dp);
290 return (dt_set_errno(dtp, EDT_NOMEM));
291 }
292
293 dt_list_append(&dtp->dt_lib_path, dp);
294 return (0);
295 }
296
297 /*ARGSUSED*/
298 static int
dt_opt_linkmode(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)299 dt_opt_linkmode(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
300 {
301 if (arg == NULL)
302 return (dt_set_errno(dtp, EDT_BADOPTVAL));
303
304 if (strcmp(arg, "kernel") == 0)
305 dtp->dt_linkmode = DT_LINK_KERNEL;
306 else if (strcmp(arg, "primary") == 0)
307 dtp->dt_linkmode = DT_LINK_PRIMARY;
308 else if (strcmp(arg, "dynamic") == 0)
309 dtp->dt_linkmode = DT_LINK_DYNAMIC;
310 else if (strcmp(arg, "static") == 0)
311 dtp->dt_linkmode = DT_LINK_STATIC;
312 else
313 return (dt_set_errno(dtp, EDT_BADOPTVAL));
314
315 return (0);
316 }
317
318 /*ARGSUSED*/
319 static int
dt_opt_linktype(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)320 dt_opt_linktype(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
321 {
322 if (arg == NULL)
323 return (dt_set_errno(dtp, EDT_BADOPTVAL));
324
325 if (strcasecmp(arg, "elf") == 0)
326 dtp->dt_linktype = DT_LTYP_ELF;
327 else if (strcasecmp(arg, "dof") == 0)
328 dtp->dt_linktype = DT_LTYP_DOF;
329 else
330 return (dt_set_errno(dtp, EDT_BADOPTVAL));
331
332 return (0);
333 }
334
335 /*ARGSUSED*/
336 static int
dt_opt_evaltime(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)337 dt_opt_evaltime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
338 {
339 if (arg == NULL)
340 return (dt_set_errno(dtp, EDT_BADOPTVAL));
341
342 if (strcmp(arg, "exec") == 0)
343 dtp->dt_prcmode = DT_PROC_STOP_CREATE;
344 else if (strcmp(arg, "preinit") == 0)
345 dtp->dt_prcmode = DT_PROC_STOP_PREINIT;
346 else if (strcmp(arg, "postinit") == 0)
347 dtp->dt_prcmode = DT_PROC_STOP_POSTINIT;
348 else if (strcmp(arg, "main") == 0)
349 dtp->dt_prcmode = DT_PROC_STOP_MAIN;
350 else
351 return (dt_set_errno(dtp, EDT_BADOPTVAL));
352
353 return (0);
354 }
355
356 /*ARGSUSED*/
357 static int
dt_opt_pgmax(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)358 dt_opt_pgmax(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
359 {
360 int n;
361
362 if (arg == NULL || (n = atoi(arg)) < 0)
363 return (dt_set_errno(dtp, EDT_BADOPTVAL));
364
365 dtp->dt_procs->dph_lrulim = n;
366 return (0);
367 }
368
369 /*ARGSUSED*/
370 static int
dt_opt_stdc(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)371 dt_opt_stdc(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
372 {
373 if (arg == NULL)
374 return (dt_set_errno(dtp, EDT_BADOPTVAL));
375
376 if (dtp->dt_pcb != NULL)
377 return (dt_set_errno(dtp, EDT_BADOPTCTX));
378
379 if (strcmp(arg, "a") == 0)
380 dtp->dt_stdcmode = DT_STDC_XA;
381 else if (strcmp(arg, "c") == 0)
382 dtp->dt_stdcmode = DT_STDC_XC;
383 else if (strcmp(arg, "s") == 0)
384 dtp->dt_stdcmode = DT_STDC_XS;
385 else if (strcmp(arg, "t") == 0)
386 dtp->dt_stdcmode = DT_STDC_XT;
387 else
388 return (dt_set_errno(dtp, EDT_BADOPTVAL));
389
390 return (0);
391 }
392
393 /*ARGSUSED*/
394 static int
dt_opt_syslibdir(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)395 dt_opt_syslibdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
396 {
397 dt_dirpath_t *dp = dt_list_next(&dtp->dt_lib_path);
398 char *path;
399
400 if (arg == NULL)
401 return (dt_set_errno(dtp, EDT_BADOPTVAL));
402
403 if ((path = strdup(arg)) == NULL)
404 return (dt_set_errno(dtp, EDT_NOMEM));
405
406 free(dp->dir_path);
407 dp->dir_path = path;
408
409 return (0);
410 }
411
412
413 /*ARGSUSED*/
414 static int
dt_opt_tree(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)415 dt_opt_tree(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
416 {
417 int m;
418
419 if (arg == NULL || (m = atoi(arg)) <= 0)
420 return (dt_set_errno(dtp, EDT_BADOPTVAL));
421
422 dtp->dt_treedump = m;
423 return (0);
424 }
425
426 /*ARGSUSED*/
427 static int
dt_opt_tregs(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)428 dt_opt_tregs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
429 {
430 int n;
431
432 if (arg == NULL || (n = atoi(arg)) <= 0)
433 return (dt_set_errno(dtp, EDT_BADOPTVAL));
434
435 dtp->dt_conf.dtc_diftupregs = n;
436 return (0);
437 }
438
439 /*ARGSUSED*/
440 static int
dt_opt_xlate(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)441 dt_opt_xlate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
442 {
443 if (arg == NULL)
444 return (dt_set_errno(dtp, EDT_BADOPTVAL));
445
446 if (strcmp(arg, "dynamic") == 0)
447 dtp->dt_xlatemode = DT_XL_DYNAMIC;
448 else if (strcmp(arg, "static") == 0)
449 dtp->dt_xlatemode = DT_XL_STATIC;
450 else
451 return (dt_set_errno(dtp, EDT_BADOPTVAL));
452
453 return (0);
454 }
455
456 /*ARGSUSED*/
457 static int
dt_opt_cflags(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)458 dt_opt_cflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
459 {
460 if (arg != NULL)
461 return (dt_set_errno(dtp, EDT_BADOPTVAL));
462
463 if (dtp->dt_pcb != NULL)
464 dtp->dt_pcb->pcb_cflags |= option;
465 else
466 dtp->dt_cflags |= option;
467
468 return (0);
469 }
470
471 static int
dt_opt_dflags(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)472 dt_opt_dflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
473 {
474 if (arg != NULL)
475 return (dt_set_errno(dtp, EDT_BADOPTVAL));
476
477 dtp->dt_dflags |= option;
478 return (0);
479 }
480
481 static int
dt_opt_invcflags(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)482 dt_opt_invcflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
483 {
484 if (arg != NULL)
485 return (dt_set_errno(dtp, EDT_BADOPTVAL));
486
487 if (dtp->dt_pcb != NULL)
488 dtp->dt_pcb->pcb_cflags &= ~option;
489 else
490 dtp->dt_cflags &= ~option;
491
492 return (0);
493 }
494
495 /*ARGSUSED*/
496 static int
dt_opt_version(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)497 dt_opt_version(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
498 {
499 dt_version_t v;
500
501 if (arg == NULL)
502 return (dt_set_errno(dtp, EDT_BADOPTVAL));
503
504 if (dt_version_str2num(arg, &v) == -1)
505 return (dt_set_errno(dtp, EDT_VERSINVAL));
506
507 if (!dt_version_defined(v))
508 return (dt_set_errno(dtp, EDT_VERSUNDEF));
509
510 return (dt_reduce(dtp, v));
511 }
512
513 static int
dt_opt_runtime(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)514 dt_opt_runtime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
515 {
516 char *end;
517 dtrace_optval_t val = 0;
518 int i;
519
520 const struct {
521 char *positive;
522 char *negative;
523 } couples[] = {
524 { "yes", "no" },
525 { "enable", "disable" },
526 { "enabled", "disabled" },
527 { "true", "false" },
528 { "on", "off" },
529 { "set", "unset" },
530 { NULL }
531 };
532
533 if (arg != NULL) {
534 if (arg[0] == '\0') {
535 val = DTRACEOPT_UNSET;
536 goto out;
537 }
538
539 for (i = 0; couples[i].positive != NULL; i++) {
540 if (strcasecmp(couples[i].positive, arg) == 0) {
541 val = 1;
542 goto out;
543 }
544
545 if (strcasecmp(couples[i].negative, arg) == 0) {
546 val = DTRACEOPT_UNSET;
547 goto out;
548 }
549 }
550
551 errno = 0;
552 val = strtoull(arg, &end, 0);
553
554 if (*end != '\0' || errno != 0 || val < 0)
555 return (dt_set_errno(dtp, EDT_BADOPTVAL));
556 }
557
558 out:
559 dtp->dt_options[option] = val;
560 return (0);
561 }
562
563 static int
dt_optval_parse(const char * arg,dtrace_optval_t * rval)564 dt_optval_parse(const char *arg, dtrace_optval_t *rval)
565 {
566 dtrace_optval_t mul = 1;
567 size_t len;
568 char *end;
569
570 len = strlen(arg);
571 errno = 0;
572
573 switch (arg[len - 1]) {
574 case 't':
575 case 'T':
576 mul *= 1024;
577 /*FALLTHRU*/
578 case 'g':
579 case 'G':
580 mul *= 1024;
581 /*FALLTHRU*/
582 case 'm':
583 case 'M':
584 mul *= 1024;
585 /*FALLTHRU*/
586 case 'k':
587 case 'K':
588 mul *= 1024;
589 /*FALLTHRU*/
590 default:
591 break;
592 }
593
594 errno = 0;
595 *rval = strtoull(arg, &end, 0) * mul;
596
597 if ((mul > 1 && end != &arg[len - 1]) || (mul == 1 && *end != '\0') ||
598 *rval < 0 || errno != 0)
599 return (-1);
600
601 return (0);
602 }
603
604 static int
dt_opt_size(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)605 dt_opt_size(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
606 {
607 dtrace_optval_t val = 0;
608
609 if (arg != NULL && dt_optval_parse(arg, &val) != 0)
610 return (dt_set_errno(dtp, EDT_BADOPTVAL));
611
612 dtp->dt_options[option] = val;
613 return (0);
614 }
615
616 static int
dt_opt_rate(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)617 dt_opt_rate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
618 {
619 char *end;
620 int i;
621 dtrace_optval_t mul = 1, val = 0;
622
623 const struct {
624 char *name;
625 hrtime_t mul;
626 } suffix[] = {
627 { "ns", NANOSEC / NANOSEC },
628 { "nsec", NANOSEC / NANOSEC },
629 { "us", NANOSEC / MICROSEC },
630 { "usec", NANOSEC / MICROSEC },
631 { "ms", NANOSEC / MILLISEC },
632 { "msec", NANOSEC / MILLISEC },
633 { "s", NANOSEC / SEC },
634 { "sec", NANOSEC / SEC },
635 { "m", NANOSEC * (hrtime_t)60 },
636 { "min", NANOSEC * (hrtime_t)60 },
637 { "h", NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
638 { "hour", NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
639 { "d", NANOSEC * (hrtime_t)(24 * 60 * 60) },
640 { "day", NANOSEC * (hrtime_t)(24 * 60 * 60) },
641 { "hz", 0 },
642 { NULL }
643 };
644
645 if (arg != NULL) {
646 errno = 0;
647 val = strtoull(arg, &end, 0);
648
649 for (i = 0; suffix[i].name != NULL; i++) {
650 if (strcasecmp(suffix[i].name, end) == 0) {
651 mul = suffix[i].mul;
652 break;
653 }
654 }
655
656 if (suffix[i].name == NULL && *end != '\0' || val < 0)
657 return (dt_set_errno(dtp, EDT_BADOPTVAL));
658
659 if (mul == 0) {
660 /*
661 * The rate has been specified in frequency-per-second.
662 */
663 if (val != 0)
664 val = NANOSEC / val;
665 } else {
666 val *= mul;
667 }
668 }
669
670 dtp->dt_options[option] = val;
671 return (0);
672 }
673
674 /*
675 * When setting the strsize option, set the option in the dt_options array
676 * using dt_opt_size() as usual, and then update the definition of the CTF
677 * type for the D intrinsic "string" to be an array of the corresponding size.
678 * If any errors occur, reset dt_options[option] to its previous value.
679 */
680 static int
dt_opt_strsize(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)681 dt_opt_strsize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
682 {
683 dtrace_optval_t val = dtp->dt_options[option];
684 ctf_file_t *fp = DT_STR_CTFP(dtp);
685 ctf_id_t type = ctf_type_resolve(fp, DT_STR_TYPE(dtp));
686 ctf_arinfo_t r;
687
688 if (dt_opt_size(dtp, arg, option) != 0)
689 return (-1); /* dt_errno is set for us */
690
691 if (dtp->dt_options[option] > UINT_MAX) {
692 dtp->dt_options[option] = val;
693 return (dt_set_errno(dtp, EOVERFLOW));
694 }
695
696 if (ctf_array_info(fp, type, &r) == CTF_ERR) {
697 dtp->dt_options[option] = val;
698 dtp->dt_ctferr = ctf_errno(fp);
699 return (dt_set_errno(dtp, EDT_CTF));
700 }
701
702 r.ctr_nelems = (uint_t)dtp->dt_options[option];
703
704 if (ctf_set_array(fp, type, &r) == CTF_ERR ||
705 ctf_update(fp) == CTF_ERR) {
706 dtp->dt_options[option] = val;
707 dtp->dt_ctferr = ctf_errno(fp);
708 return (dt_set_errno(dtp, EDT_CTF));
709 }
710
711 return (0);
712 }
713
714 static const struct {
715 const char *dtbp_name;
716 int dtbp_policy;
717 } _dtrace_bufpolicies[] = {
718 { "ring", DTRACEOPT_BUFPOLICY_RING },
719 { "fill", DTRACEOPT_BUFPOLICY_FILL },
720 { "switch", DTRACEOPT_BUFPOLICY_SWITCH },
721 { NULL, 0 }
722 };
723
724 /*ARGSUSED*/
725 static int
dt_opt_bufpolicy(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)726 dt_opt_bufpolicy(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
727 {
728 dtrace_optval_t policy = DTRACEOPT_UNSET;
729 int i;
730
731 if (arg == NULL)
732 return (dt_set_errno(dtp, EDT_BADOPTVAL));
733
734 for (i = 0; _dtrace_bufpolicies[i].dtbp_name != NULL; i++) {
735 if (strcmp(_dtrace_bufpolicies[i].dtbp_name, arg) == 0) {
736 policy = _dtrace_bufpolicies[i].dtbp_policy;
737 break;
738 }
739 }
740
741 if (policy == DTRACEOPT_UNSET)
742 return (dt_set_errno(dtp, EDT_BADOPTVAL));
743
744 dtp->dt_options[DTRACEOPT_BUFPOLICY] = policy;
745
746 return (0);
747 }
748
749 static const struct {
750 const char *dtbr_name;
751 int dtbr_policy;
752 } _dtrace_bufresize[] = {
753 { "auto", DTRACEOPT_BUFRESIZE_AUTO },
754 { "manual", DTRACEOPT_BUFRESIZE_MANUAL },
755 { NULL, 0 }
756 };
757
758 /*ARGSUSED*/
759 static int
dt_opt_bufresize(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)760 dt_opt_bufresize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
761 {
762 dtrace_optval_t policy = DTRACEOPT_UNSET;
763 int i;
764
765 if (arg == NULL)
766 return (dt_set_errno(dtp, EDT_BADOPTVAL));
767
768 for (i = 0; _dtrace_bufresize[i].dtbr_name != NULL; i++) {
769 if (strcmp(_dtrace_bufresize[i].dtbr_name, arg) == 0) {
770 policy = _dtrace_bufresize[i].dtbr_policy;
771 break;
772 }
773 }
774
775 if (policy == DTRACEOPT_UNSET)
776 return (dt_set_errno(dtp, EDT_BADOPTVAL));
777
778 dtp->dt_options[DTRACEOPT_BUFRESIZE] = policy;
779
780 return (0);
781 }
782
783 int
dt_options_load(dtrace_hdl_t * dtp)784 dt_options_load(dtrace_hdl_t *dtp)
785 {
786 dof_hdr_t hdr, *dof;
787 dof_sec_t *sec;
788 size_t offs;
789 int i;
790
791 /*
792 * To load the option values, we need to ask the kernel to provide its
793 * DOF, which we'll sift through to look for OPTDESC sections.
794 */
795 bzero(&hdr, sizeof (dof_hdr_t));
796 hdr.dofh_loadsz = sizeof (dof_hdr_t);
797
798 if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &hdr) == -1)
799 return (dt_set_errno(dtp, errno));
800
801 if (hdr.dofh_loadsz < sizeof (dof_hdr_t))
802 return (dt_set_errno(dtp, EINVAL));
803
804 dof = alloca(hdr.dofh_loadsz);
805 bzero(dof, sizeof (dof_hdr_t));
806 dof->dofh_loadsz = hdr.dofh_loadsz;
807
808 for (i = 0; i < DTRACEOPT_MAX; i++)
809 dtp->dt_options[i] = DTRACEOPT_UNSET;
810
811 if (dt_ioctl(dtp, DTRACEIOC_DOFGET, dof) == -1)
812 return (dt_set_errno(dtp, errno));
813
814 for (i = 0; i < dof->dofh_secnum; i++) {
815 sec = (dof_sec_t *)(uintptr_t)((uintptr_t)dof +
816 dof->dofh_secoff + i * dof->dofh_secsize);
817
818 if (sec->dofs_type != DOF_SECT_OPTDESC)
819 continue;
820
821 break;
822 }
823
824 for (offs = 0; offs < sec->dofs_size; offs += sec->dofs_entsize) {
825 dof_optdesc_t *opt = (dof_optdesc_t *)(uintptr_t)
826 ((uintptr_t)dof + sec->dofs_offset + offs);
827
828 if (opt->dofo_strtab != DOF_SECIDX_NONE)
829 continue;
830
831 if (opt->dofo_option >= DTRACEOPT_MAX)
832 continue;
833
834 dtp->dt_options[opt->dofo_option] = opt->dofo_value;
835 }
836
837 return (0);
838 }
839
840 /*ARGSUSED*/
841 static int
dt_opt_preallocate(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)842 dt_opt_preallocate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
843 {
844 dtrace_optval_t size;
845 void *p;
846
847 if (arg == NULL || dt_optval_parse(arg, &size) != 0)
848 return (dt_set_errno(dtp, EDT_BADOPTVAL));
849
850 if (size > SIZE_MAX)
851 size = SIZE_MAX;
852
853 if ((p = dt_zalloc(dtp, size)) == NULL) {
854 do {
855 size /= 2;
856 } while ((p = dt_zalloc(dtp, size)) == NULL);
857 }
858
859 dt_free(dtp, p);
860
861 return (0);
862 }
863
864 typedef struct dt_option {
865 const char *o_name;
866 int (*o_func)(dtrace_hdl_t *, const char *, uintptr_t);
867 uintptr_t o_option;
868 } dt_option_t;
869
870 /*
871 * Compile-time options.
872 */
873 static const dt_option_t _dtrace_ctoptions[] = {
874 { "aggpercpu", dt_opt_agg, DTRACE_A_PERCPU },
875 { "amin", dt_opt_amin },
876 { "argref", dt_opt_cflags, DTRACE_C_ARGREF },
877 { "core", dt_opt_core },
878 { "cpp", dt_opt_cflags, DTRACE_C_CPP },
879 { "cpphdrs", dt_opt_cpp_hdrs },
880 { "cpppath", dt_opt_cpp_path },
881 { "ctypes", dt_opt_ctypes },
882 { "defaultargs", dt_opt_cflags, DTRACE_C_DEFARG },
883 { "dtypes", dt_opt_dtypes },
884 { "debug", dt_opt_debug },
885 { "define", dt_opt_cpp_opts, (uintptr_t)"-D" },
886 { "droptags", dt_opt_droptags },
887 { "empty", dt_opt_cflags, DTRACE_C_EMPTY },
888 { "errtags", dt_opt_cflags, DTRACE_C_ETAGS },
889 { "evaltime", dt_opt_evaltime },
890 { "incdir", dt_opt_cpp_opts, (uintptr_t)"-I" },
891 { "iregs", dt_opt_iregs },
892 { "kdefs", dt_opt_invcflags, DTRACE_C_KNODEF },
893 { "knodefs", dt_opt_cflags, DTRACE_C_KNODEF },
894 { "late", dt_opt_xlate },
895 { "lazyload", dt_opt_lazyload },
896 { "ldpath", dt_opt_ld_path },
897 { "libdir", dt_opt_libdir },
898 { "linkmode", dt_opt_linkmode },
899 { "linktype", dt_opt_linktype },
900 { "nolibs", dt_opt_cflags, DTRACE_C_NOLIBS },
901 { "pgmax", dt_opt_pgmax },
902 { "preallocate", dt_opt_preallocate },
903 { "pspec", dt_opt_cflags, DTRACE_C_PSPEC },
904 { "stdc", dt_opt_stdc },
905 { "strip", dt_opt_dflags, DTRACE_D_STRIP },
906 { "syslibdir", dt_opt_syslibdir },
907 { "tree", dt_opt_tree },
908 { "tregs", dt_opt_tregs },
909 { "udefs", dt_opt_invcflags, DTRACE_C_UNODEF },
910 { "undef", dt_opt_cpp_opts, (uintptr_t)"-U" },
911 { "unodefs", dt_opt_cflags, DTRACE_C_UNODEF },
912 { "verbose", dt_opt_cflags, DTRACE_C_DIFV },
913 { "version", dt_opt_version },
914 { "zdefs", dt_opt_cflags, DTRACE_C_ZDEFS },
915 { NULL }
916 };
917
918 /*
919 * Run-time options.
920 */
921 static const dt_option_t _dtrace_rtoptions[] = {
922 { "aggsize", dt_opt_size, DTRACEOPT_AGGSIZE },
923 { "bufsize", dt_opt_size, DTRACEOPT_BUFSIZE },
924 { "bufpolicy", dt_opt_bufpolicy, DTRACEOPT_BUFPOLICY },
925 { "bufresize", dt_opt_bufresize, DTRACEOPT_BUFRESIZE },
926 { "cleanrate", dt_opt_rate, DTRACEOPT_CLEANRATE },
927 { "cpu", dt_opt_runtime, DTRACEOPT_CPU },
928 { "destructive", dt_opt_runtime, DTRACEOPT_DESTRUCTIVE },
929 { "dynvarsize", dt_opt_size, DTRACEOPT_DYNVARSIZE },
930 { "grabanon", dt_opt_runtime, DTRACEOPT_GRABANON },
931 { "jstackframes", dt_opt_runtime, DTRACEOPT_JSTACKFRAMES },
932 { "jstackstrsize", dt_opt_size, DTRACEOPT_JSTACKSTRSIZE },
933 { "nspec", dt_opt_runtime, DTRACEOPT_NSPEC },
934 { "specsize", dt_opt_size, DTRACEOPT_SPECSIZE },
935 { "stackframes", dt_opt_runtime, DTRACEOPT_STACKFRAMES },
936 { "statusrate", dt_opt_rate, DTRACEOPT_STATUSRATE },
937 { "strsize", dt_opt_strsize, DTRACEOPT_STRSIZE },
938 { "ustackframes", dt_opt_runtime, DTRACEOPT_USTACKFRAMES },
939 { NULL }
940 };
941
942 /*
943 * Dynamic run-time options.
944 */
945 static const dt_option_t _dtrace_drtoptions[] = {
946 { "aggrate", dt_opt_rate, DTRACEOPT_AGGRATE },
947 { "aggsortkey", dt_opt_runtime, DTRACEOPT_AGGSORTKEY },
948 { "aggsortkeypos", dt_opt_runtime, DTRACEOPT_AGGSORTKEYPOS },
949 { "aggsortpos", dt_opt_runtime, DTRACEOPT_AGGSORTPOS },
950 { "aggsortrev", dt_opt_runtime, DTRACEOPT_AGGSORTREV },
951 { "flowindent", dt_opt_runtime, DTRACEOPT_FLOWINDENT },
952 { "quiet", dt_opt_runtime, DTRACEOPT_QUIET },
953 { "rawbytes", dt_opt_runtime, DTRACEOPT_RAWBYTES },
954 { "stackindent", dt_opt_runtime, DTRACEOPT_STACKINDENT },
955 { "switchrate", dt_opt_rate, DTRACEOPT_SWITCHRATE },
956 { NULL }
957 };
958
959 int
dtrace_getopt(dtrace_hdl_t * dtp,const char * opt,dtrace_optval_t * val)960 dtrace_getopt(dtrace_hdl_t *dtp, const char *opt, dtrace_optval_t *val)
961 {
962 const dt_option_t *op;
963
964 if (opt == NULL)
965 return (dt_set_errno(dtp, EINVAL));
966
967 /*
968 * We only need to search the run-time options -- it's not legal
969 * to get the values of compile-time options.
970 */
971 for (op = _dtrace_rtoptions; op->o_name != NULL; op++) {
972 if (strcmp(op->o_name, opt) == 0) {
973 *val = dtp->dt_options[op->o_option];
974 return (0);
975 }
976 }
977
978 for (op = _dtrace_drtoptions; op->o_name != NULL; op++) {
979 if (strcmp(op->o_name, opt) == 0) {
980 *val = dtp->dt_options[op->o_option];
981 return (0);
982 }
983 }
984
985 return (dt_set_errno(dtp, EDT_BADOPTNAME));
986 }
987
988 int
dtrace_setopt(dtrace_hdl_t * dtp,const char * opt,const char * val)989 dtrace_setopt(dtrace_hdl_t *dtp, const char *opt, const char *val)
990 {
991 const dt_option_t *op;
992
993 if (opt == NULL)
994 return (dt_set_errno(dtp, EINVAL));
995
996 for (op = _dtrace_ctoptions; op->o_name != NULL; op++) {
997 if (strcmp(op->o_name, opt) == 0)
998 return (op->o_func(dtp, val, op->o_option));
999 }
1000
1001 for (op = _dtrace_drtoptions; op->o_name != NULL; op++) {
1002 if (strcmp(op->o_name, opt) == 0)
1003 return (op->o_func(dtp, val, op->o_option));
1004 }
1005
1006 for (op = _dtrace_rtoptions; op->o_name != NULL; op++) {
1007 if (strcmp(op->o_name, opt) == 0) {
1008 /*
1009 * Only dynamic run-time options may be set while
1010 * tracing is active.
1011 */
1012 if (dtp->dt_active)
1013 return (dt_set_errno(dtp, EDT_ACTIVE));
1014
1015 return (op->o_func(dtp, val, op->o_option));
1016 }
1017 }
1018
1019 return (dt_set_errno(dtp, EDT_BADOPTNAME));
1020 }
1021