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