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 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 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 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 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 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 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