1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <ctype.h>
33 #include <string.h>
34 #include <memory.h>
35 #include <sys/types.h>
36 #include <signal.h>
37 #include <libproc.h>
38 #include "ramdata.h"
39 #include "systable.h"
40 #include "proto.h"
41
42 /* XXX A bug in the <string.h> header file requires this */
43 extern char *strtok_r(char *s1, const char *s2, char **lasts);
44
45 /*
46 * option procesing ---
47 * Routines for scanning syscall, signal, fault
48 * and file descriptor lists.
49 */
50
51 /*
52 * Function prototypes for static routines in this module.
53 */
54 void upcase(char *);
55
56 const char white[] = " \t\n"; /* white space characters */
57 const char sepr[] = " ,\t\n"; /* list separator characters */
58 const char csepr[] = " :,\t\n"; /* same, with ':' added */
59
60 /*
61 * Scan list of syscall names.
62 * Return 0 on success, != 0 on any failure.
63 */
64 int
syslist(char * str,sysset_t * setp,int * fp)65 syslist(char *str, /* string of syscall names */
66 sysset_t *setp, /* syscall set */
67 int *fp) /* first-time flag */
68 {
69 char *name;
70 int exclude = FALSE;
71 int rc = 0;
72 char *lasts;
73
74 name = strtok_r(str, sepr, &lasts);
75
76 if (name != NULL && *name == '!') { /* exclude from set */
77 exclude = TRUE;
78 if (*++name == '\0')
79 name = strtok_r(NULL, sepr, &lasts);
80 } else if (!*fp) { /* first time, clear the set */
81 premptyset(setp);
82 *fp = TRUE;
83 }
84
85 for (; name; name = strtok_r(NULL, sepr, &lasts)) {
86 int sys;
87 int sysx;
88 int sysxx;
89 int sys64;
90 char *next;
91
92 if (*name == '!') { /* exclude remainder from set */
93 exclude = TRUE;
94 while (*++name == '!')
95 /* empty */;
96 if (*name == '\0')
97 continue;
98 }
99
100 sys = strtol(name, &next, 0);
101 sysx = sysxx = sys64 = 0;
102 if (sys < 0 || sys > PRMAXSYS || *next != '\0')
103 sys = 0;
104 if (sys == 0) {
105 const struct systable *stp = systable;
106 for (; sys == 0 && stp->nargs >= 0; stp++)
107 if (stp->name && strcmp(stp->name, name) == 0)
108 sys = stp-systable;
109 }
110 if (sys == 0) {
111 const struct sysalias *sap = sysalias;
112 for (; sys == 0 && sap->name; sap++)
113 if (strcmp(sap->name, name) == 0)
114 sys = sap->number;
115 }
116 if (sys > 0 && sys <= PRMAXSYS) {
117 switch (sys) {
118 case SYS_fstatat: /* set both if either */
119 case SYS_fstatat64:
120 sys = SYS_fstatat;
121 sys64 = SYS_fstatat64;
122 goto def;
123
124 case SYS_stat: /* set all if either */
125 case SYS_stat64:
126 sys = SYS_stat;
127 sys64 = SYS_stat64;
128 sysx = SYS_fstatat;
129 sysxx = SYS_fstatat64;
130 goto def;
131
132 case SYS_lstat: /* set all if either */
133 case SYS_lstat64:
134 sys = SYS_lstat;
135 sys64 = SYS_lstat64;
136 sysx = SYS_fstatat;
137 sysxx = SYS_fstatat64;
138 goto def;
139
140 case SYS_fstat: /* set all if either */
141 case SYS_fstat64:
142 sys = SYS_fstat;
143 sys64 = SYS_fstat64;
144 sysx = SYS_fstatat;
145 sysxx = SYS_fstatat64;
146 goto def;
147
148 case SYS_getdents: /* set both if either */
149 case SYS_getdents64:
150 sys = SYS_getdents;
151 sys64 = SYS_getdents64;
152 goto def;
153
154 case SYS_mmap: /* set both if either */
155 case SYS_mmap64:
156 sys = SYS_mmap;
157 sys64 = SYS_mmap64;
158 goto def;
159
160 case SYS_statvfs: /* set both if either */
161 case SYS_statvfs64:
162 sys = SYS_statvfs;
163 sys64 = SYS_statvfs64;
164 goto def;
165
166 case SYS_fstatvfs: /* set both if either */
167 case SYS_fstatvfs64:
168 sys = SYS_fstatvfs;
169 sys64 = SYS_fstatvfs64;
170 goto def;
171
172 case SYS_setrlimit: /* set both if either */
173 case SYS_setrlimit64:
174 sys = SYS_setrlimit;
175 sys64 = SYS_setrlimit64;
176 goto def;
177
178 case SYS_getrlimit: /* set both if either */
179 case SYS_getrlimit64:
180 sys = SYS_getrlimit;
181 sys64 = SYS_getrlimit64;
182 goto def;
183
184 case SYS_pread: /* set both if either */
185 case SYS_pread64:
186 sys = SYS_pread;
187 sys64 = SYS_pread64;
188 goto def;
189
190 case SYS_pwrite: /* set both if either */
191 case SYS_pwrite64:
192 sys = SYS_pwrite;
193 sys64 = SYS_pwrite64;
194 goto def;
195
196 case SYS_openat: /* set all if any */
197 case SYS_openat64:
198 case SYS_open:
199 case SYS_open64:
200 sys = SYS_openat;
201 sys64 = SYS_openat64;
202 sysx = SYS_open;
203 sysxx = SYS_open64;
204 goto def;
205
206 case SYS_forksys: /* set both if either */
207 case SYS_vfork:
208 sysx = SYS_forksys;
209 sys = SYS_vfork;
210 goto def;
211
212 case SYS_sigprocmask: /* set both if either */
213 case SYS_lwp_sigmask:
214 sysx = SYS_sigprocmask;
215 sys = SYS_lwp_sigmask;
216 goto def;
217
218 case SYS_lseek: /* set both if either */
219 case SYS_llseek:
220 sysx = SYS_lseek;
221 sys = SYS_llseek;
222 goto def;
223
224 case SYS_rename: /* set both */
225 sysx = SYS_renameat;
226 goto def;
227
228 case SYS_link: /* set both */
229 sysx = SYS_linkat;
230 goto def;
231
232 case SYS_unlink: /* set both */
233 case SYS_rmdir: /* set both */
234 sysx = SYS_unlinkat;
235 goto def;
236
237 case SYS_symlink: /* set both */
238 sysx = SYS_symlinkat;
239 goto def;
240
241 case SYS_readlink: /* set both */
242 sysx = SYS_readlinkat;
243 goto def;
244
245 case SYS_chmod: /* set both */
246 case SYS_fchmod: /* set both */
247 sysx = SYS_fchmodat;
248 goto def;
249
250 case SYS_chown: /* set both */
251 case SYS_lchown: /* set both */
252 case SYS_fchown: /* set both */
253 sysx = SYS_fchownat;
254 goto def;
255
256 case SYS_mkdir: /* set both */
257 sysx = SYS_mkdirat;
258 goto def;
259
260 case SYS_mknod: /* set both */
261 sysx = SYS_mknodat;
262 goto def;
263
264 case SYS_access: /* set both */
265 sysx = SYS_faccessat;
266 goto def;
267
268 default:
269 def:
270 if (exclude) {
271 prdelset(setp, sys);
272 if (sysx)
273 prdelset(setp, sysx);
274 if (sysxx)
275 prdelset(setp, sysxx);
276 if (sys64)
277 prdelset(setp, sys64);
278 } else {
279 praddset(setp, sys);
280 if (sysx)
281 praddset(setp, sysx);
282 if (sysxx)
283 praddset(setp, sysxx);
284 if (sys64)
285 praddset(setp, sys64);
286 }
287 break;
288 }
289 } else if (strcmp(name, "all") == 0 ||
290 strcmp(name, "ALL") == 0) {
291 if (exclude) {
292 premptyset(setp);
293 } else {
294 prfillset(setp);
295 }
296 } else {
297 (void) fprintf(stderr,
298 "%s: unrecognized syscall: %s\n",
299 command, name);
300 rc = -1;
301 }
302 }
303
304 return (rc);
305 }
306
307 /*
308 * List of signals to trace.
309 * Return 0 on success, != 0 on any failure.
310 */
311 int
siglist(private_t * pri,char * str,sigset_t * setp,int * fp)312 siglist(private_t *pri,
313 char *str, /* string of signal names */
314 sigset_t *setp, /* signal set */
315 int *fp) /* first-time flag */
316 {
317 char *name;
318 int exclude = FALSE;
319 int rc = 0;
320 char *lasts;
321
322 upcase(str);
323 name = strtok_r(str, sepr, &lasts);
324
325 if (name != NULL && *name == '!') { /* exclude from set */
326 exclude = TRUE;
327 if (*++name == '\0')
328 name = strtok_r(NULL, sepr, &lasts);
329 } else if (!*fp) { /* first time, clear the set */
330 premptyset(setp);
331 *fp = TRUE;
332 }
333
334 for (; name; name = strtok_r(NULL, sepr, &lasts)) {
335 int sig;
336 char *next;
337
338 if (*name == '!') { /* exclude remainder from set */
339 exclude = TRUE;
340 while (*++name == '!')
341 /* empty */;
342 if (*name == '\0')
343 continue;
344 }
345
346 sig = strtol(name, &next, 0);
347 if (sig <= 0 || sig > PRMAXSIG || *next != '\0') {
348 for (sig = 1; sig <= PRMAXSIG; sig++) {
349 const char *sname = rawsigname(pri, sig);
350 if (sname == NULL)
351 continue;
352 if (strcmp(sname, name) == 0 ||
353 strcmp(sname+3, name) == 0)
354 break;
355 }
356 if (sig > PRMAXSIG)
357 sig = 0;
358 }
359 if (sig > 0 && sig <= PRMAXSIG) {
360 if (exclude) {
361 prdelset(setp, sig);
362 } else {
363 praddset(setp, sig);
364 }
365 } else if (strcmp(name, "ALL") == 0) {
366 if (exclude) {
367 premptyset(setp);
368 } else {
369 prfillset(setp);
370 }
371 } else {
372 (void) fprintf(stderr,
373 "%s: unrecognized signal name/number: %s\n",
374 command, name);
375 rc = -1;
376 }
377 }
378
379 return (rc);
380 }
381
382 /*
383 * List of faults to trace.
384 * return 0 on success, != 0 on any failure.
385 */
386 int
fltlist(char * str,fltset_t * setp,int * fp)387 fltlist(char *str, /* string of fault names */
388 fltset_t *setp, /* fault set */
389 int *fp) /* first-time flag */
390 {
391 char *name;
392 int exclude = FALSE;
393 int rc = 0;
394 char *lasts;
395
396 upcase(str);
397 name = strtok_r(str, sepr, &lasts);
398
399 if (name != NULL && *name == '!') { /* exclude from set */
400 exclude = TRUE;
401 if (*++name == '\0')
402 name = strtok_r(NULL, sepr, &lasts);
403 } else if (!*fp) { /* first time, clear the set */
404 premptyset(setp);
405 *fp = TRUE;
406 }
407
408 for (; name; name = strtok_r(NULL, sepr, &lasts)) {
409 int flt;
410 char *next;
411
412 if (*name == '!') { /* exclude remainder from set */
413 exclude = TRUE;
414 while (*++name == '!')
415 /* empty */;
416 if (*name == '\0')
417 continue;
418 }
419
420 flt = strtol(name, &next, 0);
421 if (flt <= 0 || flt > PRMAXFAULT || *next != '\0') {
422 for (flt = 1; flt <= PRMAXFAULT; flt++) {
423 char fname[32];
424
425 if (proc_fltname(flt, fname,
426 sizeof (fname)) == NULL)
427 continue;
428
429 if (strcmp(fname, name) == 0 ||
430 strcmp(fname+3, name) == 0)
431 break;
432 }
433 if (flt > PRMAXFAULT)
434 flt = 0;
435 }
436 if (flt > 0 && flt <= PRMAXFAULT) {
437 if (exclude) {
438 prdelset(setp, flt);
439 } else {
440 praddset(setp, flt);
441 }
442 } else if (strcmp(name, "ALL") == 0) {
443 if (exclude) {
444 premptyset(setp);
445 } else {
446 prfillset(setp);
447 }
448 } else {
449 (void) fprintf(stderr,
450 "%s: unrecognized fault name/number: %s\n",
451 command, name);
452 rc = -1;
453 }
454 }
455
456 return (rc);
457 }
458
459 /*
460 * Gather file descriptors to dump.
461 * Return 0 on success, != 0 on any failure.
462 */
463 int
fdlist(char * str,fileset_t * setp)464 fdlist(char *str, /* string of filedescriptors */
465 fileset_t *setp) /* set of boolean flags */
466 {
467 char *name;
468 int exclude = FALSE;
469 int rc = 0;
470 char *lasts;
471
472 upcase(str);
473 name = strtok_r(str, sepr, &lasts);
474
475 if (name != NULL && *name == '!') { /* exclude from set */
476 exclude = TRUE;
477 if (*++name == '\0')
478 name = strtok_r(NULL, sepr, &lasts);
479 }
480
481 for (; name; name = strtok_r(NULL, sepr, &lasts)) {
482 int fd;
483 char *next;
484
485 if (*name == '!') { /* exclude remainder from set */
486 exclude = TRUE;
487 while (*++name == '!')
488 /* empty */;
489 if (*name == '\0')
490 continue;
491 }
492
493 fd = strtol(name, &next, 0);
494 if (fd >= 0 && fd < NOFILES_MAX && *next == '\0') {
495 fd++;
496 if (exclude) {
497 prdelset(setp, fd);
498 } else {
499 praddset(setp, fd);
500 }
501 } else if (strcmp(name, "ALL") == 0) {
502 if (exclude) {
503 premptyset(setp);
504 } else {
505 prfillset(setp);
506 }
507 } else {
508 (void) fprintf(stderr,
509 "%s: filedescriptor not in range[0..%d]: %s\n",
510 command, NOFILES_MAX-1, name);
511 rc = -1;
512 }
513 }
514
515 return (rc);
516 }
517
518 void
upcase(char * str)519 upcase(char *str)
520 {
521 int c;
522
523 while ((c = *str) != '\0')
524 *str++ = toupper(c);
525 }
526
527 /*
528 * 'arg' points to a string like:
529 * libc,libnsl,... : printf,read,write,...
530 * or
531 * libc,libnsl,... :: printf,read,write,...
532 * with possible filename pattern-matching metacharacters.
533 *
534 * Assumption: No library or function name can contain ',' or ':'.
535 */
536 int
liblist(char * arg,int hang)537 liblist(char *arg, int hang)
538 {
539 const char *star = "*";
540 struct dynpat *Dyp;
541 char *pat;
542 char *fpat;
543 char *lasts;
544 uint_t maxpat;
545
546 /* append a new dynpat structure to the end of the Dynpat list */
547 Dyp = my_malloc(sizeof (struct dynpat), NULL);
548 Dyp->next = NULL;
549 if (Lastpat == NULL)
550 Dynpat = Lastpat = Dyp;
551 else {
552 Lastpat->next = Dyp;
553 Lastpat = Dyp;
554 }
555 Dyp->flag = hang? BPT_HANG : 0;
556 Dyp->exclude_lib = 0;
557 Dyp->exclude = 0;
558 Dyp->internal = 0;
559 Dyp->Dp = NULL;
560
561 /*
562 * Find the beginning of the filename patterns
563 * and null-terminate the library name patterns.
564 */
565 if ((fpat = strchr(arg, ':')) != NULL)
566 *fpat++ = '\0';
567
568 /*
569 * Library name patterns.
570 */
571 pat = strtok_r(arg, sepr, &lasts);
572
573 /* '!' introduces an exclusion list */
574 if (pat != NULL && *pat == '!') {
575 Dyp->exclude_lib = 1;
576 pat += strspn(pat, "!");
577 if (*pat == '\0')
578 pat = strtok_r(NULL, sepr, &lasts);
579 /* force exclusion of all functions as well */
580 Dyp->exclude = 1;
581 Dyp->internal = 1;
582 fpat = NULL;
583 }
584
585 if (pat == NULL) {
586 /* empty list means all libraries */
587 Dyp->libpat = my_malloc(sizeof (char *), NULL);
588 Dyp->libpat[0] = star;
589 Dyp->nlibpat = 1;
590 } else {
591 /*
592 * We are now at the library list.
593 * Generate the list and count the library name patterns.
594 */
595 maxpat = 1;
596 Dyp->libpat = my_malloc(maxpat * sizeof (char *), NULL);
597 Dyp->nlibpat = 0;
598 Dyp->libpat[Dyp->nlibpat++] = pat;
599 while ((pat = strtok_r(NULL, sepr, &lasts)) != NULL) {
600 if (Dyp->nlibpat == maxpat) {
601 maxpat *= 2;
602 Dyp->libpat = my_realloc(Dyp->libpat,
603 maxpat * sizeof (char *), NULL);
604 }
605 Dyp->libpat[Dyp->nlibpat++] = pat;
606 }
607 }
608
609 /*
610 * Function name patterns.
611 */
612 if (fpat == NULL)
613 pat = NULL;
614 else {
615 /*
616 * We have already seen a ':'. Look for another.
617 * Double ':' means trace internal calls.
618 */
619 fpat += strspn(fpat, white);
620 if (*fpat == ':') {
621 Dyp->internal = 1;
622 *fpat++ = '\0';
623 }
624 pat = strtok_r(fpat, csepr, &lasts);
625 }
626
627 /* '!' introduces an exclusion list */
628 if (pat != NULL && *pat == '!') {
629 Dyp->exclude = 1;
630 Dyp->internal = 1;
631 pat += strspn(pat, "!");
632 if (*pat == '\0')
633 pat = strtok_r(NULL, sepr, &lasts);
634 }
635
636 if (pat == NULL) {
637 /* empty function list means exclude all functions */
638 Dyp->sympat = my_malloc(sizeof (char *), NULL);
639 Dyp->sympat[0] = star;
640 Dyp->nsympat = 1;
641 } else {
642 /*
643 * We are now at the function list.
644 * Generate the list and count the symbol name patterns.
645 */
646 maxpat = 1;
647 Dyp->sympat = my_malloc(maxpat * sizeof (char *), NULL);
648 Dyp->nsympat = 0;
649 Dyp->sympat[Dyp->nsympat++] = pat;
650 while ((pat = strtok_r(NULL, sepr, &lasts)) != NULL) {
651 if (Dyp->nsympat == maxpat) {
652 maxpat *= 2;
653 Dyp->sympat = my_realloc(Dyp->sympat,
654 maxpat * sizeof (char *), NULL);
655 }
656 Dyp->sympat[Dyp->nsympat++] = pat;
657 }
658 }
659
660 return (0);
661 }
662