blob: 84fc1b77bb050d69e94b47d91ce177224ef145a6 [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;
Denys Vlasenko2b60c352011-06-22 12:45:25 +0200130static unsigned int nprocs, tcbtabsize;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000131const char *progname;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000132
Andreas Schwabe5355de2009-10-27 16:56:43 +0100133static int detach(struct tcb *tcp, int sig);
134static int trace(void);
135static void cleanup(void);
136static void interrupt(int sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000137static sigset_t empty_set, blocked_set;
138
139#ifdef HAVE_SIG_ATOMIC_T
140static volatile sig_atomic_t interrupted;
141#else /* !HAVE_SIG_ATOMIC_T */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000142static volatile int interrupted;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000143#endif /* !HAVE_SIG_ATOMIC_T */
144
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000145#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000146
Andreas Schwabe5355de2009-10-27 16:56:43 +0100147static struct tcb *pfd2tcb(int pfd);
148static void reaper(int sig);
149static void rebuild_pollv(void);
Roland McGrathee9d4352002-12-18 04:16:10 +0000150static struct pollfd *pollv;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000151
152#ifndef HAVE_POLLABLE_PROCFS
153
Andreas Schwabe5355de2009-10-27 16:56:43 +0100154static void proc_poll_open(void);
155static void proc_poller(int pfd);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000156
157struct proc_pollfd {
158 int fd;
159 int revents;
160 int pid;
161};
162
163static int poller_pid;
164static int proc_poll_pipe[2] = { -1, -1 };
165
166#endif /* !HAVE_POLLABLE_PROCFS */
167
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000168#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000169#define POLLWANT POLLWRNORM
170#else
171#define POLLWANT POLLPRI
172#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000173#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000174
175static void
176usage(ofp, exitval)
177FILE *ofp;
178int exitval;
179{
180 fprintf(ofp, "\
Grant Edwards8a082772011-04-07 20:25:40 +0000181usage: strace [-CdDffhiqrtttTvVxxy] [-a column] [-e expr] ... [-o file]\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000182 [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n\
Grant Edwards8a082772011-04-07 20:25:40 +0000183 [-P path] [command [arg ...]]\n\
Andreas Schwabb87d30c2010-06-11 15:49:36 +0200184 or: strace -c [-D] [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000185 [command [arg ...]]\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000186-c -- count time, calls, and errors for each syscall and report summary\n\
Andreas Schwabb87d30c2010-06-11 15:49:36 +0200187-C -- like -c but also print regular output while processes are running\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000188-f -- follow forks, -ff -- with output into separate files\n\
189-F -- attempt to follow vforks, -h -- print help message\n\
190-i -- print instruction pointer at time of syscall\n\
191-q -- suppress messages about attaching, detaching, etc.\n\
192-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
193-T -- print time spent in each syscall, -V -- print version\n\
194-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
195-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
Grant Edwards8a082772011-04-07 20:25:40 +0000196-y -- print paths associated with file descriptor arguments\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000197-a column -- alignment COLUMN for printing syscall results (default %d)\n\
198-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
199 options: trace, abbrev, verbose, raw, signal, read, or write\n\
200-o file -- send trace output to FILE instead of stderr\n\
201-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
202-p pid -- trace process with process id PID, may be repeated\n\
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000203-D -- run tracer process as a detached grandchild, not as parent\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000204-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
205-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
206-u username -- run command as username handling setuid and/or setgid\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000207-E var=val -- put var=val in the environment for command\n\
208-E var -- remove var from the environment for command\n\
Grant Edwards8a082772011-04-07 20:25:40 +0000209-P path -- trace accesses to path\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000210" /* this is broken, so don't document it
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000211-z -- print only succeeding syscalls\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000212 */
213, DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000214 exit(exitval);
215}
216
Denys Vlasenko75422762011-05-27 14:36:01 +0200217static void die(void) __attribute__ ((noreturn));
218static void die(void)
219{
220 if (strace_tracer_pid == getpid()) {
221 cflag = 0;
222 cleanup();
223 }
224 exit(1);
225}
226
227static void verror_msg(int err_no, const char *fmt, va_list p)
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200228{
Dmitry V. Levin44d05322011-06-09 15:50:41 +0000229 fflush(NULL);
230 fprintf(stderr, "%s: ", progname);
231 vfprintf(stderr, fmt, p);
232 if (err_no)
233 fprintf(stderr, ": %s\n", strerror(err_no));
234 else
235 putc('\n', stderr);
236 fflush(stderr);
Denys Vlasenko75422762011-05-27 14:36:01 +0200237}
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200238
Denys Vlasenko75422762011-05-27 14:36:01 +0200239void error_msg(const char *fmt, ...)
240{
241 va_list p;
242 va_start(p, fmt);
243 verror_msg(0, fmt, p);
244 va_end(p);
245}
246
247void error_msg_and_die(const char *fmt, ...)
248{
249 va_list p;
250 va_start(p, fmt);
251 verror_msg(0, fmt, p);
252 die();
253}
254
255void perror_msg(const char *fmt, ...)
256{
257 va_list p;
258 va_start(p, fmt);
259 verror_msg(errno, fmt, p);
260 va_end(p);
261}
262
263void perror_msg_and_die(const char *fmt, ...)
264{
265 va_list p;
266 va_start(p, fmt);
267 verror_msg(errno, fmt, p);
268 die();
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200269}
270
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000271#ifdef SVR4
272#ifdef MIPS
273void
274foobar()
275{
276}
277#endif /* MIPS */
278#endif /* SVR4 */
279
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400280/* Glue for systems without a MMU that cannot provide fork() */
281#ifdef HAVE_FORK
282# define strace_vforked 0
283#else
284# define strace_vforked 1
285# define fork() vfork()
286#endif
287
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000288static int
289set_cloexec_flag(int fd)
290{
291 int flags, newflags;
292
293 if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
294 {
295 fprintf(stderr, "%s: fcntl F_GETFD: %s\n",
296 progname, strerror(errno));
297 return -1;
298 }
299
300 newflags = flags | FD_CLOEXEC;
301 if (flags == newflags)
302 return 0;
303
304 if (fcntl(fd, F_SETFD, newflags) < 0)
305 {
306 fprintf(stderr, "%s: fcntl F_SETFD: %s\n",
307 progname, strerror(errno));
308 return -1;
309 }
310
311 return 0;
312}
313
314/*
315 * When strace is setuid executable, we have to swap uids
316 * before and after filesystem and process management operations.
317 */
318static void
319swap_uid(void)
320{
321#ifndef SVR4
322 int euid = geteuid(), uid = getuid();
323
324 if (euid != uid && setreuid(euid, uid) < 0)
325 {
326 fprintf(stderr, "%s: setreuid: %s\n",
327 progname, strerror(errno));
328 exit(1);
329 }
330#endif
331}
332
Roland McGrath4bfa6262007-07-05 20:03:16 +0000333#if _LFS64_LARGEFILE
334# define fopen_for_output fopen64
335#else
336# define fopen_for_output fopen
337#endif
338
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000339static FILE *
340strace_fopen(const char *path, const char *mode)
341{
342 FILE *fp;
343
344 swap_uid();
Roland McGrath4bfa6262007-07-05 20:03:16 +0000345 if ((fp = fopen_for_output(path, mode)) == NULL)
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000346 fprintf(stderr, "%s: can't fopen '%s': %s\n",
347 progname, path, strerror(errno));
348 swap_uid();
349 if (fp && set_cloexec_flag(fileno(fp)) < 0)
350 {
351 fclose(fp);
352 fp = NULL;
353 }
354 return fp;
355}
356
357static int popen_pid = -1;
358
359#ifndef _PATH_BSHELL
360# define _PATH_BSHELL "/bin/sh"
361#endif
362
363/*
364 * We cannot use standard popen(3) here because we have to distinguish
365 * popen child process from other processes we trace, and standard popen(3)
366 * does not export its child's pid.
367 */
368static FILE *
369strace_popen(const char *command)
370{
371 int fds[2];
372
373 swap_uid();
374 if (pipe(fds) < 0)
375 {
376 fprintf(stderr, "%s: pipe: %s\n",
377 progname, strerror(errno));
378 swap_uid();
379 return NULL;
380 }
381
382 if (set_cloexec_flag(fds[1]) < 0)
383 {
384 close(fds[0]);
385 close(fds[1]);
386 swap_uid();
387 return NULL;
388 }
389
390 if ((popen_pid = fork()) == -1)
391 {
392 fprintf(stderr, "%s: fork: %s\n",
393 progname, strerror(errno));
394 close(fds[0]);
395 close(fds[1]);
396 swap_uid();
397 return NULL;
398 }
399
400 if (popen_pid)
401 {
402 /* parent */
403 close(fds[0]);
404 swap_uid();
405 return fdopen(fds[1], "w");
406 } else
407 {
408 /* child */
409 close(fds[1]);
410 if (fds[0] && (dup2(fds[0], 0) || close(fds[0])))
411 {
412 fprintf(stderr, "%s: dup2: %s\n",
413 progname, strerror(errno));
414 _exit(1);
415 }
416 execl(_PATH_BSHELL, "sh", "-c", command, NULL);
417 fprintf(stderr, "%s: execl: %s: %s\n",
418 progname, _PATH_BSHELL, strerror(errno));
419 _exit(1);
420 }
421}
422
423static int
424newoutf(struct tcb *tcp)
425{
426 if (outfname && followfork > 1) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000427 char name[520 + sizeof(int) * 3];
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000428 FILE *fp;
429
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000430 sprintf(name, "%.512s.%u", outfname, tcp->pid);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000431 if ((fp = strace_fopen(name, "w")) == NULL)
432 return -1;
433 tcp->outf = fp;
434 }
435 return 0;
436}
437
Roland McGrath02203312007-06-11 22:06:31 +0000438static void
439startup_attach(void)
440{
441 int tcbi;
442 struct tcb *tcp;
443
444 /*
445 * Block user interruptions as we would leave the traced
446 * process stopped (process state T) if we would terminate in
447 * between PTRACE_ATTACH and wait4 () on SIGSTOP.
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200448 * We rely on cleanup() from this point on.
Roland McGrath02203312007-06-11 22:06:31 +0000449 */
450 if (interactive)
451 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
452
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000453 if (daemonized_tracer) {
454 pid_t pid = fork();
455 if (pid < 0) {
456 _exit(1);
457 }
458 if (pid) { /* parent */
459 /*
Denys Vlasenko75422762011-05-27 14:36:01 +0200460 * Wait for grandchild to attach to straced process
461 * (grandparent). Grandchild SIGKILLs us after it attached.
462 * Grandparent's wait() is unblocked by our death,
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000463 * it proceeds to exec the straced program.
464 */
465 pause();
466 _exit(0); /* paranoia */
467 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200468 /* grandchild */
469 /* We will be the tracer process. Remember our new pid: */
470 strace_tracer_pid = getpid();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000471 }
472
Roland McGrath02203312007-06-11 22:06:31 +0000473 for (tcbi = 0; tcbi < tcbtabsize; tcbi++) {
474 tcp = tcbtab[tcbi];
475 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
476 continue;
477#ifdef LINUX
478 if (tcp->flags & TCB_CLONE_THREAD)
479 continue;
480#endif
481 /* Reinitialize the output since it may have changed. */
482 tcp->outf = outf;
483 if (newoutf(tcp) < 0)
484 exit(1);
485
486#ifdef USE_PROCFS
487 if (proc_open(tcp, 1) < 0) {
488 fprintf(stderr, "trouble opening proc file\n");
489 droptcb(tcp);
490 continue;
491 }
492#else /* !USE_PROCFS */
493# ifdef LINUX
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000494 if (followfork && !daemonized_tracer) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000495 char procdir[sizeof("/proc/%d/task") + sizeof(int) * 3];
Roland McGrath02203312007-06-11 22:06:31 +0000496 DIR *dir;
497
498 sprintf(procdir, "/proc/%d/task", tcp->pid);
499 dir = opendir(procdir);
500 if (dir != NULL) {
501 unsigned int ntid = 0, nerr = 0;
502 struct dirent *de;
503 int tid;
504 while ((de = readdir(dir)) != NULL) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000505 if (de->d_fileno == 0)
Roland McGrath02203312007-06-11 22:06:31 +0000506 continue;
507 tid = atoi(de->d_name);
508 if (tid <= 0)
509 continue;
510 ++ntid;
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000511 if (ptrace(PTRACE_ATTACH, tid, (char *) 1, 0) < 0)
Roland McGrath02203312007-06-11 22:06:31 +0000512 ++nerr;
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000513 else if (tid != tcbtab[tcbi]->pid) {
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000514 tcp = alloctcb(tid);
Wang Chao21b8db42010-08-27 17:43:16 +0800515 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_FOLLOWFORK;
Roland McGrath02203312007-06-11 22:06:31 +0000516 tcbtab[tcbi]->nclone_threads++;
Roland McGrath02203312007-06-11 22:06:31 +0000517 tcp->parent = tcbtab[tcbi];
518 }
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000519 if (interactive) {
520 sigprocmask(SIG_SETMASK, &empty_set, NULL);
521 if (interrupted)
522 return;
523 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
524 }
Roland McGrath02203312007-06-11 22:06:31 +0000525 }
526 closedir(dir);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000527 ntid -= nerr;
528 if (ntid == 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000529 perror("attach: ptrace(PTRACE_ATTACH, ...)");
530 droptcb(tcp);
531 continue;
532 }
533 if (!qflag) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000534 fprintf(stderr, ntid > 1
535? "Process %u attached with %u threads - interrupt to quit\n"
536: "Process %u attached - interrupt to quit\n",
537 tcbtab[tcbi]->pid, ntid);
Roland McGrath02203312007-06-11 22:06:31 +0000538 }
539 continue;
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000540 } /* if (opendir worked) */
541 } /* if (-f) */
Roland McGrath02203312007-06-11 22:06:31 +0000542# endif
543 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
544 perror("attach: ptrace(PTRACE_ATTACH, ...)");
545 droptcb(tcp);
546 continue;
547 }
548 /* INTERRUPTED is going to be checked at the top of TRACE. */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000549
550 if (daemonized_tracer) {
551 /*
552 * It is our grandparent we trace, not a -p PID.
553 * Don't want to just detach on exit, so...
554 */
555 tcp->flags &= ~TCB_ATTACHED;
556 /*
557 * Make parent go away.
558 * Also makes grandparent's wait() unblock.
559 */
560 kill(getppid(), SIGKILL);
561 }
562
Roland McGrath02203312007-06-11 22:06:31 +0000563#endif /* !USE_PROCFS */
564 if (!qflag)
565 fprintf(stderr,
566 "Process %u attached - interrupt to quit\n",
567 tcp->pid);
568 }
569
570 if (interactive)
571 sigprocmask(SIG_SETMASK, &empty_set, NULL);
572}
573
574static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200575startup_child(char **argv)
Roland McGrath02203312007-06-11 22:06:31 +0000576{
577 struct stat statbuf;
578 const char *filename;
579 char pathname[MAXPATHLEN];
580 int pid = 0;
581 struct tcb *tcp;
582
583 filename = argv[0];
584 if (strchr(filename, '/')) {
585 if (strlen(filename) > sizeof pathname - 1) {
586 errno = ENAMETOOLONG;
587 perror("strace: exec");
588 exit(1);
589 }
590 strcpy(pathname, filename);
591 }
592#ifdef USE_DEBUGGING_EXEC
593 /*
594 * Debuggers customarily check the current directory
595 * first regardless of the path but doing that gives
596 * security geeks a panic attack.
597 */
598 else if (stat(filename, &statbuf) == 0)
599 strcpy(pathname, filename);
600#endif /* USE_DEBUGGING_EXEC */
601 else {
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000602 const char *path;
Roland McGrath02203312007-06-11 22:06:31 +0000603 int m, n, len;
604
605 for (path = getenv("PATH"); path && *path; path += m) {
606 if (strchr(path, ':')) {
607 n = strchr(path, ':') - path;
608 m = n + 1;
609 }
610 else
611 m = n = strlen(path);
612 if (n == 0) {
613 if (!getcwd(pathname, MAXPATHLEN))
614 continue;
615 len = strlen(pathname);
616 }
617 else if (n > sizeof pathname - 1)
618 continue;
619 else {
620 strncpy(pathname, path, n);
621 len = n;
622 }
623 if (len && pathname[len - 1] != '/')
624 pathname[len++] = '/';
625 strcpy(pathname + len, filename);
626 if (stat(pathname, &statbuf) == 0 &&
627 /* Accept only regular files
628 with some execute bits set.
629 XXX not perfect, might still fail */
630 S_ISREG(statbuf.st_mode) &&
631 (statbuf.st_mode & 0111))
632 break;
633 }
634 }
635 if (stat(pathname, &statbuf) < 0) {
636 fprintf(stderr, "%s: %s: command not found\n",
637 progname, filename);
638 exit(1);
639 }
Dmitry V. Levina6809652008-11-10 17:14:58 +0000640 strace_child = pid = fork();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000641 if (pid < 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000642 perror("strace: fork");
643 cleanup();
644 exit(1);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000645 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200646 if ((pid != 0 && daemonized_tracer) /* -D: parent to become a traced process */
647 || (pid == 0 && !daemonized_tracer) /* not -D: child to become a traced process */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000648 ) {
649 pid = getpid();
Roland McGrath02203312007-06-11 22:06:31 +0000650#ifdef USE_PROCFS
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200651 if (outf != stderr) close(fileno(outf));
Roland McGrath02203312007-06-11 22:06:31 +0000652#ifdef MIPS
653 /* Kludge for SGI, see proc_open for details. */
654 sa.sa_handler = foobar;
655 sa.sa_flags = 0;
656 sigemptyset(&sa.sa_mask);
657 sigaction(SIGINT, &sa, NULL);
658#endif /* MIPS */
659#ifndef FREEBSD
660 pause();
661#else /* FREEBSD */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000662 kill(pid, SIGSTOP); /* stop HERE */
Roland McGrath02203312007-06-11 22:06:31 +0000663#endif /* FREEBSD */
664#else /* !USE_PROCFS */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200665 if (outf != stderr)
666 close(fileno(outf));
Roland McGrath02203312007-06-11 22:06:31 +0000667
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000668 if (!daemonized_tracer) {
669 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
670 perror("strace: ptrace(PTRACE_TRACEME, ...)");
671 exit(1);
672 }
673 if (debug)
674 kill(pid, SIGSTOP);
Roland McGrath02203312007-06-11 22:06:31 +0000675 }
Roland McGrath02203312007-06-11 22:06:31 +0000676
677 if (username != NULL || geteuid() == 0) {
678 uid_t run_euid = run_uid;
679 gid_t run_egid = run_gid;
680
681 if (statbuf.st_mode & S_ISUID)
682 run_euid = statbuf.st_uid;
683 if (statbuf.st_mode & S_ISGID)
684 run_egid = statbuf.st_gid;
685
686 /*
687 * It is important to set groups before we
688 * lose privileges on setuid.
689 */
690 if (username != NULL) {
691 if (initgroups(username, run_gid) < 0) {
692 perror("initgroups");
693 exit(1);
694 }
695 if (setregid(run_gid, run_egid) < 0) {
696 perror("setregid");
697 exit(1);
698 }
699 if (setreuid(run_uid, run_euid) < 0) {
700 perror("setreuid");
701 exit(1);
702 }
703 }
704 }
705 else
706 setreuid(run_uid, run_uid);
707
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000708 if (!daemonized_tracer) {
709 /*
710 * Induce an immediate stop so that the parent
711 * will resume us with PTRACE_SYSCALL and display
712 * this execve call normally.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400713 * Unless of course we're on a no-MMU system where
714 * we vfork()-ed, so we cannot stop the child.
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000715 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400716 if (!strace_vforked)
717 kill(getpid(), SIGSTOP);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000718 } else {
719 struct sigaction sv_sigchld;
720 sigaction(SIGCHLD, NULL, &sv_sigchld);
721 /*
722 * Make sure it is not SIG_IGN, otherwise wait
723 * will not block.
724 */
725 signal(SIGCHLD, SIG_DFL);
726 /*
727 * Wait for grandchild to attach to us.
728 * It kills child after that, and wait() unblocks.
729 */
730 alarm(3);
731 wait(NULL);
732 alarm(0);
733 sigaction(SIGCHLD, &sv_sigchld, NULL);
734 }
Roland McGrath02203312007-06-11 22:06:31 +0000735#endif /* !USE_PROCFS */
736
737 execv(pathname, argv);
738 perror("strace: exec");
739 _exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000740 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000741
742 /* We are the tracer. */
Denys Vlasenko75422762011-05-27 14:36:01 +0200743 /* With -D, we are *child* here, IOW: different pid. Fetch it. */
744 strace_tracer_pid = getpid();
745
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000746 tcp = alloctcb(daemonized_tracer ? getppid() : pid);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000747 if (daemonized_tracer) {
748 /* We want subsequent startup_attach() to attach to it. */
749 tcp->flags |= TCB_ATTACHED;
750 }
Roland McGrath02203312007-06-11 22:06:31 +0000751#ifdef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000752 if (proc_open(tcp, 0) < 0) {
753 fprintf(stderr, "trouble opening proc file\n");
754 cleanup();
755 exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000756 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000757#endif /* USE_PROCFS */
Roland McGrath02203312007-06-11 22:06:31 +0000758}
759
Wang Chaob13c0de2010-11-12 17:25:19 +0800760#ifdef LINUX
761/*
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000762 * Test whether the kernel support PTRACE_O_TRACECLONE et al options.
Wang Chaob13c0de2010-11-12 17:25:19 +0800763 * First fork a new child, call ptrace with PTRACE_SETOPTIONS on it,
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000764 * and then see which options are supported by the kernel.
Wang Chaob13c0de2010-11-12 17:25:19 +0800765 */
766static int
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200767test_ptrace_setoptions_followfork(void)
Wang Chaob13c0de2010-11-12 17:25:19 +0800768{
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000769 int pid, expected_grandchild = 0, found_grandchild = 0;
770 const unsigned int test_options = PTRACE_O_TRACECLONE |
771 PTRACE_O_TRACEFORK |
772 PTRACE_O_TRACEVFORK;
Wang Chaob13c0de2010-11-12 17:25:19 +0800773
774 if ((pid = fork()) < 0)
775 return -1;
776 else if (pid == 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000777 if (ptrace(PTRACE_TRACEME, 0, (char *)1, 0) < 0)
Wang Chaob13c0de2010-11-12 17:25:19 +0800778 _exit(1);
Wang Chaob13c0de2010-11-12 17:25:19 +0800779 kill(getpid(), SIGSTOP);
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000780 _exit(fork() < 0);
Wang Chaob13c0de2010-11-12 17:25:19 +0800781 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000782
783 while (1) {
784 int status, tracee_pid;
785
786 tracee_pid = wait(&status);
787 if (tracee_pid == -1) {
788 if (errno == EINTR)
789 continue;
790 else if (errno == ECHILD)
791 break;
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200792 perror("test_ptrace_setoptions_followfork");
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000793 return -1;
794 }
795 if (tracee_pid != pid) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000796 found_grandchild = tracee_pid;
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000797 if (ptrace(PTRACE_CONT, tracee_pid, 0, 0) < 0 &&
798 errno != ESRCH)
799 kill(tracee_pid, SIGKILL);
800 }
801 else if (WIFSTOPPED(status)) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000802 switch (WSTOPSIG(status)) {
803 case SIGSTOP:
804 if (ptrace(PTRACE_SETOPTIONS, pid,
805 NULL, test_options) < 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000806 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800807 return -1;
808 }
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000809 break;
810 case SIGTRAP:
811 if (status >> 16 == PTRACE_EVENT_FORK) {
812 long msg = 0;
813
814 if (ptrace(PTRACE_GETEVENTMSG, pid,
815 NULL, (long) &msg) == 0)
816 expected_grandchild = msg;
817 }
818 break;
Wang Chaob13c0de2010-11-12 17:25:19 +0800819 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000820 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0 &&
821 errno != ESRCH)
822 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800823 }
824 }
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000825 if (expected_grandchild && expected_grandchild == found_grandchild)
Denys Vlasenkof44cce42011-06-21 14:34:10 +0200826 ptrace_setoptions |= test_options;
Wang Chaob13c0de2010-11-12 17:25:19 +0800827 return 0;
828}
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200829
830/*
831 * Test whether the kernel support PTRACE_O_TRACESYSGOOD.
832 * First fork a new child, call ptrace(PTRACE_SETOPTIONS) on it,
833 * and then see whether it will stop with (SIGTRAP | 0x80).
834 *
835 * Use of this option enables correct handling of user-generated SIGTRAPs,
836 * and SIGTRAPs generated by special instructions such as int3 on x86:
837 * _start: .globl _start
838 * int3
839 * movl $42, %ebx
840 * movl $1, %eax
841 * int $0x80
842 * (compile with: "gcc -nostartfiles -nostdlib -o int3 int3.S")
843 */
844static void
845test_ptrace_setoptions_for_all(void)
846{
847 const unsigned int test_options = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC;
848 int pid;
849 int it_worked = 0;
850
851 pid = fork();
852 if (pid < 0)
Denys Vlasenko75422762011-05-27 14:36:01 +0200853 perror_msg_and_die("fork");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200854
855 if (pid == 0) {
856 pid = getpid();
857 if (ptrace(PTRACE_TRACEME, 0L, 0L, 0L) < 0)
Denys Vlasenko75422762011-05-27 14:36:01 +0200858 /* Note: exits with exitcode 1 */
859 perror_msg_and_die("%s: PTRACE_TRACEME doesn't work", __func__);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200860 kill(pid, SIGSTOP);
861 _exit(0); /* parent should see entry into this syscall */
862 }
863
864 while (1) {
865 int status, tracee_pid;
866
867 errno = 0;
868 tracee_pid = wait(&status);
869 if (tracee_pid <= 0) {
870 if (errno == EINTR)
871 continue;
872 kill(pid, SIGKILL);
Denys Vlasenko75422762011-05-27 14:36:01 +0200873 perror_msg_and_die("%s: unexpected wait result %d", __func__, tracee_pid);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200874 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200875 if (WIFEXITED(status)) {
876 if (WEXITSTATUS(status) == 0)
877 break;
878 /* PTRACE_TRACEME failed in child. This is fatal. */
879 exit(1);
880 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200881 if (!WIFSTOPPED(status)) {
882 kill(pid, SIGKILL);
883 error_msg_and_die("%s: unexpected wait status %x", __func__, status);
884 }
885 if (WSTOPSIG(status) == SIGSTOP) {
886 /*
887 * We don't check "options aren't accepted" error.
888 * If it happens, we'll never get (SIGTRAP | 0x80),
889 * and thus will decide to not use the option.
890 * IOW: the outcome of the test will be correct.
891 */
Denys Vlasenko75422762011-05-27 14:36:01 +0200892 if (ptrace(PTRACE_SETOPTIONS, pid, 0L, test_options) < 0)
893 if (errno != EINVAL)
894 perror_msg("PTRACE_SETOPTIONS");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200895 }
896 if (WSTOPSIG(status) == (SIGTRAP | 0x80)) {
897 it_worked = 1;
898 }
899 if (ptrace(PTRACE_SYSCALL, pid, 0L, 0L) < 0) {
900 kill(pid, SIGKILL);
Denys Vlasenko75422762011-05-27 14:36:01 +0200901 perror_msg_and_die("PTRACE_SYSCALL doesn't work");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200902 }
903 }
904
905 if (it_worked) {
Denys Vlasenko75422762011-05-27 14:36:01 +0200906 syscall_trap_sig = (SIGTRAP | 0x80);
Denys Vlasenkof44cce42011-06-21 14:34:10 +0200907 ptrace_setoptions |= test_options;
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200908 if (debug)
Denys Vlasenkof44cce42011-06-21 14:34:10 +0200909 fprintf(stderr, "ptrace_setoptions = %#x\n",
910 ptrace_setoptions);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200911 return;
912 }
913
914 fprintf(stderr,
915 "Test for PTRACE_O_TRACESYSGOOD failed, giving up using this feature.\n");
916}
Wang Chaob13c0de2010-11-12 17:25:19 +0800917#endif
918
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000919int
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000920main(int argc, char *argv[])
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000921{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000922 struct tcb *tcp;
923 int c, pid = 0;
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000924 int optF = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000925 struct sigaction sa;
926
927 static char buf[BUFSIZ];
928
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000929 progname = argv[0] ? argv[0] : "strace";
930
Denys Vlasenko75422762011-05-27 14:36:01 +0200931 strace_tracer_pid = getpid();
932
Roland McGrathee9d4352002-12-18 04:16:10 +0000933 /* Allocate the initial tcbtab. */
934 tcbtabsize = argc; /* Surely enough for all -p args. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000935 if ((tcbtab = calloc(tcbtabsize, sizeof tcbtab[0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000936 fprintf(stderr, "%s: out of memory\n", progname);
937 exit(1);
938 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000939 if ((tcbtab[0] = calloc(tcbtabsize, sizeof tcbtab[0][0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000940 fprintf(stderr, "%s: out of memory\n", progname);
941 exit(1);
942 }
Roland McGrathee9d4352002-12-18 04:16:10 +0000943 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
944 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
945
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000946 outf = stderr;
947 interactive = 1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000948 set_sortby(DEFAULT_SORTBY);
949 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000950 qualify("trace=all");
951 qualify("abbrev=all");
952 qualify("verbose=all");
953 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000954 while ((c = getopt(argc, argv,
Grant Edwards8a082772011-04-07 20:25:40 +0000955 "+cCdfFhiqrtTvVxyz"
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000956#ifndef USE_PROCFS
957 "D"
958#endif
Grant Edwards8a082772011-04-07 20:25:40 +0000959 "a:e:o:O:p:s:S:u:E:P:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000960 switch (c) {
961 case 'c':
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000962 if (cflag == CFLAG_BOTH) {
963 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
964 progname);
965 exit(1);
966 }
967 cflag = CFLAG_ONLY_STATS;
968 break;
969 case 'C':
970 if (cflag == CFLAG_ONLY_STATS) {
971 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
972 progname);
973 exit(1);
974 }
975 cflag = CFLAG_BOTH;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000976 break;
977 case 'd':
978 debug++;
979 break;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000980#ifndef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000981 case 'D':
982 daemonized_tracer = 1;
983 break;
984#endif
Roland McGrath41c48222008-07-18 00:25:10 +0000985 case 'F':
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000986 optF = 1;
987 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000988 case 'f':
989 followfork++;
990 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000991 case 'h':
992 usage(stdout, 0);
993 break;
994 case 'i':
995 iflag++;
996 break;
997 case 'q':
998 qflag++;
999 break;
1000 case 'r':
1001 rflag++;
1002 tflag++;
1003 break;
1004 case 't':
1005 tflag++;
1006 break;
1007 case 'T':
1008 dtime++;
1009 break;
1010 case 'x':
1011 xflag++;
1012 break;
Grant Edwards8a082772011-04-07 20:25:40 +00001013 case 'y':
1014 show_fd_path = 1;
1015 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001016 case 'v':
1017 qualify("abbrev=none");
1018 break;
1019 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +00001020 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001021 exit(0);
1022 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +00001023 case 'z':
1024 not_failing_only = 1;
1025 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001026 case 'a':
1027 acolumn = atoi(optarg);
1028 break;
1029 case 'e':
1030 qualify(optarg);
1031 break;
1032 case 'o':
1033 outfname = strdup(optarg);
1034 break;
1035 case 'O':
1036 set_overhead(atoi(optarg));
1037 break;
1038 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +00001039 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001040 fprintf(stderr, "%s: Invalid process id: %s\n",
1041 progname, optarg);
1042 break;
1043 }
Denys Vlasenko75422762011-05-27 14:36:01 +02001044 if (pid == strace_tracer_pid) {
Wichert Akkerman54a47671999-10-17 00:57:34 +00001045 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001046 break;
1047 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001048 tcp = alloc_tcb(pid, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001049 tcp->flags |= TCB_ATTACHED;
1050 pflag_seen++;
1051 break;
Grant Edwards8a082772011-04-07 20:25:40 +00001052 case 'P':
1053 tracing_paths = 1;
1054 if (pathtrace_select(optarg)) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001055 fprintf(stderr, "%s : failed to select path '%s'\n", progname, optarg);
Grant Edwards8a082772011-04-07 20:25:40 +00001056 exit(1);
1057 }
1058 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001059 case 's':
1060 max_strlen = atoi(optarg);
Roland McGrathdccec722005-05-09 07:45:47 +00001061 if (max_strlen < 0) {
1062 fprintf(stderr,
1063 "%s: invalid -s argument: %s\n",
1064 progname, optarg);
1065 exit(1);
1066 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001067 break;
1068 case 'S':
1069 set_sortby(optarg);
1070 break;
1071 case 'u':
1072 username = strdup(optarg);
1073 break;
Roland McGrathde6e5332003-01-24 04:31:23 +00001074 case 'E':
1075 if (putenv(optarg) < 0) {
1076 fprintf(stderr, "%s: out of memory\n",
1077 progname);
1078 exit(1);
1079 }
1080 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001081 default:
1082 usage(stderr, 1);
1083 break;
1084 }
1085 }
1086
Roland McGrathd0c4c0c2006-04-25 07:39:40 +00001087 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +00001088 usage(stderr, 1);
1089
Wang Chaod322a4b2010-08-05 14:30:11 +08001090 if (pflag_seen && daemonized_tracer) {
1091 fprintf(stderr,
1092 "%s: -D and -p are mutually exclusive options\n",
1093 progname);
1094 exit(1);
1095 }
1096
Dmitry V. Levin06350db2008-07-25 15:42:34 +00001097 if (!followfork)
1098 followfork = optF;
1099
Roland McGrathcb9def62006-04-25 07:48:03 +00001100 if (followfork > 1 && cflag) {
1101 fprintf(stderr,
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00001102 "%s: (-c or -C) and -ff are mutually exclusive options\n",
Roland McGrathcb9def62006-04-25 07:48:03 +00001103 progname);
1104 exit(1);
1105 }
1106
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001107 /* See if they want to run as another user. */
1108 if (username != NULL) {
1109 struct passwd *pent;
1110
1111 if (getuid() != 0 || geteuid() != 0) {
1112 fprintf(stderr,
1113 "%s: you must be root to use the -u option\n",
1114 progname);
1115 exit(1);
1116 }
1117 if ((pent = getpwnam(username)) == NULL) {
1118 fprintf(stderr, "%s: cannot find user `%s'\n",
Roland McGrath09553f82007-07-05 19:31:49 +00001119 progname, username);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001120 exit(1);
1121 }
1122 run_uid = pent->pw_uid;
1123 run_gid = pent->pw_gid;
1124 }
1125 else {
1126 run_uid = getuid();
1127 run_gid = getgid();
1128 }
1129
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001130#ifdef LINUX
1131 if (followfork) {
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02001132 if (test_ptrace_setoptions_followfork() < 0) {
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001133 fprintf(stderr,
1134 "Test for options supported by PTRACE_SETOPTIONS "
1135 "failed, giving up using this feature.\n");
Denys Vlasenkof44cce42011-06-21 14:34:10 +02001136 ptrace_setoptions = 0;
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001137 }
1138 if (debug)
Denys Vlasenkof44cce42011-06-21 14:34:10 +02001139 fprintf(stderr, "ptrace_setoptions = %#x\n",
1140 ptrace_setoptions);
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001141 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02001142 test_ptrace_setoptions_for_all();
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001143#endif
1144
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001145 /* Check if they want to redirect the output. */
1146 if (outfname) {
Roland McGrath37b9a662003-11-07 02:26:54 +00001147 /* See if they want to pipe the output. */
1148 if (outfname[0] == '|' || outfname[0] == '!') {
1149 /*
1150 * We can't do the <outfname>.PID funny business
1151 * when using popen, so prohibit it.
1152 */
1153 if (followfork > 1) {
1154 fprintf(stderr, "\
1155%s: piping the output and -ff are mutually exclusive options\n",
1156 progname);
1157 exit(1);
1158 }
1159
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001160 if ((outf = strace_popen(outfname + 1)) == NULL)
Roland McGrath37b9a662003-11-07 02:26:54 +00001161 exit(1);
Roland McGrath37b9a662003-11-07 02:26:54 +00001162 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001163 else if (followfork <= 1 &&
1164 (outf = strace_fopen(outfname, "w")) == NULL)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001165 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001166 }
1167
Roland McGrath37b9a662003-11-07 02:26:54 +00001168 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001169 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +00001170 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001171 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001172 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +00001173 }
Wang Chaob13c0de2010-11-12 17:25:19 +08001174
Roland McGrath54cc1c82007-11-03 23:34:11 +00001175 /* Valid states here:
1176 optind < argc pflag_seen outfname interactive
1177 1 0 0 1
1178 0 1 0 1
1179 1 0 1 0
1180 0 1 1 1
1181 */
1182
1183 /* STARTUP_CHILD must be called before the signal handlers get
1184 installed below as they are inherited into the spawned process.
1185 Also we do not need to be protected by them as during interruption
1186 in the STARTUP_CHILD mode we kill the spawned process anyway. */
1187 if (!pflag_seen)
1188 startup_child(&argv[optind]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001189
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001190 sigemptyset(&empty_set);
1191 sigemptyset(&blocked_set);
1192 sa.sa_handler = SIG_IGN;
1193 sigemptyset(&sa.sa_mask);
1194 sa.sa_flags = 0;
1195 sigaction(SIGTTOU, &sa, NULL);
1196 sigaction(SIGTTIN, &sa, NULL);
1197 if (interactive) {
1198 sigaddset(&blocked_set, SIGHUP);
1199 sigaddset(&blocked_set, SIGINT);
1200 sigaddset(&blocked_set, SIGQUIT);
1201 sigaddset(&blocked_set, SIGPIPE);
1202 sigaddset(&blocked_set, SIGTERM);
1203 sa.sa_handler = interrupt;
1204#ifdef SUNOS4
1205 /* POSIX signals on sunos4.1 are a little broken. */
1206 sa.sa_flags = SA_INTERRUPT;
1207#endif /* SUNOS4 */
1208 }
1209 sigaction(SIGHUP, &sa, NULL);
1210 sigaction(SIGINT, &sa, NULL);
1211 sigaction(SIGQUIT, &sa, NULL);
1212 sigaction(SIGPIPE, &sa, NULL);
1213 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001214#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001215 sa.sa_handler = reaper;
1216 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +00001217#else
1218 /* Make sure SIGCHLD has the default action so that waitpid
1219 definitely works without losing track of children. The user
1220 should not have given us a bogus state to inherit, but he might
1221 have. Arguably we should detect SIG_IGN here and pass it on
1222 to children, but probably noone really needs that. */
1223 sa.sa_handler = SIG_DFL;
1224 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001225#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001226
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +00001227 if (pflag_seen || daemonized_tracer)
Roland McGrath02203312007-06-11 22:06:31 +00001228 startup_attach();
Roland McGrath02203312007-06-11 22:06:31 +00001229
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001230 if (trace() < 0)
1231 exit(1);
1232 cleanup();
Dmitry V. Levina6809652008-11-10 17:14:58 +00001233 fflush(NULL);
1234 if (exit_code > 0xff) {
1235 /* Child was killed by a signal, mimic that. */
1236 exit_code &= 0xff;
1237 signal(exit_code, SIG_DFL);
1238 raise(exit_code);
1239 /* Paranoia - what if this signal is not fatal?
1240 Exit with 128 + signo then. */
1241 exit_code += 128;
1242 }
1243 exit(exit_code);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001244}
1245
Denys Vlasenko2b60c352011-06-22 12:45:25 +02001246static void
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001247expand_tcbtab(void)
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001248{
1249 /* Allocate some more TCBs and expand the table.
1250 We don't want to relocate the TCBs because our
1251 callers have pointers and it would be a pain.
1252 So tcbtab is a table of pointers. Since we never
1253 free the TCBs, we allocate a single chunk of many. */
Denys Vlasenko18da2732011-06-22 12:41:57 +02001254 int i = tcbtabsize;
1255 struct tcb *newtcbs = calloc(tcbtabsize, sizeof(newtcbs[0]));
1256 struct tcb **newtab = realloc(tcbtab, tcbtabsize * 2 * sizeof(tcbtab[0]));
1257 if (newtab == NULL || newtcbs == NULL)
1258 error_msg_and_die("expand_tcbtab: out of memory");
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001259 tcbtabsize *= 2;
1260 tcbtab = newtab;
Denys Vlasenko18da2732011-06-22 12:41:57 +02001261 while (i < tcbtabsize)
1262 tcbtab[i++] = newtcbs++;
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001263}
1264
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001265struct tcb *
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001266alloc_tcb(int pid, int command_options_parsed)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001267{
1268 int i;
1269 struct tcb *tcp;
1270
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001271 if (nprocs == tcbtabsize)
1272 expand_tcbtab();
1273
Roland McGrathee9d4352002-12-18 04:16:10 +00001274 for (i = 0; i < tcbtabsize; i++) {
1275 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001276 if ((tcp->flags & TCB_INUSE) == 0) {
Denys Vlasenko18da2732011-06-22 12:41:57 +02001277 memset(tcp, 0, sizeof(*tcp));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001278 tcp->pid = pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001279 tcp->flags = TCB_INUSE | TCB_STARTUP;
1280 tcp->outf = outf; /* Initialise to current out file */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001281 tcp->pfd = -1;
1282 nprocs++;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001283 if (command_options_parsed)
1284 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001285 return tcp;
1286 }
1287 }
Denys Vlasenko18da2732011-06-22 12:41:57 +02001288 error_msg_and_die("bug in alloc_tcb");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001289}
1290
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001291#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001292int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001293proc_open(struct tcb *tcp, int attaching)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001294{
1295 char proc[32];
1296 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001297#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +00001298 int i;
1299 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001300 sigset_t signals;
1301 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001302#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001303#ifndef HAVE_POLLABLE_PROCFS
1304 static int last_pfd;
1305#endif
1306
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001307#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001308 /* Open the process pseudo-files in /proc. */
1309 sprintf(proc, "/proc/%d/ctl", tcp->pid);
1310 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001311 perror("strace: open(\"/proc/...\", ...)");
1312 return -1;
1313 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001314 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001315 return -1;
1316 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001317 sprintf(proc, "/proc/%d/status", tcp->pid);
1318 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
1319 perror("strace: open(\"/proc/...\", ...)");
1320 return -1;
1321 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001322 if (set_cloexec_flag(tcp->pfd_stat) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001323 return -1;
1324 }
1325 sprintf(proc, "/proc/%d/as", tcp->pid);
1326 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
1327 perror("strace: open(\"/proc/...\", ...)");
1328 return -1;
1329 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001330 if (set_cloexec_flag(tcp->pfd_as) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001331 return -1;
1332 }
1333#else
1334 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001335#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001336 sprintf(proc, "/proc/%d", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001337 tcp->pfd = open(proc, O_RDWR|O_EXCL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001338#else /* FREEBSD */
1339 sprintf(proc, "/proc/%d/mem", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001340 tcp->pfd = open(proc, O_RDWR);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001341#endif /* FREEBSD */
Andreas Schwab372cc842010-07-09 11:49:27 +02001342 if (tcp->pfd < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001343 perror("strace: open(\"/proc/...\", ...)");
1344 return -1;
1345 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001346 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001347 return -1;
1348 }
1349#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001350#ifdef FREEBSD
1351 sprintf(proc, "/proc/%d/regs", tcp->pid);
1352 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
1353 perror("strace: open(\"/proc/.../regs\", ...)");
1354 return -1;
1355 }
1356 if (cflag) {
1357 sprintf(proc, "/proc/%d/status", tcp->pid);
1358 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
1359 perror("strace: open(\"/proc/.../status\", ...)");
1360 return -1;
1361 }
1362 } else
1363 tcp->pfd_status = -1;
1364#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001365 rebuild_pollv();
1366 if (!attaching) {
1367 /*
1368 * Wait for the child to pause. Because of a race
1369 * condition we have to poll for the event.
1370 */
1371 for (;;) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001372 if (IOCTL_STATUS(tcp) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001373 perror("strace: PIOCSTATUS");
1374 return -1;
1375 }
1376 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001377 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001378 }
1379 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001380#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001381 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001382 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001383 perror("strace: PIOCSTOP");
1384 return -1;
1385 }
Roland McGrath553a6092002-12-16 20:40:39 +00001386#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001387#ifdef PIOCSET
1388 /* Set Run-on-Last-Close. */
1389 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001390 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001391 perror("PIOCSET PR_RLC");
1392 return -1;
1393 }
1394 /* Set or Reset Inherit-on-Fork. */
1395 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001396 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001397 perror("PIOC{SET,RESET} PR_FORK");
1398 return -1;
1399 }
1400#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +00001401#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001402 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
1403 perror("PIOCSRLC");
1404 return -1;
1405 }
1406 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
1407 perror("PIOC{S,R}FORK");
1408 return -1;
1409 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001410#else /* FREEBSD */
1411 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
1412 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
1413 perror("PIOCGFL");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001414 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001415 }
1416 arg &= ~PF_LINGER;
1417 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001418 perror("PIOCSFL");
1419 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001420 }
1421#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001422#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001423#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +00001424 /* Enable all syscall entries we care about. */
1425 premptyset(&syscalls);
1426 for (i = 1; i < MAX_QUALS; ++i) {
1427 if (i > (sizeof syscalls) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001428 if (qual_flags[i] & QUAL_TRACE) praddset(&syscalls, i);
John Hughes19e49982001-10-19 08:59:12 +00001429 }
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001430 praddset(&syscalls, SYS_execve);
John Hughes19e49982001-10-19 08:59:12 +00001431 if (followfork) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001432 praddset(&syscalls, SYS_fork);
John Hughes19e49982001-10-19 08:59:12 +00001433#ifdef SYS_forkall
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001434 praddset(&syscalls, SYS_forkall);
John Hughes19e49982001-10-19 08:59:12 +00001435#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001436#ifdef SYS_fork1
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001437 praddset(&syscalls, SYS_fork1);
John Hughes19e49982001-10-19 08:59:12 +00001438#endif
1439#ifdef SYS_rfork1
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001440 praddset(&syscalls, SYS_rfork1);
John Hughes19e49982001-10-19 08:59:12 +00001441#endif
1442#ifdef SYS_rforkall
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001443 praddset(&syscalls, SYS_rforkall);
John Hughes19e49982001-10-19 08:59:12 +00001444#endif
1445 }
1446 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001447 perror("PIOCSENTRY");
1448 return -1;
1449 }
John Hughes19e49982001-10-19 08:59:12 +00001450 /* Enable the syscall exits. */
1451 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001452 perror("PIOSEXIT");
1453 return -1;
1454 }
John Hughes19e49982001-10-19 08:59:12 +00001455 /* Enable signals we care about. */
1456 premptyset(&signals);
1457 for (i = 1; i < MAX_QUALS; ++i) {
1458 if (i > (sizeof signals) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001459 if (qual_flags[i] & QUAL_SIGNAL) praddset(&signals, i);
John Hughes19e49982001-10-19 08:59:12 +00001460 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001461 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001462 perror("PIOCSTRACE");
1463 return -1;
1464 }
John Hughes19e49982001-10-19 08:59:12 +00001465 /* Enable faults we care about */
1466 premptyset(&faults);
1467 for (i = 1; i < MAX_QUALS; ++i) {
1468 if (i > (sizeof faults) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001469 if (qual_flags[i] & QUAL_FAULT) praddset(&faults, i);
John Hughes19e49982001-10-19 08:59:12 +00001470 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001471 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001472 perror("PIOCSFAULT");
1473 return -1;
1474 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001475#else /* FREEBSD */
1476 /* set events flags. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001477 arg = S_SIG | S_SCE | S_SCX;
1478 if (ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001479 perror("PIOCBIS");
1480 return -1;
1481 }
1482#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001483 if (!attaching) {
1484#ifdef MIPS
1485 /*
1486 * The SGI PRSABORT doesn't work for pause() so
1487 * we send it a caught signal to wake it up.
1488 */
1489 kill(tcp->pid, SIGINT);
1490#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +00001491#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001492 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001493 arg = PRSABORT;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001494 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001495 perror("PIOCRUN");
1496 return -1;
1497 }
Roland McGrath553a6092002-12-16 20:40:39 +00001498#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001499#endif /* !MIPS*/
1500#ifdef FREEBSD
1501 /* wake up the child if it received the SIGSTOP */
1502 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001503#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001504 for (;;) {
1505 /* Wait for the child to do something. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001506 if (IOCTL_WSTOP(tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001507 perror("PIOCWSTOP");
1508 return -1;
1509 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001510 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001511 tcp->flags &= ~TCB_INSYSCALL;
1512 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001513 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001514 break;
1515 }
1516 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001517#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001518 arg = 0;
1519 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001520#else /* FREEBSD */
1521 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001522#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001523 perror("PIOCRUN");
1524 return -1;
1525 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001526#ifdef FREEBSD
1527 /* handle the case where we "opened" the child before
1528 it did the kill -STOP */
1529 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1530 tcp->status.PR_WHAT == SIGSTOP)
1531 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001532#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001533 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001534#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001535 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001536#else /* FREEBSD */
1537 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001538 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001539 /* We are attaching to an already running process.
1540 * Try to figure out the state of the process in syscalls,
1541 * to handle the first event well.
1542 * This is done by having a look at the "wchan" property of the
1543 * process, which tells where it is stopped (if it is). */
1544 FILE * status;
1545 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001546
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001547 sprintf(proc, "/proc/%d/status", tcp->pid);
1548 status = fopen(proc, "r");
1549 if (status &&
1550 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1551 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1552 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1553 strcmp(wchan, "stopevent")) {
1554 /* The process is asleep in the middle of a syscall.
1555 Fake the syscall entry event */
1556 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1557 tcp->status.PR_WHY = PR_SYSENTRY;
1558 trace_syscall(tcp);
1559 }
1560 if (status)
1561 fclose(status);
1562 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001563 }
1564#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001565#ifndef HAVE_POLLABLE_PROCFS
1566 if (proc_poll_pipe[0] != -1)
1567 proc_poller(tcp->pfd);
1568 else if (nprocs > 1) {
1569 proc_poll_open();
1570 proc_poller(last_pfd);
1571 proc_poller(tcp->pfd);
1572 }
1573 last_pfd = tcp->pfd;
1574#endif /* !HAVE_POLLABLE_PROCFS */
1575 return 0;
1576}
1577
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001578#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001579
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001580struct tcb *
Roland McGrath54e931f2010-09-14 18:59:20 -07001581pid2tcb(int pid)
1582{
1583 int i;
1584
1585 if (pid <= 0)
1586 return NULL;
1587
1588 for (i = 0; i < tcbtabsize; i++) {
1589 struct tcb *tcp = tcbtab[i];
1590 if (tcp->pid == pid && (tcp->flags & TCB_INUSE))
1591 return tcp;
1592 }
1593
1594 return NULL;
1595}
1596
1597#ifdef USE_PROCFS
1598
1599static struct tcb *
1600first_used_tcb(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001601{
1602 int i;
1603 struct tcb *tcp;
Roland McGrathee9d4352002-12-18 04:16:10 +00001604 for (i = 0; i < tcbtabsize; i++) {
1605 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001606 if (tcp->flags & TCB_INUSE)
1607 return tcp;
1608 }
1609 return NULL;
1610}
1611
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001612static struct tcb *
Denys Vlasenko12014262011-05-30 14:00:14 +02001613pfd2tcb(int pfd)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001614{
1615 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001616
Roland McGrathca16be82003-01-10 19:55:28 +00001617 for (i = 0; i < tcbtabsize; i++) {
1618 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001619 if (tcp->pfd != pfd)
1620 continue;
1621 if (tcp->flags & TCB_INUSE)
1622 return tcp;
1623 }
1624 return NULL;
1625}
1626
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001627#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001628
1629void
Denys Vlasenko12014262011-05-30 14:00:14 +02001630droptcb(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001631{
1632 if (tcp->pid == 0)
1633 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001634#ifdef TCB_CLONE_THREAD
1635 if (tcp->nclone_threads > 0) {
1636 /* There are other threads left in this process, but this
1637 is the one whose PID represents the whole process.
1638 We need to keep this record around as a zombie until
1639 all the threads die. */
1640 tcp->flags |= TCB_EXITING;
1641 return;
1642 }
1643#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001644 nprocs--;
1645 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001646
Roland McGrathe29341c2003-01-10 20:14:20 +00001647 if (tcp->parent != NULL) {
Roland McGrathe29341c2003-01-10 20:14:20 +00001648#ifdef TCB_CLONE_THREAD
Roland McGrathe29341c2003-01-10 20:14:20 +00001649 if (tcp->flags & TCB_CLONE_THREAD)
1650 tcp->parent->nclone_threads--;
1651#endif
Roland McGrath276ceb32007-11-13 08:12:12 +00001652#ifdef LINUX
Denys Vlasenkob56d6d32011-06-21 16:06:28 +02001653 /* Update fields like NCLONE_DETACHED, only
1654 for zombie group leader that has already reported
1655 and been short-circuited at the top of this
Roland McGrath276ceb32007-11-13 08:12:12 +00001656 function. The same condition as at the top of DETACH. */
1657 if ((tcp->flags & TCB_CLONE_THREAD) &&
1658 tcp->parent->nclone_threads == 0 &&
1659 (tcp->parent->flags & TCB_EXITING))
1660 droptcb(tcp->parent);
1661#endif
Roland McGrathe29341c2003-01-10 20:14:20 +00001662 tcp->parent = NULL;
1663 }
1664
1665 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001666 if (tcp->pfd != -1) {
1667 close(tcp->pfd);
1668 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001669#ifdef FREEBSD
1670 if (tcp->pfd_reg != -1) {
1671 close(tcp->pfd_reg);
1672 tcp->pfd_reg = -1;
1673 }
1674 if (tcp->pfd_status != -1) {
1675 close(tcp->pfd_status);
1676 tcp->pfd_status = -1;
1677 }
Roland McGrath553a6092002-12-16 20:40:39 +00001678#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001679#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001680 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001681#endif
1682 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001683
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001684 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001685 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001686
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001687 tcp->outf = 0;
1688}
1689
Roland McGrath0a463882007-07-05 18:43:16 +00001690/* detach traced process; continue with sig
1691 Never call DETACH twice on the same process as both unattached and
1692 attached-unstopped processes give the same ESRCH. For unattached process we
1693 would SIGSTOP it and wait for its SIGSTOP notification forever. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001694
1695static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001696detach(struct tcb *tcp, int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001697{
1698 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001699#ifdef LINUX
Roland McGrath1bfd3102007-08-03 10:02:00 +00001700 int status, catch_sigstop;
Roland McGratha08a97e2005-08-03 11:23:46 +00001701 struct tcb *zombie = NULL;
1702
1703 /* If the group leader is lingering only because of this other
1704 thread now dying, then detach the leader as well. */
1705 if ((tcp->flags & TCB_CLONE_THREAD) &&
1706 tcp->parent->nclone_threads == 1 &&
1707 (tcp->parent->flags & TCB_EXITING))
1708 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001709#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001710
1711 if (tcp->flags & TCB_BPTSET)
Andreas Schwab840d85b2010-01-12 11:16:32 +01001712 clearbpt(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001713
1714#ifdef LINUX
1715 /*
1716 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001717 * before detaching. Arghh. We go through hoops
1718 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001719 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001720#if defined(SPARC)
1721#undef PTRACE_DETACH
1722#define PTRACE_DETACH PTRACE_SUNDETACH
1723#endif
Roland McGrath02203312007-06-11 22:06:31 +00001724 /*
1725 * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
1726 * expected SIGSTOP. We must catch exactly one as otherwise the
1727 * detached process would be left stopped (process state T).
1728 */
1729 catch_sigstop = (tcp->flags & TCB_STARTUP);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001730 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1731 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001732 }
1733 else if (errno != ESRCH) {
1734 /* Shouldn't happen. */
1735 perror("detach: ptrace(PTRACE_DETACH, ...)");
1736 }
Roland McGrath134813a2007-06-02 00:07:33 +00001737 else if (my_tgkill((tcp->flags & TCB_CLONE_THREAD ? tcp->parent->pid
1738 : tcp->pid),
1739 tcp->pid, 0) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001740 if (errno != ESRCH)
1741 perror("detach: checking sanity");
1742 }
Roland McGrath02203312007-06-11 22:06:31 +00001743 else if (!catch_sigstop && my_tgkill((tcp->flags & TCB_CLONE_THREAD
1744 ? tcp->parent->pid : tcp->pid),
1745 tcp->pid, SIGSTOP) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001746 if (errno != ESRCH)
1747 perror("detach: stopping child");
1748 }
Roland McGrath02203312007-06-11 22:06:31 +00001749 else
1750 catch_sigstop = 1;
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001751 if (catch_sigstop) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001752 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001753#ifdef __WALL
1754 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1755 if (errno == ECHILD) /* Already gone. */
1756 break;
1757 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001758 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001759 break;
1760 }
1761#endif /* __WALL */
1762 /* No __WALL here. */
1763 if (waitpid(tcp->pid, &status, 0) < 0) {
1764 if (errno != ECHILD) {
1765 perror("detach: waiting");
1766 break;
1767 }
1768#ifdef __WCLONE
1769 /* If no processes, try clones. */
1770 if (wait4(tcp->pid, &status, __WCLONE,
1771 NULL) < 0) {
1772 if (errno != ECHILD)
1773 perror("detach: waiting");
1774 break;
1775 }
1776#endif /* __WCLONE */
1777 }
1778#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001779 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001780#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001781 if (!WIFSTOPPED(status)) {
1782 /* Au revoir, mon ami. */
1783 break;
1784 }
1785 if (WSTOPSIG(status) == SIGSTOP) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001786 ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001787 break;
1788 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001789 error = ptrace_restart(PTRACE_CONT, tcp,
Denys Vlasenko75422762011-05-27 14:36:01 +02001790 WSTOPSIG(status) == syscall_trap_sig ? 0
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001791 : WSTOPSIG(status));
1792 if (error < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001793 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001794 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001795 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001796#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001797
1798#if defined(SUNOS4)
1799 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1800 if (sig && kill(tcp->pid, sig) < 0)
1801 perror("detach: kill");
1802 sig = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001803 error = ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001804#endif /* SUNOS4 */
1805
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001806 if (!qflag)
1807 fprintf(stderr, "Process %u detached\n", tcp->pid);
1808
1809 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001810
1811#ifdef LINUX
Roland McGrath0a463882007-07-05 18:43:16 +00001812 if (zombie != NULL) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001813 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath0a463882007-07-05 18:43:16 +00001814 droptcb(zombie);
1815 }
Roland McGratha08a97e2005-08-03 11:23:46 +00001816#endif
1817
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001818 return error;
1819}
1820
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001821#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001822
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001823static void reaper(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001824{
1825 int pid;
1826 int status;
1827
1828 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001829 }
1830}
1831
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001832#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001833
1834static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001835cleanup(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001836{
1837 int i;
1838 struct tcb *tcp;
1839
Roland McGrathee9d4352002-12-18 04:16:10 +00001840 for (i = 0; i < tcbtabsize; i++) {
1841 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001842 if (!(tcp->flags & TCB_INUSE))
1843 continue;
1844 if (debug)
1845 fprintf(stderr,
1846 "cleanup: looking at pid %u\n", tcp->pid);
1847 if (tcp_last &&
1848 (!outfname || followfork < 2 || tcp_last == tcp)) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001849 tprintf(" <unfinished ...>");
1850 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001851 }
1852 if (tcp->flags & TCB_ATTACHED)
1853 detach(tcp, 0);
1854 else {
1855 kill(tcp->pid, SIGCONT);
1856 kill(tcp->pid, SIGTERM);
1857 }
1858 }
1859 if (cflag)
1860 call_summary(outf);
1861}
1862
1863static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001864interrupt(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001865{
1866 interrupted = 1;
1867}
1868
1869#ifndef HAVE_STRERROR
1870
Roland McGrath6d2b3492002-12-30 00:51:30 +00001871#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001872extern int sys_nerr;
1873extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001874#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001875
1876const char *
Denys Vlasenko12014262011-05-30 14:00:14 +02001877strerror(int err_no)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001878{
1879 static char buf[64];
1880
Denys Vlasenko35aba6a2011-05-25 15:33:26 +02001881 if (err_no < 1 || err_no >= sys_nerr) {
1882 sprintf(buf, "Unknown error %d", err_no);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001883 return buf;
1884 }
Denys Vlasenko35aba6a2011-05-25 15:33:26 +02001885 return sys_errlist[err_no];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001886}
1887
1888#endif /* HAVE_STERRROR */
1889
1890#ifndef HAVE_STRSIGNAL
1891
Roland McGrath8f474e02003-01-14 07:53:33 +00001892#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001893extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001894#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001895#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1896extern char *_sys_siglist[];
1897#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001898
1899const char *
Denys Vlasenko12014262011-05-30 14:00:14 +02001900strsignal(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001901{
1902 static char buf[64];
1903
1904 if (sig < 1 || sig >= NSIG) {
1905 sprintf(buf, "Unknown signal %d", sig);
1906 return buf;
1907 }
1908#ifdef HAVE__SYS_SIGLIST
1909 return _sys_siglist[sig];
1910#else
1911 return sys_siglist[sig];
1912#endif
1913}
1914
1915#endif /* HAVE_STRSIGNAL */
1916
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001917#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001918
1919static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001920rebuild_pollv(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001921{
1922 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001923
Roland McGrathee9d4352002-12-18 04:16:10 +00001924 if (pollv != NULL)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001925 free(pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001926 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001927 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001928 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00001929 exit(1);
1930 }
1931
Roland McGrathca16be82003-01-10 19:55:28 +00001932 for (i = j = 0; i < tcbtabsize; i++) {
1933 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001934 if (!(tcp->flags & TCB_INUSE))
1935 continue;
1936 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001937 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001938 j++;
1939 }
1940 if (j != nprocs) {
1941 fprintf(stderr, "strace: proc miscount\n");
1942 exit(1);
1943 }
1944}
1945
1946#ifndef HAVE_POLLABLE_PROCFS
1947
1948static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001949proc_poll_open(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001950{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001951 int i;
1952
1953 if (pipe(proc_poll_pipe) < 0) {
1954 perror("pipe");
1955 exit(1);
1956 }
1957 for (i = 0; i < 2; i++) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001958 if (set_cloexec_flag(proc_poll_pipe[i]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001959 exit(1);
1960 }
1961 }
1962}
1963
1964static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001965proc_poll(struct pollfd *pollv, int nfds, int timeout)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001966{
1967 int i;
1968 int n;
1969 struct proc_pollfd pollinfo;
1970
1971 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1972 return n;
1973 if (n != sizeof(struct proc_pollfd)) {
1974 fprintf(stderr, "panic: short read: %d\n", n);
1975 exit(1);
1976 }
1977 for (i = 0; i < nprocs; i++) {
1978 if (pollv[i].fd == pollinfo.fd)
1979 pollv[i].revents = pollinfo.revents;
1980 else
1981 pollv[i].revents = 0;
1982 }
1983 poller_pid = pollinfo.pid;
1984 return 1;
1985}
1986
1987static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001988wakeup_handler(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001989{
1990}
1991
1992static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001993proc_poller(int pfd)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001994{
1995 struct proc_pollfd pollinfo;
1996 struct sigaction sa;
1997 sigset_t blocked_set, empty_set;
1998 int i;
1999 int n;
2000 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002001#ifdef FREEBSD
2002 struct procfs_status pfs;
2003#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002004
2005 switch (fork()) {
2006 case -1:
2007 perror("fork");
Dmitry V. Levina6809652008-11-10 17:14:58 +00002008 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002009 case 0:
2010 break;
2011 default:
2012 return;
2013 }
2014
2015 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
2016 sa.sa_flags = 0;
2017 sigemptyset(&sa.sa_mask);
2018 sigaction(SIGHUP, &sa, NULL);
2019 sigaction(SIGINT, &sa, NULL);
2020 sigaction(SIGQUIT, &sa, NULL);
2021 sigaction(SIGPIPE, &sa, NULL);
2022 sigaction(SIGTERM, &sa, NULL);
2023 sa.sa_handler = wakeup_handler;
2024 sigaction(SIGUSR1, &sa, NULL);
2025 sigemptyset(&blocked_set);
2026 sigaddset(&blocked_set, SIGUSR1);
2027 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2028 sigemptyset(&empty_set);
2029
2030 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
2031 perror("getrlimit(RLIMIT_NOFILE, ...)");
Dmitry V. Levina6809652008-11-10 17:14:58 +00002032 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002033 }
2034 n = rl.rlim_cur;
2035 for (i = 0; i < n; i++) {
2036 if (i != pfd && i != proc_poll_pipe[1])
2037 close(i);
2038 }
2039
2040 pollinfo.fd = pfd;
2041 pollinfo.pid = getpid();
2042 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002043#ifndef FREEBSD
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002044 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
2045#else
2046 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
2047#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002048 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002049 switch (errno) {
2050 case EINTR:
2051 continue;
2052 case EBADF:
2053 pollinfo.revents = POLLERR;
2054 break;
2055 case ENOENT:
2056 pollinfo.revents = POLLHUP;
2057 break;
2058 default:
2059 perror("proc_poller: PIOCWSTOP");
2060 }
2061 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2062 _exit(0);
2063 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002064 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002065 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2066 sigsuspend(&empty_set);
2067 }
2068}
2069
2070#endif /* !HAVE_POLLABLE_PROCFS */
2071
2072static int
2073choose_pfd()
2074{
2075 int i, j;
2076 struct tcb *tcp;
2077
2078 static int last;
2079
2080 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002081 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002082 /*
2083 * The previous process is ready to run again. We'll
2084 * let it do so if it is currently in a syscall. This
2085 * heuristic improves the readability of the trace.
2086 */
2087 tcp = pfd2tcb(pollv[last].fd);
2088 if (tcp && (tcp->flags & TCB_INSYSCALL))
2089 return pollv[last].fd;
2090 }
2091
2092 for (i = 0; i < nprocs; i++) {
2093 /* Let competing children run round robin. */
2094 j = (i + last + 1) % nprocs;
2095 if (pollv[j].revents & (POLLHUP | POLLERR)) {
2096 tcp = pfd2tcb(pollv[j].fd);
2097 if (!tcp) {
2098 fprintf(stderr, "strace: lost proc\n");
2099 exit(1);
2100 }
2101 droptcb(tcp);
2102 return -1;
2103 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002104 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002105 last = j;
2106 return pollv[j].fd;
2107 }
2108 }
2109 fprintf(stderr, "strace: nothing ready\n");
2110 exit(1);
2111}
2112
2113static int
Denys Vlasenko12014262011-05-30 14:00:14 +02002114trace(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002115{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002116#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00002117 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002118#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002119 struct tcb *tcp;
2120 int pfd;
2121 int what;
2122 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002123 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002124
2125 for (;;) {
2126 if (interactive)
2127 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2128
2129 if (nprocs == 0)
2130 break;
2131
2132 switch (nprocs) {
2133 case 1:
2134#ifndef HAVE_POLLABLE_PROCFS
2135 if (proc_poll_pipe[0] == -1) {
2136#endif
Roland McGrath54e931f2010-09-14 18:59:20 -07002137 tcp = first_used_tcb();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002138 if (!tcp)
2139 continue;
2140 pfd = tcp->pfd;
2141 if (pfd == -1)
2142 continue;
2143 break;
2144#ifndef HAVE_POLLABLE_PROCFS
2145 }
2146 /* fall through ... */
2147#endif /* !HAVE_POLLABLE_PROCFS */
2148 default:
2149#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002150#ifdef POLL_HACK
2151 /* On some systems (e.g. UnixWare) we get too much ugly
2152 "unfinished..." stuff when multiple proceses are in
2153 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00002154
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002155 if (in_syscall) {
2156 struct pollfd pv;
2157 tcp = in_syscall;
2158 in_syscall = NULL;
2159 pv.fd = tcp->pfd;
2160 pv.events = POLLWANT;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002161 if ((what = poll(&pv, 1, 1)) < 0) {
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002162 if (interrupted)
2163 return 0;
2164 continue;
2165 }
2166 else if (what == 1 && pv.revents & POLLWANT) {
2167 goto FOUND;
2168 }
2169 }
2170#endif
2171
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002172 if (poll(pollv, nprocs, INFTIM) < 0) {
2173 if (interrupted)
2174 return 0;
2175 continue;
2176 }
2177#else /* !HAVE_POLLABLE_PROCFS */
2178 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
2179 if (interrupted)
2180 return 0;
2181 continue;
2182 }
2183#endif /* !HAVE_POLLABLE_PROCFS */
2184 pfd = choose_pfd();
2185 if (pfd == -1)
2186 continue;
2187 break;
2188 }
2189
2190 /* Look up `pfd' in our table. */
2191 if ((tcp = pfd2tcb(pfd)) == NULL) {
2192 fprintf(stderr, "unknown pfd: %u\n", pfd);
2193 exit(1);
2194 }
John Hughesb6643082002-05-23 11:02:22 +00002195#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002196 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00002197#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002198 /* Get the status of the process. */
2199 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002200#ifndef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002201 ioctl_result = IOCTL_WSTOP(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002202#else /* FREEBSD */
2203 /* Thanks to some scheduling mystery, the first poller
2204 sometimes waits for the already processed end of fork
2205 event. Doing a non blocking poll here solves the problem. */
2206 if (proc_poll_pipe[0] != -1)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002207 ioctl_result = IOCTL_STATUS(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002208 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002209 ioctl_result = IOCTL_WSTOP(tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00002210#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002211 ioctl_errno = errno;
2212#ifndef HAVE_POLLABLE_PROCFS
2213 if (proc_poll_pipe[0] != -1) {
2214 if (ioctl_result < 0)
2215 kill(poller_pid, SIGKILL);
2216 else
2217 kill(poller_pid, SIGUSR1);
2218 }
2219#endif /* !HAVE_POLLABLE_PROCFS */
2220 }
2221 if (interrupted)
2222 return 0;
2223
2224 if (interactive)
2225 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2226
2227 if (ioctl_result < 0) {
2228 /* Find out what happened if it failed. */
2229 switch (ioctl_errno) {
2230 case EINTR:
2231 case EBADF:
2232 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002233#ifdef FREEBSD
2234 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00002235#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002236 case ENOENT:
2237 droptcb(tcp);
2238 continue;
2239 default:
2240 perror("PIOCWSTOP");
2241 exit(1);
2242 }
2243 }
2244
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002245#ifdef FREEBSD
2246 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2247 /* discard first event for a syscall we never entered */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002248 IOCTL(tcp->pfd, PIOCRUN, 0);
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002249 continue;
2250 }
Roland McGrath553a6092002-12-16 20:40:39 +00002251#endif
2252
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002253 /* clear the just started flag */
2254 tcp->flags &= ~TCB_STARTUP;
2255
2256 /* set current output file */
2257 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002258 curcol = tcp->curcol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002259
2260 if (cflag) {
2261 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002262#ifdef FREEBSD
2263 char buf[1024];
2264 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002265
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002266 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
2267 buf[len] = '\0';
2268 sscanf(buf,
2269 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2270 &stime.tv_sec, &stime.tv_usec);
2271 } else
2272 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002273#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002274 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2275 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002276#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002277 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2278 tcp->stime = stime;
2279 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002280 what = tcp->status.PR_WHAT;
2281 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002282#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002283 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002284 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2285 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002286 if (trace_syscall(tcp) < 0) {
2287 fprintf(stderr, "syscall trouble\n");
2288 exit(1);
2289 }
2290 }
2291 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002292#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002293 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002294#ifdef POLL_HACK
2295 in_syscall = tcp;
2296#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002297 case PR_SYSEXIT:
2298 if (trace_syscall(tcp) < 0) {
2299 fprintf(stderr, "syscall trouble\n");
2300 exit(1);
2301 }
2302 break;
2303 case PR_SIGNALLED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002304 if (cflag != CFLAG_ONLY_STATS
2305 && (qual_flags[what] & QUAL_SIGNAL)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002306 printleader(tcp);
2307 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002308 signame(what), strsignal(what));
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002309 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002310#ifdef PR_INFO
2311 if (tcp->status.PR_INFO.si_signo == what) {
2312 printleader(tcp);
2313 tprintf(" siginfo=");
2314 printsiginfo(&tcp->status.PR_INFO, 1);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002315 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002316 }
2317#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002318 }
2319 break;
2320 case PR_FAULTED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002321 if (cflag != CFLAGS_ONLY_STATS
2322 && (qual_flags[what] & QUAL_FAULT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002323 printleader(tcp);
2324 tprintf("=== FAULT %d ===", what);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002325 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002326 }
2327 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002328#ifdef FREEBSD
2329 case 0: /* handle case we polled for nothing */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002330 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00002331#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002332 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002333 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002334 exit(1);
2335 break;
2336 }
Andreas Schwabccdff482009-10-27 16:27:13 +01002337 /* Remember current print column before continuing. */
2338 tcp->curcol = curcol;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002339 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002340#ifndef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002341 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002342#else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002343 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002344#endif
Andreas Schwab372cc842010-07-09 11:49:27 +02002345 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002346 perror("PIOCRUN");
2347 exit(1);
2348 }
2349 }
2350 return 0;
2351}
2352
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002353#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002354
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002355#ifdef TCB_GROUP_EXITING
2356/* Handle an exit detach or death signal that is taking all the
2357 related clone threads with it. This is called in three circumstances:
2358 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
2359 SIG == 0 Continuing TCP will perform an exit_group syscall.
2360 SIG == other Continuing TCP with SIG will kill the process.
2361*/
2362static int
2363handle_group_exit(struct tcb *tcp, int sig)
2364{
2365 /* We need to locate our records of all the clone threads
2366 related to TCP, either its children or siblings. */
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002367 struct tcb *leader = NULL;
2368
2369 if (tcp->flags & TCB_CLONE_THREAD)
2370 leader = tcp->parent;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002371
2372 if (sig < 0) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002373 if (leader != NULL && leader != tcp
2374 && !(leader->flags & TCB_GROUP_EXITING)
2375 && !(tcp->flags & TCB_STARTUP)
2376 ) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002377 fprintf(stderr,
2378 "PANIC: handle_group_exit: %d leader %d\n",
2379 tcp->pid, leader ? leader->pid : -1);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002380 }
2381 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath0a463882007-07-05 18:43:16 +00002382 droptcb(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002383 }
2384 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00002385 /* Mark that we are taking the process down. */
2386 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002387 if (tcp->flags & TCB_ATTACHED) {
Roland McGrathd6a32f12007-07-11 08:35:11 +00002388 detach(tcp, sig);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002389 if (leader != NULL && leader != tcp)
Roland McGrath1bfd3102007-08-03 10:02:00 +00002390 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002391 } else {
2392 if (ptrace_restart(PTRACE_CONT, tcp, sig) < 0) {
2393 cleanup();
2394 return -1;
2395 }
2396 if (leader != NULL) {
Roland McGrath05690952004-10-20 01:00:27 +00002397 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002398 if (leader != tcp)
2399 droptcb(tcp);
2400 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002401 /* The leader will report to us as parent now,
2402 and then we'll get to the SIG==-1 case. */
2403 return 0;
2404 }
2405 }
2406
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002407 return 0;
2408}
2409#endif
2410
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002411#ifdef LINUX
2412static int
2413handle_ptrace_event(int status, struct tcb *tcp)
2414{
2415 if (status >> 16 == PTRACE_EVENT_VFORK ||
2416 status >> 16 == PTRACE_EVENT_CLONE ||
2417 status >> 16 == PTRACE_EVENT_FORK) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +00002418 long childpid;
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002419
2420 if (do_ptrace(PTRACE_GETEVENTMSG, tcp, NULL, &childpid) < 0) {
2421 if (errno != ESRCH) {
2422 fprintf(stderr, "\
2423%s: handle_ptrace_event: ptrace cannot get new child's pid\n",
2424 progname);
2425 cleanup();
2426 exit(1);
2427 }
2428 return -1;
2429 }
2430 return handle_new_child(tcp, childpid, 0);
2431 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002432 if (status >> 16 == PTRACE_EVENT_EXEC) {
2433 if (debug)
2434 fprintf(stderr, "PTRACE_EVENT_EXEC on pid %d (ignored)\n", tcp->pid);
2435 return 0;
2436 }
Denys Vlasenko75422762011-05-27 14:36:01 +02002437 /* Some PTRACE_EVENT_foo we didn't ask for?! */
2438 error_msg("Unexpected status %x on pid %d", status, tcp->pid);
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002439 return 1;
2440}
2441#endif
2442
Roland McGratheb9e2e82009-06-02 16:49:22 -07002443static int
2444trace()
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002445{
2446 int pid;
2447 int wait_errno;
2448 int status;
2449 struct tcb *tcp;
2450#ifdef LINUX
2451 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002452#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002453 static int wait4_options = __WALL;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002454#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002455#endif /* LINUX */
2456
Roland McGratheb9e2e82009-06-02 16:49:22 -07002457 while (nprocs != 0) {
Denys Vlasenko222713a2009-03-17 14:29:59 +00002458 if (interrupted)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002459 return 0;
2460 if (interactive)
2461 sigprocmask(SIG_SETMASK, &empty_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002462#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002463#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002464 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002465 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002466 /* this kernel does not support __WALL */
2467 wait4_options &= ~__WALL;
2468 errno = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002469 pid = wait4(-1, &status, wait4_options,
2470 cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002471 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002472 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002473 /* most likely a "cloned" process */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002474 pid = wait4(-1, &status, __WCLONE,
2475 cflag ? &ru : NULL);
2476 if (pid == -1) {
2477 fprintf(stderr, "strace: clone wait4 "
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002478 "failed: %s\n", strerror(errno));
2479 }
2480 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002481#else
2482 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
2483#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002484#endif /* LINUX */
2485#ifdef SUNOS4
2486 pid = wait(&status);
2487#endif /* SUNOS4 */
2488 wait_errno = errno;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002489 if (interactive)
2490 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002491
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002492 if (pid == -1) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002493 switch (wait_errno) {
2494 case EINTR:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002495 continue;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002496 case ECHILD:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002497 /*
2498 * We would like to verify this case
2499 * but sometimes a race in Solbourne's
2500 * version of SunOS sometimes reports
2501 * ECHILD before sending us SIGCHILD.
2502 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002503 return 0;
2504 default:
2505 errno = wait_errno;
2506 perror("strace: wait");
2507 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002508 }
2509 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002510 if (pid == popen_pid) {
2511 if (WIFEXITED(status) || WIFSIGNALED(status))
2512 popen_pid = -1;
2513 continue;
2514 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002515 if (debug)
2516 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2517
2518 /* Look up `pid' in our table. */
2519 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002520#ifdef LINUX
Roland McGrath41c48222008-07-18 00:25:10 +00002521 if (followfork) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002522 /* This is needed to go with the CLONE_PTRACE
2523 changes in process.c/util.c: we might see
2524 the child's initial trap before we see the
2525 parent return from the clone syscall.
2526 Leave the child suspended until the parent
2527 returns from its system call. Only then
2528 will we have the association of parent and
2529 child so that we know how to do clearbpt
2530 in the child. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +00002531 tcp = alloctcb(pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002532 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002533 if (!qflag)
2534 fprintf(stderr, "\
2535Process %d attached (waiting for parent)\n",
2536 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002537 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002538 else
2539 /* This can happen if a clone call used
2540 CLONE_PTRACE itself. */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002541#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002542 {
2543 fprintf(stderr, "unknown pid: %u\n", pid);
2544 if (WIFSTOPPED(status))
2545 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2546 exit(1);
2547 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002548 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002549 /* set current output file */
2550 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002551 curcol = tcp->curcol;
Denys Vlasenko84e20af2009-02-10 16:03:20 +00002552 if (cflag) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002553#ifdef LINUX
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002554 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2555 tcp->stime = ru.ru_stime;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002556#endif /* !LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002557 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002558
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002559 if (tcp->flags & TCB_SUSPENDED) {
2560 /*
2561 * Apparently, doing any ptrace() call on a stopped
2562 * process, provokes the kernel to report the process
2563 * status again on a subsequent wait(), even if the
2564 * process has not been actually restarted.
2565 * Since we have inspected the arguments of suspended
2566 * processes we end up here testing for this case.
2567 */
2568 continue;
2569 }
2570 if (WIFSIGNALED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002571 if (pid == strace_child)
2572 exit_code = 0x100 | WTERMSIG(status);
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002573 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002574 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2575 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002576 tprintf("+++ killed by %s %s+++",
2577 signame(WTERMSIG(status)),
2578#ifdef WCOREDUMP
2579 WCOREDUMP(status) ? "(core dumped) " :
2580#endif
2581 "");
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002582 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002583 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002584#ifdef TCB_GROUP_EXITING
2585 handle_group_exit(tcp, -1);
2586#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002587 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002588#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002589 continue;
2590 }
2591 if (WIFEXITED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002592 if (pid == strace_child)
2593 exit_code = WEXITSTATUS(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002594 if (debug)
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002595 fprintf(stderr, "pid %u exited with %d\n", pid, WEXITSTATUS(status));
2596 if ((tcp->flags & (TCB_ATTACHED|TCB_STARTUP)) == TCB_ATTACHED
Roland McGrath05690952004-10-20 01:00:27 +00002597#ifdef TCB_GROUP_EXITING
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002598 && !(tcp->parent && (tcp->parent->flags & TCB_GROUP_EXITING))
Roland McGrath1bfd3102007-08-03 10:02:00 +00002599 && !(tcp->flags & TCB_GROUP_EXITING)
Roland McGrath05690952004-10-20 01:00:27 +00002600#endif
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002601 ) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002602 fprintf(stderr,
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002603 "PANIC: attached pid %u exited with %d\n",
2604 pid, WEXITSTATUS(status));
2605 }
Roland McGrath0a396902003-06-10 03:05:53 +00002606 if (tcp == tcp_last) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002607 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT)) == TCB_INSYSCALL)
Roland McGrath0a396902003-06-10 03:05:53 +00002608 tprintf(" <unfinished ... exit status %d>\n",
2609 WEXITSTATUS(status));
2610 tcp_last = NULL;
2611 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002612#ifdef TCB_GROUP_EXITING
2613 handle_group_exit(tcp, -1);
2614#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002615 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002616#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002617 continue;
2618 }
2619 if (!WIFSTOPPED(status)) {
2620 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2621 droptcb(tcp);
2622 continue;
2623 }
2624 if (debug)
2625 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002626 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002627
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002628 if (status >> 16) {
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002629 if (handle_ptrace_event(status, tcp) != 1)
2630 goto tracing;
2631 }
2632
Roland McGrath02203312007-06-11 22:06:31 +00002633 /*
2634 * Interestingly, the process may stop
2635 * with STOPSIG equal to some other signal
Roland McGratheb9e2e82009-06-02 16:49:22 -07002636 * than SIGSTOP if we happend to attach
Roland McGrath02203312007-06-11 22:06:31 +00002637 * just before the process takes a signal.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002638 * A no-MMU vforked child won't send up a signal,
2639 * so skip the first (lost) execve notification.
Roland McGrath02203312007-06-11 22:06:31 +00002640 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002641 if ((tcp->flags & TCB_STARTUP) &&
2642 (WSTOPSIG(status) == SIGSTOP || strace_vforked)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002643 /*
2644 * This flag is there to keep us in sync.
2645 * Next time this process stops it should
2646 * really be entering a system call.
2647 */
2648 tcp->flags &= ~TCB_STARTUP;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002649 if (tcp->flags & TCB_BPTSET) {
Roland McGrath02203312007-06-11 22:06:31 +00002650 /*
2651 * One example is a breakpoint inherited from
2652 * parent through fork ().
2653 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002654 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2655 droptcb(tcp);
2656 cleanup();
2657 return -1;
2658 }
2659 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002660#ifdef LINUX
Denys Vlasenkof44cce42011-06-21 14:34:10 +02002661 /* If options were not set for this tracee yet */
2662 if (tcp->parent == NULL) {
2663 if (ptrace_setoptions) {
2664 if (debug)
2665 fprintf(stderr, "setting opts %x on pid %d\n", ptrace_setoptions, tcp->pid);
2666 if (ptrace(PTRACE_SETOPTIONS, tcp->pid, NULL, ptrace_setoptions) < 0) {
2667 if (errno != ESRCH) {
2668 /* Should never happen, really */
2669 perror_msg_and_die("PTRACE_SETOPTIONS");
2670 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002671 }
2672 }
2673 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002674#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002675 goto tracing;
2676 }
2677
Denys Vlasenko75422762011-05-27 14:36:01 +02002678 if (WSTOPSIG(status) != syscall_trap_sig) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002679 if (WSTOPSIG(status) == SIGSTOP &&
2680 (tcp->flags & TCB_SIGTRAPPED)) {
2681 /*
2682 * Trapped attempt to block SIGTRAP
2683 * Hope we are back in control now.
2684 */
2685 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002686 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002687 cleanup();
2688 return -1;
2689 }
2690 continue;
2691 }
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002692 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002693 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Dmitry V. Levinc15dfc72011-03-10 14:44:45 +00002694 siginfo_t si;
2695#if defined(PT_CR_IPSR) && defined(PT_CR_IIP)
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002696 long pc = 0;
2697 long psr = 0;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002698
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002699 upeek(tcp, PT_CR_IPSR, &psr);
2700 upeek(tcp, PT_CR_IIP, &pc);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002701
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002702# define PSR_RI 41
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002703 pc += (psr >> PSR_RI) & 0x3;
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002704# define PC_FORMAT_STR " @ %lx"
2705# define PC_FORMAT_ARG pc
2706#else
2707# define PC_FORMAT_STR "%s"
2708# define PC_FORMAT_ARG ""
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002709#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002710 printleader(tcp);
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002711 if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
2712 tprintf("--- ");
2713 printsiginfo(&si, verbose(tcp));
2714 tprintf(" (%s)" PC_FORMAT_STR " ---",
2715 strsignal(WSTOPSIG(status)),
2716 PC_FORMAT_ARG);
2717 } else
2718 tprintf("--- %s by %s" PC_FORMAT_STR " ---",
2719 strsignal(WSTOPSIG(status)),
2720 signame(WSTOPSIG(status)),
2721 PC_FORMAT_ARG);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002722 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002723 }
Roland McGrath05690952004-10-20 01:00:27 +00002724 if (((tcp->flags & TCB_ATTACHED) ||
2725 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002726 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002727#ifdef TCB_GROUP_EXITING
2728 handle_group_exit(tcp, WSTOPSIG(status));
2729#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002730 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002731#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002732 continue;
2733 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002734 if (ptrace_restart(PTRACE_SYSCALL, tcp, WSTOPSIG(status)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002735 cleanup();
2736 return -1;
2737 }
2738 tcp->flags &= ~TCB_SUSPENDED;
2739 continue;
2740 }
Roland McGrath02203312007-06-11 22:06:31 +00002741 /* we handled the STATUS, we are permitted to interrupt now. */
2742 if (interrupted)
2743 return 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002744 if (trace_syscall(tcp) < 0 && !tcp->ptrace_errno) {
2745 /* ptrace() failed in trace_syscall() with ESRCH.
2746 * Likely a result of process disappearing mid-flight.
2747 * Observed case: exit_group() terminating
2748 * all processes in thread group. In this case, threads
2749 * "disappear" in an unpredictable moment without any
2750 * notification to strace via wait().
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002751 */
2752 if (tcp->flags & TCB_ATTACHED) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002753 if (tcp_last) {
2754 /* Do we have dangling line "syscall(param, param"?
2755 * Finish the line then. We cannot
2756 */
2757 tcp_last->flags |= TCB_REPRINT;
2758 tprintf(" <unfinished ...>");
2759 printtrailer();
2760 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002761 detach(tcp, 0);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002762 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002763 ptrace(PTRACE_KILL,
2764 tcp->pid, (char *) 1, SIGTERM);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002765 droptcb(tcp);
2766 }
2767 continue;
2768 }
2769 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002770#ifdef TCB_GROUP_EXITING
2771 if (tcp->flags & TCB_GROUP_EXITING) {
2772 if (handle_group_exit(tcp, 0) < 0)
2773 return -1;
2774 continue;
2775 }
2776#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002777 if (tcp->flags & TCB_ATTACHED)
2778 detach(tcp, 0);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002779 else if (ptrace_restart(PTRACE_CONT, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002780 cleanup();
2781 return -1;
2782 }
2783 continue;
2784 }
2785 if (tcp->flags & TCB_SUSPENDED) {
2786 if (!qflag)
2787 fprintf(stderr, "Process %u suspended\n", pid);
2788 continue;
2789 }
2790 tracing:
Andreas Schwabccdff482009-10-27 16:27:13 +01002791 /* Remember current print column before continuing. */
2792 tcp->curcol = curcol;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002793 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002794 cleanup();
2795 return -1;
2796 }
2797 }
2798 return 0;
2799}
2800
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002801#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002802
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002803#include <stdarg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002804
2805void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002806tprintf(const char *fmt, ...)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002807{
2808 va_list args;
2809
Andreas Schwabe5355de2009-10-27 16:56:43 +01002810 va_start(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002811 if (outf) {
2812 int n = vfprintf(outf, fmt, args);
Andreas Schwabccdff482009-10-27 16:27:13 +01002813 if (n < 0) {
2814 if (outf != stderr)
2815 perror(outfname == NULL
2816 ? "<writing to pipe>" : outfname);
2817 } else
Roland McGrathb310a0c2003-11-06 23:41:22 +00002818 curcol += n;
2819 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002820 va_end(args);
2821 return;
2822}
2823
2824void
Denys Vlasenko12014262011-05-30 14:00:14 +02002825printleader(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002826{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002827 if (tcp_last) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002828 if (tcp_last->ptrace_errno) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002829 if (tcp_last->flags & TCB_INSYSCALL) {
Denys Vlasenkoe62df002011-06-08 16:15:04 +02002830 tprintf(" <unavailable>) ");
Roland McGratheb9e2e82009-06-02 16:49:22 -07002831 tabto(acolumn);
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002832 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002833 tprintf("= ? <unavailable>\n");
2834 tcp_last->ptrace_errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002835 } else if (!outfname || followfork < 2 || tcp_last == tcp) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002836 tcp_last->flags |= TCB_REPRINT;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002837 tprintf(" <unfinished ...>\n");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002838 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002839 }
2840 curcol = 0;
2841 if ((followfork == 1 || pflag_seen > 1) && outfname)
2842 tprintf("%-5d ", tcp->pid);
2843 else if (nprocs > 1 && !outfname)
2844 tprintf("[pid %5u] ", tcp->pid);
2845 if (tflag) {
2846 char str[sizeof("HH:MM:SS")];
2847 struct timeval tv, dtv;
2848 static struct timeval otv;
2849
2850 gettimeofday(&tv, NULL);
2851 if (rflag) {
2852 if (otv.tv_sec == 0)
2853 otv = tv;
2854 tv_sub(&dtv, &tv, &otv);
2855 tprintf("%6ld.%06ld ",
2856 (long) dtv.tv_sec, (long) dtv.tv_usec);
2857 otv = tv;
2858 }
2859 else if (tflag > 2) {
2860 tprintf("%ld.%06ld ",
2861 (long) tv.tv_sec, (long) tv.tv_usec);
2862 }
2863 else {
2864 time_t local = tv.tv_sec;
2865 strftime(str, sizeof(str), "%T", localtime(&local));
2866 if (tflag > 1)
2867 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2868 else
2869 tprintf("%s ", str);
2870 }
2871 }
2872 if (iflag)
2873 printcall(tcp);
2874}
2875
2876void
Denys Vlasenko12014262011-05-30 14:00:14 +02002877tabto(int col)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002878{
2879 if (curcol < col)
2880 tprintf("%*s", col - curcol, "");
2881}
2882
2883void
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002884printtrailer(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002885{
2886 tprintf("\n");
2887 tcp_last = NULL;
2888}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002889
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002890#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002891
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002892int
2893mp_ioctl(int fd, int cmd, void *arg, int size)
2894{
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002895 struct iovec iov[2];
2896 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002897
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002898 iov[0].iov_base = &cmd;
2899 iov[0].iov_len = sizeof cmd;
2900 if (arg) {
2901 ++n;
2902 iov[1].iov_base = arg;
2903 iov[1].iov_len = size;
2904 }
Roland McGrath553a6092002-12-16 20:40:39 +00002905
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002906 return writev(fd, iov, n);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002907}
2908
2909#endif