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