blob: 864e7f40009f5aa5061700201bdc5767fcb3e7fc [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 Vlasenko222713a2009-03-17 14:29:59 +0000440 if (ptrace(PTRACE_ATTACH, tid, (char *) 1, 0) < 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000441 ++nerr;
Denys Vlasenko222713a2009-03-17 14:29:59 +0000442 continue;
443 }
444#if defined LINUX && defined __NR_tkill
445 syscall(__NR_tkill, tid, SIGSTOP);
446 ptrace(PTRACE_CONT, tid, 0, 0);
447#endif
448 if (tid != tcbtab[tcbi]->pid) {
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000449 tcp = alloctcb(tid);
Denys Vlasenko84e20af2009-02-10 16:03:20 +0000450 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_CLONE_DETACHED;
Roland McGrath02203312007-06-11 22:06:31 +0000451 tcbtab[tcbi]->nchildren++;
452 tcbtab[tcbi]->nclone_threads++;
453 tcbtab[tcbi]->nclone_detached++;
454 tcp->parent = tcbtab[tcbi];
455 }
Roland McGrath02203312007-06-11 22:06:31 +0000456 }
457 closedir(dir);
Denys Vlasenko222713a2009-03-17 14:29:59 +0000458 if (interactive) {
459 sigprocmask(SIG_SETMASK, &empty_set, NULL);
460 if (interrupted)
461 return;
462 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
463 }
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000464 ntid -= nerr;
465 if (ntid == 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000466 perror("attach: ptrace(PTRACE_ATTACH, ...)");
467 droptcb(tcp);
468 continue;
469 }
470 if (!qflag) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000471 fprintf(stderr, ntid > 1
472? "Process %u attached with %u threads - interrupt to quit\n"
473: "Process %u attached - interrupt to quit\n",
474 tcbtab[tcbi]->pid, ntid);
Roland McGrath02203312007-06-11 22:06:31 +0000475 }
476 continue;
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000477 } /* if (opendir worked) */
478 } /* if (-f) */
Roland McGrath02203312007-06-11 22:06:31 +0000479# endif
480 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
481 perror("attach: ptrace(PTRACE_ATTACH, ...)");
482 droptcb(tcp);
483 continue;
484 }
Denys Vlasenko222713a2009-03-17 14:29:59 +0000485#if defined LINUX && defined __NR_tkill
486 /* If process was SIGSTOPed, and waited for,
487 even before attach, we will never get SIGSTOP
488 notification. This works around it.
489 Borrowed from GDB, thanks Jan! */
490 syscall(__NR_tkill, tcp->pid, SIGSTOP);
491 ptrace(PTRACE_CONT, tcp->pid, 0, 0);
492#endif
Roland McGrath02203312007-06-11 22:06:31 +0000493 /* INTERRUPTED is going to be checked at the top of TRACE. */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000494
495 if (daemonized_tracer) {
496 /*
497 * It is our grandparent we trace, not a -p PID.
498 * Don't want to just detach on exit, so...
499 */
500 tcp->flags &= ~TCB_ATTACHED;
501 /*
502 * Make parent go away.
503 * Also makes grandparent's wait() unblock.
504 */
505 kill(getppid(), SIGKILL);
506 }
507
Roland McGrath02203312007-06-11 22:06:31 +0000508#endif /* !USE_PROCFS */
509 if (!qflag)
510 fprintf(stderr,
511 "Process %u attached - interrupt to quit\n",
512 tcp->pid);
513 }
514
515 if (interactive)
516 sigprocmask(SIG_SETMASK, &empty_set, NULL);
517}
518
519static void
520startup_child (char **argv)
521{
522 struct stat statbuf;
523 const char *filename;
524 char pathname[MAXPATHLEN];
525 int pid = 0;
526 struct tcb *tcp;
527
528 filename = argv[0];
529 if (strchr(filename, '/')) {
530 if (strlen(filename) > sizeof pathname - 1) {
531 errno = ENAMETOOLONG;
532 perror("strace: exec");
533 exit(1);
534 }
535 strcpy(pathname, filename);
536 }
537#ifdef USE_DEBUGGING_EXEC
538 /*
539 * Debuggers customarily check the current directory
540 * first regardless of the path but doing that gives
541 * security geeks a panic attack.
542 */
543 else if (stat(filename, &statbuf) == 0)
544 strcpy(pathname, filename);
545#endif /* USE_DEBUGGING_EXEC */
546 else {
547 char *path;
548 int m, n, len;
549
550 for (path = getenv("PATH"); path && *path; path += m) {
551 if (strchr(path, ':')) {
552 n = strchr(path, ':') - path;
553 m = n + 1;
554 }
555 else
556 m = n = strlen(path);
557 if (n == 0) {
558 if (!getcwd(pathname, MAXPATHLEN))
559 continue;
560 len = strlen(pathname);
561 }
562 else if (n > sizeof pathname - 1)
563 continue;
564 else {
565 strncpy(pathname, path, n);
566 len = n;
567 }
568 if (len && pathname[len - 1] != '/')
569 pathname[len++] = '/';
570 strcpy(pathname + len, filename);
571 if (stat(pathname, &statbuf) == 0 &&
572 /* Accept only regular files
573 with some execute bits set.
574 XXX not perfect, might still fail */
575 S_ISREG(statbuf.st_mode) &&
576 (statbuf.st_mode & 0111))
577 break;
578 }
579 }
580 if (stat(pathname, &statbuf) < 0) {
581 fprintf(stderr, "%s: %s: command not found\n",
582 progname, filename);
583 exit(1);
584 }
Dmitry V. Levina6809652008-11-10 17:14:58 +0000585 strace_child = pid = fork();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000586 if (pid < 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000587 perror("strace: fork");
588 cleanup();
589 exit(1);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000590 }
591 if ((pid != 0 && daemonized_tracer) /* parent: to become a traced process */
592 || (pid == 0 && !daemonized_tracer) /* child: to become a traced process */
593 ) {
594 pid = getpid();
Roland McGrath02203312007-06-11 22:06:31 +0000595#ifdef USE_PROCFS
596 if (outf != stderr) close (fileno (outf));
597#ifdef MIPS
598 /* Kludge for SGI, see proc_open for details. */
599 sa.sa_handler = foobar;
600 sa.sa_flags = 0;
601 sigemptyset(&sa.sa_mask);
602 sigaction(SIGINT, &sa, NULL);
603#endif /* MIPS */
604#ifndef FREEBSD
605 pause();
606#else /* FREEBSD */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000607 kill(pid, SIGSTOP); /* stop HERE */
Roland McGrath02203312007-06-11 22:06:31 +0000608#endif /* FREEBSD */
609#else /* !USE_PROCFS */
610 if (outf!=stderr)
611 close(fileno (outf));
612
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000613 if (!daemonized_tracer) {
614 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
615 perror("strace: ptrace(PTRACE_TRACEME, ...)");
616 exit(1);
617 }
618 if (debug)
619 kill(pid, SIGSTOP);
Roland McGrath02203312007-06-11 22:06:31 +0000620 }
Roland McGrath02203312007-06-11 22:06:31 +0000621
622 if (username != NULL || geteuid() == 0) {
623 uid_t run_euid = run_uid;
624 gid_t run_egid = run_gid;
625
626 if (statbuf.st_mode & S_ISUID)
627 run_euid = statbuf.st_uid;
628 if (statbuf.st_mode & S_ISGID)
629 run_egid = statbuf.st_gid;
630
631 /*
632 * It is important to set groups before we
633 * lose privileges on setuid.
634 */
635 if (username != NULL) {
636 if (initgroups(username, run_gid) < 0) {
637 perror("initgroups");
638 exit(1);
639 }
640 if (setregid(run_gid, run_egid) < 0) {
641 perror("setregid");
642 exit(1);
643 }
644 if (setreuid(run_uid, run_euid) < 0) {
645 perror("setreuid");
646 exit(1);
647 }
648 }
649 }
650 else
651 setreuid(run_uid, run_uid);
652
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000653 if (!daemonized_tracer) {
654 /*
655 * Induce an immediate stop so that the parent
656 * will resume us with PTRACE_SYSCALL and display
657 * this execve call normally.
658 */
659 kill(getpid(), SIGSTOP);
660 } else {
661 struct sigaction sv_sigchld;
662 sigaction(SIGCHLD, NULL, &sv_sigchld);
663 /*
664 * Make sure it is not SIG_IGN, otherwise wait
665 * will not block.
666 */
667 signal(SIGCHLD, SIG_DFL);
668 /*
669 * Wait for grandchild to attach to us.
670 * It kills child after that, and wait() unblocks.
671 */
672 alarm(3);
673 wait(NULL);
674 alarm(0);
675 sigaction(SIGCHLD, &sv_sigchld, NULL);
676 }
Roland McGrath02203312007-06-11 22:06:31 +0000677#endif /* !USE_PROCFS */
678
679 execv(pathname, argv);
680 perror("strace: exec");
681 _exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000682 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000683
684 /* We are the tracer. */
685 tcp = alloctcb(daemonized_tracer ? getppid() : pid);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000686 if (daemonized_tracer) {
687 /* We want subsequent startup_attach() to attach to it. */
688 tcp->flags |= TCB_ATTACHED;
689 }
Roland McGrath02203312007-06-11 22:06:31 +0000690#ifdef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000691 if (proc_open(tcp, 0) < 0) {
692 fprintf(stderr, "trouble opening proc file\n");
693 cleanup();
694 exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000695 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000696#endif /* USE_PROCFS */
Roland McGrath02203312007-06-11 22:06:31 +0000697}
698
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000699int
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000700main(int argc, char *argv[])
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000701{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000702 struct tcb *tcp;
703 int c, pid = 0;
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000704 int optF = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000705 struct sigaction sa;
706
707 static char buf[BUFSIZ];
708
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000709 progname = argv[0] ? argv[0] : "strace";
710
Denys Vlasenko7e0615f2009-01-28 19:00:54 +0000711 uname(&utsname_buf);
712
Roland McGrathee9d4352002-12-18 04:16:10 +0000713 /* Allocate the initial tcbtab. */
714 tcbtabsize = argc; /* Surely enough for all -p args. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000715 if ((tcbtab = calloc(tcbtabsize, sizeof tcbtab[0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000716 fprintf(stderr, "%s: out of memory\n", progname);
717 exit(1);
718 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000719 if ((tcbtab[0] = calloc(tcbtabsize, sizeof tcbtab[0][0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000720 fprintf(stderr, "%s: out of memory\n", progname);
721 exit(1);
722 }
Roland McGrathee9d4352002-12-18 04:16:10 +0000723 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
724 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
725
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000726 outf = stderr;
727 interactive = 1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000728 set_sortby(DEFAULT_SORTBY);
729 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000730 qualify("trace=all");
731 qualify("abbrev=all");
732 qualify("verbose=all");
733 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000734 while ((c = getopt(argc, argv,
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000735 "+cdfFhiqrtTvVxz"
736#ifndef USE_PROCFS
737 "D"
738#endif
739 "a:e:o:O:p:s:S:u:E:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000740 switch (c) {
741 case 'c':
742 cflag++;
743 dtime++;
744 break;
745 case 'd':
746 debug++;
747 break;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000748#ifndef USE_PROCFS
749 /* Experimental, not documented in manpage yet. */
750 case 'D':
751 daemonized_tracer = 1;
752 break;
753#endif
Roland McGrath41c48222008-07-18 00:25:10 +0000754 case 'F':
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000755 optF = 1;
756 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000757 case 'f':
758 followfork++;
759 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000760 case 'h':
761 usage(stdout, 0);
762 break;
763 case 'i':
764 iflag++;
765 break;
766 case 'q':
767 qflag++;
768 break;
769 case 'r':
770 rflag++;
771 tflag++;
772 break;
773 case 't':
774 tflag++;
775 break;
776 case 'T':
777 dtime++;
778 break;
779 case 'x':
780 xflag++;
781 break;
782 case 'v':
783 qualify("abbrev=none");
784 break;
785 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +0000786 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000787 exit(0);
788 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000789 case 'z':
790 not_failing_only = 1;
791 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000792 case 'a':
793 acolumn = atoi(optarg);
794 break;
795 case 'e':
796 qualify(optarg);
797 break;
798 case 'o':
799 outfname = strdup(optarg);
800 break;
801 case 'O':
802 set_overhead(atoi(optarg));
803 break;
804 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +0000805 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000806 fprintf(stderr, "%s: Invalid process id: %s\n",
807 progname, optarg);
808 break;
809 }
810 if (pid == getpid()) {
Wichert Akkerman54a47671999-10-17 00:57:34 +0000811 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000812 break;
813 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000814 tcp = alloc_tcb(pid, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000815 tcp->flags |= TCB_ATTACHED;
816 pflag_seen++;
817 break;
818 case 's':
819 max_strlen = atoi(optarg);
Roland McGrathdccec722005-05-09 07:45:47 +0000820 if (max_strlen < 0) {
821 fprintf(stderr,
822 "%s: invalid -s argument: %s\n",
823 progname, optarg);
824 exit(1);
825 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000826 break;
827 case 'S':
828 set_sortby(optarg);
829 break;
830 case 'u':
831 username = strdup(optarg);
832 break;
Roland McGrathde6e5332003-01-24 04:31:23 +0000833 case 'E':
834 if (putenv(optarg) < 0) {
835 fprintf(stderr, "%s: out of memory\n",
836 progname);
837 exit(1);
838 }
839 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000840 default:
841 usage(stderr, 1);
842 break;
843 }
844 }
845
Roland McGrathd0c4c0c2006-04-25 07:39:40 +0000846 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +0000847 usage(stderr, 1);
848
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000849 if (!followfork)
850 followfork = optF;
851
Roland McGrathcb9def62006-04-25 07:48:03 +0000852 if (followfork > 1 && cflag) {
853 fprintf(stderr,
854 "%s: -c and -ff are mutually exclusive options\n",
855 progname);
856 exit(1);
857 }
858
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000859 /* See if they want to run as another user. */
860 if (username != NULL) {
861 struct passwd *pent;
862
863 if (getuid() != 0 || geteuid() != 0) {
864 fprintf(stderr,
865 "%s: you must be root to use the -u option\n",
866 progname);
867 exit(1);
868 }
869 if ((pent = getpwnam(username)) == NULL) {
870 fprintf(stderr, "%s: cannot find user `%s'\n",
Roland McGrath09553f82007-07-05 19:31:49 +0000871 progname, username);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000872 exit(1);
873 }
874 run_uid = pent->pw_uid;
875 run_gid = pent->pw_gid;
876 }
877 else {
878 run_uid = getuid();
879 run_gid = getgid();
880 }
881
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000882 /* Check if they want to redirect the output. */
883 if (outfname) {
Roland McGrath37b9a662003-11-07 02:26:54 +0000884 /* See if they want to pipe the output. */
885 if (outfname[0] == '|' || outfname[0] == '!') {
886 /*
887 * We can't do the <outfname>.PID funny business
888 * when using popen, so prohibit it.
889 */
890 if (followfork > 1) {
891 fprintf(stderr, "\
892%s: piping the output and -ff are mutually exclusive options\n",
893 progname);
894 exit(1);
895 }
896
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000897 if ((outf = strace_popen(outfname + 1)) == NULL)
Roland McGrath37b9a662003-11-07 02:26:54 +0000898 exit(1);
Roland McGrath37b9a662003-11-07 02:26:54 +0000899 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000900 else if (followfork <= 1 &&
901 (outf = strace_fopen(outfname, "w")) == NULL)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000902 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000903 }
904
Roland McGrath37b9a662003-11-07 02:26:54 +0000905 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000906 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +0000907 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000908 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000909 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +0000910 }
Roland McGrath54cc1c82007-11-03 23:34:11 +0000911 /* Valid states here:
912 optind < argc pflag_seen outfname interactive
913 1 0 0 1
914 0 1 0 1
915 1 0 1 0
916 0 1 1 1
917 */
918
919 /* STARTUP_CHILD must be called before the signal handlers get
920 installed below as they are inherited into the spawned process.
921 Also we do not need to be protected by them as during interruption
922 in the STARTUP_CHILD mode we kill the spawned process anyway. */
923 if (!pflag_seen)
924 startup_child(&argv[optind]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000925
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000926 sigemptyset(&empty_set);
927 sigemptyset(&blocked_set);
928 sa.sa_handler = SIG_IGN;
929 sigemptyset(&sa.sa_mask);
930 sa.sa_flags = 0;
931 sigaction(SIGTTOU, &sa, NULL);
932 sigaction(SIGTTIN, &sa, NULL);
933 if (interactive) {
934 sigaddset(&blocked_set, SIGHUP);
935 sigaddset(&blocked_set, SIGINT);
936 sigaddset(&blocked_set, SIGQUIT);
937 sigaddset(&blocked_set, SIGPIPE);
938 sigaddset(&blocked_set, SIGTERM);
939 sa.sa_handler = interrupt;
940#ifdef SUNOS4
941 /* POSIX signals on sunos4.1 are a little broken. */
942 sa.sa_flags = SA_INTERRUPT;
943#endif /* SUNOS4 */
944 }
945 sigaction(SIGHUP, &sa, NULL);
946 sigaction(SIGINT, &sa, NULL);
947 sigaction(SIGQUIT, &sa, NULL);
948 sigaction(SIGPIPE, &sa, NULL);
949 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000950#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000951 sa.sa_handler = reaper;
952 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000953#else
954 /* Make sure SIGCHLD has the default action so that waitpid
955 definitely works without losing track of children. The user
956 should not have given us a bogus state to inherit, but he might
957 have. Arguably we should detect SIG_IGN here and pass it on
958 to children, but probably noone really needs that. */
959 sa.sa_handler = SIG_DFL;
960 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000961#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000962
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000963 if (pflag_seen || daemonized_tracer)
Roland McGrath02203312007-06-11 22:06:31 +0000964 startup_attach();
Roland McGrath02203312007-06-11 22:06:31 +0000965
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000966 if (trace() < 0)
967 exit(1);
968 cleanup();
Dmitry V. Levina6809652008-11-10 17:14:58 +0000969 fflush(NULL);
970 if (exit_code > 0xff) {
971 /* Child was killed by a signal, mimic that. */
972 exit_code &= 0xff;
973 signal(exit_code, SIG_DFL);
974 raise(exit_code);
975 /* Paranoia - what if this signal is not fatal?
976 Exit with 128 + signo then. */
977 exit_code += 128;
978 }
979 exit(exit_code);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000980}
981
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000982void
983expand_tcbtab(void)
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000984{
985 /* Allocate some more TCBs and expand the table.
986 We don't want to relocate the TCBs because our
987 callers have pointers and it would be a pain.
988 So tcbtab is a table of pointers. Since we never
989 free the TCBs, we allocate a single chunk of many. */
990 struct tcb **newtab = (struct tcb **)
991 realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
992 struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
993 sizeof *newtcbs);
994 int i;
995 if (newtab == NULL || newtcbs == NULL) {
Dmitry V. Levin76860f62006-10-11 22:55:25 +0000996 fprintf(stderr, "%s: expand_tcbtab: out of memory\n",
997 progname);
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000998 cleanup();
999 exit(1);
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001000 }
1001 for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
1002 newtab[i] = &newtcbs[i - tcbtabsize];
1003 tcbtabsize *= 2;
1004 tcbtab = newtab;
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001005}
1006
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001007struct tcb *
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001008alloc_tcb(int pid, int command_options_parsed)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001009{
1010 int i;
1011 struct tcb *tcp;
1012
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001013 if (nprocs == tcbtabsize)
1014 expand_tcbtab();
1015
Roland McGrathee9d4352002-12-18 04:16:10 +00001016 for (i = 0; i < tcbtabsize; i++) {
1017 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001018 if ((tcp->flags & TCB_INUSE) == 0) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00001019 memset(tcp, 0, sizeof(*tcp));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001020 tcp->pid = pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001021 tcp->flags = TCB_INUSE | TCB_STARTUP;
1022 tcp->outf = outf; /* Initialise to current out file */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001023 tcp->pfd = -1;
1024 nprocs++;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001025 if (command_options_parsed)
1026 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001027 return tcp;
1028 }
1029 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001030 fprintf(stderr, "%s: bug in alloc_tcb\n", progname);
1031 cleanup();
1032 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001033}
1034
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001035#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001036int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001037proc_open(struct tcb *tcp, int attaching)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001038{
1039 char proc[32];
1040 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001041#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +00001042 int i;
1043 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001044 sigset_t signals;
1045 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001046#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001047#ifndef HAVE_POLLABLE_PROCFS
1048 static int last_pfd;
1049#endif
1050
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001051#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001052 /* Open the process pseudo-files in /proc. */
1053 sprintf(proc, "/proc/%d/ctl", tcp->pid);
1054 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001055 perror("strace: open(\"/proc/...\", ...)");
1056 return -1;
1057 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001058 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001059 return -1;
1060 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001061 sprintf(proc, "/proc/%d/status", tcp->pid);
1062 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
1063 perror("strace: open(\"/proc/...\", ...)");
1064 return -1;
1065 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001066 if (set_cloexec_flag(tcp->pfd_stat) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001067 return -1;
1068 }
1069 sprintf(proc, "/proc/%d/as", tcp->pid);
1070 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
1071 perror("strace: open(\"/proc/...\", ...)");
1072 return -1;
1073 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001074 if (set_cloexec_flag(tcp->pfd_as) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001075 return -1;
1076 }
1077#else
1078 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001079#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001080 sprintf(proc, "/proc/%d", tcp->pid);
1081 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001082#else /* FREEBSD */
1083 sprintf(proc, "/proc/%d/mem", tcp->pid);
1084 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
1085#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001086 perror("strace: open(\"/proc/...\", ...)");
1087 return -1;
1088 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001089 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001090 return -1;
1091 }
1092#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001093#ifdef FREEBSD
1094 sprintf(proc, "/proc/%d/regs", tcp->pid);
1095 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
1096 perror("strace: open(\"/proc/.../regs\", ...)");
1097 return -1;
1098 }
1099 if (cflag) {
1100 sprintf(proc, "/proc/%d/status", tcp->pid);
1101 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
1102 perror("strace: open(\"/proc/.../status\", ...)");
1103 return -1;
1104 }
1105 } else
1106 tcp->pfd_status = -1;
1107#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001108 rebuild_pollv();
1109 if (!attaching) {
1110 /*
1111 * Wait for the child to pause. Because of a race
1112 * condition we have to poll for the event.
1113 */
1114 for (;;) {
1115 if (IOCTL_STATUS (tcp) < 0) {
1116 perror("strace: PIOCSTATUS");
1117 return -1;
1118 }
1119 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001120 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001121 }
1122 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001123#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001124 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001125 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001126 perror("strace: PIOCSTOP");
1127 return -1;
1128 }
Roland McGrath553a6092002-12-16 20:40:39 +00001129#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001130#ifdef PIOCSET
1131 /* Set Run-on-Last-Close. */
1132 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001133 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001134 perror("PIOCSET PR_RLC");
1135 return -1;
1136 }
1137 /* Set or Reset Inherit-on-Fork. */
1138 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001139 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001140 perror("PIOC{SET,RESET} PR_FORK");
1141 return -1;
1142 }
1143#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +00001144#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001145 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
1146 perror("PIOCSRLC");
1147 return -1;
1148 }
1149 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
1150 perror("PIOC{S,R}FORK");
1151 return -1;
1152 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001153#else /* FREEBSD */
1154 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
1155 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
1156 perror("PIOCGFL");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001157 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001158 }
1159 arg &= ~PF_LINGER;
1160 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001161 perror("PIOCSFL");
1162 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001163 }
1164#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001165#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001166#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +00001167 /* Enable all syscall entries we care about. */
1168 premptyset(&syscalls);
1169 for (i = 1; i < MAX_QUALS; ++i) {
1170 if (i > (sizeof syscalls) * CHAR_BIT) break;
1171 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
1172 }
1173 praddset (&syscalls, SYS_execve);
1174 if (followfork) {
1175 praddset (&syscalls, SYS_fork);
1176#ifdef SYS_forkall
1177 praddset (&syscalls, SYS_forkall);
1178#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001179#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +00001180 praddset (&syscalls, SYS_fork1);
1181#endif
1182#ifdef SYS_rfork1
1183 praddset (&syscalls, SYS_rfork1);
1184#endif
1185#ifdef SYS_rforkall
1186 praddset (&syscalls, SYS_rforkall);
1187#endif
1188 }
1189 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001190 perror("PIOCSENTRY");
1191 return -1;
1192 }
John Hughes19e49982001-10-19 08:59:12 +00001193 /* Enable the syscall exits. */
1194 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001195 perror("PIOSEXIT");
1196 return -1;
1197 }
John Hughes19e49982001-10-19 08:59:12 +00001198 /* Enable signals we care about. */
1199 premptyset(&signals);
1200 for (i = 1; i < MAX_QUALS; ++i) {
1201 if (i > (sizeof signals) * CHAR_BIT) break;
1202 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
1203 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001204 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001205 perror("PIOCSTRACE");
1206 return -1;
1207 }
John Hughes19e49982001-10-19 08:59:12 +00001208 /* Enable faults we care about */
1209 premptyset(&faults);
1210 for (i = 1; i < MAX_QUALS; ++i) {
1211 if (i > (sizeof faults) * CHAR_BIT) break;
1212 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
1213 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001214 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001215 perror("PIOCSFAULT");
1216 return -1;
1217 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001218#else /* FREEBSD */
1219 /* set events flags. */
1220 arg = S_SIG | S_SCE | S_SCX ;
1221 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
1222 perror("PIOCBIS");
1223 return -1;
1224 }
1225#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001226 if (!attaching) {
1227#ifdef MIPS
1228 /*
1229 * The SGI PRSABORT doesn't work for pause() so
1230 * we send it a caught signal to wake it up.
1231 */
1232 kill(tcp->pid, SIGINT);
1233#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +00001234#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001235 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001236 arg = PRSABORT;
1237 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001238 perror("PIOCRUN");
1239 return -1;
1240 }
Roland McGrath553a6092002-12-16 20:40:39 +00001241#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001242#endif /* !MIPS*/
1243#ifdef FREEBSD
1244 /* wake up the child if it received the SIGSTOP */
1245 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001246#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001247 for (;;) {
1248 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001249 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001250 perror("PIOCWSTOP");
1251 return -1;
1252 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001253 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001254 tcp->flags &= ~TCB_INSYSCALL;
1255 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001256 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001257 break;
1258 }
1259 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001260#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001261 arg = 0;
1262 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001263#else /* FREEBSD */
1264 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001265#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001266 perror("PIOCRUN");
1267 return -1;
1268 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001269#ifdef FREEBSD
1270 /* handle the case where we "opened" the child before
1271 it did the kill -STOP */
1272 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1273 tcp->status.PR_WHAT == SIGSTOP)
1274 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001275#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001276 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001277#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001278 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001279#else /* FREEBSD */
1280 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001281 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001282 /* We are attaching to an already running process.
1283 * Try to figure out the state of the process in syscalls,
1284 * to handle the first event well.
1285 * This is done by having a look at the "wchan" property of the
1286 * process, which tells where it is stopped (if it is). */
1287 FILE * status;
1288 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001289
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001290 sprintf(proc, "/proc/%d/status", tcp->pid);
1291 status = fopen(proc, "r");
1292 if (status &&
1293 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1294 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1295 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1296 strcmp(wchan, "stopevent")) {
1297 /* The process is asleep in the middle of a syscall.
1298 Fake the syscall entry event */
1299 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1300 tcp->status.PR_WHY = PR_SYSENTRY;
1301 trace_syscall(tcp);
1302 }
1303 if (status)
1304 fclose(status);
1305 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001306 }
1307#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001308#ifndef HAVE_POLLABLE_PROCFS
1309 if (proc_poll_pipe[0] != -1)
1310 proc_poller(tcp->pfd);
1311 else if (nprocs > 1) {
1312 proc_poll_open();
1313 proc_poller(last_pfd);
1314 proc_poller(tcp->pfd);
1315 }
1316 last_pfd = tcp->pfd;
1317#endif /* !HAVE_POLLABLE_PROCFS */
1318 return 0;
1319}
1320
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001321#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001322
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001323struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001324pid2tcb(pid)
1325int pid;
1326{
1327 int i;
1328 struct tcb *tcp;
1329
Roland McGrathee9d4352002-12-18 04:16:10 +00001330 for (i = 0; i < tcbtabsize; i++) {
1331 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001332 if (pid && tcp->pid != pid)
1333 continue;
1334 if (tcp->flags & TCB_INUSE)
1335 return tcp;
1336 }
1337 return NULL;
1338}
1339
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001340#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001341
1342static struct tcb *
1343pfd2tcb(pfd)
1344int pfd;
1345{
1346 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001347
Roland McGrathca16be82003-01-10 19:55:28 +00001348 for (i = 0; i < tcbtabsize; i++) {
1349 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001350 if (tcp->pfd != pfd)
1351 continue;
1352 if (tcp->flags & TCB_INUSE)
1353 return tcp;
1354 }
1355 return NULL;
1356}
1357
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001358#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001359
1360void
1361droptcb(tcp)
1362struct tcb *tcp;
1363{
1364 if (tcp->pid == 0)
1365 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001366#ifdef TCB_CLONE_THREAD
1367 if (tcp->nclone_threads > 0) {
1368 /* There are other threads left in this process, but this
1369 is the one whose PID represents the whole process.
1370 We need to keep this record around as a zombie until
1371 all the threads die. */
1372 tcp->flags |= TCB_EXITING;
1373 return;
1374 }
1375#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001376 nprocs--;
1377 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001378
Roland McGrathe29341c2003-01-10 20:14:20 +00001379 if (tcp->parent != NULL) {
1380 tcp->parent->nchildren--;
1381#ifdef TCB_CLONE_THREAD
1382 if (tcp->flags & TCB_CLONE_DETACHED)
1383 tcp->parent->nclone_detached--;
1384 if (tcp->flags & TCB_CLONE_THREAD)
1385 tcp->parent->nclone_threads--;
1386#endif
Roland McGrath09623452003-05-23 02:27:13 +00001387#ifdef TCB_CLONE_DETACHED
1388 if (!(tcp->flags & TCB_CLONE_DETACHED))
1389#endif
1390 tcp->parent->nzombies++;
Roland McGrath276ceb32007-11-13 08:12:12 +00001391#ifdef LINUX
1392 /* Update `tcp->parent->parent->nchildren' and the other fields
1393 like NCLONE_DETACHED, only for zombie group leader that has
1394 already reported and been short-circuited at the top of this
1395 function. The same condition as at the top of DETACH. */
1396 if ((tcp->flags & TCB_CLONE_THREAD) &&
1397 tcp->parent->nclone_threads == 0 &&
1398 (tcp->parent->flags & TCB_EXITING))
1399 droptcb(tcp->parent);
1400#endif
Roland McGrathe29341c2003-01-10 20:14:20 +00001401 tcp->parent = NULL;
1402 }
1403
1404 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001405 if (tcp->pfd != -1) {
1406 close(tcp->pfd);
1407 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001408#ifdef FREEBSD
1409 if (tcp->pfd_reg != -1) {
1410 close(tcp->pfd_reg);
1411 tcp->pfd_reg = -1;
1412 }
1413 if (tcp->pfd_status != -1) {
1414 close(tcp->pfd_status);
1415 tcp->pfd_status = -1;
1416 }
Roland McGrath553a6092002-12-16 20:40:39 +00001417#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001418#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001419 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001420#endif
1421 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001422
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001423 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001424 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001425
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001426 tcp->outf = 0;
1427}
1428
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001429#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001430
1431static int
1432resume(tcp)
1433struct tcb *tcp;
1434{
1435 if (tcp == NULL)
1436 return -1;
1437
1438 if (!(tcp->flags & TCB_SUSPENDED)) {
1439 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1440 return -1;
1441 }
1442 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001443#ifdef TCB_CLONE_THREAD
1444 if (tcp->flags & TCB_CLONE_THREAD)
1445 tcp->parent->nclone_waiting--;
1446#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001447
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001448 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001449 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001450
1451 if (!qflag)
1452 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1453 return 0;
1454}
1455
Roland McGrath1bfd3102007-08-03 10:02:00 +00001456static int
1457resume_from_tcp (struct tcb *tcp)
1458{
1459 int error = 0;
1460 int resumed = 0;
1461
1462 /* XXX This won't always be quite right (but it never was).
1463 A waiter with argument 0 or < -1 is waiting for any pid in
1464 a particular pgrp, which this child might or might not be
1465 in. The waiter will only wake up if it's argument is -1
1466 or if it's waiting for tcp->pid's pgrp. It makes a
1467 difference to wake up a waiter when there might be more
1468 traced children, because it could get a false ECHILD
1469 error. OTOH, if this was the last child in the pgrp, then
1470 it ought to wake up and get ECHILD. We would have to
1471 search the system for all pid's in the pgrp to be sure.
1472
1473 && (t->waitpid == -1 ||
1474 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1475 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1476 */
1477
1478 if (tcp->parent &&
1479 (tcp->parent->flags & TCB_SUSPENDED) &&
1480 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001481 error = resume(tcp->parent);
Roland McGrath1bfd3102007-08-03 10:02:00 +00001482 ++resumed;
1483 }
1484#ifdef TCB_CLONE_THREAD
1485 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1486 /* Some other threads of our parent are waiting too. */
1487 unsigned int i;
1488
1489 /* Resume all the threads that were waiting for this PID. */
1490 for (i = 0; i < tcbtabsize; i++) {
1491 struct tcb *t = tcbtab[i];
1492 if (t->parent == tcp->parent && t != tcp
1493 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1494 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1495 && t->waitpid == tcp->pid) {
1496 error |= resume (t);
1497 ++resumed;
1498 }
1499 }
1500 if (resumed == 0)
1501 /* Noone was waiting for this PID in particular,
1502 so now we might need to resume some wildcarders. */
1503 for (i = 0; i < tcbtabsize; i++) {
1504 struct tcb *t = tcbtab[i];
1505 if (t->parent == tcp->parent && t != tcp
1506 && ((t->flags
1507 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1508 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1509 && t->waitpid <= 0
1510 ) {
1511 error |= resume (t);
1512 break;
1513 }
1514 }
1515 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001516#endif
Roland McGrath1bfd3102007-08-03 10:02:00 +00001517
1518 return error;
1519}
Roland McGrath1bfd3102007-08-03 10:02:00 +00001520
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001521#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001522
Roland McGrath0a463882007-07-05 18:43:16 +00001523/* detach traced process; continue with sig
1524 Never call DETACH twice on the same process as both unattached and
1525 attached-unstopped processes give the same ESRCH. For unattached process we
1526 would SIGSTOP it and wait for its SIGSTOP notification forever. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001527
1528static int
1529detach(tcp, sig)
1530struct tcb *tcp;
1531int sig;
1532{
1533 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001534#ifdef LINUX
Roland McGrath1bfd3102007-08-03 10:02:00 +00001535 int status, catch_sigstop;
Roland McGratha08a97e2005-08-03 11:23:46 +00001536 struct tcb *zombie = NULL;
1537
1538 /* If the group leader is lingering only because of this other
1539 thread now dying, then detach the leader as well. */
1540 if ((tcp->flags & TCB_CLONE_THREAD) &&
1541 tcp->parent->nclone_threads == 1 &&
1542 (tcp->parent->flags & TCB_EXITING))
1543 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001544#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001545
1546 if (tcp->flags & TCB_BPTSET)
1547 sig = SIGKILL;
1548
1549#ifdef LINUX
1550 /*
1551 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001552 * before detaching. Arghh. We go through hoops
1553 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001554 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001555#if defined(SPARC)
1556#undef PTRACE_DETACH
1557#define PTRACE_DETACH PTRACE_SUNDETACH
1558#endif
Roland McGrath02203312007-06-11 22:06:31 +00001559 /*
1560 * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
1561 * expected SIGSTOP. We must catch exactly one as otherwise the
1562 * detached process would be left stopped (process state T).
1563 */
1564 catch_sigstop = (tcp->flags & TCB_STARTUP);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001565 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1566 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001567 }
1568 else if (errno != ESRCH) {
1569 /* Shouldn't happen. */
1570 perror("detach: ptrace(PTRACE_DETACH, ...)");
1571 }
Roland McGrath134813a2007-06-02 00:07:33 +00001572 else if (my_tgkill((tcp->flags & TCB_CLONE_THREAD ? tcp->parent->pid
1573 : tcp->pid),
1574 tcp->pid, 0) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001575 if (errno != ESRCH)
1576 perror("detach: checking sanity");
1577 }
Roland McGrath02203312007-06-11 22:06:31 +00001578 else if (!catch_sigstop && my_tgkill((tcp->flags & TCB_CLONE_THREAD
1579 ? tcp->parent->pid : tcp->pid),
1580 tcp->pid, SIGSTOP) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001581 if (errno != ESRCH)
1582 perror("detach: stopping child");
1583 }
Roland McGrath02203312007-06-11 22:06:31 +00001584 else
1585 catch_sigstop = 1;
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001586 if (catch_sigstop) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001587 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001588#ifdef __WALL
1589 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1590 if (errno == ECHILD) /* Already gone. */
1591 break;
1592 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001593 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001594 break;
1595 }
1596#endif /* __WALL */
1597 /* No __WALL here. */
1598 if (waitpid(tcp->pid, &status, 0) < 0) {
1599 if (errno != ECHILD) {
1600 perror("detach: waiting");
1601 break;
1602 }
1603#ifdef __WCLONE
1604 /* If no processes, try clones. */
1605 if (wait4(tcp->pid, &status, __WCLONE,
1606 NULL) < 0) {
1607 if (errno != ECHILD)
1608 perror("detach: waiting");
1609 break;
1610 }
1611#endif /* __WCLONE */
1612 }
1613#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001614 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001615#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001616 if (!WIFSTOPPED(status)) {
1617 /* Au revoir, mon ami. */
1618 break;
1619 }
1620 if (WSTOPSIG(status) == SIGSTOP) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001621 ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001622 break;
1623 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001624 error = ptrace_restart(PTRACE_CONT, tcp,
Denys Vlasenko96d5a762008-12-29 19:13:27 +00001625 WSTOPSIG(status) == ptrace_stop_sig ? 0
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001626 : WSTOPSIG(status));
1627 if (error < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001628 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001629 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001630 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001631#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001632
1633#if defined(SUNOS4)
1634 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1635 if (sig && kill(tcp->pid, sig) < 0)
1636 perror("detach: kill");
1637 sig = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001638 error = ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001639#endif /* SUNOS4 */
1640
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001641#ifndef USE_PROCFS
Roland McGrath1bfd3102007-08-03 10:02:00 +00001642 error |= resume_from_tcp (tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001643#endif
1644
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001645 if (!qflag)
1646 fprintf(stderr, "Process %u detached\n", tcp->pid);
1647
1648 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001649
1650#ifdef LINUX
Roland McGrath0a463882007-07-05 18:43:16 +00001651 if (zombie != NULL) {
1652 /* TCP no longer exists therefore you must not detach () it. */
1653 droptcb(zombie);
1654 }
Roland McGratha08a97e2005-08-03 11:23:46 +00001655#endif
1656
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001657 return error;
1658}
1659
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001660#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001661
1662static void
1663reaper(sig)
1664int sig;
1665{
1666 int pid;
1667 int status;
1668
1669 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1670#if 0
1671 struct tcb *tcp;
1672
1673 tcp = pid2tcb(pid);
1674 if (tcp)
1675 droptcb(tcp);
1676#endif
1677 }
1678}
1679
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001680#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001681
1682static void
1683cleanup()
1684{
1685 int i;
1686 struct tcb *tcp;
1687
Roland McGrathee9d4352002-12-18 04:16:10 +00001688 for (i = 0; i < tcbtabsize; i++) {
1689 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001690 if (!(tcp->flags & TCB_INUSE))
1691 continue;
1692 if (debug)
1693 fprintf(stderr,
1694 "cleanup: looking at pid %u\n", tcp->pid);
1695 if (tcp_last &&
1696 (!outfname || followfork < 2 || tcp_last == tcp)) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001697 tprintf(" <unfinished ...>");
1698 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001699 }
1700 if (tcp->flags & TCB_ATTACHED)
1701 detach(tcp, 0);
1702 else {
1703 kill(tcp->pid, SIGCONT);
1704 kill(tcp->pid, SIGTERM);
1705 }
1706 }
1707 if (cflag)
1708 call_summary(outf);
1709}
1710
1711static void
1712interrupt(sig)
1713int sig;
1714{
1715 interrupted = 1;
1716}
1717
1718#ifndef HAVE_STRERROR
1719
Roland McGrath6d2b3492002-12-30 00:51:30 +00001720#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001721extern int sys_nerr;
1722extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001723#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001724
1725const char *
1726strerror(errno)
1727int errno;
1728{
1729 static char buf[64];
1730
1731 if (errno < 1 || errno >= sys_nerr) {
1732 sprintf(buf, "Unknown error %d", errno);
1733 return buf;
1734 }
1735 return sys_errlist[errno];
1736}
1737
1738#endif /* HAVE_STERRROR */
1739
1740#ifndef HAVE_STRSIGNAL
1741
Roland McGrath8f474e02003-01-14 07:53:33 +00001742#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001743extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001744#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001745#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1746extern char *_sys_siglist[];
1747#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001748
1749const char *
1750strsignal(sig)
1751int sig;
1752{
1753 static char buf[64];
1754
1755 if (sig < 1 || sig >= NSIG) {
1756 sprintf(buf, "Unknown signal %d", sig);
1757 return buf;
1758 }
1759#ifdef HAVE__SYS_SIGLIST
1760 return _sys_siglist[sig];
1761#else
1762 return sys_siglist[sig];
1763#endif
1764}
1765
1766#endif /* HAVE_STRSIGNAL */
1767
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001768#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001769
1770static void
1771rebuild_pollv()
1772{
1773 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001774
Roland McGrathee9d4352002-12-18 04:16:10 +00001775 if (pollv != NULL)
1776 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001777 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001778 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001779 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00001780 exit(1);
1781 }
1782
Roland McGrathca16be82003-01-10 19:55:28 +00001783 for (i = j = 0; i < tcbtabsize; i++) {
1784 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001785 if (!(tcp->flags & TCB_INUSE))
1786 continue;
1787 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001788 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001789 j++;
1790 }
1791 if (j != nprocs) {
1792 fprintf(stderr, "strace: proc miscount\n");
1793 exit(1);
1794 }
1795}
1796
1797#ifndef HAVE_POLLABLE_PROCFS
1798
1799static void
1800proc_poll_open()
1801{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001802 int i;
1803
1804 if (pipe(proc_poll_pipe) < 0) {
1805 perror("pipe");
1806 exit(1);
1807 }
1808 for (i = 0; i < 2; i++) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001809 if (set_cloexec_flag(proc_poll_pipe[i]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001810 exit(1);
1811 }
1812 }
1813}
1814
1815static int
1816proc_poll(pollv, nfds, timeout)
1817struct pollfd *pollv;
1818int nfds;
1819int timeout;
1820{
1821 int i;
1822 int n;
1823 struct proc_pollfd pollinfo;
1824
1825 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1826 return n;
1827 if (n != sizeof(struct proc_pollfd)) {
1828 fprintf(stderr, "panic: short read: %d\n", n);
1829 exit(1);
1830 }
1831 for (i = 0; i < nprocs; i++) {
1832 if (pollv[i].fd == pollinfo.fd)
1833 pollv[i].revents = pollinfo.revents;
1834 else
1835 pollv[i].revents = 0;
1836 }
1837 poller_pid = pollinfo.pid;
1838 return 1;
1839}
1840
1841static void
1842wakeup_handler(sig)
1843int sig;
1844{
1845}
1846
1847static void
1848proc_poller(pfd)
1849int pfd;
1850{
1851 struct proc_pollfd pollinfo;
1852 struct sigaction sa;
1853 sigset_t blocked_set, empty_set;
1854 int i;
1855 int n;
1856 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001857#ifdef FREEBSD
1858 struct procfs_status pfs;
1859#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001860
1861 switch (fork()) {
1862 case -1:
1863 perror("fork");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001864 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001865 case 0:
1866 break;
1867 default:
1868 return;
1869 }
1870
1871 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1872 sa.sa_flags = 0;
1873 sigemptyset(&sa.sa_mask);
1874 sigaction(SIGHUP, &sa, NULL);
1875 sigaction(SIGINT, &sa, NULL);
1876 sigaction(SIGQUIT, &sa, NULL);
1877 sigaction(SIGPIPE, &sa, NULL);
1878 sigaction(SIGTERM, &sa, NULL);
1879 sa.sa_handler = wakeup_handler;
1880 sigaction(SIGUSR1, &sa, NULL);
1881 sigemptyset(&blocked_set);
1882 sigaddset(&blocked_set, SIGUSR1);
1883 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1884 sigemptyset(&empty_set);
1885
1886 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1887 perror("getrlimit(RLIMIT_NOFILE, ...)");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001888 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001889 }
1890 n = rl.rlim_cur;
1891 for (i = 0; i < n; i++) {
1892 if (i != pfd && i != proc_poll_pipe[1])
1893 close(i);
1894 }
1895
1896 pollinfo.fd = pfd;
1897 pollinfo.pid = getpid();
1898 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001899#ifndef FREEBSD
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001900 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1901#else
1902 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1903#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001904 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001905 switch (errno) {
1906 case EINTR:
1907 continue;
1908 case EBADF:
1909 pollinfo.revents = POLLERR;
1910 break;
1911 case ENOENT:
1912 pollinfo.revents = POLLHUP;
1913 break;
1914 default:
1915 perror("proc_poller: PIOCWSTOP");
1916 }
1917 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1918 _exit(0);
1919 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001920 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001921 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1922 sigsuspend(&empty_set);
1923 }
1924}
1925
1926#endif /* !HAVE_POLLABLE_PROCFS */
1927
1928static int
1929choose_pfd()
1930{
1931 int i, j;
1932 struct tcb *tcp;
1933
1934 static int last;
1935
1936 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001937 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001938 /*
1939 * The previous process is ready to run again. We'll
1940 * let it do so if it is currently in a syscall. This
1941 * heuristic improves the readability of the trace.
1942 */
1943 tcp = pfd2tcb(pollv[last].fd);
1944 if (tcp && (tcp->flags & TCB_INSYSCALL))
1945 return pollv[last].fd;
1946 }
1947
1948 for (i = 0; i < nprocs; i++) {
1949 /* Let competing children run round robin. */
1950 j = (i + last + 1) % nprocs;
1951 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1952 tcp = pfd2tcb(pollv[j].fd);
1953 if (!tcp) {
1954 fprintf(stderr, "strace: lost proc\n");
1955 exit(1);
1956 }
1957 droptcb(tcp);
1958 return -1;
1959 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001960 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001961 last = j;
1962 return pollv[j].fd;
1963 }
1964 }
1965 fprintf(stderr, "strace: nothing ready\n");
1966 exit(1);
1967}
1968
1969static int
1970trace()
1971{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001972#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001973 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001974#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001975 struct tcb *tcp;
1976 int pfd;
1977 int what;
1978 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001979 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001980
1981 for (;;) {
1982 if (interactive)
1983 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1984
1985 if (nprocs == 0)
1986 break;
1987
1988 switch (nprocs) {
1989 case 1:
1990#ifndef HAVE_POLLABLE_PROCFS
1991 if (proc_poll_pipe[0] == -1) {
1992#endif
1993 tcp = pid2tcb(0);
1994 if (!tcp)
1995 continue;
1996 pfd = tcp->pfd;
1997 if (pfd == -1)
1998 continue;
1999 break;
2000#ifndef HAVE_POLLABLE_PROCFS
2001 }
2002 /* fall through ... */
2003#endif /* !HAVE_POLLABLE_PROCFS */
2004 default:
2005#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002006#ifdef POLL_HACK
2007 /* On some systems (e.g. UnixWare) we get too much ugly
2008 "unfinished..." stuff when multiple proceses are in
2009 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00002010
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002011 if (in_syscall) {
2012 struct pollfd pv;
2013 tcp = in_syscall;
2014 in_syscall = NULL;
2015 pv.fd = tcp->pfd;
2016 pv.events = POLLWANT;
2017 if ((what = poll (&pv, 1, 1)) < 0) {
2018 if (interrupted)
2019 return 0;
2020 continue;
2021 }
2022 else if (what == 1 && pv.revents & POLLWANT) {
2023 goto FOUND;
2024 }
2025 }
2026#endif
2027
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002028 if (poll(pollv, nprocs, INFTIM) < 0) {
2029 if (interrupted)
2030 return 0;
2031 continue;
2032 }
2033#else /* !HAVE_POLLABLE_PROCFS */
2034 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
2035 if (interrupted)
2036 return 0;
2037 continue;
2038 }
2039#endif /* !HAVE_POLLABLE_PROCFS */
2040 pfd = choose_pfd();
2041 if (pfd == -1)
2042 continue;
2043 break;
2044 }
2045
2046 /* Look up `pfd' in our table. */
2047 if ((tcp = pfd2tcb(pfd)) == NULL) {
2048 fprintf(stderr, "unknown pfd: %u\n", pfd);
2049 exit(1);
2050 }
John Hughesb6643082002-05-23 11:02:22 +00002051#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002052 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00002053#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002054 /* Get the status of the process. */
2055 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002056#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002057 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002058#else /* FREEBSD */
2059 /* Thanks to some scheduling mystery, the first poller
2060 sometimes waits for the already processed end of fork
2061 event. Doing a non blocking poll here solves the problem. */
2062 if (proc_poll_pipe[0] != -1)
2063 ioctl_result = IOCTL_STATUS (tcp);
2064 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002065 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00002066#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002067 ioctl_errno = errno;
2068#ifndef HAVE_POLLABLE_PROCFS
2069 if (proc_poll_pipe[0] != -1) {
2070 if (ioctl_result < 0)
2071 kill(poller_pid, SIGKILL);
2072 else
2073 kill(poller_pid, SIGUSR1);
2074 }
2075#endif /* !HAVE_POLLABLE_PROCFS */
2076 }
2077 if (interrupted)
2078 return 0;
2079
2080 if (interactive)
2081 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2082
2083 if (ioctl_result < 0) {
2084 /* Find out what happened if it failed. */
2085 switch (ioctl_errno) {
2086 case EINTR:
2087 case EBADF:
2088 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002089#ifdef FREEBSD
2090 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00002091#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002092 case ENOENT:
2093 droptcb(tcp);
2094 continue;
2095 default:
2096 perror("PIOCWSTOP");
2097 exit(1);
2098 }
2099 }
2100
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002101#ifdef FREEBSD
2102 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2103 /* discard first event for a syscall we never entered */
2104 IOCTL (tcp->pfd, PIOCRUN, 0);
2105 continue;
2106 }
Roland McGrath553a6092002-12-16 20:40:39 +00002107#endif
2108
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002109 /* clear the just started flag */
2110 tcp->flags &= ~TCB_STARTUP;
2111
2112 /* set current output file */
2113 outf = tcp->outf;
2114
2115 if (cflag) {
2116 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002117#ifdef FREEBSD
2118 char buf[1024];
2119 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002120
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002121 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
2122 buf[len] = '\0';
2123 sscanf(buf,
2124 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2125 &stime.tv_sec, &stime.tv_usec);
2126 } else
2127 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002128#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002129 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2130 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002131#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002132 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2133 tcp->stime = stime;
2134 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002135 what = tcp->status.PR_WHAT;
2136 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002137#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002138 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002139 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2140 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002141 if (trace_syscall(tcp) < 0) {
2142 fprintf(stderr, "syscall trouble\n");
2143 exit(1);
2144 }
2145 }
2146 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002147#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002148 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002149#ifdef POLL_HACK
2150 in_syscall = tcp;
2151#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002152 case PR_SYSEXIT:
2153 if (trace_syscall(tcp) < 0) {
2154 fprintf(stderr, "syscall trouble\n");
2155 exit(1);
2156 }
2157 break;
2158 case PR_SIGNALLED:
2159 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
2160 printleader(tcp);
2161 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002162 signame(what), strsignal(what));
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002163 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002164#ifdef PR_INFO
2165 if (tcp->status.PR_INFO.si_signo == what) {
2166 printleader(tcp);
2167 tprintf(" siginfo=");
2168 printsiginfo(&tcp->status.PR_INFO, 1);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002169 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002170 }
2171#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002172 }
2173 break;
2174 case PR_FAULTED:
2175 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
2176 printleader(tcp);
2177 tprintf("=== FAULT %d ===", what);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002178 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002179 }
2180 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002181#ifdef FREEBSD
2182 case 0: /* handle case we polled for nothing */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002183 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00002184#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002185 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002186 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002187 exit(1);
2188 break;
2189 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002190 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002191#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002192 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00002193#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002194 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00002195#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002196 perror("PIOCRUN");
2197 exit(1);
2198 }
2199 }
2200 return 0;
2201}
2202
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002203#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002204
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002205#ifdef TCB_GROUP_EXITING
2206/* Handle an exit detach or death signal that is taking all the
2207 related clone threads with it. This is called in three circumstances:
2208 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
2209 SIG == 0 Continuing TCP will perform an exit_group syscall.
2210 SIG == other Continuing TCP with SIG will kill the process.
2211*/
2212static int
2213handle_group_exit(struct tcb *tcp, int sig)
2214{
2215 /* We need to locate our records of all the clone threads
2216 related to TCP, either its children or siblings. */
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002217 struct tcb *leader = NULL;
2218
2219 if (tcp->flags & TCB_CLONE_THREAD)
2220 leader = tcp->parent;
2221 else if (tcp->nclone_detached > 0)
2222 leader = tcp;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002223
2224 if (sig < 0) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002225 if (leader != NULL && leader != tcp
2226 && !(leader->flags & TCB_GROUP_EXITING)
2227 && !(tcp->flags & TCB_STARTUP)
2228 ) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002229 fprintf(stderr,
2230 "PANIC: handle_group_exit: %d leader %d\n",
2231 tcp->pid, leader ? leader->pid : -1);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002232 }
2233 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath1bfd3102007-08-03 10:02:00 +00002234#ifndef USE_PROCFS
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002235 resume_from_tcp(tcp);
Roland McGrath1bfd3102007-08-03 10:02:00 +00002236#endif
Roland McGrath0a463882007-07-05 18:43:16 +00002237 droptcb(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002238 }
2239 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00002240 /* Mark that we are taking the process down. */
2241 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002242 if (tcp->flags & TCB_ATTACHED) {
Roland McGrathd6a32f12007-07-11 08:35:11 +00002243 detach(tcp, sig);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002244 if (leader != NULL && leader != tcp)
Roland McGrath1bfd3102007-08-03 10:02:00 +00002245 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002246 } else {
2247 if (ptrace_restart(PTRACE_CONT, tcp, sig) < 0) {
2248 cleanup();
2249 return -1;
2250 }
2251 if (leader != NULL) {
Roland McGrath05690952004-10-20 01:00:27 +00002252 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002253 if (leader != tcp)
2254 droptcb(tcp);
2255 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002256 /* The leader will report to us as parent now,
2257 and then we'll get to the SIG==-1 case. */
2258 return 0;
2259 }
2260 }
2261
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002262 return 0;
2263}
2264#endif
2265
Denys Vlasenko215cc272009-01-09 17:22:56 +00002266static struct tcb *
2267collect_stopped_tcbs(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002268{
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002269#ifdef LINUX
2270 static int remembered_pid;
2271 static int remembered_status;
2272#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002273 int pid;
2274 int wait_errno;
2275 int status;
2276 struct tcb *tcp;
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002277 struct tcb *found_tcps;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002278#ifdef LINUX
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002279 struct tcb **nextp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002280 struct rusage ru;
Denys Vlasenko215cc272009-01-09 17:22:56 +00002281 struct rusage* ru_ptr = cflag ? &ru : NULL;
2282 int wnohang = 0;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002283#ifdef __WALL
Denys Vlasenko215cc272009-01-09 17:22:56 +00002284 int wait4_options = __WALL;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002285#endif
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002286
2287 if (remembered_pid > 0) {
2288 pid = remembered_pid;
2289 remembered_pid = 0;
2290 if (debug)
2291 fprintf(stderr, " [remembered wait(%#x) = %u]\n",
2292 remembered_status, pid);
2293 tcp = pid2tcb(pid); /* can't be NULL */
2294 tcp->wait_status = remembered_status;
2295 tcp->next_need_service = NULL;
2296 return tcp;
2297 }
2298 nextp = &found_tcps;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002299#endif /* LINUX */
2300
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002301 found_tcps = NULL;
Denys Vlasenko215cc272009-01-09 17:22:56 +00002302 while (1) {
Denys Vlasenko222713a2009-03-17 14:29:59 +00002303 if (interrupted)
2304 break;
2305 if (interactive)
2306 sigprocmask(SIG_SETMASK, &empty_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002307#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002308#ifdef __WALL
Denys Vlasenko215cc272009-01-09 17:22:56 +00002309 pid = wait4(-1, &status, wait4_options | wnohang, ru_ptr);
Roland McGrath5bc05552002-12-17 04:50:47 +00002310 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002311 /* this kernel does not support __WALL */
2312 wait4_options &= ~__WALL;
2313 errno = 0;
Denys Vlasenko215cc272009-01-09 17:22:56 +00002314 pid = wait4(-1, &status, wait4_options | wnohang, ru_ptr);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002315 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002316 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002317 /* most likely a "cloned" process */
Denys Vlasenko215cc272009-01-09 17:22:56 +00002318 pid = wait4(-1, &status, __WCLONE | wnohang, ru_ptr);
2319 if (pid < 0 && errno != ECHILD) {
2320 fprintf(stderr, "strace: wait4(WCLONE) "
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002321 "failed: %s\n", strerror(errno));
2322 }
2323 }
Denys Vlasenko215cc272009-01-09 17:22:56 +00002324#else /* !__WALL */
2325 pid = wait4(-1, &status, wnohang, ru_ptr);
2326#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002327#endif /* LINUX */
2328#ifdef SUNOS4
2329 pid = wait(&status);
2330#endif /* SUNOS4 */
2331 wait_errno = errno;
2332 if (interactive)
2333 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2334
Denys Vlasenko215cc272009-01-09 17:22:56 +00002335 if (pid == 0 && wnohang) {
2336 /* We had at least one successful
2337 * wait() before. We waited
2338 * with WNOHANG second time.
2339 * Stop collecting more tracees,
2340 * process what we already have.
2341 */
2342 break;
2343 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002344 if (pid == -1) {
Denys Vlasenko2c8a2582009-01-21 19:05:43 +00002345 if (wait_errno == EINTR)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002346 continue;
Denys Vlasenko2c8a2582009-01-21 19:05:43 +00002347 if (wait_errno == ECHILD) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002348 /*
2349 * We would like to verify this case
2350 * but sometimes a race in Solbourne's
2351 * version of SunOS sometimes reports
2352 * ECHILD before sending us SIGCHILD.
2353 */
2354#if 0
Denys Vlasenko2c8a2582009-01-21 19:05:43 +00002355 if (nprocs != 0) {
2356 fprintf(stderr, "strace: proc miscount\n");
2357 exit(1);
2358 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002359#endif
Denys Vlasenko2c8a2582009-01-21 19:05:43 +00002360 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002361 }
Denys Vlasenko2c8a2582009-01-21 19:05:43 +00002362 errno = wait_errno;
2363 perror("strace: wait");
2364 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002365 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002366 if (pid == popen_pid) {
2367 if (WIFEXITED(status) || WIFSIGNALED(status))
2368 popen_pid = -1;
2369 continue;
2370 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002371 if (debug)
2372 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2373
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002374 /* RHEL5 bug workaround.
2375 * It can re-report stopped tasks. Happens on SIGSTOPs here.
2376 * Second (bogus) report has signal# set to 0.
2377 * Stop collecting and process what we have.
2378 */
2379 if (WIFSTOPPED(status) && WSTOPSIG(status) == 0)
2380 break;
2381
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002382 /* Look up `pid' in our table. */
2383 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002384#ifdef LINUX
Roland McGrath41c48222008-07-18 00:25:10 +00002385 if (followfork) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002386 /* This is needed to go with the CLONE_PTRACE
2387 changes in process.c/util.c: we might see
2388 the child's initial trap before we see the
2389 parent return from the clone syscall.
2390 Leave the child suspended until the parent
2391 returns from its system call. Only then
2392 will we have the association of parent and
2393 child so that we know how to do clearbpt
2394 in the child. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +00002395 tcp = alloctcb(pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002396 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002397 if (!qflag)
2398 fprintf(stderr, "\
2399Process %d attached (waiting for parent)\n",
2400 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002401 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002402 else
2403 /* This can happen if a clone call used
2404 CLONE_PTRACE itself. */
Denys Vlasenko215cc272009-01-09 17:22:56 +00002405#endif /* LINUX */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002406 {
2407 fprintf(stderr, "unknown pid: %u\n", pid);
2408 if (WIFSTOPPED(status))
2409 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2410 exit(1);
2411 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002412 }
Denys Vlasenko215cc272009-01-09 17:22:56 +00002413
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002414#ifdef LINUX
Denys Vlasenko84e20af2009-02-10 16:03:20 +00002415 if (cflag) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002416 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2417 tcp->stime = ru.ru_stime;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002418 }
Denys Vlasenko84e20af2009-02-10 16:03:20 +00002419#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002420 if (tcp->flags & TCB_SUSPENDED) {
2421 /*
2422 * Apparently, doing any ptrace() call on a stopped
2423 * process, provokes the kernel to report the process
2424 * status again on a subsequent wait(), even if the
2425 * process has not been actually restarted.
2426 * Since we have inspected the arguments of suspended
2427 * processes we end up here testing for this case.
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002428 *
2429 * We also end up here when we catch new pid of
2430 * CLONE_PTRACEd process. Do not process/restart it
2431 * until we see corresponding clone() syscall exit
2432 * in its parent.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002433 */
2434 continue;
2435 }
Denys Vlasenko215cc272009-01-09 17:22:56 +00002436
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002437#ifdef LINUX
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002438 /* So far observed only on RHEL5 ia64, but I imagine this
2439 * can legitimately happen elsewhere.
2440 * If we waited and got a stopped task notification,
2441 * subsequent wait may return the same pid again, for example,
2442 * with SIGKILL notification. SIGKILL kills even stopped tasks.
2443 * We must not add it to the list
2444 * (one task can't be inserted twice in the list).
2445 */
2446 {
2447 struct tcb *f = found_tcps;
2448 while (f) {
2449 if (f == tcp) {
2450 remembered_pid = pid;
2451 remembered_status = status;
2452 return found_tcps;
2453 }
2454 f = f->next_need_service;
2455 }
2456 }
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002457 /* It is important to not invert the order of tasks
2458 * to process. For one, alloc_tcb() above picks newly forked
2459 * threads in some order, processing of them and their parent
2460 * should be in the same order, otherwise bad things happen
2461 * (misinterpreted SIGSTOPs and such).
2462 */
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002463 tcp->wait_status = status;
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002464 *nextp = tcp;
2465 nextp = &tcp->next_need_service;
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002466 *nextp = NULL;
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002467 wnohang = WNOHANG;
2468#endif
2469#ifdef SUNOS4
2470 /* Probably need to replace wait with waitpid
2471 * and loop on Sun too, but I can't test it. Volunteers?
2472 */
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002473 tcp->wait_status = status;
2474 tcp->next_need_service = NULL;
2475 found_tcps = tcp;
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002476 break;
2477#endif
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002478 } /* while (1) - collecting all stopped/exited tracees */
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002479
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002480 return found_tcps;
2481}
2482
2483static int
2484handle_stopped_tcbs(struct tcb *tcp)
2485{
2486 for (; tcp; tcp = tcp->next_need_service) {
2487 int pid;
2488 int status;
2489
Denys Vlasenko215cc272009-01-09 17:22:56 +00002490 outf = tcp->outf;
2491 status = tcp->wait_status;
2492 pid = tcp->pid;
2493
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002494 if (WIFSIGNALED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002495 if (pid == strace_child)
2496 exit_code = 0x100 | WTERMSIG(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002497 if (!cflag
2498 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2499 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002500 tprintf("+++ killed by %s %s+++",
2501 signame(WTERMSIG(status)),
2502#ifdef WCOREDUMP
2503 WCOREDUMP(status) ? "(core dumped) " :
2504#endif
2505 "");
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002506 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002507 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002508#ifdef TCB_GROUP_EXITING
2509 handle_group_exit(tcp, -1);
2510#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002511 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002512#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002513 continue;
2514 }
2515 if (WIFEXITED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002516 if (pid == strace_child)
2517 exit_code = WEXITSTATUS(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002518 if (debug)
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002519 fprintf(stderr, "pid %u exited with %d\n", pid, WEXITSTATUS(status));
2520 if ((tcp->flags & (TCB_ATTACHED|TCB_STARTUP)) == TCB_ATTACHED
Roland McGrath05690952004-10-20 01:00:27 +00002521#ifdef TCB_GROUP_EXITING
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002522 && !(tcp->parent && (tcp->parent->flags & TCB_GROUP_EXITING))
Roland McGrath1bfd3102007-08-03 10:02:00 +00002523 && !(tcp->flags & TCB_GROUP_EXITING)
Roland McGrath05690952004-10-20 01:00:27 +00002524#endif
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002525 ) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002526 fprintf(stderr,
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002527 "PANIC: attached pid %u exited with %d\n",
2528 pid, WEXITSTATUS(status));
2529 }
Roland McGrath0a396902003-06-10 03:05:53 +00002530 if (tcp == tcp_last) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002531 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT)) == TCB_INSYSCALL)
Roland McGrath0a396902003-06-10 03:05:53 +00002532 tprintf(" <unfinished ... exit status %d>\n",
2533 WEXITSTATUS(status));
2534 tcp_last = NULL;
2535 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002536#ifdef TCB_GROUP_EXITING
2537 handle_group_exit(tcp, -1);
2538#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002539 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002540#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002541 continue;
2542 }
2543 if (!WIFSTOPPED(status)) {
2544 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2545 droptcb(tcp);
2546 continue;
2547 }
2548 if (debug)
2549 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002550 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002551
Roland McGrath02203312007-06-11 22:06:31 +00002552 /*
2553 * Interestingly, the process may stop
2554 * with STOPSIG equal to some other signal
Denys Vlasenko84e20af2009-02-10 16:03:20 +00002555 * than SIGSTOP if we happen to attach
Roland McGrath02203312007-06-11 22:06:31 +00002556 * just before the process takes a signal.
2557 */
2558 if ((tcp->flags & TCB_STARTUP) && WSTOPSIG(status) == SIGSTOP) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002559 /*
2560 * This flag is there to keep us in sync.
2561 * Next time this process stops it should
2562 * really be entering a system call.
2563 */
2564 tcp->flags &= ~TCB_STARTUP;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002565 if (tcp->flags & TCB_BPTSET) {
Roland McGrath02203312007-06-11 22:06:31 +00002566 /*
2567 * One example is a breakpoint inherited from
2568 * parent through fork ().
2569 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002570 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2571 droptcb(tcp);
2572 cleanup();
2573 return -1;
2574 }
2575 }
Denys Vlasenkob1efe532008-12-23 16:14:42 +00002576/* Add more OSes after you verified it works for them. */
Denys Vlasenkof535b542009-01-13 18:30:55 +00002577/* PTRACE_SETOPTIONS may be an enum, not a #define.
2578 * But sometimes we can test for it by checking PT_SETOPTIONS.
2579 */
2580#if defined LINUX && (defined PTRACE_SETOPTIONS || defined PT_SETOPTIONS)
Denys Vlasenko0861ecb2009-01-02 16:55:24 +00002581# ifndef PTRACE_O_TRACESYSGOOD
2582# define PTRACE_O_TRACESYSGOOD 0x00000001
2583# endif
2584# ifndef PTRACE_O_TRACEEXEC
2585# define PTRACE_O_TRACEEXEC 0x00000010
2586# endif
2587# ifndef PTRACE_EVENT_EXEC
2588# define PTRACE_EVENT_EXEC 4
2589# endif
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002590 /*
2591 * Ask kernel to set signo to SIGTRAP | 0x80
2592 * on ptrace-generated SIGTRAPs, and mark
2593 * execve's SIGTRAP with PTRACE_EVENT_EXEC.
2594 */
Denys Vlasenko96d5a762008-12-29 19:13:27 +00002595 if (!ptrace_opts_set) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002596 char *p;
Denys Vlasenko96d5a762008-12-29 19:13:27 +00002597 ptrace_opts_set = 1;
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002598
2599 /* RHEL 2.6.18 definitely has crippling bugs */
2600 /* Vanilla and Fedora 2.6.29 seems to work */
2601 p = utsname_buf.release;
2602 if (strtoul(p, &p, 10) < 2 || *p != '.')
2603 goto tracing;
2604 if (strtoul(++p, &p, 10) < 6 || *p != '.')
2605 goto tracing;
2606 if (strtoul(++p, &p, 10) < 29)
2607 goto tracing;
Denys Vlasenko96d5a762008-12-29 19:13:27 +00002608 /*
2609 * NB: even if this "succeeds", we can
2610 * revert back to SIGTRAP if we later see
2611 * that it didnt really work.
2612 * Old kernels are known to lie here.
2613 */
2614 if (ptrace(PTRACE_SETOPTIONS, pid, (char *) 0,
2615 (void *) (PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC)) == 0)
2616 ptrace_stop_sig = SIGTRAP | 0x80;
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002617 }
2618#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002619 goto tracing;
2620 }
2621
Denys Vlasenkof535b542009-01-13 18:30:55 +00002622#if defined LINUX && (defined PTRACE_SETOPTIONS || defined PT_SETOPTIONS)
Denys Vlasenko96d5a762008-12-29 19:13:27 +00002623 if (ptrace_stop_sig != SIGTRAP && WSTOPSIG(status) == SIGTRAP) {
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002624 /*
2625 * We told ptrace to report SIGTRAP | 0x80 on this process
2626 * but got bare SIGTRAP. This can be a genuine SIGTRAP:
2627 * kill(pid, SIGTRAP), trap insn, etc;
2628 * but be paranoid about it.
2629 */
2630 if (((unsigned)status >> 16) == PTRACE_EVENT_EXEC) {
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00002631 /* It's post-exec ptrace stop. Ignore it,
2632 * we will get syscall exit ptrace stop later.
2633 */
2634#ifdef TCB_WAITEXECVE
2635 tcp->flags &= ~TCB_WAITEXECVE;
2636#endif
2637 goto tracing;
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002638 } else {
2639 /* Take a better look... */
2640 siginfo_t si;
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00002641 si.si_signo = 0;
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002642 ptrace(PTRACE_GETSIGINFO, pid, (void*) 0, (void*) &si);
2643 /*
2644 * Check some fields to make sure we see
2645 * real SIGTRAP.
2646 * Otherwise interpret it as ptrace stop.
2647 * Real SIGTRAPs (int3 insn on x86, kill() etc)
2648 * have these values:
2649 * int3: kill -TRAP $pid:
2650 * si_signo:5 (SIGTRAP) si_signo:5 (SIGTRAP)
2651 * si_errno:0 si_errno:(?)
2652 * si_code:128 (SI_KERNEL) si_code:0 (SI_USER)
2653 * si_pid:0 si_pid:(>0?)
2654 * si_band:0 si_band:(?)
2655 * Ptrace stops have garbage there instead.
2656 */
2657 if (si.si_signo != SIGTRAP
2658 || (si.si_code != SI_KERNEL && si.si_code != SI_USER)
2659 ) {
Denys Vlasenko96d5a762008-12-29 19:13:27 +00002660 fprintf(stderr, "bogus SIGTRAP (si_code:%x), assuming old kernel\n", si.si_code);
2661 ptrace_stop_sig = SIGTRAP;
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002662 }
2663 }
2664 }
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002665#endif
2666
Denys Vlasenko96d5a762008-12-29 19:13:27 +00002667 if (WSTOPSIG(status) != ptrace_stop_sig) {
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002668 /* This isn't a ptrace stop. */
2669
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002670 if (WSTOPSIG(status) == SIGSTOP &&
2671 (tcp->flags & TCB_SIGTRAPPED)) {
2672 /*
2673 * Trapped attempt to block SIGTRAP
2674 * Hope we are back in control now.
2675 */
2676 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002677 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002678 cleanup();
2679 return -1;
2680 }
2681 continue;
2682 }
2683 if (!cflag
2684 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00002685 unsigned long addr = 0;
2686 long pc = 0;
Dmitry V. Levin96339422006-10-11 23:11:43 +00002687#if defined(PT_CR_IPSR) && defined(PT_CR_IIP) && defined(PT_GETSIGINFO)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002688# define PSR_RI 41
2689 struct siginfo si;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002690 long psr;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002691
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002692 upeek(tcp, PT_CR_IPSR, &psr);
2693 upeek(tcp, PT_CR_IIP, &pc);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002694
2695 pc += (psr >> PSR_RI) & 0x3;
2696 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2697 addr = (unsigned long) si.si_addr;
Roland McGrath3a055d72005-03-06 22:24:29 +00002698#elif defined PTRACE_GETSIGINFO
2699 if (WSTOPSIG(status) == SIGSEGV ||
2700 WSTOPSIG(status) == SIGBUS) {
2701 siginfo_t si;
2702 if (ptrace(PTRACE_GETSIGINFO, pid,
2703 0, &si) == 0)
2704 addr = (unsigned long)
2705 si.si_addr;
2706 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002707#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002708 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002709 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002710 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002711 strsignal(WSTOPSIG(status)), pc, addr);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002712 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002713 }
Roland McGrath05690952004-10-20 01:00:27 +00002714 if (((tcp->flags & TCB_ATTACHED) ||
2715 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002716 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002717#ifdef TCB_GROUP_EXITING
2718 handle_group_exit(tcp, WSTOPSIG(status));
2719#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002720 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002721#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002722 continue;
2723 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002724 if (ptrace_restart(PTRACE_SYSCALL, tcp, WSTOPSIG(status)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002725 cleanup();
2726 return -1;
2727 }
2728 tcp->flags &= ~TCB_SUSPENDED;
2729 continue;
2730 }
Roland McGrath02203312007-06-11 22:06:31 +00002731 /* we handled the STATUS, we are permitted to interrupt now. */
2732 if (interrupted)
2733 return 0;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002734 if (trace_syscall(tcp) < 0) {
2735 /* trace_syscall printed incompletely decoded syscall,
2736 * add error indicator.
2737 * NB: modulo bugs, errno must be nonzero, do not add
2738 * "if (err != 0)", this will hide bugs.
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002739 */
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002740 int err = tcp->ptrace_errno;
2741 tcp->ptrace_errno = 0;
2742 if (err == ESRCH)
2743 tprintf(" <unavailable>");
2744 else
2745 tprintf(" <ptrace error %d (%s)>", err, strerror(err));
2746 printtrailer();
2747 if (err == ESRCH)
2748 /* Want to get death report anyway. */
2749 goto tracing;
2750 /* Strange error, we dare not continue. */
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002751 if (tcp->flags & TCB_ATTACHED) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002752 detach(tcp, 0);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002753 } else {
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002754 ptrace(PTRACE_KILL, tcp->pid, (char *) 1, SIGTERM);
2755 /* [why SIGTERM? why not also kill(SIGKILL)?] */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002756 droptcb(tcp);
2757 }
2758 continue;
2759 }
2760 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002761#ifdef TCB_GROUP_EXITING
2762 if (tcp->flags & TCB_GROUP_EXITING) {
2763 if (handle_group_exit(tcp, 0) < 0)
2764 return -1;
2765 continue;
2766 }
2767#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002768 if (tcp->flags & TCB_ATTACHED)
2769 detach(tcp, 0);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002770 else if (ptrace_restart(PTRACE_CONT, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002771 cleanup();
2772 return -1;
2773 }
2774 continue;
2775 }
2776 if (tcp->flags & TCB_SUSPENDED) {
2777 if (!qflag)
2778 fprintf(stderr, "Process %u suspended\n", pid);
2779 continue;
2780 }
2781 tracing:
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002782 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002783 cleanup();
2784 return -1;
2785 }
Denys Vlasenko215cc272009-01-09 17:22:56 +00002786 } /* for each tcp */
2787
2788 return 0;
2789}
2790
2791static int
2792trace()
2793{
2794 int rc;
2795 struct tcb *tcbs;
2796
2797 while (nprocs != 0) {
Denys Vlasenko215cc272009-01-09 17:22:56 +00002798 /* The loop of "wait for one tracee, serve it, repeat"
2799 * may leave some tracees never served.
2800 * Kernel provides no guarantees of fairness when you have
2801 * many waitable tasks.
2802 * Try strace -f with test/many_looping_threads.c example.
2803 * To fix it, we collect *all* waitable tasks, then handle
2804 * them all, then repeat.
2805 */
2806 tcbs = collect_stopped_tcbs();
2807 if (!tcbs)
2808 break;
2809 rc = handle_stopped_tcbs(tcbs);
2810 if (rc)
2811 return rc;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002812 }
2813 return 0;
2814}
2815
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002816#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002817
2818static int curcol;
2819
2820#ifdef __STDC__
2821#include <stdarg.h>
2822#define VA_START(a, b) va_start(a, b)
2823#else
2824#include <varargs.h>
2825#define VA_START(a, b) va_start(a)
2826#endif
2827
2828void
2829#ifdef __STDC__
2830tprintf(const char *fmt, ...)
2831#else
2832tprintf(fmt, va_alist)
2833char *fmt;
2834va_dcl
2835#endif
2836{
2837 va_list args;
2838
2839 VA_START(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002840 if (outf) {
2841 int n = vfprintf(outf, fmt, args);
2842 if (n < 0 && outf != stderr)
2843 perror(outfname == NULL
2844 ? "<writing to pipe>" : outfname);
2845 else
2846 curcol += n;
2847 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002848 va_end(args);
2849 return;
2850}
2851
2852void
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002853printleader(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002854{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002855 if (tcp_last) {
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002856 int err = tcp_last->ptrace_errno;
2857 if (err) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002858 tcp_last->ptrace_errno = 0;
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002859 if (tcp_last->flags & TCB_INSYSCALL) {
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002860 if (err == ESRCH)
2861 tprintf(" <unavailable ...>\n");
2862 else
2863 tprintf(" <ptrace error %d (%s) ...>\n", err, strerror(err));
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002864 tcp_last->flags |= TCB_REPRINT;
2865 } else {
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002866 /* Not sure this branch can ever be reached.
2867 * Oh well. Using subtly different format
2868 * (without "?" after "=") to make it
2869 * noticeable (grep for '= <' in straces).
2870 */
2871 if (err == ESRCH)
2872 tprintf("= <unavailable>\n");
2873 else
2874 tprintf("= <ptrace error %d (%s)>\n", err, strerror(err));
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002875 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002876 } else if (!outfname || followfork < 2 || tcp_last == tcp) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002877 tprintf(" <unfinished ...>\n");
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002878 tcp_last->flags |= TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002879 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002880 }
2881 curcol = 0;
2882 if ((followfork == 1 || pflag_seen > 1) && outfname)
2883 tprintf("%-5d ", tcp->pid);
2884 else if (nprocs > 1 && !outfname)
2885 tprintf("[pid %5u] ", tcp->pid);
2886 if (tflag) {
2887 char str[sizeof("HH:MM:SS")];
2888 struct timeval tv, dtv;
2889 static struct timeval otv;
2890
2891 gettimeofday(&tv, NULL);
2892 if (rflag) {
2893 if (otv.tv_sec == 0)
2894 otv = tv;
2895 tv_sub(&dtv, &tv, &otv);
2896 tprintf("%6ld.%06ld ",
2897 (long) dtv.tv_sec, (long) dtv.tv_usec);
2898 otv = tv;
2899 }
2900 else if (tflag > 2) {
2901 tprintf("%ld.%06ld ",
2902 (long) tv.tv_sec, (long) tv.tv_usec);
2903 }
2904 else {
2905 time_t local = tv.tv_sec;
2906 strftime(str, sizeof(str), "%T", localtime(&local));
2907 if (tflag > 1)
2908 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2909 else
2910 tprintf("%s ", str);
2911 }
2912 }
2913 if (iflag)
2914 printcall(tcp);
2915}
2916
2917void
2918tabto(col)
2919int col;
2920{
2921 if (curcol < col)
2922 tprintf("%*s", col - curcol, "");
2923}
2924
2925void
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002926printtrailer(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002927{
2928 tprintf("\n");
2929 tcp_last = NULL;
2930}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002931
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002932#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002933
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002934int
2935mp_ioctl(int fd, int cmd, void *arg, int size)
2936{
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002937 struct iovec iov[2];
2938 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002939
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002940 iov[0].iov_base = &cmd;
2941 iov[0].iov_len = sizeof cmd;
2942 if (arg) {
2943 ++n;
2944 iov[1].iov_base = arg;
2945 iov[1].iov_len = size;
2946 }
Roland McGrath553a6092002-12-16 20:40:39 +00002947
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002948 return writev(fd, iov, n);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002949}
2950
2951#endif