blob: 4c91e51984895ce99decfdfe8e4359ae28e8a33e [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
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200357static int popen_pid = 0;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000358
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{
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200371 FILE *fp;
372 int fds[2];
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000373
374 swap_uid();
375 if (pipe(fds) < 0)
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200376 perror_msg_and_die("pipe");
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000377
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200378 set_cloexec_flag(fds[1]); /* never fails */
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000379
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200380 popen_pid = vfork();
381 if (popen_pid == -1)
382 perror_msg_and_die("vfork");
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000383
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200384 if (popen_pid == 0) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000385 /* child */
386 close(fds[1]);
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200387 if (fds[0] != 0) {
388 if (dup2(fds[0], 0))
389 perror_msg_and_die("dup2");
390 close(fds[0]);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000391 }
392 execl(_PATH_BSHELL, "sh", "-c", command, NULL);
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200393 perror_msg_and_die("Can't execute '%s'", _PATH_BSHELL);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000394 }
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200395
396 /* parent */
397 close(fds[0]);
398 swap_uid();
399 fp = fdopen(fds[1], "w");
400 if (!fp)
401 error_msg_and_die("Out of memory");
402 return fp;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000403}
404
405static int
406newoutf(struct tcb *tcp)
407{
408 if (outfname && followfork > 1) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000409 char name[520 + sizeof(int) * 3];
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000410 FILE *fp;
411
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000412 sprintf(name, "%.512s.%u", outfname, tcp->pid);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000413 if ((fp = strace_fopen(name, "w")) == NULL)
414 return -1;
415 tcp->outf = fp;
416 }
417 return 0;
418}
419
Roland McGrath02203312007-06-11 22:06:31 +0000420static void
421startup_attach(void)
422{
423 int tcbi;
424 struct tcb *tcp;
425
426 /*
427 * Block user interruptions as we would leave the traced
428 * process stopped (process state T) if we would terminate in
429 * between PTRACE_ATTACH and wait4 () on SIGSTOP.
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200430 * We rely on cleanup() from this point on.
Roland McGrath02203312007-06-11 22:06:31 +0000431 */
432 if (interactive)
433 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
434
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000435 if (daemonized_tracer) {
436 pid_t pid = fork();
437 if (pid < 0) {
438 _exit(1);
439 }
440 if (pid) { /* parent */
441 /*
Denys Vlasenko75422762011-05-27 14:36:01 +0200442 * Wait for grandchild to attach to straced process
443 * (grandparent). Grandchild SIGKILLs us after it attached.
444 * Grandparent's wait() is unblocked by our death,
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000445 * it proceeds to exec the straced program.
446 */
447 pause();
448 _exit(0); /* paranoia */
449 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200450 /* grandchild */
451 /* We will be the tracer process. Remember our new pid: */
452 strace_tracer_pid = getpid();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000453 }
454
Roland McGrath02203312007-06-11 22:06:31 +0000455 for (tcbi = 0; tcbi < tcbtabsize; tcbi++) {
456 tcp = tcbtab[tcbi];
457 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
458 continue;
459#ifdef LINUX
460 if (tcp->flags & TCB_CLONE_THREAD)
461 continue;
462#endif
463 /* Reinitialize the output since it may have changed. */
464 tcp->outf = outf;
465 if (newoutf(tcp) < 0)
466 exit(1);
467
468#ifdef USE_PROCFS
469 if (proc_open(tcp, 1) < 0) {
470 fprintf(stderr, "trouble opening proc file\n");
471 droptcb(tcp);
472 continue;
473 }
474#else /* !USE_PROCFS */
475# ifdef LINUX
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000476 if (followfork && !daemonized_tracer) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000477 char procdir[sizeof("/proc/%d/task") + sizeof(int) * 3];
Roland McGrath02203312007-06-11 22:06:31 +0000478 DIR *dir;
479
480 sprintf(procdir, "/proc/%d/task", tcp->pid);
481 dir = opendir(procdir);
482 if (dir != NULL) {
483 unsigned int ntid = 0, nerr = 0;
484 struct dirent *de;
485 int tid;
486 while ((de = readdir(dir)) != NULL) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000487 if (de->d_fileno == 0)
Roland McGrath02203312007-06-11 22:06:31 +0000488 continue;
489 tid = atoi(de->d_name);
490 if (tid <= 0)
491 continue;
492 ++ntid;
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000493 if (ptrace(PTRACE_ATTACH, tid, (char *) 1, 0) < 0)
Roland McGrath02203312007-06-11 22:06:31 +0000494 ++nerr;
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000495 else if (tid != tcbtab[tcbi]->pid) {
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000496 tcp = alloctcb(tid);
Wang Chao21b8db42010-08-27 17:43:16 +0800497 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_FOLLOWFORK;
Roland McGrath02203312007-06-11 22:06:31 +0000498 tcbtab[tcbi]->nclone_threads++;
Roland McGrath02203312007-06-11 22:06:31 +0000499 tcp->parent = tcbtab[tcbi];
500 }
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000501 if (interactive) {
502 sigprocmask(SIG_SETMASK, &empty_set, NULL);
503 if (interrupted)
504 return;
505 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
506 }
Roland McGrath02203312007-06-11 22:06:31 +0000507 }
508 closedir(dir);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000509 ntid -= nerr;
510 if (ntid == 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000511 perror("attach: ptrace(PTRACE_ATTACH, ...)");
512 droptcb(tcp);
513 continue;
514 }
515 if (!qflag) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000516 fprintf(stderr, ntid > 1
517? "Process %u attached with %u threads - interrupt to quit\n"
518: "Process %u attached - interrupt to quit\n",
519 tcbtab[tcbi]->pid, ntid);
Roland McGrath02203312007-06-11 22:06:31 +0000520 }
521 continue;
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000522 } /* if (opendir worked) */
523 } /* if (-f) */
Roland McGrath02203312007-06-11 22:06:31 +0000524# endif
525 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
526 perror("attach: ptrace(PTRACE_ATTACH, ...)");
527 droptcb(tcp);
528 continue;
529 }
530 /* INTERRUPTED is going to be checked at the top of TRACE. */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000531
532 if (daemonized_tracer) {
533 /*
534 * It is our grandparent we trace, not a -p PID.
535 * Don't want to just detach on exit, so...
536 */
537 tcp->flags &= ~TCB_ATTACHED;
538 /*
539 * Make parent go away.
540 * Also makes grandparent's wait() unblock.
541 */
542 kill(getppid(), SIGKILL);
543 }
544
Roland McGrath02203312007-06-11 22:06:31 +0000545#endif /* !USE_PROCFS */
546 if (!qflag)
547 fprintf(stderr,
548 "Process %u attached - interrupt to quit\n",
549 tcp->pid);
550 }
551
552 if (interactive)
553 sigprocmask(SIG_SETMASK, &empty_set, NULL);
554}
555
556static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200557startup_child(char **argv)
Roland McGrath02203312007-06-11 22:06:31 +0000558{
559 struct stat statbuf;
560 const char *filename;
561 char pathname[MAXPATHLEN];
562 int pid = 0;
563 struct tcb *tcp;
564
565 filename = argv[0];
566 if (strchr(filename, '/')) {
567 if (strlen(filename) > sizeof pathname - 1) {
568 errno = ENAMETOOLONG;
569 perror("strace: exec");
570 exit(1);
571 }
572 strcpy(pathname, filename);
573 }
574#ifdef USE_DEBUGGING_EXEC
575 /*
576 * Debuggers customarily check the current directory
577 * first regardless of the path but doing that gives
578 * security geeks a panic attack.
579 */
580 else if (stat(filename, &statbuf) == 0)
581 strcpy(pathname, filename);
582#endif /* USE_DEBUGGING_EXEC */
583 else {
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000584 const char *path;
Roland McGrath02203312007-06-11 22:06:31 +0000585 int m, n, len;
586
587 for (path = getenv("PATH"); path && *path; path += m) {
588 if (strchr(path, ':')) {
589 n = strchr(path, ':') - path;
590 m = n + 1;
591 }
592 else
593 m = n = strlen(path);
594 if (n == 0) {
595 if (!getcwd(pathname, MAXPATHLEN))
596 continue;
597 len = strlen(pathname);
598 }
599 else if (n > sizeof pathname - 1)
600 continue;
601 else {
602 strncpy(pathname, path, n);
603 len = n;
604 }
605 if (len && pathname[len - 1] != '/')
606 pathname[len++] = '/';
607 strcpy(pathname + len, filename);
608 if (stat(pathname, &statbuf) == 0 &&
609 /* Accept only regular files
610 with some execute bits set.
611 XXX not perfect, might still fail */
612 S_ISREG(statbuf.st_mode) &&
613 (statbuf.st_mode & 0111))
614 break;
615 }
616 }
617 if (stat(pathname, &statbuf) < 0) {
618 fprintf(stderr, "%s: %s: command not found\n",
619 progname, filename);
620 exit(1);
621 }
Dmitry V. Levina6809652008-11-10 17:14:58 +0000622 strace_child = pid = fork();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000623 if (pid < 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000624 perror("strace: fork");
625 cleanup();
626 exit(1);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000627 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200628 if ((pid != 0 && daemonized_tracer) /* -D: parent to become a traced process */
629 || (pid == 0 && !daemonized_tracer) /* not -D: child to become a traced process */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000630 ) {
631 pid = getpid();
Roland McGrath02203312007-06-11 22:06:31 +0000632#ifdef USE_PROCFS
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200633 if (outf != stderr) close(fileno(outf));
Roland McGrath02203312007-06-11 22:06:31 +0000634#ifdef MIPS
635 /* Kludge for SGI, see proc_open for details. */
636 sa.sa_handler = foobar;
637 sa.sa_flags = 0;
638 sigemptyset(&sa.sa_mask);
639 sigaction(SIGINT, &sa, NULL);
640#endif /* MIPS */
641#ifndef FREEBSD
642 pause();
643#else /* FREEBSD */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000644 kill(pid, SIGSTOP); /* stop HERE */
Roland McGrath02203312007-06-11 22:06:31 +0000645#endif /* FREEBSD */
646#else /* !USE_PROCFS */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200647 if (outf != stderr)
648 close(fileno(outf));
Roland McGrath02203312007-06-11 22:06:31 +0000649
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000650 if (!daemonized_tracer) {
651 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
652 perror("strace: ptrace(PTRACE_TRACEME, ...)");
653 exit(1);
654 }
655 if (debug)
656 kill(pid, SIGSTOP);
Roland McGrath02203312007-06-11 22:06:31 +0000657 }
Roland McGrath02203312007-06-11 22:06:31 +0000658
659 if (username != NULL || geteuid() == 0) {
660 uid_t run_euid = run_uid;
661 gid_t run_egid = run_gid;
662
663 if (statbuf.st_mode & S_ISUID)
664 run_euid = statbuf.st_uid;
665 if (statbuf.st_mode & S_ISGID)
666 run_egid = statbuf.st_gid;
667
668 /*
669 * It is important to set groups before we
670 * lose privileges on setuid.
671 */
672 if (username != NULL) {
673 if (initgroups(username, run_gid) < 0) {
674 perror("initgroups");
675 exit(1);
676 }
677 if (setregid(run_gid, run_egid) < 0) {
678 perror("setregid");
679 exit(1);
680 }
681 if (setreuid(run_uid, run_euid) < 0) {
682 perror("setreuid");
683 exit(1);
684 }
685 }
686 }
687 else
688 setreuid(run_uid, run_uid);
689
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000690 if (!daemonized_tracer) {
691 /*
692 * Induce an immediate stop so that the parent
693 * will resume us with PTRACE_SYSCALL and display
694 * this execve call normally.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400695 * Unless of course we're on a no-MMU system where
696 * we vfork()-ed, so we cannot stop the child.
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000697 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400698 if (!strace_vforked)
699 kill(getpid(), SIGSTOP);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000700 } else {
701 struct sigaction sv_sigchld;
702 sigaction(SIGCHLD, NULL, &sv_sigchld);
703 /*
704 * Make sure it is not SIG_IGN, otherwise wait
705 * will not block.
706 */
707 signal(SIGCHLD, SIG_DFL);
708 /*
709 * Wait for grandchild to attach to us.
710 * It kills child after that, and wait() unblocks.
711 */
712 alarm(3);
713 wait(NULL);
714 alarm(0);
715 sigaction(SIGCHLD, &sv_sigchld, NULL);
716 }
Roland McGrath02203312007-06-11 22:06:31 +0000717#endif /* !USE_PROCFS */
718
719 execv(pathname, argv);
720 perror("strace: exec");
721 _exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000722 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000723
724 /* We are the tracer. */
Denys Vlasenko75422762011-05-27 14:36:01 +0200725 /* With -D, we are *child* here, IOW: different pid. Fetch it. */
726 strace_tracer_pid = getpid();
727
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000728 tcp = alloctcb(daemonized_tracer ? getppid() : pid);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000729 if (daemonized_tracer) {
730 /* We want subsequent startup_attach() to attach to it. */
731 tcp->flags |= TCB_ATTACHED;
732 }
Roland McGrath02203312007-06-11 22:06:31 +0000733#ifdef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000734 if (proc_open(tcp, 0) < 0) {
735 fprintf(stderr, "trouble opening proc file\n");
736 cleanup();
737 exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000738 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000739#endif /* USE_PROCFS */
Roland McGrath02203312007-06-11 22:06:31 +0000740}
741
Wang Chaob13c0de2010-11-12 17:25:19 +0800742#ifdef LINUX
743/*
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000744 * Test whether the kernel support PTRACE_O_TRACECLONE et al options.
Wang Chaob13c0de2010-11-12 17:25:19 +0800745 * First fork a new child, call ptrace with PTRACE_SETOPTIONS on it,
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000746 * and then see which options are supported by the kernel.
Wang Chaob13c0de2010-11-12 17:25:19 +0800747 */
748static int
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200749test_ptrace_setoptions_followfork(void)
Wang Chaob13c0de2010-11-12 17:25:19 +0800750{
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000751 int pid, expected_grandchild = 0, found_grandchild = 0;
752 const unsigned int test_options = PTRACE_O_TRACECLONE |
753 PTRACE_O_TRACEFORK |
754 PTRACE_O_TRACEVFORK;
Wang Chaob13c0de2010-11-12 17:25:19 +0800755
756 if ((pid = fork()) < 0)
757 return -1;
758 else if (pid == 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000759 if (ptrace(PTRACE_TRACEME, 0, (char *)1, 0) < 0)
Wang Chaob13c0de2010-11-12 17:25:19 +0800760 _exit(1);
Wang Chaob13c0de2010-11-12 17:25:19 +0800761 kill(getpid(), SIGSTOP);
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000762 _exit(fork() < 0);
Wang Chaob13c0de2010-11-12 17:25:19 +0800763 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000764
765 while (1) {
766 int status, tracee_pid;
767
768 tracee_pid = wait(&status);
769 if (tracee_pid == -1) {
770 if (errno == EINTR)
771 continue;
772 else if (errno == ECHILD)
773 break;
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200774 perror("test_ptrace_setoptions_followfork");
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000775 return -1;
776 }
777 if (tracee_pid != pid) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000778 found_grandchild = tracee_pid;
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000779 if (ptrace(PTRACE_CONT, tracee_pid, 0, 0) < 0 &&
780 errno != ESRCH)
781 kill(tracee_pid, SIGKILL);
782 }
783 else if (WIFSTOPPED(status)) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000784 switch (WSTOPSIG(status)) {
785 case SIGSTOP:
786 if (ptrace(PTRACE_SETOPTIONS, pid,
787 NULL, test_options) < 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000788 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800789 return -1;
790 }
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000791 break;
792 case SIGTRAP:
793 if (status >> 16 == PTRACE_EVENT_FORK) {
794 long msg = 0;
795
796 if (ptrace(PTRACE_GETEVENTMSG, pid,
797 NULL, (long) &msg) == 0)
798 expected_grandchild = msg;
799 }
800 break;
Wang Chaob13c0de2010-11-12 17:25:19 +0800801 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000802 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0 &&
803 errno != ESRCH)
804 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800805 }
806 }
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000807 if (expected_grandchild && expected_grandchild == found_grandchild)
Denys Vlasenkof44cce42011-06-21 14:34:10 +0200808 ptrace_setoptions |= test_options;
Wang Chaob13c0de2010-11-12 17:25:19 +0800809 return 0;
810}
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200811
812/*
813 * Test whether the kernel support PTRACE_O_TRACESYSGOOD.
814 * First fork a new child, call ptrace(PTRACE_SETOPTIONS) on it,
815 * and then see whether it will stop with (SIGTRAP | 0x80).
816 *
817 * Use of this option enables correct handling of user-generated SIGTRAPs,
818 * and SIGTRAPs generated by special instructions such as int3 on x86:
819 * _start: .globl _start
820 * int3
821 * movl $42, %ebx
822 * movl $1, %eax
823 * int $0x80
824 * (compile with: "gcc -nostartfiles -nostdlib -o int3 int3.S")
825 */
826static void
827test_ptrace_setoptions_for_all(void)
828{
829 const unsigned int test_options = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC;
830 int pid;
831 int it_worked = 0;
832
833 pid = fork();
834 if (pid < 0)
Denys Vlasenko75422762011-05-27 14:36:01 +0200835 perror_msg_and_die("fork");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200836
837 if (pid == 0) {
838 pid = getpid();
839 if (ptrace(PTRACE_TRACEME, 0L, 0L, 0L) < 0)
Denys Vlasenko75422762011-05-27 14:36:01 +0200840 /* Note: exits with exitcode 1 */
841 perror_msg_and_die("%s: PTRACE_TRACEME doesn't work", __func__);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200842 kill(pid, SIGSTOP);
843 _exit(0); /* parent should see entry into this syscall */
844 }
845
846 while (1) {
847 int status, tracee_pid;
848
849 errno = 0;
850 tracee_pid = wait(&status);
851 if (tracee_pid <= 0) {
852 if (errno == EINTR)
853 continue;
854 kill(pid, SIGKILL);
Denys Vlasenko75422762011-05-27 14:36:01 +0200855 perror_msg_and_die("%s: unexpected wait result %d", __func__, tracee_pid);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200856 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200857 if (WIFEXITED(status)) {
858 if (WEXITSTATUS(status) == 0)
859 break;
860 /* PTRACE_TRACEME failed in child. This is fatal. */
861 exit(1);
862 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200863 if (!WIFSTOPPED(status)) {
864 kill(pid, SIGKILL);
865 error_msg_and_die("%s: unexpected wait status %x", __func__, status);
866 }
867 if (WSTOPSIG(status) == SIGSTOP) {
868 /*
869 * We don't check "options aren't accepted" error.
870 * If it happens, we'll never get (SIGTRAP | 0x80),
871 * and thus will decide to not use the option.
872 * IOW: the outcome of the test will be correct.
873 */
Denys Vlasenko75422762011-05-27 14:36:01 +0200874 if (ptrace(PTRACE_SETOPTIONS, pid, 0L, test_options) < 0)
875 if (errno != EINVAL)
876 perror_msg("PTRACE_SETOPTIONS");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200877 }
878 if (WSTOPSIG(status) == (SIGTRAP | 0x80)) {
879 it_worked = 1;
880 }
881 if (ptrace(PTRACE_SYSCALL, pid, 0L, 0L) < 0) {
882 kill(pid, SIGKILL);
Denys Vlasenko75422762011-05-27 14:36:01 +0200883 perror_msg_and_die("PTRACE_SYSCALL doesn't work");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200884 }
885 }
886
887 if (it_worked) {
Denys Vlasenko75422762011-05-27 14:36:01 +0200888 syscall_trap_sig = (SIGTRAP | 0x80);
Denys Vlasenkof44cce42011-06-21 14:34:10 +0200889 ptrace_setoptions |= test_options;
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200890 if (debug)
Denys Vlasenkof44cce42011-06-21 14:34:10 +0200891 fprintf(stderr, "ptrace_setoptions = %#x\n",
892 ptrace_setoptions);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200893 return;
894 }
895
896 fprintf(stderr,
897 "Test for PTRACE_O_TRACESYSGOOD failed, giving up using this feature.\n");
898}
Wang Chaob13c0de2010-11-12 17:25:19 +0800899#endif
900
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000901int
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000902main(int argc, char *argv[])
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000903{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000904 struct tcb *tcp;
905 int c, pid = 0;
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000906 int optF = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000907 struct sigaction sa;
908
909 static char buf[BUFSIZ];
910
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000911 progname = argv[0] ? argv[0] : "strace";
912
Denys Vlasenko75422762011-05-27 14:36:01 +0200913 strace_tracer_pid = getpid();
914
Roland McGrathee9d4352002-12-18 04:16:10 +0000915 /* Allocate the initial tcbtab. */
916 tcbtabsize = argc; /* Surely enough for all -p args. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000917 if ((tcbtab = calloc(tcbtabsize, sizeof tcbtab[0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000918 fprintf(stderr, "%s: out of memory\n", progname);
919 exit(1);
920 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000921 if ((tcbtab[0] = calloc(tcbtabsize, sizeof tcbtab[0][0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000922 fprintf(stderr, "%s: out of memory\n", progname);
923 exit(1);
924 }
Roland McGrathee9d4352002-12-18 04:16:10 +0000925 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
926 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
927
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000928 outf = stderr;
929 interactive = 1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000930 set_sortby(DEFAULT_SORTBY);
931 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000932 qualify("trace=all");
933 qualify("abbrev=all");
934 qualify("verbose=all");
935 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000936 while ((c = getopt(argc, argv,
Grant Edwards8a082772011-04-07 20:25:40 +0000937 "+cCdfFhiqrtTvVxyz"
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000938#ifndef USE_PROCFS
939 "D"
940#endif
Grant Edwards8a082772011-04-07 20:25:40 +0000941 "a:e:o:O:p:s:S:u:E:P:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000942 switch (c) {
943 case 'c':
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000944 if (cflag == CFLAG_BOTH) {
945 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
946 progname);
947 exit(1);
948 }
949 cflag = CFLAG_ONLY_STATS;
950 break;
951 case 'C':
952 if (cflag == CFLAG_ONLY_STATS) {
953 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
954 progname);
955 exit(1);
956 }
957 cflag = CFLAG_BOTH;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000958 break;
959 case 'd':
960 debug++;
961 break;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000962#ifndef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000963 case 'D':
964 daemonized_tracer = 1;
965 break;
966#endif
Roland McGrath41c48222008-07-18 00:25:10 +0000967 case 'F':
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000968 optF = 1;
969 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000970 case 'f':
971 followfork++;
972 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000973 case 'h':
974 usage(stdout, 0);
975 break;
976 case 'i':
977 iflag++;
978 break;
979 case 'q':
980 qflag++;
981 break;
982 case 'r':
983 rflag++;
984 tflag++;
985 break;
986 case 't':
987 tflag++;
988 break;
989 case 'T':
990 dtime++;
991 break;
992 case 'x':
993 xflag++;
994 break;
Grant Edwards8a082772011-04-07 20:25:40 +0000995 case 'y':
996 show_fd_path = 1;
997 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000998 case 'v':
999 qualify("abbrev=none");
1000 break;
1001 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +00001002 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001003 exit(0);
1004 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +00001005 case 'z':
1006 not_failing_only = 1;
1007 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001008 case 'a':
1009 acolumn = atoi(optarg);
1010 break;
1011 case 'e':
1012 qualify(optarg);
1013 break;
1014 case 'o':
1015 outfname = strdup(optarg);
1016 break;
1017 case 'O':
1018 set_overhead(atoi(optarg));
1019 break;
1020 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +00001021 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001022 fprintf(stderr, "%s: Invalid process id: %s\n",
1023 progname, optarg);
1024 break;
1025 }
Denys Vlasenko75422762011-05-27 14:36:01 +02001026 if (pid == strace_tracer_pid) {
Wichert Akkerman54a47671999-10-17 00:57:34 +00001027 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001028 break;
1029 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001030 tcp = alloc_tcb(pid, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001031 tcp->flags |= TCB_ATTACHED;
1032 pflag_seen++;
1033 break;
Grant Edwards8a082772011-04-07 20:25:40 +00001034 case 'P':
1035 tracing_paths = 1;
1036 if (pathtrace_select(optarg)) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001037 fprintf(stderr, "%s : failed to select path '%s'\n", progname, optarg);
Grant Edwards8a082772011-04-07 20:25:40 +00001038 exit(1);
1039 }
1040 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001041 case 's':
1042 max_strlen = atoi(optarg);
Roland McGrathdccec722005-05-09 07:45:47 +00001043 if (max_strlen < 0) {
1044 fprintf(stderr,
1045 "%s: invalid -s argument: %s\n",
1046 progname, optarg);
1047 exit(1);
1048 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001049 break;
1050 case 'S':
1051 set_sortby(optarg);
1052 break;
1053 case 'u':
1054 username = strdup(optarg);
1055 break;
Roland McGrathde6e5332003-01-24 04:31:23 +00001056 case 'E':
1057 if (putenv(optarg) < 0) {
1058 fprintf(stderr, "%s: out of memory\n",
1059 progname);
1060 exit(1);
1061 }
1062 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001063 default:
1064 usage(stderr, 1);
1065 break;
1066 }
1067 }
1068
Roland McGrathd0c4c0c2006-04-25 07:39:40 +00001069 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +00001070 usage(stderr, 1);
1071
Wang Chaod322a4b2010-08-05 14:30:11 +08001072 if (pflag_seen && daemonized_tracer) {
1073 fprintf(stderr,
1074 "%s: -D and -p are mutually exclusive options\n",
1075 progname);
1076 exit(1);
1077 }
1078
Dmitry V. Levin06350db2008-07-25 15:42:34 +00001079 if (!followfork)
1080 followfork = optF;
1081
Roland McGrathcb9def62006-04-25 07:48:03 +00001082 if (followfork > 1 && cflag) {
1083 fprintf(stderr,
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00001084 "%s: (-c or -C) and -ff are mutually exclusive options\n",
Roland McGrathcb9def62006-04-25 07:48:03 +00001085 progname);
1086 exit(1);
1087 }
1088
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001089 /* See if they want to run as another user. */
1090 if (username != NULL) {
1091 struct passwd *pent;
1092
1093 if (getuid() != 0 || geteuid() != 0) {
1094 fprintf(stderr,
1095 "%s: you must be root to use the -u option\n",
1096 progname);
1097 exit(1);
1098 }
1099 if ((pent = getpwnam(username)) == NULL) {
1100 fprintf(stderr, "%s: cannot find user `%s'\n",
Roland McGrath09553f82007-07-05 19:31:49 +00001101 progname, username);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001102 exit(1);
1103 }
1104 run_uid = pent->pw_uid;
1105 run_gid = pent->pw_gid;
1106 }
1107 else {
1108 run_uid = getuid();
1109 run_gid = getgid();
1110 }
1111
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001112#ifdef LINUX
1113 if (followfork) {
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02001114 if (test_ptrace_setoptions_followfork() < 0) {
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001115 fprintf(stderr,
1116 "Test for options supported by PTRACE_SETOPTIONS "
1117 "failed, giving up using this feature.\n");
Denys Vlasenkof44cce42011-06-21 14:34:10 +02001118 ptrace_setoptions = 0;
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001119 }
1120 if (debug)
Denys Vlasenkof44cce42011-06-21 14:34:10 +02001121 fprintf(stderr, "ptrace_setoptions = %#x\n",
1122 ptrace_setoptions);
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001123 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02001124 test_ptrace_setoptions_for_all();
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001125#endif
1126
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001127 /* Check if they want to redirect the output. */
1128 if (outfname) {
Roland McGrath37b9a662003-11-07 02:26:54 +00001129 /* See if they want to pipe the output. */
1130 if (outfname[0] == '|' || outfname[0] == '!') {
1131 /*
1132 * We can't do the <outfname>.PID funny business
1133 * when using popen, so prohibit it.
1134 */
Denys Vlasenko7dd23382011-06-22 13:03:56 +02001135 if (followfork > 1)
1136 error_msg_and_die("Piping the output and -ff are mutually exclusive");
1137 outf = strace_popen(outfname + 1);
Roland McGrath37b9a662003-11-07 02:26:54 +00001138 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001139 else if (followfork <= 1 &&
1140 (outf = strace_fopen(outfname, "w")) == NULL)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001141 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001142 }
1143
Roland McGrath37b9a662003-11-07 02:26:54 +00001144 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001145 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +00001146 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001147 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001148 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +00001149 }
Wang Chaob13c0de2010-11-12 17:25:19 +08001150
Roland McGrath54cc1c82007-11-03 23:34:11 +00001151 /* Valid states here:
1152 optind < argc pflag_seen outfname interactive
1153 1 0 0 1
1154 0 1 0 1
1155 1 0 1 0
1156 0 1 1 1
1157 */
1158
1159 /* STARTUP_CHILD must be called before the signal handlers get
1160 installed below as they are inherited into the spawned process.
1161 Also we do not need to be protected by them as during interruption
1162 in the STARTUP_CHILD mode we kill the spawned process anyway. */
1163 if (!pflag_seen)
1164 startup_child(&argv[optind]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001165
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001166 sigemptyset(&empty_set);
1167 sigemptyset(&blocked_set);
1168 sa.sa_handler = SIG_IGN;
1169 sigemptyset(&sa.sa_mask);
1170 sa.sa_flags = 0;
1171 sigaction(SIGTTOU, &sa, NULL);
1172 sigaction(SIGTTIN, &sa, NULL);
1173 if (interactive) {
1174 sigaddset(&blocked_set, SIGHUP);
1175 sigaddset(&blocked_set, SIGINT);
1176 sigaddset(&blocked_set, SIGQUIT);
1177 sigaddset(&blocked_set, SIGPIPE);
1178 sigaddset(&blocked_set, SIGTERM);
1179 sa.sa_handler = interrupt;
1180#ifdef SUNOS4
1181 /* POSIX signals on sunos4.1 are a little broken. */
1182 sa.sa_flags = SA_INTERRUPT;
1183#endif /* SUNOS4 */
1184 }
1185 sigaction(SIGHUP, &sa, NULL);
1186 sigaction(SIGINT, &sa, NULL);
1187 sigaction(SIGQUIT, &sa, NULL);
1188 sigaction(SIGPIPE, &sa, NULL);
1189 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001190#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001191 sa.sa_handler = reaper;
1192 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +00001193#else
1194 /* Make sure SIGCHLD has the default action so that waitpid
1195 definitely works without losing track of children. The user
1196 should not have given us a bogus state to inherit, but he might
1197 have. Arguably we should detect SIG_IGN here and pass it on
1198 to children, but probably noone really needs that. */
1199 sa.sa_handler = SIG_DFL;
1200 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001201#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001202
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +00001203 if (pflag_seen || daemonized_tracer)
Roland McGrath02203312007-06-11 22:06:31 +00001204 startup_attach();
Roland McGrath02203312007-06-11 22:06:31 +00001205
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001206 if (trace() < 0)
1207 exit(1);
1208 cleanup();
Dmitry V. Levina6809652008-11-10 17:14:58 +00001209 fflush(NULL);
1210 if (exit_code > 0xff) {
1211 /* Child was killed by a signal, mimic that. */
1212 exit_code &= 0xff;
1213 signal(exit_code, SIG_DFL);
1214 raise(exit_code);
1215 /* Paranoia - what if this signal is not fatal?
1216 Exit with 128 + signo then. */
1217 exit_code += 128;
1218 }
1219 exit(exit_code);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001220}
1221
Denys Vlasenko2b60c352011-06-22 12:45:25 +02001222static void
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001223expand_tcbtab(void)
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001224{
1225 /* Allocate some more TCBs and expand the table.
1226 We don't want to relocate the TCBs because our
1227 callers have pointers and it would be a pain.
1228 So tcbtab is a table of pointers. Since we never
1229 free the TCBs, we allocate a single chunk of many. */
Denys Vlasenko18da2732011-06-22 12:41:57 +02001230 int i = tcbtabsize;
1231 struct tcb *newtcbs = calloc(tcbtabsize, sizeof(newtcbs[0]));
1232 struct tcb **newtab = realloc(tcbtab, tcbtabsize * 2 * sizeof(tcbtab[0]));
1233 if (newtab == NULL || newtcbs == NULL)
1234 error_msg_and_die("expand_tcbtab: out of memory");
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001235 tcbtabsize *= 2;
1236 tcbtab = newtab;
Denys Vlasenko18da2732011-06-22 12:41:57 +02001237 while (i < tcbtabsize)
1238 tcbtab[i++] = newtcbs++;
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001239}
1240
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001241struct tcb *
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001242alloc_tcb(int pid, int command_options_parsed)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001243{
1244 int i;
1245 struct tcb *tcp;
1246
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001247 if (nprocs == tcbtabsize)
1248 expand_tcbtab();
1249
Roland McGrathee9d4352002-12-18 04:16:10 +00001250 for (i = 0; i < tcbtabsize; i++) {
1251 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001252 if ((tcp->flags & TCB_INUSE) == 0) {
Denys Vlasenko18da2732011-06-22 12:41:57 +02001253 memset(tcp, 0, sizeof(*tcp));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001254 tcp->pid = pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001255 tcp->flags = TCB_INUSE | TCB_STARTUP;
1256 tcp->outf = outf; /* Initialise to current out file */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001257 tcp->pfd = -1;
1258 nprocs++;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001259 if (command_options_parsed)
1260 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001261 return tcp;
1262 }
1263 }
Denys Vlasenko18da2732011-06-22 12:41:57 +02001264 error_msg_and_die("bug in alloc_tcb");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001265}
1266
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001267#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001268int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001269proc_open(struct tcb *tcp, int attaching)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001270{
1271 char proc[32];
1272 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001273#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +00001274 int i;
1275 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001276 sigset_t signals;
1277 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001278#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001279#ifndef HAVE_POLLABLE_PROCFS
1280 static int last_pfd;
1281#endif
1282
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001283#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001284 /* Open the process pseudo-files in /proc. */
1285 sprintf(proc, "/proc/%d/ctl", tcp->pid);
1286 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001287 perror("strace: open(\"/proc/...\", ...)");
1288 return -1;
1289 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001290 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001291 return -1;
1292 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001293 sprintf(proc, "/proc/%d/status", tcp->pid);
1294 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
1295 perror("strace: open(\"/proc/...\", ...)");
1296 return -1;
1297 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001298 if (set_cloexec_flag(tcp->pfd_stat) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001299 return -1;
1300 }
1301 sprintf(proc, "/proc/%d/as", tcp->pid);
1302 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
1303 perror("strace: open(\"/proc/...\", ...)");
1304 return -1;
1305 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001306 if (set_cloexec_flag(tcp->pfd_as) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001307 return -1;
1308 }
1309#else
1310 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001311#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001312 sprintf(proc, "/proc/%d", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001313 tcp->pfd = open(proc, O_RDWR|O_EXCL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001314#else /* FREEBSD */
1315 sprintf(proc, "/proc/%d/mem", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001316 tcp->pfd = open(proc, O_RDWR);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001317#endif /* FREEBSD */
Andreas Schwab372cc842010-07-09 11:49:27 +02001318 if (tcp->pfd < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001319 perror("strace: open(\"/proc/...\", ...)");
1320 return -1;
1321 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001322 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001323 return -1;
1324 }
1325#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001326#ifdef FREEBSD
1327 sprintf(proc, "/proc/%d/regs", tcp->pid);
1328 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
1329 perror("strace: open(\"/proc/.../regs\", ...)");
1330 return -1;
1331 }
1332 if (cflag) {
1333 sprintf(proc, "/proc/%d/status", tcp->pid);
1334 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
1335 perror("strace: open(\"/proc/.../status\", ...)");
1336 return -1;
1337 }
1338 } else
1339 tcp->pfd_status = -1;
1340#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001341 rebuild_pollv();
1342 if (!attaching) {
1343 /*
1344 * Wait for the child to pause. Because of a race
1345 * condition we have to poll for the event.
1346 */
1347 for (;;) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001348 if (IOCTL_STATUS(tcp) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001349 perror("strace: PIOCSTATUS");
1350 return -1;
1351 }
1352 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001353 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001354 }
1355 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001356#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001357 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001358 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001359 perror("strace: PIOCSTOP");
1360 return -1;
1361 }
Roland McGrath553a6092002-12-16 20:40:39 +00001362#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001363#ifdef PIOCSET
1364 /* Set Run-on-Last-Close. */
1365 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001366 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001367 perror("PIOCSET PR_RLC");
1368 return -1;
1369 }
1370 /* Set or Reset Inherit-on-Fork. */
1371 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001372 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001373 perror("PIOC{SET,RESET} PR_FORK");
1374 return -1;
1375 }
1376#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +00001377#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001378 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
1379 perror("PIOCSRLC");
1380 return -1;
1381 }
1382 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
1383 perror("PIOC{S,R}FORK");
1384 return -1;
1385 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001386#else /* FREEBSD */
1387 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
1388 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
1389 perror("PIOCGFL");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001390 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001391 }
1392 arg &= ~PF_LINGER;
1393 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001394 perror("PIOCSFL");
1395 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001396 }
1397#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001398#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001399#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +00001400 /* Enable all syscall entries we care about. */
1401 premptyset(&syscalls);
1402 for (i = 1; i < MAX_QUALS; ++i) {
1403 if (i > (sizeof syscalls) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001404 if (qual_flags[i] & QUAL_TRACE) praddset(&syscalls, i);
John Hughes19e49982001-10-19 08:59:12 +00001405 }
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001406 praddset(&syscalls, SYS_execve);
John Hughes19e49982001-10-19 08:59:12 +00001407 if (followfork) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001408 praddset(&syscalls, SYS_fork);
John Hughes19e49982001-10-19 08:59:12 +00001409#ifdef SYS_forkall
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001410 praddset(&syscalls, SYS_forkall);
John Hughes19e49982001-10-19 08:59:12 +00001411#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001412#ifdef SYS_fork1
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001413 praddset(&syscalls, SYS_fork1);
John Hughes19e49982001-10-19 08:59:12 +00001414#endif
1415#ifdef SYS_rfork1
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001416 praddset(&syscalls, SYS_rfork1);
John Hughes19e49982001-10-19 08:59:12 +00001417#endif
1418#ifdef SYS_rforkall
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001419 praddset(&syscalls, SYS_rforkall);
John Hughes19e49982001-10-19 08:59:12 +00001420#endif
1421 }
1422 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001423 perror("PIOCSENTRY");
1424 return -1;
1425 }
John Hughes19e49982001-10-19 08:59:12 +00001426 /* Enable the syscall exits. */
1427 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001428 perror("PIOSEXIT");
1429 return -1;
1430 }
John Hughes19e49982001-10-19 08:59:12 +00001431 /* Enable signals we care about. */
1432 premptyset(&signals);
1433 for (i = 1; i < MAX_QUALS; ++i) {
1434 if (i > (sizeof signals) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001435 if (qual_flags[i] & QUAL_SIGNAL) praddset(&signals, i);
John Hughes19e49982001-10-19 08:59:12 +00001436 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001437 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001438 perror("PIOCSTRACE");
1439 return -1;
1440 }
John Hughes19e49982001-10-19 08:59:12 +00001441 /* Enable faults we care about */
1442 premptyset(&faults);
1443 for (i = 1; i < MAX_QUALS; ++i) {
1444 if (i > (sizeof faults) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001445 if (qual_flags[i] & QUAL_FAULT) praddset(&faults, i);
John Hughes19e49982001-10-19 08:59:12 +00001446 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001447 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001448 perror("PIOCSFAULT");
1449 return -1;
1450 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001451#else /* FREEBSD */
1452 /* set events flags. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001453 arg = S_SIG | S_SCE | S_SCX;
1454 if (ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001455 perror("PIOCBIS");
1456 return -1;
1457 }
1458#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001459 if (!attaching) {
1460#ifdef MIPS
1461 /*
1462 * The SGI PRSABORT doesn't work for pause() so
1463 * we send it a caught signal to wake it up.
1464 */
1465 kill(tcp->pid, SIGINT);
1466#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +00001467#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001468 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001469 arg = PRSABORT;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001470 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001471 perror("PIOCRUN");
1472 return -1;
1473 }
Roland McGrath553a6092002-12-16 20:40:39 +00001474#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001475#endif /* !MIPS*/
1476#ifdef FREEBSD
1477 /* wake up the child if it received the SIGSTOP */
1478 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001479#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001480 for (;;) {
1481 /* Wait for the child to do something. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001482 if (IOCTL_WSTOP(tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001483 perror("PIOCWSTOP");
1484 return -1;
1485 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001486 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001487 tcp->flags &= ~TCB_INSYSCALL;
1488 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001489 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001490 break;
1491 }
1492 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001493#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001494 arg = 0;
1495 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001496#else /* FREEBSD */
1497 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001498#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001499 perror("PIOCRUN");
1500 return -1;
1501 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001502#ifdef FREEBSD
1503 /* handle the case where we "opened" the child before
1504 it did the kill -STOP */
1505 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1506 tcp->status.PR_WHAT == SIGSTOP)
1507 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001508#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001509 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001510#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001511 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001512#else /* FREEBSD */
1513 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001514 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001515 /* We are attaching to an already running process.
1516 * Try to figure out the state of the process in syscalls,
1517 * to handle the first event well.
1518 * This is done by having a look at the "wchan" property of the
1519 * process, which tells where it is stopped (if it is). */
1520 FILE * status;
1521 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001522
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001523 sprintf(proc, "/proc/%d/status", tcp->pid);
1524 status = fopen(proc, "r");
1525 if (status &&
1526 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1527 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1528 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1529 strcmp(wchan, "stopevent")) {
1530 /* The process is asleep in the middle of a syscall.
1531 Fake the syscall entry event */
1532 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1533 tcp->status.PR_WHY = PR_SYSENTRY;
1534 trace_syscall(tcp);
1535 }
1536 if (status)
1537 fclose(status);
1538 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001539 }
1540#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001541#ifndef HAVE_POLLABLE_PROCFS
1542 if (proc_poll_pipe[0] != -1)
1543 proc_poller(tcp->pfd);
1544 else if (nprocs > 1) {
1545 proc_poll_open();
1546 proc_poller(last_pfd);
1547 proc_poller(tcp->pfd);
1548 }
1549 last_pfd = tcp->pfd;
1550#endif /* !HAVE_POLLABLE_PROCFS */
1551 return 0;
1552}
1553
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001554#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001555
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001556struct tcb *
Roland McGrath54e931f2010-09-14 18:59:20 -07001557pid2tcb(int pid)
1558{
1559 int i;
1560
1561 if (pid <= 0)
1562 return NULL;
1563
1564 for (i = 0; i < tcbtabsize; i++) {
1565 struct tcb *tcp = tcbtab[i];
1566 if (tcp->pid == pid && (tcp->flags & TCB_INUSE))
1567 return tcp;
1568 }
1569
1570 return NULL;
1571}
1572
1573#ifdef USE_PROCFS
1574
1575static struct tcb *
1576first_used_tcb(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001577{
1578 int i;
1579 struct tcb *tcp;
Roland McGrathee9d4352002-12-18 04:16:10 +00001580 for (i = 0; i < tcbtabsize; i++) {
1581 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001582 if (tcp->flags & TCB_INUSE)
1583 return tcp;
1584 }
1585 return NULL;
1586}
1587
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001588static struct tcb *
Denys Vlasenko12014262011-05-30 14:00:14 +02001589pfd2tcb(int pfd)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001590{
1591 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001592
Roland McGrathca16be82003-01-10 19:55:28 +00001593 for (i = 0; i < tcbtabsize; i++) {
1594 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001595 if (tcp->pfd != pfd)
1596 continue;
1597 if (tcp->flags & TCB_INUSE)
1598 return tcp;
1599 }
1600 return NULL;
1601}
1602
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001603#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001604
1605void
Denys Vlasenko12014262011-05-30 14:00:14 +02001606droptcb(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001607{
1608 if (tcp->pid == 0)
1609 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001610#ifdef TCB_CLONE_THREAD
1611 if (tcp->nclone_threads > 0) {
1612 /* There are other threads left in this process, but this
1613 is the one whose PID represents the whole process.
1614 We need to keep this record around as a zombie until
1615 all the threads die. */
1616 tcp->flags |= TCB_EXITING;
1617 return;
1618 }
1619#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001620 nprocs--;
1621 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001622
Roland McGrathe29341c2003-01-10 20:14:20 +00001623 if (tcp->parent != NULL) {
Roland McGrathe29341c2003-01-10 20:14:20 +00001624#ifdef TCB_CLONE_THREAD
Roland McGrathe29341c2003-01-10 20:14:20 +00001625 if (tcp->flags & TCB_CLONE_THREAD)
1626 tcp->parent->nclone_threads--;
1627#endif
Roland McGrath276ceb32007-11-13 08:12:12 +00001628#ifdef LINUX
Denys Vlasenkob56d6d32011-06-21 16:06:28 +02001629 /* Update fields like NCLONE_DETACHED, only
1630 for zombie group leader that has already reported
1631 and been short-circuited at the top of this
Roland McGrath276ceb32007-11-13 08:12:12 +00001632 function. The same condition as at the top of DETACH. */
1633 if ((tcp->flags & TCB_CLONE_THREAD) &&
1634 tcp->parent->nclone_threads == 0 &&
1635 (tcp->parent->flags & TCB_EXITING))
1636 droptcb(tcp->parent);
1637#endif
Roland McGrathe29341c2003-01-10 20:14:20 +00001638 tcp->parent = NULL;
1639 }
1640
1641 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001642 if (tcp->pfd != -1) {
1643 close(tcp->pfd);
1644 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001645#ifdef FREEBSD
1646 if (tcp->pfd_reg != -1) {
1647 close(tcp->pfd_reg);
1648 tcp->pfd_reg = -1;
1649 }
1650 if (tcp->pfd_status != -1) {
1651 close(tcp->pfd_status);
1652 tcp->pfd_status = -1;
1653 }
Roland McGrath553a6092002-12-16 20:40:39 +00001654#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001655#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001656 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001657#endif
1658 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001659
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001660 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001661 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001662
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001663 tcp->outf = 0;
1664}
1665
Roland McGrath0a463882007-07-05 18:43:16 +00001666/* detach traced process; continue with sig
1667 Never call DETACH twice on the same process as both unattached and
1668 attached-unstopped processes give the same ESRCH. For unattached process we
1669 would SIGSTOP it and wait for its SIGSTOP notification forever. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001670
1671static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001672detach(struct tcb *tcp, int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001673{
1674 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001675#ifdef LINUX
Roland McGrath1bfd3102007-08-03 10:02:00 +00001676 int status, catch_sigstop;
Roland McGratha08a97e2005-08-03 11:23:46 +00001677 struct tcb *zombie = NULL;
1678
1679 /* If the group leader is lingering only because of this other
1680 thread now dying, then detach the leader as well. */
1681 if ((tcp->flags & TCB_CLONE_THREAD) &&
1682 tcp->parent->nclone_threads == 1 &&
1683 (tcp->parent->flags & TCB_EXITING))
1684 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001685#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001686
1687 if (tcp->flags & TCB_BPTSET)
Andreas Schwab840d85b2010-01-12 11:16:32 +01001688 clearbpt(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001689
1690#ifdef LINUX
1691 /*
1692 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001693 * before detaching. Arghh. We go through hoops
1694 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001695 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001696#if defined(SPARC)
1697#undef PTRACE_DETACH
1698#define PTRACE_DETACH PTRACE_SUNDETACH
1699#endif
Roland McGrath02203312007-06-11 22:06:31 +00001700 /*
1701 * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
1702 * expected SIGSTOP. We must catch exactly one as otherwise the
1703 * detached process would be left stopped (process state T).
1704 */
1705 catch_sigstop = (tcp->flags & TCB_STARTUP);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001706 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1707 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001708 }
1709 else if (errno != ESRCH) {
1710 /* Shouldn't happen. */
1711 perror("detach: ptrace(PTRACE_DETACH, ...)");
1712 }
Roland McGrath134813a2007-06-02 00:07:33 +00001713 else if (my_tgkill((tcp->flags & TCB_CLONE_THREAD ? tcp->parent->pid
1714 : tcp->pid),
1715 tcp->pid, 0) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001716 if (errno != ESRCH)
1717 perror("detach: checking sanity");
1718 }
Roland McGrath02203312007-06-11 22:06:31 +00001719 else if (!catch_sigstop && my_tgkill((tcp->flags & TCB_CLONE_THREAD
1720 ? tcp->parent->pid : tcp->pid),
1721 tcp->pid, SIGSTOP) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001722 if (errno != ESRCH)
1723 perror("detach: stopping child");
1724 }
Roland McGrath02203312007-06-11 22:06:31 +00001725 else
1726 catch_sigstop = 1;
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001727 if (catch_sigstop) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001728 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001729#ifdef __WALL
1730 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1731 if (errno == ECHILD) /* Already gone. */
1732 break;
1733 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001734 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001735 break;
1736 }
1737#endif /* __WALL */
1738 /* No __WALL here. */
1739 if (waitpid(tcp->pid, &status, 0) < 0) {
1740 if (errno != ECHILD) {
1741 perror("detach: waiting");
1742 break;
1743 }
1744#ifdef __WCLONE
1745 /* If no processes, try clones. */
1746 if (wait4(tcp->pid, &status, __WCLONE,
1747 NULL) < 0) {
1748 if (errno != ECHILD)
1749 perror("detach: waiting");
1750 break;
1751 }
1752#endif /* __WCLONE */
1753 }
1754#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001755 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001756#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001757 if (!WIFSTOPPED(status)) {
1758 /* Au revoir, mon ami. */
1759 break;
1760 }
1761 if (WSTOPSIG(status) == SIGSTOP) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001762 ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001763 break;
1764 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001765 error = ptrace_restart(PTRACE_CONT, tcp,
Denys Vlasenko75422762011-05-27 14:36:01 +02001766 WSTOPSIG(status) == syscall_trap_sig ? 0
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001767 : WSTOPSIG(status));
1768 if (error < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001769 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001770 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001771 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001772#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001773
1774#if defined(SUNOS4)
1775 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1776 if (sig && kill(tcp->pid, sig) < 0)
1777 perror("detach: kill");
1778 sig = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001779 error = ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001780#endif /* SUNOS4 */
1781
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001782 if (!qflag)
1783 fprintf(stderr, "Process %u detached\n", tcp->pid);
1784
1785 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001786
1787#ifdef LINUX
Roland McGrath0a463882007-07-05 18:43:16 +00001788 if (zombie != NULL) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001789 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath0a463882007-07-05 18:43:16 +00001790 droptcb(zombie);
1791 }
Roland McGratha08a97e2005-08-03 11:23:46 +00001792#endif
1793
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001794 return error;
1795}
1796
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001797#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001798
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001799static void reaper(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001800{
1801 int pid;
1802 int status;
1803
1804 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001805 }
1806}
1807
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001808#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001809
1810static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001811cleanup(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001812{
1813 int i;
1814 struct tcb *tcp;
1815
Roland McGrathee9d4352002-12-18 04:16:10 +00001816 for (i = 0; i < tcbtabsize; i++) {
1817 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001818 if (!(tcp->flags & TCB_INUSE))
1819 continue;
1820 if (debug)
1821 fprintf(stderr,
1822 "cleanup: looking at pid %u\n", tcp->pid);
1823 if (tcp_last &&
1824 (!outfname || followfork < 2 || tcp_last == tcp)) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001825 tprintf(" <unfinished ...>");
1826 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001827 }
1828 if (tcp->flags & TCB_ATTACHED)
1829 detach(tcp, 0);
1830 else {
1831 kill(tcp->pid, SIGCONT);
1832 kill(tcp->pid, SIGTERM);
1833 }
1834 }
1835 if (cflag)
1836 call_summary(outf);
1837}
1838
1839static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001840interrupt(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001841{
1842 interrupted = 1;
1843}
1844
1845#ifndef HAVE_STRERROR
1846
Roland McGrath6d2b3492002-12-30 00:51:30 +00001847#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001848extern int sys_nerr;
1849extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001850#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001851
1852const char *
Denys Vlasenko12014262011-05-30 14:00:14 +02001853strerror(int err_no)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001854{
1855 static char buf[64];
1856
Denys Vlasenko35aba6a2011-05-25 15:33:26 +02001857 if (err_no < 1 || err_no >= sys_nerr) {
1858 sprintf(buf, "Unknown error %d", err_no);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001859 return buf;
1860 }
Denys Vlasenko35aba6a2011-05-25 15:33:26 +02001861 return sys_errlist[err_no];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001862}
1863
1864#endif /* HAVE_STERRROR */
1865
1866#ifndef HAVE_STRSIGNAL
1867
Roland McGrath8f474e02003-01-14 07:53:33 +00001868#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001869extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001870#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001871#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1872extern char *_sys_siglist[];
1873#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001874
1875const char *
Denys Vlasenko12014262011-05-30 14:00:14 +02001876strsignal(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001877{
1878 static char buf[64];
1879
1880 if (sig < 1 || sig >= NSIG) {
1881 sprintf(buf, "Unknown signal %d", sig);
1882 return buf;
1883 }
1884#ifdef HAVE__SYS_SIGLIST
1885 return _sys_siglist[sig];
1886#else
1887 return sys_siglist[sig];
1888#endif
1889}
1890
1891#endif /* HAVE_STRSIGNAL */
1892
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001893#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001894
1895static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001896rebuild_pollv(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001897{
1898 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001899
Roland McGrathee9d4352002-12-18 04:16:10 +00001900 if (pollv != NULL)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001901 free(pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001902 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001903 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001904 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00001905 exit(1);
1906 }
1907
Roland McGrathca16be82003-01-10 19:55:28 +00001908 for (i = j = 0; i < tcbtabsize; i++) {
1909 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001910 if (!(tcp->flags & TCB_INUSE))
1911 continue;
1912 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001913 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001914 j++;
1915 }
1916 if (j != nprocs) {
1917 fprintf(stderr, "strace: proc miscount\n");
1918 exit(1);
1919 }
1920}
1921
1922#ifndef HAVE_POLLABLE_PROCFS
1923
1924static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001925proc_poll_open(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001926{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001927 int i;
1928
1929 if (pipe(proc_poll_pipe) < 0) {
1930 perror("pipe");
1931 exit(1);
1932 }
1933 for (i = 0; i < 2; i++) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001934 if (set_cloexec_flag(proc_poll_pipe[i]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001935 exit(1);
1936 }
1937 }
1938}
1939
1940static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001941proc_poll(struct pollfd *pollv, int nfds, int timeout)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001942{
1943 int i;
1944 int n;
1945 struct proc_pollfd pollinfo;
1946
1947 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1948 return n;
1949 if (n != sizeof(struct proc_pollfd)) {
1950 fprintf(stderr, "panic: short read: %d\n", n);
1951 exit(1);
1952 }
1953 for (i = 0; i < nprocs; i++) {
1954 if (pollv[i].fd == pollinfo.fd)
1955 pollv[i].revents = pollinfo.revents;
1956 else
1957 pollv[i].revents = 0;
1958 }
1959 poller_pid = pollinfo.pid;
1960 return 1;
1961}
1962
1963static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001964wakeup_handler(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001965{
1966}
1967
1968static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001969proc_poller(int pfd)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001970{
1971 struct proc_pollfd pollinfo;
1972 struct sigaction sa;
1973 sigset_t blocked_set, empty_set;
1974 int i;
1975 int n;
1976 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001977#ifdef FREEBSD
1978 struct procfs_status pfs;
1979#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001980
1981 switch (fork()) {
1982 case -1:
1983 perror("fork");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001984 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001985 case 0:
1986 break;
1987 default:
1988 return;
1989 }
1990
1991 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1992 sa.sa_flags = 0;
1993 sigemptyset(&sa.sa_mask);
1994 sigaction(SIGHUP, &sa, NULL);
1995 sigaction(SIGINT, &sa, NULL);
1996 sigaction(SIGQUIT, &sa, NULL);
1997 sigaction(SIGPIPE, &sa, NULL);
1998 sigaction(SIGTERM, &sa, NULL);
1999 sa.sa_handler = wakeup_handler;
2000 sigaction(SIGUSR1, &sa, NULL);
2001 sigemptyset(&blocked_set);
2002 sigaddset(&blocked_set, SIGUSR1);
2003 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2004 sigemptyset(&empty_set);
2005
2006 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
2007 perror("getrlimit(RLIMIT_NOFILE, ...)");
Dmitry V. Levina6809652008-11-10 17:14:58 +00002008 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002009 }
2010 n = rl.rlim_cur;
2011 for (i = 0; i < n; i++) {
2012 if (i != pfd && i != proc_poll_pipe[1])
2013 close(i);
2014 }
2015
2016 pollinfo.fd = pfd;
2017 pollinfo.pid = getpid();
2018 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002019#ifndef FREEBSD
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002020 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
2021#else
2022 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
2023#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002024 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002025 switch (errno) {
2026 case EINTR:
2027 continue;
2028 case EBADF:
2029 pollinfo.revents = POLLERR;
2030 break;
2031 case ENOENT:
2032 pollinfo.revents = POLLHUP;
2033 break;
2034 default:
2035 perror("proc_poller: PIOCWSTOP");
2036 }
2037 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2038 _exit(0);
2039 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002040 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002041 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2042 sigsuspend(&empty_set);
2043 }
2044}
2045
2046#endif /* !HAVE_POLLABLE_PROCFS */
2047
2048static int
2049choose_pfd()
2050{
2051 int i, j;
2052 struct tcb *tcp;
2053
2054 static int last;
2055
2056 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002057 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002058 /*
2059 * The previous process is ready to run again. We'll
2060 * let it do so if it is currently in a syscall. This
2061 * heuristic improves the readability of the trace.
2062 */
2063 tcp = pfd2tcb(pollv[last].fd);
2064 if (tcp && (tcp->flags & TCB_INSYSCALL))
2065 return pollv[last].fd;
2066 }
2067
2068 for (i = 0; i < nprocs; i++) {
2069 /* Let competing children run round robin. */
2070 j = (i + last + 1) % nprocs;
2071 if (pollv[j].revents & (POLLHUP | POLLERR)) {
2072 tcp = pfd2tcb(pollv[j].fd);
2073 if (!tcp) {
2074 fprintf(stderr, "strace: lost proc\n");
2075 exit(1);
2076 }
2077 droptcb(tcp);
2078 return -1;
2079 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002080 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002081 last = j;
2082 return pollv[j].fd;
2083 }
2084 }
2085 fprintf(stderr, "strace: nothing ready\n");
2086 exit(1);
2087}
2088
2089static int
Denys Vlasenko12014262011-05-30 14:00:14 +02002090trace(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002091{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002092#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00002093 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002094#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002095 struct tcb *tcp;
2096 int pfd;
2097 int what;
2098 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002099 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002100
2101 for (;;) {
2102 if (interactive)
2103 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2104
2105 if (nprocs == 0)
2106 break;
2107
2108 switch (nprocs) {
2109 case 1:
2110#ifndef HAVE_POLLABLE_PROCFS
2111 if (proc_poll_pipe[0] == -1) {
2112#endif
Roland McGrath54e931f2010-09-14 18:59:20 -07002113 tcp = first_used_tcb();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002114 if (!tcp)
2115 continue;
2116 pfd = tcp->pfd;
2117 if (pfd == -1)
2118 continue;
2119 break;
2120#ifndef HAVE_POLLABLE_PROCFS
2121 }
2122 /* fall through ... */
2123#endif /* !HAVE_POLLABLE_PROCFS */
2124 default:
2125#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002126#ifdef POLL_HACK
2127 /* On some systems (e.g. UnixWare) we get too much ugly
2128 "unfinished..." stuff when multiple proceses are in
2129 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00002130
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002131 if (in_syscall) {
2132 struct pollfd pv;
2133 tcp = in_syscall;
2134 in_syscall = NULL;
2135 pv.fd = tcp->pfd;
2136 pv.events = POLLWANT;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002137 if ((what = poll(&pv, 1, 1)) < 0) {
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002138 if (interrupted)
2139 return 0;
2140 continue;
2141 }
2142 else if (what == 1 && pv.revents & POLLWANT) {
2143 goto FOUND;
2144 }
2145 }
2146#endif
2147
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002148 if (poll(pollv, nprocs, INFTIM) < 0) {
2149 if (interrupted)
2150 return 0;
2151 continue;
2152 }
2153#else /* !HAVE_POLLABLE_PROCFS */
2154 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
2155 if (interrupted)
2156 return 0;
2157 continue;
2158 }
2159#endif /* !HAVE_POLLABLE_PROCFS */
2160 pfd = choose_pfd();
2161 if (pfd == -1)
2162 continue;
2163 break;
2164 }
2165
2166 /* Look up `pfd' in our table. */
2167 if ((tcp = pfd2tcb(pfd)) == NULL) {
2168 fprintf(stderr, "unknown pfd: %u\n", pfd);
2169 exit(1);
2170 }
John Hughesb6643082002-05-23 11:02:22 +00002171#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002172 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00002173#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002174 /* Get the status of the process. */
2175 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002176#ifndef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002177 ioctl_result = IOCTL_WSTOP(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002178#else /* FREEBSD */
2179 /* Thanks to some scheduling mystery, the first poller
2180 sometimes waits for the already processed end of fork
2181 event. Doing a non blocking poll here solves the problem. */
2182 if (proc_poll_pipe[0] != -1)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002183 ioctl_result = IOCTL_STATUS(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002184 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002185 ioctl_result = IOCTL_WSTOP(tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00002186#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002187 ioctl_errno = errno;
2188#ifndef HAVE_POLLABLE_PROCFS
2189 if (proc_poll_pipe[0] != -1) {
2190 if (ioctl_result < 0)
2191 kill(poller_pid, SIGKILL);
2192 else
2193 kill(poller_pid, SIGUSR1);
2194 }
2195#endif /* !HAVE_POLLABLE_PROCFS */
2196 }
2197 if (interrupted)
2198 return 0;
2199
2200 if (interactive)
2201 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2202
2203 if (ioctl_result < 0) {
2204 /* Find out what happened if it failed. */
2205 switch (ioctl_errno) {
2206 case EINTR:
2207 case EBADF:
2208 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002209#ifdef FREEBSD
2210 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00002211#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002212 case ENOENT:
2213 droptcb(tcp);
2214 continue;
2215 default:
2216 perror("PIOCWSTOP");
2217 exit(1);
2218 }
2219 }
2220
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002221#ifdef FREEBSD
2222 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2223 /* discard first event for a syscall we never entered */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002224 IOCTL(tcp->pfd, PIOCRUN, 0);
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002225 continue;
2226 }
Roland McGrath553a6092002-12-16 20:40:39 +00002227#endif
2228
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002229 /* clear the just started flag */
2230 tcp->flags &= ~TCB_STARTUP;
2231
2232 /* set current output file */
2233 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002234 curcol = tcp->curcol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002235
2236 if (cflag) {
2237 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002238#ifdef FREEBSD
2239 char buf[1024];
2240 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002241
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002242 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
2243 buf[len] = '\0';
2244 sscanf(buf,
2245 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2246 &stime.tv_sec, &stime.tv_usec);
2247 } else
2248 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002249#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002250 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2251 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002252#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002253 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2254 tcp->stime = stime;
2255 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002256 what = tcp->status.PR_WHAT;
2257 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002258#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002259 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002260 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2261 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002262 if (trace_syscall(tcp) < 0) {
2263 fprintf(stderr, "syscall trouble\n");
2264 exit(1);
2265 }
2266 }
2267 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002268#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002269 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002270#ifdef POLL_HACK
2271 in_syscall = tcp;
2272#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002273 case PR_SYSEXIT:
2274 if (trace_syscall(tcp) < 0) {
2275 fprintf(stderr, "syscall trouble\n");
2276 exit(1);
2277 }
2278 break;
2279 case PR_SIGNALLED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002280 if (cflag != CFLAG_ONLY_STATS
2281 && (qual_flags[what] & QUAL_SIGNAL)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002282 printleader(tcp);
2283 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002284 signame(what), strsignal(what));
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002285 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002286#ifdef PR_INFO
2287 if (tcp->status.PR_INFO.si_signo == what) {
2288 printleader(tcp);
2289 tprintf(" siginfo=");
2290 printsiginfo(&tcp->status.PR_INFO, 1);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002291 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002292 }
2293#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002294 }
2295 break;
2296 case PR_FAULTED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002297 if (cflag != CFLAGS_ONLY_STATS
2298 && (qual_flags[what] & QUAL_FAULT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002299 printleader(tcp);
2300 tprintf("=== FAULT %d ===", what);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002301 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002302 }
2303 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002304#ifdef FREEBSD
2305 case 0: /* handle case we polled for nothing */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002306 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00002307#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002308 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002309 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002310 exit(1);
2311 break;
2312 }
Andreas Schwabccdff482009-10-27 16:27:13 +01002313 /* Remember current print column before continuing. */
2314 tcp->curcol = curcol;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002315 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002316#ifndef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002317 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002318#else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002319 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002320#endif
Andreas Schwab372cc842010-07-09 11:49:27 +02002321 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002322 perror("PIOCRUN");
2323 exit(1);
2324 }
2325 }
2326 return 0;
2327}
2328
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002329#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002330
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002331#ifdef TCB_GROUP_EXITING
2332/* Handle an exit detach or death signal that is taking all the
2333 related clone threads with it. This is called in three circumstances:
2334 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
2335 SIG == 0 Continuing TCP will perform an exit_group syscall.
2336 SIG == other Continuing TCP with SIG will kill the process.
2337*/
2338static int
2339handle_group_exit(struct tcb *tcp, int sig)
2340{
2341 /* We need to locate our records of all the clone threads
2342 related to TCP, either its children or siblings. */
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002343 struct tcb *leader = NULL;
2344
2345 if (tcp->flags & TCB_CLONE_THREAD)
2346 leader = tcp->parent;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002347
2348 if (sig < 0) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002349 if (leader != NULL && leader != tcp
2350 && !(leader->flags & TCB_GROUP_EXITING)
2351 && !(tcp->flags & TCB_STARTUP)
2352 ) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002353 fprintf(stderr,
2354 "PANIC: handle_group_exit: %d leader %d\n",
2355 tcp->pid, leader ? leader->pid : -1);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002356 }
2357 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath0a463882007-07-05 18:43:16 +00002358 droptcb(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002359 }
2360 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00002361 /* Mark that we are taking the process down. */
2362 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002363 if (tcp->flags & TCB_ATTACHED) {
Roland McGrathd6a32f12007-07-11 08:35:11 +00002364 detach(tcp, sig);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002365 if (leader != NULL && leader != tcp)
Roland McGrath1bfd3102007-08-03 10:02:00 +00002366 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002367 } else {
2368 if (ptrace_restart(PTRACE_CONT, tcp, sig) < 0) {
2369 cleanup();
2370 return -1;
2371 }
2372 if (leader != NULL) {
Roland McGrath05690952004-10-20 01:00:27 +00002373 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002374 if (leader != tcp)
2375 droptcb(tcp);
2376 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002377 /* The leader will report to us as parent now,
2378 and then we'll get to the SIG==-1 case. */
2379 return 0;
2380 }
2381 }
2382
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002383 return 0;
2384}
2385#endif
2386
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002387#ifdef LINUX
2388static int
2389handle_ptrace_event(int status, struct tcb *tcp)
2390{
2391 if (status >> 16 == PTRACE_EVENT_VFORK ||
2392 status >> 16 == PTRACE_EVENT_CLONE ||
2393 status >> 16 == PTRACE_EVENT_FORK) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +00002394 long childpid;
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002395
2396 if (do_ptrace(PTRACE_GETEVENTMSG, tcp, NULL, &childpid) < 0) {
2397 if (errno != ESRCH) {
2398 fprintf(stderr, "\
2399%s: handle_ptrace_event: ptrace cannot get new child's pid\n",
2400 progname);
2401 cleanup();
2402 exit(1);
2403 }
2404 return -1;
2405 }
2406 return handle_new_child(tcp, childpid, 0);
2407 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002408 if (status >> 16 == PTRACE_EVENT_EXEC) {
2409 if (debug)
2410 fprintf(stderr, "PTRACE_EVENT_EXEC on pid %d (ignored)\n", tcp->pid);
2411 return 0;
2412 }
Denys Vlasenko75422762011-05-27 14:36:01 +02002413 /* Some PTRACE_EVENT_foo we didn't ask for?! */
2414 error_msg("Unexpected status %x on pid %d", status, tcp->pid);
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002415 return 1;
2416}
2417#endif
2418
Roland McGratheb9e2e82009-06-02 16:49:22 -07002419static int
2420trace()
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002421{
2422 int pid;
2423 int wait_errno;
2424 int status;
2425 struct tcb *tcp;
2426#ifdef LINUX
2427 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002428#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002429 static int wait4_options = __WALL;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002430#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002431#endif /* LINUX */
2432
Roland McGratheb9e2e82009-06-02 16:49:22 -07002433 while (nprocs != 0) {
Denys Vlasenko222713a2009-03-17 14:29:59 +00002434 if (interrupted)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002435 return 0;
2436 if (interactive)
2437 sigprocmask(SIG_SETMASK, &empty_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002438#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002439#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002440 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002441 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002442 /* this kernel does not support __WALL */
2443 wait4_options &= ~__WALL;
2444 errno = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002445 pid = wait4(-1, &status, wait4_options,
2446 cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002447 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002448 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002449 /* most likely a "cloned" process */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002450 pid = wait4(-1, &status, __WCLONE,
2451 cflag ? &ru : NULL);
2452 if (pid == -1) {
2453 fprintf(stderr, "strace: clone wait4 "
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002454 "failed: %s\n", strerror(errno));
2455 }
2456 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002457#else
2458 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
2459#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002460#endif /* LINUX */
2461#ifdef SUNOS4
2462 pid = wait(&status);
2463#endif /* SUNOS4 */
2464 wait_errno = errno;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002465 if (interactive)
2466 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002467
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002468 if (pid == -1) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002469 switch (wait_errno) {
2470 case EINTR:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002471 continue;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002472 case ECHILD:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002473 /*
2474 * We would like to verify this case
2475 * but sometimes a race in Solbourne's
2476 * version of SunOS sometimes reports
2477 * ECHILD before sending us SIGCHILD.
2478 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002479 return 0;
2480 default:
2481 errno = wait_errno;
2482 perror("strace: wait");
2483 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002484 }
2485 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002486 if (pid == popen_pid) {
2487 if (WIFEXITED(status) || WIFSIGNALED(status))
Denys Vlasenko7dd23382011-06-22 13:03:56 +02002488 popen_pid = 0;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002489 continue;
2490 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002491 if (debug)
2492 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2493
2494 /* Look up `pid' in our table. */
2495 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002496#ifdef LINUX
Roland McGrath41c48222008-07-18 00:25:10 +00002497 if (followfork) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002498 /* This is needed to go with the CLONE_PTRACE
2499 changes in process.c/util.c: we might see
2500 the child's initial trap before we see the
2501 parent return from the clone syscall.
2502 Leave the child suspended until the parent
2503 returns from its system call. Only then
2504 will we have the association of parent and
2505 child so that we know how to do clearbpt
2506 in the child. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +00002507 tcp = alloctcb(pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002508 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002509 if (!qflag)
2510 fprintf(stderr, "\
2511Process %d attached (waiting for parent)\n",
2512 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002513 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002514 else
2515 /* This can happen if a clone call used
2516 CLONE_PTRACE itself. */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002517#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002518 {
2519 fprintf(stderr, "unknown pid: %u\n", pid);
2520 if (WIFSTOPPED(status))
2521 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2522 exit(1);
2523 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002524 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002525 /* set current output file */
2526 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002527 curcol = tcp->curcol;
Denys Vlasenko84e20af2009-02-10 16:03:20 +00002528 if (cflag) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002529#ifdef LINUX
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002530 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2531 tcp->stime = ru.ru_stime;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002532#endif /* !LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002533 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002534
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002535 if (tcp->flags & TCB_SUSPENDED) {
2536 /*
2537 * Apparently, doing any ptrace() call on a stopped
2538 * process, provokes the kernel to report the process
2539 * status again on a subsequent wait(), even if the
2540 * process has not been actually restarted.
2541 * Since we have inspected the arguments of suspended
2542 * processes we end up here testing for this case.
2543 */
2544 continue;
2545 }
2546 if (WIFSIGNALED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002547 if (pid == strace_child)
2548 exit_code = 0x100 | WTERMSIG(status);
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002549 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002550 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2551 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002552 tprintf("+++ killed by %s %s+++",
2553 signame(WTERMSIG(status)),
2554#ifdef WCOREDUMP
2555 WCOREDUMP(status) ? "(core dumped) " :
2556#endif
2557 "");
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002558 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002559 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002560#ifdef TCB_GROUP_EXITING
2561 handle_group_exit(tcp, -1);
2562#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002563 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002564#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002565 continue;
2566 }
2567 if (WIFEXITED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002568 if (pid == strace_child)
2569 exit_code = WEXITSTATUS(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002570 if (debug)
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002571 fprintf(stderr, "pid %u exited with %d\n", pid, WEXITSTATUS(status));
2572 if ((tcp->flags & (TCB_ATTACHED|TCB_STARTUP)) == TCB_ATTACHED
Roland McGrath05690952004-10-20 01:00:27 +00002573#ifdef TCB_GROUP_EXITING
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002574 && !(tcp->parent && (tcp->parent->flags & TCB_GROUP_EXITING))
Roland McGrath1bfd3102007-08-03 10:02:00 +00002575 && !(tcp->flags & TCB_GROUP_EXITING)
Roland McGrath05690952004-10-20 01:00:27 +00002576#endif
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002577 ) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002578 fprintf(stderr,
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002579 "PANIC: attached pid %u exited with %d\n",
2580 pid, WEXITSTATUS(status));
2581 }
Roland McGrath0a396902003-06-10 03:05:53 +00002582 if (tcp == tcp_last) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002583 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT)) == TCB_INSYSCALL)
Roland McGrath0a396902003-06-10 03:05:53 +00002584 tprintf(" <unfinished ... exit status %d>\n",
2585 WEXITSTATUS(status));
2586 tcp_last = NULL;
2587 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002588#ifdef TCB_GROUP_EXITING
2589 handle_group_exit(tcp, -1);
2590#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002591 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002592#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002593 continue;
2594 }
2595 if (!WIFSTOPPED(status)) {
2596 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2597 droptcb(tcp);
2598 continue;
2599 }
2600 if (debug)
2601 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002602 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002603
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002604 if (status >> 16) {
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002605 if (handle_ptrace_event(status, tcp) != 1)
2606 goto tracing;
2607 }
2608
Roland McGrath02203312007-06-11 22:06:31 +00002609 /*
2610 * Interestingly, the process may stop
2611 * with STOPSIG equal to some other signal
Roland McGratheb9e2e82009-06-02 16:49:22 -07002612 * than SIGSTOP if we happend to attach
Roland McGrath02203312007-06-11 22:06:31 +00002613 * just before the process takes a signal.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002614 * A no-MMU vforked child won't send up a signal,
2615 * so skip the first (lost) execve notification.
Roland McGrath02203312007-06-11 22:06:31 +00002616 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002617 if ((tcp->flags & TCB_STARTUP) &&
2618 (WSTOPSIG(status) == SIGSTOP || strace_vforked)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002619 /*
2620 * This flag is there to keep us in sync.
2621 * Next time this process stops it should
2622 * really be entering a system call.
2623 */
2624 tcp->flags &= ~TCB_STARTUP;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002625 if (tcp->flags & TCB_BPTSET) {
Roland McGrath02203312007-06-11 22:06:31 +00002626 /*
2627 * One example is a breakpoint inherited from
2628 * parent through fork ().
2629 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002630 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2631 droptcb(tcp);
2632 cleanup();
2633 return -1;
2634 }
2635 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002636#ifdef LINUX
Denys Vlasenkof44cce42011-06-21 14:34:10 +02002637 /* If options were not set for this tracee yet */
2638 if (tcp->parent == NULL) {
2639 if (ptrace_setoptions) {
2640 if (debug)
2641 fprintf(stderr, "setting opts %x on pid %d\n", ptrace_setoptions, tcp->pid);
2642 if (ptrace(PTRACE_SETOPTIONS, tcp->pid, NULL, ptrace_setoptions) < 0) {
2643 if (errno != ESRCH) {
2644 /* Should never happen, really */
2645 perror_msg_and_die("PTRACE_SETOPTIONS");
2646 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002647 }
2648 }
2649 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002650#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002651 goto tracing;
2652 }
2653
Denys Vlasenko75422762011-05-27 14:36:01 +02002654 if (WSTOPSIG(status) != syscall_trap_sig) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002655 if (WSTOPSIG(status) == SIGSTOP &&
2656 (tcp->flags & TCB_SIGTRAPPED)) {
2657 /*
2658 * Trapped attempt to block SIGTRAP
2659 * Hope we are back in control now.
2660 */
2661 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002662 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002663 cleanup();
2664 return -1;
2665 }
2666 continue;
2667 }
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002668 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002669 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Dmitry V. Levinc15dfc72011-03-10 14:44:45 +00002670 siginfo_t si;
2671#if defined(PT_CR_IPSR) && defined(PT_CR_IIP)
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002672 long pc = 0;
2673 long psr = 0;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002674
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002675 upeek(tcp, PT_CR_IPSR, &psr);
2676 upeek(tcp, PT_CR_IIP, &pc);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002677
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002678# define PSR_RI 41
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002679 pc += (psr >> PSR_RI) & 0x3;
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002680# define PC_FORMAT_STR " @ %lx"
2681# define PC_FORMAT_ARG pc
2682#else
2683# define PC_FORMAT_STR "%s"
2684# define PC_FORMAT_ARG ""
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002685#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002686 printleader(tcp);
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002687 if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
2688 tprintf("--- ");
2689 printsiginfo(&si, verbose(tcp));
2690 tprintf(" (%s)" PC_FORMAT_STR " ---",
2691 strsignal(WSTOPSIG(status)),
2692 PC_FORMAT_ARG);
2693 } else
2694 tprintf("--- %s by %s" PC_FORMAT_STR " ---",
2695 strsignal(WSTOPSIG(status)),
2696 signame(WSTOPSIG(status)),
2697 PC_FORMAT_ARG);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002698 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002699 }
Roland McGrath05690952004-10-20 01:00:27 +00002700 if (((tcp->flags & TCB_ATTACHED) ||
2701 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002702 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002703#ifdef TCB_GROUP_EXITING
2704 handle_group_exit(tcp, WSTOPSIG(status));
2705#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002706 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002707#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002708 continue;
2709 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002710 if (ptrace_restart(PTRACE_SYSCALL, tcp, WSTOPSIG(status)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002711 cleanup();
2712 return -1;
2713 }
2714 tcp->flags &= ~TCB_SUSPENDED;
2715 continue;
2716 }
Roland McGrath02203312007-06-11 22:06:31 +00002717 /* we handled the STATUS, we are permitted to interrupt now. */
2718 if (interrupted)
2719 return 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002720 if (trace_syscall(tcp) < 0 && !tcp->ptrace_errno) {
2721 /* ptrace() failed in trace_syscall() with ESRCH.
2722 * Likely a result of process disappearing mid-flight.
2723 * Observed case: exit_group() terminating
2724 * all processes in thread group. In this case, threads
2725 * "disappear" in an unpredictable moment without any
2726 * notification to strace via wait().
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002727 */
2728 if (tcp->flags & TCB_ATTACHED) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002729 if (tcp_last) {
2730 /* Do we have dangling line "syscall(param, param"?
2731 * Finish the line then. We cannot
2732 */
2733 tcp_last->flags |= TCB_REPRINT;
2734 tprintf(" <unfinished ...>");
2735 printtrailer();
2736 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002737 detach(tcp, 0);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002738 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002739 ptrace(PTRACE_KILL,
2740 tcp->pid, (char *) 1, SIGTERM);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002741 droptcb(tcp);
2742 }
2743 continue;
2744 }
2745 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002746#ifdef TCB_GROUP_EXITING
2747 if (tcp->flags & TCB_GROUP_EXITING) {
2748 if (handle_group_exit(tcp, 0) < 0)
2749 return -1;
2750 continue;
2751 }
2752#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002753 if (tcp->flags & TCB_ATTACHED)
2754 detach(tcp, 0);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002755 else if (ptrace_restart(PTRACE_CONT, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002756 cleanup();
2757 return -1;
2758 }
2759 continue;
2760 }
2761 if (tcp->flags & TCB_SUSPENDED) {
2762 if (!qflag)
2763 fprintf(stderr, "Process %u suspended\n", pid);
2764 continue;
2765 }
2766 tracing:
Andreas Schwabccdff482009-10-27 16:27:13 +01002767 /* Remember current print column before continuing. */
2768 tcp->curcol = curcol;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002769 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002770 cleanup();
2771 return -1;
2772 }
2773 }
2774 return 0;
2775}
2776
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002777#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002778
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002779#include <stdarg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002780
2781void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002782tprintf(const char *fmt, ...)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002783{
2784 va_list args;
2785
Andreas Schwabe5355de2009-10-27 16:56:43 +01002786 va_start(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002787 if (outf) {
2788 int n = vfprintf(outf, fmt, args);
Andreas Schwabccdff482009-10-27 16:27:13 +01002789 if (n < 0) {
2790 if (outf != stderr)
2791 perror(outfname == NULL
2792 ? "<writing to pipe>" : outfname);
2793 } else
Roland McGrathb310a0c2003-11-06 23:41:22 +00002794 curcol += n;
2795 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002796 va_end(args);
2797 return;
2798}
2799
2800void
Denys Vlasenko12014262011-05-30 14:00:14 +02002801printleader(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002802{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002803 if (tcp_last) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002804 if (tcp_last->ptrace_errno) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002805 if (tcp_last->flags & TCB_INSYSCALL) {
Denys Vlasenkoe62df002011-06-08 16:15:04 +02002806 tprintf(" <unavailable>) ");
Roland McGratheb9e2e82009-06-02 16:49:22 -07002807 tabto(acolumn);
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002808 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002809 tprintf("= ? <unavailable>\n");
2810 tcp_last->ptrace_errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002811 } else if (!outfname || followfork < 2 || tcp_last == tcp) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002812 tcp_last->flags |= TCB_REPRINT;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002813 tprintf(" <unfinished ...>\n");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002814 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002815 }
2816 curcol = 0;
2817 if ((followfork == 1 || pflag_seen > 1) && outfname)
2818 tprintf("%-5d ", tcp->pid);
2819 else if (nprocs > 1 && !outfname)
2820 tprintf("[pid %5u] ", tcp->pid);
2821 if (tflag) {
2822 char str[sizeof("HH:MM:SS")];
2823 struct timeval tv, dtv;
2824 static struct timeval otv;
2825
2826 gettimeofday(&tv, NULL);
2827 if (rflag) {
2828 if (otv.tv_sec == 0)
2829 otv = tv;
2830 tv_sub(&dtv, &tv, &otv);
2831 tprintf("%6ld.%06ld ",
2832 (long) dtv.tv_sec, (long) dtv.tv_usec);
2833 otv = tv;
2834 }
2835 else if (tflag > 2) {
2836 tprintf("%ld.%06ld ",
2837 (long) tv.tv_sec, (long) tv.tv_usec);
2838 }
2839 else {
2840 time_t local = tv.tv_sec;
2841 strftime(str, sizeof(str), "%T", localtime(&local));
2842 if (tflag > 1)
2843 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2844 else
2845 tprintf("%s ", str);
2846 }
2847 }
2848 if (iflag)
2849 printcall(tcp);
2850}
2851
2852void
Denys Vlasenko12014262011-05-30 14:00:14 +02002853tabto(int col)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002854{
2855 if (curcol < col)
2856 tprintf("%*s", col - curcol, "");
2857}
2858
2859void
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002860printtrailer(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002861{
2862 tprintf("\n");
2863 tcp_last = NULL;
2864}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002865
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002866#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002867
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002868int
2869mp_ioctl(int fd, int cmd, void *arg, int size)
2870{
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002871 struct iovec iov[2];
2872 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002873
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002874 iov[0].iov_base = &cmd;
2875 iov[0].iov_len = sizeof cmd;
2876 if (arg) {
2877 ++n;
2878 iov[1].iov_base = arg;
2879 iov[1].iov_len = size;
2880 }
Roland McGrath553a6092002-12-16 20:40:39 +00002881
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002882 return writev(fd, iov, n);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002883}
2884
2885#endif