blob: 6fb6fd6eb610d35e1e28ac65e471e0760a7a5549 [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;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001288#ifdef TCB_CLONE_THREAD
Wang Chao21b8db42010-08-27 17:43:16 +08001289 tcp->nclone_threads = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001290#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001291 tcp->flags = TCB_INUSE | TCB_STARTUP;
1292 tcp->outf = outf; /* Initialise to current out file */
Andreas Schwabccdff482009-10-27 16:27:13 +01001293 tcp->curcol = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001294 tcp->stime.tv_sec = 0;
1295 tcp->stime.tv_usec = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001296 tcp->pfd = -1;
1297 nprocs++;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001298 if (command_options_parsed)
1299 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001300 return tcp;
1301 }
1302 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001303 fprintf(stderr, "%s: bug in alloc_tcb\n", progname);
1304 cleanup();
1305 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001306}
1307
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001308#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001309int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001310proc_open(struct tcb *tcp, int attaching)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001311{
1312 char proc[32];
1313 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001314#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +00001315 int i;
1316 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001317 sigset_t signals;
1318 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001319#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001320#ifndef HAVE_POLLABLE_PROCFS
1321 static int last_pfd;
1322#endif
1323
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001324#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001325 /* Open the process pseudo-files in /proc. */
1326 sprintf(proc, "/proc/%d/ctl", tcp->pid);
1327 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001328 perror("strace: open(\"/proc/...\", ...)");
1329 return -1;
1330 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001331 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001332 return -1;
1333 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001334 sprintf(proc, "/proc/%d/status", tcp->pid);
1335 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
1336 perror("strace: open(\"/proc/...\", ...)");
1337 return -1;
1338 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001339 if (set_cloexec_flag(tcp->pfd_stat) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001340 return -1;
1341 }
1342 sprintf(proc, "/proc/%d/as", tcp->pid);
1343 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
1344 perror("strace: open(\"/proc/...\", ...)");
1345 return -1;
1346 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001347 if (set_cloexec_flag(tcp->pfd_as) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001348 return -1;
1349 }
1350#else
1351 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001352#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001353 sprintf(proc, "/proc/%d", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001354 tcp->pfd = open(proc, O_RDWR|O_EXCL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001355#else /* FREEBSD */
1356 sprintf(proc, "/proc/%d/mem", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001357 tcp->pfd = open(proc, O_RDWR);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001358#endif /* FREEBSD */
Andreas Schwab372cc842010-07-09 11:49:27 +02001359 if (tcp->pfd < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001360 perror("strace: open(\"/proc/...\", ...)");
1361 return -1;
1362 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001363 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001364 return -1;
1365 }
1366#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001367#ifdef FREEBSD
1368 sprintf(proc, "/proc/%d/regs", tcp->pid);
1369 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
1370 perror("strace: open(\"/proc/.../regs\", ...)");
1371 return -1;
1372 }
1373 if (cflag) {
1374 sprintf(proc, "/proc/%d/status", tcp->pid);
1375 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
1376 perror("strace: open(\"/proc/.../status\", ...)");
1377 return -1;
1378 }
1379 } else
1380 tcp->pfd_status = -1;
1381#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001382 rebuild_pollv();
1383 if (!attaching) {
1384 /*
1385 * Wait for the child to pause. Because of a race
1386 * condition we have to poll for the event.
1387 */
1388 for (;;) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001389 if (IOCTL_STATUS(tcp) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001390 perror("strace: PIOCSTATUS");
1391 return -1;
1392 }
1393 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001394 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001395 }
1396 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001397#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001398 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001399 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001400 perror("strace: PIOCSTOP");
1401 return -1;
1402 }
Roland McGrath553a6092002-12-16 20:40:39 +00001403#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001404#ifdef PIOCSET
1405 /* Set Run-on-Last-Close. */
1406 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001407 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001408 perror("PIOCSET PR_RLC");
1409 return -1;
1410 }
1411 /* Set or Reset Inherit-on-Fork. */
1412 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001413 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001414 perror("PIOC{SET,RESET} PR_FORK");
1415 return -1;
1416 }
1417#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +00001418#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001419 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
1420 perror("PIOCSRLC");
1421 return -1;
1422 }
1423 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
1424 perror("PIOC{S,R}FORK");
1425 return -1;
1426 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001427#else /* FREEBSD */
1428 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
1429 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
1430 perror("PIOCGFL");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001431 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001432 }
1433 arg &= ~PF_LINGER;
1434 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001435 perror("PIOCSFL");
1436 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001437 }
1438#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001439#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001440#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +00001441 /* Enable all syscall entries we care about. */
1442 premptyset(&syscalls);
1443 for (i = 1; i < MAX_QUALS; ++i) {
1444 if (i > (sizeof syscalls) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001445 if (qual_flags[i] & QUAL_TRACE) praddset(&syscalls, i);
John Hughes19e49982001-10-19 08:59:12 +00001446 }
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001447 praddset(&syscalls, SYS_execve);
John Hughes19e49982001-10-19 08:59:12 +00001448 if (followfork) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001449 praddset(&syscalls, SYS_fork);
John Hughes19e49982001-10-19 08:59:12 +00001450#ifdef SYS_forkall
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001451 praddset(&syscalls, SYS_forkall);
John Hughes19e49982001-10-19 08:59:12 +00001452#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001453#ifdef SYS_fork1
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001454 praddset(&syscalls, SYS_fork1);
John Hughes19e49982001-10-19 08:59:12 +00001455#endif
1456#ifdef SYS_rfork1
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001457 praddset(&syscalls, SYS_rfork1);
John Hughes19e49982001-10-19 08:59:12 +00001458#endif
1459#ifdef SYS_rforkall
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001460 praddset(&syscalls, SYS_rforkall);
John Hughes19e49982001-10-19 08:59:12 +00001461#endif
1462 }
1463 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001464 perror("PIOCSENTRY");
1465 return -1;
1466 }
John Hughes19e49982001-10-19 08:59:12 +00001467 /* Enable the syscall exits. */
1468 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001469 perror("PIOSEXIT");
1470 return -1;
1471 }
John Hughes19e49982001-10-19 08:59:12 +00001472 /* Enable signals we care about. */
1473 premptyset(&signals);
1474 for (i = 1; i < MAX_QUALS; ++i) {
1475 if (i > (sizeof signals) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001476 if (qual_flags[i] & QUAL_SIGNAL) praddset(&signals, i);
John Hughes19e49982001-10-19 08:59:12 +00001477 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001478 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001479 perror("PIOCSTRACE");
1480 return -1;
1481 }
John Hughes19e49982001-10-19 08:59:12 +00001482 /* Enable faults we care about */
1483 premptyset(&faults);
1484 for (i = 1; i < MAX_QUALS; ++i) {
1485 if (i > (sizeof faults) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001486 if (qual_flags[i] & QUAL_FAULT) praddset(&faults, i);
John Hughes19e49982001-10-19 08:59:12 +00001487 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001488 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001489 perror("PIOCSFAULT");
1490 return -1;
1491 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001492#else /* FREEBSD */
1493 /* set events flags. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001494 arg = S_SIG | S_SCE | S_SCX;
1495 if (ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001496 perror("PIOCBIS");
1497 return -1;
1498 }
1499#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001500 if (!attaching) {
1501#ifdef MIPS
1502 /*
1503 * The SGI PRSABORT doesn't work for pause() so
1504 * we send it a caught signal to wake it up.
1505 */
1506 kill(tcp->pid, SIGINT);
1507#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +00001508#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001509 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001510 arg = PRSABORT;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001511 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001512 perror("PIOCRUN");
1513 return -1;
1514 }
Roland McGrath553a6092002-12-16 20:40:39 +00001515#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001516#endif /* !MIPS*/
1517#ifdef FREEBSD
1518 /* wake up the child if it received the SIGSTOP */
1519 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001520#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001521 for (;;) {
1522 /* Wait for the child to do something. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001523 if (IOCTL_WSTOP(tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001524 perror("PIOCWSTOP");
1525 return -1;
1526 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001527 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001528 tcp->flags &= ~TCB_INSYSCALL;
1529 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001530 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001531 break;
1532 }
1533 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001534#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001535 arg = 0;
1536 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001537#else /* FREEBSD */
1538 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001539#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001540 perror("PIOCRUN");
1541 return -1;
1542 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001543#ifdef FREEBSD
1544 /* handle the case where we "opened" the child before
1545 it did the kill -STOP */
1546 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1547 tcp->status.PR_WHAT == SIGSTOP)
1548 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001549#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001550 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001551#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001552 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001553#else /* FREEBSD */
1554 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001555 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001556 /* We are attaching to an already running process.
1557 * Try to figure out the state of the process in syscalls,
1558 * to handle the first event well.
1559 * This is done by having a look at the "wchan" property of the
1560 * process, which tells where it is stopped (if it is). */
1561 FILE * status;
1562 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001563
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001564 sprintf(proc, "/proc/%d/status", tcp->pid);
1565 status = fopen(proc, "r");
1566 if (status &&
1567 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1568 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1569 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1570 strcmp(wchan, "stopevent")) {
1571 /* The process is asleep in the middle of a syscall.
1572 Fake the syscall entry event */
1573 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1574 tcp->status.PR_WHY = PR_SYSENTRY;
1575 trace_syscall(tcp);
1576 }
1577 if (status)
1578 fclose(status);
1579 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001580 }
1581#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001582#ifndef HAVE_POLLABLE_PROCFS
1583 if (proc_poll_pipe[0] != -1)
1584 proc_poller(tcp->pfd);
1585 else if (nprocs > 1) {
1586 proc_poll_open();
1587 proc_poller(last_pfd);
1588 proc_poller(tcp->pfd);
1589 }
1590 last_pfd = tcp->pfd;
1591#endif /* !HAVE_POLLABLE_PROCFS */
1592 return 0;
1593}
1594
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001595#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001596
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001597struct tcb *
Roland McGrath54e931f2010-09-14 18:59:20 -07001598pid2tcb(int pid)
1599{
1600 int i;
1601
1602 if (pid <= 0)
1603 return NULL;
1604
1605 for (i = 0; i < tcbtabsize; i++) {
1606 struct tcb *tcp = tcbtab[i];
1607 if (tcp->pid == pid && (tcp->flags & TCB_INUSE))
1608 return tcp;
1609 }
1610
1611 return NULL;
1612}
1613
1614#ifdef USE_PROCFS
1615
1616static struct tcb *
1617first_used_tcb(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001618{
1619 int i;
1620 struct tcb *tcp;
Roland McGrathee9d4352002-12-18 04:16:10 +00001621 for (i = 0; i < tcbtabsize; i++) {
1622 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001623 if (tcp->flags & TCB_INUSE)
1624 return tcp;
1625 }
1626 return NULL;
1627}
1628
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001629static struct tcb *
Denys Vlasenko12014262011-05-30 14:00:14 +02001630pfd2tcb(int pfd)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001631{
1632 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001633
Roland McGrathca16be82003-01-10 19:55:28 +00001634 for (i = 0; i < tcbtabsize; i++) {
1635 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001636 if (tcp->pfd != pfd)
1637 continue;
1638 if (tcp->flags & TCB_INUSE)
1639 return tcp;
1640 }
1641 return NULL;
1642}
1643
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001644#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001645
1646void
Denys Vlasenko12014262011-05-30 14:00:14 +02001647droptcb(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001648{
1649 if (tcp->pid == 0)
1650 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001651#ifdef TCB_CLONE_THREAD
1652 if (tcp->nclone_threads > 0) {
1653 /* There are other threads left in this process, but this
1654 is the one whose PID represents the whole process.
1655 We need to keep this record around as a zombie until
1656 all the threads die. */
1657 tcp->flags |= TCB_EXITING;
1658 return;
1659 }
1660#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001661 nprocs--;
1662 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001663
Roland McGrathe29341c2003-01-10 20:14:20 +00001664 if (tcp->parent != NULL) {
1665 tcp->parent->nchildren--;
1666#ifdef TCB_CLONE_THREAD
Roland McGrathe29341c2003-01-10 20:14:20 +00001667 if (tcp->flags & TCB_CLONE_THREAD)
1668 tcp->parent->nclone_threads--;
1669#endif
Roland McGrath276ceb32007-11-13 08:12:12 +00001670#ifdef LINUX
1671 /* Update `tcp->parent->parent->nchildren' and the other fields
1672 like NCLONE_DETACHED, only for zombie group leader that has
1673 already reported and been short-circuited at the top of this
1674 function. The same condition as at the top of DETACH. */
1675 if ((tcp->flags & TCB_CLONE_THREAD) &&
1676 tcp->parent->nclone_threads == 0 &&
1677 (tcp->parent->flags & TCB_EXITING))
1678 droptcb(tcp->parent);
1679#endif
Roland McGrathe29341c2003-01-10 20:14:20 +00001680 tcp->parent = NULL;
1681 }
1682
1683 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001684 if (tcp->pfd != -1) {
1685 close(tcp->pfd);
1686 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001687#ifdef FREEBSD
1688 if (tcp->pfd_reg != -1) {
1689 close(tcp->pfd_reg);
1690 tcp->pfd_reg = -1;
1691 }
1692 if (tcp->pfd_status != -1) {
1693 close(tcp->pfd_status);
1694 tcp->pfd_status = -1;
1695 }
Roland McGrath553a6092002-12-16 20:40:39 +00001696#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001697#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001698 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001699#endif
1700 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001701
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001702 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001703 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001704
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001705 tcp->outf = 0;
1706}
1707
Roland McGrath0a463882007-07-05 18:43:16 +00001708/* detach traced process; continue with sig
1709 Never call DETACH twice on the same process as both unattached and
1710 attached-unstopped processes give the same ESRCH. For unattached process we
1711 would SIGSTOP it and wait for its SIGSTOP notification forever. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001712
1713static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001714detach(struct tcb *tcp, int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001715{
1716 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001717#ifdef LINUX
Roland McGrath1bfd3102007-08-03 10:02:00 +00001718 int status, catch_sigstop;
Roland McGratha08a97e2005-08-03 11:23:46 +00001719 struct tcb *zombie = NULL;
1720
1721 /* If the group leader is lingering only because of this other
1722 thread now dying, then detach the leader as well. */
1723 if ((tcp->flags & TCB_CLONE_THREAD) &&
1724 tcp->parent->nclone_threads == 1 &&
1725 (tcp->parent->flags & TCB_EXITING))
1726 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001727#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001728
1729 if (tcp->flags & TCB_BPTSET)
Andreas Schwab840d85b2010-01-12 11:16:32 +01001730 clearbpt(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001731
1732#ifdef LINUX
1733 /*
1734 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001735 * before detaching. Arghh. We go through hoops
1736 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001737 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001738#if defined(SPARC)
1739#undef PTRACE_DETACH
1740#define PTRACE_DETACH PTRACE_SUNDETACH
1741#endif
Roland McGrath02203312007-06-11 22:06:31 +00001742 /*
1743 * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
1744 * expected SIGSTOP. We must catch exactly one as otherwise the
1745 * detached process would be left stopped (process state T).
1746 */
1747 catch_sigstop = (tcp->flags & TCB_STARTUP);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001748 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1749 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001750 }
1751 else if (errno != ESRCH) {
1752 /* Shouldn't happen. */
1753 perror("detach: ptrace(PTRACE_DETACH, ...)");
1754 }
Roland McGrath134813a2007-06-02 00:07:33 +00001755 else if (my_tgkill((tcp->flags & TCB_CLONE_THREAD ? tcp->parent->pid
1756 : tcp->pid),
1757 tcp->pid, 0) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001758 if (errno != ESRCH)
1759 perror("detach: checking sanity");
1760 }
Roland McGrath02203312007-06-11 22:06:31 +00001761 else if (!catch_sigstop && my_tgkill((tcp->flags & TCB_CLONE_THREAD
1762 ? tcp->parent->pid : tcp->pid),
1763 tcp->pid, SIGSTOP) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001764 if (errno != ESRCH)
1765 perror("detach: stopping child");
1766 }
Roland McGrath02203312007-06-11 22:06:31 +00001767 else
1768 catch_sigstop = 1;
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001769 if (catch_sigstop) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001770 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001771#ifdef __WALL
1772 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1773 if (errno == ECHILD) /* Already gone. */
1774 break;
1775 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001776 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001777 break;
1778 }
1779#endif /* __WALL */
1780 /* No __WALL here. */
1781 if (waitpid(tcp->pid, &status, 0) < 0) {
1782 if (errno != ECHILD) {
1783 perror("detach: waiting");
1784 break;
1785 }
1786#ifdef __WCLONE
1787 /* If no processes, try clones. */
1788 if (wait4(tcp->pid, &status, __WCLONE,
1789 NULL) < 0) {
1790 if (errno != ECHILD)
1791 perror("detach: waiting");
1792 break;
1793 }
1794#endif /* __WCLONE */
1795 }
1796#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001797 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001798#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001799 if (!WIFSTOPPED(status)) {
1800 /* Au revoir, mon ami. */
1801 break;
1802 }
1803 if (WSTOPSIG(status) == SIGSTOP) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001804 ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001805 break;
1806 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001807 error = ptrace_restart(PTRACE_CONT, tcp,
Denys Vlasenko75422762011-05-27 14:36:01 +02001808 WSTOPSIG(status) == syscall_trap_sig ? 0
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001809 : WSTOPSIG(status));
1810 if (error < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001811 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001812 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001813 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001814#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001815
1816#if defined(SUNOS4)
1817 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1818 if (sig && kill(tcp->pid, sig) < 0)
1819 perror("detach: kill");
1820 sig = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001821 error = ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001822#endif /* SUNOS4 */
1823
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001824 if (!qflag)
1825 fprintf(stderr, "Process %u detached\n", tcp->pid);
1826
1827 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001828
1829#ifdef LINUX
Roland McGrath0a463882007-07-05 18:43:16 +00001830 if (zombie != NULL) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001831 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath0a463882007-07-05 18:43:16 +00001832 droptcb(zombie);
1833 }
Roland McGratha08a97e2005-08-03 11:23:46 +00001834#endif
1835
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001836 return error;
1837}
1838
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001839#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001840
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001841static void reaper(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001842{
1843 int pid;
1844 int status;
1845
1846 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001847 }
1848}
1849
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001850#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001851
1852static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001853cleanup(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001854{
1855 int i;
1856 struct tcb *tcp;
1857
Roland McGrathee9d4352002-12-18 04:16:10 +00001858 for (i = 0; i < tcbtabsize; i++) {
1859 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001860 if (!(tcp->flags & TCB_INUSE))
1861 continue;
1862 if (debug)
1863 fprintf(stderr,
1864 "cleanup: looking at pid %u\n", tcp->pid);
1865 if (tcp_last &&
1866 (!outfname || followfork < 2 || tcp_last == tcp)) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001867 tprintf(" <unfinished ...>");
1868 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001869 }
1870 if (tcp->flags & TCB_ATTACHED)
1871 detach(tcp, 0);
1872 else {
1873 kill(tcp->pid, SIGCONT);
1874 kill(tcp->pid, SIGTERM);
1875 }
1876 }
1877 if (cflag)
1878 call_summary(outf);
1879}
1880
1881static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001882interrupt(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001883{
1884 interrupted = 1;
1885}
1886
1887#ifndef HAVE_STRERROR
1888
Roland McGrath6d2b3492002-12-30 00:51:30 +00001889#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001890extern int sys_nerr;
1891extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001892#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001893
1894const char *
Denys Vlasenko12014262011-05-30 14:00:14 +02001895strerror(int err_no)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001896{
1897 static char buf[64];
1898
Denys Vlasenko35aba6a2011-05-25 15:33:26 +02001899 if (err_no < 1 || err_no >= sys_nerr) {
1900 sprintf(buf, "Unknown error %d", err_no);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001901 return buf;
1902 }
Denys Vlasenko35aba6a2011-05-25 15:33:26 +02001903 return sys_errlist[err_no];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001904}
1905
1906#endif /* HAVE_STERRROR */
1907
1908#ifndef HAVE_STRSIGNAL
1909
Roland McGrath8f474e02003-01-14 07:53:33 +00001910#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001911extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001912#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001913#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1914extern char *_sys_siglist[];
1915#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001916
1917const char *
Denys Vlasenko12014262011-05-30 14:00:14 +02001918strsignal(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001919{
1920 static char buf[64];
1921
1922 if (sig < 1 || sig >= NSIG) {
1923 sprintf(buf, "Unknown signal %d", sig);
1924 return buf;
1925 }
1926#ifdef HAVE__SYS_SIGLIST
1927 return _sys_siglist[sig];
1928#else
1929 return sys_siglist[sig];
1930#endif
1931}
1932
1933#endif /* HAVE_STRSIGNAL */
1934
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001935#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001936
1937static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001938rebuild_pollv(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001939{
1940 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001941
Roland McGrathee9d4352002-12-18 04:16:10 +00001942 if (pollv != NULL)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001943 free(pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001944 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001945 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001946 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00001947 exit(1);
1948 }
1949
Roland McGrathca16be82003-01-10 19:55:28 +00001950 for (i = j = 0; i < tcbtabsize; i++) {
1951 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001952 if (!(tcp->flags & TCB_INUSE))
1953 continue;
1954 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001955 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001956 j++;
1957 }
1958 if (j != nprocs) {
1959 fprintf(stderr, "strace: proc miscount\n");
1960 exit(1);
1961 }
1962}
1963
1964#ifndef HAVE_POLLABLE_PROCFS
1965
1966static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001967proc_poll_open(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001968{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001969 int i;
1970
1971 if (pipe(proc_poll_pipe) < 0) {
1972 perror("pipe");
1973 exit(1);
1974 }
1975 for (i = 0; i < 2; i++) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001976 if (set_cloexec_flag(proc_poll_pipe[i]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001977 exit(1);
1978 }
1979 }
1980}
1981
1982static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001983proc_poll(struct pollfd *pollv, int nfds, int timeout)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001984{
1985 int i;
1986 int n;
1987 struct proc_pollfd pollinfo;
1988
1989 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1990 return n;
1991 if (n != sizeof(struct proc_pollfd)) {
1992 fprintf(stderr, "panic: short read: %d\n", n);
1993 exit(1);
1994 }
1995 for (i = 0; i < nprocs; i++) {
1996 if (pollv[i].fd == pollinfo.fd)
1997 pollv[i].revents = pollinfo.revents;
1998 else
1999 pollv[i].revents = 0;
2000 }
2001 poller_pid = pollinfo.pid;
2002 return 1;
2003}
2004
2005static void
Denys Vlasenko12014262011-05-30 14:00:14 +02002006wakeup_handler(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002007{
2008}
2009
2010static void
Denys Vlasenko12014262011-05-30 14:00:14 +02002011proc_poller(int pfd)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002012{
2013 struct proc_pollfd pollinfo;
2014 struct sigaction sa;
2015 sigset_t blocked_set, empty_set;
2016 int i;
2017 int n;
2018 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002019#ifdef FREEBSD
2020 struct procfs_status pfs;
2021#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002022
2023 switch (fork()) {
2024 case -1:
2025 perror("fork");
Dmitry V. Levina6809652008-11-10 17:14:58 +00002026 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002027 case 0:
2028 break;
2029 default:
2030 return;
2031 }
2032
2033 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
2034 sa.sa_flags = 0;
2035 sigemptyset(&sa.sa_mask);
2036 sigaction(SIGHUP, &sa, NULL);
2037 sigaction(SIGINT, &sa, NULL);
2038 sigaction(SIGQUIT, &sa, NULL);
2039 sigaction(SIGPIPE, &sa, NULL);
2040 sigaction(SIGTERM, &sa, NULL);
2041 sa.sa_handler = wakeup_handler;
2042 sigaction(SIGUSR1, &sa, NULL);
2043 sigemptyset(&blocked_set);
2044 sigaddset(&blocked_set, SIGUSR1);
2045 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2046 sigemptyset(&empty_set);
2047
2048 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
2049 perror("getrlimit(RLIMIT_NOFILE, ...)");
Dmitry V. Levina6809652008-11-10 17:14:58 +00002050 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002051 }
2052 n = rl.rlim_cur;
2053 for (i = 0; i < n; i++) {
2054 if (i != pfd && i != proc_poll_pipe[1])
2055 close(i);
2056 }
2057
2058 pollinfo.fd = pfd;
2059 pollinfo.pid = getpid();
2060 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002061#ifndef FREEBSD
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002062 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
2063#else
2064 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
2065#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002066 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002067 switch (errno) {
2068 case EINTR:
2069 continue;
2070 case EBADF:
2071 pollinfo.revents = POLLERR;
2072 break;
2073 case ENOENT:
2074 pollinfo.revents = POLLHUP;
2075 break;
2076 default:
2077 perror("proc_poller: PIOCWSTOP");
2078 }
2079 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2080 _exit(0);
2081 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002082 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002083 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2084 sigsuspend(&empty_set);
2085 }
2086}
2087
2088#endif /* !HAVE_POLLABLE_PROCFS */
2089
2090static int
2091choose_pfd()
2092{
2093 int i, j;
2094 struct tcb *tcp;
2095
2096 static int last;
2097
2098 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002099 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002100 /*
2101 * The previous process is ready to run again. We'll
2102 * let it do so if it is currently in a syscall. This
2103 * heuristic improves the readability of the trace.
2104 */
2105 tcp = pfd2tcb(pollv[last].fd);
2106 if (tcp && (tcp->flags & TCB_INSYSCALL))
2107 return pollv[last].fd;
2108 }
2109
2110 for (i = 0; i < nprocs; i++) {
2111 /* Let competing children run round robin. */
2112 j = (i + last + 1) % nprocs;
2113 if (pollv[j].revents & (POLLHUP | POLLERR)) {
2114 tcp = pfd2tcb(pollv[j].fd);
2115 if (!tcp) {
2116 fprintf(stderr, "strace: lost proc\n");
2117 exit(1);
2118 }
2119 droptcb(tcp);
2120 return -1;
2121 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002122 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002123 last = j;
2124 return pollv[j].fd;
2125 }
2126 }
2127 fprintf(stderr, "strace: nothing ready\n");
2128 exit(1);
2129}
2130
2131static int
Denys Vlasenko12014262011-05-30 14:00:14 +02002132trace(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002133{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002134#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00002135 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002136#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002137 struct tcb *tcp;
2138 int pfd;
2139 int what;
2140 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002141 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002142
2143 for (;;) {
2144 if (interactive)
2145 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2146
2147 if (nprocs == 0)
2148 break;
2149
2150 switch (nprocs) {
2151 case 1:
2152#ifndef HAVE_POLLABLE_PROCFS
2153 if (proc_poll_pipe[0] == -1) {
2154#endif
Roland McGrath54e931f2010-09-14 18:59:20 -07002155 tcp = first_used_tcb();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002156 if (!tcp)
2157 continue;
2158 pfd = tcp->pfd;
2159 if (pfd == -1)
2160 continue;
2161 break;
2162#ifndef HAVE_POLLABLE_PROCFS
2163 }
2164 /* fall through ... */
2165#endif /* !HAVE_POLLABLE_PROCFS */
2166 default:
2167#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002168#ifdef POLL_HACK
2169 /* On some systems (e.g. UnixWare) we get too much ugly
2170 "unfinished..." stuff when multiple proceses are in
2171 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00002172
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002173 if (in_syscall) {
2174 struct pollfd pv;
2175 tcp = in_syscall;
2176 in_syscall = NULL;
2177 pv.fd = tcp->pfd;
2178 pv.events = POLLWANT;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002179 if ((what = poll(&pv, 1, 1)) < 0) {
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002180 if (interrupted)
2181 return 0;
2182 continue;
2183 }
2184 else if (what == 1 && pv.revents & POLLWANT) {
2185 goto FOUND;
2186 }
2187 }
2188#endif
2189
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002190 if (poll(pollv, nprocs, INFTIM) < 0) {
2191 if (interrupted)
2192 return 0;
2193 continue;
2194 }
2195#else /* !HAVE_POLLABLE_PROCFS */
2196 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
2197 if (interrupted)
2198 return 0;
2199 continue;
2200 }
2201#endif /* !HAVE_POLLABLE_PROCFS */
2202 pfd = choose_pfd();
2203 if (pfd == -1)
2204 continue;
2205 break;
2206 }
2207
2208 /* Look up `pfd' in our table. */
2209 if ((tcp = pfd2tcb(pfd)) == NULL) {
2210 fprintf(stderr, "unknown pfd: %u\n", pfd);
2211 exit(1);
2212 }
John Hughesb6643082002-05-23 11:02:22 +00002213#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002214 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00002215#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002216 /* Get the status of the process. */
2217 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002218#ifndef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002219 ioctl_result = IOCTL_WSTOP(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002220#else /* FREEBSD */
2221 /* Thanks to some scheduling mystery, the first poller
2222 sometimes waits for the already processed end of fork
2223 event. Doing a non blocking poll here solves the problem. */
2224 if (proc_poll_pipe[0] != -1)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002225 ioctl_result = IOCTL_STATUS(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002226 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002227 ioctl_result = IOCTL_WSTOP(tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00002228#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002229 ioctl_errno = errno;
2230#ifndef HAVE_POLLABLE_PROCFS
2231 if (proc_poll_pipe[0] != -1) {
2232 if (ioctl_result < 0)
2233 kill(poller_pid, SIGKILL);
2234 else
2235 kill(poller_pid, SIGUSR1);
2236 }
2237#endif /* !HAVE_POLLABLE_PROCFS */
2238 }
2239 if (interrupted)
2240 return 0;
2241
2242 if (interactive)
2243 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2244
2245 if (ioctl_result < 0) {
2246 /* Find out what happened if it failed. */
2247 switch (ioctl_errno) {
2248 case EINTR:
2249 case EBADF:
2250 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002251#ifdef FREEBSD
2252 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00002253#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002254 case ENOENT:
2255 droptcb(tcp);
2256 continue;
2257 default:
2258 perror("PIOCWSTOP");
2259 exit(1);
2260 }
2261 }
2262
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002263#ifdef FREEBSD
2264 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2265 /* discard first event for a syscall we never entered */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002266 IOCTL(tcp->pfd, PIOCRUN, 0);
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002267 continue;
2268 }
Roland McGrath553a6092002-12-16 20:40:39 +00002269#endif
2270
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002271 /* clear the just started flag */
2272 tcp->flags &= ~TCB_STARTUP;
2273
2274 /* set current output file */
2275 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002276 curcol = tcp->curcol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002277
2278 if (cflag) {
2279 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002280#ifdef FREEBSD
2281 char buf[1024];
2282 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002283
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002284 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
2285 buf[len] = '\0';
2286 sscanf(buf,
2287 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2288 &stime.tv_sec, &stime.tv_usec);
2289 } else
2290 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002291#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002292 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2293 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002294#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002295 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2296 tcp->stime = stime;
2297 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002298 what = tcp->status.PR_WHAT;
2299 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002300#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002301 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002302 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2303 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002304 if (trace_syscall(tcp) < 0) {
2305 fprintf(stderr, "syscall trouble\n");
2306 exit(1);
2307 }
2308 }
2309 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002310#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002311 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002312#ifdef POLL_HACK
2313 in_syscall = tcp;
2314#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002315 case PR_SYSEXIT:
2316 if (trace_syscall(tcp) < 0) {
2317 fprintf(stderr, "syscall trouble\n");
2318 exit(1);
2319 }
2320 break;
2321 case PR_SIGNALLED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002322 if (cflag != CFLAG_ONLY_STATS
2323 && (qual_flags[what] & QUAL_SIGNAL)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002324 printleader(tcp);
2325 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002326 signame(what), strsignal(what));
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002327 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002328#ifdef PR_INFO
2329 if (tcp->status.PR_INFO.si_signo == what) {
2330 printleader(tcp);
2331 tprintf(" siginfo=");
2332 printsiginfo(&tcp->status.PR_INFO, 1);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002333 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002334 }
2335#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002336 }
2337 break;
2338 case PR_FAULTED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002339 if (cflag != CFLAGS_ONLY_STATS
2340 && (qual_flags[what] & QUAL_FAULT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002341 printleader(tcp);
2342 tprintf("=== FAULT %d ===", what);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002343 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002344 }
2345 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002346#ifdef FREEBSD
2347 case 0: /* handle case we polled for nothing */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002348 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00002349#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002350 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002351 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002352 exit(1);
2353 break;
2354 }
Andreas Schwabccdff482009-10-27 16:27:13 +01002355 /* Remember current print column before continuing. */
2356 tcp->curcol = curcol;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002357 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002358#ifndef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002359 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002360#else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002361 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002362#endif
Andreas Schwab372cc842010-07-09 11:49:27 +02002363 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002364 perror("PIOCRUN");
2365 exit(1);
2366 }
2367 }
2368 return 0;
2369}
2370
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002371#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002372
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002373#ifdef TCB_GROUP_EXITING
2374/* Handle an exit detach or death signal that is taking all the
2375 related clone threads with it. This is called in three circumstances:
2376 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
2377 SIG == 0 Continuing TCP will perform an exit_group syscall.
2378 SIG == other Continuing TCP with SIG will kill the process.
2379*/
2380static int
2381handle_group_exit(struct tcb *tcp, int sig)
2382{
2383 /* We need to locate our records of all the clone threads
2384 related to TCP, either its children or siblings. */
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002385 struct tcb *leader = NULL;
2386
2387 if (tcp->flags & TCB_CLONE_THREAD)
2388 leader = tcp->parent;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002389
2390 if (sig < 0) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002391 if (leader != NULL && leader != tcp
2392 && !(leader->flags & TCB_GROUP_EXITING)
2393 && !(tcp->flags & TCB_STARTUP)
2394 ) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002395 fprintf(stderr,
2396 "PANIC: handle_group_exit: %d leader %d\n",
2397 tcp->pid, leader ? leader->pid : -1);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002398 }
2399 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath0a463882007-07-05 18:43:16 +00002400 droptcb(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002401 }
2402 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00002403 /* Mark that we are taking the process down. */
2404 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002405 if (tcp->flags & TCB_ATTACHED) {
Roland McGrathd6a32f12007-07-11 08:35:11 +00002406 detach(tcp, sig);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002407 if (leader != NULL && leader != tcp)
Roland McGrath1bfd3102007-08-03 10:02:00 +00002408 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002409 } else {
2410 if (ptrace_restart(PTRACE_CONT, tcp, sig) < 0) {
2411 cleanup();
2412 return -1;
2413 }
2414 if (leader != NULL) {
Roland McGrath05690952004-10-20 01:00:27 +00002415 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002416 if (leader != tcp)
2417 droptcb(tcp);
2418 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002419 /* The leader will report to us as parent now,
2420 and then we'll get to the SIG==-1 case. */
2421 return 0;
2422 }
2423 }
2424
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002425 return 0;
2426}
2427#endif
2428
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002429#ifdef LINUX
2430static int
2431handle_ptrace_event(int status, struct tcb *tcp)
2432{
2433 if (status >> 16 == PTRACE_EVENT_VFORK ||
2434 status >> 16 == PTRACE_EVENT_CLONE ||
2435 status >> 16 == PTRACE_EVENT_FORK) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +00002436 long childpid;
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002437
2438 if (do_ptrace(PTRACE_GETEVENTMSG, tcp, NULL, &childpid) < 0) {
2439 if (errno != ESRCH) {
2440 fprintf(stderr, "\
2441%s: handle_ptrace_event: ptrace cannot get new child's pid\n",
2442 progname);
2443 cleanup();
2444 exit(1);
2445 }
2446 return -1;
2447 }
2448 return handle_new_child(tcp, childpid, 0);
2449 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002450 if (status >> 16 == PTRACE_EVENT_EXEC) {
2451 if (debug)
2452 fprintf(stderr, "PTRACE_EVENT_EXEC on pid %d (ignored)\n", tcp->pid);
2453 return 0;
2454 }
Denys Vlasenko75422762011-05-27 14:36:01 +02002455 /* Some PTRACE_EVENT_foo we didn't ask for?! */
2456 error_msg("Unexpected status %x on pid %d", status, tcp->pid);
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002457 return 1;
2458}
2459#endif
2460
Roland McGratheb9e2e82009-06-02 16:49:22 -07002461static int
2462trace()
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002463{
2464 int pid;
2465 int wait_errno;
2466 int status;
2467 struct tcb *tcp;
2468#ifdef LINUX
2469 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002470#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002471 static int wait4_options = __WALL;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002472#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002473#endif /* LINUX */
2474
Roland McGratheb9e2e82009-06-02 16:49:22 -07002475 while (nprocs != 0) {
Denys Vlasenko222713a2009-03-17 14:29:59 +00002476 if (interrupted)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002477 return 0;
2478 if (interactive)
2479 sigprocmask(SIG_SETMASK, &empty_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002480#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002481#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002482 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002483 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002484 /* this kernel does not support __WALL */
2485 wait4_options &= ~__WALL;
2486 errno = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002487 pid = wait4(-1, &status, wait4_options,
2488 cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002489 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002490 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002491 /* most likely a "cloned" process */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002492 pid = wait4(-1, &status, __WCLONE,
2493 cflag ? &ru : NULL);
2494 if (pid == -1) {
2495 fprintf(stderr, "strace: clone wait4 "
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002496 "failed: %s\n", strerror(errno));
2497 }
2498 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002499#else
2500 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
2501#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002502#endif /* LINUX */
2503#ifdef SUNOS4
2504 pid = wait(&status);
2505#endif /* SUNOS4 */
2506 wait_errno = errno;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002507 if (interactive)
2508 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002509
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002510 if (pid == -1) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002511 switch (wait_errno) {
2512 case EINTR:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002513 continue;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002514 case ECHILD:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002515 /*
2516 * We would like to verify this case
2517 * but sometimes a race in Solbourne's
2518 * version of SunOS sometimes reports
2519 * ECHILD before sending us SIGCHILD.
2520 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002521 return 0;
2522 default:
2523 errno = wait_errno;
2524 perror("strace: wait");
2525 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002526 }
2527 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002528 if (pid == popen_pid) {
2529 if (WIFEXITED(status) || WIFSIGNALED(status))
2530 popen_pid = -1;
2531 continue;
2532 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002533 if (debug)
2534 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2535
2536 /* Look up `pid' in our table. */
2537 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002538#ifdef LINUX
Roland McGrath41c48222008-07-18 00:25:10 +00002539 if (followfork) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002540 /* This is needed to go with the CLONE_PTRACE
2541 changes in process.c/util.c: we might see
2542 the child's initial trap before we see the
2543 parent return from the clone syscall.
2544 Leave the child suspended until the parent
2545 returns from its system call. Only then
2546 will we have the association of parent and
2547 child so that we know how to do clearbpt
2548 in the child. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +00002549 tcp = alloctcb(pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002550 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002551 if (!qflag)
2552 fprintf(stderr, "\
2553Process %d attached (waiting for parent)\n",
2554 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002555 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002556 else
2557 /* This can happen if a clone call used
2558 CLONE_PTRACE itself. */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002559#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002560 {
2561 fprintf(stderr, "unknown pid: %u\n", pid);
2562 if (WIFSTOPPED(status))
2563 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2564 exit(1);
2565 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002566 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002567 /* set current output file */
2568 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002569 curcol = tcp->curcol;
Denys Vlasenko84e20af2009-02-10 16:03:20 +00002570 if (cflag) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002571#ifdef LINUX
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002572 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2573 tcp->stime = ru.ru_stime;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002574#endif /* !LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002575 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002576
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002577 if (tcp->flags & TCB_SUSPENDED) {
2578 /*
2579 * Apparently, doing any ptrace() call on a stopped
2580 * process, provokes the kernel to report the process
2581 * status again on a subsequent wait(), even if the
2582 * process has not been actually restarted.
2583 * Since we have inspected the arguments of suspended
2584 * processes we end up here testing for this case.
2585 */
2586 continue;
2587 }
2588 if (WIFSIGNALED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002589 if (pid == strace_child)
2590 exit_code = 0x100 | WTERMSIG(status);
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002591 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002592 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2593 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002594 tprintf("+++ killed by %s %s+++",
2595 signame(WTERMSIG(status)),
2596#ifdef WCOREDUMP
2597 WCOREDUMP(status) ? "(core dumped) " :
2598#endif
2599 "");
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002600 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002601 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002602#ifdef TCB_GROUP_EXITING
2603 handle_group_exit(tcp, -1);
2604#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002605 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002606#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002607 continue;
2608 }
2609 if (WIFEXITED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002610 if (pid == strace_child)
2611 exit_code = WEXITSTATUS(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002612 if (debug)
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002613 fprintf(stderr, "pid %u exited with %d\n", pid, WEXITSTATUS(status));
2614 if ((tcp->flags & (TCB_ATTACHED|TCB_STARTUP)) == TCB_ATTACHED
Roland McGrath05690952004-10-20 01:00:27 +00002615#ifdef TCB_GROUP_EXITING
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002616 && !(tcp->parent && (tcp->parent->flags & TCB_GROUP_EXITING))
Roland McGrath1bfd3102007-08-03 10:02:00 +00002617 && !(tcp->flags & TCB_GROUP_EXITING)
Roland McGrath05690952004-10-20 01:00:27 +00002618#endif
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002619 ) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002620 fprintf(stderr,
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002621 "PANIC: attached pid %u exited with %d\n",
2622 pid, WEXITSTATUS(status));
2623 }
Roland McGrath0a396902003-06-10 03:05:53 +00002624 if (tcp == tcp_last) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002625 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT)) == TCB_INSYSCALL)
Roland McGrath0a396902003-06-10 03:05:53 +00002626 tprintf(" <unfinished ... exit status %d>\n",
2627 WEXITSTATUS(status));
2628 tcp_last = NULL;
2629 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002630#ifdef TCB_GROUP_EXITING
2631 handle_group_exit(tcp, -1);
2632#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002633 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002634#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002635 continue;
2636 }
2637 if (!WIFSTOPPED(status)) {
2638 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2639 droptcb(tcp);
2640 continue;
2641 }
2642 if (debug)
2643 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002644 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002645
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002646 if (status >> 16) {
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002647 if (handle_ptrace_event(status, tcp) != 1)
2648 goto tracing;
2649 }
2650
Roland McGrath02203312007-06-11 22:06:31 +00002651 /*
2652 * Interestingly, the process may stop
2653 * with STOPSIG equal to some other signal
Roland McGratheb9e2e82009-06-02 16:49:22 -07002654 * than SIGSTOP if we happend to attach
Roland McGrath02203312007-06-11 22:06:31 +00002655 * just before the process takes a signal.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002656 * A no-MMU vforked child won't send up a signal,
2657 * so skip the first (lost) execve notification.
Roland McGrath02203312007-06-11 22:06:31 +00002658 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002659 if ((tcp->flags & TCB_STARTUP) &&
2660 (WSTOPSIG(status) == SIGSTOP || strace_vforked)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002661 /*
2662 * This flag is there to keep us in sync.
2663 * Next time this process stops it should
2664 * really be entering a system call.
2665 */
2666 tcp->flags &= ~TCB_STARTUP;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002667 if (tcp->flags & TCB_BPTSET) {
Roland McGrath02203312007-06-11 22:06:31 +00002668 /*
2669 * One example is a breakpoint inherited from
2670 * parent through fork ().
2671 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002672 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2673 droptcb(tcp);
2674 cleanup();
2675 return -1;
2676 }
2677 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002678#ifdef LINUX
Denys Vlasenkof44cce42011-06-21 14:34:10 +02002679 /* If options were not set for this tracee yet */
2680 if (tcp->parent == NULL) {
2681 if (ptrace_setoptions) {
2682 if (debug)
2683 fprintf(stderr, "setting opts %x on pid %d\n", ptrace_setoptions, tcp->pid);
2684 if (ptrace(PTRACE_SETOPTIONS, tcp->pid, NULL, ptrace_setoptions) < 0) {
2685 if (errno != ESRCH) {
2686 /* Should never happen, really */
2687 perror_msg_and_die("PTRACE_SETOPTIONS");
2688 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002689 }
2690 }
2691 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002692#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002693 goto tracing;
2694 }
2695
Denys Vlasenko75422762011-05-27 14:36:01 +02002696 if (WSTOPSIG(status) != syscall_trap_sig) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002697 if (WSTOPSIG(status) == SIGSTOP &&
2698 (tcp->flags & TCB_SIGTRAPPED)) {
2699 /*
2700 * Trapped attempt to block SIGTRAP
2701 * Hope we are back in control now.
2702 */
2703 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002704 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002705 cleanup();
2706 return -1;
2707 }
2708 continue;
2709 }
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002710 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002711 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Dmitry V. Levinc15dfc72011-03-10 14:44:45 +00002712 siginfo_t si;
2713#if defined(PT_CR_IPSR) && defined(PT_CR_IIP)
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002714 long pc = 0;
2715 long psr = 0;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002716
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002717 upeek(tcp, PT_CR_IPSR, &psr);
2718 upeek(tcp, PT_CR_IIP, &pc);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002719
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002720# define PSR_RI 41
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002721 pc += (psr >> PSR_RI) & 0x3;
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002722# define PC_FORMAT_STR " @ %lx"
2723# define PC_FORMAT_ARG pc
2724#else
2725# define PC_FORMAT_STR "%s"
2726# define PC_FORMAT_ARG ""
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002727#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002728 printleader(tcp);
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002729 if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
2730 tprintf("--- ");
2731 printsiginfo(&si, verbose(tcp));
2732 tprintf(" (%s)" PC_FORMAT_STR " ---",
2733 strsignal(WSTOPSIG(status)),
2734 PC_FORMAT_ARG);
2735 } else
2736 tprintf("--- %s by %s" PC_FORMAT_STR " ---",
2737 strsignal(WSTOPSIG(status)),
2738 signame(WSTOPSIG(status)),
2739 PC_FORMAT_ARG);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002740 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002741 }
Roland McGrath05690952004-10-20 01:00:27 +00002742 if (((tcp->flags & TCB_ATTACHED) ||
2743 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002744 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002745#ifdef TCB_GROUP_EXITING
2746 handle_group_exit(tcp, WSTOPSIG(status));
2747#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002748 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002749#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002750 continue;
2751 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002752 if (ptrace_restart(PTRACE_SYSCALL, tcp, WSTOPSIG(status)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002753 cleanup();
2754 return -1;
2755 }
2756 tcp->flags &= ~TCB_SUSPENDED;
2757 continue;
2758 }
Roland McGrath02203312007-06-11 22:06:31 +00002759 /* we handled the STATUS, we are permitted to interrupt now. */
2760 if (interrupted)
2761 return 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002762 if (trace_syscall(tcp) < 0 && !tcp->ptrace_errno) {
2763 /* ptrace() failed in trace_syscall() with ESRCH.
2764 * Likely a result of process disappearing mid-flight.
2765 * Observed case: exit_group() terminating
2766 * all processes in thread group. In this case, threads
2767 * "disappear" in an unpredictable moment without any
2768 * notification to strace via wait().
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002769 */
2770 if (tcp->flags & TCB_ATTACHED) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002771 if (tcp_last) {
2772 /* Do we have dangling line "syscall(param, param"?
2773 * Finish the line then. We cannot
2774 */
2775 tcp_last->flags |= TCB_REPRINT;
2776 tprintf(" <unfinished ...>");
2777 printtrailer();
2778 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002779 detach(tcp, 0);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002780 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002781 ptrace(PTRACE_KILL,
2782 tcp->pid, (char *) 1, SIGTERM);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002783 droptcb(tcp);
2784 }
2785 continue;
2786 }
2787 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002788#ifdef TCB_GROUP_EXITING
2789 if (tcp->flags & TCB_GROUP_EXITING) {
2790 if (handle_group_exit(tcp, 0) < 0)
2791 return -1;
2792 continue;
2793 }
2794#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002795 if (tcp->flags & TCB_ATTACHED)
2796 detach(tcp, 0);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002797 else if (ptrace_restart(PTRACE_CONT, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002798 cleanup();
2799 return -1;
2800 }
2801 continue;
2802 }
2803 if (tcp->flags & TCB_SUSPENDED) {
2804 if (!qflag)
2805 fprintf(stderr, "Process %u suspended\n", pid);
2806 continue;
2807 }
2808 tracing:
Andreas Schwabccdff482009-10-27 16:27:13 +01002809 /* Remember current print column before continuing. */
2810 tcp->curcol = curcol;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002811 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002812 cleanup();
2813 return -1;
2814 }
2815 }
2816 return 0;
2817}
2818
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002819#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002820
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002821#include <stdarg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002822
2823void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002824tprintf(const char *fmt, ...)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002825{
2826 va_list args;
2827
Andreas Schwabe5355de2009-10-27 16:56:43 +01002828 va_start(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002829 if (outf) {
2830 int n = vfprintf(outf, fmt, args);
Andreas Schwabccdff482009-10-27 16:27:13 +01002831 if (n < 0) {
2832 if (outf != stderr)
2833 perror(outfname == NULL
2834 ? "<writing to pipe>" : outfname);
2835 } else
Roland McGrathb310a0c2003-11-06 23:41:22 +00002836 curcol += n;
2837 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002838 va_end(args);
2839 return;
2840}
2841
2842void
Denys Vlasenko12014262011-05-30 14:00:14 +02002843printleader(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002844{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002845 if (tcp_last) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002846 if (tcp_last->ptrace_errno) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002847 if (tcp_last->flags & TCB_INSYSCALL) {
Denys Vlasenkoe62df002011-06-08 16:15:04 +02002848 tprintf(" <unavailable>) ");
Roland McGratheb9e2e82009-06-02 16:49:22 -07002849 tabto(acolumn);
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002850 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002851 tprintf("= ? <unavailable>\n");
2852 tcp_last->ptrace_errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002853 } else if (!outfname || followfork < 2 || tcp_last == tcp) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002854 tcp_last->flags |= TCB_REPRINT;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002855 tprintf(" <unfinished ...>\n");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002856 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002857 }
2858 curcol = 0;
2859 if ((followfork == 1 || pflag_seen > 1) && outfname)
2860 tprintf("%-5d ", tcp->pid);
2861 else if (nprocs > 1 && !outfname)
2862 tprintf("[pid %5u] ", tcp->pid);
2863 if (tflag) {
2864 char str[sizeof("HH:MM:SS")];
2865 struct timeval tv, dtv;
2866 static struct timeval otv;
2867
2868 gettimeofday(&tv, NULL);
2869 if (rflag) {
2870 if (otv.tv_sec == 0)
2871 otv = tv;
2872 tv_sub(&dtv, &tv, &otv);
2873 tprintf("%6ld.%06ld ",
2874 (long) dtv.tv_sec, (long) dtv.tv_usec);
2875 otv = tv;
2876 }
2877 else if (tflag > 2) {
2878 tprintf("%ld.%06ld ",
2879 (long) tv.tv_sec, (long) tv.tv_usec);
2880 }
2881 else {
2882 time_t local = tv.tv_sec;
2883 strftime(str, sizeof(str), "%T", localtime(&local));
2884 if (tflag > 1)
2885 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2886 else
2887 tprintf("%s ", str);
2888 }
2889 }
2890 if (iflag)
2891 printcall(tcp);
2892}
2893
2894void
Denys Vlasenko12014262011-05-30 14:00:14 +02002895tabto(int col)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002896{
2897 if (curcol < col)
2898 tprintf("%*s", col - curcol, "");
2899}
2900
2901void
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002902printtrailer(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002903{
2904 tprintf("\n");
2905 tcp_last = NULL;
2906}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002907
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002908#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002909
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002910int
2911mp_ioctl(int fd, int cmd, void *arg, int size)
2912{
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002913 struct iovec iov[2];
2914 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002915
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002916 iov[0].iov_base = &cmd;
2917 iov[0].iov_len = sizeof cmd;
2918 if (arg) {
2919 ++n;
2920 iov[1].iov_base = arg;
2921 iov[1].iov_len = size;
2922 }
Roland McGrath553a6092002-12-16 20:40:39 +00002923
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002924 return writev(fd, iov, n);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002925}
2926
2927#endif