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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 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 31 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */ 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <ctype.h> 37 #include <string.h> 38 #include <memory.h> 39 #include <sys/types.h> 40 #include <signal.h> 41 #include <libproc.h> 42 #include "ramdata.h" 43 #include "systable.h" 44 #include "proto.h" 45 46 /* XXX A bug in the <string.h> header file requires this */ 47 extern char *strtok_r(char *s1, const char *s2, char **lasts); 48 49 /* 50 * option procesing --- 51 * Routines for scanning syscall, signal, fault 52 * and file descriptor lists. 53 */ 54 55 /* 56 * Function prototypes for static routines in this module. 57 */ 58 void upcase(char *); 59 60 const char white[] = " \t\n"; /* white space characters */ 61 const char sepr[] = " ,\t\n"; /* list separator characters */ 62 const char csepr[] = " :,\t\n"; /* same, with ':' added */ 63 64 /* 65 * Scan list of syscall names. 66 * Return 0 on success, != 0 on any failure. 67 */ 68 int 69 syslist(char *str, /* string of syscall names */ 70 sysset_t *setp, /* syscall set */ 71 int *fp) /* first-time flag */ 72 { 73 char *name; 74 int exclude = FALSE; 75 int rc = 0; 76 char *lasts; 77 78 name = strtok_r(str, sepr, &lasts); 79 80 if (name != NULL && *name == '!') { /* exclude from set */ 81 exclude = TRUE; 82 if (*++name == '\0') 83 name = strtok_r(NULL, sepr, &lasts); 84 } else if (!*fp) { /* first time, clear the set */ 85 premptyset(setp); 86 *fp = TRUE; 87 } 88 89 for (; name; name = strtok_r(NULL, sepr, &lasts)) { 90 int sys; 91 int sysx; 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 = 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 sys = SYS_forkall; 215 sysx = SYS_fork1; 216 sys64 = SYS_vfork; 217 goto def; 218 219 case SYS_exec: /* set both if either */ 220 case SYS_execve: 221 sysx = SYS_exec; 222 sys = SYS_execve; 223 goto def; 224 225 case SYS_poll: /* set both if either */ 226 case SYS_pollsys: 227 sysx = SYS_poll; 228 sys = SYS_pollsys; 229 goto def; 230 231 case SYS_sigprocmask: /* set both if either */ 232 case SYS_lwp_sigmask: 233 sysx = SYS_sigprocmask; 234 sys = SYS_lwp_sigmask; 235 goto def; 236 237 case SYS_wait: /* set both if either */ 238 case SYS_waitsys: 239 sysx = SYS_wait; 240 sys = SYS_waitsys; 241 goto def; 242 243 case SYS_lseek: /* set both if either */ 244 case SYS_llseek: 245 sysx = SYS_lseek; 246 sys = SYS_llseek; 247 goto def; 248 249 case SYS_lwp_mutex_lock: /* set both if either */ 250 case SYS_lwp_mutex_timedlock: 251 sysx = SYS_lwp_mutex_lock; 252 sys = SYS_lwp_mutex_timedlock; 253 goto def; 254 255 case SYS_lwp_sema_wait: /* set both if either */ 256 case SYS_lwp_sema_timedwait: 257 sysx = SYS_lwp_sema_wait; 258 sys = SYS_lwp_sema_timedwait; 259 goto def; 260 261 default: 262 def: 263 if (exclude) { 264 prdelset(setp, sys); 265 if (sysx) 266 prdelset(setp, sysx); 267 if (sys64) 268 prdelset(setp, sys64); 269 } else { 270 praddset(setp, sys); 271 if (sysx) 272 praddset(setp, sysx); 273 if (sys64) 274 praddset(setp, sys64); 275 } 276 break; 277 } 278 } else if (strcmp(name, "all") == 0 || 279 strcmp(name, "ALL") == 0) { 280 if (exclude) { 281 premptyset(setp); 282 } else { 283 prfillset(setp); 284 } 285 } else { 286 (void) fprintf(stderr, 287 "%s: unrecognized syscall: %s\n", 288 command, name); 289 rc = -1; 290 } 291 } 292 293 return (rc); 294 } 295 296 /* 297 * List of signals to trace. 298 * Return 0 on success, != 0 on any failure. 299 */ 300 int 301 siglist(private_t *pri, 302 char *str, /* string of signal names */ 303 sigset_t *setp, /* signal set */ 304 int *fp) /* first-time flag */ 305 { 306 char *name; 307 int exclude = FALSE; 308 int rc = 0; 309 char *lasts; 310 311 upcase(str); 312 name = strtok_r(str, sepr, &lasts); 313 314 if (name != NULL && *name == '!') { /* exclude from set */ 315 exclude = TRUE; 316 if (*++name == '\0') 317 name = strtok_r(NULL, sepr, &lasts); 318 } else if (!*fp) { /* first time, clear the set */ 319 premptyset(setp); 320 *fp = TRUE; 321 } 322 323 for (; name; name = strtok_r(NULL, sepr, &lasts)) { 324 int sig; 325 char *next; 326 327 if (*name == '!') { /* exclude remainder from set */ 328 exclude = TRUE; 329 while (*++name == '!') 330 /* empty */; 331 if (*name == '\0') 332 continue; 333 } 334 335 sig = strtol(name, &next, 0); 336 if (sig <= 0 || sig > PRMAXSIG || *next != '\0') { 337 for (sig = 1; sig <= PRMAXSIG; sig++) { 338 const char *sname = rawsigname(pri, sig); 339 if (sname == NULL) 340 continue; 341 if (strcmp(sname, name) == 0 || 342 strcmp(sname+3, name) == 0) 343 break; 344 } 345 if (sig > PRMAXSIG) 346 sig = 0; 347 } 348 if (sig > 0 && sig <= PRMAXSIG) { 349 if (exclude) { 350 prdelset(setp, sig); 351 } else { 352 praddset(setp, sig); 353 } 354 } else if (strcmp(name, "ALL") == 0) { 355 if (exclude) { 356 premptyset(setp); 357 } else { 358 prfillset(setp); 359 } 360 } else { 361 (void) fprintf(stderr, 362 "%s: unrecognized signal name/number: %s\n", 363 command, name); 364 rc = -1; 365 } 366 } 367 368 return (rc); 369 } 370 371 /* 372 * List of faults to trace. 373 * return 0 on success, != 0 on any failure. 374 */ 375 int 376 fltlist(char *str, /* string of fault names */ 377 fltset_t *setp, /* fault set */ 378 int *fp) /* first-time flag */ 379 { 380 char *name; 381 int exclude = FALSE; 382 int rc = 0; 383 char *lasts; 384 385 upcase(str); 386 name = strtok_r(str, sepr, &lasts); 387 388 if (name != NULL && *name == '!') { /* exclude from set */ 389 exclude = TRUE; 390 if (*++name == '\0') 391 name = strtok_r(NULL, sepr, &lasts); 392 } else if (!*fp) { /* first time, clear the set */ 393 premptyset(setp); 394 *fp = TRUE; 395 } 396 397 for (; name; name = strtok_r(NULL, sepr, &lasts)) { 398 int flt; 399 char *next; 400 401 if (*name == '!') { /* exclude remainder from set */ 402 exclude = TRUE; 403 while (*++name == '!') 404 /* empty */; 405 if (*name == '\0') 406 continue; 407 } 408 409 flt = strtol(name, &next, 0); 410 if (flt <= 0 || flt > PRMAXFAULT || *next != '\0') { 411 for (flt = 1; flt <= PRMAXFAULT; flt++) { 412 char fname[32]; 413 414 if (proc_fltname(flt, fname, 415 sizeof (fname)) == NULL) 416 continue; 417 418 if (strcmp(fname, name) == 0 || 419 strcmp(fname+3, name) == 0) 420 break; 421 } 422 if (flt > PRMAXFAULT) 423 flt = 0; 424 } 425 if (flt > 0 && flt <= PRMAXFAULT) { 426 if (exclude) { 427 prdelset(setp, flt); 428 } else { 429 praddset(setp, flt); 430 } 431 } else if (strcmp(name, "ALL") == 0) { 432 if (exclude) { 433 premptyset(setp); 434 } else { 435 prfillset(setp); 436 } 437 } else { 438 (void) fprintf(stderr, 439 "%s: unrecognized fault name/number: %s\n", 440 command, name); 441 rc = -1; 442 } 443 } 444 445 return (rc); 446 } 447 448 /* 449 * Gather file descriptors to dump. 450 * Return 0 on success, != 0 on any failure. 451 */ 452 int 453 fdlist(char *str, /* string of filedescriptors */ 454 fileset_t *setp) /* set of boolean flags */ 455 { 456 char *name; 457 int exclude = FALSE; 458 int rc = 0; 459 char *lasts; 460 461 upcase(str); 462 name = strtok_r(str, sepr, &lasts); 463 464 if (name != NULL && *name == '!') { /* exclude from set */ 465 exclude = TRUE; 466 if (*++name == '\0') 467 name = strtok_r(NULL, sepr, &lasts); 468 } 469 470 for (; name; name = strtok_r(NULL, sepr, &lasts)) { 471 int fd; 472 char *next; 473 474 if (*name == '!') { /* exclude remainder from set */ 475 exclude = TRUE; 476 while (*++name == '!') 477 /* empty */; 478 if (*name == '\0') 479 continue; 480 } 481 482 fd = strtol(name, &next, 0); 483 if (fd >= 0 && fd < NOFILES_MAX && *next == '\0') { 484 fd++; 485 if (exclude) { 486 prdelset(setp, fd); 487 } else { 488 praddset(setp, fd); 489 } 490 } else if (strcmp(name, "ALL") == 0) { 491 if (exclude) { 492 premptyset(setp); 493 } else { 494 prfillset(setp); 495 } 496 } else { 497 (void) fprintf(stderr, 498 "%s: filedescriptor not in range[0..%d]: %s\n", 499 command, NOFILES_MAX-1, name); 500 rc = -1; 501 } 502 } 503 504 return (rc); 505 } 506 507 void 508 upcase(char *str) 509 { 510 int c; 511 512 while ((c = *str) != '\0') 513 *str++ = toupper(c); 514 } 515 516 /* 517 * 'arg' points to a string like: 518 * libc,libnsl,... : printf,read,write,... 519 * or 520 * libc,libnsl,... :: printf,read,write,... 521 * with possible filename pattern-matching metacharacters. 522 * 523 * Assumption: No library or function name can contain ',' or ':'. 524 */ 525 int 526 liblist(char *arg, int hang) 527 { 528 const char *star = "*"; 529 struct dynpat *Dyp; 530 char *pat; 531 char *fpat; 532 char *lasts; 533 uint_t maxpat; 534 535 /* append a new dynpat structure to the end of the Dynpat list */ 536 Dyp = my_malloc(sizeof (struct dynpat), NULL); 537 Dyp->next = NULL; 538 if (Lastpat == NULL) 539 Dynpat = Lastpat = Dyp; 540 else { 541 Lastpat->next = Dyp; 542 Lastpat = Dyp; 543 } 544 Dyp->flag = hang? BPT_HANG : 0; 545 Dyp->exclude_lib = 0; 546 Dyp->exclude = 0; 547 Dyp->internal = 0; 548 Dyp->Dp = NULL; 549 550 /* 551 * Find the beginning of the filename patterns 552 * and null-terminate the library name patterns. 553 */ 554 if ((fpat = strchr(arg, ':')) != NULL) 555 *fpat++ = '\0'; 556 557 /* 558 * Library name patterns. 559 */ 560 pat = strtok_r(arg, sepr, &lasts); 561 562 /* '!' introduces an exclusion list */ 563 if (pat != NULL && *pat == '!') { 564 Dyp->exclude_lib = 1; 565 pat += strspn(pat, "!"); 566 if (*pat == '\0') 567 pat = strtok_r(NULL, sepr, &lasts); 568 /* force exclusion of all functions as well */ 569 Dyp->exclude = 1; 570 Dyp->internal = 1; 571 fpat = NULL; 572 } 573 574 if (pat == NULL) { 575 /* empty list means all libraries */ 576 Dyp->libpat = my_malloc(sizeof (char *), NULL); 577 Dyp->libpat[0] = star; 578 Dyp->nlibpat = 1; 579 } else { 580 /* 581 * We are now at the library list. 582 * Generate the list and count the library name patterns. 583 */ 584 maxpat = 1; 585 Dyp->libpat = my_malloc(maxpat * sizeof (char *), NULL); 586 Dyp->nlibpat = 0; 587 Dyp->libpat[Dyp->nlibpat++] = pat; 588 while ((pat = strtok_r(NULL, sepr, &lasts)) != NULL) { 589 if (Dyp->nlibpat == maxpat) { 590 maxpat *= 2; 591 Dyp->libpat = my_realloc(Dyp->libpat, 592 maxpat * sizeof (char *), NULL); 593 } 594 Dyp->libpat[Dyp->nlibpat++] = pat; 595 } 596 } 597 598 /* 599 * Function name patterns. 600 */ 601 if (fpat == NULL) 602 pat = NULL; 603 else { 604 /* 605 * We have already seen a ':'. Look for another. 606 * Double ':' means trace internal calls. 607 */ 608 fpat += strspn(fpat, white); 609 if (*fpat == ':') { 610 Dyp->internal = 1; 611 *fpat++ = '\0'; 612 } 613 pat = strtok_r(fpat, csepr, &lasts); 614 } 615 616 /* '!' introduces an exclusion list */ 617 if (pat != NULL && *pat == '!') { 618 Dyp->exclude = 1; 619 Dyp->internal = 1; 620 pat += strspn(pat, "!"); 621 if (*pat == '\0') 622 pat = strtok_r(NULL, sepr, &lasts); 623 } 624 625 if (pat == NULL) { 626 /* empty function list means exclude all functions */ 627 Dyp->sympat = my_malloc(sizeof (char *), NULL); 628 Dyp->sympat[0] = star; 629 Dyp->nsympat = 1; 630 } else { 631 /* 632 * We are now at the function list. 633 * Generate the list and count the symbol name patterns. 634 */ 635 maxpat = 1; 636 Dyp->sympat = my_malloc(maxpat * sizeof (char *), NULL); 637 Dyp->nsympat = 0; 638 Dyp->sympat[Dyp->nsympat++] = pat; 639 while ((pat = strtok_r(NULL, sepr, &lasts)) != NULL) { 640 if (Dyp->nsympat == maxpat) { 641 maxpat *= 2; 642 Dyp->sympat = my_realloc(Dyp->sympat, 643 maxpat * sizeof (char *), NULL); 644 } 645 Dyp->sympat[Dyp->nsympat++] = pat; 646 } 647 } 648 649 return (0); 650 } 651