blob: fb056134a117cb1bbdf98f5b1ea9db304bd4010f [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00006 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * $Id$
31 */
32
33#include "defs.h"
34
Roland McGrath795edb12005-02-02 04:44:57 +000035#include <sys/types.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000036#include <signal.h>
37#include <errno.h>
38#include <sys/param.h>
39#include <fcntl.h>
40#include <sys/resource.h>
41#include <sys/wait.h>
42#include <sys/stat.h>
Denys Vlasenko7e0615f2009-01-28 19:00:54 +000043#include <sys/utsname.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000044#include <pwd.h>
45#include <grp.h>
46#include <string.h>
John Hughes19e49982001-10-19 08:59:12 +000047#include <limits.h>
Roland McGrath70b08532004-04-09 00:25:21 +000048#include <dirent.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000049
Roland McGrath134813a2007-06-02 00:07:33 +000050#ifdef LINUX
51# include <asm/unistd.h>
52# if defined __NR_tgkill
53# define my_tgkill(pid, tid, sig) syscall (__NR_tgkill, (pid), (tid), (sig))
54# elif defined __NR_tkill
55# define my_tgkill(pid, tid, sig) syscall (__NR_tkill, (tid), (sig))
56# else
57 /* kill() may choose arbitrarily the target task of the process group
58 while we later wait on a that specific TID. PID process waits become
59 TID task specific waits for a process under ptrace(2). */
60# warning "Neither tkill(2) nor tgkill(2) available, risk of strace hangs!"
61# define my_tgkill(pid, tid, sig) kill ((tid), (sig))
62# endif
63#endif
64
Wichert Akkerman7b3346b2001-10-09 23:47:38 +000065#if defined(IA64) && defined(LINUX)
66# include <asm/ptrace_offsets.h>
67#endif
68
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +000069#ifdef USE_PROCFS
70#include <poll.h>
71#endif
72
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000073#ifdef SVR4
74#include <sys/stropts.h>
Wichert Akkermanea78f0f1999-11-29 15:34:02 +000075#ifdef HAVE_MP_PROCFS
John Hughes1d08dcf2001-07-10 13:48:44 +000076#ifdef HAVE_SYS_UIO_H
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000077#include <sys/uio.h>
78#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000079#endif
John Hughes1d08dcf2001-07-10 13:48:44 +000080#endif
Denys Vlasenko96d5a762008-12-29 19:13:27 +000081extern char **environ;
Denys Vlasenko418d66a2009-01-17 01:52:54 +000082extern int optind;
83extern char *optarg;
Denys Vlasenko96d5a762008-12-29 19:13:27 +000084
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000085
Roland McGrath41c48222008-07-18 00:25:10 +000086int debug = 0, followfork = 0;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +000087int dtime = 0, cflag = 0, xflag = 0, qflag = 0;
88static int iflag = 0, interactive = 0, pflag_seen = 0, rflag = 0, tflag = 0;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +000089/*
90 * daemonized_tracer supports -D option.
91 * With this option, strace forks twice.
92 * Unlike normal case, with -D *grandparent* process exec's,
93 * becoming a traced process. Child exits (this prevents traced process
94 * from having children it doesn't expect to have), and grandchild
95 * attaches to grandparent similarly to strace -p PID.
96 * This allows for more transparent interaction in cases
97 * when process and its parent are communicating via signals,
98 * wait() etc. Without -D, strace process gets lodged in between,
99 * disrupting parent<->child link.
100 */
101static bool daemonized_tracer = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000102
Denys Vlasenko7e0615f2009-01-28 19:00:54 +0000103static struct utsname utsname_buf;
104
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000105/* Sometimes we want to print only succeeding syscalls. */
106int not_failing_only = 0;
107
Dmitry V. Levina6809652008-11-10 17:14:58 +0000108static int exit_code = 0;
109static int strace_child = 0;
Denys Vlasenko96d5a762008-12-29 19:13:27 +0000110static int ptrace_stop_sig = SIGTRAP;
Denys Vlasenko8ed57272009-02-25 14:24:02 +0000111#if defined LINUX && (defined PTRACE_SETOPTIONS || defined PT_SETOPTIONS)
Denys Vlasenko96d5a762008-12-29 19:13:27 +0000112static bool ptrace_opts_set;
Denys Vlasenko8ed57272009-02-25 14:24:02 +0000113#endif
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +0000114static char *username = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000115uid_t run_uid;
116gid_t run_gid;
117
118int acolumn = DEFAULT_ACOLUMN;
119int max_strlen = DEFAULT_STRLEN;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +0000120static char *outfname = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000121FILE *outf;
Roland McGrathee9d4352002-12-18 04:16:10 +0000122struct tcb **tcbtab;
123unsigned int nprocs, tcbtabsize;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000124char *progname;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000125
Roland McGrath0a463882007-07-05 18:43:16 +0000126static int detach P((struct tcb *tcp, int sig));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000127static int trace P((void));
128static void cleanup P((void));
129static void interrupt P((int sig));
130static sigset_t empty_set, blocked_set;
131
132#ifdef HAVE_SIG_ATOMIC_T
133static volatile sig_atomic_t interrupted;
134#else /* !HAVE_SIG_ATOMIC_T */
135#ifdef __STDC__
136static volatile int interrupted;
137#else /* !__STDC__ */
138static int interrupted;
139#endif /* !__STDC__ */
140#endif /* !HAVE_SIG_ATOMIC_T */
141
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000142#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000143
144static struct tcb *pfd2tcb P((int pfd));
145static void reaper P((int sig));
146static void rebuild_pollv P((void));
Roland McGrathee9d4352002-12-18 04:16:10 +0000147static struct pollfd *pollv;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000148
149#ifndef HAVE_POLLABLE_PROCFS
150
151static void proc_poll_open P((void));
152static void proc_poller P((int pfd));
153
154struct proc_pollfd {
155 int fd;
156 int revents;
157 int pid;
158};
159
160static int poller_pid;
161static int proc_poll_pipe[2] = { -1, -1 };
162
163#endif /* !HAVE_POLLABLE_PROCFS */
164
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000165#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000166#define POLLWANT POLLWRNORM
167#else
168#define POLLWANT POLLPRI
169#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000170#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000171
172static void
173usage(ofp, exitval)
174FILE *ofp;
175int exitval;
176{
177 fprintf(ofp, "\
178usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000179 [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n\
180 [command [arg ...]]\n\
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000181 or: strace -c -D [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000182 [command [arg ...]]\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000183-c -- count time, calls, and errors for each syscall and report summary\n\
184-f -- follow forks, -ff -- with output into separate files\n\
185-F -- attempt to follow vforks, -h -- print help message\n\
186-i -- print instruction pointer at time of syscall\n\
187-q -- suppress messages about attaching, detaching, etc.\n\
188-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
189-T -- print time spent in each syscall, -V -- print version\n\
190-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
191-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
192-a column -- alignment COLUMN for printing syscall results (default %d)\n\
193-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
194 options: trace, abbrev, verbose, raw, signal, read, or write\n\
195-o file -- send trace output to FILE instead of stderr\n\
196-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
197-p pid -- trace process with process id PID, may be repeated\n\
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000198-D -- run tracer process as a detached grandchild, not as parent\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000199-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
200-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
201-u username -- run command as username handling setuid and/or setgid\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000202-E var=val -- put var=val in the environment for command\n\
203-E var -- remove var from the environment for command\n\
204" /* this is broken, so don't document it
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000205-z -- print only succeeding syscalls\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000206 */
207, DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000208 exit(exitval);
209}
210
211#ifdef SVR4
212#ifdef MIPS
213void
214foobar()
215{
216}
217#endif /* MIPS */
218#endif /* SVR4 */
219
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000220static int
221set_cloexec_flag(int fd)
222{
223 int flags, newflags;
224
225 if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
226 {
227 fprintf(stderr, "%s: fcntl F_GETFD: %s\n",
228 progname, strerror(errno));
229 return -1;
230 }
231
232 newflags = flags | FD_CLOEXEC;
233 if (flags == newflags)
234 return 0;
235
236 if (fcntl(fd, F_SETFD, newflags) < 0)
237 {
238 fprintf(stderr, "%s: fcntl F_SETFD: %s\n",
239 progname, strerror(errno));
240 return -1;
241 }
242
243 return 0;
244}
245
246/*
247 * When strace is setuid executable, we have to swap uids
248 * before and after filesystem and process management operations.
249 */
250static void
251swap_uid(void)
252{
253#ifndef SVR4
254 int euid = geteuid(), uid = getuid();
255
256 if (euid != uid && setreuid(euid, uid) < 0)
257 {
258 fprintf(stderr, "%s: setreuid: %s\n",
259 progname, strerror(errno));
260 exit(1);
261 }
262#endif
263}
264
Roland McGrath4bfa6262007-07-05 20:03:16 +0000265#if _LFS64_LARGEFILE
266# define fopen_for_output fopen64
267#else
268# define fopen_for_output fopen
269#endif
270
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000271static FILE *
272strace_fopen(const char *path, const char *mode)
273{
274 FILE *fp;
275
276 swap_uid();
Roland McGrath4bfa6262007-07-05 20:03:16 +0000277 if ((fp = fopen_for_output(path, mode)) == NULL)
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000278 fprintf(stderr, "%s: can't fopen '%s': %s\n",
279 progname, path, strerror(errno));
280 swap_uid();
281 if (fp && set_cloexec_flag(fileno(fp)) < 0)
282 {
283 fclose(fp);
284 fp = NULL;
285 }
286 return fp;
287}
288
289static int popen_pid = -1;
290
291#ifndef _PATH_BSHELL
292# define _PATH_BSHELL "/bin/sh"
293#endif
294
295/*
296 * We cannot use standard popen(3) here because we have to distinguish
297 * popen child process from other processes we trace, and standard popen(3)
298 * does not export its child's pid.
299 */
300static FILE *
301strace_popen(const char *command)
302{
303 int fds[2];
304
305 swap_uid();
306 if (pipe(fds) < 0)
307 {
308 fprintf(stderr, "%s: pipe: %s\n",
309 progname, strerror(errno));
310 swap_uid();
311 return NULL;
312 }
313
314 if (set_cloexec_flag(fds[1]) < 0)
315 {
316 close(fds[0]);
317 close(fds[1]);
318 swap_uid();
319 return NULL;
320 }
321
322 if ((popen_pid = fork()) == -1)
323 {
324 fprintf(stderr, "%s: fork: %s\n",
325 progname, strerror(errno));
326 close(fds[0]);
327 close(fds[1]);
328 swap_uid();
329 return NULL;
330 }
331
332 if (popen_pid)
333 {
334 /* parent */
335 close(fds[0]);
336 swap_uid();
337 return fdopen(fds[1], "w");
338 } else
339 {
340 /* child */
341 close(fds[1]);
342 if (fds[0] && (dup2(fds[0], 0) || close(fds[0])))
343 {
344 fprintf(stderr, "%s: dup2: %s\n",
345 progname, strerror(errno));
346 _exit(1);
347 }
348 execl(_PATH_BSHELL, "sh", "-c", command, NULL);
349 fprintf(stderr, "%s: execl: %s: %s\n",
350 progname, _PATH_BSHELL, strerror(errno));
351 _exit(1);
352 }
353}
354
355static int
356newoutf(struct tcb *tcp)
357{
358 if (outfname && followfork > 1) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000359 char name[520 + sizeof(int) * 3];
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000360 FILE *fp;
361
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000362 sprintf(name, "%.512s.%u", outfname, tcp->pid);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000363 if ((fp = strace_fopen(name, "w")) == NULL)
364 return -1;
365 tcp->outf = fp;
366 }
367 return 0;
368}
369
Roland McGrath02203312007-06-11 22:06:31 +0000370static void
371startup_attach(void)
372{
373 int tcbi;
374 struct tcb *tcp;
375
376 /*
377 * Block user interruptions as we would leave the traced
378 * process stopped (process state T) if we would terminate in
379 * between PTRACE_ATTACH and wait4 () on SIGSTOP.
380 * We rely on cleanup () from this point on.
381 */
382 if (interactive)
383 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
384
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000385 if (daemonized_tracer) {
386 pid_t pid = fork();
387 if (pid < 0) {
388 _exit(1);
389 }
390 if (pid) { /* parent */
391 /*
392 * Wait for child to attach to straced process
393 * (our parent). Child SIGKILLs us after it attached.
394 * Parent's wait() is unblocked by our death,
395 * it proceeds to exec the straced program.
396 */
397 pause();
398 _exit(0); /* paranoia */
399 }
400 }
401
Roland McGrath02203312007-06-11 22:06:31 +0000402 for (tcbi = 0; tcbi < tcbtabsize; tcbi++) {
403 tcp = tcbtab[tcbi];
404 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
405 continue;
406#ifdef LINUX
407 if (tcp->flags & TCB_CLONE_THREAD)
408 continue;
409#endif
410 /* Reinitialize the output since it may have changed. */
411 tcp->outf = outf;
412 if (newoutf(tcp) < 0)
413 exit(1);
414
415#ifdef USE_PROCFS
416 if (proc_open(tcp, 1) < 0) {
417 fprintf(stderr, "trouble opening proc file\n");
418 droptcb(tcp);
419 continue;
420 }
421#else /* !USE_PROCFS */
422# ifdef LINUX
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000423 if (followfork && !daemonized_tracer) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000424 char procdir[sizeof("/proc/%d/task") + sizeof(int) * 3];
Roland McGrath02203312007-06-11 22:06:31 +0000425 DIR *dir;
426
427 sprintf(procdir, "/proc/%d/task", tcp->pid);
428 dir = opendir(procdir);
429 if (dir != NULL) {
430 unsigned int ntid = 0, nerr = 0;
431 struct dirent *de;
432 int tid;
433 while ((de = readdir(dir)) != NULL) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000434 if (de->d_fileno == 0)
Roland McGrath02203312007-06-11 22:06:31 +0000435 continue;
436 tid = atoi(de->d_name);
437 if (tid <= 0)
438 continue;
439 ++ntid;
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000440 if (ptrace(PTRACE_ATTACH, tid, (char *) 1, 0) < 0)
Roland McGrath02203312007-06-11 22:06:31 +0000441 ++nerr;
442 else if (tid != tcbtab[tcbi]->pid) {
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000443 tcp = alloctcb(tid);
Denys Vlasenko84e20af2009-02-10 16:03:20 +0000444 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_CLONE_DETACHED;
Roland McGrath02203312007-06-11 22:06:31 +0000445 tcbtab[tcbi]->nchildren++;
446 tcbtab[tcbi]->nclone_threads++;
447 tcbtab[tcbi]->nclone_detached++;
448 tcp->parent = tcbtab[tcbi];
449 }
450 if (interactive) {
451 sigprocmask(SIG_SETMASK, &empty_set, NULL);
452 if (interrupted)
453 return;
454 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
455 }
456 }
457 closedir(dir);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000458 ntid -= nerr;
459 if (ntid == 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000460 perror("attach: ptrace(PTRACE_ATTACH, ...)");
461 droptcb(tcp);
462 continue;
463 }
464 if (!qflag) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000465 fprintf(stderr, ntid > 1
466? "Process %u attached with %u threads - interrupt to quit\n"
467: "Process %u attached - interrupt to quit\n",
468 tcbtab[tcbi]->pid, ntid);
Roland McGrath02203312007-06-11 22:06:31 +0000469 }
470 continue;
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000471 } /* if (opendir worked) */
472 } /* if (-f) */
Roland McGrath02203312007-06-11 22:06:31 +0000473# endif
474 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
475 perror("attach: ptrace(PTRACE_ATTACH, ...)");
476 droptcb(tcp);
477 continue;
478 }
479 /* INTERRUPTED is going to be checked at the top of TRACE. */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000480
481 if (daemonized_tracer) {
482 /*
483 * It is our grandparent we trace, not a -p PID.
484 * Don't want to just detach on exit, so...
485 */
486 tcp->flags &= ~TCB_ATTACHED;
487 /*
488 * Make parent go away.
489 * Also makes grandparent's wait() unblock.
490 */
491 kill(getppid(), SIGKILL);
492 }
493
Roland McGrath02203312007-06-11 22:06:31 +0000494#endif /* !USE_PROCFS */
495 if (!qflag)
496 fprintf(stderr,
497 "Process %u attached - interrupt to quit\n",
498 tcp->pid);
499 }
500
501 if (interactive)
502 sigprocmask(SIG_SETMASK, &empty_set, NULL);
503}
504
505static void
506startup_child (char **argv)
507{
508 struct stat statbuf;
509 const char *filename;
510 char pathname[MAXPATHLEN];
511 int pid = 0;
512 struct tcb *tcp;
513
514 filename = argv[0];
515 if (strchr(filename, '/')) {
516 if (strlen(filename) > sizeof pathname - 1) {
517 errno = ENAMETOOLONG;
518 perror("strace: exec");
519 exit(1);
520 }
521 strcpy(pathname, filename);
522 }
523#ifdef USE_DEBUGGING_EXEC
524 /*
525 * Debuggers customarily check the current directory
526 * first regardless of the path but doing that gives
527 * security geeks a panic attack.
528 */
529 else if (stat(filename, &statbuf) == 0)
530 strcpy(pathname, filename);
531#endif /* USE_DEBUGGING_EXEC */
532 else {
533 char *path;
534 int m, n, len;
535
536 for (path = getenv("PATH"); path && *path; path += m) {
537 if (strchr(path, ':')) {
538 n = strchr(path, ':') - path;
539 m = n + 1;
540 }
541 else
542 m = n = strlen(path);
543 if (n == 0) {
544 if (!getcwd(pathname, MAXPATHLEN))
545 continue;
546 len = strlen(pathname);
547 }
548 else if (n > sizeof pathname - 1)
549 continue;
550 else {
551 strncpy(pathname, path, n);
552 len = n;
553 }
554 if (len && pathname[len - 1] != '/')
555 pathname[len++] = '/';
556 strcpy(pathname + len, filename);
557 if (stat(pathname, &statbuf) == 0 &&
558 /* Accept only regular files
559 with some execute bits set.
560 XXX not perfect, might still fail */
561 S_ISREG(statbuf.st_mode) &&
562 (statbuf.st_mode & 0111))
563 break;
564 }
565 }
566 if (stat(pathname, &statbuf) < 0) {
567 fprintf(stderr, "%s: %s: command not found\n",
568 progname, filename);
569 exit(1);
570 }
Dmitry V. Levina6809652008-11-10 17:14:58 +0000571 strace_child = pid = fork();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000572 if (pid < 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000573 perror("strace: fork");
574 cleanup();
575 exit(1);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000576 }
577 if ((pid != 0 && daemonized_tracer) /* parent: to become a traced process */
578 || (pid == 0 && !daemonized_tracer) /* child: to become a traced process */
579 ) {
580 pid = getpid();
Roland McGrath02203312007-06-11 22:06:31 +0000581#ifdef USE_PROCFS
582 if (outf != stderr) close (fileno (outf));
583#ifdef MIPS
584 /* Kludge for SGI, see proc_open for details. */
585 sa.sa_handler = foobar;
586 sa.sa_flags = 0;
587 sigemptyset(&sa.sa_mask);
588 sigaction(SIGINT, &sa, NULL);
589#endif /* MIPS */
590#ifndef FREEBSD
591 pause();
592#else /* FREEBSD */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000593 kill(pid, SIGSTOP); /* stop HERE */
Roland McGrath02203312007-06-11 22:06:31 +0000594#endif /* FREEBSD */
595#else /* !USE_PROCFS */
596 if (outf!=stderr)
597 close(fileno (outf));
598
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000599 if (!daemonized_tracer) {
600 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
601 perror("strace: ptrace(PTRACE_TRACEME, ...)");
602 exit(1);
603 }
604 if (debug)
605 kill(pid, SIGSTOP);
Roland McGrath02203312007-06-11 22:06:31 +0000606 }
Roland McGrath02203312007-06-11 22:06:31 +0000607
608 if (username != NULL || geteuid() == 0) {
609 uid_t run_euid = run_uid;
610 gid_t run_egid = run_gid;
611
612 if (statbuf.st_mode & S_ISUID)
613 run_euid = statbuf.st_uid;
614 if (statbuf.st_mode & S_ISGID)
615 run_egid = statbuf.st_gid;
616
617 /*
618 * It is important to set groups before we
619 * lose privileges on setuid.
620 */
621 if (username != NULL) {
622 if (initgroups(username, run_gid) < 0) {
623 perror("initgroups");
624 exit(1);
625 }
626 if (setregid(run_gid, run_egid) < 0) {
627 perror("setregid");
628 exit(1);
629 }
630 if (setreuid(run_uid, run_euid) < 0) {
631 perror("setreuid");
632 exit(1);
633 }
634 }
635 }
636 else
637 setreuid(run_uid, run_uid);
638
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000639 if (!daemonized_tracer) {
640 /*
641 * Induce an immediate stop so that the parent
642 * will resume us with PTRACE_SYSCALL and display
643 * this execve call normally.
644 */
645 kill(getpid(), SIGSTOP);
646 } else {
647 struct sigaction sv_sigchld;
648 sigaction(SIGCHLD, NULL, &sv_sigchld);
649 /*
650 * Make sure it is not SIG_IGN, otherwise wait
651 * will not block.
652 */
653 signal(SIGCHLD, SIG_DFL);
654 /*
655 * Wait for grandchild to attach to us.
656 * It kills child after that, and wait() unblocks.
657 */
658 alarm(3);
659 wait(NULL);
660 alarm(0);
661 sigaction(SIGCHLD, &sv_sigchld, NULL);
662 }
Roland McGrath02203312007-06-11 22:06:31 +0000663#endif /* !USE_PROCFS */
664
665 execv(pathname, argv);
666 perror("strace: exec");
667 _exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000668 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000669
670 /* We are the tracer. */
671 tcp = alloctcb(daemonized_tracer ? getppid() : pid);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000672 if (daemonized_tracer) {
673 /* We want subsequent startup_attach() to attach to it. */
674 tcp->flags |= TCB_ATTACHED;
675 }
Roland McGrath02203312007-06-11 22:06:31 +0000676#ifdef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000677 if (proc_open(tcp, 0) < 0) {
678 fprintf(stderr, "trouble opening proc file\n");
679 cleanup();
680 exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000681 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000682#endif /* USE_PROCFS */
Roland McGrath02203312007-06-11 22:06:31 +0000683}
684
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000685int
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000686main(int argc, char *argv[])
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000687{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000688 struct tcb *tcp;
689 int c, pid = 0;
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000690 int optF = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000691 struct sigaction sa;
692
693 static char buf[BUFSIZ];
694
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000695 progname = argv[0] ? argv[0] : "strace";
696
Denys Vlasenko7e0615f2009-01-28 19:00:54 +0000697 uname(&utsname_buf);
698
Roland McGrathee9d4352002-12-18 04:16:10 +0000699 /* Allocate the initial tcbtab. */
700 tcbtabsize = argc; /* Surely enough for all -p args. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000701 if ((tcbtab = calloc(tcbtabsize, sizeof tcbtab[0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000702 fprintf(stderr, "%s: out of memory\n", progname);
703 exit(1);
704 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000705 if ((tcbtab[0] = calloc(tcbtabsize, sizeof tcbtab[0][0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000706 fprintf(stderr, "%s: out of memory\n", progname);
707 exit(1);
708 }
Roland McGrathee9d4352002-12-18 04:16:10 +0000709 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
710 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
711
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000712 outf = stderr;
713 interactive = 1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000714 set_sortby(DEFAULT_SORTBY);
715 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000716 qualify("trace=all");
717 qualify("abbrev=all");
718 qualify("verbose=all");
719 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000720 while ((c = getopt(argc, argv,
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000721 "+cdfFhiqrtTvVxz"
722#ifndef USE_PROCFS
723 "D"
724#endif
725 "a:e:o:O:p:s:S:u:E:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000726 switch (c) {
727 case 'c':
728 cflag++;
729 dtime++;
730 break;
731 case 'd':
732 debug++;
733 break;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000734#ifndef USE_PROCFS
735 /* Experimental, not documented in manpage yet. */
736 case 'D':
737 daemonized_tracer = 1;
738 break;
739#endif
Roland McGrath41c48222008-07-18 00:25:10 +0000740 case 'F':
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000741 optF = 1;
742 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000743 case 'f':
744 followfork++;
745 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000746 case 'h':
747 usage(stdout, 0);
748 break;
749 case 'i':
750 iflag++;
751 break;
752 case 'q':
753 qflag++;
754 break;
755 case 'r':
756 rflag++;
757 tflag++;
758 break;
759 case 't':
760 tflag++;
761 break;
762 case 'T':
763 dtime++;
764 break;
765 case 'x':
766 xflag++;
767 break;
768 case 'v':
769 qualify("abbrev=none");
770 break;
771 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +0000772 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000773 exit(0);
774 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000775 case 'z':
776 not_failing_only = 1;
777 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000778 case 'a':
779 acolumn = atoi(optarg);
780 break;
781 case 'e':
782 qualify(optarg);
783 break;
784 case 'o':
785 outfname = strdup(optarg);
786 break;
787 case 'O':
788 set_overhead(atoi(optarg));
789 break;
790 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +0000791 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000792 fprintf(stderr, "%s: Invalid process id: %s\n",
793 progname, optarg);
794 break;
795 }
796 if (pid == getpid()) {
Wichert Akkerman54a47671999-10-17 00:57:34 +0000797 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000798 break;
799 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000800 tcp = alloc_tcb(pid, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000801 tcp->flags |= TCB_ATTACHED;
802 pflag_seen++;
803 break;
804 case 's':
805 max_strlen = atoi(optarg);
Roland McGrathdccec722005-05-09 07:45:47 +0000806 if (max_strlen < 0) {
807 fprintf(stderr,
808 "%s: invalid -s argument: %s\n",
809 progname, optarg);
810 exit(1);
811 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000812 break;
813 case 'S':
814 set_sortby(optarg);
815 break;
816 case 'u':
817 username = strdup(optarg);
818 break;
Roland McGrathde6e5332003-01-24 04:31:23 +0000819 case 'E':
820 if (putenv(optarg) < 0) {
821 fprintf(stderr, "%s: out of memory\n",
822 progname);
823 exit(1);
824 }
825 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000826 default:
827 usage(stderr, 1);
828 break;
829 }
830 }
831
Roland McGrathd0c4c0c2006-04-25 07:39:40 +0000832 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +0000833 usage(stderr, 1);
834
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000835 if (!followfork)
836 followfork = optF;
837
Roland McGrathcb9def62006-04-25 07:48:03 +0000838 if (followfork > 1 && cflag) {
839 fprintf(stderr,
840 "%s: -c and -ff are mutually exclusive options\n",
841 progname);
842 exit(1);
843 }
844
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000845 /* See if they want to run as another user. */
846 if (username != NULL) {
847 struct passwd *pent;
848
849 if (getuid() != 0 || geteuid() != 0) {
850 fprintf(stderr,
851 "%s: you must be root to use the -u option\n",
852 progname);
853 exit(1);
854 }
855 if ((pent = getpwnam(username)) == NULL) {
856 fprintf(stderr, "%s: cannot find user `%s'\n",
Roland McGrath09553f82007-07-05 19:31:49 +0000857 progname, username);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000858 exit(1);
859 }
860 run_uid = pent->pw_uid;
861 run_gid = pent->pw_gid;
862 }
863 else {
864 run_uid = getuid();
865 run_gid = getgid();
866 }
867
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000868 /* Check if they want to redirect the output. */
869 if (outfname) {
Roland McGrath37b9a662003-11-07 02:26:54 +0000870 /* See if they want to pipe the output. */
871 if (outfname[0] == '|' || outfname[0] == '!') {
872 /*
873 * We can't do the <outfname>.PID funny business
874 * when using popen, so prohibit it.
875 */
876 if (followfork > 1) {
877 fprintf(stderr, "\
878%s: piping the output and -ff are mutually exclusive options\n",
879 progname);
880 exit(1);
881 }
882
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000883 if ((outf = strace_popen(outfname + 1)) == NULL)
Roland McGrath37b9a662003-11-07 02:26:54 +0000884 exit(1);
Roland McGrath37b9a662003-11-07 02:26:54 +0000885 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000886 else if (followfork <= 1 &&
887 (outf = strace_fopen(outfname, "w")) == NULL)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000888 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000889 }
890
Roland McGrath37b9a662003-11-07 02:26:54 +0000891 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000892 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +0000893 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000894 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000895 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +0000896 }
Roland McGrath54cc1c82007-11-03 23:34:11 +0000897 /* Valid states here:
898 optind < argc pflag_seen outfname interactive
899 1 0 0 1
900 0 1 0 1
901 1 0 1 0
902 0 1 1 1
903 */
904
905 /* STARTUP_CHILD must be called before the signal handlers get
906 installed below as they are inherited into the spawned process.
907 Also we do not need to be protected by them as during interruption
908 in the STARTUP_CHILD mode we kill the spawned process anyway. */
909 if (!pflag_seen)
910 startup_child(&argv[optind]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000911
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000912 sigemptyset(&empty_set);
913 sigemptyset(&blocked_set);
914 sa.sa_handler = SIG_IGN;
915 sigemptyset(&sa.sa_mask);
916 sa.sa_flags = 0;
917 sigaction(SIGTTOU, &sa, NULL);
918 sigaction(SIGTTIN, &sa, NULL);
919 if (interactive) {
920 sigaddset(&blocked_set, SIGHUP);
921 sigaddset(&blocked_set, SIGINT);
922 sigaddset(&blocked_set, SIGQUIT);
923 sigaddset(&blocked_set, SIGPIPE);
924 sigaddset(&blocked_set, SIGTERM);
925 sa.sa_handler = interrupt;
926#ifdef SUNOS4
927 /* POSIX signals on sunos4.1 are a little broken. */
928 sa.sa_flags = SA_INTERRUPT;
929#endif /* SUNOS4 */
930 }
931 sigaction(SIGHUP, &sa, NULL);
932 sigaction(SIGINT, &sa, NULL);
933 sigaction(SIGQUIT, &sa, NULL);
934 sigaction(SIGPIPE, &sa, NULL);
935 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000936#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000937 sa.sa_handler = reaper;
938 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000939#else
940 /* Make sure SIGCHLD has the default action so that waitpid
941 definitely works without losing track of children. The user
942 should not have given us a bogus state to inherit, but he might
943 have. Arguably we should detect SIG_IGN here and pass it on
944 to children, but probably noone really needs that. */
945 sa.sa_handler = SIG_DFL;
946 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000947#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000948
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000949 if (pflag_seen || daemonized_tracer)
Roland McGrath02203312007-06-11 22:06:31 +0000950 startup_attach();
Roland McGrath02203312007-06-11 22:06:31 +0000951
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000952 if (trace() < 0)
953 exit(1);
954 cleanup();
Dmitry V. Levina6809652008-11-10 17:14:58 +0000955 fflush(NULL);
956 if (exit_code > 0xff) {
957 /* Child was killed by a signal, mimic that. */
958 exit_code &= 0xff;
959 signal(exit_code, SIG_DFL);
960 raise(exit_code);
961 /* Paranoia - what if this signal is not fatal?
962 Exit with 128 + signo then. */
963 exit_code += 128;
964 }
965 exit(exit_code);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000966}
967
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000968void
969expand_tcbtab(void)
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000970{
971 /* Allocate some more TCBs and expand the table.
972 We don't want to relocate the TCBs because our
973 callers have pointers and it would be a pain.
974 So tcbtab is a table of pointers. Since we never
975 free the TCBs, we allocate a single chunk of many. */
976 struct tcb **newtab = (struct tcb **)
977 realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
978 struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
979 sizeof *newtcbs);
980 int i;
981 if (newtab == NULL || newtcbs == NULL) {
Dmitry V. Levin76860f62006-10-11 22:55:25 +0000982 fprintf(stderr, "%s: expand_tcbtab: out of memory\n",
983 progname);
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000984 cleanup();
985 exit(1);
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000986 }
987 for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
988 newtab[i] = &newtcbs[i - tcbtabsize];
989 tcbtabsize *= 2;
990 tcbtab = newtab;
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000991}
992
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000993struct tcb *
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000994alloc_tcb(int pid, int command_options_parsed)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000995{
996 int i;
997 struct tcb *tcp;
998
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000999 if (nprocs == tcbtabsize)
1000 expand_tcbtab();
1001
Roland McGrathee9d4352002-12-18 04:16:10 +00001002 for (i = 0; i < tcbtabsize; i++) {
1003 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001004 if ((tcp->flags & TCB_INUSE) == 0) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00001005 memset(tcp, 0, sizeof(*tcp));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001006 tcp->pid = pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001007 tcp->flags = TCB_INUSE | TCB_STARTUP;
1008 tcp->outf = outf; /* Initialise to current out file */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001009 tcp->pfd = -1;
1010 nprocs++;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001011 if (command_options_parsed)
1012 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001013 return tcp;
1014 }
1015 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001016 fprintf(stderr, "%s: bug in alloc_tcb\n", progname);
1017 cleanup();
1018 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001019}
1020
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001021#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001022int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001023proc_open(struct tcb *tcp, int attaching)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001024{
1025 char proc[32];
1026 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001027#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +00001028 int i;
1029 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001030 sigset_t signals;
1031 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001032#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001033#ifndef HAVE_POLLABLE_PROCFS
1034 static int last_pfd;
1035#endif
1036
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001037#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001038 /* Open the process pseudo-files in /proc. */
1039 sprintf(proc, "/proc/%d/ctl", tcp->pid);
1040 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001041 perror("strace: open(\"/proc/...\", ...)");
1042 return -1;
1043 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001044 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001045 return -1;
1046 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001047 sprintf(proc, "/proc/%d/status", tcp->pid);
1048 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
1049 perror("strace: open(\"/proc/...\", ...)");
1050 return -1;
1051 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001052 if (set_cloexec_flag(tcp->pfd_stat) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001053 return -1;
1054 }
1055 sprintf(proc, "/proc/%d/as", tcp->pid);
1056 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
1057 perror("strace: open(\"/proc/...\", ...)");
1058 return -1;
1059 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001060 if (set_cloexec_flag(tcp->pfd_as) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001061 return -1;
1062 }
1063#else
1064 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001065#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001066 sprintf(proc, "/proc/%d", tcp->pid);
1067 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001068#else /* FREEBSD */
1069 sprintf(proc, "/proc/%d/mem", tcp->pid);
1070 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
1071#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001072 perror("strace: open(\"/proc/...\", ...)");
1073 return -1;
1074 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001075 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001076 return -1;
1077 }
1078#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001079#ifdef FREEBSD
1080 sprintf(proc, "/proc/%d/regs", tcp->pid);
1081 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
1082 perror("strace: open(\"/proc/.../regs\", ...)");
1083 return -1;
1084 }
1085 if (cflag) {
1086 sprintf(proc, "/proc/%d/status", tcp->pid);
1087 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
1088 perror("strace: open(\"/proc/.../status\", ...)");
1089 return -1;
1090 }
1091 } else
1092 tcp->pfd_status = -1;
1093#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001094 rebuild_pollv();
1095 if (!attaching) {
1096 /*
1097 * Wait for the child to pause. Because of a race
1098 * condition we have to poll for the event.
1099 */
1100 for (;;) {
1101 if (IOCTL_STATUS (tcp) < 0) {
1102 perror("strace: PIOCSTATUS");
1103 return -1;
1104 }
1105 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001106 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001107 }
1108 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001109#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001110 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001111 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001112 perror("strace: PIOCSTOP");
1113 return -1;
1114 }
Roland McGrath553a6092002-12-16 20:40:39 +00001115#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001116#ifdef PIOCSET
1117 /* Set Run-on-Last-Close. */
1118 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001119 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001120 perror("PIOCSET PR_RLC");
1121 return -1;
1122 }
1123 /* Set or Reset Inherit-on-Fork. */
1124 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001125 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001126 perror("PIOC{SET,RESET} PR_FORK");
1127 return -1;
1128 }
1129#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +00001130#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001131 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
1132 perror("PIOCSRLC");
1133 return -1;
1134 }
1135 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
1136 perror("PIOC{S,R}FORK");
1137 return -1;
1138 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001139#else /* FREEBSD */
1140 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
1141 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
1142 perror("PIOCGFL");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001143 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001144 }
1145 arg &= ~PF_LINGER;
1146 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001147 perror("PIOCSFL");
1148 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001149 }
1150#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001151#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001152#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +00001153 /* Enable all syscall entries we care about. */
1154 premptyset(&syscalls);
1155 for (i = 1; i < MAX_QUALS; ++i) {
1156 if (i > (sizeof syscalls) * CHAR_BIT) break;
1157 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
1158 }
1159 praddset (&syscalls, SYS_execve);
1160 if (followfork) {
1161 praddset (&syscalls, SYS_fork);
1162#ifdef SYS_forkall
1163 praddset (&syscalls, SYS_forkall);
1164#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001165#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +00001166 praddset (&syscalls, SYS_fork1);
1167#endif
1168#ifdef SYS_rfork1
1169 praddset (&syscalls, SYS_rfork1);
1170#endif
1171#ifdef SYS_rforkall
1172 praddset (&syscalls, SYS_rforkall);
1173#endif
1174 }
1175 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001176 perror("PIOCSENTRY");
1177 return -1;
1178 }
John Hughes19e49982001-10-19 08:59:12 +00001179 /* Enable the syscall exits. */
1180 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001181 perror("PIOSEXIT");
1182 return -1;
1183 }
John Hughes19e49982001-10-19 08:59:12 +00001184 /* Enable signals we care about. */
1185 premptyset(&signals);
1186 for (i = 1; i < MAX_QUALS; ++i) {
1187 if (i > (sizeof signals) * CHAR_BIT) break;
1188 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
1189 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001190 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001191 perror("PIOCSTRACE");
1192 return -1;
1193 }
John Hughes19e49982001-10-19 08:59:12 +00001194 /* Enable faults we care about */
1195 premptyset(&faults);
1196 for (i = 1; i < MAX_QUALS; ++i) {
1197 if (i > (sizeof faults) * CHAR_BIT) break;
1198 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
1199 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001200 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001201 perror("PIOCSFAULT");
1202 return -1;
1203 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001204#else /* FREEBSD */
1205 /* set events flags. */
1206 arg = S_SIG | S_SCE | S_SCX ;
1207 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
1208 perror("PIOCBIS");
1209 return -1;
1210 }
1211#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001212 if (!attaching) {
1213#ifdef MIPS
1214 /*
1215 * The SGI PRSABORT doesn't work for pause() so
1216 * we send it a caught signal to wake it up.
1217 */
1218 kill(tcp->pid, SIGINT);
1219#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +00001220#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001221 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001222 arg = PRSABORT;
1223 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001224 perror("PIOCRUN");
1225 return -1;
1226 }
Roland McGrath553a6092002-12-16 20:40:39 +00001227#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001228#endif /* !MIPS*/
1229#ifdef FREEBSD
1230 /* wake up the child if it received the SIGSTOP */
1231 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001232#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001233 for (;;) {
1234 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001235 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001236 perror("PIOCWSTOP");
1237 return -1;
1238 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001239 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001240 tcp->flags &= ~TCB_INSYSCALL;
1241 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001242 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001243 break;
1244 }
1245 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001246#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001247 arg = 0;
1248 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001249#else /* FREEBSD */
1250 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001251#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001252 perror("PIOCRUN");
1253 return -1;
1254 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001255#ifdef FREEBSD
1256 /* handle the case where we "opened" the child before
1257 it did the kill -STOP */
1258 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1259 tcp->status.PR_WHAT == SIGSTOP)
1260 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001261#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001262 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001263#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001264 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001265#else /* FREEBSD */
1266 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001267 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001268 /* We are attaching to an already running process.
1269 * Try to figure out the state of the process in syscalls,
1270 * to handle the first event well.
1271 * This is done by having a look at the "wchan" property of the
1272 * process, which tells where it is stopped (if it is). */
1273 FILE * status;
1274 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001275
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001276 sprintf(proc, "/proc/%d/status", tcp->pid);
1277 status = fopen(proc, "r");
1278 if (status &&
1279 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1280 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1281 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1282 strcmp(wchan, "stopevent")) {
1283 /* The process is asleep in the middle of a syscall.
1284 Fake the syscall entry event */
1285 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1286 tcp->status.PR_WHY = PR_SYSENTRY;
1287 trace_syscall(tcp);
1288 }
1289 if (status)
1290 fclose(status);
1291 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001292 }
1293#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001294#ifndef HAVE_POLLABLE_PROCFS
1295 if (proc_poll_pipe[0] != -1)
1296 proc_poller(tcp->pfd);
1297 else if (nprocs > 1) {
1298 proc_poll_open();
1299 proc_poller(last_pfd);
1300 proc_poller(tcp->pfd);
1301 }
1302 last_pfd = tcp->pfd;
1303#endif /* !HAVE_POLLABLE_PROCFS */
1304 return 0;
1305}
1306
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001307#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001308
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001309struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001310pid2tcb(pid)
1311int pid;
1312{
1313 int i;
1314 struct tcb *tcp;
1315
Roland McGrathee9d4352002-12-18 04:16:10 +00001316 for (i = 0; i < tcbtabsize; i++) {
1317 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001318 if (pid && tcp->pid != pid)
1319 continue;
1320 if (tcp->flags & TCB_INUSE)
1321 return tcp;
1322 }
1323 return NULL;
1324}
1325
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001326#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001327
1328static struct tcb *
1329pfd2tcb(pfd)
1330int pfd;
1331{
1332 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001333
Roland McGrathca16be82003-01-10 19:55:28 +00001334 for (i = 0; i < tcbtabsize; i++) {
1335 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001336 if (tcp->pfd != pfd)
1337 continue;
1338 if (tcp->flags & TCB_INUSE)
1339 return tcp;
1340 }
1341 return NULL;
1342}
1343
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001344#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001345
1346void
1347droptcb(tcp)
1348struct tcb *tcp;
1349{
1350 if (tcp->pid == 0)
1351 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001352#ifdef TCB_CLONE_THREAD
1353 if (tcp->nclone_threads > 0) {
1354 /* There are other threads left in this process, but this
1355 is the one whose PID represents the whole process.
1356 We need to keep this record around as a zombie until
1357 all the threads die. */
1358 tcp->flags |= TCB_EXITING;
1359 return;
1360 }
1361#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001362 nprocs--;
1363 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001364
Roland McGrathe29341c2003-01-10 20:14:20 +00001365 if (tcp->parent != NULL) {
1366 tcp->parent->nchildren--;
1367#ifdef TCB_CLONE_THREAD
1368 if (tcp->flags & TCB_CLONE_DETACHED)
1369 tcp->parent->nclone_detached--;
1370 if (tcp->flags & TCB_CLONE_THREAD)
1371 tcp->parent->nclone_threads--;
1372#endif
Roland McGrath09623452003-05-23 02:27:13 +00001373#ifdef TCB_CLONE_DETACHED
1374 if (!(tcp->flags & TCB_CLONE_DETACHED))
1375#endif
1376 tcp->parent->nzombies++;
Roland McGrath276ceb32007-11-13 08:12:12 +00001377#ifdef LINUX
1378 /* Update `tcp->parent->parent->nchildren' and the other fields
1379 like NCLONE_DETACHED, only for zombie group leader that has
1380 already reported and been short-circuited at the top of this
1381 function. The same condition as at the top of DETACH. */
1382 if ((tcp->flags & TCB_CLONE_THREAD) &&
1383 tcp->parent->nclone_threads == 0 &&
1384 (tcp->parent->flags & TCB_EXITING))
1385 droptcb(tcp->parent);
1386#endif
Roland McGrathe29341c2003-01-10 20:14:20 +00001387 tcp->parent = NULL;
1388 }
1389
1390 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001391 if (tcp->pfd != -1) {
1392 close(tcp->pfd);
1393 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001394#ifdef FREEBSD
1395 if (tcp->pfd_reg != -1) {
1396 close(tcp->pfd_reg);
1397 tcp->pfd_reg = -1;
1398 }
1399 if (tcp->pfd_status != -1) {
1400 close(tcp->pfd_status);
1401 tcp->pfd_status = -1;
1402 }
Roland McGrath553a6092002-12-16 20:40:39 +00001403#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001404#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001405 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001406#endif
1407 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001408
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001409 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001410 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001411
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001412 tcp->outf = 0;
1413}
1414
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001415#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001416
1417static int
1418resume(tcp)
1419struct tcb *tcp;
1420{
1421 if (tcp == NULL)
1422 return -1;
1423
1424 if (!(tcp->flags & TCB_SUSPENDED)) {
1425 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1426 return -1;
1427 }
1428 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001429#ifdef TCB_CLONE_THREAD
1430 if (tcp->flags & TCB_CLONE_THREAD)
1431 tcp->parent->nclone_waiting--;
1432#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001433
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001434 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001435 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001436
1437 if (!qflag)
1438 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1439 return 0;
1440}
1441
Roland McGrath1bfd3102007-08-03 10:02:00 +00001442static int
1443resume_from_tcp (struct tcb *tcp)
1444{
1445 int error = 0;
1446 int resumed = 0;
1447
1448 /* XXX This won't always be quite right (but it never was).
1449 A waiter with argument 0 or < -1 is waiting for any pid in
1450 a particular pgrp, which this child might or might not be
1451 in. The waiter will only wake up if it's argument is -1
1452 or if it's waiting for tcp->pid's pgrp. It makes a
1453 difference to wake up a waiter when there might be more
1454 traced children, because it could get a false ECHILD
1455 error. OTOH, if this was the last child in the pgrp, then
1456 it ought to wake up and get ECHILD. We would have to
1457 search the system for all pid's in the pgrp to be sure.
1458
1459 && (t->waitpid == -1 ||
1460 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1461 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1462 */
1463
1464 if (tcp->parent &&
1465 (tcp->parent->flags & TCB_SUSPENDED) &&
1466 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001467 error = resume(tcp->parent);
Roland McGrath1bfd3102007-08-03 10:02:00 +00001468 ++resumed;
1469 }
1470#ifdef TCB_CLONE_THREAD
1471 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1472 /* Some other threads of our parent are waiting too. */
1473 unsigned int i;
1474
1475 /* Resume all the threads that were waiting for this PID. */
1476 for (i = 0; i < tcbtabsize; i++) {
1477 struct tcb *t = tcbtab[i];
1478 if (t->parent == tcp->parent && t != tcp
1479 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1480 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1481 && t->waitpid == tcp->pid) {
1482 error |= resume (t);
1483 ++resumed;
1484 }
1485 }
1486 if (resumed == 0)
1487 /* Noone was waiting for this PID in particular,
1488 so now we might need to resume some wildcarders. */
1489 for (i = 0; i < tcbtabsize; i++) {
1490 struct tcb *t = tcbtab[i];
1491 if (t->parent == tcp->parent && t != tcp
1492 && ((t->flags
1493 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1494 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1495 && t->waitpid <= 0
1496 ) {
1497 error |= resume (t);
1498 break;
1499 }
1500 }
1501 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001502#endif
Roland McGrath1bfd3102007-08-03 10:02:00 +00001503
1504 return error;
1505}
Roland McGrath1bfd3102007-08-03 10:02:00 +00001506
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001507#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001508
Roland McGrath0a463882007-07-05 18:43:16 +00001509/* detach traced process; continue with sig
1510 Never call DETACH twice on the same process as both unattached and
1511 attached-unstopped processes give the same ESRCH. For unattached process we
1512 would SIGSTOP it and wait for its SIGSTOP notification forever. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001513
1514static int
1515detach(tcp, sig)
1516struct tcb *tcp;
1517int sig;
1518{
1519 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001520#ifdef LINUX
Roland McGrath1bfd3102007-08-03 10:02:00 +00001521 int status, catch_sigstop;
Roland McGratha08a97e2005-08-03 11:23:46 +00001522 struct tcb *zombie = NULL;
1523
1524 /* If the group leader is lingering only because of this other
1525 thread now dying, then detach the leader as well. */
1526 if ((tcp->flags & TCB_CLONE_THREAD) &&
1527 tcp->parent->nclone_threads == 1 &&
1528 (tcp->parent->flags & TCB_EXITING))
1529 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001530#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001531
1532 if (tcp->flags & TCB_BPTSET)
1533 sig = SIGKILL;
1534
1535#ifdef LINUX
1536 /*
1537 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001538 * before detaching. Arghh. We go through hoops
1539 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001540 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001541#if defined(SPARC)
1542#undef PTRACE_DETACH
1543#define PTRACE_DETACH PTRACE_SUNDETACH
1544#endif
Roland McGrath02203312007-06-11 22:06:31 +00001545 /*
1546 * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
1547 * expected SIGSTOP. We must catch exactly one as otherwise the
1548 * detached process would be left stopped (process state T).
1549 */
1550 catch_sigstop = (tcp->flags & TCB_STARTUP);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001551 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1552 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001553 }
1554 else if (errno != ESRCH) {
1555 /* Shouldn't happen. */
1556 perror("detach: ptrace(PTRACE_DETACH, ...)");
1557 }
Roland McGrath134813a2007-06-02 00:07:33 +00001558 else if (my_tgkill((tcp->flags & TCB_CLONE_THREAD ? tcp->parent->pid
1559 : tcp->pid),
1560 tcp->pid, 0) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001561 if (errno != ESRCH)
1562 perror("detach: checking sanity");
1563 }
Roland McGrath02203312007-06-11 22:06:31 +00001564 else if (!catch_sigstop && my_tgkill((tcp->flags & TCB_CLONE_THREAD
1565 ? tcp->parent->pid : tcp->pid),
1566 tcp->pid, SIGSTOP) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001567 if (errno != ESRCH)
1568 perror("detach: stopping child");
1569 }
Roland McGrath02203312007-06-11 22:06:31 +00001570 else
1571 catch_sigstop = 1;
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001572 if (catch_sigstop) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001573 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001574#ifdef __WALL
1575 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1576 if (errno == ECHILD) /* Already gone. */
1577 break;
1578 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001579 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001580 break;
1581 }
1582#endif /* __WALL */
1583 /* No __WALL here. */
1584 if (waitpid(tcp->pid, &status, 0) < 0) {
1585 if (errno != ECHILD) {
1586 perror("detach: waiting");
1587 break;
1588 }
1589#ifdef __WCLONE
1590 /* If no processes, try clones. */
1591 if (wait4(tcp->pid, &status, __WCLONE,
1592 NULL) < 0) {
1593 if (errno != ECHILD)
1594 perror("detach: waiting");
1595 break;
1596 }
1597#endif /* __WCLONE */
1598 }
1599#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001600 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001601#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001602 if (!WIFSTOPPED(status)) {
1603 /* Au revoir, mon ami. */
1604 break;
1605 }
1606 if (WSTOPSIG(status) == SIGSTOP) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001607 ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001608 break;
1609 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001610 error = ptrace_restart(PTRACE_CONT, tcp,
Denys Vlasenko96d5a762008-12-29 19:13:27 +00001611 WSTOPSIG(status) == ptrace_stop_sig ? 0
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001612 : WSTOPSIG(status));
1613 if (error < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001614 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001615 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001616 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001617#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001618
1619#if defined(SUNOS4)
1620 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1621 if (sig && kill(tcp->pid, sig) < 0)
1622 perror("detach: kill");
1623 sig = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001624 error = ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001625#endif /* SUNOS4 */
1626
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001627#ifndef USE_PROCFS
Roland McGrath1bfd3102007-08-03 10:02:00 +00001628 error |= resume_from_tcp (tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001629#endif
1630
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001631 if (!qflag)
1632 fprintf(stderr, "Process %u detached\n", tcp->pid);
1633
1634 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001635
1636#ifdef LINUX
Roland McGrath0a463882007-07-05 18:43:16 +00001637 if (zombie != NULL) {
1638 /* TCP no longer exists therefore you must not detach () it. */
1639 droptcb(zombie);
1640 }
Roland McGratha08a97e2005-08-03 11:23:46 +00001641#endif
1642
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001643 return error;
1644}
1645
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001646#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001647
1648static void
1649reaper(sig)
1650int sig;
1651{
1652 int pid;
1653 int status;
1654
1655 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1656#if 0
1657 struct tcb *tcp;
1658
1659 tcp = pid2tcb(pid);
1660 if (tcp)
1661 droptcb(tcp);
1662#endif
1663 }
1664}
1665
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001666#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001667
1668static void
1669cleanup()
1670{
1671 int i;
1672 struct tcb *tcp;
1673
Roland McGrathee9d4352002-12-18 04:16:10 +00001674 for (i = 0; i < tcbtabsize; i++) {
1675 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001676 if (!(tcp->flags & TCB_INUSE))
1677 continue;
1678 if (debug)
1679 fprintf(stderr,
1680 "cleanup: looking at pid %u\n", tcp->pid);
1681 if (tcp_last &&
1682 (!outfname || followfork < 2 || tcp_last == tcp)) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001683 tprintf(" <unfinished ...>");
1684 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001685 }
1686 if (tcp->flags & TCB_ATTACHED)
1687 detach(tcp, 0);
1688 else {
1689 kill(tcp->pid, SIGCONT);
1690 kill(tcp->pid, SIGTERM);
1691 }
1692 }
1693 if (cflag)
1694 call_summary(outf);
1695}
1696
1697static void
1698interrupt(sig)
1699int sig;
1700{
1701 interrupted = 1;
1702}
1703
1704#ifndef HAVE_STRERROR
1705
Roland McGrath6d2b3492002-12-30 00:51:30 +00001706#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001707extern int sys_nerr;
1708extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001709#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001710
1711const char *
1712strerror(errno)
1713int errno;
1714{
1715 static char buf[64];
1716
1717 if (errno < 1 || errno >= sys_nerr) {
1718 sprintf(buf, "Unknown error %d", errno);
1719 return buf;
1720 }
1721 return sys_errlist[errno];
1722}
1723
1724#endif /* HAVE_STERRROR */
1725
1726#ifndef HAVE_STRSIGNAL
1727
Roland McGrath8f474e02003-01-14 07:53:33 +00001728#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001729extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001730#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001731#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1732extern char *_sys_siglist[];
1733#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001734
1735const char *
1736strsignal(sig)
1737int sig;
1738{
1739 static char buf[64];
1740
1741 if (sig < 1 || sig >= NSIG) {
1742 sprintf(buf, "Unknown signal %d", sig);
1743 return buf;
1744 }
1745#ifdef HAVE__SYS_SIGLIST
1746 return _sys_siglist[sig];
1747#else
1748 return sys_siglist[sig];
1749#endif
1750}
1751
1752#endif /* HAVE_STRSIGNAL */
1753
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001754#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001755
1756static void
1757rebuild_pollv()
1758{
1759 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001760
Roland McGrathee9d4352002-12-18 04:16:10 +00001761 if (pollv != NULL)
1762 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001763 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001764 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001765 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00001766 exit(1);
1767 }
1768
Roland McGrathca16be82003-01-10 19:55:28 +00001769 for (i = j = 0; i < tcbtabsize; i++) {
1770 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001771 if (!(tcp->flags & TCB_INUSE))
1772 continue;
1773 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001774 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001775 j++;
1776 }
1777 if (j != nprocs) {
1778 fprintf(stderr, "strace: proc miscount\n");
1779 exit(1);
1780 }
1781}
1782
1783#ifndef HAVE_POLLABLE_PROCFS
1784
1785static void
1786proc_poll_open()
1787{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001788 int i;
1789
1790 if (pipe(proc_poll_pipe) < 0) {
1791 perror("pipe");
1792 exit(1);
1793 }
1794 for (i = 0; i < 2; i++) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001795 if (set_cloexec_flag(proc_poll_pipe[i]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001796 exit(1);
1797 }
1798 }
1799}
1800
1801static int
1802proc_poll(pollv, nfds, timeout)
1803struct pollfd *pollv;
1804int nfds;
1805int timeout;
1806{
1807 int i;
1808 int n;
1809 struct proc_pollfd pollinfo;
1810
1811 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1812 return n;
1813 if (n != sizeof(struct proc_pollfd)) {
1814 fprintf(stderr, "panic: short read: %d\n", n);
1815 exit(1);
1816 }
1817 for (i = 0; i < nprocs; i++) {
1818 if (pollv[i].fd == pollinfo.fd)
1819 pollv[i].revents = pollinfo.revents;
1820 else
1821 pollv[i].revents = 0;
1822 }
1823 poller_pid = pollinfo.pid;
1824 return 1;
1825}
1826
1827static void
1828wakeup_handler(sig)
1829int sig;
1830{
1831}
1832
1833static void
1834proc_poller(pfd)
1835int pfd;
1836{
1837 struct proc_pollfd pollinfo;
1838 struct sigaction sa;
1839 sigset_t blocked_set, empty_set;
1840 int i;
1841 int n;
1842 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001843#ifdef FREEBSD
1844 struct procfs_status pfs;
1845#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001846
1847 switch (fork()) {
1848 case -1:
1849 perror("fork");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001850 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001851 case 0:
1852 break;
1853 default:
1854 return;
1855 }
1856
1857 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1858 sa.sa_flags = 0;
1859 sigemptyset(&sa.sa_mask);
1860 sigaction(SIGHUP, &sa, NULL);
1861 sigaction(SIGINT, &sa, NULL);
1862 sigaction(SIGQUIT, &sa, NULL);
1863 sigaction(SIGPIPE, &sa, NULL);
1864 sigaction(SIGTERM, &sa, NULL);
1865 sa.sa_handler = wakeup_handler;
1866 sigaction(SIGUSR1, &sa, NULL);
1867 sigemptyset(&blocked_set);
1868 sigaddset(&blocked_set, SIGUSR1);
1869 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1870 sigemptyset(&empty_set);
1871
1872 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1873 perror("getrlimit(RLIMIT_NOFILE, ...)");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001874 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001875 }
1876 n = rl.rlim_cur;
1877 for (i = 0; i < n; i++) {
1878 if (i != pfd && i != proc_poll_pipe[1])
1879 close(i);
1880 }
1881
1882 pollinfo.fd = pfd;
1883 pollinfo.pid = getpid();
1884 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001885#ifndef FREEBSD
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001886 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1887#else
1888 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1889#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001890 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001891 switch (errno) {
1892 case EINTR:
1893 continue;
1894 case EBADF:
1895 pollinfo.revents = POLLERR;
1896 break;
1897 case ENOENT:
1898 pollinfo.revents = POLLHUP;
1899 break;
1900 default:
1901 perror("proc_poller: PIOCWSTOP");
1902 }
1903 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1904 _exit(0);
1905 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001906 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001907 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1908 sigsuspend(&empty_set);
1909 }
1910}
1911
1912#endif /* !HAVE_POLLABLE_PROCFS */
1913
1914static int
1915choose_pfd()
1916{
1917 int i, j;
1918 struct tcb *tcp;
1919
1920 static int last;
1921
1922 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001923 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001924 /*
1925 * The previous process is ready to run again. We'll
1926 * let it do so if it is currently in a syscall. This
1927 * heuristic improves the readability of the trace.
1928 */
1929 tcp = pfd2tcb(pollv[last].fd);
1930 if (tcp && (tcp->flags & TCB_INSYSCALL))
1931 return pollv[last].fd;
1932 }
1933
1934 for (i = 0; i < nprocs; i++) {
1935 /* Let competing children run round robin. */
1936 j = (i + last + 1) % nprocs;
1937 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1938 tcp = pfd2tcb(pollv[j].fd);
1939 if (!tcp) {
1940 fprintf(stderr, "strace: lost proc\n");
1941 exit(1);
1942 }
1943 droptcb(tcp);
1944 return -1;
1945 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001946 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001947 last = j;
1948 return pollv[j].fd;
1949 }
1950 }
1951 fprintf(stderr, "strace: nothing ready\n");
1952 exit(1);
1953}
1954
1955static int
1956trace()
1957{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001958#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001959 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001960#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001961 struct tcb *tcp;
1962 int pfd;
1963 int what;
1964 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001965 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001966
1967 for (;;) {
1968 if (interactive)
1969 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1970
1971 if (nprocs == 0)
1972 break;
1973
1974 switch (nprocs) {
1975 case 1:
1976#ifndef HAVE_POLLABLE_PROCFS
1977 if (proc_poll_pipe[0] == -1) {
1978#endif
1979 tcp = pid2tcb(0);
1980 if (!tcp)
1981 continue;
1982 pfd = tcp->pfd;
1983 if (pfd == -1)
1984 continue;
1985 break;
1986#ifndef HAVE_POLLABLE_PROCFS
1987 }
1988 /* fall through ... */
1989#endif /* !HAVE_POLLABLE_PROCFS */
1990 default:
1991#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001992#ifdef POLL_HACK
1993 /* On some systems (e.g. UnixWare) we get too much ugly
1994 "unfinished..." stuff when multiple proceses are in
1995 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001996
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001997 if (in_syscall) {
1998 struct pollfd pv;
1999 tcp = in_syscall;
2000 in_syscall = NULL;
2001 pv.fd = tcp->pfd;
2002 pv.events = POLLWANT;
2003 if ((what = poll (&pv, 1, 1)) < 0) {
2004 if (interrupted)
2005 return 0;
2006 continue;
2007 }
2008 else if (what == 1 && pv.revents & POLLWANT) {
2009 goto FOUND;
2010 }
2011 }
2012#endif
2013
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002014 if (poll(pollv, nprocs, INFTIM) < 0) {
2015 if (interrupted)
2016 return 0;
2017 continue;
2018 }
2019#else /* !HAVE_POLLABLE_PROCFS */
2020 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
2021 if (interrupted)
2022 return 0;
2023 continue;
2024 }
2025#endif /* !HAVE_POLLABLE_PROCFS */
2026 pfd = choose_pfd();
2027 if (pfd == -1)
2028 continue;
2029 break;
2030 }
2031
2032 /* Look up `pfd' in our table. */
2033 if ((tcp = pfd2tcb(pfd)) == NULL) {
2034 fprintf(stderr, "unknown pfd: %u\n", pfd);
2035 exit(1);
2036 }
John Hughesb6643082002-05-23 11:02:22 +00002037#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002038 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00002039#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002040 /* Get the status of the process. */
2041 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002042#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002043 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002044#else /* FREEBSD */
2045 /* Thanks to some scheduling mystery, the first poller
2046 sometimes waits for the already processed end of fork
2047 event. Doing a non blocking poll here solves the problem. */
2048 if (proc_poll_pipe[0] != -1)
2049 ioctl_result = IOCTL_STATUS (tcp);
2050 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002051 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00002052#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002053 ioctl_errno = errno;
2054#ifndef HAVE_POLLABLE_PROCFS
2055 if (proc_poll_pipe[0] != -1) {
2056 if (ioctl_result < 0)
2057 kill(poller_pid, SIGKILL);
2058 else
2059 kill(poller_pid, SIGUSR1);
2060 }
2061#endif /* !HAVE_POLLABLE_PROCFS */
2062 }
2063 if (interrupted)
2064 return 0;
2065
2066 if (interactive)
2067 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2068
2069 if (ioctl_result < 0) {
2070 /* Find out what happened if it failed. */
2071 switch (ioctl_errno) {
2072 case EINTR:
2073 case EBADF:
2074 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002075#ifdef FREEBSD
2076 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00002077#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002078 case ENOENT:
2079 droptcb(tcp);
2080 continue;
2081 default:
2082 perror("PIOCWSTOP");
2083 exit(1);
2084 }
2085 }
2086
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002087#ifdef FREEBSD
2088 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2089 /* discard first event for a syscall we never entered */
2090 IOCTL (tcp->pfd, PIOCRUN, 0);
2091 continue;
2092 }
Roland McGrath553a6092002-12-16 20:40:39 +00002093#endif
2094
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002095 /* clear the just started flag */
2096 tcp->flags &= ~TCB_STARTUP;
2097
2098 /* set current output file */
2099 outf = tcp->outf;
2100
2101 if (cflag) {
2102 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002103#ifdef FREEBSD
2104 char buf[1024];
2105 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002106
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002107 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
2108 buf[len] = '\0';
2109 sscanf(buf,
2110 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2111 &stime.tv_sec, &stime.tv_usec);
2112 } else
2113 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002114#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002115 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2116 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002117#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002118 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2119 tcp->stime = stime;
2120 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002121 what = tcp->status.PR_WHAT;
2122 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002123#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002124 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002125 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2126 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002127 if (trace_syscall(tcp) < 0) {
2128 fprintf(stderr, "syscall trouble\n");
2129 exit(1);
2130 }
2131 }
2132 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002133#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002134 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002135#ifdef POLL_HACK
2136 in_syscall = tcp;
2137#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002138 case PR_SYSEXIT:
2139 if (trace_syscall(tcp) < 0) {
2140 fprintf(stderr, "syscall trouble\n");
2141 exit(1);
2142 }
2143 break;
2144 case PR_SIGNALLED:
2145 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
2146 printleader(tcp);
2147 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002148 signame(what), strsignal(what));
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002149 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002150#ifdef PR_INFO
2151 if (tcp->status.PR_INFO.si_signo == what) {
2152 printleader(tcp);
2153 tprintf(" siginfo=");
2154 printsiginfo(&tcp->status.PR_INFO, 1);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002155 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002156 }
2157#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002158 }
2159 break;
2160 case PR_FAULTED:
2161 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
2162 printleader(tcp);
2163 tprintf("=== FAULT %d ===", what);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002164 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002165 }
2166 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002167#ifdef FREEBSD
2168 case 0: /* handle case we polled for nothing */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002169 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00002170#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002171 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002172 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002173 exit(1);
2174 break;
2175 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002176 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002177#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002178 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00002179#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002180 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00002181#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002182 perror("PIOCRUN");
2183 exit(1);
2184 }
2185 }
2186 return 0;
2187}
2188
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002189#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002190
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002191#ifdef TCB_GROUP_EXITING
2192/* Handle an exit detach or death signal that is taking all the
2193 related clone threads with it. This is called in three circumstances:
2194 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
2195 SIG == 0 Continuing TCP will perform an exit_group syscall.
2196 SIG == other Continuing TCP with SIG will kill the process.
2197*/
2198static int
2199handle_group_exit(struct tcb *tcp, int sig)
2200{
2201 /* We need to locate our records of all the clone threads
2202 related to TCP, either its children or siblings. */
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002203 struct tcb *leader = NULL;
2204
2205 if (tcp->flags & TCB_CLONE_THREAD)
2206 leader = tcp->parent;
2207 else if (tcp->nclone_detached > 0)
2208 leader = tcp;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002209
2210 if (sig < 0) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002211 if (leader != NULL && leader != tcp
2212 && !(leader->flags & TCB_GROUP_EXITING)
2213 && !(tcp->flags & TCB_STARTUP)
2214 ) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002215 fprintf(stderr,
2216 "PANIC: handle_group_exit: %d leader %d\n",
2217 tcp->pid, leader ? leader->pid : -1);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002218 }
2219 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath1bfd3102007-08-03 10:02:00 +00002220#ifndef USE_PROCFS
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002221 resume_from_tcp(tcp);
Roland McGrath1bfd3102007-08-03 10:02:00 +00002222#endif
Roland McGrath0a463882007-07-05 18:43:16 +00002223 droptcb(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002224 }
2225 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00002226 /* Mark that we are taking the process down. */
2227 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002228 if (tcp->flags & TCB_ATTACHED) {
Roland McGrathd6a32f12007-07-11 08:35:11 +00002229 detach(tcp, sig);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002230 if (leader != NULL && leader != tcp)
Roland McGrath1bfd3102007-08-03 10:02:00 +00002231 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002232 } else {
2233 if (ptrace_restart(PTRACE_CONT, tcp, sig) < 0) {
2234 cleanup();
2235 return -1;
2236 }
2237 if (leader != NULL) {
Roland McGrath05690952004-10-20 01:00:27 +00002238 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002239 if (leader != tcp)
2240 droptcb(tcp);
2241 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002242 /* The leader will report to us as parent now,
2243 and then we'll get to the SIG==-1 case. */
2244 return 0;
2245 }
2246 }
2247
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002248 return 0;
2249}
2250#endif
2251
Denys Vlasenko215cc272009-01-09 17:22:56 +00002252static struct tcb *
2253collect_stopped_tcbs(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002254{
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002255#ifdef LINUX
2256 static int remembered_pid;
2257 static int remembered_status;
2258#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002259 int pid;
2260 int wait_errno;
2261 int status;
2262 struct tcb *tcp;
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002263 struct tcb *found_tcps;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002264#ifdef LINUX
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002265 struct tcb **nextp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002266 struct rusage ru;
Denys Vlasenko215cc272009-01-09 17:22:56 +00002267 struct rusage* ru_ptr = cflag ? &ru : NULL;
2268 int wnohang = 0;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002269#ifdef __WALL
Denys Vlasenko215cc272009-01-09 17:22:56 +00002270 int wait4_options = __WALL;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002271#endif
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002272
2273 if (remembered_pid > 0) {
2274 pid = remembered_pid;
2275 remembered_pid = 0;
2276 if (debug)
2277 fprintf(stderr, " [remembered wait(%#x) = %u]\n",
2278 remembered_status, pid);
2279 tcp = pid2tcb(pid); /* can't be NULL */
2280 tcp->wait_status = remembered_status;
2281 tcp->next_need_service = NULL;
2282 return tcp;
2283 }
2284 nextp = &found_tcps;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002285#endif /* LINUX */
2286
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002287 found_tcps = NULL;
Denys Vlasenko215cc272009-01-09 17:22:56 +00002288 while (1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002289#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002290#ifdef __WALL
Denys Vlasenko215cc272009-01-09 17:22:56 +00002291 pid = wait4(-1, &status, wait4_options | wnohang, ru_ptr);
Roland McGrath5bc05552002-12-17 04:50:47 +00002292 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002293 /* this kernel does not support __WALL */
2294 wait4_options &= ~__WALL;
2295 errno = 0;
Denys Vlasenko215cc272009-01-09 17:22:56 +00002296 pid = wait4(-1, &status, wait4_options | wnohang, ru_ptr);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002297 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002298 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002299 /* most likely a "cloned" process */
Denys Vlasenko215cc272009-01-09 17:22:56 +00002300 pid = wait4(-1, &status, __WCLONE | wnohang, ru_ptr);
2301 if (pid < 0 && errno != ECHILD) {
2302 fprintf(stderr, "strace: wait4(WCLONE) "
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002303 "failed: %s\n", strerror(errno));
2304 }
2305 }
Denys Vlasenko215cc272009-01-09 17:22:56 +00002306#else /* !__WALL */
2307 pid = wait4(-1, &status, wnohang, ru_ptr);
2308#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002309#endif /* LINUX */
2310#ifdef SUNOS4
2311 pid = wait(&status);
2312#endif /* SUNOS4 */
2313 wait_errno = errno;
2314 if (interactive)
2315 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2316
Denys Vlasenko215cc272009-01-09 17:22:56 +00002317 if (pid == 0 && wnohang) {
2318 /* We had at least one successful
2319 * wait() before. We waited
2320 * with WNOHANG second time.
2321 * Stop collecting more tracees,
2322 * process what we already have.
2323 */
2324 break;
2325 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002326 if (pid == -1) {
Denys Vlasenko2c8a2582009-01-21 19:05:43 +00002327 if (wait_errno == EINTR)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002328 continue;
Denys Vlasenko2c8a2582009-01-21 19:05:43 +00002329 if (wait_errno == ECHILD) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002330 /*
2331 * We would like to verify this case
2332 * but sometimes a race in Solbourne's
2333 * version of SunOS sometimes reports
2334 * ECHILD before sending us SIGCHILD.
2335 */
2336#if 0
Denys Vlasenko2c8a2582009-01-21 19:05:43 +00002337 if (nprocs != 0) {
2338 fprintf(stderr, "strace: proc miscount\n");
2339 exit(1);
2340 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002341#endif
Denys Vlasenko2c8a2582009-01-21 19:05:43 +00002342 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002343 }
Denys Vlasenko2c8a2582009-01-21 19:05:43 +00002344 errno = wait_errno;
2345 perror("strace: wait");
2346 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002347 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002348 if (pid == popen_pid) {
2349 if (WIFEXITED(status) || WIFSIGNALED(status))
2350 popen_pid = -1;
2351 continue;
2352 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002353 if (debug)
2354 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2355
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002356 /* RHEL5 bug workaround.
2357 * It can re-report stopped tasks. Happens on SIGSTOPs here.
2358 * Second (bogus) report has signal# set to 0.
2359 * Stop collecting and process what we have.
2360 */
2361 if (WIFSTOPPED(status) && WSTOPSIG(status) == 0)
2362 break;
2363
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002364 /* Look up `pid' in our table. */
2365 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002366#ifdef LINUX
Roland McGrath41c48222008-07-18 00:25:10 +00002367 if (followfork) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002368 /* This is needed to go with the CLONE_PTRACE
2369 changes in process.c/util.c: we might see
2370 the child's initial trap before we see the
2371 parent return from the clone syscall.
2372 Leave the child suspended until the parent
2373 returns from its system call. Only then
2374 will we have the association of parent and
2375 child so that we know how to do clearbpt
2376 in the child. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +00002377 tcp = alloctcb(pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002378 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002379 if (!qflag)
2380 fprintf(stderr, "\
2381Process %d attached (waiting for parent)\n",
2382 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002383 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002384 else
2385 /* This can happen if a clone call used
2386 CLONE_PTRACE itself. */
Denys Vlasenko215cc272009-01-09 17:22:56 +00002387#endif /* LINUX */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002388 {
2389 fprintf(stderr, "unknown pid: %u\n", pid);
2390 if (WIFSTOPPED(status))
2391 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2392 exit(1);
2393 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002394 }
Denys Vlasenko215cc272009-01-09 17:22:56 +00002395
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002396#ifdef LINUX
Denys Vlasenko84e20af2009-02-10 16:03:20 +00002397 if (cflag) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002398 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2399 tcp->stime = ru.ru_stime;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002400 }
Denys Vlasenko84e20af2009-02-10 16:03:20 +00002401#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002402 if (tcp->flags & TCB_SUSPENDED) {
2403 /*
2404 * Apparently, doing any ptrace() call on a stopped
2405 * process, provokes the kernel to report the process
2406 * status again on a subsequent wait(), even if the
2407 * process has not been actually restarted.
2408 * Since we have inspected the arguments of suspended
2409 * processes we end up here testing for this case.
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002410 *
2411 * We also end up here when we catch new pid of
2412 * CLONE_PTRACEd process. Do not process/restart it
2413 * until we see corresponding clone() syscall exit
2414 * in its parent.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002415 */
2416 continue;
2417 }
Denys Vlasenko215cc272009-01-09 17:22:56 +00002418
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002419#ifdef LINUX
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002420 /* So far observed only on RHEL5 ia64, but I imagine this
2421 * can legitimately happen elsewhere.
2422 * If we waited and got a stopped task notification,
2423 * subsequent wait may return the same pid again, for example,
2424 * with SIGKILL notification. SIGKILL kills even stopped tasks.
2425 * We must not add it to the list
2426 * (one task can't be inserted twice in the list).
2427 */
2428 {
2429 struct tcb *f = found_tcps;
2430 while (f) {
2431 if (f == tcp) {
2432 remembered_pid = pid;
2433 remembered_status = status;
2434 return found_tcps;
2435 }
2436 f = f->next_need_service;
2437 }
2438 }
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002439 /* It is important to not invert the order of tasks
2440 * to process. For one, alloc_tcb() above picks newly forked
2441 * threads in some order, processing of them and their parent
2442 * should be in the same order, otherwise bad things happen
2443 * (misinterpreted SIGSTOPs and such).
2444 */
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002445 tcp->wait_status = status;
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002446 *nextp = tcp;
2447 nextp = &tcp->next_need_service;
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002448 *nextp = NULL;
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002449 wnohang = WNOHANG;
2450#endif
2451#ifdef SUNOS4
2452 /* Probably need to replace wait with waitpid
2453 * and loop on Sun too, but I can't test it. Volunteers?
2454 */
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002455 tcp->wait_status = status;
2456 tcp->next_need_service = NULL;
2457 found_tcps = tcp;
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002458 break;
2459#endif
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002460 } /* while (1) - collecting all stopped/exited tracees */
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002461
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002462 return found_tcps;
2463}
2464
2465static int
2466handle_stopped_tcbs(struct tcb *tcp)
2467{
2468 for (; tcp; tcp = tcp->next_need_service) {
2469 int pid;
2470 int status;
2471
Denys Vlasenko215cc272009-01-09 17:22:56 +00002472 outf = tcp->outf;
2473 status = tcp->wait_status;
2474 pid = tcp->pid;
2475
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002476 if (WIFSIGNALED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002477 if (pid == strace_child)
2478 exit_code = 0x100 | WTERMSIG(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002479 if (!cflag
2480 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2481 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002482 tprintf("+++ killed by %s %s+++",
2483 signame(WTERMSIG(status)),
2484#ifdef WCOREDUMP
2485 WCOREDUMP(status) ? "(core dumped) " :
2486#endif
2487 "");
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002488 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002489 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002490#ifdef TCB_GROUP_EXITING
2491 handle_group_exit(tcp, -1);
2492#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002493 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002494#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002495 continue;
2496 }
2497 if (WIFEXITED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002498 if (pid == strace_child)
2499 exit_code = WEXITSTATUS(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002500 if (debug)
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002501 fprintf(stderr, "pid %u exited with %d\n", pid, WEXITSTATUS(status));
2502 if ((tcp->flags & (TCB_ATTACHED|TCB_STARTUP)) == TCB_ATTACHED
Roland McGrath05690952004-10-20 01:00:27 +00002503#ifdef TCB_GROUP_EXITING
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002504 && !(tcp->parent && (tcp->parent->flags & TCB_GROUP_EXITING))
Roland McGrath1bfd3102007-08-03 10:02:00 +00002505 && !(tcp->flags & TCB_GROUP_EXITING)
Roland McGrath05690952004-10-20 01:00:27 +00002506#endif
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002507 ) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002508 fprintf(stderr,
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002509 "PANIC: attached pid %u exited with %d\n",
2510 pid, WEXITSTATUS(status));
2511 }
Roland McGrath0a396902003-06-10 03:05:53 +00002512 if (tcp == tcp_last) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002513 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT)) == TCB_INSYSCALL)
Roland McGrath0a396902003-06-10 03:05:53 +00002514 tprintf(" <unfinished ... exit status %d>\n",
2515 WEXITSTATUS(status));
2516 tcp_last = NULL;
2517 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002518#ifdef TCB_GROUP_EXITING
2519 handle_group_exit(tcp, -1);
2520#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002521 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002522#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002523 continue;
2524 }
2525 if (!WIFSTOPPED(status)) {
2526 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2527 droptcb(tcp);
2528 continue;
2529 }
2530 if (debug)
2531 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002532 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002533
Roland McGrath02203312007-06-11 22:06:31 +00002534 /*
2535 * Interestingly, the process may stop
2536 * with STOPSIG equal to some other signal
Denys Vlasenko84e20af2009-02-10 16:03:20 +00002537 * than SIGSTOP if we happen to attach
Roland McGrath02203312007-06-11 22:06:31 +00002538 * just before the process takes a signal.
2539 */
2540 if ((tcp->flags & TCB_STARTUP) && WSTOPSIG(status) == SIGSTOP) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002541 /*
2542 * This flag is there to keep us in sync.
2543 * Next time this process stops it should
2544 * really be entering a system call.
2545 */
2546 tcp->flags &= ~TCB_STARTUP;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002547 if (tcp->flags & TCB_BPTSET) {
Roland McGrath02203312007-06-11 22:06:31 +00002548 /*
2549 * One example is a breakpoint inherited from
2550 * parent through fork ().
2551 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002552 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2553 droptcb(tcp);
2554 cleanup();
2555 return -1;
2556 }
2557 }
Denys Vlasenkob1efe532008-12-23 16:14:42 +00002558/* Add more OSes after you verified it works for them. */
Denys Vlasenkof535b542009-01-13 18:30:55 +00002559/* PTRACE_SETOPTIONS may be an enum, not a #define.
2560 * But sometimes we can test for it by checking PT_SETOPTIONS.
2561 */
2562#if defined LINUX && (defined PTRACE_SETOPTIONS || defined PT_SETOPTIONS)
Denys Vlasenko0861ecb2009-01-02 16:55:24 +00002563# ifndef PTRACE_O_TRACESYSGOOD
2564# define PTRACE_O_TRACESYSGOOD 0x00000001
2565# endif
2566# ifndef PTRACE_O_TRACEEXEC
2567# define PTRACE_O_TRACEEXEC 0x00000010
2568# endif
2569# ifndef PTRACE_EVENT_EXEC
2570# define PTRACE_EVENT_EXEC 4
2571# endif
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002572 /*
2573 * Ask kernel to set signo to SIGTRAP | 0x80
2574 * on ptrace-generated SIGTRAPs, and mark
2575 * execve's SIGTRAP with PTRACE_EVENT_EXEC.
2576 */
Denys Vlasenko96d5a762008-12-29 19:13:27 +00002577 if (!ptrace_opts_set) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002578 char *p;
Denys Vlasenko96d5a762008-12-29 19:13:27 +00002579 ptrace_opts_set = 1;
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002580
2581 /* RHEL 2.6.18 definitely has crippling bugs */
2582 /* Vanilla and Fedora 2.6.29 seems to work */
2583 p = utsname_buf.release;
2584 if (strtoul(p, &p, 10) < 2 || *p != '.')
2585 goto tracing;
2586 if (strtoul(++p, &p, 10) < 6 || *p != '.')
2587 goto tracing;
2588 if (strtoul(++p, &p, 10) < 29)
2589 goto tracing;
Denys Vlasenko96d5a762008-12-29 19:13:27 +00002590 /*
2591 * NB: even if this "succeeds", we can
2592 * revert back to SIGTRAP if we later see
2593 * that it didnt really work.
2594 * Old kernels are known to lie here.
2595 */
2596 if (ptrace(PTRACE_SETOPTIONS, pid, (char *) 0,
2597 (void *) (PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC)) == 0)
2598 ptrace_stop_sig = SIGTRAP | 0x80;
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002599 }
2600#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002601 goto tracing;
2602 }
2603
Denys Vlasenkof535b542009-01-13 18:30:55 +00002604#if defined LINUX && (defined PTRACE_SETOPTIONS || defined PT_SETOPTIONS)
Denys Vlasenko96d5a762008-12-29 19:13:27 +00002605 if (ptrace_stop_sig != SIGTRAP && WSTOPSIG(status) == SIGTRAP) {
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002606 /*
2607 * We told ptrace to report SIGTRAP | 0x80 on this process
2608 * but got bare SIGTRAP. This can be a genuine SIGTRAP:
2609 * kill(pid, SIGTRAP), trap insn, etc;
2610 * but be paranoid about it.
2611 */
2612 if (((unsigned)status >> 16) == PTRACE_EVENT_EXEC) {
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00002613 /* It's post-exec ptrace stop. Ignore it,
2614 * we will get syscall exit ptrace stop later.
2615 */
2616#ifdef TCB_WAITEXECVE
2617 tcp->flags &= ~TCB_WAITEXECVE;
2618#endif
2619 goto tracing;
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002620 } else {
2621 /* Take a better look... */
2622 siginfo_t si;
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00002623 si.si_signo = 0;
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002624 ptrace(PTRACE_GETSIGINFO, pid, (void*) 0, (void*) &si);
2625 /*
2626 * Check some fields to make sure we see
2627 * real SIGTRAP.
2628 * Otherwise interpret it as ptrace stop.
2629 * Real SIGTRAPs (int3 insn on x86, kill() etc)
2630 * have these values:
2631 * int3: kill -TRAP $pid:
2632 * si_signo:5 (SIGTRAP) si_signo:5 (SIGTRAP)
2633 * si_errno:0 si_errno:(?)
2634 * si_code:128 (SI_KERNEL) si_code:0 (SI_USER)
2635 * si_pid:0 si_pid:(>0?)
2636 * si_band:0 si_band:(?)
2637 * Ptrace stops have garbage there instead.
2638 */
2639 if (si.si_signo != SIGTRAP
2640 || (si.si_code != SI_KERNEL && si.si_code != SI_USER)
2641 ) {
Denys Vlasenko96d5a762008-12-29 19:13:27 +00002642 fprintf(stderr, "bogus SIGTRAP (si_code:%x), assuming old kernel\n", si.si_code);
2643 ptrace_stop_sig = SIGTRAP;
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002644 }
2645 }
2646 }
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002647#endif
2648
Denys Vlasenko96d5a762008-12-29 19:13:27 +00002649 if (WSTOPSIG(status) != ptrace_stop_sig) {
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002650 /* This isn't a ptrace stop. */
2651
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002652 if (WSTOPSIG(status) == SIGSTOP &&
2653 (tcp->flags & TCB_SIGTRAPPED)) {
2654 /*
2655 * Trapped attempt to block SIGTRAP
2656 * Hope we are back in control now.
2657 */
2658 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002659 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002660 cleanup();
2661 return -1;
2662 }
2663 continue;
2664 }
2665 if (!cflag
2666 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00002667 unsigned long addr = 0;
2668 long pc = 0;
Dmitry V. Levin96339422006-10-11 23:11:43 +00002669#if defined(PT_CR_IPSR) && defined(PT_CR_IIP) && defined(PT_GETSIGINFO)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002670# define PSR_RI 41
2671 struct siginfo si;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002672 long psr;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002673
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002674 upeek(tcp, PT_CR_IPSR, &psr);
2675 upeek(tcp, PT_CR_IIP, &pc);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002676
2677 pc += (psr >> PSR_RI) & 0x3;
2678 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2679 addr = (unsigned long) si.si_addr;
Roland McGrath3a055d72005-03-06 22:24:29 +00002680#elif defined PTRACE_GETSIGINFO
2681 if (WSTOPSIG(status) == SIGSEGV ||
2682 WSTOPSIG(status) == SIGBUS) {
2683 siginfo_t si;
2684 if (ptrace(PTRACE_GETSIGINFO, pid,
2685 0, &si) == 0)
2686 addr = (unsigned long)
2687 si.si_addr;
2688 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002689#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002690 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002691 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002692 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002693 strsignal(WSTOPSIG(status)), pc, addr);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002694 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002695 }
Roland McGrath05690952004-10-20 01:00:27 +00002696 if (((tcp->flags & TCB_ATTACHED) ||
2697 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002698 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002699#ifdef TCB_GROUP_EXITING
2700 handle_group_exit(tcp, WSTOPSIG(status));
2701#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002702 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002703#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002704 continue;
2705 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002706 if (ptrace_restart(PTRACE_SYSCALL, tcp, WSTOPSIG(status)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002707 cleanup();
2708 return -1;
2709 }
2710 tcp->flags &= ~TCB_SUSPENDED;
2711 continue;
2712 }
Roland McGrath02203312007-06-11 22:06:31 +00002713 /* we handled the STATUS, we are permitted to interrupt now. */
2714 if (interrupted)
2715 return 0;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002716 if (trace_syscall(tcp) < 0) {
2717 /* trace_syscall printed incompletely decoded syscall,
2718 * add error indicator.
2719 * NB: modulo bugs, errno must be nonzero, do not add
2720 * "if (err != 0)", this will hide bugs.
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002721 */
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002722 int err = tcp->ptrace_errno;
2723 tcp->ptrace_errno = 0;
2724 if (err == ESRCH)
2725 tprintf(" <unavailable>");
2726 else
2727 tprintf(" <ptrace error %d (%s)>", err, strerror(err));
2728 printtrailer();
2729 if (err == ESRCH)
2730 /* Want to get death report anyway. */
2731 goto tracing;
2732 /* Strange error, we dare not continue. */
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002733 if (tcp->flags & TCB_ATTACHED) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002734 detach(tcp, 0);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002735 } else {
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002736 ptrace(PTRACE_KILL, tcp->pid, (char *) 1, SIGTERM);
2737 /* [why SIGTERM? why not also kill(SIGKILL)?] */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002738 droptcb(tcp);
2739 }
2740 continue;
2741 }
2742 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002743#ifdef TCB_GROUP_EXITING
2744 if (tcp->flags & TCB_GROUP_EXITING) {
2745 if (handle_group_exit(tcp, 0) < 0)
2746 return -1;
2747 continue;
2748 }
2749#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002750 if (tcp->flags & TCB_ATTACHED)
2751 detach(tcp, 0);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002752 else if (ptrace_restart(PTRACE_CONT, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002753 cleanup();
2754 return -1;
2755 }
2756 continue;
2757 }
2758 if (tcp->flags & TCB_SUSPENDED) {
2759 if (!qflag)
2760 fprintf(stderr, "Process %u suspended\n", pid);
2761 continue;
2762 }
2763 tracing:
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002764 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002765 cleanup();
2766 return -1;
2767 }
Denys Vlasenko215cc272009-01-09 17:22:56 +00002768 } /* for each tcp */
2769
2770 return 0;
2771}
2772
2773static int
2774trace()
2775{
2776 int rc;
2777 struct tcb *tcbs;
2778
2779 while (nprocs != 0) {
2780 if (interrupted)
2781 return 0;
2782 if (interactive)
2783 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2784
2785 /* The loop of "wait for one tracee, serve it, repeat"
2786 * may leave some tracees never served.
2787 * Kernel provides no guarantees of fairness when you have
2788 * many waitable tasks.
2789 * Try strace -f with test/many_looping_threads.c example.
2790 * To fix it, we collect *all* waitable tasks, then handle
2791 * them all, then repeat.
2792 */
2793 tcbs = collect_stopped_tcbs();
2794 if (!tcbs)
2795 break;
2796 rc = handle_stopped_tcbs(tcbs);
2797 if (rc)
2798 return rc;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002799 }
2800 return 0;
2801}
2802
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002803#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002804
2805static int curcol;
2806
2807#ifdef __STDC__
2808#include <stdarg.h>
2809#define VA_START(a, b) va_start(a, b)
2810#else
2811#include <varargs.h>
2812#define VA_START(a, b) va_start(a)
2813#endif
2814
2815void
2816#ifdef __STDC__
2817tprintf(const char *fmt, ...)
2818#else
2819tprintf(fmt, va_alist)
2820char *fmt;
2821va_dcl
2822#endif
2823{
2824 va_list args;
2825
2826 VA_START(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002827 if (outf) {
2828 int n = vfprintf(outf, fmt, args);
2829 if (n < 0 && outf != stderr)
2830 perror(outfname == NULL
2831 ? "<writing to pipe>" : outfname);
2832 else
2833 curcol += n;
2834 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002835 va_end(args);
2836 return;
2837}
2838
2839void
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002840printleader(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002841{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002842 if (tcp_last) {
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002843 int err = tcp_last->ptrace_errno;
2844 if (err) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002845 tcp_last->ptrace_errno = 0;
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002846 if (tcp_last->flags & TCB_INSYSCALL) {
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002847 if (err == ESRCH)
2848 tprintf(" <unavailable ...>\n");
2849 else
2850 tprintf(" <ptrace error %d (%s) ...>\n", err, strerror(err));
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002851 tcp_last->flags |= TCB_REPRINT;
2852 } else {
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002853 /* Not sure this branch can ever be reached.
2854 * Oh well. Using subtly different format
2855 * (without "?" after "=") to make it
2856 * noticeable (grep for '= <' in straces).
2857 */
2858 if (err == ESRCH)
2859 tprintf("= <unavailable>\n");
2860 else
2861 tprintf("= <ptrace error %d (%s)>\n", err, strerror(err));
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002862 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002863 } else if (!outfname || followfork < 2 || tcp_last == tcp) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002864 tprintf(" <unfinished ...>\n");
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002865 tcp_last->flags |= TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002866 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002867 }
2868 curcol = 0;
2869 if ((followfork == 1 || pflag_seen > 1) && outfname)
2870 tprintf("%-5d ", tcp->pid);
2871 else if (nprocs > 1 && !outfname)
2872 tprintf("[pid %5u] ", tcp->pid);
2873 if (tflag) {
2874 char str[sizeof("HH:MM:SS")];
2875 struct timeval tv, dtv;
2876 static struct timeval otv;
2877
2878 gettimeofday(&tv, NULL);
2879 if (rflag) {
2880 if (otv.tv_sec == 0)
2881 otv = tv;
2882 tv_sub(&dtv, &tv, &otv);
2883 tprintf("%6ld.%06ld ",
2884 (long) dtv.tv_sec, (long) dtv.tv_usec);
2885 otv = tv;
2886 }
2887 else if (tflag > 2) {
2888 tprintf("%ld.%06ld ",
2889 (long) tv.tv_sec, (long) tv.tv_usec);
2890 }
2891 else {
2892 time_t local = tv.tv_sec;
2893 strftime(str, sizeof(str), "%T", localtime(&local));
2894 if (tflag > 1)
2895 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2896 else
2897 tprintf("%s ", str);
2898 }
2899 }
2900 if (iflag)
2901 printcall(tcp);
2902}
2903
2904void
2905tabto(col)
2906int col;
2907{
2908 if (curcol < col)
2909 tprintf("%*s", col - curcol, "");
2910}
2911
2912void
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002913printtrailer(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002914{
2915 tprintf("\n");
2916 tcp_last = NULL;
2917}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002918
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002919#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002920
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002921int
2922mp_ioctl(int fd, int cmd, void *arg, int size)
2923{
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002924 struct iovec iov[2];
2925 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002926
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002927 iov[0].iov_base = &cmd;
2928 iov[0].iov_len = sizeof cmd;
2929 if (arg) {
2930 ++n;
2931 iov[1].iov_base = arg;
2932 iov[1].iov_len = size;
2933 }
Roland McGrath553a6092002-12-16 20:40:39 +00002934
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002935 return writev(fd, iov, n);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002936}
2937
2938#endif