blob: 3b393719b49f51b16e306815ccea9c5291f5a81c [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>
Denys Vlasenko3454e4b2011-05-23 21:29:03 +020036#include <stdarg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000037#include <signal.h>
38#include <errno.h>
39#include <sys/param.h>
40#include <fcntl.h>
41#include <sys/resource.h>
42#include <sys/wait.h>
43#include <sys/stat.h>
44#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
Denys Vlasenkob63256e2011-06-07 12:13:24 +020053# define my_tgkill(pid, tid, sig) syscall(__NR_tgkill, (pid), (tid), (sig))
Roland McGrath134813a2007-06-02 00:07:33 +000054# elif defined __NR_tkill
Denys Vlasenkob63256e2011-06-07 12:13:24 +020055# define my_tgkill(pid, tid, sig) syscall(__NR_tkill, (tid), (sig))
Roland McGrath134813a2007-06-02 00:07:33 +000056# 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!"
Denys Vlasenkob63256e2011-06-07 12:13:24 +020061# define my_tgkill(pid, tid, sig) kill((tid), (sig))
Roland McGrath134813a2007-06-02 00:07:33 +000062# 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;
Denys Vlasenkof44cce42011-06-21 14:34:10 +020087unsigned int ptrace_setoptions = 0;
Denys Vlasenko3454e4b2011-05-23 21:29:03 +020088/* Which WSTOPSIG(status) value marks syscall traps? */
Denys Vlasenko75422762011-05-27 14:36:01 +020089static unsigned int syscall_trap_sig = SIGTRAP;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +000090int dtime = 0, xflag = 0, qflag = 0;
91cflag_t cflag = CFLAG_NONE;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +000092static int iflag = 0, interactive = 0, pflag_seen = 0, rflag = 0, tflag = 0;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +000093/*
94 * daemonized_tracer supports -D option.
95 * With this option, strace forks twice.
96 * Unlike normal case, with -D *grandparent* process exec's,
97 * becoming a traced process. Child exits (this prevents traced process
98 * from having children it doesn't expect to have), and grandchild
99 * attaches to grandparent similarly to strace -p PID.
100 * This allows for more transparent interaction in cases
101 * when process and its parent are communicating via signals,
102 * wait() etc. Without -D, strace process gets lodged in between,
103 * disrupting parent<->child link.
104 */
105static bool daemonized_tracer = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000106
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000107/* Sometimes we want to print only succeeding syscalls. */
108int not_failing_only = 0;
109
Grant Edwards8a082772011-04-07 20:25:40 +0000110/* Show path associated with fd arguments */
111int show_fd_path = 0;
112
113/* are we filtering traces based on paths? */
114int tracing_paths = 0;
115
Dmitry V. Levina6809652008-11-10 17:14:58 +0000116static int exit_code = 0;
117static int strace_child = 0;
Denys Vlasenko75422762011-05-27 14:36:01 +0200118static int strace_tracer_pid = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700119
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +0000120static char *username = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000121uid_t run_uid;
122gid_t run_gid;
123
124int acolumn = DEFAULT_ACOLUMN;
125int max_strlen = DEFAULT_STRLEN;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +0000126static char *outfname = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000127FILE *outf;
Andreas Schwabccdff482009-10-27 16:27:13 +0100128static int curcol;
Roland McGrathee9d4352002-12-18 04:16:10 +0000129struct tcb **tcbtab;
130unsigned int nprocs, tcbtabsize;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000131const char *progname;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700132extern char **environ;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000133
Andreas Schwabe5355de2009-10-27 16:56:43 +0100134static int detach(struct tcb *tcp, int sig);
135static int trace(void);
136static void cleanup(void);
137static void interrupt(int sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000138static sigset_t empty_set, blocked_set;
139
140#ifdef HAVE_SIG_ATOMIC_T
141static volatile sig_atomic_t interrupted;
142#else /* !HAVE_SIG_ATOMIC_T */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000143static volatile int interrupted;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000144#endif /* !HAVE_SIG_ATOMIC_T */
145
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000146#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000147
Andreas Schwabe5355de2009-10-27 16:56:43 +0100148static struct tcb *pfd2tcb(int pfd);
149static void reaper(int sig);
150static void rebuild_pollv(void);
Roland McGrathee9d4352002-12-18 04:16:10 +0000151static struct pollfd *pollv;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152
153#ifndef HAVE_POLLABLE_PROCFS
154
Andreas Schwabe5355de2009-10-27 16:56:43 +0100155static void proc_poll_open(void);
156static void proc_poller(int pfd);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000157
158struct proc_pollfd {
159 int fd;
160 int revents;
161 int pid;
162};
163
164static int poller_pid;
165static int proc_poll_pipe[2] = { -1, -1 };
166
167#endif /* !HAVE_POLLABLE_PROCFS */
168
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000169#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000170#define POLLWANT POLLWRNORM
171#else
172#define POLLWANT POLLPRI
173#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000174#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000175
176static void
177usage(ofp, exitval)
178FILE *ofp;
179int exitval;
180{
181 fprintf(ofp, "\
Grant Edwards8a082772011-04-07 20:25:40 +0000182usage: strace [-CdDffhiqrtttTvVxxy] [-a column] [-e expr] ... [-o file]\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000183 [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n\
Grant Edwards8a082772011-04-07 20:25:40 +0000184 [-P path] [command [arg ...]]\n\
Andreas Schwabb87d30c2010-06-11 15:49:36 +0200185 or: strace -c [-D] [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000186 [command [arg ...]]\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000187-c -- count time, calls, and errors for each syscall and report summary\n\
Andreas Schwabb87d30c2010-06-11 15:49:36 +0200188-C -- like -c but also print regular output while processes are running\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000189-f -- follow forks, -ff -- with output into separate files\n\
190-F -- attempt to follow vforks, -h -- print help message\n\
191-i -- print instruction pointer at time of syscall\n\
192-q -- suppress messages about attaching, detaching, etc.\n\
193-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
194-T -- print time spent in each syscall, -V -- print version\n\
195-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
196-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
Grant Edwards8a082772011-04-07 20:25:40 +0000197-y -- print paths associated with file descriptor arguments\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000198-a column -- alignment COLUMN for printing syscall results (default %d)\n\
199-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
200 options: trace, abbrev, verbose, raw, signal, read, or write\n\
201-o file -- send trace output to FILE instead of stderr\n\
202-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
203-p pid -- trace process with process id PID, may be repeated\n\
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000204-D -- run tracer process as a detached grandchild, not as parent\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000205-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
206-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
207-u username -- run command as username handling setuid and/or setgid\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000208-E var=val -- put var=val in the environment for command\n\
209-E var -- remove var from the environment for command\n\
Grant Edwards8a082772011-04-07 20:25:40 +0000210-P path -- trace accesses to path\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000211" /* this is broken, so don't document it
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000212-z -- print only succeeding syscalls\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000213 */
214, DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000215 exit(exitval);
216}
217
Denys Vlasenko75422762011-05-27 14:36:01 +0200218static void die(void) __attribute__ ((noreturn));
219static void die(void)
220{
221 if (strace_tracer_pid == getpid()) {
222 cflag = 0;
223 cleanup();
224 }
225 exit(1);
226}
227
228static void verror_msg(int err_no, const char *fmt, va_list p)
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200229{
Dmitry V. Levin44d05322011-06-09 15:50:41 +0000230 fflush(NULL);
231 fprintf(stderr, "%s: ", progname);
232 vfprintf(stderr, fmt, p);
233 if (err_no)
234 fprintf(stderr, ": %s\n", strerror(err_no));
235 else
236 putc('\n', stderr);
237 fflush(stderr);
Denys Vlasenko75422762011-05-27 14:36:01 +0200238}
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200239
Denys Vlasenko75422762011-05-27 14:36:01 +0200240void error_msg(const char *fmt, ...)
241{
242 va_list p;
243 va_start(p, fmt);
244 verror_msg(0, fmt, p);
245 va_end(p);
246}
247
248void error_msg_and_die(const char *fmt, ...)
249{
250 va_list p;
251 va_start(p, fmt);
252 verror_msg(0, fmt, p);
253 die();
254}
255
256void perror_msg(const char *fmt, ...)
257{
258 va_list p;
259 va_start(p, fmt);
260 verror_msg(errno, fmt, p);
261 va_end(p);
262}
263
264void perror_msg_and_die(const char *fmt, ...)
265{
266 va_list p;
267 va_start(p, fmt);
268 verror_msg(errno, fmt, p);
269 die();
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200270}
271
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000272#ifdef SVR4
273#ifdef MIPS
274void
275foobar()
276{
277}
278#endif /* MIPS */
279#endif /* SVR4 */
280
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400281/* Glue for systems without a MMU that cannot provide fork() */
282#ifdef HAVE_FORK
283# define strace_vforked 0
284#else
285# define strace_vforked 1
286# define fork() vfork()
287#endif
288
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000289static int
290set_cloexec_flag(int fd)
291{
292 int flags, newflags;
293
294 if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
295 {
296 fprintf(stderr, "%s: fcntl F_GETFD: %s\n",
297 progname, strerror(errno));
298 return -1;
299 }
300
301 newflags = flags | FD_CLOEXEC;
302 if (flags == newflags)
303 return 0;
304
305 if (fcntl(fd, F_SETFD, newflags) < 0)
306 {
307 fprintf(stderr, "%s: fcntl F_SETFD: %s\n",
308 progname, strerror(errno));
309 return -1;
310 }
311
312 return 0;
313}
314
315/*
316 * When strace is setuid executable, we have to swap uids
317 * before and after filesystem and process management operations.
318 */
319static void
320swap_uid(void)
321{
322#ifndef SVR4
323 int euid = geteuid(), uid = getuid();
324
325 if (euid != uid && setreuid(euid, uid) < 0)
326 {
327 fprintf(stderr, "%s: setreuid: %s\n",
328 progname, strerror(errno));
329 exit(1);
330 }
331#endif
332}
333
Roland McGrath4bfa6262007-07-05 20:03:16 +0000334#if _LFS64_LARGEFILE
335# define fopen_for_output fopen64
336#else
337# define fopen_for_output fopen
338#endif
339
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000340static FILE *
341strace_fopen(const char *path, const char *mode)
342{
343 FILE *fp;
344
345 swap_uid();
Roland McGrath4bfa6262007-07-05 20:03:16 +0000346 if ((fp = fopen_for_output(path, mode)) == NULL)
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000347 fprintf(stderr, "%s: can't fopen '%s': %s\n",
348 progname, path, strerror(errno));
349 swap_uid();
350 if (fp && set_cloexec_flag(fileno(fp)) < 0)
351 {
352 fclose(fp);
353 fp = NULL;
354 }
355 return fp;
356}
357
358static int popen_pid = -1;
359
360#ifndef _PATH_BSHELL
361# define _PATH_BSHELL "/bin/sh"
362#endif
363
364/*
365 * We cannot use standard popen(3) here because we have to distinguish
366 * popen child process from other processes we trace, and standard popen(3)
367 * does not export its child's pid.
368 */
369static FILE *
370strace_popen(const char *command)
371{
372 int fds[2];
373
374 swap_uid();
375 if (pipe(fds) < 0)
376 {
377 fprintf(stderr, "%s: pipe: %s\n",
378 progname, strerror(errno));
379 swap_uid();
380 return NULL;
381 }
382
383 if (set_cloexec_flag(fds[1]) < 0)
384 {
385 close(fds[0]);
386 close(fds[1]);
387 swap_uid();
388 return NULL;
389 }
390
391 if ((popen_pid = fork()) == -1)
392 {
393 fprintf(stderr, "%s: fork: %s\n",
394 progname, strerror(errno));
395 close(fds[0]);
396 close(fds[1]);
397 swap_uid();
398 return NULL;
399 }
400
401 if (popen_pid)
402 {
403 /* parent */
404 close(fds[0]);
405 swap_uid();
406 return fdopen(fds[1], "w");
407 } else
408 {
409 /* child */
410 close(fds[1]);
411 if (fds[0] && (dup2(fds[0], 0) || close(fds[0])))
412 {
413 fprintf(stderr, "%s: dup2: %s\n",
414 progname, strerror(errno));
415 _exit(1);
416 }
417 execl(_PATH_BSHELL, "sh", "-c", command, NULL);
418 fprintf(stderr, "%s: execl: %s: %s\n",
419 progname, _PATH_BSHELL, strerror(errno));
420 _exit(1);
421 }
422}
423
424static int
425newoutf(struct tcb *tcp)
426{
427 if (outfname && followfork > 1) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000428 char name[520 + sizeof(int) * 3];
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000429 FILE *fp;
430
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000431 sprintf(name, "%.512s.%u", outfname, tcp->pid);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000432 if ((fp = strace_fopen(name, "w")) == NULL)
433 return -1;
434 tcp->outf = fp;
435 }
436 return 0;
437}
438
Roland McGrath02203312007-06-11 22:06:31 +0000439static void
440startup_attach(void)
441{
442 int tcbi;
443 struct tcb *tcp;
444
445 /*
446 * Block user interruptions as we would leave the traced
447 * process stopped (process state T) if we would terminate in
448 * between PTRACE_ATTACH and wait4 () on SIGSTOP.
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200449 * We rely on cleanup() from this point on.
Roland McGrath02203312007-06-11 22:06:31 +0000450 */
451 if (interactive)
452 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
453
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000454 if (daemonized_tracer) {
455 pid_t pid = fork();
456 if (pid < 0) {
457 _exit(1);
458 }
459 if (pid) { /* parent */
460 /*
Denys Vlasenko75422762011-05-27 14:36:01 +0200461 * Wait for grandchild to attach to straced process
462 * (grandparent). Grandchild SIGKILLs us after it attached.
463 * Grandparent's wait() is unblocked by our death,
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000464 * it proceeds to exec the straced program.
465 */
466 pause();
467 _exit(0); /* paranoia */
468 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200469 /* grandchild */
470 /* We will be the tracer process. Remember our new pid: */
471 strace_tracer_pid = getpid();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000472 }
473
Roland McGrath02203312007-06-11 22:06:31 +0000474 for (tcbi = 0; tcbi < tcbtabsize; tcbi++) {
475 tcp = tcbtab[tcbi];
476 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
477 continue;
478#ifdef LINUX
479 if (tcp->flags & TCB_CLONE_THREAD)
480 continue;
481#endif
482 /* Reinitialize the output since it may have changed. */
483 tcp->outf = outf;
484 if (newoutf(tcp) < 0)
485 exit(1);
486
487#ifdef USE_PROCFS
488 if (proc_open(tcp, 1) < 0) {
489 fprintf(stderr, "trouble opening proc file\n");
490 droptcb(tcp);
491 continue;
492 }
493#else /* !USE_PROCFS */
494# ifdef LINUX
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000495 if (followfork && !daemonized_tracer) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000496 char procdir[sizeof("/proc/%d/task") + sizeof(int) * 3];
Roland McGrath02203312007-06-11 22:06:31 +0000497 DIR *dir;
498
499 sprintf(procdir, "/proc/%d/task", tcp->pid);
500 dir = opendir(procdir);
501 if (dir != NULL) {
502 unsigned int ntid = 0, nerr = 0;
503 struct dirent *de;
504 int tid;
505 while ((de = readdir(dir)) != NULL) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000506 if (de->d_fileno == 0)
Roland McGrath02203312007-06-11 22:06:31 +0000507 continue;
508 tid = atoi(de->d_name);
509 if (tid <= 0)
510 continue;
511 ++ntid;
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000512 if (ptrace(PTRACE_ATTACH, tid, (char *) 1, 0) < 0)
Roland McGrath02203312007-06-11 22:06:31 +0000513 ++nerr;
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000514 else if (tid != tcbtab[tcbi]->pid) {
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000515 tcp = alloctcb(tid);
Wang Chao21b8db42010-08-27 17:43:16 +0800516 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_FOLLOWFORK;
Roland McGrath02203312007-06-11 22:06:31 +0000517 tcbtab[tcbi]->nclone_threads++;
Roland McGrath02203312007-06-11 22:06:31 +0000518 tcp->parent = tcbtab[tcbi];
519 }
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000520 if (interactive) {
521 sigprocmask(SIG_SETMASK, &empty_set, NULL);
522 if (interrupted)
523 return;
524 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
525 }
Roland McGrath02203312007-06-11 22:06:31 +0000526 }
527 closedir(dir);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000528 ntid -= nerr;
529 if (ntid == 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000530 perror("attach: ptrace(PTRACE_ATTACH, ...)");
531 droptcb(tcp);
532 continue;
533 }
534 if (!qflag) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000535 fprintf(stderr, ntid > 1
536? "Process %u attached with %u threads - interrupt to quit\n"
537: "Process %u attached - interrupt to quit\n",
538 tcbtab[tcbi]->pid, ntid);
Roland McGrath02203312007-06-11 22:06:31 +0000539 }
540 continue;
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000541 } /* if (opendir worked) */
542 } /* if (-f) */
Roland McGrath02203312007-06-11 22:06:31 +0000543# endif
544 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
545 perror("attach: ptrace(PTRACE_ATTACH, ...)");
546 droptcb(tcp);
547 continue;
548 }
549 /* INTERRUPTED is going to be checked at the top of TRACE. */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000550
551 if (daemonized_tracer) {
552 /*
553 * It is our grandparent we trace, not a -p PID.
554 * Don't want to just detach on exit, so...
555 */
556 tcp->flags &= ~TCB_ATTACHED;
557 /*
558 * Make parent go away.
559 * Also makes grandparent's wait() unblock.
560 */
561 kill(getppid(), SIGKILL);
562 }
563
Roland McGrath02203312007-06-11 22:06:31 +0000564#endif /* !USE_PROCFS */
565 if (!qflag)
566 fprintf(stderr,
567 "Process %u attached - interrupt to quit\n",
568 tcp->pid);
569 }
570
571 if (interactive)
572 sigprocmask(SIG_SETMASK, &empty_set, NULL);
573}
574
575static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200576startup_child(char **argv)
Roland McGrath02203312007-06-11 22:06:31 +0000577{
578 struct stat statbuf;
579 const char *filename;
580 char pathname[MAXPATHLEN];
581 int pid = 0;
582 struct tcb *tcp;
583
584 filename = argv[0];
585 if (strchr(filename, '/')) {
586 if (strlen(filename) > sizeof pathname - 1) {
587 errno = ENAMETOOLONG;
588 perror("strace: exec");
589 exit(1);
590 }
591 strcpy(pathname, filename);
592 }
593#ifdef USE_DEBUGGING_EXEC
594 /*
595 * Debuggers customarily check the current directory
596 * first regardless of the path but doing that gives
597 * security geeks a panic attack.
598 */
599 else if (stat(filename, &statbuf) == 0)
600 strcpy(pathname, filename);
601#endif /* USE_DEBUGGING_EXEC */
602 else {
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000603 const char *path;
Roland McGrath02203312007-06-11 22:06:31 +0000604 int m, n, len;
605
606 for (path = getenv("PATH"); path && *path; path += m) {
607 if (strchr(path, ':')) {
608 n = strchr(path, ':') - path;
609 m = n + 1;
610 }
611 else
612 m = n = strlen(path);
613 if (n == 0) {
614 if (!getcwd(pathname, MAXPATHLEN))
615 continue;
616 len = strlen(pathname);
617 }
618 else if (n > sizeof pathname - 1)
619 continue;
620 else {
621 strncpy(pathname, path, n);
622 len = n;
623 }
624 if (len && pathname[len - 1] != '/')
625 pathname[len++] = '/';
626 strcpy(pathname + len, filename);
627 if (stat(pathname, &statbuf) == 0 &&
628 /* Accept only regular files
629 with some execute bits set.
630 XXX not perfect, might still fail */
631 S_ISREG(statbuf.st_mode) &&
632 (statbuf.st_mode & 0111))
633 break;
634 }
635 }
636 if (stat(pathname, &statbuf) < 0) {
637 fprintf(stderr, "%s: %s: command not found\n",
638 progname, filename);
639 exit(1);
640 }
Dmitry V. Levina6809652008-11-10 17:14:58 +0000641 strace_child = pid = fork();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000642 if (pid < 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000643 perror("strace: fork");
644 cleanup();
645 exit(1);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000646 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200647 if ((pid != 0 && daemonized_tracer) /* -D: parent to become a traced process */
648 || (pid == 0 && !daemonized_tracer) /* not -D: child to become a traced process */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000649 ) {
650 pid = getpid();
Roland McGrath02203312007-06-11 22:06:31 +0000651#ifdef USE_PROCFS
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200652 if (outf != stderr) close(fileno(outf));
Roland McGrath02203312007-06-11 22:06:31 +0000653#ifdef MIPS
654 /* Kludge for SGI, see proc_open for details. */
655 sa.sa_handler = foobar;
656 sa.sa_flags = 0;
657 sigemptyset(&sa.sa_mask);
658 sigaction(SIGINT, &sa, NULL);
659#endif /* MIPS */
660#ifndef FREEBSD
661 pause();
662#else /* FREEBSD */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000663 kill(pid, SIGSTOP); /* stop HERE */
Roland McGrath02203312007-06-11 22:06:31 +0000664#endif /* FREEBSD */
665#else /* !USE_PROCFS */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200666 if (outf != stderr)
667 close(fileno(outf));
Roland McGrath02203312007-06-11 22:06:31 +0000668
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000669 if (!daemonized_tracer) {
670 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
671 perror("strace: ptrace(PTRACE_TRACEME, ...)");
672 exit(1);
673 }
674 if (debug)
675 kill(pid, SIGSTOP);
Roland McGrath02203312007-06-11 22:06:31 +0000676 }
Roland McGrath02203312007-06-11 22:06:31 +0000677
678 if (username != NULL || geteuid() == 0) {
679 uid_t run_euid = run_uid;
680 gid_t run_egid = run_gid;
681
682 if (statbuf.st_mode & S_ISUID)
683 run_euid = statbuf.st_uid;
684 if (statbuf.st_mode & S_ISGID)
685 run_egid = statbuf.st_gid;
686
687 /*
688 * It is important to set groups before we
689 * lose privileges on setuid.
690 */
691 if (username != NULL) {
692 if (initgroups(username, run_gid) < 0) {
693 perror("initgroups");
694 exit(1);
695 }
696 if (setregid(run_gid, run_egid) < 0) {
697 perror("setregid");
698 exit(1);
699 }
700 if (setreuid(run_uid, run_euid) < 0) {
701 perror("setreuid");
702 exit(1);
703 }
704 }
705 }
706 else
707 setreuid(run_uid, run_uid);
708
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000709 if (!daemonized_tracer) {
710 /*
711 * Induce an immediate stop so that the parent
712 * will resume us with PTRACE_SYSCALL and display
713 * this execve call normally.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400714 * Unless of course we're on a no-MMU system where
715 * we vfork()-ed, so we cannot stop the child.
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000716 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400717 if (!strace_vforked)
718 kill(getpid(), SIGSTOP);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000719 } else {
720 struct sigaction sv_sigchld;
721 sigaction(SIGCHLD, NULL, &sv_sigchld);
722 /*
723 * Make sure it is not SIG_IGN, otherwise wait
724 * will not block.
725 */
726 signal(SIGCHLD, SIG_DFL);
727 /*
728 * Wait for grandchild to attach to us.
729 * It kills child after that, and wait() unblocks.
730 */
731 alarm(3);
732 wait(NULL);
733 alarm(0);
734 sigaction(SIGCHLD, &sv_sigchld, NULL);
735 }
Roland McGrath02203312007-06-11 22:06:31 +0000736#endif /* !USE_PROCFS */
737
738 execv(pathname, argv);
739 perror("strace: exec");
740 _exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000741 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000742
743 /* We are the tracer. */
Denys Vlasenko75422762011-05-27 14:36:01 +0200744 /* With -D, we are *child* here, IOW: different pid. Fetch it. */
745 strace_tracer_pid = getpid();
746
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000747 tcp = alloctcb(daemonized_tracer ? getppid() : pid);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000748 if (daemonized_tracer) {
749 /* We want subsequent startup_attach() to attach to it. */
750 tcp->flags |= TCB_ATTACHED;
751 }
Roland McGrath02203312007-06-11 22:06:31 +0000752#ifdef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000753 if (proc_open(tcp, 0) < 0) {
754 fprintf(stderr, "trouble opening proc file\n");
755 cleanup();
756 exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000757 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000758#endif /* USE_PROCFS */
Roland McGrath02203312007-06-11 22:06:31 +0000759}
760
Wang Chaob13c0de2010-11-12 17:25:19 +0800761#ifdef LINUX
762/*
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000763 * Test whether the kernel support PTRACE_O_TRACECLONE et al options.
Wang Chaob13c0de2010-11-12 17:25:19 +0800764 * First fork a new child, call ptrace with PTRACE_SETOPTIONS on it,
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000765 * and then see which options are supported by the kernel.
Wang Chaob13c0de2010-11-12 17:25:19 +0800766 */
767static int
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200768test_ptrace_setoptions_followfork(void)
Wang Chaob13c0de2010-11-12 17:25:19 +0800769{
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000770 int pid, expected_grandchild = 0, found_grandchild = 0;
771 const unsigned int test_options = PTRACE_O_TRACECLONE |
772 PTRACE_O_TRACEFORK |
773 PTRACE_O_TRACEVFORK;
Wang Chaob13c0de2010-11-12 17:25:19 +0800774
775 if ((pid = fork()) < 0)
776 return -1;
777 else if (pid == 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000778 if (ptrace(PTRACE_TRACEME, 0, (char *)1, 0) < 0)
Wang Chaob13c0de2010-11-12 17:25:19 +0800779 _exit(1);
Wang Chaob13c0de2010-11-12 17:25:19 +0800780 kill(getpid(), SIGSTOP);
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000781 _exit(fork() < 0);
Wang Chaob13c0de2010-11-12 17:25:19 +0800782 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000783
784 while (1) {
785 int status, tracee_pid;
786
787 tracee_pid = wait(&status);
788 if (tracee_pid == -1) {
789 if (errno == EINTR)
790 continue;
791 else if (errno == ECHILD)
792 break;
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200793 perror("test_ptrace_setoptions_followfork");
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000794 return -1;
795 }
796 if (tracee_pid != pid) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000797 found_grandchild = tracee_pid;
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000798 if (ptrace(PTRACE_CONT, tracee_pid, 0, 0) < 0 &&
799 errno != ESRCH)
800 kill(tracee_pid, SIGKILL);
801 }
802 else if (WIFSTOPPED(status)) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000803 switch (WSTOPSIG(status)) {
804 case SIGSTOP:
805 if (ptrace(PTRACE_SETOPTIONS, pid,
806 NULL, test_options) < 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000807 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800808 return -1;
809 }
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000810 break;
811 case SIGTRAP:
812 if (status >> 16 == PTRACE_EVENT_FORK) {
813 long msg = 0;
814
815 if (ptrace(PTRACE_GETEVENTMSG, pid,
816 NULL, (long) &msg) == 0)
817 expected_grandchild = msg;
818 }
819 break;
Wang Chaob13c0de2010-11-12 17:25:19 +0800820 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000821 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0 &&
822 errno != ESRCH)
823 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800824 }
825 }
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000826 if (expected_grandchild && expected_grandchild == found_grandchild)
Denys Vlasenkof44cce42011-06-21 14:34:10 +0200827 ptrace_setoptions |= test_options;
Wang Chaob13c0de2010-11-12 17:25:19 +0800828 return 0;
829}
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200830
831/*
832 * Test whether the kernel support PTRACE_O_TRACESYSGOOD.
833 * First fork a new child, call ptrace(PTRACE_SETOPTIONS) on it,
834 * and then see whether it will stop with (SIGTRAP | 0x80).
835 *
836 * Use of this option enables correct handling of user-generated SIGTRAPs,
837 * and SIGTRAPs generated by special instructions such as int3 on x86:
838 * _start: .globl _start
839 * int3
840 * movl $42, %ebx
841 * movl $1, %eax
842 * int $0x80
843 * (compile with: "gcc -nostartfiles -nostdlib -o int3 int3.S")
844 */
845static void
846test_ptrace_setoptions_for_all(void)
847{
848 const unsigned int test_options = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC;
849 int pid;
850 int it_worked = 0;
851
852 pid = fork();
853 if (pid < 0)
Denys Vlasenko75422762011-05-27 14:36:01 +0200854 perror_msg_and_die("fork");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200855
856 if (pid == 0) {
857 pid = getpid();
858 if (ptrace(PTRACE_TRACEME, 0L, 0L, 0L) < 0)
Denys Vlasenko75422762011-05-27 14:36:01 +0200859 /* Note: exits with exitcode 1 */
860 perror_msg_and_die("%s: PTRACE_TRACEME doesn't work", __func__);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200861 kill(pid, SIGSTOP);
862 _exit(0); /* parent should see entry into this syscall */
863 }
864
865 while (1) {
866 int status, tracee_pid;
867
868 errno = 0;
869 tracee_pid = wait(&status);
870 if (tracee_pid <= 0) {
871 if (errno == EINTR)
872 continue;
873 kill(pid, SIGKILL);
Denys Vlasenko75422762011-05-27 14:36:01 +0200874 perror_msg_and_die("%s: unexpected wait result %d", __func__, tracee_pid);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200875 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200876 if (WIFEXITED(status)) {
877 if (WEXITSTATUS(status) == 0)
878 break;
879 /* PTRACE_TRACEME failed in child. This is fatal. */
880 exit(1);
881 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200882 if (!WIFSTOPPED(status)) {
883 kill(pid, SIGKILL);
884 error_msg_and_die("%s: unexpected wait status %x", __func__, status);
885 }
886 if (WSTOPSIG(status) == SIGSTOP) {
887 /*
888 * We don't check "options aren't accepted" error.
889 * If it happens, we'll never get (SIGTRAP | 0x80),
890 * and thus will decide to not use the option.
891 * IOW: the outcome of the test will be correct.
892 */
Denys Vlasenko75422762011-05-27 14:36:01 +0200893 if (ptrace(PTRACE_SETOPTIONS, pid, 0L, test_options) < 0)
894 if (errno != EINVAL)
895 perror_msg("PTRACE_SETOPTIONS");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200896 }
897 if (WSTOPSIG(status) == (SIGTRAP | 0x80)) {
898 it_worked = 1;
899 }
900 if (ptrace(PTRACE_SYSCALL, pid, 0L, 0L) < 0) {
901 kill(pid, SIGKILL);
Denys Vlasenko75422762011-05-27 14:36:01 +0200902 perror_msg_and_die("PTRACE_SYSCALL doesn't work");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200903 }
904 }
905
906 if (it_worked) {
Denys Vlasenko75422762011-05-27 14:36:01 +0200907 syscall_trap_sig = (SIGTRAP | 0x80);
Denys Vlasenkof44cce42011-06-21 14:34:10 +0200908 ptrace_setoptions |= test_options;
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200909 if (debug)
Denys Vlasenkof44cce42011-06-21 14:34:10 +0200910 fprintf(stderr, "ptrace_setoptions = %#x\n",
911 ptrace_setoptions);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200912 return;
913 }
914
915 fprintf(stderr,
916 "Test for PTRACE_O_TRACESYSGOOD failed, giving up using this feature.\n");
917}
Wang Chaob13c0de2010-11-12 17:25:19 +0800918#endif
919
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000920int
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000921main(int argc, char *argv[])
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000922{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000923 struct tcb *tcp;
924 int c, pid = 0;
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000925 int optF = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000926 struct sigaction sa;
927
928 static char buf[BUFSIZ];
929
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000930 progname = argv[0] ? argv[0] : "strace";
931
Denys Vlasenko75422762011-05-27 14:36:01 +0200932 strace_tracer_pid = getpid();
933
Roland McGrathee9d4352002-12-18 04:16:10 +0000934 /* Allocate the initial tcbtab. */
935 tcbtabsize = argc; /* Surely enough for all -p args. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000936 if ((tcbtab = calloc(tcbtabsize, sizeof tcbtab[0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000937 fprintf(stderr, "%s: out of memory\n", progname);
938 exit(1);
939 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000940 if ((tcbtab[0] = calloc(tcbtabsize, sizeof tcbtab[0][0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000941 fprintf(stderr, "%s: out of memory\n", progname);
942 exit(1);
943 }
Roland McGrathee9d4352002-12-18 04:16:10 +0000944 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
945 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
946
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000947 outf = stderr;
948 interactive = 1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000949 set_sortby(DEFAULT_SORTBY);
950 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000951 qualify("trace=all");
952 qualify("abbrev=all");
953 qualify("verbose=all");
954 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000955 while ((c = getopt(argc, argv,
Grant Edwards8a082772011-04-07 20:25:40 +0000956 "+cCdfFhiqrtTvVxyz"
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000957#ifndef USE_PROCFS
958 "D"
959#endif
Grant Edwards8a082772011-04-07 20:25:40 +0000960 "a:e:o:O:p:s:S:u:E:P:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000961 switch (c) {
962 case 'c':
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000963 if (cflag == CFLAG_BOTH) {
964 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
965 progname);
966 exit(1);
967 }
968 cflag = CFLAG_ONLY_STATS;
969 break;
970 case 'C':
971 if (cflag == CFLAG_ONLY_STATS) {
972 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
973 progname);
974 exit(1);
975 }
976 cflag = CFLAG_BOTH;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000977 break;
978 case 'd':
979 debug++;
980 break;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000981#ifndef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000982 case 'D':
983 daemonized_tracer = 1;
984 break;
985#endif
Roland McGrath41c48222008-07-18 00:25:10 +0000986 case 'F':
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000987 optF = 1;
988 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000989 case 'f':
990 followfork++;
991 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000992 case 'h':
993 usage(stdout, 0);
994 break;
995 case 'i':
996 iflag++;
997 break;
998 case 'q':
999 qflag++;
1000 break;
1001 case 'r':
1002 rflag++;
1003 tflag++;
1004 break;
1005 case 't':
1006 tflag++;
1007 break;
1008 case 'T':
1009 dtime++;
1010 break;
1011 case 'x':
1012 xflag++;
1013 break;
Grant Edwards8a082772011-04-07 20:25:40 +00001014 case 'y':
1015 show_fd_path = 1;
1016 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001017 case 'v':
1018 qualify("abbrev=none");
1019 break;
1020 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +00001021 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001022 exit(0);
1023 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +00001024 case 'z':
1025 not_failing_only = 1;
1026 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001027 case 'a':
1028 acolumn = atoi(optarg);
1029 break;
1030 case 'e':
1031 qualify(optarg);
1032 break;
1033 case 'o':
1034 outfname = strdup(optarg);
1035 break;
1036 case 'O':
1037 set_overhead(atoi(optarg));
1038 break;
1039 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +00001040 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001041 fprintf(stderr, "%s: Invalid process id: %s\n",
1042 progname, optarg);
1043 break;
1044 }
Denys Vlasenko75422762011-05-27 14:36:01 +02001045 if (pid == strace_tracer_pid) {
Wichert Akkerman54a47671999-10-17 00:57:34 +00001046 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001047 break;
1048 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001049 tcp = alloc_tcb(pid, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001050 tcp->flags |= TCB_ATTACHED;
1051 pflag_seen++;
1052 break;
Grant Edwards8a082772011-04-07 20:25:40 +00001053 case 'P':
1054 tracing_paths = 1;
1055 if (pathtrace_select(optarg)) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001056 fprintf(stderr, "%s : failed to select path '%s'\n", progname, optarg);
Grant Edwards8a082772011-04-07 20:25:40 +00001057 exit(1);
1058 }
1059 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001060 case 's':
1061 max_strlen = atoi(optarg);
Roland McGrathdccec722005-05-09 07:45:47 +00001062 if (max_strlen < 0) {
1063 fprintf(stderr,
1064 "%s: invalid -s argument: %s\n",
1065 progname, optarg);
1066 exit(1);
1067 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001068 break;
1069 case 'S':
1070 set_sortby(optarg);
1071 break;
1072 case 'u':
1073 username = strdup(optarg);
1074 break;
Roland McGrathde6e5332003-01-24 04:31:23 +00001075 case 'E':
1076 if (putenv(optarg) < 0) {
1077 fprintf(stderr, "%s: out of memory\n",
1078 progname);
1079 exit(1);
1080 }
1081 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001082 default:
1083 usage(stderr, 1);
1084 break;
1085 }
1086 }
1087
Roland McGrathd0c4c0c2006-04-25 07:39:40 +00001088 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +00001089 usage(stderr, 1);
1090
Wang Chaod322a4b2010-08-05 14:30:11 +08001091 if (pflag_seen && daemonized_tracer) {
1092 fprintf(stderr,
1093 "%s: -D and -p are mutually exclusive options\n",
1094 progname);
1095 exit(1);
1096 }
1097
Dmitry V. Levin06350db2008-07-25 15:42:34 +00001098 if (!followfork)
1099 followfork = optF;
1100
Roland McGrathcb9def62006-04-25 07:48:03 +00001101 if (followfork > 1 && cflag) {
1102 fprintf(stderr,
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00001103 "%s: (-c or -C) and -ff are mutually exclusive options\n",
Roland McGrathcb9def62006-04-25 07:48:03 +00001104 progname);
1105 exit(1);
1106 }
1107
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001108 /* See if they want to run as another user. */
1109 if (username != NULL) {
1110 struct passwd *pent;
1111
1112 if (getuid() != 0 || geteuid() != 0) {
1113 fprintf(stderr,
1114 "%s: you must be root to use the -u option\n",
1115 progname);
1116 exit(1);
1117 }
1118 if ((pent = getpwnam(username)) == NULL) {
1119 fprintf(stderr, "%s: cannot find user `%s'\n",
Roland McGrath09553f82007-07-05 19:31:49 +00001120 progname, username);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001121 exit(1);
1122 }
1123 run_uid = pent->pw_uid;
1124 run_gid = pent->pw_gid;
1125 }
1126 else {
1127 run_uid = getuid();
1128 run_gid = getgid();
1129 }
1130
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001131#ifdef LINUX
1132 if (followfork) {
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02001133 if (test_ptrace_setoptions_followfork() < 0) {
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001134 fprintf(stderr,
1135 "Test for options supported by PTRACE_SETOPTIONS "
1136 "failed, giving up using this feature.\n");
Denys Vlasenkof44cce42011-06-21 14:34:10 +02001137 ptrace_setoptions = 0;
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001138 }
1139 if (debug)
Denys Vlasenkof44cce42011-06-21 14:34:10 +02001140 fprintf(stderr, "ptrace_setoptions = %#x\n",
1141 ptrace_setoptions);
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001142 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02001143 test_ptrace_setoptions_for_all();
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001144#endif
1145
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001146 /* Check if they want to redirect the output. */
1147 if (outfname) {
Roland McGrath37b9a662003-11-07 02:26:54 +00001148 /* See if they want to pipe the output. */
1149 if (outfname[0] == '|' || outfname[0] == '!') {
1150 /*
1151 * We can't do the <outfname>.PID funny business
1152 * when using popen, so prohibit it.
1153 */
1154 if (followfork > 1) {
1155 fprintf(stderr, "\
1156%s: piping the output and -ff are mutually exclusive options\n",
1157 progname);
1158 exit(1);
1159 }
1160
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001161 if ((outf = strace_popen(outfname + 1)) == NULL)
Roland McGrath37b9a662003-11-07 02:26:54 +00001162 exit(1);
Roland McGrath37b9a662003-11-07 02:26:54 +00001163 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001164 else if (followfork <= 1 &&
1165 (outf = strace_fopen(outfname, "w")) == NULL)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001166 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001167 }
1168
Roland McGrath37b9a662003-11-07 02:26:54 +00001169 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001170 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +00001171 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001172 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001173 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +00001174 }
Wang Chaob13c0de2010-11-12 17:25:19 +08001175
Roland McGrath54cc1c82007-11-03 23:34:11 +00001176 /* Valid states here:
1177 optind < argc pflag_seen outfname interactive
1178 1 0 0 1
1179 0 1 0 1
1180 1 0 1 0
1181 0 1 1 1
1182 */
1183
1184 /* STARTUP_CHILD must be called before the signal handlers get
1185 installed below as they are inherited into the spawned process.
1186 Also we do not need to be protected by them as during interruption
1187 in the STARTUP_CHILD mode we kill the spawned process anyway. */
1188 if (!pflag_seen)
1189 startup_child(&argv[optind]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001190
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001191 sigemptyset(&empty_set);
1192 sigemptyset(&blocked_set);
1193 sa.sa_handler = SIG_IGN;
1194 sigemptyset(&sa.sa_mask);
1195 sa.sa_flags = 0;
1196 sigaction(SIGTTOU, &sa, NULL);
1197 sigaction(SIGTTIN, &sa, NULL);
1198 if (interactive) {
1199 sigaddset(&blocked_set, SIGHUP);
1200 sigaddset(&blocked_set, SIGINT);
1201 sigaddset(&blocked_set, SIGQUIT);
1202 sigaddset(&blocked_set, SIGPIPE);
1203 sigaddset(&blocked_set, SIGTERM);
1204 sa.sa_handler = interrupt;
1205#ifdef SUNOS4
1206 /* POSIX signals on sunos4.1 are a little broken. */
1207 sa.sa_flags = SA_INTERRUPT;
1208#endif /* SUNOS4 */
1209 }
1210 sigaction(SIGHUP, &sa, NULL);
1211 sigaction(SIGINT, &sa, NULL);
1212 sigaction(SIGQUIT, &sa, NULL);
1213 sigaction(SIGPIPE, &sa, NULL);
1214 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001215#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001216 sa.sa_handler = reaper;
1217 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +00001218#else
1219 /* Make sure SIGCHLD has the default action so that waitpid
1220 definitely works without losing track of children. The user
1221 should not have given us a bogus state to inherit, but he might
1222 have. Arguably we should detect SIG_IGN here and pass it on
1223 to children, but probably noone really needs that. */
1224 sa.sa_handler = SIG_DFL;
1225 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001226#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001227
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +00001228 if (pflag_seen || daemonized_tracer)
Roland McGrath02203312007-06-11 22:06:31 +00001229 startup_attach();
Roland McGrath02203312007-06-11 22:06:31 +00001230
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001231 if (trace() < 0)
1232 exit(1);
1233 cleanup();
Dmitry V. Levina6809652008-11-10 17:14:58 +00001234 fflush(NULL);
1235 if (exit_code > 0xff) {
1236 /* Child was killed by a signal, mimic that. */
1237 exit_code &= 0xff;
1238 signal(exit_code, SIG_DFL);
1239 raise(exit_code);
1240 /* Paranoia - what if this signal is not fatal?
1241 Exit with 128 + signo then. */
1242 exit_code += 128;
1243 }
1244 exit(exit_code);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001245}
1246
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001247void
1248expand_tcbtab(void)
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001249{
1250 /* Allocate some more TCBs and expand the table.
1251 We don't want to relocate the TCBs because our
1252 callers have pointers and it would be a pain.
1253 So tcbtab is a table of pointers. Since we never
1254 free the TCBs, we allocate a single chunk of many. */
Denys Vlasenko18da2732011-06-22 12:41:57 +02001255 int i = tcbtabsize;
1256 struct tcb *newtcbs = calloc(tcbtabsize, sizeof(newtcbs[0]));
1257 struct tcb **newtab = realloc(tcbtab, tcbtabsize * 2 * sizeof(tcbtab[0]));
1258 if (newtab == NULL || newtcbs == NULL)
1259 error_msg_and_die("expand_tcbtab: out of memory");
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001260 tcbtabsize *= 2;
1261 tcbtab = newtab;
Denys Vlasenko18da2732011-06-22 12:41:57 +02001262 while (i < tcbtabsize)
1263 tcbtab[i++] = newtcbs++;
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001264}
1265
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001266struct tcb *
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001267alloc_tcb(int pid, int command_options_parsed)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001268{
1269 int i;
1270 struct tcb *tcp;
1271
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001272 if (nprocs == tcbtabsize)
1273 expand_tcbtab();
1274
Roland McGrathee9d4352002-12-18 04:16:10 +00001275 for (i = 0; i < tcbtabsize; i++) {
1276 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001277 if ((tcp->flags & TCB_INUSE) == 0) {
Denys Vlasenko18da2732011-06-22 12:41:57 +02001278 memset(tcp, 0, sizeof(*tcp));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001279 tcp->pid = pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001280 tcp->flags = TCB_INUSE | TCB_STARTUP;
1281 tcp->outf = outf; /* Initialise to current out file */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001282 tcp->pfd = -1;
1283 nprocs++;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001284 if (command_options_parsed)
1285 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001286 return tcp;
1287 }
1288 }
Denys Vlasenko18da2732011-06-22 12:41:57 +02001289 error_msg_and_die("bug in alloc_tcb");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001290}
1291
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001292#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001293int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001294proc_open(struct tcb *tcp, int attaching)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001295{
1296 char proc[32];
1297 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001298#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +00001299 int i;
1300 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001301 sigset_t signals;
1302 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001303#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001304#ifndef HAVE_POLLABLE_PROCFS
1305 static int last_pfd;
1306#endif
1307
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001308#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001309 /* Open the process pseudo-files in /proc. */
1310 sprintf(proc, "/proc/%d/ctl", tcp->pid);
1311 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001312 perror("strace: open(\"/proc/...\", ...)");
1313 return -1;
1314 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001315 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001316 return -1;
1317 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001318 sprintf(proc, "/proc/%d/status", tcp->pid);
1319 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
1320 perror("strace: open(\"/proc/...\", ...)");
1321 return -1;
1322 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001323 if (set_cloexec_flag(tcp->pfd_stat) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001324 return -1;
1325 }
1326 sprintf(proc, "/proc/%d/as", tcp->pid);
1327 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
1328 perror("strace: open(\"/proc/...\", ...)");
1329 return -1;
1330 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001331 if (set_cloexec_flag(tcp->pfd_as) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001332 return -1;
1333 }
1334#else
1335 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001336#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001337 sprintf(proc, "/proc/%d", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001338 tcp->pfd = open(proc, O_RDWR|O_EXCL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001339#else /* FREEBSD */
1340 sprintf(proc, "/proc/%d/mem", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001341 tcp->pfd = open(proc, O_RDWR);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001342#endif /* FREEBSD */
Andreas Schwab372cc842010-07-09 11:49:27 +02001343 if (tcp->pfd < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001344 perror("strace: open(\"/proc/...\", ...)");
1345 return -1;
1346 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001347 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001348 return -1;
1349 }
1350#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001351#ifdef FREEBSD
1352 sprintf(proc, "/proc/%d/regs", tcp->pid);
1353 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
1354 perror("strace: open(\"/proc/.../regs\", ...)");
1355 return -1;
1356 }
1357 if (cflag) {
1358 sprintf(proc, "/proc/%d/status", tcp->pid);
1359 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
1360 perror("strace: open(\"/proc/.../status\", ...)");
1361 return -1;
1362 }
1363 } else
1364 tcp->pfd_status = -1;
1365#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001366 rebuild_pollv();
1367 if (!attaching) {
1368 /*
1369 * Wait for the child to pause. Because of a race
1370 * condition we have to poll for the event.
1371 */
1372 for (;;) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001373 if (IOCTL_STATUS(tcp) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001374 perror("strace: PIOCSTATUS");
1375 return -1;
1376 }
1377 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001378 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001379 }
1380 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001381#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001382 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001383 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001384 perror("strace: PIOCSTOP");
1385 return -1;
1386 }
Roland McGrath553a6092002-12-16 20:40:39 +00001387#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001388#ifdef PIOCSET
1389 /* Set Run-on-Last-Close. */
1390 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001391 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001392 perror("PIOCSET PR_RLC");
1393 return -1;
1394 }
1395 /* Set or Reset Inherit-on-Fork. */
1396 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001397 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001398 perror("PIOC{SET,RESET} PR_FORK");
1399 return -1;
1400 }
1401#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +00001402#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001403 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
1404 perror("PIOCSRLC");
1405 return -1;
1406 }
1407 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
1408 perror("PIOC{S,R}FORK");
1409 return -1;
1410 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001411#else /* FREEBSD */
1412 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
1413 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
1414 perror("PIOCGFL");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001415 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001416 }
1417 arg &= ~PF_LINGER;
1418 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001419 perror("PIOCSFL");
1420 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001421 }
1422#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001423#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001424#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +00001425 /* Enable all syscall entries we care about. */
1426 premptyset(&syscalls);
1427 for (i = 1; i < MAX_QUALS; ++i) {
1428 if (i > (sizeof syscalls) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001429 if (qual_flags[i] & QUAL_TRACE) praddset(&syscalls, i);
John Hughes19e49982001-10-19 08:59:12 +00001430 }
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001431 praddset(&syscalls, SYS_execve);
John Hughes19e49982001-10-19 08:59:12 +00001432 if (followfork) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001433 praddset(&syscalls, SYS_fork);
John Hughes19e49982001-10-19 08:59:12 +00001434#ifdef SYS_forkall
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001435 praddset(&syscalls, SYS_forkall);
John Hughes19e49982001-10-19 08:59:12 +00001436#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001437#ifdef SYS_fork1
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001438 praddset(&syscalls, SYS_fork1);
John Hughes19e49982001-10-19 08:59:12 +00001439#endif
1440#ifdef SYS_rfork1
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001441 praddset(&syscalls, SYS_rfork1);
John Hughes19e49982001-10-19 08:59:12 +00001442#endif
1443#ifdef SYS_rforkall
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001444 praddset(&syscalls, SYS_rforkall);
John Hughes19e49982001-10-19 08:59:12 +00001445#endif
1446 }
1447 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001448 perror("PIOCSENTRY");
1449 return -1;
1450 }
John Hughes19e49982001-10-19 08:59:12 +00001451 /* Enable the syscall exits. */
1452 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001453 perror("PIOSEXIT");
1454 return -1;
1455 }
John Hughes19e49982001-10-19 08:59:12 +00001456 /* Enable signals we care about. */
1457 premptyset(&signals);
1458 for (i = 1; i < MAX_QUALS; ++i) {
1459 if (i > (sizeof signals) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001460 if (qual_flags[i] & QUAL_SIGNAL) praddset(&signals, i);
John Hughes19e49982001-10-19 08:59:12 +00001461 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001462 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001463 perror("PIOCSTRACE");
1464 return -1;
1465 }
John Hughes19e49982001-10-19 08:59:12 +00001466 /* Enable faults we care about */
1467 premptyset(&faults);
1468 for (i = 1; i < MAX_QUALS; ++i) {
1469 if (i > (sizeof faults) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001470 if (qual_flags[i] & QUAL_FAULT) praddset(&faults, i);
John Hughes19e49982001-10-19 08:59:12 +00001471 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001472 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001473 perror("PIOCSFAULT");
1474 return -1;
1475 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001476#else /* FREEBSD */
1477 /* set events flags. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001478 arg = S_SIG | S_SCE | S_SCX;
1479 if (ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001480 perror("PIOCBIS");
1481 return -1;
1482 }
1483#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001484 if (!attaching) {
1485#ifdef MIPS
1486 /*
1487 * The SGI PRSABORT doesn't work for pause() so
1488 * we send it a caught signal to wake it up.
1489 */
1490 kill(tcp->pid, SIGINT);
1491#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +00001492#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001493 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001494 arg = PRSABORT;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001495 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001496 perror("PIOCRUN");
1497 return -1;
1498 }
Roland McGrath553a6092002-12-16 20:40:39 +00001499#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001500#endif /* !MIPS*/
1501#ifdef FREEBSD
1502 /* wake up the child if it received the SIGSTOP */
1503 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001504#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001505 for (;;) {
1506 /* Wait for the child to do something. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001507 if (IOCTL_WSTOP(tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001508 perror("PIOCWSTOP");
1509 return -1;
1510 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001511 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001512 tcp->flags &= ~TCB_INSYSCALL;
1513 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001514 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001515 break;
1516 }
1517 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001518#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001519 arg = 0;
1520 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001521#else /* FREEBSD */
1522 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001523#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001524 perror("PIOCRUN");
1525 return -1;
1526 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001527#ifdef FREEBSD
1528 /* handle the case where we "opened" the child before
1529 it did the kill -STOP */
1530 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1531 tcp->status.PR_WHAT == SIGSTOP)
1532 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001533#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001534 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001535#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001536 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001537#else /* FREEBSD */
1538 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001539 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001540 /* We are attaching to an already running process.
1541 * Try to figure out the state of the process in syscalls,
1542 * to handle the first event well.
1543 * This is done by having a look at the "wchan" property of the
1544 * process, which tells where it is stopped (if it is). */
1545 FILE * status;
1546 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001547
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001548 sprintf(proc, "/proc/%d/status", tcp->pid);
1549 status = fopen(proc, "r");
1550 if (status &&
1551 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1552 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1553 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1554 strcmp(wchan, "stopevent")) {
1555 /* The process is asleep in the middle of a syscall.
1556 Fake the syscall entry event */
1557 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1558 tcp->status.PR_WHY = PR_SYSENTRY;
1559 trace_syscall(tcp);
1560 }
1561 if (status)
1562 fclose(status);
1563 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001564 }
1565#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001566#ifndef HAVE_POLLABLE_PROCFS
1567 if (proc_poll_pipe[0] != -1)
1568 proc_poller(tcp->pfd);
1569 else if (nprocs > 1) {
1570 proc_poll_open();
1571 proc_poller(last_pfd);
1572 proc_poller(tcp->pfd);
1573 }
1574 last_pfd = tcp->pfd;
1575#endif /* !HAVE_POLLABLE_PROCFS */
1576 return 0;
1577}
1578
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001579#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001580
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001581struct tcb *
Roland McGrath54e931f2010-09-14 18:59:20 -07001582pid2tcb(int pid)
1583{
1584 int i;
1585
1586 if (pid <= 0)
1587 return NULL;
1588
1589 for (i = 0; i < tcbtabsize; i++) {
1590 struct tcb *tcp = tcbtab[i];
1591 if (tcp->pid == pid && (tcp->flags & TCB_INUSE))
1592 return tcp;
1593 }
1594
1595 return NULL;
1596}
1597
1598#ifdef USE_PROCFS
1599
1600static struct tcb *
1601first_used_tcb(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001602{
1603 int i;
1604 struct tcb *tcp;
Roland McGrathee9d4352002-12-18 04:16:10 +00001605 for (i = 0; i < tcbtabsize; i++) {
1606 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001607 if (tcp->flags & TCB_INUSE)
1608 return tcp;
1609 }
1610 return NULL;
1611}
1612
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001613static struct tcb *
Denys Vlasenko12014262011-05-30 14:00:14 +02001614pfd2tcb(int pfd)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001615{
1616 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001617
Roland McGrathca16be82003-01-10 19:55:28 +00001618 for (i = 0; i < tcbtabsize; i++) {
1619 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001620 if (tcp->pfd != pfd)
1621 continue;
1622 if (tcp->flags & TCB_INUSE)
1623 return tcp;
1624 }
1625 return NULL;
1626}
1627
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001628#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001629
1630void
Denys Vlasenko12014262011-05-30 14:00:14 +02001631droptcb(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001632{
1633 if (tcp->pid == 0)
1634 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001635#ifdef TCB_CLONE_THREAD
1636 if (tcp->nclone_threads > 0) {
1637 /* There are other threads left in this process, but this
1638 is the one whose PID represents the whole process.
1639 We need to keep this record around as a zombie until
1640 all the threads die. */
1641 tcp->flags |= TCB_EXITING;
1642 return;
1643 }
1644#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001645 nprocs--;
1646 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001647
Roland McGrathe29341c2003-01-10 20:14:20 +00001648 if (tcp->parent != NULL) {
Roland McGrathe29341c2003-01-10 20:14:20 +00001649#ifdef TCB_CLONE_THREAD
Roland McGrathe29341c2003-01-10 20:14:20 +00001650 if (tcp->flags & TCB_CLONE_THREAD)
1651 tcp->parent->nclone_threads--;
1652#endif
Roland McGrath276ceb32007-11-13 08:12:12 +00001653#ifdef LINUX
Denys Vlasenkob56d6d32011-06-21 16:06:28 +02001654 /* Update fields like NCLONE_DETACHED, only
1655 for zombie group leader that has already reported
1656 and been short-circuited at the top of this
Roland McGrath276ceb32007-11-13 08:12:12 +00001657 function. The same condition as at the top of DETACH. */
1658 if ((tcp->flags & TCB_CLONE_THREAD) &&
1659 tcp->parent->nclone_threads == 0 &&
1660 (tcp->parent->flags & TCB_EXITING))
1661 droptcb(tcp->parent);
1662#endif
Roland McGrathe29341c2003-01-10 20:14:20 +00001663 tcp->parent = NULL;
1664 }
1665
1666 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001667 if (tcp->pfd != -1) {
1668 close(tcp->pfd);
1669 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001670#ifdef FREEBSD
1671 if (tcp->pfd_reg != -1) {
1672 close(tcp->pfd_reg);
1673 tcp->pfd_reg = -1;
1674 }
1675 if (tcp->pfd_status != -1) {
1676 close(tcp->pfd_status);
1677 tcp->pfd_status = -1;
1678 }
Roland McGrath553a6092002-12-16 20:40:39 +00001679#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001680#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001681 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001682#endif
1683 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001684
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001685 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001686 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001687
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001688 tcp->outf = 0;
1689}
1690
Roland McGrath0a463882007-07-05 18:43:16 +00001691/* detach traced process; continue with sig
1692 Never call DETACH twice on the same process as both unattached and
1693 attached-unstopped processes give the same ESRCH. For unattached process we
1694 would SIGSTOP it and wait for its SIGSTOP notification forever. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001695
1696static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001697detach(struct tcb *tcp, int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001698{
1699 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001700#ifdef LINUX
Roland McGrath1bfd3102007-08-03 10:02:00 +00001701 int status, catch_sigstop;
Roland McGratha08a97e2005-08-03 11:23:46 +00001702 struct tcb *zombie = NULL;
1703
1704 /* If the group leader is lingering only because of this other
1705 thread now dying, then detach the leader as well. */
1706 if ((tcp->flags & TCB_CLONE_THREAD) &&
1707 tcp->parent->nclone_threads == 1 &&
1708 (tcp->parent->flags & TCB_EXITING))
1709 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001710#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001711
1712 if (tcp->flags & TCB_BPTSET)
Andreas Schwab840d85b2010-01-12 11:16:32 +01001713 clearbpt(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001714
1715#ifdef LINUX
1716 /*
1717 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001718 * before detaching. Arghh. We go through hoops
1719 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001720 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001721#if defined(SPARC)
1722#undef PTRACE_DETACH
1723#define PTRACE_DETACH PTRACE_SUNDETACH
1724#endif
Roland McGrath02203312007-06-11 22:06:31 +00001725 /*
1726 * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
1727 * expected SIGSTOP. We must catch exactly one as otherwise the
1728 * detached process would be left stopped (process state T).
1729 */
1730 catch_sigstop = (tcp->flags & TCB_STARTUP);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001731 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1732 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001733 }
1734 else if (errno != ESRCH) {
1735 /* Shouldn't happen. */
1736 perror("detach: ptrace(PTRACE_DETACH, ...)");
1737 }
Roland McGrath134813a2007-06-02 00:07:33 +00001738 else if (my_tgkill((tcp->flags & TCB_CLONE_THREAD ? tcp->parent->pid
1739 : tcp->pid),
1740 tcp->pid, 0) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001741 if (errno != ESRCH)
1742 perror("detach: checking sanity");
1743 }
Roland McGrath02203312007-06-11 22:06:31 +00001744 else if (!catch_sigstop && my_tgkill((tcp->flags & TCB_CLONE_THREAD
1745 ? tcp->parent->pid : tcp->pid),
1746 tcp->pid, SIGSTOP) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001747 if (errno != ESRCH)
1748 perror("detach: stopping child");
1749 }
Roland McGrath02203312007-06-11 22:06:31 +00001750 else
1751 catch_sigstop = 1;
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001752 if (catch_sigstop) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001753 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001754#ifdef __WALL
1755 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1756 if (errno == ECHILD) /* Already gone. */
1757 break;
1758 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001759 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001760 break;
1761 }
1762#endif /* __WALL */
1763 /* No __WALL here. */
1764 if (waitpid(tcp->pid, &status, 0) < 0) {
1765 if (errno != ECHILD) {
1766 perror("detach: waiting");
1767 break;
1768 }
1769#ifdef __WCLONE
1770 /* If no processes, try clones. */
1771 if (wait4(tcp->pid, &status, __WCLONE,
1772 NULL) < 0) {
1773 if (errno != ECHILD)
1774 perror("detach: waiting");
1775 break;
1776 }
1777#endif /* __WCLONE */
1778 }
1779#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001780 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001781#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001782 if (!WIFSTOPPED(status)) {
1783 /* Au revoir, mon ami. */
1784 break;
1785 }
1786 if (WSTOPSIG(status) == SIGSTOP) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001787 ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001788 break;
1789 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001790 error = ptrace_restart(PTRACE_CONT, tcp,
Denys Vlasenko75422762011-05-27 14:36:01 +02001791 WSTOPSIG(status) == syscall_trap_sig ? 0
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001792 : WSTOPSIG(status));
1793 if (error < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001794 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001795 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001796 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001797#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001798
1799#if defined(SUNOS4)
1800 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1801 if (sig && kill(tcp->pid, sig) < 0)
1802 perror("detach: kill");
1803 sig = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001804 error = ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001805#endif /* SUNOS4 */
1806
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001807 if (!qflag)
1808 fprintf(stderr, "Process %u detached\n", tcp->pid);
1809
1810 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001811
1812#ifdef LINUX
Roland McGrath0a463882007-07-05 18:43:16 +00001813 if (zombie != NULL) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001814 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath0a463882007-07-05 18:43:16 +00001815 droptcb(zombie);
1816 }
Roland McGratha08a97e2005-08-03 11:23:46 +00001817#endif
1818
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001819 return error;
1820}
1821
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001822#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001823
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001824static void reaper(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001825{
1826 int pid;
1827 int status;
1828
1829 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001830 }
1831}
1832
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001833#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001834
1835static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001836cleanup(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001837{
1838 int i;
1839 struct tcb *tcp;
1840
Roland McGrathee9d4352002-12-18 04:16:10 +00001841 for (i = 0; i < tcbtabsize; i++) {
1842 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001843 if (!(tcp->flags & TCB_INUSE))
1844 continue;
1845 if (debug)
1846 fprintf(stderr,
1847 "cleanup: looking at pid %u\n", tcp->pid);
1848 if (tcp_last &&
1849 (!outfname || followfork < 2 || tcp_last == tcp)) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001850 tprintf(" <unfinished ...>");
1851 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001852 }
1853 if (tcp->flags & TCB_ATTACHED)
1854 detach(tcp, 0);
1855 else {
1856 kill(tcp->pid, SIGCONT);
1857 kill(tcp->pid, SIGTERM);
1858 }
1859 }
1860 if (cflag)
1861 call_summary(outf);
1862}
1863
1864static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001865interrupt(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001866{
1867 interrupted = 1;
1868}
1869
1870#ifndef HAVE_STRERROR
1871
Roland McGrath6d2b3492002-12-30 00:51:30 +00001872#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001873extern int sys_nerr;
1874extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001875#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001876
1877const char *
Denys Vlasenko12014262011-05-30 14:00:14 +02001878strerror(int err_no)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001879{
1880 static char buf[64];
1881
Denys Vlasenko35aba6a2011-05-25 15:33:26 +02001882 if (err_no < 1 || err_no >= sys_nerr) {
1883 sprintf(buf, "Unknown error %d", err_no);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001884 return buf;
1885 }
Denys Vlasenko35aba6a2011-05-25 15:33:26 +02001886 return sys_errlist[err_no];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001887}
1888
1889#endif /* HAVE_STERRROR */
1890
1891#ifndef HAVE_STRSIGNAL
1892
Roland McGrath8f474e02003-01-14 07:53:33 +00001893#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001894extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001895#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001896#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1897extern char *_sys_siglist[];
1898#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001899
1900const char *
Denys Vlasenko12014262011-05-30 14:00:14 +02001901strsignal(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001902{
1903 static char buf[64];
1904
1905 if (sig < 1 || sig >= NSIG) {
1906 sprintf(buf, "Unknown signal %d", sig);
1907 return buf;
1908 }
1909#ifdef HAVE__SYS_SIGLIST
1910 return _sys_siglist[sig];
1911#else
1912 return sys_siglist[sig];
1913#endif
1914}
1915
1916#endif /* HAVE_STRSIGNAL */
1917
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001918#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001919
1920static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001921rebuild_pollv(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001922{
1923 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001924
Roland McGrathee9d4352002-12-18 04:16:10 +00001925 if (pollv != NULL)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001926 free(pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001927 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001928 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001929 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00001930 exit(1);
1931 }
1932
Roland McGrathca16be82003-01-10 19:55:28 +00001933 for (i = j = 0; i < tcbtabsize; i++) {
1934 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001935 if (!(tcp->flags & TCB_INUSE))
1936 continue;
1937 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001938 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001939 j++;
1940 }
1941 if (j != nprocs) {
1942 fprintf(stderr, "strace: proc miscount\n");
1943 exit(1);
1944 }
1945}
1946
1947#ifndef HAVE_POLLABLE_PROCFS
1948
1949static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001950proc_poll_open(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001951{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001952 int i;
1953
1954 if (pipe(proc_poll_pipe) < 0) {
1955 perror("pipe");
1956 exit(1);
1957 }
1958 for (i = 0; i < 2; i++) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001959 if (set_cloexec_flag(proc_poll_pipe[i]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001960 exit(1);
1961 }
1962 }
1963}
1964
1965static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001966proc_poll(struct pollfd *pollv, int nfds, int timeout)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001967{
1968 int i;
1969 int n;
1970 struct proc_pollfd pollinfo;
1971
1972 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1973 return n;
1974 if (n != sizeof(struct proc_pollfd)) {
1975 fprintf(stderr, "panic: short read: %d\n", n);
1976 exit(1);
1977 }
1978 for (i = 0; i < nprocs; i++) {
1979 if (pollv[i].fd == pollinfo.fd)
1980 pollv[i].revents = pollinfo.revents;
1981 else
1982 pollv[i].revents = 0;
1983 }
1984 poller_pid = pollinfo.pid;
1985 return 1;
1986}
1987
1988static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001989wakeup_handler(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001990{
1991}
1992
1993static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001994proc_poller(int pfd)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001995{
1996 struct proc_pollfd pollinfo;
1997 struct sigaction sa;
1998 sigset_t blocked_set, empty_set;
1999 int i;
2000 int n;
2001 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002002#ifdef FREEBSD
2003 struct procfs_status pfs;
2004#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002005
2006 switch (fork()) {
2007 case -1:
2008 perror("fork");
Dmitry V. Levina6809652008-11-10 17:14:58 +00002009 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002010 case 0:
2011 break;
2012 default:
2013 return;
2014 }
2015
2016 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
2017 sa.sa_flags = 0;
2018 sigemptyset(&sa.sa_mask);
2019 sigaction(SIGHUP, &sa, NULL);
2020 sigaction(SIGINT, &sa, NULL);
2021 sigaction(SIGQUIT, &sa, NULL);
2022 sigaction(SIGPIPE, &sa, NULL);
2023 sigaction(SIGTERM, &sa, NULL);
2024 sa.sa_handler = wakeup_handler;
2025 sigaction(SIGUSR1, &sa, NULL);
2026 sigemptyset(&blocked_set);
2027 sigaddset(&blocked_set, SIGUSR1);
2028 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2029 sigemptyset(&empty_set);
2030
2031 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
2032 perror("getrlimit(RLIMIT_NOFILE, ...)");
Dmitry V. Levina6809652008-11-10 17:14:58 +00002033 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002034 }
2035 n = rl.rlim_cur;
2036 for (i = 0; i < n; i++) {
2037 if (i != pfd && i != proc_poll_pipe[1])
2038 close(i);
2039 }
2040
2041 pollinfo.fd = pfd;
2042 pollinfo.pid = getpid();
2043 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002044#ifndef FREEBSD
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002045 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
2046#else
2047 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
2048#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002049 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002050 switch (errno) {
2051 case EINTR:
2052 continue;
2053 case EBADF:
2054 pollinfo.revents = POLLERR;
2055 break;
2056 case ENOENT:
2057 pollinfo.revents = POLLHUP;
2058 break;
2059 default:
2060 perror("proc_poller: PIOCWSTOP");
2061 }
2062 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2063 _exit(0);
2064 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002065 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002066 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2067 sigsuspend(&empty_set);
2068 }
2069}
2070
2071#endif /* !HAVE_POLLABLE_PROCFS */
2072
2073static int
2074choose_pfd()
2075{
2076 int i, j;
2077 struct tcb *tcp;
2078
2079 static int last;
2080
2081 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002082 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002083 /*
2084 * The previous process is ready to run again. We'll
2085 * let it do so if it is currently in a syscall. This
2086 * heuristic improves the readability of the trace.
2087 */
2088 tcp = pfd2tcb(pollv[last].fd);
2089 if (tcp && (tcp->flags & TCB_INSYSCALL))
2090 return pollv[last].fd;
2091 }
2092
2093 for (i = 0; i < nprocs; i++) {
2094 /* Let competing children run round robin. */
2095 j = (i + last + 1) % nprocs;
2096 if (pollv[j].revents & (POLLHUP | POLLERR)) {
2097 tcp = pfd2tcb(pollv[j].fd);
2098 if (!tcp) {
2099 fprintf(stderr, "strace: lost proc\n");
2100 exit(1);
2101 }
2102 droptcb(tcp);
2103 return -1;
2104 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002105 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002106 last = j;
2107 return pollv[j].fd;
2108 }
2109 }
2110 fprintf(stderr, "strace: nothing ready\n");
2111 exit(1);
2112}
2113
2114static int
Denys Vlasenko12014262011-05-30 14:00:14 +02002115trace(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002116{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002117#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00002118 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002119#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002120 struct tcb *tcp;
2121 int pfd;
2122 int what;
2123 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002124 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002125
2126 for (;;) {
2127 if (interactive)
2128 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2129
2130 if (nprocs == 0)
2131 break;
2132
2133 switch (nprocs) {
2134 case 1:
2135#ifndef HAVE_POLLABLE_PROCFS
2136 if (proc_poll_pipe[0] == -1) {
2137#endif
Roland McGrath54e931f2010-09-14 18:59:20 -07002138 tcp = first_used_tcb();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002139 if (!tcp)
2140 continue;
2141 pfd = tcp->pfd;
2142 if (pfd == -1)
2143 continue;
2144 break;
2145#ifndef HAVE_POLLABLE_PROCFS
2146 }
2147 /* fall through ... */
2148#endif /* !HAVE_POLLABLE_PROCFS */
2149 default:
2150#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002151#ifdef POLL_HACK
2152 /* On some systems (e.g. UnixWare) we get too much ugly
2153 "unfinished..." stuff when multiple proceses are in
2154 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00002155
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002156 if (in_syscall) {
2157 struct pollfd pv;
2158 tcp = in_syscall;
2159 in_syscall = NULL;
2160 pv.fd = tcp->pfd;
2161 pv.events = POLLWANT;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002162 if ((what = poll(&pv, 1, 1)) < 0) {
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002163 if (interrupted)
2164 return 0;
2165 continue;
2166 }
2167 else if (what == 1 && pv.revents & POLLWANT) {
2168 goto FOUND;
2169 }
2170 }
2171#endif
2172
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002173 if (poll(pollv, nprocs, INFTIM) < 0) {
2174 if (interrupted)
2175 return 0;
2176 continue;
2177 }
2178#else /* !HAVE_POLLABLE_PROCFS */
2179 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
2180 if (interrupted)
2181 return 0;
2182 continue;
2183 }
2184#endif /* !HAVE_POLLABLE_PROCFS */
2185 pfd = choose_pfd();
2186 if (pfd == -1)
2187 continue;
2188 break;
2189 }
2190
2191 /* Look up `pfd' in our table. */
2192 if ((tcp = pfd2tcb(pfd)) == NULL) {
2193 fprintf(stderr, "unknown pfd: %u\n", pfd);
2194 exit(1);
2195 }
John Hughesb6643082002-05-23 11:02:22 +00002196#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002197 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00002198#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002199 /* Get the status of the process. */
2200 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002201#ifndef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002202 ioctl_result = IOCTL_WSTOP(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002203#else /* FREEBSD */
2204 /* Thanks to some scheduling mystery, the first poller
2205 sometimes waits for the already processed end of fork
2206 event. Doing a non blocking poll here solves the problem. */
2207 if (proc_poll_pipe[0] != -1)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002208 ioctl_result = IOCTL_STATUS(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002209 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002210 ioctl_result = IOCTL_WSTOP(tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00002211#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002212 ioctl_errno = errno;
2213#ifndef HAVE_POLLABLE_PROCFS
2214 if (proc_poll_pipe[0] != -1) {
2215 if (ioctl_result < 0)
2216 kill(poller_pid, SIGKILL);
2217 else
2218 kill(poller_pid, SIGUSR1);
2219 }
2220#endif /* !HAVE_POLLABLE_PROCFS */
2221 }
2222 if (interrupted)
2223 return 0;
2224
2225 if (interactive)
2226 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2227
2228 if (ioctl_result < 0) {
2229 /* Find out what happened if it failed. */
2230 switch (ioctl_errno) {
2231 case EINTR:
2232 case EBADF:
2233 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002234#ifdef FREEBSD
2235 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00002236#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002237 case ENOENT:
2238 droptcb(tcp);
2239 continue;
2240 default:
2241 perror("PIOCWSTOP");
2242 exit(1);
2243 }
2244 }
2245
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002246#ifdef FREEBSD
2247 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2248 /* discard first event for a syscall we never entered */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002249 IOCTL(tcp->pfd, PIOCRUN, 0);
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002250 continue;
2251 }
Roland McGrath553a6092002-12-16 20:40:39 +00002252#endif
2253
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002254 /* clear the just started flag */
2255 tcp->flags &= ~TCB_STARTUP;
2256
2257 /* set current output file */
2258 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002259 curcol = tcp->curcol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002260
2261 if (cflag) {
2262 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002263#ifdef FREEBSD
2264 char buf[1024];
2265 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002266
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002267 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
2268 buf[len] = '\0';
2269 sscanf(buf,
2270 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2271 &stime.tv_sec, &stime.tv_usec);
2272 } else
2273 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002274#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002275 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2276 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002277#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002278 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2279 tcp->stime = stime;
2280 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002281 what = tcp->status.PR_WHAT;
2282 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002283#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002284 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002285 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2286 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002287 if (trace_syscall(tcp) < 0) {
2288 fprintf(stderr, "syscall trouble\n");
2289 exit(1);
2290 }
2291 }
2292 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002293#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002294 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002295#ifdef POLL_HACK
2296 in_syscall = tcp;
2297#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002298 case PR_SYSEXIT:
2299 if (trace_syscall(tcp) < 0) {
2300 fprintf(stderr, "syscall trouble\n");
2301 exit(1);
2302 }
2303 break;
2304 case PR_SIGNALLED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002305 if (cflag != CFLAG_ONLY_STATS
2306 && (qual_flags[what] & QUAL_SIGNAL)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002307 printleader(tcp);
2308 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002309 signame(what), strsignal(what));
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002310 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002311#ifdef PR_INFO
2312 if (tcp->status.PR_INFO.si_signo == what) {
2313 printleader(tcp);
2314 tprintf(" siginfo=");
2315 printsiginfo(&tcp->status.PR_INFO, 1);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002316 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002317 }
2318#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002319 }
2320 break;
2321 case PR_FAULTED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002322 if (cflag != CFLAGS_ONLY_STATS
2323 && (qual_flags[what] & QUAL_FAULT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002324 printleader(tcp);
2325 tprintf("=== FAULT %d ===", what);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002326 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002327 }
2328 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002329#ifdef FREEBSD
2330 case 0: /* handle case we polled for nothing */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002331 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00002332#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002333 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002334 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002335 exit(1);
2336 break;
2337 }
Andreas Schwabccdff482009-10-27 16:27:13 +01002338 /* Remember current print column before continuing. */
2339 tcp->curcol = curcol;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002340 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002341#ifndef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002342 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002343#else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002344 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002345#endif
Andreas Schwab372cc842010-07-09 11:49:27 +02002346 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002347 perror("PIOCRUN");
2348 exit(1);
2349 }
2350 }
2351 return 0;
2352}
2353
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002354#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002355
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002356#ifdef TCB_GROUP_EXITING
2357/* Handle an exit detach or death signal that is taking all the
2358 related clone threads with it. This is called in three circumstances:
2359 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
2360 SIG == 0 Continuing TCP will perform an exit_group syscall.
2361 SIG == other Continuing TCP with SIG will kill the process.
2362*/
2363static int
2364handle_group_exit(struct tcb *tcp, int sig)
2365{
2366 /* We need to locate our records of all the clone threads
2367 related to TCP, either its children or siblings. */
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002368 struct tcb *leader = NULL;
2369
2370 if (tcp->flags & TCB_CLONE_THREAD)
2371 leader = tcp->parent;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002372
2373 if (sig < 0) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002374 if (leader != NULL && leader != tcp
2375 && !(leader->flags & TCB_GROUP_EXITING)
2376 && !(tcp->flags & TCB_STARTUP)
2377 ) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002378 fprintf(stderr,
2379 "PANIC: handle_group_exit: %d leader %d\n",
2380 tcp->pid, leader ? leader->pid : -1);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002381 }
2382 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath0a463882007-07-05 18:43:16 +00002383 droptcb(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002384 }
2385 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00002386 /* Mark that we are taking the process down. */
2387 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002388 if (tcp->flags & TCB_ATTACHED) {
Roland McGrathd6a32f12007-07-11 08:35:11 +00002389 detach(tcp, sig);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002390 if (leader != NULL && leader != tcp)
Roland McGrath1bfd3102007-08-03 10:02:00 +00002391 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002392 } else {
2393 if (ptrace_restart(PTRACE_CONT, tcp, sig) < 0) {
2394 cleanup();
2395 return -1;
2396 }
2397 if (leader != NULL) {
Roland McGrath05690952004-10-20 01:00:27 +00002398 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002399 if (leader != tcp)
2400 droptcb(tcp);
2401 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002402 /* The leader will report to us as parent now,
2403 and then we'll get to the SIG==-1 case. */
2404 return 0;
2405 }
2406 }
2407
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002408 return 0;
2409}
2410#endif
2411
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002412#ifdef LINUX
2413static int
2414handle_ptrace_event(int status, struct tcb *tcp)
2415{
2416 if (status >> 16 == PTRACE_EVENT_VFORK ||
2417 status >> 16 == PTRACE_EVENT_CLONE ||
2418 status >> 16 == PTRACE_EVENT_FORK) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +00002419 long childpid;
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002420
2421 if (do_ptrace(PTRACE_GETEVENTMSG, tcp, NULL, &childpid) < 0) {
2422 if (errno != ESRCH) {
2423 fprintf(stderr, "\
2424%s: handle_ptrace_event: ptrace cannot get new child's pid\n",
2425 progname);
2426 cleanup();
2427 exit(1);
2428 }
2429 return -1;
2430 }
2431 return handle_new_child(tcp, childpid, 0);
2432 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002433 if (status >> 16 == PTRACE_EVENT_EXEC) {
2434 if (debug)
2435 fprintf(stderr, "PTRACE_EVENT_EXEC on pid %d (ignored)\n", tcp->pid);
2436 return 0;
2437 }
Denys Vlasenko75422762011-05-27 14:36:01 +02002438 /* Some PTRACE_EVENT_foo we didn't ask for?! */
2439 error_msg("Unexpected status %x on pid %d", status, tcp->pid);
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002440 return 1;
2441}
2442#endif
2443
Roland McGratheb9e2e82009-06-02 16:49:22 -07002444static int
2445trace()
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002446{
2447 int pid;
2448 int wait_errno;
2449 int status;
2450 struct tcb *tcp;
2451#ifdef LINUX
2452 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002453#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002454 static int wait4_options = __WALL;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002455#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002456#endif /* LINUX */
2457
Roland McGratheb9e2e82009-06-02 16:49:22 -07002458 while (nprocs != 0) {
Denys Vlasenko222713a2009-03-17 14:29:59 +00002459 if (interrupted)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002460 return 0;
2461 if (interactive)
2462 sigprocmask(SIG_SETMASK, &empty_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002463#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002464#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002465 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002466 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002467 /* this kernel does not support __WALL */
2468 wait4_options &= ~__WALL;
2469 errno = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002470 pid = wait4(-1, &status, wait4_options,
2471 cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002472 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002473 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002474 /* most likely a "cloned" process */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002475 pid = wait4(-1, &status, __WCLONE,
2476 cflag ? &ru : NULL);
2477 if (pid == -1) {
2478 fprintf(stderr, "strace: clone wait4 "
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002479 "failed: %s\n", strerror(errno));
2480 }
2481 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002482#else
2483 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
2484#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002485#endif /* LINUX */
2486#ifdef SUNOS4
2487 pid = wait(&status);
2488#endif /* SUNOS4 */
2489 wait_errno = errno;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002490 if (interactive)
2491 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002492
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002493 if (pid == -1) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002494 switch (wait_errno) {
2495 case EINTR:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002496 continue;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002497 case ECHILD:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002498 /*
2499 * We would like to verify this case
2500 * but sometimes a race in Solbourne's
2501 * version of SunOS sometimes reports
2502 * ECHILD before sending us SIGCHILD.
2503 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002504 return 0;
2505 default:
2506 errno = wait_errno;
2507 perror("strace: wait");
2508 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002509 }
2510 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002511 if (pid == popen_pid) {
2512 if (WIFEXITED(status) || WIFSIGNALED(status))
2513 popen_pid = -1;
2514 continue;
2515 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002516 if (debug)
2517 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2518
2519 /* Look up `pid' in our table. */
2520 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002521#ifdef LINUX
Roland McGrath41c48222008-07-18 00:25:10 +00002522 if (followfork) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002523 /* This is needed to go with the CLONE_PTRACE
2524 changes in process.c/util.c: we might see
2525 the child's initial trap before we see the
2526 parent return from the clone syscall.
2527 Leave the child suspended until the parent
2528 returns from its system call. Only then
2529 will we have the association of parent and
2530 child so that we know how to do clearbpt
2531 in the child. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +00002532 tcp = alloctcb(pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002533 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002534 if (!qflag)
2535 fprintf(stderr, "\
2536Process %d attached (waiting for parent)\n",
2537 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002538 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002539 else
2540 /* This can happen if a clone call used
2541 CLONE_PTRACE itself. */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002542#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002543 {
2544 fprintf(stderr, "unknown pid: %u\n", pid);
2545 if (WIFSTOPPED(status))
2546 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2547 exit(1);
2548 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002549 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002550 /* set current output file */
2551 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002552 curcol = tcp->curcol;
Denys Vlasenko84e20af2009-02-10 16:03:20 +00002553 if (cflag) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002554#ifdef LINUX
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002555 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2556 tcp->stime = ru.ru_stime;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002557#endif /* !LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002558 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002559
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002560 if (tcp->flags & TCB_SUSPENDED) {
2561 /*
2562 * Apparently, doing any ptrace() call on a stopped
2563 * process, provokes the kernel to report the process
2564 * status again on a subsequent wait(), even if the
2565 * process has not been actually restarted.
2566 * Since we have inspected the arguments of suspended
2567 * processes we end up here testing for this case.
2568 */
2569 continue;
2570 }
2571 if (WIFSIGNALED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002572 if (pid == strace_child)
2573 exit_code = 0x100 | WTERMSIG(status);
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002574 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002575 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2576 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002577 tprintf("+++ killed by %s %s+++",
2578 signame(WTERMSIG(status)),
2579#ifdef WCOREDUMP
2580 WCOREDUMP(status) ? "(core dumped) " :
2581#endif
2582 "");
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002583 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002584 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002585#ifdef TCB_GROUP_EXITING
2586 handle_group_exit(tcp, -1);
2587#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002588 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002589#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002590 continue;
2591 }
2592 if (WIFEXITED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002593 if (pid == strace_child)
2594 exit_code = WEXITSTATUS(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002595 if (debug)
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002596 fprintf(stderr, "pid %u exited with %d\n", pid, WEXITSTATUS(status));
2597 if ((tcp->flags & (TCB_ATTACHED|TCB_STARTUP)) == TCB_ATTACHED
Roland McGrath05690952004-10-20 01:00:27 +00002598#ifdef TCB_GROUP_EXITING
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002599 && !(tcp->parent && (tcp->parent->flags & TCB_GROUP_EXITING))
Roland McGrath1bfd3102007-08-03 10:02:00 +00002600 && !(tcp->flags & TCB_GROUP_EXITING)
Roland McGrath05690952004-10-20 01:00:27 +00002601#endif
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002602 ) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002603 fprintf(stderr,
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002604 "PANIC: attached pid %u exited with %d\n",
2605 pid, WEXITSTATUS(status));
2606 }
Roland McGrath0a396902003-06-10 03:05:53 +00002607 if (tcp == tcp_last) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002608 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT)) == TCB_INSYSCALL)
Roland McGrath0a396902003-06-10 03:05:53 +00002609 tprintf(" <unfinished ... exit status %d>\n",
2610 WEXITSTATUS(status));
2611 tcp_last = NULL;
2612 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002613#ifdef TCB_GROUP_EXITING
2614 handle_group_exit(tcp, -1);
2615#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002616 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002617#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002618 continue;
2619 }
2620 if (!WIFSTOPPED(status)) {
2621 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2622 droptcb(tcp);
2623 continue;
2624 }
2625 if (debug)
2626 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002627 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002628
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002629 if (status >> 16) {
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002630 if (handle_ptrace_event(status, tcp) != 1)
2631 goto tracing;
2632 }
2633
Roland McGrath02203312007-06-11 22:06:31 +00002634 /*
2635 * Interestingly, the process may stop
2636 * with STOPSIG equal to some other signal
Roland McGratheb9e2e82009-06-02 16:49:22 -07002637 * than SIGSTOP if we happend to attach
Roland McGrath02203312007-06-11 22:06:31 +00002638 * just before the process takes a signal.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002639 * A no-MMU vforked child won't send up a signal,
2640 * so skip the first (lost) execve notification.
Roland McGrath02203312007-06-11 22:06:31 +00002641 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002642 if ((tcp->flags & TCB_STARTUP) &&
2643 (WSTOPSIG(status) == SIGSTOP || strace_vforked)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002644 /*
2645 * This flag is there to keep us in sync.
2646 * Next time this process stops it should
2647 * really be entering a system call.
2648 */
2649 tcp->flags &= ~TCB_STARTUP;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002650 if (tcp->flags & TCB_BPTSET) {
Roland McGrath02203312007-06-11 22:06:31 +00002651 /*
2652 * One example is a breakpoint inherited from
2653 * parent through fork ().
2654 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002655 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2656 droptcb(tcp);
2657 cleanup();
2658 return -1;
2659 }
2660 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002661#ifdef LINUX
Denys Vlasenkof44cce42011-06-21 14:34:10 +02002662 /* If options were not set for this tracee yet */
2663 if (tcp->parent == NULL) {
2664 if (ptrace_setoptions) {
2665 if (debug)
2666 fprintf(stderr, "setting opts %x on pid %d\n", ptrace_setoptions, tcp->pid);
2667 if (ptrace(PTRACE_SETOPTIONS, tcp->pid, NULL, ptrace_setoptions) < 0) {
2668 if (errno != ESRCH) {
2669 /* Should never happen, really */
2670 perror_msg_and_die("PTRACE_SETOPTIONS");
2671 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002672 }
2673 }
2674 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002675#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002676 goto tracing;
2677 }
2678
Denys Vlasenko75422762011-05-27 14:36:01 +02002679 if (WSTOPSIG(status) != syscall_trap_sig) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002680 if (WSTOPSIG(status) == SIGSTOP &&
2681 (tcp->flags & TCB_SIGTRAPPED)) {
2682 /*
2683 * Trapped attempt to block SIGTRAP
2684 * Hope we are back in control now.
2685 */
2686 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002687 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002688 cleanup();
2689 return -1;
2690 }
2691 continue;
2692 }
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002693 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002694 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Dmitry V. Levinc15dfc72011-03-10 14:44:45 +00002695 siginfo_t si;
2696#if defined(PT_CR_IPSR) && defined(PT_CR_IIP)
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002697 long pc = 0;
2698 long psr = 0;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002699
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002700 upeek(tcp, PT_CR_IPSR, &psr);
2701 upeek(tcp, PT_CR_IIP, &pc);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002702
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002703# define PSR_RI 41
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002704 pc += (psr >> PSR_RI) & 0x3;
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002705# define PC_FORMAT_STR " @ %lx"
2706# define PC_FORMAT_ARG pc
2707#else
2708# define PC_FORMAT_STR "%s"
2709# define PC_FORMAT_ARG ""
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002710#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002711 printleader(tcp);
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002712 if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
2713 tprintf("--- ");
2714 printsiginfo(&si, verbose(tcp));
2715 tprintf(" (%s)" PC_FORMAT_STR " ---",
2716 strsignal(WSTOPSIG(status)),
2717 PC_FORMAT_ARG);
2718 } else
2719 tprintf("--- %s by %s" PC_FORMAT_STR " ---",
2720 strsignal(WSTOPSIG(status)),
2721 signame(WSTOPSIG(status)),
2722 PC_FORMAT_ARG);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002723 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002724 }
Roland McGrath05690952004-10-20 01:00:27 +00002725 if (((tcp->flags & TCB_ATTACHED) ||
2726 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002727 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002728#ifdef TCB_GROUP_EXITING
2729 handle_group_exit(tcp, WSTOPSIG(status));
2730#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002731 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002732#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002733 continue;
2734 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002735 if (ptrace_restart(PTRACE_SYSCALL, tcp, WSTOPSIG(status)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002736 cleanup();
2737 return -1;
2738 }
2739 tcp->flags &= ~TCB_SUSPENDED;
2740 continue;
2741 }
Roland McGrath02203312007-06-11 22:06:31 +00002742 /* we handled the STATUS, we are permitted to interrupt now. */
2743 if (interrupted)
2744 return 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002745 if (trace_syscall(tcp) < 0 && !tcp->ptrace_errno) {
2746 /* ptrace() failed in trace_syscall() with ESRCH.
2747 * Likely a result of process disappearing mid-flight.
2748 * Observed case: exit_group() terminating
2749 * all processes in thread group. In this case, threads
2750 * "disappear" in an unpredictable moment without any
2751 * notification to strace via wait().
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002752 */
2753 if (tcp->flags & TCB_ATTACHED) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002754 if (tcp_last) {
2755 /* Do we have dangling line "syscall(param, param"?
2756 * Finish the line then. We cannot
2757 */
2758 tcp_last->flags |= TCB_REPRINT;
2759 tprintf(" <unfinished ...>");
2760 printtrailer();
2761 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002762 detach(tcp, 0);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002763 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002764 ptrace(PTRACE_KILL,
2765 tcp->pid, (char *) 1, SIGTERM);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002766 droptcb(tcp);
2767 }
2768 continue;
2769 }
2770 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002771#ifdef TCB_GROUP_EXITING
2772 if (tcp->flags & TCB_GROUP_EXITING) {
2773 if (handle_group_exit(tcp, 0) < 0)
2774 return -1;
2775 continue;
2776 }
2777#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002778 if (tcp->flags & TCB_ATTACHED)
2779 detach(tcp, 0);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002780 else if (ptrace_restart(PTRACE_CONT, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002781 cleanup();
2782 return -1;
2783 }
2784 continue;
2785 }
2786 if (tcp->flags & TCB_SUSPENDED) {
2787 if (!qflag)
2788 fprintf(stderr, "Process %u suspended\n", pid);
2789 continue;
2790 }
2791 tracing:
Andreas Schwabccdff482009-10-27 16:27:13 +01002792 /* Remember current print column before continuing. */
2793 tcp->curcol = curcol;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002794 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002795 cleanup();
2796 return -1;
2797 }
2798 }
2799 return 0;
2800}
2801
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002802#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002803
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002804#include <stdarg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002805
2806void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002807tprintf(const char *fmt, ...)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002808{
2809 va_list args;
2810
Andreas Schwabe5355de2009-10-27 16:56:43 +01002811 va_start(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002812 if (outf) {
2813 int n = vfprintf(outf, fmt, args);
Andreas Schwabccdff482009-10-27 16:27:13 +01002814 if (n < 0) {
2815 if (outf != stderr)
2816 perror(outfname == NULL
2817 ? "<writing to pipe>" : outfname);
2818 } else
Roland McGrathb310a0c2003-11-06 23:41:22 +00002819 curcol += n;
2820 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002821 va_end(args);
2822 return;
2823}
2824
2825void
Denys Vlasenko12014262011-05-30 14:00:14 +02002826printleader(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002827{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002828 if (tcp_last) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002829 if (tcp_last->ptrace_errno) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002830 if (tcp_last->flags & TCB_INSYSCALL) {
Denys Vlasenkoe62df002011-06-08 16:15:04 +02002831 tprintf(" <unavailable>) ");
Roland McGratheb9e2e82009-06-02 16:49:22 -07002832 tabto(acolumn);
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002833 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002834 tprintf("= ? <unavailable>\n");
2835 tcp_last->ptrace_errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002836 } else if (!outfname || followfork < 2 || tcp_last == tcp) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002837 tcp_last->flags |= TCB_REPRINT;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002838 tprintf(" <unfinished ...>\n");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002839 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002840 }
2841 curcol = 0;
2842 if ((followfork == 1 || pflag_seen > 1) && outfname)
2843 tprintf("%-5d ", tcp->pid);
2844 else if (nprocs > 1 && !outfname)
2845 tprintf("[pid %5u] ", tcp->pid);
2846 if (tflag) {
2847 char str[sizeof("HH:MM:SS")];
2848 struct timeval tv, dtv;
2849 static struct timeval otv;
2850
2851 gettimeofday(&tv, NULL);
2852 if (rflag) {
2853 if (otv.tv_sec == 0)
2854 otv = tv;
2855 tv_sub(&dtv, &tv, &otv);
2856 tprintf("%6ld.%06ld ",
2857 (long) dtv.tv_sec, (long) dtv.tv_usec);
2858 otv = tv;
2859 }
2860 else if (tflag > 2) {
2861 tprintf("%ld.%06ld ",
2862 (long) tv.tv_sec, (long) tv.tv_usec);
2863 }
2864 else {
2865 time_t local = tv.tv_sec;
2866 strftime(str, sizeof(str), "%T", localtime(&local));
2867 if (tflag > 1)
2868 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2869 else
2870 tprintf("%s ", str);
2871 }
2872 }
2873 if (iflag)
2874 printcall(tcp);
2875}
2876
2877void
Denys Vlasenko12014262011-05-30 14:00:14 +02002878tabto(int col)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002879{
2880 if (curcol < col)
2881 tprintf("%*s", col - curcol, "");
2882}
2883
2884void
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002885printtrailer(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002886{
2887 tprintf("\n");
2888 tcp_last = NULL;
2889}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002890
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002891#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002892
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002893int
2894mp_ioctl(int fd, int cmd, void *arg, int size)
2895{
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002896 struct iovec iov[2];
2897 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002898
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002899 iov[0].iov_base = &cmd;
2900 iov[0].iov_len = sizeof cmd;
2901 if (arg) {
2902 ++n;
2903 iov[1].iov_base = arg;
2904 iov[1].iov_len = size;
2905 }
Roland McGrath553a6092002-12-16 20:40:39 +00002906
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002907 return writev(fd, iov, n);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002908}
2909
2910#endif