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