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