1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 1914 casper * Common Development and Distribution License (the "License"). 6 1914 casper * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 1132 raf 22 0 stevel /* 23 5355 rh87107 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 0 stevel * Use is subject to license terms. 25 0 stevel */ 26 0 stevel 27 0 stevel /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 0 stevel 29 0 stevel #pragma ident "%Z%%M% %I% %E% SMI" 30 0 stevel 31 0 stevel #include <stdio.h> 32 1914 casper #include <stdio_ext.h> 33 0 stevel #include <stdlib.h> 34 0 stevel #include <unistd.h> 35 0 stevel #include <fcntl.h> 36 0 stevel #include <ctype.h> 37 0 stevel #include <string.h> 38 0 stevel #include <memory.h> 39 0 stevel #include <signal.h> 40 0 stevel #include <wait.h> 41 0 stevel #include <limits.h> 42 0 stevel #include <errno.h> 43 0 stevel #include <sys/types.h> 44 0 stevel #include <sys/time.h> 45 0 stevel #include <sys/times.h> 46 0 stevel #include <sys/fstyp.h> 47 0 stevel #include <sys/fsid.h> 48 0 stevel #include <sys/stat.h> 49 0 stevel #include <sys/mman.h> 50 0 stevel #include <sys/resource.h> 51 0 stevel #include <libproc.h> 52 0 stevel #include "ramdata.h" 53 0 stevel #include "proto.h" 54 0 stevel #include "htbl.h" 55 0 stevel 56 0 stevel /* 57 0 stevel * The user can trace individual threads by using the 'pid/1,3-6,8-' syntax. 58 0 stevel * This structure keeps track of pid/lwp specifications. If there are no LWPs 59 0 stevel * specified, then 'lwps' will be NULL. 60 0 stevel */ 61 0 stevel typedef struct proc_set { 62 0 stevel pid_t pid; 63 0 stevel const char *lwps; 64 0 stevel } proc_set_t; 65 0 stevel 66 0 stevel /* 67 0 stevel * Function prototypes for static routines in this file. 68 0 stevel */ 69 0 stevel void setup_basetime(hrtime_t, struct timeval *); 70 0 stevel int xcreat(char *); 71 0 stevel void setoutput(int); 72 0 stevel void report(private_t *, time_t); 73 0 stevel void prtim(timestruc_t *); 74 0 stevel void pids(char *, proc_set_t *); 75 0 stevel void psargs(private_t *); 76 0 stevel int control(private_t *, pid_t); 77 0 stevel int grabit(private_t *, proc_set_t *); 78 0 stevel void release(private_t *, pid_t); 79 0 stevel void intr(int); 80 0 stevel int wait4all(void); 81 0 stevel void letgo(private_t *); 82 0 stevel void child_to_file(); 83 0 stevel void file_to_parent(); 84 0 stevel void per_proc_init(); 85 0 stevel int lib_sort(const void *, const void *); 86 0 stevel int key_sort(const void *, const void *); 87 0 stevel 88 0 stevel void *worker_thread(void *); 89 0 stevel void main_thread(int); 90 0 stevel 91 0 stevel /* 92 0 stevel * Test for empty set. 93 0 stevel * is_empty() should not be called directly. 94 0 stevel */ 95 0 stevel int is_empty(const uint32_t *, size_t); 96 0 stevel #define isemptyset(sp) \ 97 0 stevel is_empty((uint32_t *)(sp), sizeof (*(sp)) / sizeof (uint32_t)) 98 0 stevel 99 0 stevel /* 100 0 stevel * OR the second set into the first set. 101 0 stevel * or_set() should not be called directly. 102 0 stevel */ 103 0 stevel void or_set(uint32_t *, const uint32_t *, size_t); 104 0 stevel #define prorset(sp1, sp2) \ 105 0 stevel or_set((uint32_t *)(sp1), (uint32_t *)(sp2), \ 106 0 stevel sizeof (*(sp1)) / sizeof (uint32_t)) 107 0 stevel 108 0 stevel /* fetch or allocate thread-private data */ 109 0 stevel private_t * 110 0 stevel get_private() 111 0 stevel { 112 0 stevel void *value; 113 0 stevel private_t *pri = NULL; 114 0 stevel 115 0 stevel if (thr_getspecific(private_key, &value) == 0) 116 0 stevel pri = value; 117 0 stevel if (pri == NULL) { 118 0 stevel pri = my_malloc(sizeof (*pri), NULL); 119 0 stevel (void) memset(pri, 0, sizeof (*pri)); 120 0 stevel pri->sys_path = my_malloc(pri->sys_psize = 16, NULL); 121 0 stevel pri->sys_string = my_malloc(pri->sys_ssize = 32, NULL); 122 0 stevel if (thr_setspecific(private_key, pri) == ENOMEM) 123 0 stevel abend("memory allocation failure", NULL); 124 0 stevel } 125 0 stevel return (pri); 126 0 stevel } 127 0 stevel 128 0 stevel /* destructor function for thread-private data */ 129 0 stevel void 130 0 stevel free_private(void *value) 131 0 stevel { 132 0 stevel private_t *pri = value; 133 0 stevel 134 0 stevel if (pri->sys_path) 135 0 stevel free(pri->sys_path); 136 0 stevel if (pri->sys_string) 137 0 stevel free(pri->sys_string); 138 0 stevel if (pri->exec_string) 139 0 stevel free(pri->exec_string); 140 0 stevel if (pri->str_buffer) 141 0 stevel free(pri->str_buffer); 142 0 stevel free(pri); 143 0 stevel } 144 0 stevel 145 0 stevel /* 146 0 stevel * This is called by the main thread (via create_thread()) 147 0 stevel * and is also called from other threads in worker_thread() 148 0 stevel * while holding truss_lock. No further locking is required. 149 0 stevel */ 150 0 stevel void 151 0 stevel insert_lwpid(lwpid_t lwpid) 152 0 stevel { 153 0 stevel int i; 154 0 stevel 155 0 stevel truss_nlwp++; 156 0 stevel for (i = 0; i < truss_maxlwp; i++) { 157 0 stevel if (truss_lwpid[i] == 0) 158 0 stevel break; 159 0 stevel } 160 0 stevel if (i == truss_maxlwp) { 161 0 stevel /* double the size of the array */ 162 0 stevel truss_lwpid = my_realloc(truss_lwpid, 163 0 stevel truss_maxlwp * 2 * sizeof (lwpid_t), NULL); 164 0 stevel (void) memset(&truss_lwpid[truss_maxlwp], 0, 165 0 stevel truss_maxlwp * sizeof (lwpid_t)); 166 0 stevel truss_maxlwp *= 2; 167 0 stevel } 168 0 stevel truss_lwpid[i] = lwpid; 169 0 stevel } 170 0 stevel 171 0 stevel /* 172 1132 raf * This is called from the first worker thread to encounter one of 173 1132 raf * (leave_hung || interrupt || sigusr1). It must notify all other 174 1132 raf * worker threads of the same condition. truss_lock is held. 175 0 stevel */ 176 0 stevel void 177 1132 raf broadcast_signals(void) 178 0 stevel { 179 0 stevel static int int_notified = FALSE; 180 0 stevel static int usr1_notified = FALSE; 181 0 stevel static int usr2_notified = FALSE; 182 1132 raf lwpid_t my_id = thr_self(); 183 1132 raf lwpid_t lwpid; 184 0 stevel int i; 185 0 stevel 186 0 stevel if (interrupt && !int_notified) { 187 0 stevel int_notified = TRUE; 188 0 stevel for (i = 0; i < truss_maxlwp; i++) { 189 1132 raf if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id) 190 1132 raf (void) thr_kill(lwpid, interrupt); 191 0 stevel } 192 0 stevel } 193 0 stevel if (sigusr1 && !usr1_notified) { 194 0 stevel usr1_notified = TRUE; 195 0 stevel for (i = 0; i < truss_maxlwp; i++) { 196 1132 raf if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id) 197 1132 raf (void) thr_kill(lwpid, SIGUSR1); 198 0 stevel } 199 0 stevel } 200 0 stevel if (leave_hung && !usr2_notified) { 201 0 stevel usr2_notified = TRUE; 202 0 stevel for (i = 0; i < truss_maxlwp; i++) { 203 1132 raf if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id) 204 1132 raf (void) thr_kill(lwpid, SIGUSR2); 205 0 stevel } 206 0 stevel } 207 0 stevel } 208 0 stevel 209 0 stevel static struct ps_lwphandle * 210 0 stevel grab_lwp(lwpid_t who) 211 0 stevel { 212 0 stevel struct ps_lwphandle *Lwp; 213 0 stevel int gcode; 214 0 stevel 215 0 stevel if ((Lwp = Lgrab(Proc, who, &gcode)) == NULL) { 216 0 stevel if (gcode != G_NOPROC) { 217 0 stevel (void) fprintf(stderr, 218 0 stevel "%s: cannot grab LWP %u in process %d," 219 0 stevel " reason: %s\n", 220 0 stevel command, who, (int)Pstatus(Proc)->pr_pid, 221 0 stevel Lgrab_error(gcode)); 222 0 stevel interrupt = SIGTERM; /* post an interrupt */ 223 0 stevel } 224 0 stevel } 225 0 stevel return (Lwp); 226 0 stevel } 227 0 stevel 228 0 stevel /* 229 0 stevel * Iteration function called for each initial lwp in the controlled process. 230 0 stevel */ 231 0 stevel /* ARGSUSED */ 232 0 stevel int 233 0 stevel create_thread(void *arg, const lwpstatus_t *Lsp) 234 0 stevel { 235 0 stevel struct ps_lwphandle *new_Lwp; 236 0 stevel lwpid_t lwpid; 237 0 stevel int *count = arg; 238 0 stevel 239 0 stevel if (lwptrace(Pstatus(Proc)->pr_pid, Lsp->pr_lwpid)) 240 0 stevel *count += 1; 241 0 stevel 242 0 stevel if ((new_Lwp = grab_lwp(Lsp->pr_lwpid)) != NULL) { 243 0 stevel if (thr_create(NULL, 0, worker_thread, new_Lwp, 244 0 stevel THR_BOUND | THR_SUSPENDED, &lwpid) != 0) 245 0 stevel abend("cannot create lwp to follow child lwp", NULL); 246 0 stevel insert_lwpid(lwpid); 247 0 stevel } 248 0 stevel return (0); 249 0 stevel } 250 0 stevel 251 0 stevel int 252 0 stevel main(int argc, char *argv[]) 253 0 stevel { 254 0 stevel private_t *pri; 255 0 stevel struct tms tms; 256 0 stevel struct rlimit rlim; 257 0 stevel int ofd = -1; 258 0 stevel int opt; 259 0 stevel int i; 260 0 stevel int first; 261 0 stevel int errflg = FALSE; 262 0 stevel int badname = FALSE; 263 0 stevel proc_set_t *grab = NULL; 264 0 stevel const pstatus_t *Psp; 265 0 stevel const lwpstatus_t *Lsp; 266 0 stevel int sharedmem; 267 0 stevel 268 0 stevel /* a few of these need to be initialized to NULL */ 269 0 stevel Cp = NULL; 270 0 stevel fcall_tbl = NULL; 271 0 stevel 272 0 stevel /* 273 0 stevel * Make sure fd's 0, 1, and 2 are allocated, 274 0 stevel * just in case truss was invoked from init. 275 0 stevel */ 276 0 stevel while ((i = open("/dev/null", O_RDWR)) >= 0 && i < 2) 277 0 stevel ; 278 0 stevel if (i > 2) 279 0 stevel (void) close(i); 280 0 stevel 281 0 stevel starttime = times(&tms); /* for elapsed timing */ 282 0 stevel 283 0 stevel /* this should be per-traced-process */ 284 0 stevel pagesize = sysconf(_SC_PAGESIZE); 285 0 stevel 286 0 stevel /* command name (e.g., "truss") */ 287 0 stevel if ((command = strrchr(argv[0], '/')) != NULL) 288 0 stevel command++; 289 0 stevel else 290 0 stevel command = argv[0]; 291 0 stevel 292 0 stevel /* set up the initial private data */ 293 0 stevel (void) mutex_init(&truss_lock, USYNC_THREAD, NULL); 294 0 stevel (void) mutex_init(&count_lock, USYNC_THREAD, NULL); 295 0 stevel (void) cond_init(&truss_cv, USYNC_THREAD, NULL); 296 0 stevel if (thr_keycreate(&private_key, free_private) == ENOMEM) 297 0 stevel abend("memory allocation failure", NULL); 298 0 stevel pri = get_private(); 299 0 stevel 300 0 stevel Euid = geteuid(); 301 0 stevel Egid = getegid(); 302 0 stevel Ruid = getuid(); 303 0 stevel Rgid = getgid(); 304 0 stevel ancestor = getpid(); 305 0 stevel 306 0 stevel prfillset(&trace); /* default: trace all system calls */ 307 0 stevel premptyset(&verbose); /* default: no syscall verbosity */ 308 0 stevel premptyset(&rawout); /* default: no raw syscall interpretation */ 309 0 stevel 310 0 stevel prfillset(&signals); /* default: trace all signals */ 311 0 stevel 312 0 stevel prfillset(&faults); /* default: trace all faults */ 313 0 stevel prdelset(&faults, FLTPAGE); /* except this one */ 314 0 stevel 315 0 stevel premptyset(&readfd); /* default: dump no buffers */ 316 0 stevel premptyset(&writefd); 317 0 stevel 318 0 stevel premptyset(&syshang); /* default: hang on no system calls */ 319 0 stevel premptyset(&sighang); /* default: hang on no signals */ 320 0 stevel premptyset(&flthang); /* default: hang on no faults */ 321 1132 raf 322 1132 raf (void) sigemptyset(&emptyset); /* for unblocking all signals */ 323 1132 raf (void) sigfillset(&fillset); /* for blocking all signals */ 324 0 stevel 325 0 stevel #define OPTIONS "FpfcaeildDEht:T:v:x:s:S:m:M:u:U:r:w:o:" 326 0 stevel while ((opt = getopt(argc, argv, OPTIONS)) != EOF) { 327 0 stevel switch (opt) { 328 0 stevel case 'F': /* force grabbing (no O_EXCL) */ 329 0 stevel Fflag = PGRAB_FORCE; 330 0 stevel break; 331 0 stevel case 'p': /* grab processes */ 332 0 stevel pflag = TRUE; 333 0 stevel break; 334 0 stevel case 'f': /* follow children */ 335 0 stevel fflag = TRUE; 336 0 stevel break; 337 0 stevel case 'c': /* don't trace, just count */ 338 0 stevel cflag = TRUE; 339 0 stevel iflag = TRUE; /* implies no interruptable syscalls */ 340 0 stevel break; 341 0 stevel case 'a': /* display argument lists */ 342 0 stevel aflag = TRUE; 343 0 stevel break; 344 0 stevel case 'e': /* display environments */ 345 0 stevel eflag = TRUE; 346 0 stevel break; 347 0 stevel case 'i': /* don't show interruptable syscalls */ 348 0 stevel iflag = TRUE; 349 0 stevel break; 350 0 stevel case 'l': /* show lwp id for each syscall */ 351 0 stevel lflag = TRUE; 352 0 stevel break; 353 0 stevel case 'h': /* debugging: report hash stats */ 354 0 stevel hflag = TRUE; 355 0 stevel break; 356 0 stevel case 'd': /* show time stamps */ 357 0 stevel dflag = TRUE; 358 0 stevel break; 359 0 stevel case 'D': /* show time deltas */ 360 0 stevel Dflag = TRUE; 361 0 stevel break; 362 0 stevel case 'E': 363 0 stevel Eflag = TRUE; /* show syscall times */ 364 0 stevel break; 365 0 stevel case 't': /* system calls to trace */ 366 0 stevel if (syslist(optarg, &trace, &tflag)) 367 0 stevel badname = TRUE; 368 0 stevel break; 369 0 stevel case 'T': /* system calls to hang process */ 370 0 stevel if (syslist(optarg, &syshang, &Tflag)) 371 0 stevel badname = TRUE; 372 0 stevel break; 373 0 stevel case 'v': /* verbose interpretation of syscalls */ 374 0 stevel if (syslist(optarg, &verbose, &vflag)) 375 0 stevel badname = TRUE; 376 0 stevel break; 377 0 stevel case 'x': /* raw interpretation of syscalls */ 378 0 stevel if (syslist(optarg, &rawout, &xflag)) 379 0 stevel badname = TRUE; 380 0 stevel break; 381 0 stevel case 's': /* signals to trace */ 382 0 stevel if (siglist(pri, optarg, &signals, &sflag)) 383 0 stevel badname = TRUE; 384 0 stevel break; 385 0 stevel case 'S': /* signals to hang process */ 386 0 stevel if (siglist(pri, optarg, &sighang, &Sflag)) 387 0 stevel badname = TRUE; 388 0 stevel break; 389 0 stevel case 'm': /* machine faults to trace */ 390 0 stevel if (fltlist(optarg, &faults, &mflag)) 391 0 stevel badname = TRUE; 392 0 stevel break; 393 0 stevel case 'M': /* machine faults to hang process */ 394 0 stevel if (fltlist(optarg, &flthang, &Mflag)) 395 0 stevel badname = TRUE; 396 0 stevel break; 397 0 stevel case 'u': /* user library functions to trace */ 398 0 stevel if (liblist(optarg, 0)) 399 0 stevel badname = TRUE; 400 0 stevel break; 401 0 stevel case 'U': /* user library functions to hang */ 402 0 stevel if (liblist(optarg, 1)) 403 0 stevel badname = TRUE; 404 0 stevel break; 405 0 stevel case 'r': /* show contents of read(fd) */ 406 0 stevel if (fdlist(optarg, &readfd)) 407 0 stevel badname = TRUE; 408 0 stevel break; 409 0 stevel case 'w': /* show contents of write(fd) */ 410 0 stevel if (fdlist(optarg, &writefd)) 411 0 stevel badname = TRUE; 412 0 stevel break; 413 0 stevel case 'o': /* output file for trace */ 414 0 stevel oflag = TRUE; 415 0 stevel if (ofd >= 0) 416 0 stevel (void) close(ofd); 417 0 stevel if ((ofd = xcreat(optarg)) < 0) { 418 0 stevel perror(optarg); 419 0 stevel badname = TRUE; 420 0 stevel } 421 0 stevel break; 422 0 stevel default: 423 0 stevel errflg = TRUE; 424 0 stevel break; 425 0 stevel } 426 0 stevel } 427 0 stevel 428 0 stevel if (badname) 429 0 stevel exit(2); 430 0 stevel 431 0 stevel /* if -a or -e was specified, force tracing of exec() */ 432 0 stevel if (aflag || eflag) { 433 0 stevel praddset(&trace, SYS_exec); 434 0 stevel praddset(&trace, SYS_execve); 435 0 stevel } 436 0 stevel 437 0 stevel /* 438 0 stevel * Make sure that all system calls, signals, and machine faults 439 0 stevel * that hang the process are added to their trace sets. 440 0 stevel */ 441 0 stevel prorset(&trace, &syshang); 442 0 stevel prorset(&signals, &sighang); 443 0 stevel prorset(&faults, &flthang); 444 0 stevel 445 0 stevel argc -= optind; 446 0 stevel argv += optind; 447 0 stevel 448 0 stevel /* collect the specified process ids */ 449 0 stevel if (pflag && argc > 0) { 450 0 stevel grab = my_malloc(argc * sizeof (proc_set_t), 451 0 stevel "memory for process-ids"); 452 0 stevel while (argc-- > 0) 453 0 stevel pids(*argv++, grab); 454 0 stevel } 455 0 stevel 456 0 stevel if (errflg || (argc <= 0 && ngrab <= 0)) { 457 0 stevel (void) fprintf(stderr, 458 0 stevel "usage:\t%s [-fcaeildDEF] [-[tTvx] [!]syscalls] [-[sS] [!]signals]\\\n", 459 0 stevel command); 460 0 stevel (void) fprintf(stderr, 461 0 stevel "\t[-[mM] [!]faults] [-[rw] [!]fds] [-[uU] [!]libs:[:][!]funcs]\\\n"); 462 0 stevel (void) fprintf(stderr, 463 0 stevel "\t[-o outfile] command | -p pid[/lwps] ...\n"); 464 0 stevel exit(2); 465 0 stevel } 466 0 stevel 467 0 stevel if (argc > 0) { /* create the controlled process */ 468 0 stevel int err; 469 0 stevel char path[PATH_MAX]; 470 0 stevel 471 0 stevel Proc = Pcreate(argv[0], &argv[0], &err, path, sizeof (path)); 472 0 stevel if (Proc == NULL) { 473 0 stevel switch (err) { 474 0 stevel case C_PERM: 475 0 stevel (void) fprintf(stderr, 476 0 stevel "%s: cannot trace set-id or " 477 0 stevel "unreadable object file: %s\n", 478 0 stevel command, path); 479 0 stevel break; 480 0 stevel case C_LP64: 481 0 stevel (void) fprintf(stderr, 482 0 stevel "%s: cannot control _LP64 " 483 0 stevel "program: %s\n", 484 0 stevel command, path); 485 0 stevel break; 486 0 stevel case C_NOEXEC: 487 0 stevel (void) fprintf(stderr, 488 0 stevel "%s: cannot execute program: %s\n", 489 0 stevel command, argv[0]); 490 0 stevel break; 491 0 stevel case C_NOENT: 492 0 stevel (void) fprintf(stderr, 493 0 stevel "%s: cannot find program: %s\n", 494 0 stevel command, argv[0]); 495 0 stevel break; 496 0 stevel case C_STRANGE: 497 0 stevel break; 498 0 stevel default: 499 0 stevel (void) fprintf(stderr, "%s: %s\n", 500 0 stevel command, Pcreate_error(err)); 501 0 stevel break; 502 0 stevel } 503 0 stevel exit(2); 504 0 stevel } 505 0 stevel if (fflag || Dynpat != NULL) 506 0 stevel (void) Psetflags(Proc, PR_FORK); 507 0 stevel else 508 0 stevel (void) Punsetflags(Proc, PR_FORK); 509 0 stevel Psp = Pstatus(Proc); 510 0 stevel Lsp = &Psp->pr_lwp; 511 0 stevel pri->lwpstat = Lsp; 512 0 stevel data_model = Psp->pr_dmodel; 513 0 stevel created = Psp->pr_pid; 514 0 stevel make_pname(pri, 0); 515 0 stevel (void) sysentry(pri, 1); 516 0 stevel pri->length = 0; 517 0 stevel if (!cflag && prismember(&trace, SYS_execve)) { 518 0 stevel pri->exec_string = my_realloc(pri->exec_string, 519 0 stevel strlen(pri->sys_string) + 1, NULL); 520 0 stevel (void) strcpy(pri->exec_pname, pri->pname); 521 0 stevel (void) strcpy(pri->exec_string, pri->sys_string); 522 0 stevel pri->length += strlen(pri->sys_string); 523 0 stevel pri->exec_lwpid = pri->lwpstat->pr_lwpid; 524 0 stevel pri->sys_leng = 0; 525 0 stevel *pri->sys_string = '\0'; 526 0 stevel } 527 0 stevel pri->syslast = Psp->pr_stime; 528 0 stevel pri->usrlast = Psp->pr_utime; 529 0 stevel } 530 0 stevel 531 0 stevel /* 532 0 stevel * Now that we have created the victim process, 533 0 stevel * give ourself a million file descriptors. 534 0 stevel * This is enough to deal with a multithreaded 535 0 stevel * victim process that has half a million lwps. 536 0 stevel */ 537 0 stevel rlim.rlim_cur = 1024 * 1024; 538 0 stevel rlim.rlim_max = 1024 * 1024; 539 0 stevel if ((Euid != 0 || setrlimit(RLIMIT_NOFILE, &rlim) != 0) && 540 0 stevel getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 541 0 stevel /* 542 0 stevel * Failing the million, give ourself as many 543 0 stevel * file descriptors as we can get. 544 0 stevel */ 545 0 stevel rlim.rlim_cur = rlim.rlim_max; 546 0 stevel (void) setrlimit(RLIMIT_NOFILE, &rlim); 547 0 stevel } 548 1914 casper (void) enable_extended_FILE_stdio(-1, -1); 549 0 stevel 550 0 stevel setoutput(ofd); /* establish truss output */ 551 0 stevel istty = isatty(1); 552 0 stevel 553 0 stevel if (setvbuf(stdout, (char *)NULL, _IOFBF, MYBUFSIZ) != 0) 554 0 stevel abend("setvbuf() failure", NULL); 555 0 stevel 556 0 stevel /* 557 0 stevel * Set up signal dispositions. 558 0 stevel */ 559 0 stevel if (created && (oflag || !istty)) { /* ignore interrupts */ 560 0 stevel (void) sigset(SIGHUP, SIG_IGN); 561 0 stevel (void) sigset(SIGINT, SIG_IGN); 562 0 stevel (void) sigset(SIGQUIT, SIG_IGN); 563 0 stevel } else { /* receive interrupts */ 564 0 stevel if (sigset(SIGHUP, SIG_IGN) == SIG_DFL) 565 0 stevel (void) sigset(SIGHUP, intr); 566 0 stevel if (sigset(SIGINT, SIG_IGN) == SIG_DFL) 567 0 stevel (void) sigset(SIGINT, intr); 568 0 stevel if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL) 569 0 stevel (void) sigset(SIGQUIT, intr); 570 0 stevel } 571 0 stevel (void) sigset(SIGTERM, intr); 572 0 stevel (void) sigset(SIGUSR1, intr); 573 0 stevel (void) sigset(SIGUSR2, intr); 574 0 stevel (void) sigset(SIGPIPE, intr); 575 0 stevel 576 0 stevel /* don't accumulate zombie children */ 577 0 stevel (void) sigset(SIGCLD, SIG_IGN); 578 0 stevel 579 0 stevel /* create shared mem space for global mutexes */ 580 0 stevel 581 0 stevel sharedmem = (fflag || Dynpat != NULL || ngrab > 1); 582 0 stevel gps = (void *)mmap(NULL, sizeof (struct global_psinfo), 583 0 stevel PROT_READ|PROT_WRITE, 584 0 stevel MAP_ANON | (sharedmem? MAP_SHARED : MAP_PRIVATE), 585 0 stevel -1, (off_t)0); 586 0 stevel if (gps == MAP_FAILED) 587 0 stevel abend("cannot allocate ", "memory for counts"); 588 0 stevel i = sharedmem? USYNC_PROCESS : USYNC_THREAD; 589 0 stevel (void) mutex_init(&gps->ps_mutex0, i, NULL); 590 0 stevel (void) mutex_init(&gps->ps_mutex1, i, NULL); 591 0 stevel (void) mutex_init(&gps->fork_lock, i, NULL); 592 0 stevel (void) cond_init(&gps->fork_cv, i, NULL); 593 0 stevel 594 0 stevel 595 0 stevel /* config tmp file if counting and following */ 596 0 stevel if (fflag && cflag) { 597 0 stevel char *tmps = tempnam("/var/tmp", "truss"); 598 0 stevel sfd = open(tmps, O_CREAT|O_APPEND|O_EXCL|O_RDWR, 0600); 599 0 stevel if (sfd == -1) 600 0 stevel abend("Error creating tmpfile", NULL); 601 0 stevel if (unlink(tmps) == -1) 602 0 stevel abend("Error unlinking tmpfile", NULL); 603 0 stevel free(tmps); 604 0 stevel tmps = NULL; 605 0 stevel } 606 0 stevel 607 0 stevel if (created) { 608 0 stevel per_proc_init(); 609 0 stevel procadd(created, NULL); 610 0 stevel show_cred(pri, TRUE); 611 0 stevel } else { /* grab the specified processes */ 612 0 stevel int gotone = FALSE; 613 0 stevel 614 0 stevel i = 0; 615 0 stevel while (i < ngrab) { /* grab first process */ 616 0 stevel if (grabit(pri, &grab[i++])) { 617 0 stevel Psp = Pstatus(Proc); 618 0 stevel Lsp = &Psp->pr_lwp; 619 0 stevel gotone = TRUE; 620 0 stevel break; 621 0 stevel } 622 0 stevel } 623 0 stevel if (!gotone) 624 0 stevel abend(NULL, NULL); 625 0 stevel per_proc_init(); 626 0 stevel while (i < ngrab) { /* grab the remainder */ 627 0 stevel proc_set_t *set = &grab[i++]; 628 0 stevel 629 0 stevel (void) mutex_lock(&truss_lock); 630 3235 raf switch (fork()) { 631 0 stevel case -1: 632 0 stevel (void) fprintf(stderr, 633 0 stevel "%s: cannot fork to control process, pid# %d\n", 634 0 stevel command, (int)set->pid); 635 0 stevel /* FALLTHROUGH */ 636 0 stevel default: 637 0 stevel (void) mutex_unlock(&truss_lock); 638 0 stevel continue; /* parent carries on */ 639 0 stevel 640 0 stevel case 0: /* child grabs process */ 641 0 stevel (void) mutex_unlock(&truss_lock); 642 0 stevel Pfree(Proc); 643 0 stevel descendent = TRUE; 644 0 stevel if (grabit(pri, set)) { 645 0 stevel Psp = Pstatus(Proc); 646 0 stevel Lsp = &Psp->pr_lwp; 647 0 stevel per_proc_init(); 648 0 stevel break; 649 0 stevel } 650 0 stevel exit(2); 651 0 stevel } 652 0 stevel break; 653 0 stevel } 654 0 stevel free(grab); 655 0 stevel } 656 0 stevel 657 0 stevel 658 0 stevel /* 659 0 stevel * If running setuid-root, become root for real to avoid 660 0 stevel * affecting the per-user limitation on the maximum number 661 0 stevel * of processes (one benefit of running setuid-root). 662 0 stevel */ 663 0 stevel if (Rgid != Egid) 664 0 stevel (void) setgid(Egid); 665 0 stevel if (Ruid != Euid) 666 0 stevel (void) setuid(Euid); 667 0 stevel 668 0 stevel if (!created && aflag && prismember(&trace, SYS_execve)) { 669 0 stevel psargs(pri); 670 0 stevel Flush(); 671 0 stevel } 672 0 stevel 673 0 stevel if (created && Pstate(Proc) != PS_STOP) /* assertion */ 674 0 stevel if (!(interrupt | sigusr1)) 675 0 stevel abend("ASSERT error: process is not stopped", NULL); 676 0 stevel 677 0 stevel traceeven = trace; /* trace these system calls */ 678 0 stevel 679 0 stevel /* trace these regardless, even if we don't report results */ 680 0 stevel praddset(&traceeven, SYS_exit); 681 0 stevel praddset(&traceeven, SYS_lwp_create); 682 0 stevel praddset(&traceeven, SYS_lwp_exit); 683 0 stevel praddset(&traceeven, SYS_exec); 684 0 stevel praddset(&traceeven, SYS_execve); 685 0 stevel praddset(&traceeven, SYS_open); 686 0 stevel praddset(&traceeven, SYS_open64); 687 0 stevel praddset(&traceeven, SYS_forkall); 688 0 stevel praddset(&traceeven, SYS_vfork); 689 0 stevel praddset(&traceeven, SYS_fork1); 690 3235 raf praddset(&traceeven, SYS_forksys); 691 0 stevel 692 0 stevel /* for I/O buffer dumps, force tracing of read()s and write()s */ 693 0 stevel if (!isemptyset(&readfd)) { 694 0 stevel praddset(&traceeven, SYS_read); 695 0 stevel praddset(&traceeven, SYS_readv); 696 0 stevel praddset(&traceeven, SYS_pread); 697 0 stevel praddset(&traceeven, SYS_pread64); 698 0 stevel praddset(&traceeven, SYS_recv); 699 0 stevel praddset(&traceeven, SYS_recvfrom); 700 0 stevel praddset(&traceeven, SYS_recvmsg); 701 0 stevel } 702 0 stevel if (!isemptyset(&writefd)) { 703 0 stevel praddset(&traceeven, SYS_write); 704 0 stevel praddset(&traceeven, SYS_writev); 705 0 stevel praddset(&traceeven, SYS_pwrite); 706 0 stevel praddset(&traceeven, SYS_pwrite64); 707 0 stevel praddset(&traceeven, SYS_send); 708 0 stevel praddset(&traceeven, SYS_sendto); 709 0 stevel praddset(&traceeven, SYS_sendmsg); 710 0 stevel } 711 0 stevel 712 0 stevel if (cflag || Eflag) { 713 0 stevel Psetsysentry(Proc, &traceeven); 714 0 stevel } 715 0 stevel Psetsysexit(Proc, &traceeven); 716 0 stevel 717 0 stevel /* special case -- cannot trace sysexit because context is changed */ 718 0 stevel if (prismember(&trace, SYS_context)) { 719 0 stevel (void) Psysentry(Proc, SYS_context, TRUE); 720 0 stevel (void) Psysexit(Proc, SYS_context, FALSE); 721 0 stevel prdelset(&traceeven, SYS_context); 722 0 stevel } 723 0 stevel 724 0 stevel /* special case -- sysexit not traced by OS */ 725 0 stevel if (prismember(&trace, SYS_evtrapret)) { 726 0 stevel (void) Psysentry(Proc, SYS_evtrapret, TRUE); 727 0 stevel (void) Psysexit(Proc, SYS_evtrapret, FALSE); 728 0 stevel prdelset(&traceeven, SYS_evtrapret); 729 0 stevel } 730 0 stevel 731 0 stevel /* special case -- trace exec() on entry to get the args */ 732 0 stevel (void) Psysentry(Proc, SYS_exec, TRUE); 733 0 stevel (void) Psysentry(Proc, SYS_execve, TRUE); 734 0 stevel 735 0 stevel /* special case -- sysexit never reached */ 736 0 stevel (void) Psysentry(Proc, SYS_exit, TRUE); 737 0 stevel (void) Psysentry(Proc, SYS_lwp_exit, TRUE); 738 0 stevel (void) Psysexit(Proc, SYS_exit, FALSE); 739 0 stevel (void) Psysexit(Proc, SYS_lwp_exit, FALSE); 740 0 stevel 741 0 stevel Psetsignal(Proc, &signals); /* trace these signals */ 742 0 stevel Psetfault(Proc, &faults); /* trace these faults */ 743 0 stevel 744 0 stevel /* for function call tracing */ 745 0 stevel if (Dynpat != NULL) { 746 0 stevel /* trace these regardless, to deal with function calls */ 747 0 stevel (void) Pfault(Proc, FLTBPT, TRUE); 748 0 stevel (void) Pfault(Proc, FLTTRACE, TRUE); 749 0 stevel 750 0 stevel /* needed for x86 */ 751 0 stevel (void) Psetflags(Proc, PR_BPTADJ); 752 0 stevel 753 0 stevel /* 754 0 stevel * Find functions and set breakpoints on grabbed process. 755 0 stevel * A process stopped on exec() gets its breakpoints set below. 756 0 stevel */ 757 0 stevel if ((Lsp->pr_why != PR_SYSENTRY && 758 0 stevel Lsp->pr_why != PR_SYSEXIT) || 759 0 stevel (Lsp->pr_what != SYS_exec && 760 0 stevel Lsp->pr_what != SYS_execve)) { 761 0 stevel establish_breakpoints(); 762 0 stevel establish_stacks(); 763 0 stevel } 764 0 stevel } 765 0 stevel 766 0 stevel /* 767 0 stevel * Use asynchronous-stop for multithreaded truss. 768 0 stevel * truss runs one lwp for each lwp in the target process. 769 0 stevel */ 770 0 stevel (void) Psetflags(Proc, PR_ASYNC); 771 0 stevel 772 0 stevel /* flush out all tracing flags now. */ 773 0 stevel Psync(Proc); 774 0 stevel 775 0 stevel /* 776 0 stevel * If we grabbed a running process, set it running again. 777 0 stevel * Since we are tracing lwp_create() and lwp_exit(), the 778 0 stevel * lwps will not change in the process until we create all 779 0 stevel * of the truss worker threads. 780 0 stevel * We leave a created process stopped so its exec() can be reported. 781 0 stevel */ 782 0 stevel first = created? FALSE : TRUE; 783 0 stevel if (!created && 784 0 stevel ((Pstate(Proc) == PS_STOP && Lsp->pr_why == PR_REQUESTED) || 785 0 stevel (Lsp->pr_flags & PR_DSTOP))) 786 0 stevel first = FALSE; 787 0 stevel 788 0 stevel main_thread(first); 789 0 stevel return (0); 790 0 stevel } 791 0 stevel 792 0 stevel /* 793 3235 raf * Called from main() and from control() after fork(). 794 0 stevel */ 795 0 stevel void 796 0 stevel main_thread(int first) 797 0 stevel { 798 0 stevel private_t *pri = get_private(); 799 0 stevel struct tms tms; 800 0 stevel int flags; 801 0 stevel int retc; 802 0 stevel int i; 803 0 stevel int count; 804 1132 raf 805 1132 raf /* 806 1132 raf * Block all signals in the main thread. 807 1132 raf * Some worker thread will receive signals. 808 1132 raf */ 809 1132 raf (void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL); 810 0 stevel 811 0 stevel /* 812 0 stevel * If we are dealing with a previously hung process, 813 0 stevel * arrange not to leave it hung on the same system call. 814 0 stevel */ 815 0 stevel primary_lwp = (first && Pstate(Proc) == PS_STOP)? 816 0 stevel Pstatus(Proc)->pr_lwp.pr_lwpid : 0; 817 0 stevel 818 0 stevel /* 819 0 stevel * Create worker threads to match the lwps in the target process. 820 0 stevel */ 821 0 stevel truss_nlwp = 0; 822 0 stevel truss_maxlwp = 1; 823 0 stevel truss_lwpid = my_realloc(truss_lwpid, sizeof (lwpid_t), NULL); 824 0 stevel truss_lwpid[0] = 0; 825 0 stevel count = 0; 826 0 stevel (void) Plwp_iter(Proc, create_thread, &count); 827 0 stevel 828 0 stevel if (count == 0) { 829 0 stevel (void) printf("(Warning: no matching active LWPs found, " 830 0 stevel "waiting)\n"); 831 0 stevel Flush(); 832 0 stevel } 833 0 stevel 834 0 stevel /* 835 0 stevel * Set all of the truss worker threads running now. 836 0 stevel */ 837 0 stevel (void) mutex_lock(&truss_lock); 838 0 stevel for (i = 0; i < truss_maxlwp; i++) { 839 0 stevel if (truss_lwpid[i]) 840 0 stevel (void) thr_continue(truss_lwpid[i]); 841 0 stevel } 842 0 stevel (void) mutex_unlock(&truss_lock); 843 0 stevel 844 0 stevel /* 845 1132 raf * Wait until all worker threads terminate. 846 0 stevel */ 847 1132 raf while (thr_join(0, NULL, NULL) == 0) 848 1132 raf continue; 849 0 stevel 850 0 stevel (void) Punsetflags(Proc, PR_ASYNC); 851 0 stevel Psync(Proc); 852 0 stevel if (sigusr1) 853 0 stevel letgo(pri); 854 0 stevel flags = PRELEASE_CLEAR; 855 0 stevel if (leave_hung) 856 0 stevel flags |= PRELEASE_HANG; 857 0 stevel Prelease(Proc, flags); 858 0 stevel 859 0 stevel procdel(); 860 0 stevel retc = (leave_hung? 0 : wait4all()); 861 0 stevel 862 0 stevel if (!descendent) { 863 0 stevel interrupt = 0; /* another interrupt kills the report */ 864 0 stevel if (cflag) { 865 0 stevel if (fflag) 866 0 stevel file_to_parent(); 867 0 stevel report(pri, times(&tms) - starttime); 868 0 stevel } 869 0 stevel } else if (cflag && fflag) { 870 0 stevel child_to_file(); 871 0 stevel } 872 0 stevel 873 0 stevel exit(retc); /* exit with exit status of created process, else 0 */ 874 0 stevel } 875 0 stevel 876 0 stevel void * 877 0 stevel worker_thread(void *arg) 878 0 stevel { 879 0 stevel struct ps_lwphandle *Lwp = (struct ps_lwphandle *)arg; 880 0 stevel const pstatus_t *Psp = Pstatus(Proc); 881 0 stevel const lwpstatus_t *Lsp = Lstatus(Lwp); 882 0 stevel struct syscount *scp; 883 0 stevel lwpid_t who = Lsp->pr_lwpid; 884 0 stevel int first = (who == primary_lwp); 885 0 stevel private_t *pri = get_private(); 886 0 stevel int req_flag = 0; 887 1132 raf int leave_it_hung = FALSE; 888 0 stevel int reset_traps = FALSE; 889 0 stevel int gcode; 890 0 stevel int what; 891 0 stevel int ow_in_effect = 0; 892 0 stevel long ow_syscall = 0; 893 0 stevel long ow_subcode = 0; 894 0 stevel char *ow_string = NULL; 895 0 stevel sysset_t full_set; 896 0 stevel sysset_t running_set; 897 0 stevel int dotrace = lwptrace(Psp->pr_pid, Lsp->pr_lwpid); 898 0 stevel 899 0 stevel pri->Lwp = Lwp; 900 0 stevel pri->lwpstat = Lsp; 901 0 stevel pri->syslast = Lsp->pr_stime; 902 0 stevel pri->usrlast = Lsp->pr_utime; 903 0 stevel make_pname(pri, 0); 904 0 stevel 905 0 stevel prfillset(&full_set); 906 0 stevel 907 1132 raf /* we were created with all signals blocked; unblock them */ 908 1132 raf (void) thr_sigsetmask(SIG_SETMASK, &emptyset, NULL); 909 1132 raf 910 0 stevel /* 911 1132 raf * Run this loop until the victim lwp terminates or we receive 912 1132 raf * a termination condition (leave_hung | interrupt | sigusr1). 913 0 stevel */ 914 0 stevel for (;;) { 915 0 stevel if (interrupt | sigusr1) { 916 0 stevel (void) Lstop(Lwp, MILLISEC); 917 0 stevel if (Lstate(Lwp) == PS_RUN) 918 0 stevel break; 919 0 stevel } 920 0 stevel if (Lstate(Lwp) == PS_RUN) { 921 0 stevel /* millisecond timeout is for sleeping syscalls */ 922 0 stevel uint_t tout = (iflag || req_flag)? 0 : MILLISEC; 923 0 stevel 924 0 stevel /* 925 0 stevel * If we are to leave this lwp stopped in sympathy 926 0 stevel * with another lwp that has been left hung, or if 927 0 stevel * we have been interrupted or instructed to release 928 0 stevel * our victim process, and this lwp is stopped but 929 0 stevel * not on an event of interest to /proc, then just 930 0 stevel * leave it in that state. 931 0 stevel */ 932 0 stevel if ((leave_hung | interrupt | sigusr1) && 933 0 stevel (Lsp->pr_flags & (PR_STOPPED|PR_ISTOP)) 934 0 stevel == PR_STOPPED) 935 0 stevel break; 936 0 stevel 937 0 stevel (void) Lwait(Lwp, tout); 938 0 stevel if (Lstate(Lwp) == PS_RUN && 939 0 stevel tout != 0 && !(interrupt | sigusr1)) { 940 0 stevel (void) mutex_lock(&truss_lock); 941 0 stevel if ((Lsp->pr_flags & PR_STOPPED) && 942 0 stevel Lsp->pr_why == PR_JOBCONTROL) 943 0 stevel req_flag = jobcontrol(pri, dotrace); 944 0 stevel else 945 0 stevel req_flag = requested(pri, req_flag, 946 0 stevel dotrace); 947 0 stevel (void) mutex_unlock(&truss_lock); 948 0 stevel } 949 0 stevel continue; 950 0 stevel } 951 0 stevel data_model = Psp->pr_dmodel; 952 0 stevel if (Lstate(Lwp) == PS_UNDEAD) 953 0 stevel break; 954 0 stevel if (Lstate(Lwp) == PS_LOST) { /* we lost control */ 955 0 stevel /* 956 0 stevel * After exec(), only one LWP remains in the process. 957 0 stevel * /proc makes the thread following that LWP receive 958 0 stevel * EAGAIN (PS_LOST) if the program being exec()ed 959 0 stevel * is a set-id program. Every other controlling 960 0 stevel * thread receives ENOENT (because its LWP vanished). 961 0 stevel * We are the controlling thread for the exec()ing LWP. 962 0 stevel * We must wait until all of our siblings terminate 963 0 stevel * before attempting to reopen the process. 964 0 stevel */ 965 0 stevel (void) mutex_lock(&truss_lock); 966 0 stevel while (truss_nlwp > 1) 967 0 stevel (void) cond_wait(&truss_cv, &truss_lock); 968 0 stevel if (Preopen(Proc) == 0) { /* we got control back */ 969 0 stevel /* 970 0 stevel * We have to free and re-grab the LWP. 971 0 stevel * The process is guaranteed to be at exit 972 0 stevel * from exec() or execve() and have only 973 0 stevel * one LWP, namely this one, and the LWP 974 0 stevel * is guaranteed to have lwpid == 1. 975 0 stevel * This "cannot fail". 976 0 stevel */ 977 0 stevel who = 1; 978 0 stevel Lfree(Lwp); 979 0 stevel pri->Lwp = Lwp = 980 0 stevel Lgrab(Proc, who, &gcode); 981 0 stevel if (Lwp == NULL) 982 0 stevel abend("Lgrab error: ", 983 0 stevel Lgrab_error(gcode)); 984 0 stevel pri->lwpstat = Lsp = Lstatus(Lwp); 985 0 stevel (void) mutex_unlock(&truss_lock); 986 0 stevel continue; 987 0 stevel } 988 0 stevel 989 0 stevel /* we really lost it */ 990 0 stevel if (pri->exec_string && *pri->exec_string) { 991 0 stevel if (pri->exec_pname[0] != '\0') 992 0 stevel (void) fputs(pri->exec_pname, stdout); 993 0 stevel timestamp(pri); 994 0 stevel (void) fputs(pri->exec_string, stdout); 995 0 stevel (void) fputc('\n', stdout); 996 0 stevel } else if (pri->length) { 997 0 stevel (void) fputc('\n', stdout); 998 0 stevel } 999 0 stevel if (pri->sys_valid) 1000 0 stevel (void) printf( 1001 0 stevel "%s\t*** cannot trace across exec() of %s ***\n", 1002 0 stevel pri->pname, pri->sys_path); 1003 0 stevel else 1004 0 stevel (void) printf( 1005 0 stevel "%s\t*** lost control of process ***\n", 1006 0 stevel pri->pname); 1007 0 stevel pri->length = 0; 1008 0 stevel Flush(); 1009 0 stevel (void) mutex_unlock(&truss_lock); 1010 0 stevel break; 1011 0 stevel } 1012 0 stevel if (Lstate(Lwp) != PS_STOP) { 1013 0 stevel (void) fprintf(stderr, 1014 0 stevel "%s: state = %d\n", command, Lstate(Lwp)); 1015 0 stevel abend(pri->pname, "uncaught status of subject lwp"); 1016 0 stevel } 1017 0 stevel 1018 0 stevel make_pname(pri, 0); 1019 0 stevel 1020 0 stevel (void) mutex_lock(&truss_lock); 1021 0 stevel 1022 0 stevel what = Lsp->pr_what; 1023 0 stevel req_flag = 0; 1024 0 stevel 1025 0 stevel switch (Lsp->pr_why) { 1026 0 stevel case PR_REQUESTED: 1027 0 stevel break; 1028 0 stevel case PR_SIGNALLED: 1029 0 stevel req_flag = signalled(pri, req_flag, dotrace); 1030 0 stevel if (Sflag && !first && prismember(&sighang, what)) 1031 0 stevel leave_it_hung = TRUE; 1032 0 stevel break; 1033 0 stevel case PR_FAULTED: 1034 0 stevel if (what == FLTBPT) { 1035 0 stevel int rval; 1036 0 stevel 1037 0 stevel (void) Pstop(Proc, 0); 1038 0 stevel rval = function_trace(pri, first, 0, dotrace); 1039 0 stevel if (rval == 1) 1040 0 stevel leave_it_hung = TRUE; 1041 0 stevel if (rval >= 0) 1042 0 stevel break; 1043 0 stevel } 1044 0 stevel if (faulted(pri, dotrace) && 1045 0 stevel Mflag && !first && prismember(&flthang, what)) 1046 0 stevel leave_it_hung = TRUE; 1047 0 stevel break; 1048 0 stevel case PR_JOBCONTROL: /* can't happen except first time */ 1049 0 stevel req_flag = jobcontrol(pri, dotrace); 1050 0 stevel break; 1051 0 stevel case PR_SYSENTRY: 1052 0 stevel /* protect ourself from operating system error */ 1053 0 stevel if (what <= 0 || what > PRMAXSYS) 1054 0 stevel what = PRMAXSYS; 1055 0 stevel pri->length = 0; 1056 0 stevel /* 1057 0 stevel * ow_in_effect checks to see whether or not we 1058 0 stevel * are attempting to quantify the time spent in 1059 0 stevel * a one way system call. This is necessary as 1060 0 stevel * some system calls never return, yet it is desireable 1061 0 stevel * to determine how much time the traced process 1062 0 stevel * spends in these calls. To do this, a one way 1063 0 stevel * flag is set on SYSENTRY when the call is recieved. 1064 0 stevel * After this, the call mask for the SYSENTRY events 1065 0 stevel * is filled so that the traced process will stop 1066 0 stevel * on the entry to the very next system call. 1067 0 stevel * This appears to the the best way to determine 1068 0 stevel * system time elapsed between a one way system call. 1069 0 stevel * Once the next call occurs, values that have been 1070 0 stevel * stashed are used to record the correct syscall 1071 0 stevel * and time, and the SYSENTRY event mask is restored 1072 0 stevel * so that the traced process may continue. 1073 0 stevel */ 1074 0 stevel if (dotrace && ow_in_effect) { 1075 0 stevel if (cflag) { 1076 0 stevel (void) mutex_lock(&count_lock); 1077 0 stevel scp = Cp->syscount[ow_syscall]; 1078 0 stevel if (ow_subcode != -1) 1079 0 stevel scp += ow_subcode; 1080 0 stevel scp->count++; 1081 0 stevel accumulate(&scp->stime, 1082 0 stevel &Lsp->pr_stime, &pri->syslast); 1083 0 stevel accumulate(&Cp->usrtotal, 1084 0 stevel &Lsp->pr_utime, &pri->usrlast); 1085 0 stevel pri->syslast = Lsp->pr_stime; 1086 0 stevel pri->usrlast = Lsp->pr_utime; 1087 0 stevel (void) mutex_unlock(&count_lock); 1088 0 stevel } else if (Eflag) { 1089 0 stevel putpname(pri); 1090 0 stevel timestamp(pri); 1091 0 stevel (void) printf("%s\n", ow_string); 1092 0 stevel free(ow_string); 1093 0 stevel ow_string = NULL; 1094 0 stevel pri->syslast = Lsp->pr_stime; 1095 0 stevel } 1096 0 stevel ow_in_effect = 0; 1097 0 stevel Psetsysentry(Proc, &running_set); 1098 0 stevel } 1099 0 stevel 1100 0 stevel /* 1101 0 stevel * Special cases. Most syscalls are traced on exit. 1102 0 stevel */ 1103 0 stevel switch (what) { 1104 0 stevel case SYS_exit: /* exit() */ 1105 0 stevel case SYS_lwp_exit: /* lwp_exit() */ 1106 0 stevel case SYS_context: /* [get|set]context() */ 1107 0 stevel case SYS_evtrapret: /* evtrapret() */ 1108 0 stevel if (dotrace && cflag && 1109 0 stevel prismember(&trace, what)) { 1110 0 stevel ow_in_effect = 1; 1111 0 stevel ow_syscall = what; 1112 0 stevel ow_subcode = getsubcode(pri); 1113 0 stevel pri->syslast = Lsp->pr_stime; 1114 0 stevel running_set = 1115 0 stevel (Pstatus(Proc))->pr_sysentry; 1116 0 stevel Psetsysentry(Proc, &full_set); 1117 0 stevel } else if (dotrace && Eflag && 1118 0 stevel prismember(&trace, what)) { 1119 0 stevel (void) sysentry(pri, dotrace); 1120 0 stevel ow_in_effect = 1; 1121 0 stevel ow_string = my_malloc( 1122 0 stevel strlen(pri->sys_string) + 1, NULL); 1123 0 stevel (void) strcpy(ow_string, 1124 0 stevel pri->sys_string); 1125 0 stevel running_set = 1126 0 stevel (Pstatus(Proc))->pr_sysentry; 1127 0 stevel Psetsysentry(Proc, &full_set); 1128 0 stevel pri->syslast = Lsp->pr_stime; 1129 0 stevel } else if (dotrace && 1130 0 stevel prismember(&trace, what)) { 1131 0 stevel (void) sysentry(pri, dotrace); 1132 0 stevel putpname(pri); 1133 0 stevel timestamp(pri); 1134 0 stevel pri->length += 1135 0 stevel printf("%s\n", pri->sys_string); 1136 0 stevel Flush(); 1137 0 stevel } 1138 0 stevel pri->sys_leng = 0; 1139 0 stevel *pri->sys_string = '\0'; 1140 0 stevel 1141 0 stevel if (what == SYS_exit) 1142 0 stevel exit_called = TRUE; 1143 0 stevel break; 1144 0 stevel case SYS_exec: 1145 0 stevel case SYS_execve: 1146 0 stevel (void) sysentry(pri, dotrace); 1147 0 stevel if (dotrace && !cflag && 1148 0 stevel prismember(&trace, what)) { 1149 0 stevel pri->exec_string = 1150 0 stevel my_realloc(pri->exec_string, 1151 0 stevel strlen(pri->sys_string) + 1, 1152 0 stevel NULL); 1153 0 stevel (void) strcpy(pri->exec_pname, 1154 0 stevel pri->pname); 1155 0 stevel (void) strcpy(pri->exec_string, 1156 0 stevel pri->sys_string); 1157 0 stevel pri->length += strlen(pri->sys_string); 1158 0 stevel pri->exec_lwpid = Lsp->pr_lwpid; 1159 0 stevel } 1160 0 stevel pri->sys_leng = 0; 1161 0 stevel *pri->sys_string = '\0'; 1162 0 stevel break; 1163 0 stevel default: 1164 0 stevel if (dotrace && (cflag || Eflag) && 1165 0 stevel prismember(&trace, what)) { 1166 0 stevel pri->syslast = Lsp->pr_stime; 1167 0 stevel } 1168 0 stevel break; 1169 0 stevel } 1170 0 stevel if (dotrace && Tflag && !first && 1171 0 stevel (prismember(&syshang, what) || 1172 0 stevel (exit_called && prismember(&syshang, SYS_exit)))) 1173 0 stevel leave_it_hung = TRUE; 1174 0 stevel break; 1175 0 stevel case PR_SYSEXIT: 1176 0 stevel /* check for write open of a /proc file */ 1177 0 stevel if ((what == SYS_open || what == SYS_open64)) { 1178 0 stevel (void) sysentry(pri, dotrace); 1179 0 stevel pri->Errno = Lsp->pr_errno; 1180 0 stevel pri->ErrPriv = Lsp->pr_errpriv; 1181 0 stevel if ((pri->Errno == 0 || pri->Errno == EBUSY) && 1182 0 stevel pri->sys_valid && 1183 0 stevel (pri->sys_nargs > 1 && 1184 0 stevel (pri->sys_args[1]&0x3) != O_RDONLY)) { 1185 0 stevel int rv = checkproc(pri); 1186 0 stevel if (rv == 1 && Fflag != PGRAB_FORCE) { 1187 0 stevel /* 1188 0 stevel * The process opened itself 1189 0 stevel * and no -F flag was specified. 1190 0 stevel * Just print the open() call 1191 0 stevel * and let go of the process. 1192 0 stevel */ 1193 0 stevel if (dotrace && !cflag && 1194 0 stevel prismember(&trace, what)) { 1195 0 stevel putpname(pri); 1196 0 stevel timestamp(pri); 1197 0 stevel (void) printf("%s\n", 1198 0 stevel pri->sys_string); 1199 0 stevel Flush(); 1200 0 stevel } 1201 1132 raf sigusr1 = TRUE; 1202 0 stevel (void) mutex_unlock( 1203 0 stevel &truss_lock); 1204 0 stevel goto out; 1205 0 stevel } 1206 0 stevel if (rv == 2) { 1207 0 stevel /* 1208 0 stevel * Process opened someone else. 1209 0 stevel * The open is being reissued. 1210 0 stevel * Don't report this one. 1211 0 stevel */ 1212 0 stevel pri->sys_leng = 0; 1213 0 stevel *pri->sys_string = '\0'; 1214 0 stevel pri->sys_nargs = 0; 1215 0 stevel break; 1216 0 stevel } 1217 0 stevel } 1218 0 stevel } 1219 0 stevel if ((what == SYS_exec || what == SYS_execve) && 1220 0 stevel pri->Errno == 0) { 1221 0 stevel /* 1222 0 stevel * Refresh the data model on exec() in case it 1223 0 stevel * is different from the parent. Lwait() 1224 0 stevel * doesn't update process-wide status, so we 1225 0 stevel * have to explicitly call Pstopstatus() to get 1226 0 stevel * the new state. 1227 0 stevel */ 1228 0 stevel (void) Pstopstatus(Proc, PCNULL, 0); 1229 0 stevel data_model = Psp->pr_dmodel; 1230 0 stevel } 1231 0 stevel if (sysexit(pri, dotrace)) 1232 0 stevel Flush(); 1233 0 stevel if (what == SYS_lwp_create && pri->Rval1 != 0) { 1234 0 stevel struct ps_lwphandle *new_Lwp; 1235 0 stevel lwpid_t lwpid; 1236 0 stevel 1237 0 stevel if ((new_Lwp = grab_lwp(pri->Rval1)) != NULL) { 1238 1132 raf (void) thr_sigsetmask(SIG_SETMASK, 1239 1132 raf &fillset, NULL); 1240 0 stevel if (thr_create(NULL, 0, worker_thread, 1241 0 stevel new_Lwp, THR_BOUND | THR_SUSPENDED, 1242 0 stevel &lwpid) != 0) 1243 0 stevel abend("cannot create lwp ", 1244 0 stevel "to follow child lwp"); 1245 0 stevel insert_lwpid(lwpid); 1246 0 stevel (void) thr_continue(lwpid); 1247 1132 raf (void) thr_sigsetmask(SIG_SETMASK, 1248 1132 raf &emptyset, NULL); 1249 0 stevel } 1250 0 stevel } 1251 0 stevel pri->sys_nargs = 0; 1252 0 stevel if (dotrace && Tflag && !first && 1253 0 stevel prismember(&syshang, what)) 1254 0 stevel leave_it_hung = TRUE; 1255 0 stevel if ((what == SYS_exec || what == SYS_execve) && 1256 0 stevel pri->Errno == 0) { 1257 0 stevel is_vfork_child = FALSE; 1258 0 stevel reset_breakpoints(); 1259 0 stevel /* 1260 0 stevel * exec() resets the calling LWP's lwpid to 1. 1261 0 stevel * If the LWP has changed its lwpid, then 1262 0 stevel * we have to free and re-grab the LWP 1263 0 stevel * in order to keep libproc consistent. 1264 0 stevel * This "cannot fail". 1265 0 stevel */ 1266 0 stevel if (who != Lsp->pr_lwpid) { 1267 0 stevel /* 1268 0 stevel * We must wait for all of our 1269 0 stevel * siblings to terminate. 1270 0 stevel */ 1271 0 stevel while (truss_nlwp > 1) 1272 0 stevel (void) cond_wait(&truss_cv, 1273 0 stevel &truss_lock); 1274 0 stevel who = Lsp->pr_lwpid; 1275 0 stevel Lfree(Lwp); 1276 0 stevel pri->Lwp = Lwp = 1277 0 stevel Lgrab(Proc, who, &gcode); 1278 0 stevel if (Lwp == NULL) 1279 0 stevel abend("Lgrab error: ", 1280 0 stevel Lgrab_error(gcode)); 1281 0 stevel pri->lwpstat = Lsp = Lstatus(Lwp); 1282 0 stevel } 1283 0 stevel } 1284 0 stevel break; 1285 0 stevel default: 1286 0 stevel req_flag = 0; 1287 0 stevel (void) fprintf(stderr, 1288 0 stevel "unknown reason for stopping: %d/%d\n", 1289 0 stevel Lsp->pr_why, what); 1290 0 stevel abend(NULL, NULL); 1291 0 stevel } 1292 0 stevel 1293 0 stevel if (pri->child) { /* controlled process fork()ed */ 1294 0 stevel if (fflag || Dynpat != NULL) { 1295 0 stevel if (Lsp->pr_why == PR_SYSEXIT && 1296 3235 raf (Lsp->pr_what == SYS_vfork || 1297 3235 raf (Lsp->pr_what == SYS_forksys && 1298 3235 raf Lsp->pr_sysarg[0] == 2))) { 1299 0 stevel is_vfork_child = TRUE; 1300 3235 raf (void) Pstop(Proc, 0); 1301 3235 raf } 1302 0 stevel if (control(pri, pri->child)) { 1303 0 stevel (void) mutex_unlock(&truss_lock); 1304 0 stevel pri->child = 0; 1305 0 stevel if (!fflag) { 1306 0 stevel /* 1307 0 stevel * If this is vfork(), then 1308 0 stevel * this clears the breakpoints 1309 0 stevel * in the parent's address space 1310 0 stevel * as well as in the child's. 1311 0 stevel */ 1312 0 stevel clear_breakpoints(); 1313 0 stevel Prelease(Proc, PRELEASE_CLEAR); 1314 0 stevel _exit(0); 1315 0 stevel } 1316 0 stevel main_thread(FALSE); 1317 0 stevel /* NOTREACHED */ 1318 0 stevel } 1319 0 stevel 1320 0 stevel /* 1321 0 stevel * Here, we are still the parent truss. 1322 3235 raf * If the child messes with the breakpoints and 1323 0 stevel * this is vfork(), we have to set them again. 1324 0 stevel */ 1325 5355 rh87107 if (Dynpat != NULL && is_vfork_child && !fflag) 1326 0 stevel reset_traps = TRUE; 1327 0 stevel is_vfork_child = FALSE; 1328 0 stevel } 1329 0 stevel pri->child = 0; 1330 0 stevel } 1331 0 stevel 1332 0 stevel if (leave_it_hung) { 1333 0 stevel (void) mutex_unlock(&truss_lock); 1334 0 stevel break; 1335 0 stevel } 1336 0 stevel 1337 0 stevel if (reset_traps) { 1338 0 stevel /* 1339 0 stevel * To recover from vfork, we must catch the lwp 1340 0 stevel * that issued the vfork() when it returns to user 1341 0 stevel * level, with all other lwps remaining stopped. 1342 3235 raf * For this purpose, we have directed all lwps to 1343 3235 raf * stop and we now set the vfork()ing lwp running 1344 3235 raf * with the PRSTEP flag. We expect to capture it 1345 3235 raf * when it stops again showing PR_FAULTED/FLTTRACE. 1346 0 stevel * We are holding truss_lock, so no other threads 1347 0 stevel * in truss will set any other lwps in the victim 1348 0 stevel * process running. 1349 0 stevel */ 1350 0 stevel reset_traps = FALSE; 1351 0 stevel (void) Lsetrun(Lwp, 0, PRSTEP); 1352 0 stevel do { 1353 0 stevel (void) Lwait(Lwp, 0); 1354 0 stevel } while (Lstate(Lwp) == PS_RUN); 1355 0 stevel if (Lstate(Lwp) == PS_STOP && 1356 0 stevel Lsp->pr_why == PR_FAULTED && 1357 0 stevel Lsp->pr_what == FLTTRACE) { 1358 0 stevel reestablish_traps(); 1359 0 stevel (void) Lsetrun(Lwp, 0, PRCFAULT|PRSTOP); 1360 0 stevel } else { 1361 0 stevel (void) printf("%s\t*** Expected PR_FAULTED/" 1362 0 stevel "FLTTRACE stop following vfork()\n", 1363 0 stevel pri->pname); 1364 0 stevel } 1365 0 stevel } 1366 0 stevel 1367 0 stevel if (Lstate(Lwp) == PS_STOP) { 1368 0 stevel int flags = 0; 1369 0 stevel 1370 0 stevel if (interrupt | sigusr1) { 1371 0 stevel (void) mutex_unlock(&truss_lock); 1372 0 stevel break; 1373 0 stevel } 1374 0 stevel /* 1375 0 stevel * If we must leave this lwp hung is sympathy with 1376 0 stevel * another lwp that is being left hung on purpose, 1377 0 stevel * then push the state onward toward PR_REQUESTED. 1378 0 stevel */ 1379 0 stevel if (leave_hung) { 1380 0 stevel if (Lsp->pr_why == PR_REQUESTED) { 1381 0 stevel (void) mutex_unlock(&truss_lock); 1382 0 stevel break; 1383 0 stevel } 1384 0 stevel flags |= PRSTOP; 1385 0 stevel } 1386 0 stevel if (Lsetrun(Lwp, 0, flags) != 0 && 1387 0 stevel Lstate(Lwp) != PS_LOST && 1388 0 stevel Lstate(Lwp) != PS_UNDEAD) { 1389 0 stevel (void) mutex_unlock(&truss_lock); 1390 0 stevel perror("Lsetrun"); 1391 0 stevel abend("cannot start subject lwp", NULL); 1392 0 stevel /* NOTREACHED */ 1393 0 stevel } 1394 0 stevel } 1395 0 stevel first = FALSE; 1396 0 stevel 1397 0 stevel (void) mutex_unlock(&truss_lock); 1398 0 stevel } 1399 0 stevel 1400 0 stevel out: 1401 1132 raf /* block all signals in preparation for exiting */ 1402 1132 raf (void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL); 1403 1132 raf 1404 1132 raf if (Lstate(Lwp) == PS_UNDEAD || Lstate(Lwp) == PS_LOST) 1405 1132 raf (void) mutex_lock(&truss_lock); 1406 1132 raf else { 1407 0 stevel (void) Lstop(Lwp, MILLISEC); 1408 0 stevel (void) mutex_lock(&truss_lock); 1409 0 stevel if (Lstate(Lwp) == PS_STOP && 1410 0 stevel Lsp->pr_why == PR_FAULTED && 1411 0 stevel Lsp->pr_what == FLTBPT) 1412 0 stevel (void) function_trace(pri, 0, 1, dotrace); 1413 0 stevel } 1414 0 stevel 1415 0 stevel if (dotrace && ow_in_effect) { 1416 0 stevel if (cflag) { 1417 0 stevel (void) mutex_lock(&count_lock); 1418 0 stevel scp = Cp->syscount[ow_syscall]; 1419 0 stevel if (ow_subcode != -1) 1420 0 stevel scp += ow_subcode; 1421 0 stevel scp->count++; 1422 0 stevel accumulate(&scp->stime, 1423 0 stevel &Lsp->pr_stime, &pri->syslast); 1424 0 stevel accumulate(&Cp->usrtotal, 1425 0 stevel &Lsp->pr_utime, &pri->usrlast); 1426 0 stevel pri->syslast = Lsp->pr_stime; 1427 0 stevel pri->usrlast = Lsp->pr_utime; 1428 0 stevel (void) mutex_unlock(&count_lock); 1429 0 stevel } else if (Eflag) { 1430 0 stevel putpname(pri); 1431 0 stevel timestamp(pri); 1432 0 stevel (void) printf("%s\n", ow_string); 1433 0 stevel free(ow_string); 1434 0 stevel ow_string = NULL; 1435 0 stevel pri->syslast = Lsp->pr_stime; 1436 0 stevel } 1437 0 stevel ow_in_effect = 0; 1438 0 stevel Psetsysentry(Proc, &running_set); 1439 0 stevel } 1440 0 stevel 1441 1132 raf if (Lstate(Lwp) == PS_UNDEAD || Lstate(Lwp) == PS_LOST) { 1442 1132 raf /* 1443 1132 raf * The victim thread has exited or we lost control of 1444 1132 raf * the process. Remove ourself from the list of all 1445 1132 raf * truss threads and notify everyone waiting for this. 1446 1132 raf */ 1447 1132 raf lwpid_t my_id = thr_self(); 1448 1132 raf int i; 1449 1132 raf 1450 1132 raf for (i = 0; i < truss_maxlwp; i++) { 1451 1132 raf if (truss_lwpid[i] == my_id) { 1452 1132 raf truss_lwpid[i] = 0; 1453 1132 raf break; 1454 1132 raf } 1455 1132 raf } 1456 1132 raf if (--truss_nlwp != 0) { 1457 1132 raf (void) cond_broadcast(&truss_cv); 1458 1132 raf } else { 1459 1132 raf /* 1460 1132 raf * The last truss worker thread is terminating. 1461 1132 raf * The address space is gone (UNDEAD) or is 1462 1132 raf * inaccessible (LOST) so we cannot clear the 1463 1132 raf * breakpoints. Just report the htable stats. 1464 1132 raf */ 1465 1132 raf report_htable_stats(); 1466 1132 raf } 1467 1132 raf } else { 1468 1132 raf /* 1469 1132 raf * The victim thread is not a zombie thread, and we have not 1470 1132 raf * lost control of the process. We must have gotten here due 1471 1132 raf * to (leave_hung || leave_it_hung || interrupt || sigusr1). 1472 1132 raf * In these cases, we must carefully uninstrument the process 1473 1132 raf * and either set it running or leave it stopped and abandoned. 1474 1132 raf */ 1475 1132 raf static int nstopped = 0; 1476 1132 raf static int cleared = 0; 1477 1132 raf 1478 1132 raf if (leave_it_hung) 1479 1132 raf leave_hung = TRUE; 1480 1132 raf if ((leave_hung | interrupt | sigusr1) == 0) 1481 1132 raf abend("(leave_hung | interrupt | sigusr1) == 0", NULL); 1482 1132 raf 1483 1132 raf /* 1484 1132 raf * The first truss thread through here needs to instruct all 1485 1132 raf * application threads to stop -- they're not necessarily 1486 1132 raf * going to stop on their own. 1487 1132 raf */ 1488 1132 raf if (nstopped++ == 0) 1489 1132 raf (void) Pdstop(Proc); 1490 1132 raf 1491 1132 raf /* 1492 1132 raf * Notify all other worker threads about the reason 1493 1132 raf * for being here (leave_hung || interrupt || sigusr1). 1494 1132 raf */ 1495 1132 raf broadcast_signals(); 1496 1132 raf 1497 1132 raf /* 1498 1132 raf * Once the last thread has reached this point, then and 1499 1132 raf * only then is it safe to remove breakpoints and other 1500 1132 raf * instrumentation. Since breakpoints are executed without 1501 1132 raf * truss_lock held, a monitor thread can't exit until all 1502 1132 raf * breakpoints have been removed, and we can't be sure the 1503 1132 raf * procedure to execute a breakpoint won't temporarily 1504 1132 raf * reinstall a breakpont. Accordingly, we need to wait 1505 1132 raf * until all threads are in a known state. 1506 1132 raf */ 1507 1132 raf while (nstopped != truss_nlwp) 1508 1132 raf (void) cond_wait(&truss_cv, &truss_lock); 1509 1132 raf 1510 1132 raf /* 1511 1132 raf * All truss threads have reached this point. 1512 1132 raf * One of them clears the breakpoints and 1513 1132 raf * wakes up everybody else to finish up. 1514 1132 raf */ 1515 1132 raf if (cleared++ == 0) { 1516 1132 raf /* 1517 1132 raf * All threads should already be stopped, 1518 1132 raf * but just to be safe... 1519 1132 raf */ 1520 1132 raf (void) Pstop(Proc, MILLISEC); 1521 1132 raf clear_breakpoints(); 1522 1132 raf (void) Psysexit(Proc, SYS_forkall, FALSE); 1523 1132 raf (void) Psysexit(Proc, SYS_vfork, FALSE); 1524 1132 raf (void) Psysexit(Proc, SYS_fork1, FALSE); 1525 3235 raf (void) Psysexit(Proc, SYS_forksys, FALSE); 1526 1132 raf (void) Punsetflags(Proc, PR_FORK); 1527 1132 raf Psync(Proc); 1528 1132 raf fflag = 0; 1529 1132 raf (void) cond_broadcast(&truss_cv); 1530 1132 raf } 1531 1132 raf 1532 1132 raf if (!leave_hung && Lstate(Lwp) == PS_STOP) 1533 1132 raf (void) Lsetrun(Lwp, 0, 0); 1534 1132 raf } 1535 1132 raf 1536 0 stevel (void) Lfree(Lwp); 1537 0 stevel (void) mutex_unlock(&truss_lock); 1538 1132 raf return (NULL); 1539 0 stevel } 1540 0 stevel 1541 0 stevel /* 1542 0 stevel * Give a base date for time stamps, adjusted to the 1543 0 stevel * stop time of the selected (first or created) process. 1544 0 stevel */ 1545 0 stevel void 1546 0 stevel setup_basetime(hrtime_t basehrtime, struct timeval *basedate) 1547 0 stevel { 1548 0 stevel const pstatus_t *Psp = Pstatus(Proc); 1549 0 stevel (void) mutex_lock(&count_lock); 1550 0 stevel Cp->basetime = Psp->pr_lwp.pr_tstamp; 1551 0 stevel (void) mutex_unlock(&count_lock); 1552 0 stevel 1553 0 stevel if ((dflag|Dflag) && !cflag) { 1554 0 stevel const struct tm *ptm; 1555 0 stevel const char *ptime; 1556 0 stevel const char *pdst; 1557 0 stevel hrtime_t delta = basehrtime - 1558 0 stevel ((hrtime_t)Cp->basetime.tv_sec * NANOSEC + 1559 0 stevel Cp->basetime.tv_nsec); 1560 0 stevel 1561 0 stevel if (delta > 0) { 1562 0 stevel basedate->tv_sec -= (time_t)(delta / NANOSEC); 1563 0 stevel basedate->tv_usec -= (delta % NANOSEC) / 1000; 1564 0 stevel if (basedate->tv_usec < 0) { 1565 0 stevel basedate->tv_sec--; 1566 0 stevel basedate->tv_usec += MICROSEC; 1567 0 stevel } 1568 0 stevel } 1569 0 stevel ptm = localtime(&basedate->tv_sec); 1570 0 stevel ptime = asctime(ptm); 1571 0 stevel if ((pdst = tzname[ptm->tm_isdst ? 1 : 0]) == NULL) 1572 0 stevel pdst = "???"; 1573 0 stevel if (dflag) { 1574 0 stevel (void) printf( 1575 0 stevel "Base time stamp: %ld.%4.4ld [ %.20s%s %.4s ]\n", 1576 0 stevel basedate->tv_sec, basedate->tv_usec / 100, 1577 0 stevel ptime, pdst, ptime + 20); 1578 0 stevel Flush(); 1579 0 stevel } 1580 0 stevel } 1581 0 stevel } 1582 0 stevel 1583 0 stevel /* 1584 0 stevel * Performs per-process initializations. If truss is following a victim 1585 0 stevel * process it will fork additional truss processes to follow new processes 1586 0 stevel * created. Here is where each new truss process gets its per-process data 1587 0 stevel * initialized. 1588 0 stevel */ 1589 0 stevel 1590 0 stevel void 1591 0 stevel per_proc_init() 1592 0 stevel { 1593 0 stevel void *pmem; 1594 0 stevel struct timeval basedate; 1595 0 stevel hrtime_t basehrtime; 1596 0 stevel struct syscount *scp; 1597 0 stevel int i; 1598 0 stevel timestruc_t c_basetime; 1599 0 stevel 1600 0 stevel /* Make sure we only configure the basetime for the first truss proc */ 1601 0 stevel 1602 0 stevel if (Cp == NULL) { 1603 0 stevel pmem = my_malloc(sizeof (struct counts) + maxsyscalls() * 1604 0 stevel sizeof (struct syscount), NULL); 1605 0 stevel Cp = (struct counts *)pmem; 1606 0 stevel basehrtime = gethrtime(); 1607 0 stevel (void) gettimeofday(&basedate, NULL); 1608 0 stevel setup_basetime(basehrtime, &basedate); 1609 0 stevel } 1610 0 stevel 1611 0 stevel c_basetime = Cp->basetime; 1612 0 stevel 1613 0 stevel (void) memset(Cp, 0, sizeof (struct counts) + maxsyscalls() * 1614 0 stevel sizeof (struct syscount)); 1615 0 stevel 1616 0 stevel Cp->basetime = c_basetime; 1617 0 stevel 1618 0 stevel if (fcall_tbl != NULL) 1619 0 stevel destroy_hash(fcall_tbl); 1620 0 stevel fcall_tbl = init_hash(4096); 1621 0 stevel 1622 0 stevel (void) mutex_lock(&count_lock); 1623 0 stevel scp = (struct syscount *)(Cp + 1); 1624 0 stevel for (i = 0; i <= PRMAXSYS; i++) { 1625 0 stevel Cp->syscount[i] = scp; 1626 0 stevel scp += nsubcodes(i); 1627 0 stevel } 1628 0 stevel (void) mutex_unlock(&count_lock); 1629 0 stevel } 1630 0 stevel 1631 0 stevel 1632 0 stevel /* 1633 0 stevel * Writes child state to a tempfile where it can be read and 1634 0 stevel * accumulated by the parent process. The file descriptor is shared 1635 0 stevel * among the processes. Ordering of writes does not matter, it is, however, 1636 0 stevel * necessary to ensure that all writes are atomic. 1637 0 stevel */ 1638 0 stevel 1639 0 stevel void 1640 0 stevel child_to_file() 1641 0 stevel { 1642 0 stevel hiter_t *itr; 1643 0 stevel hentry_t *ntry; 1644 0 stevel hdntry_t fentry; 1645 0 stevel char *s = NULL; 1646 0 stevel char *t = NULL; 1647 0 stevel unsigned char *buf = NULL; 1648 0 stevel size_t bufsz = 0; 1649 0 stevel size_t i = 0; 1650 0 stevel size_t j = 0; 1651 0 stevel 1652 0 stevel /* ensure that we are in fact a child process */ 1653 0 stevel if (!descendent) 1654 0 stevel return; 1655 0 stevel 1656 0 stevel /* enumerate fcall_tbl (tbl locked until freed) */ 1657 0 stevel if (Dynpat != NULL) { 1658 0 stevel itr = iterate_hash(fcall_tbl); 1659 0 stevel 1660 0 stevel ntry = iter_next(itr); 1661 0 stevel while (ntry != NULL) { 1662 0 stevel fentry.type = HD_hashntry; 1663 0 stevel fentry.count = ntry->count; 1664 0 stevel s = ntry->key; 1665 0 stevel t = ntry->lib; 1666 0 stevel i = strlen(s) + 1; 1667 0 stevel j = strlen(t) + 1; 1668 0 stevel fentry.sz_key = i; 1669 0 stevel fentry.sz_lib = j; 1670 0 stevel if (i + sizeof (fentry) > bufsz) { 1671 0 stevel buf = my_realloc(buf, i + j + sizeof (fentry), 1672 0 stevel NULL); 1673 0 stevel bufsz = i + j + sizeof (fentry); 1674 0 stevel } 1675 0 stevel (void) memcpy(buf, &fentry, sizeof (fentry)); 1676 0 stevel (void) strlcpy((char *)(buf + sizeof (fentry)), t, j); 1677 0 stevel (void) strlcpy((char *)(buf + sizeof (fentry) + j), 1678 0 stevel s, i); 1679 0 stevel if (write(sfd, buf, sizeof (fentry) + i + j) == -1) 1680 0 stevel abend("Error writing to tmp file", NULL); 1681 0 stevel ntry = iter_next(itr); 1682 0 stevel } 1683 0 stevel iter_free(itr); 1684 0 stevel } 1685 0 stevel 1686 0 stevel /* Now write the count/syscount structs down */ 1687 0 stevel bufsz = sizeof (fentry) + (sizeof (struct counts) + maxsyscalls() * 1688 0 stevel sizeof (struct syscount)); 1689 0 stevel buf = my_realloc(buf, bufsz, NULL); 1690 0 stevel fentry.type = HD_cts_syscts; 1691 0 stevel fentry.count = 0; /* undefined, really */ 1692 0 stevel fentry.sz_key = bufsz - sizeof (fentry); 1693 0 stevel fentry.sz_lib = 0; /* also undefined */ 1694 0 stevel (void) memcpy(buf, &fentry, sizeof (fentry)); 1695 0 stevel (void) memcpy((char *)(buf + sizeof (fentry)), Cp, 1696 0 stevel bufsz - sizeof (fentry)); 1697 0 stevel if (write(sfd, buf, bufsz) == -1) 1698 0 stevel abend("Error writing cts/syscts to tmpfile", NULL); 1699 0 stevel 1700 0 stevel free(buf); 1701 0 stevel } 1702 0 stevel 1703 0 stevel /* 1704 0 stevel * The following reads entries from the tempfile back to the parent 1705 0 stevel * so that information can be collected and summed for overall statistics. 1706 0 stevel * This reads records out of the tempfile. If they are hash table entries, 1707 0 stevel * the record is merged with the hash table kept by the parent process. 1708 0 stevel * If the information is a struct count/struct syscount pair, they are 1709 0 stevel * copied and added into the count/syscount array kept by the parent. 1710 0 stevel */ 1711 0 stevel 1712 0 stevel void 1713 0 stevel file_to_parent() 1714 0 stevel { 1715 0 stevel hdntry_t ntry; 1716 0 stevel char *s = NULL; 1717 0 stevel char *t = NULL; 1718 0 stevel size_t c_offset = 0; 1719 0 stevel size_t filesz; 1720 0 stevel size_t t_strsz = 0; 1721 0 stevel size_t s_strsz = 0; 1722 0 stevel struct stat fsi; 1723 0 stevel 1724 0 stevel if (descendent) 1725 0 stevel return; 1726 0 stevel 1727 0 stevel if (fstat(sfd, &fsi) == -1) 1728 0 stevel abend("Error stat-ing tempfile", NULL); 1729 0 stevel filesz = fsi.st_size; 1730 0 stevel 1731 0 stevel while (c_offset < filesz) { 1732 0 stevel /* first get hdntry */ 1733 0 stevel if (pread(sfd, &ntry, sizeof (hdntry_t), c_offset) != 1734 0 stevel sizeof (hdntry_t)) 1735 0 stevel abend("Unable to perform full read of hdntry", NULL); 1736 0 stevel c_offset += sizeof (hdntry_t); 1737 0 stevel 1738 0 stevel switch (ntry.type) { 1739 0 stevel case HD_hashntry: 1740 0 stevel 1741 0 stevel /* first get lib string */ 1742 0 stevel if (ntry.sz_lib > t_strsz) { 1743 0 stevel t = my_realloc(t, ntry.sz_lib, NULL); 1744 0 stevel t_strsz = ntry.sz_lib; 1745 0 stevel } 1746 0 stevel 1747 0 stevel (void) memset(t, 0, t_strsz); 1748 0 stevel 1749 0 stevel /* now actually get the string */ 1750 0 stevel if (pread(sfd, t, ntry.sz_lib, c_offset) != ntry.sz_lib) 1751 0 stevel abend("Unable to perform full read of lib str", 1752 0 stevel NULL); 1753 0 stevel c_offset += ntry.sz_lib; 1754 0 stevel 1755 0 stevel /* now get key string */ 1756 0 stevel 1757 0 stevel if (ntry.sz_key > s_strsz) { 1758 0 stevel s = my_realloc(s, ntry.sz_key, NULL); 1759 0 stevel s_strsz = ntry.sz_key; 1760 0 stevel } 1761 0 stevel (void) memset(s, 0, s_strsz); 1762 0 stevel if (pread(sfd, s, ntry.sz_key, c_offset) != ntry.sz_key) 1763 0 stevel abend("Unable to perform full read of key str", 1764 0 stevel NULL); 1765 0 stevel c_offset += ntry.sz_key; 1766 0 stevel 1767 0 stevel add_fcall(fcall_tbl, t, s, ntry.count); 1768 0 stevel break; 1769 0 stevel 1770 0 stevel case HD_cts_syscts: 1771 0 stevel { 1772 0 stevel struct counts *ncp; 1773 0 stevel size_t bfsz = sizeof (struct counts) + maxsyscalls() 1774 0 stevel * sizeof (struct syscount); 1775 0 stevel int i; 1776 0 stevel struct syscount *sscp; 1777 0 stevel 1778 0 stevel if (ntry.sz_key != bfsz) 1779 0 stevel abend("cts/syscts size does not sanity check", 1780 0 stevel NULL); 1781 0 stevel ncp = my_malloc(ntry.sz_key, NULL); 1782 0 stevel 1783 0 stevel if (pread(sfd, ncp, ntry.sz_key, c_offset) != 1784 0 stevel ntry.sz_key) 1785 0 stevel abend("Unable to perform full read of cts", 1786 0 stevel NULL); 1787 0 stevel c_offset += ntry.sz_key; 1788 0 stevel 1789 0 stevel sscp = (struct syscount *)(ncp + 1); 1790 0 stevel 1791 0 stevel (void) mutex_lock(&count_lock); 1792 0 stevel 1793 0 stevel Cp->usrtotal.tv_sec += ncp->usrtotal.tv_sec; 1794 0 stevel Cp->usrtotal.tv_nsec += ncp->usrtotal.tv_nsec; 1795 0 stevel if (Cp->usrtotal.tv_nsec >= NANOSEC) { 1796 0 stevel Cp->usrtotal.tv_nsec -= NANOSEC; 1797 0 stevel Cp->usrtotal.tv_sec++; 1798 0 stevel } 1799 0 stevel for (i = 0; i <= PRMAXSYS; i++) { 1800 0 stevel ncp->syscount[i] = sscp; 1801 0 stevel sscp += nsubcodes(i); 1802 0 stevel } 1803 0 stevel 1804 0 stevel for (i = 0; i <= PRMAXFAULT; i++) { 1805 0 stevel Cp->fltcount[i] += ncp->fltcount[i]; 1806 0 stevel } 1807 0 stevel 1808 0 stevel for (i = 0; i <= PRMAXSIG; i++) { 1809 0 stevel Cp->sigcount[i] += ncp->sigcount[i]; 1810 0 stevel } 1811 0 stevel 1812 0 stevel for (i = 0; i <= PRMAXSYS; i++) { 1813 0 stevel struct syscount *scp = Cp->syscount[i]; 1814 0 stevel struct syscount *nscp = ncp->syscount[i]; 1815 0 stevel int n = nsubcodes(i); 1816 0 stevel int subcode; 1817 0 stevel 1818 0 stevel for (subcode = 0; subcode < n; subcode++, 1819 0 stevel scp++, nscp++) { 1820 0 stevel scp->count += nscp->count; 1821 0 stevel scp->error += nscp->error; 1822 0 stevel scp->stime.tv_sec += nscp->stime.tv_sec; 1823 0 stevel scp->stime.tv_nsec += 1824 0 stevel nscp->stime.tv_nsec; 1825 0 stevel if (scp->stime.tv_nsec >= NANOSEC) { 1826 0 stevel scp->stime.tv_nsec -= NANOSEC; 1827 0 stevel scp->stime.tv_sec++; 1828 0 stevel } 1829 0 stevel } 1830 0 stevel } 1831 0 stevel (void) mutex_unlock(&count_lock); 1832 0 stevel free(ncp); 1833 0 stevel break; 1834 0 stevel } 1835 0 stevel default: 1836 0 stevel 1837 0 stevel abend("Unknown file entry type encountered", NULL); 1838 0 stevel break; 1839 0 stevel 1840 0 stevel } 1841 0 stevel 1842 0 stevel if (fstat(sfd, &fsi) == -1) 1843 0 stevel abend("Error stat-ing tempfile", NULL); 1844 0 stevel filesz = fsi.st_size; 1845 0 stevel } 1846 0 stevel if (s != NULL) 1847 0 stevel free(s); 1848 0 stevel if (t != NULL) 1849 0 stevel free(t); 1850 0 stevel } 1851 0 stevel 1852 0 stevel void 1853 0 stevel make_pname(private_t *pri, id_t tid) 1854 0 stevel { 1855 0 stevel if (!cflag) { 1856 0 stevel int ff = (fflag || ngrab > 1); 1857 0 stevel int lf = (lflag | tid | (Thr_agent != NULL) | (truss_nlwp > 1)); 1858 0 stevel pid_t pid = Pstatus(Proc)->pr_pid; 1859 0 stevel id_t lwpid = pri->lwpstat->pr_lwpid; 1860 0 stevel 1861 0 stevel if (ff != pri->pparam.ff || 1862 0 stevel lf != pri->pparam.lf || 1863 0 stevel pid != pri->pparam.pid || 1864 0 stevel lwpid != pri->pparam.lwpid || 1865 0 stevel tid != pri->pparam.tid) { 1866 0 stevel char *s = pri->pname; 1867 0 stevel 1868 0 stevel if (ff) 1869 0 stevel s += sprintf(s, "%d", (int)pid); 1870 0 stevel if (lf) 1871 0 stevel s += sprintf(s, "/%d", (int)lwpid); 1872 0 stevel if (tid) 1873 0 stevel s += sprintf(s, "@%d", (int)tid); 1874 0 stevel if (ff || lf) 1875 0 stevel *s++ = ':', *s++ = '\t'; 1876 0 stevel if (ff && lf && s < pri->pname + 9) 1877 0 stevel *s++ = '\t'; 1878 0 stevel *s = '\0'; 1879 0 stevel pri->pparam.ff = ff; 1880 0 stevel pri->pparam.lf = lf; 1881 0 stevel pri->pparam.pid = pid; 1882 0 stevel pri->pparam.lwpid = lwpid; 1883 0 stevel pri->pparam.tid = tid; 1884 0 stevel } 1885 0 stevel } 1886 0 stevel } 1887 0 stevel 1888 0 stevel /* 1889 0 stevel * Print the pri->pname[] string, if any. 1890 0 stevel */ 1891 0 stevel void 1892 0 stevel putpname(private_t *pri) 1893 0 stevel { 1894 0 stevel if (pri->pname[0]) 1895 0 stevel (void) fputs(pri->pname, stdout); 1896 0 stevel } 1897 0 stevel 1898 0 stevel /* 1899 0 stevel * Print the timestamp, if requested (-d, -D, or -E). 1900 0 stevel */ 1901 0 stevel void 1902 0 stevel timestamp(private_t *pri) 1903 0 stevel { 1904 0 stevel const lwpstatus_t *Lsp = pri->lwpstat; 1905 0 stevel int seconds; 1906 0 stevel int fraction; 1907 0 stevel 1908 0 stevel if (!(dflag|Dflag|Eflag) || !(Lsp->pr_flags & PR_STOPPED)) 1909 0 stevel return; 1910 0 stevel 1911 0 stevel seconds = Lsp->pr_tstamp.tv_sec - Cp->basetime.tv_sec; 1912 0 stevel fraction = Lsp->pr_tstamp.tv_nsec - Cp->basetime.tv_nsec; 1913 0 stevel if (fraction < 0) { 1914 0 stevel seconds--; 1915 0 stevel fraction += NANOSEC; 1916 0 stevel } 1917 0 stevel /* fraction in 1/10 milliseconds, rounded up */ 1918 0 stevel fraction = (fraction + 50000) / 100000; 1919 0 stevel if (fraction >= (MILLISEC * 10)) { 1920 0 stevel seconds++; 1921 0 stevel fraction -= (MILLISEC * 10); 1922 0 stevel } 1923 0 stevel 1924 0 stevel if (dflag) /* time stamp */ 1925 0 stevel (void) printf("%2d.%4.4d\t", seconds, fraction); 1926 0 stevel 1927 0 stevel if (Dflag) { /* time delta */ 1928 0 stevel int oseconds = pri->seconds; 1929 0 stevel int ofraction = pri->fraction; 1930 0 stevel 1931 0 stevel pri->seconds = seconds; 1932 0 stevel pri->fraction = fraction; 1933 0 stevel seconds -= oseconds; 1934 0 stevel fraction -= ofraction; 1935 0 stevel if (fraction < 0) { 1936 0 stevel seconds--; 1937 0 stevel fraction += (MILLISEC * 10); 1938 0 stevel } 1939 0 stevel (void) printf("%2d.%4.4d\t", seconds, fraction); 1940 0 stevel } 1941 0 stevel 1942 0 stevel if (Eflag) { 1943 0 stevel seconds = Lsp->pr_stime.tv_sec - pri->syslast.tv_sec; 1944 0 stevel fraction = Lsp->pr_stime.tv_nsec - pri->syslast.tv_nsec; 1945 0 stevel 1946 0 stevel if (fraction < 0) { 1947 0 stevel seconds--; 1948 0 stevel fraction += NANOSEC; 1949 0 stevel } 1950 0 stevel /* fraction in 1/10 milliseconds, rounded up */ 1951 0 stevel fraction = (fraction + 50000) / 100000; 1952 0 stevel if (fraction >= (MILLISEC * 10)) { 1953 0 stevel seconds++; 1954 0 stevel fraction -= (MILLISEC * 10); 1955 0 stevel } 1956 0 stevel (void) printf("%2d.%4.4d\t", seconds, fraction); 1957 0 stevel } 1958 0 stevel } 1959 0 stevel 1960 0 stevel /* 1961 0 stevel * Create output file, being careful about 1962 0 stevel * suid/sgid and file descriptor 0, 1, 2 issues. 1963 0 stevel */ 1964 0 stevel int 1965 0 stevel xcreat(char *path) 1966 0 stevel { 1967 0 stevel int fd; 1968 0 stevel int mode = 0666; 1969 0 stevel 1970 0 stevel if (Euid == Ruid && Egid == Rgid) /* not set-id */ 1971 0 stevel fd = creat(path, mode); 1972 0 stevel else if (access(path, F_OK) != 0) { /* file doesn't exist */ 1973 0 stevel /* if directory permissions OK, create file & set ownership */ 1974 0 stevel 1975 0 stevel char *dir; 1976 0 stevel char *p; 1977 0 stevel char dot[4]; 1978 0 stevel 1979 0 stevel /* generate path for directory containing file */ 1980 0 stevel if ((p = strrchr(path, '/')) == NULL) { /* no '/' */ 1981 0 stevel p = dir = dot; 1982 0 stevel *p++ = '.'; /* current directory */ 1983 0 stevel *p = '\0'; 1984 0 stevel } else if (p == path) { /* leading '/' */ 1985 0 stevel p = dir = dot; 1986 0 stevel *p++ = '/'; /* root directory */ 1987 0 stevel *p = '\0'; 1988 0 stevel } else { /* embedded '/' */ 1989 0 stevel dir = path; /* directory path */ 1990 0 stevel *p = '\0'; 1991 0 stevel } 1992 0 stevel 1993 0 stevel if (access(dir, W_OK|X_OK) != 0) { 1994 0 stevel /* not writeable/searchable */ 1995 0 stevel *p = '/'; 1996 0 stevel fd = -1; 1997 0 stevel } else { /* create file and set ownership correctly */ 1998 0 stevel *p = '/'; 1999 0 stevel if ((fd = creat(path, mode)) >= 0) 2000 0 stevel (void) chown(path, (int)Ruid, (int)Rgid); 2001 0 stevel } 2002 0 stevel } else if (access(path, W_OK) != 0) /* file not writeable */ 2003 0 stevel fd = -1; 2004 0 stevel else 2005 0 stevel fd = creat(path, mode); 2006 0 stevel 2007 0 stevel /* 2008 0 stevel * Make sure it's not one of 0, 1, or 2. 2009 0 stevel * This allows truss to work when spawned by init(1m). 2010 0 stevel */ 2011 0 stevel if (0 <= fd && fd <= 2) { 2012 0 stevel int dfd = fcntl(fd, F_DUPFD, 3); 2013 0 stevel (void) close(fd); 2014 0 stevel fd = dfd; 2015 0 stevel } 2016 0 stevel 2017 0 stevel /* 2018 0 stevel * Mark it close-on-exec so created processes don't inherit it. 2019 0 stevel */ 2020 0 stevel if (fd >= 0) 2021 0 stevel (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 2022 0 stevel 2023 0 stevel return (fd); 2024 0 stevel } 2025 0 stevel 2026 0 stevel void 2027 0 stevel setoutput(int ofd) 2028 0 stevel { 2029 0 stevel if (ofd < 0) { 2030 0 stevel (void) close(1); 2031 0 stevel (void) fcntl(2, F_DUPFD, 1); 2032 0 stevel } else if (ofd != 1) { 2033 0 stevel (void) close(1); 2034 0 stevel (void) fcntl(ofd, F_DUPFD, 1); 2035 0 stevel (void) close(ofd); 2036 0 stevel /* if no stderr, make it the same file */ 2037 0 stevel if ((ofd = dup(2)) < 0) 2038 0 stevel (void) fcntl(1, F_DUPFD, 2); 2039 0 stevel else 2040 0 stevel (void) close(ofd); 2041 0 stevel } 2042 0 stevel } 2043 0 stevel 2044 0 stevel /* 2045 0 stevel * Accumulate time differencies: a += e - s; 2046 0 stevel */ 2047 0 stevel void 2048 0 stevel accumulate(timestruc_t *ap, const timestruc_t *ep, const timestruc_t *sp) 2049 0 stevel { 2050 0 stevel ap->tv_sec += ep->tv_sec - sp->tv_sec; 2051 0 stevel ap->tv_nsec += ep->tv_nsec - sp->tv_nsec; 2052 0 stevel if (ap->tv_nsec >= NANOSEC) { 2053 0 stevel ap->tv_nsec -= NANOSEC; 2054 0 stevel ap->tv_sec++; 2055 0 stevel } else if (ap->tv_nsec < 0) { 2056 0 stevel ap->tv_nsec += NANOSEC; 2057 0 stevel ap->tv_sec--; 2058 0 stevel } 2059 0 stevel } 2060 0 stevel 2061 0 stevel int 2062 0 stevel lib_sort(const void *p1, const void *p2) 2063 0 stevel { 2064 0 stevel int cmpr = 0; 2065 0 stevel long i; 2066 0 stevel long j; 2067 0 stevel 2068 0 stevel hentry_t *t1 = (hentry_t *)p1; 2069 0 stevel hentry_t *t2 = (hentry_t *)p2; 2070 0 stevel 2071 0 stevel char *p = t1->lib; 2072 0 stevel char *q = t2->lib; 2073 0 stevel 2074 0 stevel if ((cmpr = strcmp(p, q)) == 0) { 2075 0 stevel i = t1->count; 2076 0 stevel j = t2->count; 2077 0 stevel if (i > j) 2078 0 stevel return (-1); 2079 0 stevel else if (i < j) 2080 0 stevel return (1); 2081 0 stevel else { 2082 0 stevel p = t1->key; 2083 0 stevel q = t2->key; 2084 0 stevel return (strcmp(p, q)); 2085 0 stevel } 2086 0 stevel } else 2087 0 stevel return (cmpr); 2088 0 stevel } 2089 0 stevel 2090 0 stevel void 2091 0 stevel report(private_t *pri, time_t lapse) /* elapsed time, clock ticks */ 2092 0 stevel { 2093 0 stevel int i; 2094 0 stevel long count; 2095 0 stevel const char *name; 2096 0 stevel long error; 2097 0 stevel long total; 2098 0 stevel long errtot; 2099 0 stevel timestruc_t tickzero; 2100 0 stevel timestruc_t ticks; 2101 0 stevel timestruc_t ticktot; 2102 0 stevel 2103 0 stevel if (descendent) 2104 0 stevel return; 2105 0 stevel 2106 0 stevel for (i = 0, total = 0; i <= PRMAXFAULT && !interrupt; i++) { 2107 0 stevel if ((count = Cp->fltcount[i]) != 0) { 2108 0 stevel if (total == 0) /* produce header */ 2109 0 stevel (void) printf("faults -------------\n"); 2110 0 stevel 2111 0 stevel name = proc_fltname(i, pri->flt_name, 2112 0 stevel sizeof (pri->flt_name)); 2113 0 stevel 2114 0 stevel (void) printf("%s%s\t%4ld\n", name, 2115 0 stevel (((int)strlen(name) < 8)? 2116 0 stevel (const char *)"\t" : (const char *)""), 2117 0 stevel count); 2118 0 stevel total += count; 2119 0 stevel } 2120 0 stevel } 2121 0 stevel if (total && !interrupt) 2122 0 stevel (void) printf("total:\t\t%4ld\n\n", total); 2123 0 stevel 2124 0 stevel for (i = 0, total = 0; i <= PRMAXSIG && !interrupt; i++) { 2125 0 stevel if ((count = Cp->sigcount[i]) != 0) { 2126 0 stevel if (total == 0) /* produce header */ 2127 0 stevel (void) printf("signals ------------\n"); 2128 0 stevel name = signame(pri, i); 2129 0 stevel (void) printf("%s%s\t%4ld\n", name, 2130 0 stevel (((int)strlen(name) < 8)? 2131 0 stevel (const char *)"\t" : (const char *)""), 2132 0 stevel count); 2133 0 stevel total += count; 2134 0 stevel } 2135 0 stevel } 2136 0 stevel if (total && !interrupt) 2137 0 stevel (void) printf("total:\t\t%4ld\n\n", total); 2138 0 stevel 2139 0 stevel if ((Dynpat != NULL) && !interrupt) { 2140 0 stevel size_t elem = elements_in_table(fcall_tbl); 2141 0 stevel hiter_t *itr = iterate_hash(fcall_tbl); 2142 0 stevel hentry_t *tmp = iter_next(itr); 2143 0 stevel hentry_t *stbl = my_malloc(elem * sizeof (hentry_t), NULL); 2144 0 stevel i = 0; 2145 0 stevel while ((tmp != NULL) && (i < elem)) { 2146 0 stevel stbl[i].prev = tmp->prev; 2147 0 stevel stbl[i].next = tmp->next; 2148 0 stevel stbl[i].lib = tmp->lib; 2149 0 stevel stbl[i].key = tmp->key; 2150 0 stevel stbl[i].count = tmp->count; 2151 0 stevel tmp = iter_next(itr); 2152 0 stevel i++; 2153 0 stevel } 2154 0 stevel qsort((void *)stbl, elem, sizeof (hentry_t), 2155 0 stevel lib_sort); 2156 0 stevel (void) printf( 2157 0 stevel "\n%-20s %-40s %s\n", "Library:", "Function", "calls"); 2158 0 stevel for (i = 0; i < elem; i++) { 2159 0 stevel (void) printf("%-20s %-40s %ld\n", stbl[i].lib, 2160 0 stevel stbl[i].key, stbl[i].count); 2161 0 stevel } 2162 0 stevel iter_free(itr); 2163 0 stevel free(stbl); 2164 0 stevel itr = NULL; 2165 0 stevel } 2166 0 stevel 2167 0 stevel if (!interrupt) 2168 0 stevel (void) printf( 2169 0 stevel "\nsyscall seconds calls errors\n"); 2170 0 stevel 2171 0 stevel total = errtot = 0; 2172 0 stevel tickzero.tv_sec = ticks.tv_sec = ticktot.tv_sec = 0; 2173 0 stevel tickzero.tv_nsec = ticks.tv_nsec = ticktot.tv_nsec = 0; 2174 0 stevel for (i = 0; i <= PRMAXSYS && !interrupt; i++) { 2175 0 stevel struct syscount *scp = Cp->syscount[i]; 2176 0 stevel int n = nsubcodes(i); 2177 0 stevel int subcode; 2178 0 stevel 2179 0 stevel for (subcode = 0; subcode < n; subcode++, scp++) { 2180 0 stevel if ((count = scp->count) != 0 || scp->error) { 2181 0 stevel (void) printf("%-19.19s ", 2182 0 stevel sysname(pri, i, subcode)); 2183 0 stevel 2184 0 stevel ticks = scp->stime; 2185 0 stevel accumulate(&ticktot, &ticks, &tickzero); 2186 0 stevel prtim(&ticks); 2187 0 stevel 2188 0 stevel (void) printf(" %7ld", count); 2189 0 stevel if ((error = scp->error) != 0) 2190 0 stevel (void) printf(" %7ld", error); 2191 0 stevel (void) fputc('\n', stdout); 2192 0 stevel total += count; 2193 0 stevel errtot += error; 2194 0 stevel } 2195 0 stevel } 2196 0 stevel } 2197 0 stevel 2198 0 stevel if (!interrupt) { 2199 0 stevel (void) printf( 2200 0 stevel " -------- ------ ----\n"); 2201 0 stevel (void) printf("sys totals: "); 2202 0 stevel prtim(&ticktot); 2203 0 stevel (void) printf(" %7ld %6ld\n", total, errtot); 2204 0 stevel } 2205 0 stevel 2206 0 stevel if (!interrupt) { 2207 0 stevel (void) printf("usr time: "); 2208 0 stevel prtim(&Cp->usrtotal); 2209 0 stevel (void) fputc('\n', stdout); 2210 0 stevel } 2211 0 stevel 2212 0 stevel if (!interrupt) { 2213 0 stevel int hz = (int)sysconf(_SC_CLK_TCK); 2214 0 stevel 2215 0 stevel ticks.tv_sec = lapse / hz; 2216 0 stevel ticks.tv_nsec = (lapse % hz) * (1000000000 / hz); 2217 0 stevel (void) printf("elapsed: "); 2218 0 stevel prtim(&ticks); 2219 0 stevel (void) fputc('\n', stdout); 2220 0 stevel } 2221 0 stevel } 2222 0 stevel 2223 0 stevel void 2224 0 stevel prtim(timestruc_t *tp) 2225 0 stevel { 2226 0 stevel time_t sec; 2227 0 stevel 2228 0 stevel if ((sec = tp->tv_sec) != 0) /* whole seconds */ 2229 0 stevel (void) printf("%5lu", sec); 2230 0 stevel else 2231 0 stevel (void) printf(" "); 2232 0 stevel 2233 0 stevel (void) printf(".%3.3ld", tp->tv_nsec/1000000); /* fraction */ 2234 0 stevel } 2235 0 stevel 2236 0 stevel /* 2237 0 stevel * Gather process id's. 2238 0 stevel * Return 0 on success, != 0 on failure. 2239 0 stevel */ 2240 0 stevel void 2241 0 stevel pids(char *arg, proc_set_t *grab) 2242 0 stevel { 2243 0 stevel pid_t pid = -1; 2244 0 stevel int i; 2245 0 stevel const char *lwps = NULL; 2246 0 stevel 2247 0 stevel if ((pid = proc_arg_xpsinfo(arg, PR_ARG_PIDS, NULL, &i, &lwps)) < 0) { 2248 0 stevel (void) fprintf(stderr, "%s: cannot trace '%s': %s\n", 2249 0 stevel command, arg, Pgrab_error(i)); 2250 0 stevel return; 2251 0 stevel } 2252 0 stevel 2253 0 stevel for (i = 0; i < ngrab; i++) 2254 0 stevel if (grab[i].pid == pid) /* duplicate */ 2255 0 stevel break; 2256 0 stevel 2257 0 stevel if (i == ngrab) { 2258 0 stevel grab[ngrab].pid = pid; 2259 0 stevel grab[ngrab].lwps = lwps; 2260 0 stevel ngrab++; 2261 0 stevel } else { 2262 0 stevel (void) fprintf(stderr, "%s: duplicate process-id ignored: %d\n", 2263 0 stevel command, (int)pid); 2264 0 stevel } 2265 0 stevel } 2266 0 stevel 2267 0 stevel /* 2268 0 stevel * Report psargs string. 2269 0 stevel */ 2270 0 stevel void 2271 0 stevel psargs(private_t *pri) 2272 0 stevel { 2273 0 stevel pid_t pid = Pstatus(Proc)->pr_pid; 2274 0 stevel psinfo_t psinfo; 2275 0 stevel 2276 0 stevel if (proc_get_psinfo(pid, &psinfo) == 0) 2277 0 stevel (void) printf("%spsargs: %.64s\n", 2278 0 stevel pri->pname, psinfo.pr_psargs); 2279 0 stevel else { 2280 0 stevel perror("psargs()"); 2281 0 stevel (void) printf("%s\t*** Cannot read psinfo file for pid %d\n", 2282 0 stevel pri->pname, (int)pid); 2283 0 stevel } 2284 0 stevel } 2285 0 stevel 2286 0 stevel char * 2287 0 stevel fetchstring(private_t *pri, long addr, int maxleng) 2288 0 stevel { 2289 0 stevel int nbyte; 2290 0 stevel int leng = 0; 2291 0 stevel char string[41]; 2292 0 stevel 2293 0 stevel string[40] = '\0'; 2294 0 stevel if (pri->str_bsize == 0) /* initial allocation of string buffer */ 2295 0 stevel pri->str_buffer = 2296 0 stevel my_malloc(pri->str_bsize = 16, "string buffer"); 2297 0 stevel *pri->str_buffer = '\0'; 2298 0 stevel 2299 0 stevel for (nbyte = 40; nbyte == 40 && leng < maxleng; addr += 40) { 2300 0 stevel if ((nbyte = Pread(Proc, string, 40, addr)) <= 0) 2301 0 stevel return (leng? pri->str_buffer : NULL); 2302 0 stevel if (nbyte > 0 && 2303 0 stevel (nbyte = strlen(string)) > 0) { 2304 0 stevel while (leng + nbyte >= pri->str_bsize) 2305 0 stevel pri->str_buffer = 2306 0 stevel my_realloc(pri->str_buffer, 2307 0 stevel pri->str_bsize *= 2, "string buffer"); 2308 0 stevel (void) strcpy(pri->str_buffer+leng, string); 2309 0 stevel leng += nbyte; 2310 0 stevel } 2311 0 stevel } 2312 0 stevel 2313 0 stevel if (leng > maxleng) 2314 0 stevel leng = maxleng; 2315 0 stevel pri->str_buffer[leng] = '\0'; 2316 0 stevel 2317 0 stevel return (pri->str_buffer); 2318 0 stevel } 2319 0 stevel 2320 0 stevel void 2321 0 stevel show_cred(private_t *pri, int new) 2322 0 stevel { 2323 0 stevel prcred_t cred; 2324 0 stevel 2325 0 stevel if (proc_get_cred(Pstatus(Proc)->pr_pid, &cred, 0) < 0) { 2326 0 stevel perror("show_cred()"); 2327 0 stevel (void) printf("%s\t*** Cannot get credentials\n", pri->pname); 2328 0 stevel return; 2329 0 stevel } 2330 0 stevel 2331 0 stevel if (!cflag && prismember(&trace, SYS_exec)) { 2332 0 stevel if (new) 2333 0 stevel credentials = cred; 2334 0 stevel if ((new && cred.pr_ruid != cred.pr_suid) || 2335 0 stevel cred.pr_ruid != credentials.pr_ruid || 2336 0 stevel cred.pr_suid != credentials.pr_suid) 2337 0 stevel (void) printf( 2338 0 stevel "%s *** SUID: ruid/euid/suid = %d / %d / %d ***\n", 2339 0 stevel pri->pname, 2340 0 stevel (int)cred.pr_ruid, 2341 0 stevel (int)cred.pr_euid, 2342 0 stevel (int)cred.pr_suid); 2343 0 stevel if ((new && cred.pr_rgid != cred.pr_sgid) || 2344 0 stevel cred.pr_rgid != credentials.pr_rgid || 2345 0 stevel cred.pr_sgid != credentials.pr_sgid) 2346 0 stevel (void) printf( 2347 0 stevel "%s *** SGID: rgid/egid/sgid = %d / %d / %d ***\n", 2348 0 stevel pri->pname, 2349 0 stevel (int)cred.pr_rgid, 2350 0 stevel (int)cred.pr_egid, 2351 0 stevel (int)cred.pr_sgid); 2352 0 stevel } 2353 0 stevel 2354 0 stevel credentials = cred; 2355 0 stevel } 2356 0 stevel 2357 0 stevel /* 2358 0 stevel * Take control of a child process. 2359 0 stevel * We come here with truss_lock held. 2360 0 stevel */ 2361 0 stevel int 2362 0 stevel control(private_t *pri, pid_t pid) 2363 0 stevel { 2364 0 stevel const pstatus_t *Psp; 2365 0 stevel const lwpstatus_t *Lsp; 2366 0 stevel pid_t childpid = 0; 2367 0 stevel long flags; 2368 0 stevel int rc; 2369 0 stevel 2370 0 stevel (void) mutex_lock(&gps->fork_lock); 2371 0 stevel while (gps->fork_pid != 0) 2372 0 stevel (void) cond_wait(&gps->fork_cv, &gps->fork_lock); 2373 0 stevel gps->fork_pid = getpid(); /* parent pid */ 2374 3235 raf if ((childpid = fork()) == -1) { 2375 0 stevel (void) printf("%s\t*** Cannot fork() to control process #%d\n", 2376 0 stevel pri->pname, (int)pid); 2377 0 stevel Flush(); 2378 0 stevel gps->fork_pid = 0; 2379 0 stevel (void) cond_broadcast(&gps->fork_cv); 2380 0 stevel (void) mutex_unlock(&gps->fork_lock); 2381 0 stevel release(pri, pid); 2382 0 stevel return (FALSE); 2383 0 stevel } 2384 0 stevel 2385 0 stevel if (childpid != 0) { 2386 0 stevel /* 2387 0 stevel * The parent carries on, after a brief pause. 2388 0 stevel * The parent must wait until the child executes procadd(pid). 2389 0 stevel */ 2390 0 stevel while (gps->fork_pid != childpid) 2391 0 stevel (void) cond_wait(&gps->fork_cv, &gps->fork_lock); 2392 0 stevel gps->fork_pid = 0; 2393 0 stevel (void) cond_broadcast(&gps->fork_cv); 2394 0 stevel (void) mutex_unlock(&gps->fork_lock); 2395 0 stevel return (FALSE); 2396 0 stevel } 2397 0 stevel 2398 0 stevel childpid = getpid(); 2399 0 stevel descendent = TRUE; 2400 0 stevel exit_called = FALSE; 2401 0 stevel Pfree(Proc); /* forget old process */ 2402 0 stevel 2403 0 stevel /* 2404 0 stevel * The parent process owns the shared gps->fork_lock. 2405 0 stevel * The child must grab it again. 2406 0 stevel */ 2407 0 stevel (void) mutex_lock(&gps->fork_lock); 2408 0 stevel 2409 0 stevel /* 2410 0 stevel * Child grabs the process and retains the tracing flags. 2411 0 stevel */ 2412 0 stevel if ((Proc = Pgrab(pid, PGRAB_RETAIN, &rc)) == NULL) { 2413 0 stevel (void) fprintf(stderr, 2414 0 stevel "%s: cannot control child process, pid# %d: %s\n", 2415 0 stevel command, (int)pid, Pgrab_error(rc)); 2416 0 stevel gps->fork_pid = childpid; 2417 0 stevel (void) cond_broadcast(&gps->fork_cv); 2418 0 stevel (void) mutex_unlock(&gps->fork_lock); 2419 0 stevel exit(2); 2420 0 stevel } 2421 0 stevel 2422 0 stevel per_proc_init(); 2423 0 stevel /* 2424 0 stevel * Add ourself to the set of truss processes 2425 0 stevel * and notify the parent to carry on. 2426 0 stevel */ 2427 0 stevel procadd(pid, NULL); 2428 0 stevel gps->fork_pid = childpid; 2429 0 stevel (void) cond_broadcast(&gps->fork_cv); 2430 0 stevel (void) mutex_unlock(&gps->fork_lock); 2431 0 stevel 2432 0 stevel /* 2433 0 stevel * We may have grabbed the child before it is fully stopped on exit 2434 0 stevel * from fork. Wait one second (at most) for it to settle down. 2435 0 stevel */ 2436 0 stevel (void) Pwait(Proc, MILLISEC); 2437 0 stevel if (Rdb_agent != NULL) 2438 0 stevel Rdb_agent = Prd_agent(Proc); 2439 0 stevel 2440 0 stevel Psp = Pstatus(Proc); 2441 0 stevel Lsp = &Psp->pr_lwp; 2442 0 stevel pri->lwpstat = Lsp; 2443 0 stevel data_model = Psp->pr_dmodel; 2444 0 stevel 2445 0 stevel make_pname(pri, 0); 2446 0 stevel 2447 0 stevel pri->syslast = Psp->pr_stime; 2448 0 stevel pri->usrlast = Psp->pr_utime; 2449 0 stevel 2450 0 stevel flags = PR_FORK | PR_ASYNC; 2451 0 stevel if (Dynpat != NULL) 2452 0 stevel flags |= PR_BPTADJ; /* needed for x86 */ 2453 0 stevel (void) Psetflags(Proc, flags); 2454 0 stevel 2455 0 stevel return (TRUE); 2456 0 stevel } 2457 0 stevel 2458 0 stevel /* 2459 0 stevel * Take control of an existing process. 2460 0 stevel */ 2461 0 stevel int 2462 0 stevel grabit(private_t *pri, proc_set_t *set) 2463 0 stevel { 2464 0 stevel const pstatus_t *Psp; 2465 0 stevel const lwpstatus_t *Lsp; 2466 0 stevel int gcode; 2467 0 stevel 2468 0 stevel /* 2469 0 stevel * Don't force the takeover unless the -F option was specified. 2470 0 stevel */ 2471 0 stevel if ((Proc = Pgrab(set->pid, Fflag, &gcode)) == NULL) { 2472 0 stevel (void) fprintf(stderr, "%s: %s: %d\n", 2473 0 stevel command, Pgrab_error(gcode), (int)set->pid); 2474 0 stevel pri->lwpstat = NULL; 2475 0 stevel return (FALSE); 2476 0 stevel } 2477 0 stevel Psp = Pstatus(Proc); 2478 0 stevel Lsp = &Psp->pr_lwp; 2479 0 stevel pri->lwpstat = Lsp; 2480 0 stevel 2481 0 stevel make_pname(pri, 0); 2482 0 stevel 2483 0 stevel data_model = Psp->pr_dmodel; 2484 0 stevel pri->syslast = Psp->pr_stime; 2485 0 stevel pri->usrlast = Psp->pr_utime; 2486 0 stevel 2487 0 stevel if (fflag || Dynpat != NULL) 2488 0 stevel (void) Psetflags(Proc, PR_FORK); 2489 0 stevel else 2490 0 stevel (void) Punsetflags(Proc, PR_FORK); 2491 0 stevel procadd(set->pid, set->lwps); 2492 0 stevel show_cred(pri, TRUE); 2493 0 stevel return (TRUE); 2494 0 stevel } 2495 0 stevel 2496 0 stevel /* 2497 0 stevel * Release process from control. 2498 0 stevel */ 2499 0 stevel void 2500 0 stevel release(private_t *pri, pid_t pid) 2501 0 stevel { 2502 0 stevel /* 2503 0 stevel * The process in question is the child of a traced process. 2504 0 stevel * We are here to turn off the inherited tracing flags. 2505 0 stevel */ 2506 0 stevel int fd; 2507 0 stevel char ctlname[100]; 2508 0 stevel long ctl[2]; 2509 0 stevel 2510 0 stevel ctl[0] = PCSET; 2511 0 stevel ctl[1] = PR_RLC; 2512 0 stevel 2513 0 stevel /* process is freshly forked, no need for exclusive open */ 2514 0 stevel (void) sprintf(ctlname, "/proc/%d/ctl", (int)pid); 2515 0 stevel if ((fd = open(ctlname, O_WRONLY)) < 0 || 2516 0 stevel write(fd, (char *)ctl, sizeof (ctl)) < 0) { 2517 0 stevel perror("release()"); 2518 0 stevel (void) printf( 2519 0 stevel "%s\t*** Cannot release child process, pid# %d\n", 2520 0 stevel pri->pname, (int)pid); 2521 0 stevel Flush(); 2522 0 stevel } 2523 0 stevel if (fd >= 0) /* run-on-last-close sets the process running */ 2524 0 stevel (void) close(fd); 2525 0 stevel } 2526 0 stevel 2527 0 stevel void 2528 0 stevel intr(int sig) 2529 0 stevel { 2530 0 stevel /* 2531 0 stevel * SIGUSR1 is special. It is used by one truss process to tell 2532 0 stevel * another truss process to release its controlled process. 2533 0 stevel * SIGUSR2 is also special. It is used to wake up threads waiting 2534 0 stevel * for a victim lwp to stop after an event that will leave the 2535 0 stevel * process hung (stopped and abandoned) has occurred. 2536 0 stevel */ 2537 0 stevel if (sig == SIGUSR1) { 2538 0 stevel sigusr1 = TRUE; 2539 0 stevel } else if (sig == SIGUSR2) { 2540 0 stevel void *value; 2541 0 stevel private_t *pri; 2542 0 stevel struct ps_lwphandle *Lwp; 2543 0 stevel 2544 0 stevel if (thr_getspecific(private_key, &value) == 0 && 2545 0 stevel (pri = value) != NULL && 2546 0 stevel (Lwp = pri->Lwp) != NULL) 2547 0 stevel (void) Lstop(Lwp, MILLISEC / 10); 2548 0 stevel } else { 2549 0 stevel interrupt = sig; 2550 0 stevel } 2551 0 stevel } 2552 0 stevel 2553 0 stevel void 2554 0 stevel errmsg(const char *s, const char *q) 2555 0 stevel { 2556 0 stevel char msg[512]; 2557 0 stevel 2558 0 stevel if (s || q) { 2559 0 stevel msg[0] = '\0'; 2560 0 stevel if (command) { 2561 0 stevel (void) strcpy(msg, command); 2562 0 stevel (void) strcat(msg, ": "); 2563 0 stevel } 2564 0 stevel if (s) 2565 0 stevel (void) strcat(msg, s); 2566 0 stevel if (q) 2567 0 stevel (void) strcat(msg, q); 2568 0 stevel (void) strcat(msg, "\n"); 2569 0 stevel (void) write(2, msg, (size_t)strlen(msg)); 2570 0 stevel } 2571 0 stevel } 2572 0 stevel 2573 0 stevel void 2574 0 stevel abend(const char *s, const char *q) 2575 0 stevel { 2576 1132 raf (void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL); 2577 0 stevel if (Proc) { 2578 0 stevel Flush(); 2579 0 stevel errmsg(s, q); 2580 0 stevel clear_breakpoints(); 2581 0 stevel (void) Punsetflags(Proc, PR_ASYNC); 2582 0 stevel Prelease(Proc, created? PRELEASE_KILL : PRELEASE_CLEAR); 2583 0 stevel procdel(); 2584 0 stevel (void) wait4all(); 2585 0 stevel } else { 2586 0 stevel errmsg(s, q); 2587 0 stevel } 2588 0 stevel exit(2); 2589 0 stevel } 2590 0 stevel 2591 0 stevel /* 2592 0 stevel * Allocate memory. 2593 0 stevel * If allocation fails then print a message and abort. 2594 0 stevel */ 2595 0 stevel void * 2596 0 stevel my_realloc(void *buf, size_t size, const char *msg) 2597 0 stevel { 2598 0 stevel if ((buf = realloc(buf, size)) == NULL) { 2599 0 stevel if (msg != NULL) 2600 0 stevel abend("cannot allocate ", msg); 2601 0 stevel else 2602 0 stevel abend("memory allocation failure", NULL); 2603 0 stevel } 2604 0 stevel 2605 0 stevel return (buf); 2606 0 stevel } 2607 0 stevel 2608 0 stevel void * 2609 0 stevel my_calloc(size_t nelem, size_t elsize, const char *msg) 2610 0 stevel { 2611 0 stevel void *buf = NULL; 2612 0 stevel 2613 0 stevel if ((buf = calloc(nelem, elsize)) == NULL) { 2614 0 stevel if (msg != NULL) 2615 0 stevel abend("cannot allocate ", msg); 2616 0 stevel else 2617 0 stevel abend("memory allocation failure", NULL); 2618 0 stevel } 2619 0 stevel 2620 0 stevel return (buf); 2621 0 stevel } 2622 0 stevel 2623 0 stevel void * 2624 0 stevel my_malloc(size_t size, const char *msg) 2625 0 stevel { 2626 0 stevel return (my_realloc(NULL, size, msg)); 2627 0 stevel } 2628 0 stevel 2629 0 stevel int 2630 0 stevel wait4all() 2631 0 stevel { 2632 0 stevel int i; 2633 0 stevel pid_t pid; 2634 0 stevel int rc = 0; 2635 0 stevel int status; 2636 0 stevel 2637 0 stevel for (i = 0; i < 10; i++) { 2638 0 stevel while ((pid = wait(&status)) != -1) { 2639 0 stevel /* return exit() code of the created process */ 2640 0 stevel if (pid == created) { 2641 0 stevel if (WIFEXITED(status)) 2642 0 stevel rc = WEXITSTATUS(status); 2643 0 stevel else 2644 0 stevel rc |= 0x80; /* +128 to indicate sig */ 2645 0 stevel } 2646 0 stevel } 2647 0 stevel if (errno != EINTR && errno != ERESTART) 2648 0 stevel break; 2649 0 stevel } 2650 0 stevel 2651 0 stevel if (i >= 10) /* repeated interrupts */ 2652 0 stevel rc = 2; 2653 0 stevel 2654 0 stevel return (rc); 2655 0 stevel } 2656 0 stevel 2657 0 stevel void 2658 0 stevel letgo(private_t *pri) 2659 0 stevel { 2660 0 stevel (void) printf("%s\t*** process otherwise traced, releasing ...\n", 2661 0 stevel pri->pname); 2662 0 stevel } 2663 0 stevel 2664 0 stevel /* 2665 0 stevel * Test for empty set. 2666 0 stevel * support routine used by isemptyset() macro. 2667 0 stevel */ 2668 0 stevel int 2669 0 stevel is_empty(const uint32_t *sp, /* pointer to set (array of int32's) */ 2670 0 stevel size_t n) /* number of int32's in set */ 2671 0 stevel { 2672 0 stevel if (n) { 2673 0 stevel do { 2674 0 stevel if (*sp++) 2675 0 stevel return (FALSE); 2676 0 stevel } while (--n); 2677 0 stevel } 2678 0 stevel 2679 0 stevel return (TRUE); 2680 0 stevel } 2681 0 stevel 2682 0 stevel /* 2683 0 stevel * OR the second set into the first. 2684 0 stevel * The sets must be the same size. 2685 0 stevel */ 2686 0 stevel void 2687 0 stevel or_set(uint32_t *sp1, const uint32_t *sp2, size_t n) 2688 0 stevel { 2689 0 stevel if (n) { 2690 0 stevel do { 2691 0 stevel *sp1++ |= *sp2++; 2692 0 stevel } while (--n); 2693 0 stevel } 2694 0 stevel } 2695