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