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