blob: 93e6d29fb90446bf1371247d26baf917a2c99100 [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]->nchildren++;
518 tcbtab[tcbi]->nclone_threads++;
Roland McGrath02203312007-06-11 22:06:31 +0000519 tcp->parent = tcbtab[tcbi];
520 }
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000521 if (interactive) {
522 sigprocmask(SIG_SETMASK, &empty_set, NULL);
523 if (interrupted)
524 return;
525 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
526 }
Roland McGrath02203312007-06-11 22:06:31 +0000527 }
528 closedir(dir);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000529 ntid -= nerr;
530 if (ntid == 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000531 perror("attach: ptrace(PTRACE_ATTACH, ...)");
532 droptcb(tcp);
533 continue;
534 }
535 if (!qflag) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000536 fprintf(stderr, ntid > 1
537? "Process %u attached with %u threads - interrupt to quit\n"
538: "Process %u attached - interrupt to quit\n",
539 tcbtab[tcbi]->pid, ntid);
Roland McGrath02203312007-06-11 22:06:31 +0000540 }
541 continue;
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000542 } /* if (opendir worked) */
543 } /* if (-f) */
Roland McGrath02203312007-06-11 22:06:31 +0000544# endif
545 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
546 perror("attach: ptrace(PTRACE_ATTACH, ...)");
547 droptcb(tcp);
548 continue;
549 }
550 /* INTERRUPTED is going to be checked at the top of TRACE. */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000551
552 if (daemonized_tracer) {
553 /*
554 * It is our grandparent we trace, not a -p PID.
555 * Don't want to just detach on exit, so...
556 */
557 tcp->flags &= ~TCB_ATTACHED;
558 /*
559 * Make parent go away.
560 * Also makes grandparent's wait() unblock.
561 */
562 kill(getppid(), SIGKILL);
563 }
564
Roland McGrath02203312007-06-11 22:06:31 +0000565#endif /* !USE_PROCFS */
566 if (!qflag)
567 fprintf(stderr,
568 "Process %u attached - interrupt to quit\n",
569 tcp->pid);
570 }
571
572 if (interactive)
573 sigprocmask(SIG_SETMASK, &empty_set, NULL);
574}
575
576static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200577startup_child(char **argv)
Roland McGrath02203312007-06-11 22:06:31 +0000578{
579 struct stat statbuf;
580 const char *filename;
581 char pathname[MAXPATHLEN];
582 int pid = 0;
583 struct tcb *tcp;
584
585 filename = argv[0];
586 if (strchr(filename, '/')) {
587 if (strlen(filename) > sizeof pathname - 1) {
588 errno = ENAMETOOLONG;
589 perror("strace: exec");
590 exit(1);
591 }
592 strcpy(pathname, filename);
593 }
594#ifdef USE_DEBUGGING_EXEC
595 /*
596 * Debuggers customarily check the current directory
597 * first regardless of the path but doing that gives
598 * security geeks a panic attack.
599 */
600 else if (stat(filename, &statbuf) == 0)
601 strcpy(pathname, filename);
602#endif /* USE_DEBUGGING_EXEC */
603 else {
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000604 const char *path;
Roland McGrath02203312007-06-11 22:06:31 +0000605 int m, n, len;
606
607 for (path = getenv("PATH"); path && *path; path += m) {
608 if (strchr(path, ':')) {
609 n = strchr(path, ':') - path;
610 m = n + 1;
611 }
612 else
613 m = n = strlen(path);
614 if (n == 0) {
615 if (!getcwd(pathname, MAXPATHLEN))
616 continue;
617 len = strlen(pathname);
618 }
619 else if (n > sizeof pathname - 1)
620 continue;
621 else {
622 strncpy(pathname, path, n);
623 len = n;
624 }
625 if (len && pathname[len - 1] != '/')
626 pathname[len++] = '/';
627 strcpy(pathname + len, filename);
628 if (stat(pathname, &statbuf) == 0 &&
629 /* Accept only regular files
630 with some execute bits set.
631 XXX not perfect, might still fail */
632 S_ISREG(statbuf.st_mode) &&
633 (statbuf.st_mode & 0111))
634 break;
635 }
636 }
637 if (stat(pathname, &statbuf) < 0) {
638 fprintf(stderr, "%s: %s: command not found\n",
639 progname, filename);
640 exit(1);
641 }
Dmitry V. Levina6809652008-11-10 17:14:58 +0000642 strace_child = pid = fork();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000643 if (pid < 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000644 perror("strace: fork");
645 cleanup();
646 exit(1);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000647 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200648 if ((pid != 0 && daemonized_tracer) /* -D: parent to become a traced process */
649 || (pid == 0 && !daemonized_tracer) /* not -D: child to become a traced process */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000650 ) {
651 pid = getpid();
Roland McGrath02203312007-06-11 22:06:31 +0000652#ifdef USE_PROCFS
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200653 if (outf != stderr) close(fileno(outf));
Roland McGrath02203312007-06-11 22:06:31 +0000654#ifdef MIPS
655 /* Kludge for SGI, see proc_open for details. */
656 sa.sa_handler = foobar;
657 sa.sa_flags = 0;
658 sigemptyset(&sa.sa_mask);
659 sigaction(SIGINT, &sa, NULL);
660#endif /* MIPS */
661#ifndef FREEBSD
662 pause();
663#else /* FREEBSD */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000664 kill(pid, SIGSTOP); /* stop HERE */
Roland McGrath02203312007-06-11 22:06:31 +0000665#endif /* FREEBSD */
666#else /* !USE_PROCFS */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200667 if (outf != stderr)
668 close(fileno(outf));
Roland McGrath02203312007-06-11 22:06:31 +0000669
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000670 if (!daemonized_tracer) {
671 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
672 perror("strace: ptrace(PTRACE_TRACEME, ...)");
673 exit(1);
674 }
675 if (debug)
676 kill(pid, SIGSTOP);
Roland McGrath02203312007-06-11 22:06:31 +0000677 }
Roland McGrath02203312007-06-11 22:06:31 +0000678
679 if (username != NULL || geteuid() == 0) {
680 uid_t run_euid = run_uid;
681 gid_t run_egid = run_gid;
682
683 if (statbuf.st_mode & S_ISUID)
684 run_euid = statbuf.st_uid;
685 if (statbuf.st_mode & S_ISGID)
686 run_egid = statbuf.st_gid;
687
688 /*
689 * It is important to set groups before we
690 * lose privileges on setuid.
691 */
692 if (username != NULL) {
693 if (initgroups(username, run_gid) < 0) {
694 perror("initgroups");
695 exit(1);
696 }
697 if (setregid(run_gid, run_egid) < 0) {
698 perror("setregid");
699 exit(1);
700 }
701 if (setreuid(run_uid, run_euid) < 0) {
702 perror("setreuid");
703 exit(1);
704 }
705 }
706 }
707 else
708 setreuid(run_uid, run_uid);
709
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000710 if (!daemonized_tracer) {
711 /*
712 * Induce an immediate stop so that the parent
713 * will resume us with PTRACE_SYSCALL and display
714 * this execve call normally.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400715 * Unless of course we're on a no-MMU system where
716 * we vfork()-ed, so we cannot stop the child.
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000717 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400718 if (!strace_vforked)
719 kill(getpid(), SIGSTOP);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000720 } else {
721 struct sigaction sv_sigchld;
722 sigaction(SIGCHLD, NULL, &sv_sigchld);
723 /*
724 * Make sure it is not SIG_IGN, otherwise wait
725 * will not block.
726 */
727 signal(SIGCHLD, SIG_DFL);
728 /*
729 * Wait for grandchild to attach to us.
730 * It kills child after that, and wait() unblocks.
731 */
732 alarm(3);
733 wait(NULL);
734 alarm(0);
735 sigaction(SIGCHLD, &sv_sigchld, NULL);
736 }
Roland McGrath02203312007-06-11 22:06:31 +0000737#endif /* !USE_PROCFS */
738
739 execv(pathname, argv);
740 perror("strace: exec");
741 _exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000742 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000743
744 /* We are the tracer. */
Denys Vlasenko75422762011-05-27 14:36:01 +0200745 /* With -D, we are *child* here, IOW: different pid. Fetch it. */
746 strace_tracer_pid = getpid();
747
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000748 tcp = alloctcb(daemonized_tracer ? getppid() : pid);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000749 if (daemonized_tracer) {
750 /* We want subsequent startup_attach() to attach to it. */
751 tcp->flags |= TCB_ATTACHED;
752 }
Roland McGrath02203312007-06-11 22:06:31 +0000753#ifdef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000754 if (proc_open(tcp, 0) < 0) {
755 fprintf(stderr, "trouble opening proc file\n");
756 cleanup();
757 exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000758 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000759#endif /* USE_PROCFS */
Roland McGrath02203312007-06-11 22:06:31 +0000760}
761
Wang Chaob13c0de2010-11-12 17:25:19 +0800762#ifdef LINUX
763/*
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000764 * Test whether the kernel support PTRACE_O_TRACECLONE et al options.
Wang Chaob13c0de2010-11-12 17:25:19 +0800765 * First fork a new child, call ptrace with PTRACE_SETOPTIONS on it,
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000766 * and then see which options are supported by the kernel.
Wang Chaob13c0de2010-11-12 17:25:19 +0800767 */
768static int
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200769test_ptrace_setoptions_followfork(void)
Wang Chaob13c0de2010-11-12 17:25:19 +0800770{
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000771 int pid, expected_grandchild = 0, found_grandchild = 0;
772 const unsigned int test_options = PTRACE_O_TRACECLONE |
773 PTRACE_O_TRACEFORK |
774 PTRACE_O_TRACEVFORK;
Wang Chaob13c0de2010-11-12 17:25:19 +0800775
776 if ((pid = fork()) < 0)
777 return -1;
778 else if (pid == 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000779 if (ptrace(PTRACE_TRACEME, 0, (char *)1, 0) < 0)
Wang Chaob13c0de2010-11-12 17:25:19 +0800780 _exit(1);
Wang Chaob13c0de2010-11-12 17:25:19 +0800781 kill(getpid(), SIGSTOP);
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000782 _exit(fork() < 0);
Wang Chaob13c0de2010-11-12 17:25:19 +0800783 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000784
785 while (1) {
786 int status, tracee_pid;
787
788 tracee_pid = wait(&status);
789 if (tracee_pid == -1) {
790 if (errno == EINTR)
791 continue;
792 else if (errno == ECHILD)
793 break;
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200794 perror("test_ptrace_setoptions_followfork");
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000795 return -1;
796 }
797 if (tracee_pid != pid) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000798 found_grandchild = tracee_pid;
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000799 if (ptrace(PTRACE_CONT, tracee_pid, 0, 0) < 0 &&
800 errno != ESRCH)
801 kill(tracee_pid, SIGKILL);
802 }
803 else if (WIFSTOPPED(status)) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000804 switch (WSTOPSIG(status)) {
805 case SIGSTOP:
806 if (ptrace(PTRACE_SETOPTIONS, pid,
807 NULL, test_options) < 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000808 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800809 return -1;
810 }
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000811 break;
812 case SIGTRAP:
813 if (status >> 16 == PTRACE_EVENT_FORK) {
814 long msg = 0;
815
816 if (ptrace(PTRACE_GETEVENTMSG, pid,
817 NULL, (long) &msg) == 0)
818 expected_grandchild = msg;
819 }
820 break;
Wang Chaob13c0de2010-11-12 17:25:19 +0800821 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000822 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0 &&
823 errno != ESRCH)
824 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800825 }
826 }
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000827 if (expected_grandchild && expected_grandchild == found_grandchild)
Denys Vlasenkof44cce42011-06-21 14:34:10 +0200828 ptrace_setoptions |= test_options;
Wang Chaob13c0de2010-11-12 17:25:19 +0800829 return 0;
830}
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200831
832/*
833 * Test whether the kernel support PTRACE_O_TRACESYSGOOD.
834 * First fork a new child, call ptrace(PTRACE_SETOPTIONS) on it,
835 * and then see whether it will stop with (SIGTRAP | 0x80).
836 *
837 * Use of this option enables correct handling of user-generated SIGTRAPs,
838 * and SIGTRAPs generated by special instructions such as int3 on x86:
839 * _start: .globl _start
840 * int3
841 * movl $42, %ebx
842 * movl $1, %eax
843 * int $0x80
844 * (compile with: "gcc -nostartfiles -nostdlib -o int3 int3.S")
845 */
846static void
847test_ptrace_setoptions_for_all(void)
848{
849 const unsigned int test_options = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC;
850 int pid;
851 int it_worked = 0;
852
853 pid = fork();
854 if (pid < 0)
Denys Vlasenko75422762011-05-27 14:36:01 +0200855 perror_msg_and_die("fork");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200856
857 if (pid == 0) {
858 pid = getpid();
859 if (ptrace(PTRACE_TRACEME, 0L, 0L, 0L) < 0)
Denys Vlasenko75422762011-05-27 14:36:01 +0200860 /* Note: exits with exitcode 1 */
861 perror_msg_and_die("%s: PTRACE_TRACEME doesn't work", __func__);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200862 kill(pid, SIGSTOP);
863 _exit(0); /* parent should see entry into this syscall */
864 }
865
866 while (1) {
867 int status, tracee_pid;
868
869 errno = 0;
870 tracee_pid = wait(&status);
871 if (tracee_pid <= 0) {
872 if (errno == EINTR)
873 continue;
874 kill(pid, SIGKILL);
Denys Vlasenko75422762011-05-27 14:36:01 +0200875 perror_msg_and_die("%s: unexpected wait result %d", __func__, tracee_pid);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200876 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200877 if (WIFEXITED(status)) {
878 if (WEXITSTATUS(status) == 0)
879 break;
880 /* PTRACE_TRACEME failed in child. This is fatal. */
881 exit(1);
882 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200883 if (!WIFSTOPPED(status)) {
884 kill(pid, SIGKILL);
885 error_msg_and_die("%s: unexpected wait status %x", __func__, status);
886 }
887 if (WSTOPSIG(status) == SIGSTOP) {
888 /*
889 * We don't check "options aren't accepted" error.
890 * If it happens, we'll never get (SIGTRAP | 0x80),
891 * and thus will decide to not use the option.
892 * IOW: the outcome of the test will be correct.
893 */
Denys Vlasenko75422762011-05-27 14:36:01 +0200894 if (ptrace(PTRACE_SETOPTIONS, pid, 0L, test_options) < 0)
895 if (errno != EINVAL)
896 perror_msg("PTRACE_SETOPTIONS");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200897 }
898 if (WSTOPSIG(status) == (SIGTRAP | 0x80)) {
899 it_worked = 1;
900 }
901 if (ptrace(PTRACE_SYSCALL, pid, 0L, 0L) < 0) {
902 kill(pid, SIGKILL);
Denys Vlasenko75422762011-05-27 14:36:01 +0200903 perror_msg_and_die("PTRACE_SYSCALL doesn't work");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200904 }
905 }
906
907 if (it_worked) {
Denys Vlasenko75422762011-05-27 14:36:01 +0200908 syscall_trap_sig = (SIGTRAP | 0x80);
Denys Vlasenkof44cce42011-06-21 14:34:10 +0200909 ptrace_setoptions |= test_options;
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200910 if (debug)
Denys Vlasenkof44cce42011-06-21 14:34:10 +0200911 fprintf(stderr, "ptrace_setoptions = %#x\n",
912 ptrace_setoptions);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200913 return;
914 }
915
916 fprintf(stderr,
917 "Test for PTRACE_O_TRACESYSGOOD failed, giving up using this feature.\n");
918}
Wang Chaob13c0de2010-11-12 17:25:19 +0800919#endif
920
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000921int
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000922main(int argc, char *argv[])
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000923{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000924 struct tcb *tcp;
925 int c, pid = 0;
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000926 int optF = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000927 struct sigaction sa;
928
929 static char buf[BUFSIZ];
930
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000931 progname = argv[0] ? argv[0] : "strace";
932
Denys Vlasenko75422762011-05-27 14:36:01 +0200933 strace_tracer_pid = getpid();
934
Roland McGrathee9d4352002-12-18 04:16:10 +0000935 /* Allocate the initial tcbtab. */
936 tcbtabsize = argc; /* Surely enough for all -p args. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000937 if ((tcbtab = calloc(tcbtabsize, sizeof tcbtab[0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000938 fprintf(stderr, "%s: out of memory\n", progname);
939 exit(1);
940 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000941 if ((tcbtab[0] = calloc(tcbtabsize, sizeof tcbtab[0][0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000942 fprintf(stderr, "%s: out of memory\n", progname);
943 exit(1);
944 }
Roland McGrathee9d4352002-12-18 04:16:10 +0000945 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
946 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
947
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000948 outf = stderr;
949 interactive = 1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000950 set_sortby(DEFAULT_SORTBY);
951 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000952 qualify("trace=all");
953 qualify("abbrev=all");
954 qualify("verbose=all");
955 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000956 while ((c = getopt(argc, argv,
Grant Edwards8a082772011-04-07 20:25:40 +0000957 "+cCdfFhiqrtTvVxyz"
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000958#ifndef USE_PROCFS
959 "D"
960#endif
Grant Edwards8a082772011-04-07 20:25:40 +0000961 "a:e:o:O:p:s:S:u:E:P:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000962 switch (c) {
963 case 'c':
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000964 if (cflag == CFLAG_BOTH) {
965 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
966 progname);
967 exit(1);
968 }
969 cflag = CFLAG_ONLY_STATS;
970 break;
971 case 'C':
972 if (cflag == CFLAG_ONLY_STATS) {
973 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
974 progname);
975 exit(1);
976 }
977 cflag = CFLAG_BOTH;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000978 break;
979 case 'd':
980 debug++;
981 break;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000982#ifndef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000983 case 'D':
984 daemonized_tracer = 1;
985 break;
986#endif
Roland McGrath41c48222008-07-18 00:25:10 +0000987 case 'F':
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000988 optF = 1;
989 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000990 case 'f':
991 followfork++;
992 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000993 case 'h':
994 usage(stdout, 0);
995 break;
996 case 'i':
997 iflag++;
998 break;
999 case 'q':
1000 qflag++;
1001 break;
1002 case 'r':
1003 rflag++;
1004 tflag++;
1005 break;
1006 case 't':
1007 tflag++;
1008 break;
1009 case 'T':
1010 dtime++;
1011 break;
1012 case 'x':
1013 xflag++;
1014 break;
Grant Edwards8a082772011-04-07 20:25:40 +00001015 case 'y':
1016 show_fd_path = 1;
1017 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001018 case 'v':
1019 qualify("abbrev=none");
1020 break;
1021 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +00001022 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001023 exit(0);
1024 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +00001025 case 'z':
1026 not_failing_only = 1;
1027 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001028 case 'a':
1029 acolumn = atoi(optarg);
1030 break;
1031 case 'e':
1032 qualify(optarg);
1033 break;
1034 case 'o':
1035 outfname = strdup(optarg);
1036 break;
1037 case 'O':
1038 set_overhead(atoi(optarg));
1039 break;
1040 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +00001041 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001042 fprintf(stderr, "%s: Invalid process id: %s\n",
1043 progname, optarg);
1044 break;
1045 }
Denys Vlasenko75422762011-05-27 14:36:01 +02001046 if (pid == strace_tracer_pid) {
Wichert Akkerman54a47671999-10-17 00:57:34 +00001047 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001048 break;
1049 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001050 tcp = alloc_tcb(pid, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001051 tcp->flags |= TCB_ATTACHED;
1052 pflag_seen++;
1053 break;
Grant Edwards8a082772011-04-07 20:25:40 +00001054 case 'P':
1055 tracing_paths = 1;
1056 if (pathtrace_select(optarg)) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001057 fprintf(stderr, "%s : failed to select path '%s'\n", progname, optarg);
Grant Edwards8a082772011-04-07 20:25:40 +00001058 exit(1);
1059 }
1060 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001061 case 's':
1062 max_strlen = atoi(optarg);
Roland McGrathdccec722005-05-09 07:45:47 +00001063 if (max_strlen < 0) {
1064 fprintf(stderr,
1065 "%s: invalid -s argument: %s\n",
1066 progname, optarg);
1067 exit(1);
1068 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001069 break;
1070 case 'S':
1071 set_sortby(optarg);
1072 break;
1073 case 'u':
1074 username = strdup(optarg);
1075 break;
Roland McGrathde6e5332003-01-24 04:31:23 +00001076 case 'E':
1077 if (putenv(optarg) < 0) {
1078 fprintf(stderr, "%s: out of memory\n",
1079 progname);
1080 exit(1);
1081 }
1082 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001083 default:
1084 usage(stderr, 1);
1085 break;
1086 }
1087 }
1088
Roland McGrathd0c4c0c2006-04-25 07:39:40 +00001089 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +00001090 usage(stderr, 1);
1091
Wang Chaod322a4b2010-08-05 14:30:11 +08001092 if (pflag_seen && daemonized_tracer) {
1093 fprintf(stderr,
1094 "%s: -D and -p are mutually exclusive options\n",
1095 progname);
1096 exit(1);
1097 }
1098
Dmitry V. Levin06350db2008-07-25 15:42:34 +00001099 if (!followfork)
1100 followfork = optF;
1101
Roland McGrathcb9def62006-04-25 07:48:03 +00001102 if (followfork > 1 && cflag) {
1103 fprintf(stderr,
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00001104 "%s: (-c or -C) and -ff are mutually exclusive options\n",
Roland McGrathcb9def62006-04-25 07:48:03 +00001105 progname);
1106 exit(1);
1107 }
1108
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001109 /* See if they want to run as another user. */
1110 if (username != NULL) {
1111 struct passwd *pent;
1112
1113 if (getuid() != 0 || geteuid() != 0) {
1114 fprintf(stderr,
1115 "%s: you must be root to use the -u option\n",
1116 progname);
1117 exit(1);
1118 }
1119 if ((pent = getpwnam(username)) == NULL) {
1120 fprintf(stderr, "%s: cannot find user `%s'\n",
Roland McGrath09553f82007-07-05 19:31:49 +00001121 progname, username);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001122 exit(1);
1123 }
1124 run_uid = pent->pw_uid;
1125 run_gid = pent->pw_gid;
1126 }
1127 else {
1128 run_uid = getuid();
1129 run_gid = getgid();
1130 }
1131
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001132#ifdef LINUX
1133 if (followfork) {
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02001134 if (test_ptrace_setoptions_followfork() < 0) {
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001135 fprintf(stderr,
1136 "Test for options supported by PTRACE_SETOPTIONS "
1137 "failed, giving up using this feature.\n");
Denys Vlasenkof44cce42011-06-21 14:34:10 +02001138 ptrace_setoptions = 0;
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001139 }
1140 if (debug)
Denys Vlasenkof44cce42011-06-21 14:34:10 +02001141 fprintf(stderr, "ptrace_setoptions = %#x\n",
1142 ptrace_setoptions);
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001143 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02001144 test_ptrace_setoptions_for_all();
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001145#endif
1146
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001147 /* Check if they want to redirect the output. */
1148 if (outfname) {
Roland McGrath37b9a662003-11-07 02:26:54 +00001149 /* See if they want to pipe the output. */
1150 if (outfname[0] == '|' || outfname[0] == '!') {
1151 /*
1152 * We can't do the <outfname>.PID funny business
1153 * when using popen, so prohibit it.
1154 */
1155 if (followfork > 1) {
1156 fprintf(stderr, "\
1157%s: piping the output and -ff are mutually exclusive options\n",
1158 progname);
1159 exit(1);
1160 }
1161
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001162 if ((outf = strace_popen(outfname + 1)) == NULL)
Roland McGrath37b9a662003-11-07 02:26:54 +00001163 exit(1);
Roland McGrath37b9a662003-11-07 02:26:54 +00001164 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001165 else if (followfork <= 1 &&
1166 (outf = strace_fopen(outfname, "w")) == NULL)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001167 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001168 }
1169
Roland McGrath37b9a662003-11-07 02:26:54 +00001170 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001171 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +00001172 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001173 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001174 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +00001175 }
Wang Chaob13c0de2010-11-12 17:25:19 +08001176
Roland McGrath54cc1c82007-11-03 23:34:11 +00001177 /* Valid states here:
1178 optind < argc pflag_seen outfname interactive
1179 1 0 0 1
1180 0 1 0 1
1181 1 0 1 0
1182 0 1 1 1
1183 */
1184
1185 /* STARTUP_CHILD must be called before the signal handlers get
1186 installed below as they are inherited into the spawned process.
1187 Also we do not need to be protected by them as during interruption
1188 in the STARTUP_CHILD mode we kill the spawned process anyway. */
1189 if (!pflag_seen)
1190 startup_child(&argv[optind]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001191
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001192 sigemptyset(&empty_set);
1193 sigemptyset(&blocked_set);
1194 sa.sa_handler = SIG_IGN;
1195 sigemptyset(&sa.sa_mask);
1196 sa.sa_flags = 0;
1197 sigaction(SIGTTOU, &sa, NULL);
1198 sigaction(SIGTTIN, &sa, NULL);
1199 if (interactive) {
1200 sigaddset(&blocked_set, SIGHUP);
1201 sigaddset(&blocked_set, SIGINT);
1202 sigaddset(&blocked_set, SIGQUIT);
1203 sigaddset(&blocked_set, SIGPIPE);
1204 sigaddset(&blocked_set, SIGTERM);
1205 sa.sa_handler = interrupt;
1206#ifdef SUNOS4
1207 /* POSIX signals on sunos4.1 are a little broken. */
1208 sa.sa_flags = SA_INTERRUPT;
1209#endif /* SUNOS4 */
1210 }
1211 sigaction(SIGHUP, &sa, NULL);
1212 sigaction(SIGINT, &sa, NULL);
1213 sigaction(SIGQUIT, &sa, NULL);
1214 sigaction(SIGPIPE, &sa, NULL);
1215 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001216#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001217 sa.sa_handler = reaper;
1218 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +00001219#else
1220 /* Make sure SIGCHLD has the default action so that waitpid
1221 definitely works without losing track of children. The user
1222 should not have given us a bogus state to inherit, but he might
1223 have. Arguably we should detect SIG_IGN here and pass it on
1224 to children, but probably noone really needs that. */
1225 sa.sa_handler = SIG_DFL;
1226 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001227#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001228
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +00001229 if (pflag_seen || daemonized_tracer)
Roland McGrath02203312007-06-11 22:06:31 +00001230 startup_attach();
Roland McGrath02203312007-06-11 22:06:31 +00001231
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001232 if (trace() < 0)
1233 exit(1);
1234 cleanup();
Dmitry V. Levina6809652008-11-10 17:14:58 +00001235 fflush(NULL);
1236 if (exit_code > 0xff) {
1237 /* Child was killed by a signal, mimic that. */
1238 exit_code &= 0xff;
1239 signal(exit_code, SIG_DFL);
1240 raise(exit_code);
1241 /* Paranoia - what if this signal is not fatal?
1242 Exit with 128 + signo then. */
1243 exit_code += 128;
1244 }
1245 exit(exit_code);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001246}
1247
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001248void
1249expand_tcbtab(void)
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001250{
1251 /* Allocate some more TCBs and expand the table.
1252 We don't want to relocate the TCBs because our
1253 callers have pointers and it would be a pain.
1254 So tcbtab is a table of pointers. Since we never
1255 free the TCBs, we allocate a single chunk of many. */
1256 struct tcb **newtab = (struct tcb **)
1257 realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
1258 struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
1259 sizeof *newtcbs);
1260 int i;
1261 if (newtab == NULL || newtcbs == NULL) {
Dmitry V. Levin76860f62006-10-11 22:55:25 +00001262 fprintf(stderr, "%s: expand_tcbtab: out of memory\n",
1263 progname);
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001264 cleanup();
1265 exit(1);
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001266 }
1267 for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
1268 newtab[i] = &newtcbs[i - tcbtabsize];
1269 tcbtabsize *= 2;
1270 tcbtab = newtab;
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001271}
1272
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001273struct tcb *
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001274alloc_tcb(int pid, int command_options_parsed)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001275{
1276 int i;
1277 struct tcb *tcp;
1278
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001279 if (nprocs == tcbtabsize)
1280 expand_tcbtab();
1281
Roland McGrathee9d4352002-12-18 04:16:10 +00001282 for (i = 0; i < tcbtabsize; i++) {
1283 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001284 if ((tcp->flags & TCB_INUSE) == 0) {
1285 tcp->pid = pid;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001286 tcp->parent = NULL;
1287 tcp->nchildren = 0;
1288 tcp->nzombies = 0;
1289#ifdef TCB_CLONE_THREAD
Wang Chao21b8db42010-08-27 17:43:16 +08001290 tcp->nclone_threads = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001291#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001292 tcp->flags = TCB_INUSE | TCB_STARTUP;
1293 tcp->outf = outf; /* Initialise to current out file */
Andreas Schwabccdff482009-10-27 16:27:13 +01001294 tcp->curcol = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001295 tcp->stime.tv_sec = 0;
1296 tcp->stime.tv_usec = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001297 tcp->pfd = -1;
1298 nprocs++;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001299 if (command_options_parsed)
1300 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001301 return tcp;
1302 }
1303 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001304 fprintf(stderr, "%s: bug in alloc_tcb\n", progname);
1305 cleanup();
1306 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001307}
1308
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001309#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001310int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001311proc_open(struct tcb *tcp, int attaching)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001312{
1313 char proc[32];
1314 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001315#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +00001316 int i;
1317 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001318 sigset_t signals;
1319 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001320#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001321#ifndef HAVE_POLLABLE_PROCFS
1322 static int last_pfd;
1323#endif
1324
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001325#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001326 /* Open the process pseudo-files in /proc. */
1327 sprintf(proc, "/proc/%d/ctl", tcp->pid);
1328 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001329 perror("strace: open(\"/proc/...\", ...)");
1330 return -1;
1331 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001332 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001333 return -1;
1334 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001335 sprintf(proc, "/proc/%d/status", tcp->pid);
1336 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
1337 perror("strace: open(\"/proc/...\", ...)");
1338 return -1;
1339 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001340 if (set_cloexec_flag(tcp->pfd_stat) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001341 return -1;
1342 }
1343 sprintf(proc, "/proc/%d/as", tcp->pid);
1344 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
1345 perror("strace: open(\"/proc/...\", ...)");
1346 return -1;
1347 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001348 if (set_cloexec_flag(tcp->pfd_as) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001349 return -1;
1350 }
1351#else
1352 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001353#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001354 sprintf(proc, "/proc/%d", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001355 tcp->pfd = open(proc, O_RDWR|O_EXCL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001356#else /* FREEBSD */
1357 sprintf(proc, "/proc/%d/mem", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001358 tcp->pfd = open(proc, O_RDWR);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001359#endif /* FREEBSD */
Andreas Schwab372cc842010-07-09 11:49:27 +02001360 if (tcp->pfd < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001361 perror("strace: open(\"/proc/...\", ...)");
1362 return -1;
1363 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001364 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001365 return -1;
1366 }
1367#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001368#ifdef FREEBSD
1369 sprintf(proc, "/proc/%d/regs", tcp->pid);
1370 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
1371 perror("strace: open(\"/proc/.../regs\", ...)");
1372 return -1;
1373 }
1374 if (cflag) {
1375 sprintf(proc, "/proc/%d/status", tcp->pid);
1376 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
1377 perror("strace: open(\"/proc/.../status\", ...)");
1378 return -1;
1379 }
1380 } else
1381 tcp->pfd_status = -1;
1382#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001383 rebuild_pollv();
1384 if (!attaching) {
1385 /*
1386 * Wait for the child to pause. Because of a race
1387 * condition we have to poll for the event.
1388 */
1389 for (;;) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001390 if (IOCTL_STATUS(tcp) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001391 perror("strace: PIOCSTATUS");
1392 return -1;
1393 }
1394 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001395 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001396 }
1397 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001398#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001399 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001400 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001401 perror("strace: PIOCSTOP");
1402 return -1;
1403 }
Roland McGrath553a6092002-12-16 20:40:39 +00001404#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001405#ifdef PIOCSET
1406 /* Set Run-on-Last-Close. */
1407 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001408 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001409 perror("PIOCSET PR_RLC");
1410 return -1;
1411 }
1412 /* Set or Reset Inherit-on-Fork. */
1413 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001414 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001415 perror("PIOC{SET,RESET} PR_FORK");
1416 return -1;
1417 }
1418#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +00001419#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001420 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
1421 perror("PIOCSRLC");
1422 return -1;
1423 }
1424 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
1425 perror("PIOC{S,R}FORK");
1426 return -1;
1427 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001428#else /* FREEBSD */
1429 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
1430 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
1431 perror("PIOCGFL");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001432 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001433 }
1434 arg &= ~PF_LINGER;
1435 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001436 perror("PIOCSFL");
1437 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001438 }
1439#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001440#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001441#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +00001442 /* Enable all syscall entries we care about. */
1443 premptyset(&syscalls);
1444 for (i = 1; i < MAX_QUALS; ++i) {
1445 if (i > (sizeof syscalls) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001446 if (qual_flags[i] & QUAL_TRACE) praddset(&syscalls, i);
John Hughes19e49982001-10-19 08:59:12 +00001447 }
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001448 praddset(&syscalls, SYS_execve);
John Hughes19e49982001-10-19 08:59:12 +00001449 if (followfork) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001450 praddset(&syscalls, SYS_fork);
John Hughes19e49982001-10-19 08:59:12 +00001451#ifdef SYS_forkall
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001452 praddset(&syscalls, SYS_forkall);
John Hughes19e49982001-10-19 08:59:12 +00001453#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001454#ifdef SYS_fork1
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001455 praddset(&syscalls, SYS_fork1);
John Hughes19e49982001-10-19 08:59:12 +00001456#endif
1457#ifdef SYS_rfork1
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001458 praddset(&syscalls, SYS_rfork1);
John Hughes19e49982001-10-19 08:59:12 +00001459#endif
1460#ifdef SYS_rforkall
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001461 praddset(&syscalls, SYS_rforkall);
John Hughes19e49982001-10-19 08:59:12 +00001462#endif
1463 }
1464 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001465 perror("PIOCSENTRY");
1466 return -1;
1467 }
John Hughes19e49982001-10-19 08:59:12 +00001468 /* Enable the syscall exits. */
1469 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001470 perror("PIOSEXIT");
1471 return -1;
1472 }
John Hughes19e49982001-10-19 08:59:12 +00001473 /* Enable signals we care about. */
1474 premptyset(&signals);
1475 for (i = 1; i < MAX_QUALS; ++i) {
1476 if (i > (sizeof signals) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001477 if (qual_flags[i] & QUAL_SIGNAL) praddset(&signals, i);
John Hughes19e49982001-10-19 08:59:12 +00001478 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001479 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001480 perror("PIOCSTRACE");
1481 return -1;
1482 }
John Hughes19e49982001-10-19 08:59:12 +00001483 /* Enable faults we care about */
1484 premptyset(&faults);
1485 for (i = 1; i < MAX_QUALS; ++i) {
1486 if (i > (sizeof faults) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001487 if (qual_flags[i] & QUAL_FAULT) praddset(&faults, i);
John Hughes19e49982001-10-19 08:59:12 +00001488 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001489 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001490 perror("PIOCSFAULT");
1491 return -1;
1492 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001493#else /* FREEBSD */
1494 /* set events flags. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001495 arg = S_SIG | S_SCE | S_SCX;
1496 if (ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001497 perror("PIOCBIS");
1498 return -1;
1499 }
1500#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001501 if (!attaching) {
1502#ifdef MIPS
1503 /*
1504 * The SGI PRSABORT doesn't work for pause() so
1505 * we send it a caught signal to wake it up.
1506 */
1507 kill(tcp->pid, SIGINT);
1508#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +00001509#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001510 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001511 arg = PRSABORT;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001512 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001513 perror("PIOCRUN");
1514 return -1;
1515 }
Roland McGrath553a6092002-12-16 20:40:39 +00001516#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001517#endif /* !MIPS*/
1518#ifdef FREEBSD
1519 /* wake up the child if it received the SIGSTOP */
1520 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001521#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001522 for (;;) {
1523 /* Wait for the child to do something. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001524 if (IOCTL_WSTOP(tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001525 perror("PIOCWSTOP");
1526 return -1;
1527 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001528 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001529 tcp->flags &= ~TCB_INSYSCALL;
1530 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001531 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001532 break;
1533 }
1534 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001535#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001536 arg = 0;
1537 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001538#else /* FREEBSD */
1539 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001540#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001541 perror("PIOCRUN");
1542 return -1;
1543 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001544#ifdef FREEBSD
1545 /* handle the case where we "opened" the child before
1546 it did the kill -STOP */
1547 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1548 tcp->status.PR_WHAT == SIGSTOP)
1549 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001550#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001551 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001552#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001553 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001554#else /* FREEBSD */
1555 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001556 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001557 /* We are attaching to an already running process.
1558 * Try to figure out the state of the process in syscalls,
1559 * to handle the first event well.
1560 * This is done by having a look at the "wchan" property of the
1561 * process, which tells where it is stopped (if it is). */
1562 FILE * status;
1563 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001564
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001565 sprintf(proc, "/proc/%d/status", tcp->pid);
1566 status = fopen(proc, "r");
1567 if (status &&
1568 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1569 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1570 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1571 strcmp(wchan, "stopevent")) {
1572 /* The process is asleep in the middle of a syscall.
1573 Fake the syscall entry event */
1574 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1575 tcp->status.PR_WHY = PR_SYSENTRY;
1576 trace_syscall(tcp);
1577 }
1578 if (status)
1579 fclose(status);
1580 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001581 }
1582#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001583#ifndef HAVE_POLLABLE_PROCFS
1584 if (proc_poll_pipe[0] != -1)
1585 proc_poller(tcp->pfd);
1586 else if (nprocs > 1) {
1587 proc_poll_open();
1588 proc_poller(last_pfd);
1589 proc_poller(tcp->pfd);
1590 }
1591 last_pfd = tcp->pfd;
1592#endif /* !HAVE_POLLABLE_PROCFS */
1593 return 0;
1594}
1595
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001596#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001597
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001598struct tcb *
Roland McGrath54e931f2010-09-14 18:59:20 -07001599pid2tcb(int pid)
1600{
1601 int i;
1602
1603 if (pid <= 0)
1604 return NULL;
1605
1606 for (i = 0; i < tcbtabsize; i++) {
1607 struct tcb *tcp = tcbtab[i];
1608 if (tcp->pid == pid && (tcp->flags & TCB_INUSE))
1609 return tcp;
1610 }
1611
1612 return NULL;
1613}
1614
1615#ifdef USE_PROCFS
1616
1617static struct tcb *
1618first_used_tcb(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001619{
1620 int i;
1621 struct tcb *tcp;
Roland McGrathee9d4352002-12-18 04:16:10 +00001622 for (i = 0; i < tcbtabsize; i++) {
1623 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001624 if (tcp->flags & TCB_INUSE)
1625 return tcp;
1626 }
1627 return NULL;
1628}
1629
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001630static struct tcb *
Denys Vlasenko12014262011-05-30 14:00:14 +02001631pfd2tcb(int pfd)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001632{
1633 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001634
Roland McGrathca16be82003-01-10 19:55:28 +00001635 for (i = 0; i < tcbtabsize; i++) {
1636 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001637 if (tcp->pfd != pfd)
1638 continue;
1639 if (tcp->flags & TCB_INUSE)
1640 return tcp;
1641 }
1642 return NULL;
1643}
1644
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001645#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001646
1647void
Denys Vlasenko12014262011-05-30 14:00:14 +02001648droptcb(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001649{
1650 if (tcp->pid == 0)
1651 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001652#ifdef TCB_CLONE_THREAD
1653 if (tcp->nclone_threads > 0) {
1654 /* There are other threads left in this process, but this
1655 is the one whose PID represents the whole process.
1656 We need to keep this record around as a zombie until
1657 all the threads die. */
1658 tcp->flags |= TCB_EXITING;
1659 return;
1660 }
1661#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001662 nprocs--;
1663 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001664
Roland McGrathe29341c2003-01-10 20:14:20 +00001665 if (tcp->parent != NULL) {
1666 tcp->parent->nchildren--;
1667#ifdef TCB_CLONE_THREAD
Roland McGrathe29341c2003-01-10 20:14:20 +00001668 if (tcp->flags & TCB_CLONE_THREAD)
1669 tcp->parent->nclone_threads--;
1670#endif
Wang Chao21b8db42010-08-27 17:43:16 +08001671 tcp->parent->nzombies++;
Roland McGrath276ceb32007-11-13 08:12:12 +00001672#ifdef LINUX
1673 /* Update `tcp->parent->parent->nchildren' and the other fields
1674 like NCLONE_DETACHED, only for zombie group leader that has
1675 already reported and been short-circuited at the top of this
1676 function. The same condition as at the top of DETACH. */
1677 if ((tcp->flags & TCB_CLONE_THREAD) &&
1678 tcp->parent->nclone_threads == 0 &&
1679 (tcp->parent->flags & TCB_EXITING))
1680 droptcb(tcp->parent);
1681#endif
Roland McGrathe29341c2003-01-10 20:14:20 +00001682 tcp->parent = NULL;
1683 }
1684
1685 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001686 if (tcp->pfd != -1) {
1687 close(tcp->pfd);
1688 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001689#ifdef FREEBSD
1690 if (tcp->pfd_reg != -1) {
1691 close(tcp->pfd_reg);
1692 tcp->pfd_reg = -1;
1693 }
1694 if (tcp->pfd_status != -1) {
1695 close(tcp->pfd_status);
1696 tcp->pfd_status = -1;
1697 }
Roland McGrath553a6092002-12-16 20:40:39 +00001698#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001699#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001700 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001701#endif
1702 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001703
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001704 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001705 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001706
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001707 tcp->outf = 0;
1708}
1709
Roland McGrath0a463882007-07-05 18:43:16 +00001710/* detach traced process; continue with sig
1711 Never call DETACH twice on the same process as both unattached and
1712 attached-unstopped processes give the same ESRCH. For unattached process we
1713 would SIGSTOP it and wait for its SIGSTOP notification forever. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001714
1715static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001716detach(struct tcb *tcp, int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001717{
1718 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001719#ifdef LINUX
Roland McGrath1bfd3102007-08-03 10:02:00 +00001720 int status, catch_sigstop;
Roland McGratha08a97e2005-08-03 11:23:46 +00001721 struct tcb *zombie = NULL;
1722
1723 /* If the group leader is lingering only because of this other
1724 thread now dying, then detach the leader as well. */
1725 if ((tcp->flags & TCB_CLONE_THREAD) &&
1726 tcp->parent->nclone_threads == 1 &&
1727 (tcp->parent->flags & TCB_EXITING))
1728 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001729#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001730
1731 if (tcp->flags & TCB_BPTSET)
Andreas Schwab840d85b2010-01-12 11:16:32 +01001732 clearbpt(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001733
1734#ifdef LINUX
1735 /*
1736 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001737 * before detaching. Arghh. We go through hoops
1738 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001739 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001740#if defined(SPARC)
1741#undef PTRACE_DETACH
1742#define PTRACE_DETACH PTRACE_SUNDETACH
1743#endif
Roland McGrath02203312007-06-11 22:06:31 +00001744 /*
1745 * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
1746 * expected SIGSTOP. We must catch exactly one as otherwise the
1747 * detached process would be left stopped (process state T).
1748 */
1749 catch_sigstop = (tcp->flags & TCB_STARTUP);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001750 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1751 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001752 }
1753 else if (errno != ESRCH) {
1754 /* Shouldn't happen. */
1755 perror("detach: ptrace(PTRACE_DETACH, ...)");
1756 }
Roland McGrath134813a2007-06-02 00:07:33 +00001757 else if (my_tgkill((tcp->flags & TCB_CLONE_THREAD ? tcp->parent->pid
1758 : tcp->pid),
1759 tcp->pid, 0) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001760 if (errno != ESRCH)
1761 perror("detach: checking sanity");
1762 }
Roland McGrath02203312007-06-11 22:06:31 +00001763 else if (!catch_sigstop && my_tgkill((tcp->flags & TCB_CLONE_THREAD
1764 ? tcp->parent->pid : tcp->pid),
1765 tcp->pid, SIGSTOP) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001766 if (errno != ESRCH)
1767 perror("detach: stopping child");
1768 }
Roland McGrath02203312007-06-11 22:06:31 +00001769 else
1770 catch_sigstop = 1;
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001771 if (catch_sigstop) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001772 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001773#ifdef __WALL
1774 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1775 if (errno == ECHILD) /* Already gone. */
1776 break;
1777 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001778 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001779 break;
1780 }
1781#endif /* __WALL */
1782 /* No __WALL here. */
1783 if (waitpid(tcp->pid, &status, 0) < 0) {
1784 if (errno != ECHILD) {
1785 perror("detach: waiting");
1786 break;
1787 }
1788#ifdef __WCLONE
1789 /* If no processes, try clones. */
1790 if (wait4(tcp->pid, &status, __WCLONE,
1791 NULL) < 0) {
1792 if (errno != ECHILD)
1793 perror("detach: waiting");
1794 break;
1795 }
1796#endif /* __WCLONE */
1797 }
1798#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001799 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001800#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001801 if (!WIFSTOPPED(status)) {
1802 /* Au revoir, mon ami. */
1803 break;
1804 }
1805 if (WSTOPSIG(status) == SIGSTOP) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001806 ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001807 break;
1808 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001809 error = ptrace_restart(PTRACE_CONT, tcp,
Denys Vlasenko75422762011-05-27 14:36:01 +02001810 WSTOPSIG(status) == syscall_trap_sig ? 0
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001811 : WSTOPSIG(status));
1812 if (error < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001813 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001814 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001815 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001816#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001817
1818#if defined(SUNOS4)
1819 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1820 if (sig && kill(tcp->pid, sig) < 0)
1821 perror("detach: kill");
1822 sig = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001823 error = ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001824#endif /* SUNOS4 */
1825
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001826 if (!qflag)
1827 fprintf(stderr, "Process %u detached\n", tcp->pid);
1828
1829 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001830
1831#ifdef LINUX
Roland McGrath0a463882007-07-05 18:43:16 +00001832 if (zombie != NULL) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001833 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath0a463882007-07-05 18:43:16 +00001834 droptcb(zombie);
1835 }
Roland McGratha08a97e2005-08-03 11:23:46 +00001836#endif
1837
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001838 return error;
1839}
1840
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001841#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001842
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001843static void reaper(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001844{
1845 int pid;
1846 int status;
1847
1848 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001849 }
1850}
1851
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001852#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001853
1854static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001855cleanup(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001856{
1857 int i;
1858 struct tcb *tcp;
1859
Roland McGrathee9d4352002-12-18 04:16:10 +00001860 for (i = 0; i < tcbtabsize; i++) {
1861 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001862 if (!(tcp->flags & TCB_INUSE))
1863 continue;
1864 if (debug)
1865 fprintf(stderr,
1866 "cleanup: looking at pid %u\n", tcp->pid);
1867 if (tcp_last &&
1868 (!outfname || followfork < 2 || tcp_last == tcp)) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001869 tprintf(" <unfinished ...>");
1870 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001871 }
1872 if (tcp->flags & TCB_ATTACHED)
1873 detach(tcp, 0);
1874 else {
1875 kill(tcp->pid, SIGCONT);
1876 kill(tcp->pid, SIGTERM);
1877 }
1878 }
1879 if (cflag)
1880 call_summary(outf);
1881}
1882
1883static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001884interrupt(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001885{
1886 interrupted = 1;
1887}
1888
1889#ifndef HAVE_STRERROR
1890
Roland McGrath6d2b3492002-12-30 00:51:30 +00001891#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001892extern int sys_nerr;
1893extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001894#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001895
1896const char *
Denys Vlasenko12014262011-05-30 14:00:14 +02001897strerror(int err_no)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001898{
1899 static char buf[64];
1900
Denys Vlasenko35aba6a2011-05-25 15:33:26 +02001901 if (err_no < 1 || err_no >= sys_nerr) {
1902 sprintf(buf, "Unknown error %d", err_no);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001903 return buf;
1904 }
Denys Vlasenko35aba6a2011-05-25 15:33:26 +02001905 return sys_errlist[err_no];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001906}
1907
1908#endif /* HAVE_STERRROR */
1909
1910#ifndef HAVE_STRSIGNAL
1911
Roland McGrath8f474e02003-01-14 07:53:33 +00001912#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001913extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001914#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001915#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1916extern char *_sys_siglist[];
1917#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001918
1919const char *
Denys Vlasenko12014262011-05-30 14:00:14 +02001920strsignal(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001921{
1922 static char buf[64];
1923
1924 if (sig < 1 || sig >= NSIG) {
1925 sprintf(buf, "Unknown signal %d", sig);
1926 return buf;
1927 }
1928#ifdef HAVE__SYS_SIGLIST
1929 return _sys_siglist[sig];
1930#else
1931 return sys_siglist[sig];
1932#endif
1933}
1934
1935#endif /* HAVE_STRSIGNAL */
1936
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001937#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001938
1939static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001940rebuild_pollv(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001941{
1942 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001943
Roland McGrathee9d4352002-12-18 04:16:10 +00001944 if (pollv != NULL)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001945 free(pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001946 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001947 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001948 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00001949 exit(1);
1950 }
1951
Roland McGrathca16be82003-01-10 19:55:28 +00001952 for (i = j = 0; i < tcbtabsize; i++) {
1953 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001954 if (!(tcp->flags & TCB_INUSE))
1955 continue;
1956 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001957 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001958 j++;
1959 }
1960 if (j != nprocs) {
1961 fprintf(stderr, "strace: proc miscount\n");
1962 exit(1);
1963 }
1964}
1965
1966#ifndef HAVE_POLLABLE_PROCFS
1967
1968static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001969proc_poll_open(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001970{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001971 int i;
1972
1973 if (pipe(proc_poll_pipe) < 0) {
1974 perror("pipe");
1975 exit(1);
1976 }
1977 for (i = 0; i < 2; i++) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001978 if (set_cloexec_flag(proc_poll_pipe[i]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001979 exit(1);
1980 }
1981 }
1982}
1983
1984static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001985proc_poll(struct pollfd *pollv, int nfds, int timeout)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001986{
1987 int i;
1988 int n;
1989 struct proc_pollfd pollinfo;
1990
1991 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1992 return n;
1993 if (n != sizeof(struct proc_pollfd)) {
1994 fprintf(stderr, "panic: short read: %d\n", n);
1995 exit(1);
1996 }
1997 for (i = 0; i < nprocs; i++) {
1998 if (pollv[i].fd == pollinfo.fd)
1999 pollv[i].revents = pollinfo.revents;
2000 else
2001 pollv[i].revents = 0;
2002 }
2003 poller_pid = pollinfo.pid;
2004 return 1;
2005}
2006
2007static void
Denys Vlasenko12014262011-05-30 14:00:14 +02002008wakeup_handler(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002009{
2010}
2011
2012static void
Denys Vlasenko12014262011-05-30 14:00:14 +02002013proc_poller(int pfd)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002014{
2015 struct proc_pollfd pollinfo;
2016 struct sigaction sa;
2017 sigset_t blocked_set, empty_set;
2018 int i;
2019 int n;
2020 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002021#ifdef FREEBSD
2022 struct procfs_status pfs;
2023#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002024
2025 switch (fork()) {
2026 case -1:
2027 perror("fork");
Dmitry V. Levina6809652008-11-10 17:14:58 +00002028 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002029 case 0:
2030 break;
2031 default:
2032 return;
2033 }
2034
2035 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
2036 sa.sa_flags = 0;
2037 sigemptyset(&sa.sa_mask);
2038 sigaction(SIGHUP, &sa, NULL);
2039 sigaction(SIGINT, &sa, NULL);
2040 sigaction(SIGQUIT, &sa, NULL);
2041 sigaction(SIGPIPE, &sa, NULL);
2042 sigaction(SIGTERM, &sa, NULL);
2043 sa.sa_handler = wakeup_handler;
2044 sigaction(SIGUSR1, &sa, NULL);
2045 sigemptyset(&blocked_set);
2046 sigaddset(&blocked_set, SIGUSR1);
2047 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2048 sigemptyset(&empty_set);
2049
2050 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
2051 perror("getrlimit(RLIMIT_NOFILE, ...)");
Dmitry V. Levina6809652008-11-10 17:14:58 +00002052 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002053 }
2054 n = rl.rlim_cur;
2055 for (i = 0; i < n; i++) {
2056 if (i != pfd && i != proc_poll_pipe[1])
2057 close(i);
2058 }
2059
2060 pollinfo.fd = pfd;
2061 pollinfo.pid = getpid();
2062 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002063#ifndef FREEBSD
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002064 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
2065#else
2066 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
2067#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002068 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002069 switch (errno) {
2070 case EINTR:
2071 continue;
2072 case EBADF:
2073 pollinfo.revents = POLLERR;
2074 break;
2075 case ENOENT:
2076 pollinfo.revents = POLLHUP;
2077 break;
2078 default:
2079 perror("proc_poller: PIOCWSTOP");
2080 }
2081 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2082 _exit(0);
2083 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002084 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002085 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2086 sigsuspend(&empty_set);
2087 }
2088}
2089
2090#endif /* !HAVE_POLLABLE_PROCFS */
2091
2092static int
2093choose_pfd()
2094{
2095 int i, j;
2096 struct tcb *tcp;
2097
2098 static int last;
2099
2100 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002101 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002102 /*
2103 * The previous process is ready to run again. We'll
2104 * let it do so if it is currently in a syscall. This
2105 * heuristic improves the readability of the trace.
2106 */
2107 tcp = pfd2tcb(pollv[last].fd);
2108 if (tcp && (tcp->flags & TCB_INSYSCALL))
2109 return pollv[last].fd;
2110 }
2111
2112 for (i = 0; i < nprocs; i++) {
2113 /* Let competing children run round robin. */
2114 j = (i + last + 1) % nprocs;
2115 if (pollv[j].revents & (POLLHUP | POLLERR)) {
2116 tcp = pfd2tcb(pollv[j].fd);
2117 if (!tcp) {
2118 fprintf(stderr, "strace: lost proc\n");
2119 exit(1);
2120 }
2121 droptcb(tcp);
2122 return -1;
2123 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002124 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002125 last = j;
2126 return pollv[j].fd;
2127 }
2128 }
2129 fprintf(stderr, "strace: nothing ready\n");
2130 exit(1);
2131}
2132
2133static int
Denys Vlasenko12014262011-05-30 14:00:14 +02002134trace(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002135{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002136#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00002137 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002138#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002139 struct tcb *tcp;
2140 int pfd;
2141 int what;
2142 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002143 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002144
2145 for (;;) {
2146 if (interactive)
2147 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2148
2149 if (nprocs == 0)
2150 break;
2151
2152 switch (nprocs) {
2153 case 1:
2154#ifndef HAVE_POLLABLE_PROCFS
2155 if (proc_poll_pipe[0] == -1) {
2156#endif
Roland McGrath54e931f2010-09-14 18:59:20 -07002157 tcp = first_used_tcb();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002158 if (!tcp)
2159 continue;
2160 pfd = tcp->pfd;
2161 if (pfd == -1)
2162 continue;
2163 break;
2164#ifndef HAVE_POLLABLE_PROCFS
2165 }
2166 /* fall through ... */
2167#endif /* !HAVE_POLLABLE_PROCFS */
2168 default:
2169#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002170#ifdef POLL_HACK
2171 /* On some systems (e.g. UnixWare) we get too much ugly
2172 "unfinished..." stuff when multiple proceses are in
2173 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00002174
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002175 if (in_syscall) {
2176 struct pollfd pv;
2177 tcp = in_syscall;
2178 in_syscall = NULL;
2179 pv.fd = tcp->pfd;
2180 pv.events = POLLWANT;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002181 if ((what = poll(&pv, 1, 1)) < 0) {
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002182 if (interrupted)
2183 return 0;
2184 continue;
2185 }
2186 else if (what == 1 && pv.revents & POLLWANT) {
2187 goto FOUND;
2188 }
2189 }
2190#endif
2191
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002192 if (poll(pollv, nprocs, INFTIM) < 0) {
2193 if (interrupted)
2194 return 0;
2195 continue;
2196 }
2197#else /* !HAVE_POLLABLE_PROCFS */
2198 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
2199 if (interrupted)
2200 return 0;
2201 continue;
2202 }
2203#endif /* !HAVE_POLLABLE_PROCFS */
2204 pfd = choose_pfd();
2205 if (pfd == -1)
2206 continue;
2207 break;
2208 }
2209
2210 /* Look up `pfd' in our table. */
2211 if ((tcp = pfd2tcb(pfd)) == NULL) {
2212 fprintf(stderr, "unknown pfd: %u\n", pfd);
2213 exit(1);
2214 }
John Hughesb6643082002-05-23 11:02:22 +00002215#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002216 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00002217#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002218 /* Get the status of the process. */
2219 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002220#ifndef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002221 ioctl_result = IOCTL_WSTOP(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002222#else /* FREEBSD */
2223 /* Thanks to some scheduling mystery, the first poller
2224 sometimes waits for the already processed end of fork
2225 event. Doing a non blocking poll here solves the problem. */
2226 if (proc_poll_pipe[0] != -1)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002227 ioctl_result = IOCTL_STATUS(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002228 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002229 ioctl_result = IOCTL_WSTOP(tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00002230#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002231 ioctl_errno = errno;
2232#ifndef HAVE_POLLABLE_PROCFS
2233 if (proc_poll_pipe[0] != -1) {
2234 if (ioctl_result < 0)
2235 kill(poller_pid, SIGKILL);
2236 else
2237 kill(poller_pid, SIGUSR1);
2238 }
2239#endif /* !HAVE_POLLABLE_PROCFS */
2240 }
2241 if (interrupted)
2242 return 0;
2243
2244 if (interactive)
2245 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2246
2247 if (ioctl_result < 0) {
2248 /* Find out what happened if it failed. */
2249 switch (ioctl_errno) {
2250 case EINTR:
2251 case EBADF:
2252 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002253#ifdef FREEBSD
2254 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00002255#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002256 case ENOENT:
2257 droptcb(tcp);
2258 continue;
2259 default:
2260 perror("PIOCWSTOP");
2261 exit(1);
2262 }
2263 }
2264
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002265#ifdef FREEBSD
2266 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2267 /* discard first event for a syscall we never entered */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002268 IOCTL(tcp->pfd, PIOCRUN, 0);
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002269 continue;
2270 }
Roland McGrath553a6092002-12-16 20:40:39 +00002271#endif
2272
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002273 /* clear the just started flag */
2274 tcp->flags &= ~TCB_STARTUP;
2275
2276 /* set current output file */
2277 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002278 curcol = tcp->curcol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002279
2280 if (cflag) {
2281 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002282#ifdef FREEBSD
2283 char buf[1024];
2284 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002285
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002286 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
2287 buf[len] = '\0';
2288 sscanf(buf,
2289 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2290 &stime.tv_sec, &stime.tv_usec);
2291 } else
2292 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002293#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002294 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2295 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002296#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002297 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2298 tcp->stime = stime;
2299 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002300 what = tcp->status.PR_WHAT;
2301 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002302#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002303 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002304 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2305 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002306 if (trace_syscall(tcp) < 0) {
2307 fprintf(stderr, "syscall trouble\n");
2308 exit(1);
2309 }
2310 }
2311 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002312#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002313 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002314#ifdef POLL_HACK
2315 in_syscall = tcp;
2316#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002317 case PR_SYSEXIT:
2318 if (trace_syscall(tcp) < 0) {
2319 fprintf(stderr, "syscall trouble\n");
2320 exit(1);
2321 }
2322 break;
2323 case PR_SIGNALLED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002324 if (cflag != CFLAG_ONLY_STATS
2325 && (qual_flags[what] & QUAL_SIGNAL)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002326 printleader(tcp);
2327 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002328 signame(what), strsignal(what));
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002329 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002330#ifdef PR_INFO
2331 if (tcp->status.PR_INFO.si_signo == what) {
2332 printleader(tcp);
2333 tprintf(" siginfo=");
2334 printsiginfo(&tcp->status.PR_INFO, 1);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002335 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002336 }
2337#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002338 }
2339 break;
2340 case PR_FAULTED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002341 if (cflag != CFLAGS_ONLY_STATS
2342 && (qual_flags[what] & QUAL_FAULT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002343 printleader(tcp);
2344 tprintf("=== FAULT %d ===", what);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002345 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002346 }
2347 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002348#ifdef FREEBSD
2349 case 0: /* handle case we polled for nothing */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002350 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00002351#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002352 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002353 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002354 exit(1);
2355 break;
2356 }
Andreas Schwabccdff482009-10-27 16:27:13 +01002357 /* Remember current print column before continuing. */
2358 tcp->curcol = curcol;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002359 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002360#ifndef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002361 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002362#else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002363 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002364#endif
Andreas Schwab372cc842010-07-09 11:49:27 +02002365 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002366 perror("PIOCRUN");
2367 exit(1);
2368 }
2369 }
2370 return 0;
2371}
2372
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002373#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002374
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002375#ifdef TCB_GROUP_EXITING
2376/* Handle an exit detach or death signal that is taking all the
2377 related clone threads with it. This is called in three circumstances:
2378 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
2379 SIG == 0 Continuing TCP will perform an exit_group syscall.
2380 SIG == other Continuing TCP with SIG will kill the process.
2381*/
2382static int
2383handle_group_exit(struct tcb *tcp, int sig)
2384{
2385 /* We need to locate our records of all the clone threads
2386 related to TCP, either its children or siblings. */
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002387 struct tcb *leader = NULL;
2388
2389 if (tcp->flags & TCB_CLONE_THREAD)
2390 leader = tcp->parent;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002391
2392 if (sig < 0) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002393 if (leader != NULL && leader != tcp
2394 && !(leader->flags & TCB_GROUP_EXITING)
2395 && !(tcp->flags & TCB_STARTUP)
2396 ) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002397 fprintf(stderr,
2398 "PANIC: handle_group_exit: %d leader %d\n",
2399 tcp->pid, leader ? leader->pid : -1);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002400 }
2401 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath0a463882007-07-05 18:43:16 +00002402 droptcb(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002403 }
2404 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00002405 /* Mark that we are taking the process down. */
2406 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002407 if (tcp->flags & TCB_ATTACHED) {
Roland McGrathd6a32f12007-07-11 08:35:11 +00002408 detach(tcp, sig);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002409 if (leader != NULL && leader != tcp)
Roland McGrath1bfd3102007-08-03 10:02:00 +00002410 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002411 } else {
2412 if (ptrace_restart(PTRACE_CONT, tcp, sig) < 0) {
2413 cleanup();
2414 return -1;
2415 }
2416 if (leader != NULL) {
Roland McGrath05690952004-10-20 01:00:27 +00002417 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002418 if (leader != tcp)
2419 droptcb(tcp);
2420 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002421 /* The leader will report to us as parent now,
2422 and then we'll get to the SIG==-1 case. */
2423 return 0;
2424 }
2425 }
2426
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002427 return 0;
2428}
2429#endif
2430
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002431#ifdef LINUX
2432static int
2433handle_ptrace_event(int status, struct tcb *tcp)
2434{
2435 if (status >> 16 == PTRACE_EVENT_VFORK ||
2436 status >> 16 == PTRACE_EVENT_CLONE ||
2437 status >> 16 == PTRACE_EVENT_FORK) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +00002438 long childpid;
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002439
2440 if (do_ptrace(PTRACE_GETEVENTMSG, tcp, NULL, &childpid) < 0) {
2441 if (errno != ESRCH) {
2442 fprintf(stderr, "\
2443%s: handle_ptrace_event: ptrace cannot get new child's pid\n",
2444 progname);
2445 cleanup();
2446 exit(1);
2447 }
2448 return -1;
2449 }
2450 return handle_new_child(tcp, childpid, 0);
2451 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002452 if (status >> 16 == PTRACE_EVENT_EXEC) {
2453 if (debug)
2454 fprintf(stderr, "PTRACE_EVENT_EXEC on pid %d (ignored)\n", tcp->pid);
2455 return 0;
2456 }
Denys Vlasenko75422762011-05-27 14:36:01 +02002457 /* Some PTRACE_EVENT_foo we didn't ask for?! */
2458 error_msg("Unexpected status %x on pid %d", status, tcp->pid);
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002459 return 1;
2460}
2461#endif
2462
Roland McGratheb9e2e82009-06-02 16:49:22 -07002463static int
2464trace()
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002465{
2466 int pid;
2467 int wait_errno;
2468 int status;
2469 struct tcb *tcp;
2470#ifdef LINUX
2471 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002472#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002473 static int wait4_options = __WALL;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002474#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002475#endif /* LINUX */
2476
Roland McGratheb9e2e82009-06-02 16:49:22 -07002477 while (nprocs != 0) {
Denys Vlasenko222713a2009-03-17 14:29:59 +00002478 if (interrupted)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002479 return 0;
2480 if (interactive)
2481 sigprocmask(SIG_SETMASK, &empty_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002482#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002483#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002484 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002485 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002486 /* this kernel does not support __WALL */
2487 wait4_options &= ~__WALL;
2488 errno = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002489 pid = wait4(-1, &status, wait4_options,
2490 cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002491 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002492 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002493 /* most likely a "cloned" process */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002494 pid = wait4(-1, &status, __WCLONE,
2495 cflag ? &ru : NULL);
2496 if (pid == -1) {
2497 fprintf(stderr, "strace: clone wait4 "
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002498 "failed: %s\n", strerror(errno));
2499 }
2500 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002501#else
2502 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
2503#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002504#endif /* LINUX */
2505#ifdef SUNOS4
2506 pid = wait(&status);
2507#endif /* SUNOS4 */
2508 wait_errno = errno;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002509 if (interactive)
2510 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002511
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002512 if (pid == -1) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002513 switch (wait_errno) {
2514 case EINTR:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002515 continue;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002516 case ECHILD:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002517 /*
2518 * We would like to verify this case
2519 * but sometimes a race in Solbourne's
2520 * version of SunOS sometimes reports
2521 * ECHILD before sending us SIGCHILD.
2522 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002523 return 0;
2524 default:
2525 errno = wait_errno;
2526 perror("strace: wait");
2527 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002528 }
2529 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002530 if (pid == popen_pid) {
2531 if (WIFEXITED(status) || WIFSIGNALED(status))
2532 popen_pid = -1;
2533 continue;
2534 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002535 if (debug)
2536 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2537
2538 /* Look up `pid' in our table. */
2539 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002540#ifdef LINUX
Roland McGrath41c48222008-07-18 00:25:10 +00002541 if (followfork) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002542 /* This is needed to go with the CLONE_PTRACE
2543 changes in process.c/util.c: we might see
2544 the child's initial trap before we see the
2545 parent return from the clone syscall.
2546 Leave the child suspended until the parent
2547 returns from its system call. Only then
2548 will we have the association of parent and
2549 child so that we know how to do clearbpt
2550 in the child. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +00002551 tcp = alloctcb(pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002552 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002553 if (!qflag)
2554 fprintf(stderr, "\
2555Process %d attached (waiting for parent)\n",
2556 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002557 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002558 else
2559 /* This can happen if a clone call used
2560 CLONE_PTRACE itself. */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002561#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002562 {
2563 fprintf(stderr, "unknown pid: %u\n", pid);
2564 if (WIFSTOPPED(status))
2565 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2566 exit(1);
2567 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002568 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002569 /* set current output file */
2570 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002571 curcol = tcp->curcol;
Denys Vlasenko84e20af2009-02-10 16:03:20 +00002572 if (cflag) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002573#ifdef LINUX
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002574 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2575 tcp->stime = ru.ru_stime;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002576#endif /* !LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002577 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002578
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002579 if (tcp->flags & TCB_SUSPENDED) {
2580 /*
2581 * Apparently, doing any ptrace() call on a stopped
2582 * process, provokes the kernel to report the process
2583 * status again on a subsequent wait(), even if the
2584 * process has not been actually restarted.
2585 * Since we have inspected the arguments of suspended
2586 * processes we end up here testing for this case.
2587 */
2588 continue;
2589 }
2590 if (WIFSIGNALED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002591 if (pid == strace_child)
2592 exit_code = 0x100 | WTERMSIG(status);
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002593 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002594 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2595 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002596 tprintf("+++ killed by %s %s+++",
2597 signame(WTERMSIG(status)),
2598#ifdef WCOREDUMP
2599 WCOREDUMP(status) ? "(core dumped) " :
2600#endif
2601 "");
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002602 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002603 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002604#ifdef TCB_GROUP_EXITING
2605 handle_group_exit(tcp, -1);
2606#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002607 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002608#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002609 continue;
2610 }
2611 if (WIFEXITED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002612 if (pid == strace_child)
2613 exit_code = WEXITSTATUS(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002614 if (debug)
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002615 fprintf(stderr, "pid %u exited with %d\n", pid, WEXITSTATUS(status));
2616 if ((tcp->flags & (TCB_ATTACHED|TCB_STARTUP)) == TCB_ATTACHED
Roland McGrath05690952004-10-20 01:00:27 +00002617#ifdef TCB_GROUP_EXITING
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002618 && !(tcp->parent && (tcp->parent->flags & TCB_GROUP_EXITING))
Roland McGrath1bfd3102007-08-03 10:02:00 +00002619 && !(tcp->flags & TCB_GROUP_EXITING)
Roland McGrath05690952004-10-20 01:00:27 +00002620#endif
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002621 ) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002622 fprintf(stderr,
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002623 "PANIC: attached pid %u exited with %d\n",
2624 pid, WEXITSTATUS(status));
2625 }
Roland McGrath0a396902003-06-10 03:05:53 +00002626 if (tcp == tcp_last) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002627 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT)) == TCB_INSYSCALL)
Roland McGrath0a396902003-06-10 03:05:53 +00002628 tprintf(" <unfinished ... exit status %d>\n",
2629 WEXITSTATUS(status));
2630 tcp_last = NULL;
2631 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002632#ifdef TCB_GROUP_EXITING
2633 handle_group_exit(tcp, -1);
2634#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002635 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002636#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002637 continue;
2638 }
2639 if (!WIFSTOPPED(status)) {
2640 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2641 droptcb(tcp);
2642 continue;
2643 }
2644 if (debug)
2645 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002646 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002647
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002648 if (status >> 16) {
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002649 if (handle_ptrace_event(status, tcp) != 1)
2650 goto tracing;
2651 }
2652
Roland McGrath02203312007-06-11 22:06:31 +00002653 /*
2654 * Interestingly, the process may stop
2655 * with STOPSIG equal to some other signal
Roland McGratheb9e2e82009-06-02 16:49:22 -07002656 * than SIGSTOP if we happend to attach
Roland McGrath02203312007-06-11 22:06:31 +00002657 * just before the process takes a signal.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002658 * A no-MMU vforked child won't send up a signal,
2659 * so skip the first (lost) execve notification.
Roland McGrath02203312007-06-11 22:06:31 +00002660 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002661 if ((tcp->flags & TCB_STARTUP) &&
2662 (WSTOPSIG(status) == SIGSTOP || strace_vforked)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002663 /*
2664 * This flag is there to keep us in sync.
2665 * Next time this process stops it should
2666 * really be entering a system call.
2667 */
2668 tcp->flags &= ~TCB_STARTUP;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002669 if (tcp->flags & TCB_BPTSET) {
Roland McGrath02203312007-06-11 22:06:31 +00002670 /*
2671 * One example is a breakpoint inherited from
2672 * parent through fork ().
2673 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002674 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2675 droptcb(tcp);
2676 cleanup();
2677 return -1;
2678 }
2679 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002680#ifdef LINUX
Denys Vlasenkof44cce42011-06-21 14:34:10 +02002681 /* If options were not set for this tracee yet */
2682 if (tcp->parent == NULL) {
2683 if (ptrace_setoptions) {
2684 if (debug)
2685 fprintf(stderr, "setting opts %x on pid %d\n", ptrace_setoptions, tcp->pid);
2686 if (ptrace(PTRACE_SETOPTIONS, tcp->pid, NULL, ptrace_setoptions) < 0) {
2687 if (errno != ESRCH) {
2688 /* Should never happen, really */
2689 perror_msg_and_die("PTRACE_SETOPTIONS");
2690 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002691 }
2692 }
2693 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002694#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002695 goto tracing;
2696 }
2697
Denys Vlasenko75422762011-05-27 14:36:01 +02002698 if (WSTOPSIG(status) != syscall_trap_sig) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002699 if (WSTOPSIG(status) == SIGSTOP &&
2700 (tcp->flags & TCB_SIGTRAPPED)) {
2701 /*
2702 * Trapped attempt to block SIGTRAP
2703 * Hope we are back in control now.
2704 */
2705 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002706 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002707 cleanup();
2708 return -1;
2709 }
2710 continue;
2711 }
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002712 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002713 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Dmitry V. Levinc15dfc72011-03-10 14:44:45 +00002714 siginfo_t si;
2715#if defined(PT_CR_IPSR) && defined(PT_CR_IIP)
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002716 long pc = 0;
2717 long psr = 0;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002718
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002719 upeek(tcp, PT_CR_IPSR, &psr);
2720 upeek(tcp, PT_CR_IIP, &pc);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002721
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002722# define PSR_RI 41
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002723 pc += (psr >> PSR_RI) & 0x3;
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002724# define PC_FORMAT_STR " @ %lx"
2725# define PC_FORMAT_ARG pc
2726#else
2727# define PC_FORMAT_STR "%s"
2728# define PC_FORMAT_ARG ""
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002729#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002730 printleader(tcp);
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002731 if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
2732 tprintf("--- ");
2733 printsiginfo(&si, verbose(tcp));
2734 tprintf(" (%s)" PC_FORMAT_STR " ---",
2735 strsignal(WSTOPSIG(status)),
2736 PC_FORMAT_ARG);
2737 } else
2738 tprintf("--- %s by %s" PC_FORMAT_STR " ---",
2739 strsignal(WSTOPSIG(status)),
2740 signame(WSTOPSIG(status)),
2741 PC_FORMAT_ARG);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002742 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002743 }
Roland McGrath05690952004-10-20 01:00:27 +00002744 if (((tcp->flags & TCB_ATTACHED) ||
2745 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002746 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002747#ifdef TCB_GROUP_EXITING
2748 handle_group_exit(tcp, WSTOPSIG(status));
2749#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002750 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002751#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002752 continue;
2753 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002754 if (ptrace_restart(PTRACE_SYSCALL, tcp, WSTOPSIG(status)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002755 cleanup();
2756 return -1;
2757 }
2758 tcp->flags &= ~TCB_SUSPENDED;
2759 continue;
2760 }
Roland McGrath02203312007-06-11 22:06:31 +00002761 /* we handled the STATUS, we are permitted to interrupt now. */
2762 if (interrupted)
2763 return 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002764 if (trace_syscall(tcp) < 0 && !tcp->ptrace_errno) {
2765 /* ptrace() failed in trace_syscall() with ESRCH.
2766 * Likely a result of process disappearing mid-flight.
2767 * Observed case: exit_group() terminating
2768 * all processes in thread group. In this case, threads
2769 * "disappear" in an unpredictable moment without any
2770 * notification to strace via wait().
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002771 */
2772 if (tcp->flags & TCB_ATTACHED) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002773 if (tcp_last) {
2774 /* Do we have dangling line "syscall(param, param"?
2775 * Finish the line then. We cannot
2776 */
2777 tcp_last->flags |= TCB_REPRINT;
2778 tprintf(" <unfinished ...>");
2779 printtrailer();
2780 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002781 detach(tcp, 0);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002782 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002783 ptrace(PTRACE_KILL,
2784 tcp->pid, (char *) 1, SIGTERM);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002785 droptcb(tcp);
2786 }
2787 continue;
2788 }
2789 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002790#ifdef TCB_GROUP_EXITING
2791 if (tcp->flags & TCB_GROUP_EXITING) {
2792 if (handle_group_exit(tcp, 0) < 0)
2793 return -1;
2794 continue;
2795 }
2796#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002797 if (tcp->flags & TCB_ATTACHED)
2798 detach(tcp, 0);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002799 else if (ptrace_restart(PTRACE_CONT, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002800 cleanup();
2801 return -1;
2802 }
2803 continue;
2804 }
2805 if (tcp->flags & TCB_SUSPENDED) {
2806 if (!qflag)
2807 fprintf(stderr, "Process %u suspended\n", pid);
2808 continue;
2809 }
2810 tracing:
Andreas Schwabccdff482009-10-27 16:27:13 +01002811 /* Remember current print column before continuing. */
2812 tcp->curcol = curcol;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002813 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002814 cleanup();
2815 return -1;
2816 }
2817 }
2818 return 0;
2819}
2820
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002821#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002822
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002823#include <stdarg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002824
2825void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002826tprintf(const char *fmt, ...)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002827{
2828 va_list args;
2829
Andreas Schwabe5355de2009-10-27 16:56:43 +01002830 va_start(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002831 if (outf) {
2832 int n = vfprintf(outf, fmt, args);
Andreas Schwabccdff482009-10-27 16:27:13 +01002833 if (n < 0) {
2834 if (outf != stderr)
2835 perror(outfname == NULL
2836 ? "<writing to pipe>" : outfname);
2837 } else
Roland McGrathb310a0c2003-11-06 23:41:22 +00002838 curcol += n;
2839 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002840 va_end(args);
2841 return;
2842}
2843
2844void
Denys Vlasenko12014262011-05-30 14:00:14 +02002845printleader(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002846{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002847 if (tcp_last) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002848 if (tcp_last->ptrace_errno) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002849 if (tcp_last->flags & TCB_INSYSCALL) {
Denys Vlasenkoe62df002011-06-08 16:15:04 +02002850 tprintf(" <unavailable>) ");
Roland McGratheb9e2e82009-06-02 16:49:22 -07002851 tabto(acolumn);
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002852 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002853 tprintf("= ? <unavailable>\n");
2854 tcp_last->ptrace_errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002855 } else if (!outfname || followfork < 2 || tcp_last == tcp) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002856 tcp_last->flags |= TCB_REPRINT;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002857 tprintf(" <unfinished ...>\n");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002858 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002859 }
2860 curcol = 0;
2861 if ((followfork == 1 || pflag_seen > 1) && outfname)
2862 tprintf("%-5d ", tcp->pid);
2863 else if (nprocs > 1 && !outfname)
2864 tprintf("[pid %5u] ", tcp->pid);
2865 if (tflag) {
2866 char str[sizeof("HH:MM:SS")];
2867 struct timeval tv, dtv;
2868 static struct timeval otv;
2869
2870 gettimeofday(&tv, NULL);
2871 if (rflag) {
2872 if (otv.tv_sec == 0)
2873 otv = tv;
2874 tv_sub(&dtv, &tv, &otv);
2875 tprintf("%6ld.%06ld ",
2876 (long) dtv.tv_sec, (long) dtv.tv_usec);
2877 otv = tv;
2878 }
2879 else if (tflag > 2) {
2880 tprintf("%ld.%06ld ",
2881 (long) tv.tv_sec, (long) tv.tv_usec);
2882 }
2883 else {
2884 time_t local = tv.tv_sec;
2885 strftime(str, sizeof(str), "%T", localtime(&local));
2886 if (tflag > 1)
2887 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2888 else
2889 tprintf("%s ", str);
2890 }
2891 }
2892 if (iflag)
2893 printcall(tcp);
2894}
2895
2896void
Denys Vlasenko12014262011-05-30 14:00:14 +02002897tabto(int col)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002898{
2899 if (curcol < col)
2900 tprintf("%*s", col - curcol, "");
2901}
2902
2903void
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002904printtrailer(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002905{
2906 tprintf("\n");
2907 tcp_last = NULL;
2908}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002909
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002910#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002911
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002912int
2913mp_ioctl(int fd, int cmd, void *arg, int size)
2914{
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002915 struct iovec iov[2];
2916 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002917
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002918 iov[0].iov_base = &cmd;
2919 iov[0].iov_len = sizeof cmd;
2920 if (arg) {
2921 ++n;
2922 iov[1].iov_base = arg;
2923 iov[1].iov_len = size;
2924 }
Roland McGrath553a6092002-12-16 20:40:39 +00002925
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002926 return writev(fd, iov, n);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002927}
2928
2929#endif