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