blob: 110625556ff46587bc8eb1c815125f2681956942 [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;
Denys Vlasenkoead73bd2011-06-24 22:49:58 +0200121static uid_t run_uid;
122static gid_t run_gid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000123
124int acolumn = DEFAULT_ACOLUMN;
125int max_strlen = DEFAULT_STRLEN;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +0000126static char *outfname = NULL;
Denys Vlasenkoead73bd2011-06-24 22:49:58 +0200127static FILE *outf;
Andreas Schwabccdff482009-10-27 16:27:13 +0100128static int curcol;
Denys Vlasenkoead73bd2011-06-24 22:49:58 +0200129static struct tcb **tcbtab;
Denys Vlasenko2b60c352011-06-22 12:45:25 +0200130static unsigned int nprocs, tcbtabsize;
Denys Vlasenkoead73bd2011-06-24 22:49:58 +0200131static const 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
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200176usage(FILE *ofp, int exitval)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000177{
178 fprintf(ofp, "\
Grant Edwards8a082772011-04-07 20:25:40 +0000179usage: strace [-CdDffhiqrtttTvVxxy] [-a column] [-e expr] ... [-o file]\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000180 [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n\
Grant Edwards8a082772011-04-07 20:25:40 +0000181 [-P path] [command [arg ...]]\n\
Andreas Schwabb87d30c2010-06-11 15:49:36 +0200182 or: strace -c [-D] [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000183 [command [arg ...]]\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000184-c -- count time, calls, and errors for each syscall and report summary\n\
Andreas Schwabb87d30c2010-06-11 15:49:36 +0200185-C -- like -c but also print regular output while processes are running\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000186-f -- follow forks, -ff -- with output into separate files\n\
187-F -- attempt to follow vforks, -h -- print help message\n\
188-i -- print instruction pointer at time of syscall\n\
189-q -- suppress messages about attaching, detaching, etc.\n\
190-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
191-T -- print time spent in each syscall, -V -- print version\n\
192-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
193-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
Grant Edwards8a082772011-04-07 20:25:40 +0000194-y -- print paths associated with file descriptor arguments\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000195-a column -- alignment COLUMN for printing syscall results (default %d)\n\
196-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
197 options: trace, abbrev, verbose, raw, signal, read, or write\n\
198-o file -- send trace output to FILE instead of stderr\n\
199-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
200-p pid -- trace process with process id PID, may be repeated\n\
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000201-D -- run tracer process as a detached grandchild, not as parent\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000202-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
203-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
204-u username -- run command as username handling setuid and/or setgid\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000205-E var=val -- put var=val in the environment for command\n\
206-E var -- remove var from the environment for command\n\
Grant Edwards8a082772011-04-07 20:25:40 +0000207-P path -- trace accesses to path\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000208" /* this is broken, so don't document it
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000209-z -- print only succeeding syscalls\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000210 */
211, DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000212 exit(exitval);
213}
214
Denys Vlasenko75422762011-05-27 14:36:01 +0200215static void die(void) __attribute__ ((noreturn));
216static void die(void)
217{
218 if (strace_tracer_pid == getpid()) {
219 cflag = 0;
220 cleanup();
221 }
222 exit(1);
223}
224
225static void verror_msg(int err_no, const char *fmt, va_list p)
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200226{
Dmitry V. Levin44d05322011-06-09 15:50:41 +0000227 fflush(NULL);
228 fprintf(stderr, "%s: ", progname);
229 vfprintf(stderr, fmt, p);
230 if (err_no)
231 fprintf(stderr, ": %s\n", strerror(err_no));
232 else
233 putc('\n', stderr);
234 fflush(stderr);
Denys Vlasenko75422762011-05-27 14:36:01 +0200235}
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200236
Denys Vlasenko75422762011-05-27 14:36:01 +0200237void error_msg(const char *fmt, ...)
238{
239 va_list p;
240 va_start(p, fmt);
241 verror_msg(0, fmt, p);
242 va_end(p);
243}
244
245void error_msg_and_die(const char *fmt, ...)
246{
247 va_list p;
248 va_start(p, fmt);
249 verror_msg(0, fmt, p);
250 die();
251}
252
253void perror_msg(const char *fmt, ...)
254{
255 va_list p;
256 va_start(p, fmt);
257 verror_msg(errno, fmt, p);
258 va_end(p);
259}
260
261void perror_msg_and_die(const char *fmt, ...)
262{
263 va_list p;
264 va_start(p, fmt);
265 verror_msg(errno, fmt, p);
266 die();
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200267}
268
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000269#ifdef SVR4
270#ifdef MIPS
271void
272foobar()
273{
274}
275#endif /* MIPS */
276#endif /* SVR4 */
277
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400278/* Glue for systems without a MMU that cannot provide fork() */
279#ifdef HAVE_FORK
280# define strace_vforked 0
281#else
282# define strace_vforked 1
283# define fork() vfork()
284#endif
285
Denys Vlasenko1f532ab2011-06-22 13:11:23 +0200286static void
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000287set_cloexec_flag(int fd)
288{
Denys Vlasenko1f532ab2011-06-22 13:11:23 +0200289 int flags, newflags;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000290
Denys Vlasenko1f532ab2011-06-22 13:11:23 +0200291 flags = fcntl(fd, F_GETFD);
292 if (flags < 0) {
293 /* Can happen only if fd is bad.
294 * Should never happen: if it does, we have a bug
295 * in the caller. Therefore we just abort
296 * instead of propagating the error.
297 */
298 perror_msg_and_die("fcntl(%d, F_GETFD)", fd);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000299 }
300
301 newflags = flags | FD_CLOEXEC;
302 if (flags == newflags)
Denys Vlasenko1f532ab2011-06-22 13:11:23 +0200303 return;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000304
Denys Vlasenko1f532ab2011-06-22 13:11:23 +0200305 fcntl(fd, F_SETFD, newflags); /* never fails */
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000306}
307
308/*
309 * When strace is setuid executable, we have to swap uids
310 * before and after filesystem and process management operations.
311 */
312static void
313swap_uid(void)
314{
315#ifndef SVR4
316 int euid = geteuid(), uid = getuid();
317
Denys Vlasenko7b609d52011-06-22 14:32:43 +0200318 if (euid != uid && setreuid(euid, uid) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200319 perror_msg_and_die("setreuid");
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000320 }
321#endif
322}
323
Roland McGrath4bfa6262007-07-05 20:03:16 +0000324#if _LFS64_LARGEFILE
325# define fopen_for_output fopen64
326#else
327# define fopen_for_output fopen
328#endif
329
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000330static FILE *
Denys Vlasenko3d5ed412011-06-22 13:17:16 +0200331strace_fopen(const char *path)
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000332{
333 FILE *fp;
334
335 swap_uid();
Denys Vlasenko3d5ed412011-06-22 13:17:16 +0200336 fp = fopen_for_output(path, "w");
337 if (!fp)
338 perror_msg_and_die("Can't fopen '%s'", path);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000339 swap_uid();
Denys Vlasenko3d5ed412011-06-22 13:17:16 +0200340 set_cloexec_flag(fileno(fp));
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000341 return fp;
342}
343
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200344static int popen_pid = 0;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000345
346#ifndef _PATH_BSHELL
347# define _PATH_BSHELL "/bin/sh"
348#endif
349
350/*
351 * We cannot use standard popen(3) here because we have to distinguish
352 * popen child process from other processes we trace, and standard popen(3)
353 * does not export its child's pid.
354 */
355static FILE *
356strace_popen(const char *command)
357{
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200358 FILE *fp;
359 int fds[2];
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000360
361 swap_uid();
362 if (pipe(fds) < 0)
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200363 perror_msg_and_die("pipe");
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000364
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200365 set_cloexec_flag(fds[1]); /* never fails */
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000366
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200367 popen_pid = vfork();
368 if (popen_pid == -1)
369 perror_msg_and_die("vfork");
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000370
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200371 if (popen_pid == 0) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000372 /* child */
373 close(fds[1]);
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200374 if (fds[0] != 0) {
375 if (dup2(fds[0], 0))
376 perror_msg_and_die("dup2");
377 close(fds[0]);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000378 }
379 execl(_PATH_BSHELL, "sh", "-c", command, NULL);
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200380 perror_msg_and_die("Can't execute '%s'", _PATH_BSHELL);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000381 }
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200382
383 /* parent */
384 close(fds[0]);
385 swap_uid();
386 fp = fdopen(fds[1], "w");
387 if (!fp)
388 error_msg_and_die("Out of memory");
389 return fp;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000390}
391
Denys Vlasenko3d5ed412011-06-22 13:17:16 +0200392static void
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000393newoutf(struct tcb *tcp)
394{
395 if (outfname && followfork > 1) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000396 char name[520 + sizeof(int) * 3];
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000397 sprintf(name, "%.512s.%u", outfname, tcp->pid);
Denys Vlasenko3d5ed412011-06-22 13:17:16 +0200398 tcp->outf = strace_fopen(name);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000399 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000400}
401
Roland McGrath02203312007-06-11 22:06:31 +0000402static void
403startup_attach(void)
404{
405 int tcbi;
406 struct tcb *tcp;
407
408 /*
409 * Block user interruptions as we would leave the traced
410 * process stopped (process state T) if we would terminate in
411 * between PTRACE_ATTACH and wait4 () on SIGSTOP.
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200412 * We rely on cleanup() from this point on.
Roland McGrath02203312007-06-11 22:06:31 +0000413 */
414 if (interactive)
415 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
416
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000417 if (daemonized_tracer) {
418 pid_t pid = fork();
419 if (pid < 0) {
420 _exit(1);
421 }
422 if (pid) { /* parent */
423 /*
Denys Vlasenko75422762011-05-27 14:36:01 +0200424 * Wait for grandchild to attach to straced process
425 * (grandparent). Grandchild SIGKILLs us after it attached.
426 * Grandparent's wait() is unblocked by our death,
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000427 * it proceeds to exec the straced program.
428 */
429 pause();
430 _exit(0); /* paranoia */
431 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200432 /* grandchild */
433 /* We will be the tracer process. Remember our new pid: */
434 strace_tracer_pid = getpid();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000435 }
436
Roland McGrath02203312007-06-11 22:06:31 +0000437 for (tcbi = 0; tcbi < tcbtabsize; tcbi++) {
438 tcp = tcbtab[tcbi];
439 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
440 continue;
441#ifdef LINUX
442 if (tcp->flags & TCB_CLONE_THREAD)
443 continue;
444#endif
445 /* Reinitialize the output since it may have changed. */
446 tcp->outf = outf;
Denys Vlasenko3d5ed412011-06-22 13:17:16 +0200447 newoutf(tcp);
Roland McGrath02203312007-06-11 22:06:31 +0000448
449#ifdef USE_PROCFS
450 if (proc_open(tcp, 1) < 0) {
451 fprintf(stderr, "trouble opening proc file\n");
452 droptcb(tcp);
453 continue;
454 }
455#else /* !USE_PROCFS */
456# ifdef LINUX
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000457 if (followfork && !daemonized_tracer) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000458 char procdir[sizeof("/proc/%d/task") + sizeof(int) * 3];
Roland McGrath02203312007-06-11 22:06:31 +0000459 DIR *dir;
460
461 sprintf(procdir, "/proc/%d/task", tcp->pid);
462 dir = opendir(procdir);
463 if (dir != NULL) {
464 unsigned int ntid = 0, nerr = 0;
465 struct dirent *de;
466 int tid;
467 while ((de = readdir(dir)) != NULL) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000468 if (de->d_fileno == 0)
Roland McGrath02203312007-06-11 22:06:31 +0000469 continue;
470 tid = atoi(de->d_name);
471 if (tid <= 0)
472 continue;
473 ++ntid;
Denys Vlasenkof95397a2011-06-24 16:51:16 +0200474 if (ptrace(PTRACE_ATTACH, tid, (char *) 1, 0) < 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000475 ++nerr;
Denys Vlasenkof95397a2011-06-24 16:51:16 +0200476 if (debug)
477 fprintf(stderr, "attach to pid %d failed\n", tid);
478 }
479 else {
480 if (debug)
481 fprintf(stderr, "attach to pid %d succeeded\n", tid);
482 if (tid != tcbtab[tcbi]->pid) {
483 tcp = alloctcb(tid);
484 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD;
Denys Vlasenkof95397a2011-06-24 16:51:16 +0200485 tcp->parent = tcbtab[tcbi];
486 }
Roland McGrath02203312007-06-11 22:06:31 +0000487 }
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000488 if (interactive) {
489 sigprocmask(SIG_SETMASK, &empty_set, NULL);
490 if (interrupted)
491 return;
492 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
493 }
Roland McGrath02203312007-06-11 22:06:31 +0000494 }
495 closedir(dir);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000496 ntid -= nerr;
497 if (ntid == 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000498 perror("attach: ptrace(PTRACE_ATTACH, ...)");
499 droptcb(tcp);
500 continue;
501 }
502 if (!qflag) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000503 fprintf(stderr, ntid > 1
504? "Process %u attached with %u threads - interrupt to quit\n"
505: "Process %u attached - interrupt to quit\n",
506 tcbtab[tcbi]->pid, ntid);
Roland McGrath02203312007-06-11 22:06:31 +0000507 }
508 continue;
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000509 } /* if (opendir worked) */
510 } /* if (-f) */
Roland McGrath02203312007-06-11 22:06:31 +0000511# endif
512 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
513 perror("attach: ptrace(PTRACE_ATTACH, ...)");
514 droptcb(tcp);
515 continue;
516 }
Denys Vlasenkof95397a2011-06-24 16:51:16 +0200517 if (debug)
518 fprintf(stderr, "attach to pid %d (main) succeeded\n", tcp->pid);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000519
520 if (daemonized_tracer) {
521 /*
522 * It is our grandparent we trace, not a -p PID.
523 * Don't want to just detach on exit, so...
524 */
525 tcp->flags &= ~TCB_ATTACHED;
526 /*
527 * Make parent go away.
528 * Also makes grandparent's wait() unblock.
529 */
530 kill(getppid(), SIGKILL);
531 }
532
Roland McGrath02203312007-06-11 22:06:31 +0000533#endif /* !USE_PROCFS */
534 if (!qflag)
535 fprintf(stderr,
536 "Process %u attached - interrupt to quit\n",
537 tcp->pid);
Denys Vlasenkof95397a2011-06-24 16:51:16 +0200538 } /* for each tcbtab[] */
Roland McGrath02203312007-06-11 22:06:31 +0000539
540 if (interactive)
541 sigprocmask(SIG_SETMASK, &empty_set, NULL);
542}
543
544static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200545startup_child(char **argv)
Roland McGrath02203312007-06-11 22:06:31 +0000546{
547 struct stat statbuf;
548 const char *filename;
549 char pathname[MAXPATHLEN];
550 int pid = 0;
551 struct tcb *tcp;
552
553 filename = argv[0];
554 if (strchr(filename, '/')) {
555 if (strlen(filename) > sizeof pathname - 1) {
556 errno = ENAMETOOLONG;
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200557 perror_msg_and_die("exec");
Roland McGrath02203312007-06-11 22:06:31 +0000558 }
559 strcpy(pathname, filename);
560 }
561#ifdef USE_DEBUGGING_EXEC
562 /*
563 * Debuggers customarily check the current directory
564 * first regardless of the path but doing that gives
565 * security geeks a panic attack.
566 */
567 else if (stat(filename, &statbuf) == 0)
568 strcpy(pathname, filename);
569#endif /* USE_DEBUGGING_EXEC */
570 else {
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000571 const char *path;
Roland McGrath02203312007-06-11 22:06:31 +0000572 int m, n, len;
573
574 for (path = getenv("PATH"); path && *path; path += m) {
575 if (strchr(path, ':')) {
576 n = strchr(path, ':') - path;
577 m = n + 1;
578 }
579 else
580 m = n = strlen(path);
581 if (n == 0) {
582 if (!getcwd(pathname, MAXPATHLEN))
583 continue;
584 len = strlen(pathname);
585 }
586 else if (n > sizeof pathname - 1)
587 continue;
588 else {
589 strncpy(pathname, path, n);
590 len = n;
591 }
592 if (len && pathname[len - 1] != '/')
593 pathname[len++] = '/';
594 strcpy(pathname + len, filename);
595 if (stat(pathname, &statbuf) == 0 &&
596 /* Accept only regular files
597 with some execute bits set.
598 XXX not perfect, might still fail */
599 S_ISREG(statbuf.st_mode) &&
600 (statbuf.st_mode & 0111))
601 break;
602 }
603 }
604 if (stat(pathname, &statbuf) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200605 perror_msg_and_die("Can't stat '%s'", filename);
Roland McGrath02203312007-06-11 22:06:31 +0000606 }
Dmitry V. Levina6809652008-11-10 17:14:58 +0000607 strace_child = pid = fork();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000608 if (pid < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200609 perror_msg_and_die("fork");
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000610 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200611 if ((pid != 0 && daemonized_tracer) /* -D: parent to become a traced process */
612 || (pid == 0 && !daemonized_tracer) /* not -D: child to become a traced process */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000613 ) {
614 pid = getpid();
Roland McGrath02203312007-06-11 22:06:31 +0000615#ifdef USE_PROCFS
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200616 if (outf != stderr) close(fileno(outf));
Roland McGrath02203312007-06-11 22:06:31 +0000617#ifdef MIPS
618 /* Kludge for SGI, see proc_open for details. */
619 sa.sa_handler = foobar;
620 sa.sa_flags = 0;
621 sigemptyset(&sa.sa_mask);
622 sigaction(SIGINT, &sa, NULL);
623#endif /* MIPS */
624#ifndef FREEBSD
625 pause();
626#else /* FREEBSD */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000627 kill(pid, SIGSTOP); /* stop HERE */
Roland McGrath02203312007-06-11 22:06:31 +0000628#endif /* FREEBSD */
629#else /* !USE_PROCFS */
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200630 if (outf != stderr)
631 close(fileno(outf));
Roland McGrath02203312007-06-11 22:06:31 +0000632
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000633 if (!daemonized_tracer) {
634 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200635 perror_msg_and_die("ptrace(PTRACE_TRACEME, ...)");
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000636 }
637 if (debug)
638 kill(pid, SIGSTOP);
Roland McGrath02203312007-06-11 22:06:31 +0000639 }
Roland McGrath02203312007-06-11 22:06:31 +0000640
641 if (username != NULL || geteuid() == 0) {
642 uid_t run_euid = run_uid;
643 gid_t run_egid = run_gid;
644
645 if (statbuf.st_mode & S_ISUID)
646 run_euid = statbuf.st_uid;
647 if (statbuf.st_mode & S_ISGID)
648 run_egid = statbuf.st_gid;
649
650 /*
651 * It is important to set groups before we
652 * lose privileges on setuid.
653 */
654 if (username != NULL) {
655 if (initgroups(username, run_gid) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200656 perror_msg_and_die("initgroups");
Roland McGrath02203312007-06-11 22:06:31 +0000657 }
658 if (setregid(run_gid, run_egid) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200659 perror_msg_and_die("setregid");
Roland McGrath02203312007-06-11 22:06:31 +0000660 }
661 if (setreuid(run_uid, run_euid) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200662 perror_msg_and_die("setreuid");
Roland McGrath02203312007-06-11 22:06:31 +0000663 }
664 }
665 }
666 else
667 setreuid(run_uid, run_uid);
668
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000669 if (!daemonized_tracer) {
670 /*
671 * Induce an immediate stop so that the parent
672 * will resume us with PTRACE_SYSCALL and display
673 * this execve call normally.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400674 * Unless of course we're on a no-MMU system where
675 * we vfork()-ed, so we cannot stop the child.
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000676 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400677 if (!strace_vforked)
678 kill(getpid(), SIGSTOP);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000679 } else {
680 struct sigaction sv_sigchld;
681 sigaction(SIGCHLD, NULL, &sv_sigchld);
682 /*
683 * Make sure it is not SIG_IGN, otherwise wait
684 * will not block.
685 */
686 signal(SIGCHLD, SIG_DFL);
687 /*
688 * Wait for grandchild to attach to us.
689 * It kills child after that, and wait() unblocks.
690 */
691 alarm(3);
692 wait(NULL);
693 alarm(0);
694 sigaction(SIGCHLD, &sv_sigchld, NULL);
695 }
Roland McGrath02203312007-06-11 22:06:31 +0000696#endif /* !USE_PROCFS */
697
698 execv(pathname, argv);
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200699 perror_msg_and_die("exec");
Roland McGrath02203312007-06-11 22:06:31 +0000700 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000701
702 /* We are the tracer. */
Denys Vlasenko75422762011-05-27 14:36:01 +0200703 /* With -D, we are *child* here, IOW: different pid. Fetch it. */
704 strace_tracer_pid = getpid();
705
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000706 tcp = alloctcb(daemonized_tracer ? getppid() : pid);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000707 if (daemonized_tracer) {
708 /* We want subsequent startup_attach() to attach to it. */
709 tcp->flags |= TCB_ATTACHED;
710 }
Roland McGrath02203312007-06-11 22:06:31 +0000711#ifdef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000712 if (proc_open(tcp, 0) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200713 perror_msg_and_die("trouble opening proc file");
Roland McGrath02203312007-06-11 22:06:31 +0000714 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000715#endif /* USE_PROCFS */
Roland McGrath02203312007-06-11 22:06:31 +0000716}
717
Wang Chaob13c0de2010-11-12 17:25:19 +0800718#ifdef LINUX
719/*
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000720 * Test whether the kernel support PTRACE_O_TRACECLONE et al options.
Wang Chaob13c0de2010-11-12 17:25:19 +0800721 * First fork a new child, call ptrace with PTRACE_SETOPTIONS on it,
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000722 * and then see which options are supported by the kernel.
Wang Chaob13c0de2010-11-12 17:25:19 +0800723 */
724static int
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200725test_ptrace_setoptions_followfork(void)
Wang Chaob13c0de2010-11-12 17:25:19 +0800726{
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000727 int pid, expected_grandchild = 0, found_grandchild = 0;
728 const unsigned int test_options = PTRACE_O_TRACECLONE |
729 PTRACE_O_TRACEFORK |
730 PTRACE_O_TRACEVFORK;
Wang Chaob13c0de2010-11-12 17:25:19 +0800731
732 if ((pid = fork()) < 0)
733 return -1;
734 else if (pid == 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000735 if (ptrace(PTRACE_TRACEME, 0, (char *)1, 0) < 0)
Wang Chaob13c0de2010-11-12 17:25:19 +0800736 _exit(1);
Wang Chaob13c0de2010-11-12 17:25:19 +0800737 kill(getpid(), SIGSTOP);
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000738 _exit(fork() < 0);
Wang Chaob13c0de2010-11-12 17:25:19 +0800739 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000740
741 while (1) {
742 int status, tracee_pid;
743
744 tracee_pid = wait(&status);
745 if (tracee_pid == -1) {
746 if (errno == EINTR)
747 continue;
748 else if (errno == ECHILD)
749 break;
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200750 perror("test_ptrace_setoptions_followfork");
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000751 return -1;
752 }
753 if (tracee_pid != pid) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000754 found_grandchild = tracee_pid;
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000755 if (ptrace(PTRACE_CONT, tracee_pid, 0, 0) < 0 &&
756 errno != ESRCH)
757 kill(tracee_pid, SIGKILL);
758 }
759 else if (WIFSTOPPED(status)) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000760 switch (WSTOPSIG(status)) {
761 case SIGSTOP:
762 if (ptrace(PTRACE_SETOPTIONS, pid,
763 NULL, test_options) < 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000764 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800765 return -1;
766 }
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000767 break;
768 case SIGTRAP:
769 if (status >> 16 == PTRACE_EVENT_FORK) {
770 long msg = 0;
771
772 if (ptrace(PTRACE_GETEVENTMSG, pid,
773 NULL, (long) &msg) == 0)
774 expected_grandchild = msg;
775 }
776 break;
Wang Chaob13c0de2010-11-12 17:25:19 +0800777 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000778 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0 &&
779 errno != ESRCH)
780 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800781 }
782 }
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000783 if (expected_grandchild && expected_grandchild == found_grandchild)
Denys Vlasenkof44cce42011-06-21 14:34:10 +0200784 ptrace_setoptions |= test_options;
Wang Chaob13c0de2010-11-12 17:25:19 +0800785 return 0;
786}
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200787
788/*
789 * Test whether the kernel support PTRACE_O_TRACESYSGOOD.
790 * First fork a new child, call ptrace(PTRACE_SETOPTIONS) on it,
791 * and then see whether it will stop with (SIGTRAP | 0x80).
792 *
793 * Use of this option enables correct handling of user-generated SIGTRAPs,
794 * and SIGTRAPs generated by special instructions such as int3 on x86:
795 * _start: .globl _start
796 * int3
797 * movl $42, %ebx
798 * movl $1, %eax
799 * int $0x80
800 * (compile with: "gcc -nostartfiles -nostdlib -o int3 int3.S")
801 */
802static void
803test_ptrace_setoptions_for_all(void)
804{
805 const unsigned int test_options = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC;
806 int pid;
807 int it_worked = 0;
808
809 pid = fork();
810 if (pid < 0)
Denys Vlasenko75422762011-05-27 14:36:01 +0200811 perror_msg_and_die("fork");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200812
813 if (pid == 0) {
814 pid = getpid();
815 if (ptrace(PTRACE_TRACEME, 0L, 0L, 0L) < 0)
Denys Vlasenko75422762011-05-27 14:36:01 +0200816 /* Note: exits with exitcode 1 */
817 perror_msg_and_die("%s: PTRACE_TRACEME doesn't work", __func__);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200818 kill(pid, SIGSTOP);
819 _exit(0); /* parent should see entry into this syscall */
820 }
821
822 while (1) {
823 int status, tracee_pid;
824
825 errno = 0;
826 tracee_pid = wait(&status);
827 if (tracee_pid <= 0) {
828 if (errno == EINTR)
829 continue;
830 kill(pid, SIGKILL);
Denys Vlasenko75422762011-05-27 14:36:01 +0200831 perror_msg_and_die("%s: unexpected wait result %d", __func__, tracee_pid);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200832 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200833 if (WIFEXITED(status)) {
834 if (WEXITSTATUS(status) == 0)
835 break;
836 /* PTRACE_TRACEME failed in child. This is fatal. */
837 exit(1);
838 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200839 if (!WIFSTOPPED(status)) {
840 kill(pid, SIGKILL);
841 error_msg_and_die("%s: unexpected wait status %x", __func__, status);
842 }
843 if (WSTOPSIG(status) == SIGSTOP) {
844 /*
845 * We don't check "options aren't accepted" error.
846 * If it happens, we'll never get (SIGTRAP | 0x80),
847 * and thus will decide to not use the option.
848 * IOW: the outcome of the test will be correct.
849 */
Denys Vlasenko75422762011-05-27 14:36:01 +0200850 if (ptrace(PTRACE_SETOPTIONS, pid, 0L, test_options) < 0)
851 if (errno != EINVAL)
852 perror_msg("PTRACE_SETOPTIONS");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200853 }
854 if (WSTOPSIG(status) == (SIGTRAP | 0x80)) {
855 it_worked = 1;
856 }
857 if (ptrace(PTRACE_SYSCALL, pid, 0L, 0L) < 0) {
858 kill(pid, SIGKILL);
Denys Vlasenko75422762011-05-27 14:36:01 +0200859 perror_msg_and_die("PTRACE_SYSCALL doesn't work");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200860 }
861 }
862
863 if (it_worked) {
Denys Vlasenko75422762011-05-27 14:36:01 +0200864 syscall_trap_sig = (SIGTRAP | 0x80);
Denys Vlasenkof44cce42011-06-21 14:34:10 +0200865 ptrace_setoptions |= test_options;
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200866 if (debug)
Denys Vlasenkof44cce42011-06-21 14:34:10 +0200867 fprintf(stderr, "ptrace_setoptions = %#x\n",
868 ptrace_setoptions);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200869 return;
870 }
871
872 fprintf(stderr,
873 "Test for PTRACE_O_TRACESYSGOOD failed, giving up using this feature.\n");
874}
Wang Chaob13c0de2010-11-12 17:25:19 +0800875#endif
876
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000877int
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000878main(int argc, char *argv[])
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000879{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000880 struct tcb *tcp;
881 int c, pid = 0;
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000882 int optF = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000883 struct sigaction sa;
884
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000885 progname = argv[0] ? argv[0] : "strace";
886
Denys Vlasenko75422762011-05-27 14:36:01 +0200887 strace_tracer_pid = getpid();
888
Roland McGrathee9d4352002-12-18 04:16:10 +0000889 /* Allocate the initial tcbtab. */
890 tcbtabsize = argc; /* Surely enough for all -p args. */
Denys Vlasenko4f12af22011-06-23 13:16:23 +0200891 tcbtab = calloc(tcbtabsize, sizeof(tcbtab[0]));
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200892 if (tcbtab == NULL)
893 error_msg_and_die("Out of memory");
Denys Vlasenko4f12af22011-06-23 13:16:23 +0200894 tcp = calloc(tcbtabsize, sizeof(*tcp));
895 if (tcp == NULL)
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200896 error_msg_and_die("Out of memory");
Denys Vlasenko4f12af22011-06-23 13:16:23 +0200897 for (c = 0; c < tcbtabsize; c++)
898 tcbtab[c] = tcp++;
Roland McGrathee9d4352002-12-18 04:16:10 +0000899
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000900 outf = stderr;
901 interactive = 1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000902 set_sortby(DEFAULT_SORTBY);
903 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000904 qualify("trace=all");
905 qualify("abbrev=all");
906 qualify("verbose=all");
907 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000908 while ((c = getopt(argc, argv,
Grant Edwards8a082772011-04-07 20:25:40 +0000909 "+cCdfFhiqrtTvVxyz"
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000910#ifndef USE_PROCFS
911 "D"
912#endif
Grant Edwards8a082772011-04-07 20:25:40 +0000913 "a:e:o:O:p:s:S:u:E:P:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000914 switch (c) {
915 case 'c':
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000916 if (cflag == CFLAG_BOTH) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200917 error_msg_and_die("-c and -C are mutually exclusive options");
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000918 }
919 cflag = CFLAG_ONLY_STATS;
920 break;
921 case 'C':
922 if (cflag == CFLAG_ONLY_STATS) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200923 error_msg_and_die("-c and -C are mutually exclusive options");
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000924 }
925 cflag = CFLAG_BOTH;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000926 break;
927 case 'd':
928 debug++;
929 break;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000930#ifndef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000931 case 'D':
932 daemonized_tracer = 1;
933 break;
934#endif
Roland McGrath41c48222008-07-18 00:25:10 +0000935 case 'F':
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000936 optF = 1;
937 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000938 case 'f':
939 followfork++;
940 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000941 case 'h':
942 usage(stdout, 0);
943 break;
944 case 'i':
945 iflag++;
946 break;
947 case 'q':
948 qflag++;
949 break;
950 case 'r':
951 rflag++;
952 tflag++;
953 break;
954 case 't':
955 tflag++;
956 break;
957 case 'T':
958 dtime++;
959 break;
960 case 'x':
961 xflag++;
962 break;
Grant Edwards8a082772011-04-07 20:25:40 +0000963 case 'y':
964 show_fd_path = 1;
965 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000966 case 'v':
967 qualify("abbrev=none");
968 break;
969 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +0000970 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000971 exit(0);
972 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000973 case 'z':
974 not_failing_only = 1;
975 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000976 case 'a':
977 acolumn = atoi(optarg);
978 break;
979 case 'e':
980 qualify(optarg);
981 break;
982 case 'o':
983 outfname = strdup(optarg);
984 break;
985 case 'O':
986 set_overhead(atoi(optarg));
987 break;
988 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +0000989 if ((pid = atoi(optarg)) <= 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200990 error_msg("Invalid process id: '%s'", optarg);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000991 break;
992 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200993 if (pid == strace_tracer_pid) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200994 error_msg("I'm sorry, I can't let you do that, Dave.");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000995 break;
996 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000997 tcp = alloc_tcb(pid, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000998 tcp->flags |= TCB_ATTACHED;
999 pflag_seen++;
1000 break;
Grant Edwards8a082772011-04-07 20:25:40 +00001001 case 'P':
1002 tracing_paths = 1;
1003 if (pathtrace_select(optarg)) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001004 error_msg_and_die("Failed to select path '%s'", optarg);
Grant Edwards8a082772011-04-07 20:25:40 +00001005 }
1006 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001007 case 's':
1008 max_strlen = atoi(optarg);
Roland McGrathdccec722005-05-09 07:45:47 +00001009 if (max_strlen < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001010 error_msg_and_die("Invalid -s argument: '%s'", optarg);
Roland McGrathdccec722005-05-09 07:45:47 +00001011 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001012 break;
1013 case 'S':
1014 set_sortby(optarg);
1015 break;
1016 case 'u':
1017 username = strdup(optarg);
1018 break;
Roland McGrathde6e5332003-01-24 04:31:23 +00001019 case 'E':
1020 if (putenv(optarg) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001021 error_msg_and_die("Out of memory");
Roland McGrathde6e5332003-01-24 04:31:23 +00001022 }
1023 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001024 default:
1025 usage(stderr, 1);
1026 break;
1027 }
1028 }
1029
Roland McGrathd0c4c0c2006-04-25 07:39:40 +00001030 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +00001031 usage(stderr, 1);
1032
Wang Chaod322a4b2010-08-05 14:30:11 +08001033 if (pflag_seen && daemonized_tracer) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001034 error_msg_and_die("-D and -p are mutually exclusive options");
Wang Chaod322a4b2010-08-05 14:30:11 +08001035 }
1036
Dmitry V. Levin06350db2008-07-25 15:42:34 +00001037 if (!followfork)
1038 followfork = optF;
1039
Roland McGrathcb9def62006-04-25 07:48:03 +00001040 if (followfork > 1 && cflag) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001041 error_msg_and_die("(-c or -C) and -ff are mutually exclusive options");
Roland McGrathcb9def62006-04-25 07:48:03 +00001042 }
1043
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001044 /* See if they want to run as another user. */
1045 if (username != NULL) {
1046 struct passwd *pent;
1047
1048 if (getuid() != 0 || geteuid() != 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001049 error_msg_and_die("You must be root to use the -u option");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001050 }
1051 if ((pent = getpwnam(username)) == NULL) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001052 error_msg_and_die("Cannot find user '%s'", username);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001053 }
1054 run_uid = pent->pw_uid;
1055 run_gid = pent->pw_gid;
1056 }
1057 else {
1058 run_uid = getuid();
1059 run_gid = getgid();
1060 }
1061
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001062#ifdef LINUX
1063 if (followfork) {
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02001064 if (test_ptrace_setoptions_followfork() < 0) {
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001065 fprintf(stderr,
1066 "Test for options supported by PTRACE_SETOPTIONS "
1067 "failed, giving up using this feature.\n");
Denys Vlasenkof44cce42011-06-21 14:34:10 +02001068 ptrace_setoptions = 0;
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001069 }
1070 if (debug)
Denys Vlasenkof44cce42011-06-21 14:34:10 +02001071 fprintf(stderr, "ptrace_setoptions = %#x\n",
1072 ptrace_setoptions);
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001073 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02001074 test_ptrace_setoptions_for_all();
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001075#endif
1076
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001077 /* Check if they want to redirect the output. */
1078 if (outfname) {
Roland McGrath37b9a662003-11-07 02:26:54 +00001079 /* See if they want to pipe the output. */
1080 if (outfname[0] == '|' || outfname[0] == '!') {
1081 /*
1082 * We can't do the <outfname>.PID funny business
1083 * when using popen, so prohibit it.
1084 */
Denys Vlasenko7dd23382011-06-22 13:03:56 +02001085 if (followfork > 1)
1086 error_msg_and_die("Piping the output and -ff are mutually exclusive");
1087 outf = strace_popen(outfname + 1);
Roland McGrath37b9a662003-11-07 02:26:54 +00001088 }
Denys Vlasenko3d5ed412011-06-22 13:17:16 +02001089 else if (followfork <= 1)
1090 outf = strace_fopen(outfname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001091 }
1092
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001093 if (!outfname || outfname[0] == '|' || outfname[0] == '!') {
1094 static char buf[BUFSIZ];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001095 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001096 }
Roland McGrath37b9a662003-11-07 02:26:54 +00001097 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001098 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001099 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +00001100 }
Wang Chaob13c0de2010-11-12 17:25:19 +08001101
Roland McGrath54cc1c82007-11-03 23:34:11 +00001102 /* Valid states here:
1103 optind < argc pflag_seen outfname interactive
1104 1 0 0 1
1105 0 1 0 1
1106 1 0 1 0
1107 0 1 1 1
1108 */
1109
1110 /* STARTUP_CHILD must be called before the signal handlers get
1111 installed below as they are inherited into the spawned process.
1112 Also we do not need to be protected by them as during interruption
1113 in the STARTUP_CHILD mode we kill the spawned process anyway. */
1114 if (!pflag_seen)
1115 startup_child(&argv[optind]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001116
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001117 sigemptyset(&empty_set);
1118 sigemptyset(&blocked_set);
1119 sa.sa_handler = SIG_IGN;
1120 sigemptyset(&sa.sa_mask);
1121 sa.sa_flags = 0;
1122 sigaction(SIGTTOU, &sa, NULL);
1123 sigaction(SIGTTIN, &sa, NULL);
1124 if (interactive) {
1125 sigaddset(&blocked_set, SIGHUP);
1126 sigaddset(&blocked_set, SIGINT);
1127 sigaddset(&blocked_set, SIGQUIT);
1128 sigaddset(&blocked_set, SIGPIPE);
1129 sigaddset(&blocked_set, SIGTERM);
1130 sa.sa_handler = interrupt;
1131#ifdef SUNOS4
1132 /* POSIX signals on sunos4.1 are a little broken. */
1133 sa.sa_flags = SA_INTERRUPT;
1134#endif /* SUNOS4 */
1135 }
1136 sigaction(SIGHUP, &sa, NULL);
1137 sigaction(SIGINT, &sa, NULL);
1138 sigaction(SIGQUIT, &sa, NULL);
1139 sigaction(SIGPIPE, &sa, NULL);
1140 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001141#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001142 sa.sa_handler = reaper;
1143 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +00001144#else
1145 /* Make sure SIGCHLD has the default action so that waitpid
1146 definitely works without losing track of children. The user
1147 should not have given us a bogus state to inherit, but he might
1148 have. Arguably we should detect SIG_IGN here and pass it on
1149 to children, but probably noone really needs that. */
1150 sa.sa_handler = SIG_DFL;
1151 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001152#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001153
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +00001154 if (pflag_seen || daemonized_tracer)
Roland McGrath02203312007-06-11 22:06:31 +00001155 startup_attach();
Roland McGrath02203312007-06-11 22:06:31 +00001156
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001157 if (trace() < 0)
1158 exit(1);
1159 cleanup();
Dmitry V. Levina6809652008-11-10 17:14:58 +00001160 fflush(NULL);
1161 if (exit_code > 0xff) {
1162 /* Child was killed by a signal, mimic that. */
1163 exit_code &= 0xff;
1164 signal(exit_code, SIG_DFL);
1165 raise(exit_code);
1166 /* Paranoia - what if this signal is not fatal?
1167 Exit with 128 + signo then. */
1168 exit_code += 128;
1169 }
1170 exit(exit_code);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001171}
1172
Denys Vlasenko2b60c352011-06-22 12:45:25 +02001173static void
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001174expand_tcbtab(void)
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001175{
1176 /* Allocate some more TCBs and expand the table.
1177 We don't want to relocate the TCBs because our
1178 callers have pointers and it would be a pain.
1179 So tcbtab is a table of pointers. Since we never
1180 free the TCBs, we allocate a single chunk of many. */
Denys Vlasenko18da2732011-06-22 12:41:57 +02001181 int i = tcbtabsize;
1182 struct tcb *newtcbs = calloc(tcbtabsize, sizeof(newtcbs[0]));
1183 struct tcb **newtab = realloc(tcbtab, tcbtabsize * 2 * sizeof(tcbtab[0]));
1184 if (newtab == NULL || newtcbs == NULL)
1185 error_msg_and_die("expand_tcbtab: out of memory");
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001186 tcbtabsize *= 2;
1187 tcbtab = newtab;
Denys Vlasenko18da2732011-06-22 12:41:57 +02001188 while (i < tcbtabsize)
1189 tcbtab[i++] = newtcbs++;
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001190}
1191
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001192struct tcb *
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001193alloc_tcb(int pid, int command_options_parsed)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001194{
1195 int i;
1196 struct tcb *tcp;
1197
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001198 if (nprocs == tcbtabsize)
1199 expand_tcbtab();
1200
Roland McGrathee9d4352002-12-18 04:16:10 +00001201 for (i = 0; i < tcbtabsize; i++) {
1202 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001203 if ((tcp->flags & TCB_INUSE) == 0) {
Denys Vlasenko18da2732011-06-22 12:41:57 +02001204 memset(tcp, 0, sizeof(*tcp));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001205 tcp->pid = pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001206 tcp->flags = TCB_INUSE | TCB_STARTUP;
1207 tcp->outf = outf; /* Initialise to current out file */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001208 tcp->pfd = -1;
1209 nprocs++;
Denys Vlasenko1d5f12e2011-06-24 16:41:35 +02001210 if (debug)
1211 fprintf(stderr, "new tcb for pid %d, active tcbs:%d\n", tcp->pid, nprocs);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001212 if (command_options_parsed)
1213 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001214 return tcp;
1215 }
1216 }
Denys Vlasenko18da2732011-06-22 12:41:57 +02001217 error_msg_and_die("bug in alloc_tcb");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001218}
1219
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001220#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001221int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001222proc_open(struct tcb *tcp, int attaching)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001223{
1224 char proc[32];
1225 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001226#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +00001227 int i;
1228 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001229 sigset_t signals;
1230 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001231#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001232#ifndef HAVE_POLLABLE_PROCFS
1233 static int last_pfd;
1234#endif
1235
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001236#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001237 /* Open the process pseudo-files in /proc. */
1238 sprintf(proc, "/proc/%d/ctl", tcp->pid);
1239 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001240 perror("strace: open(\"/proc/...\", ...)");
1241 return -1;
1242 }
Denys Vlasenko1f532ab2011-06-22 13:11:23 +02001243 set_cloexec_flag(tcp->pfd);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001244 sprintf(proc, "/proc/%d/status", tcp->pid);
1245 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
1246 perror("strace: open(\"/proc/...\", ...)");
1247 return -1;
1248 }
Denys Vlasenko1f532ab2011-06-22 13:11:23 +02001249 set_cloexec_flag(tcp->pfd_stat);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001250 sprintf(proc, "/proc/%d/as", tcp->pid);
1251 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
1252 perror("strace: open(\"/proc/...\", ...)");
1253 return -1;
1254 }
Denys Vlasenko1f532ab2011-06-22 13:11:23 +02001255 set_cloexec_flag(tcp->pfd_as);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001256#else
1257 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001258#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001259 sprintf(proc, "/proc/%d", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001260 tcp->pfd = open(proc, O_RDWR|O_EXCL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001261#else /* FREEBSD */
1262 sprintf(proc, "/proc/%d/mem", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001263 tcp->pfd = open(proc, O_RDWR);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001264#endif /* FREEBSD */
Andreas Schwab372cc842010-07-09 11:49:27 +02001265 if (tcp->pfd < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001266 perror("strace: open(\"/proc/...\", ...)");
1267 return -1;
1268 }
Denys Vlasenko1f532ab2011-06-22 13:11:23 +02001269 set_cloexec_flag(tcp->pfd);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001270#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001271#ifdef FREEBSD
1272 sprintf(proc, "/proc/%d/regs", tcp->pid);
1273 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
1274 perror("strace: open(\"/proc/.../regs\", ...)");
1275 return -1;
1276 }
1277 if (cflag) {
1278 sprintf(proc, "/proc/%d/status", tcp->pid);
1279 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
1280 perror("strace: open(\"/proc/.../status\", ...)");
1281 return -1;
1282 }
1283 } else
1284 tcp->pfd_status = -1;
1285#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001286 rebuild_pollv();
1287 if (!attaching) {
1288 /*
1289 * Wait for the child to pause. Because of a race
1290 * condition we have to poll for the event.
1291 */
1292 for (;;) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001293 if (IOCTL_STATUS(tcp) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001294 perror("strace: PIOCSTATUS");
1295 return -1;
1296 }
1297 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001298 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001299 }
1300 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001301#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001302 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001303 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001304 perror("strace: PIOCSTOP");
1305 return -1;
1306 }
Roland McGrath553a6092002-12-16 20:40:39 +00001307#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001308#ifdef PIOCSET
1309 /* Set Run-on-Last-Close. */
1310 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001311 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001312 perror("PIOCSET PR_RLC");
1313 return -1;
1314 }
1315 /* Set or Reset Inherit-on-Fork. */
1316 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001317 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001318 perror("PIOC{SET,RESET} PR_FORK");
1319 return -1;
1320 }
1321#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +00001322#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001323 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
1324 perror("PIOCSRLC");
1325 return -1;
1326 }
1327 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
1328 perror("PIOC{S,R}FORK");
1329 return -1;
1330 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001331#else /* FREEBSD */
1332 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
1333 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
1334 perror("PIOCGFL");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001335 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001336 }
1337 arg &= ~PF_LINGER;
1338 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001339 perror("PIOCSFL");
1340 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001341 }
1342#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001343#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001344#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +00001345 /* Enable all syscall entries we care about. */
1346 premptyset(&syscalls);
1347 for (i = 1; i < MAX_QUALS; ++i) {
1348 if (i > (sizeof syscalls) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001349 if (qual_flags[i] & QUAL_TRACE) praddset(&syscalls, i);
John Hughes19e49982001-10-19 08:59:12 +00001350 }
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001351 praddset(&syscalls, SYS_execve);
John Hughes19e49982001-10-19 08:59:12 +00001352 if (followfork) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001353 praddset(&syscalls, SYS_fork);
John Hughes19e49982001-10-19 08:59:12 +00001354#ifdef SYS_forkall
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001355 praddset(&syscalls, SYS_forkall);
John Hughes19e49982001-10-19 08:59:12 +00001356#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001357#ifdef SYS_fork1
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001358 praddset(&syscalls, SYS_fork1);
John Hughes19e49982001-10-19 08:59:12 +00001359#endif
1360#ifdef SYS_rfork1
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001361 praddset(&syscalls, SYS_rfork1);
John Hughes19e49982001-10-19 08:59:12 +00001362#endif
1363#ifdef SYS_rforkall
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001364 praddset(&syscalls, SYS_rforkall);
John Hughes19e49982001-10-19 08:59:12 +00001365#endif
1366 }
1367 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001368 perror("PIOCSENTRY");
1369 return -1;
1370 }
John Hughes19e49982001-10-19 08:59:12 +00001371 /* Enable the syscall exits. */
1372 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001373 perror("PIOSEXIT");
1374 return -1;
1375 }
John Hughes19e49982001-10-19 08:59:12 +00001376 /* Enable signals we care about. */
1377 premptyset(&signals);
1378 for (i = 1; i < MAX_QUALS; ++i) {
1379 if (i > (sizeof signals) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001380 if (qual_flags[i] & QUAL_SIGNAL) praddset(&signals, i);
John Hughes19e49982001-10-19 08:59:12 +00001381 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001382 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001383 perror("PIOCSTRACE");
1384 return -1;
1385 }
John Hughes19e49982001-10-19 08:59:12 +00001386 /* Enable faults we care about */
1387 premptyset(&faults);
1388 for (i = 1; i < MAX_QUALS; ++i) {
1389 if (i > (sizeof faults) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001390 if (qual_flags[i] & QUAL_FAULT) praddset(&faults, i);
John Hughes19e49982001-10-19 08:59:12 +00001391 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001392 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001393 perror("PIOCSFAULT");
1394 return -1;
1395 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001396#else /* FREEBSD */
1397 /* set events flags. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001398 arg = S_SIG | S_SCE | S_SCX;
1399 if (ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001400 perror("PIOCBIS");
1401 return -1;
1402 }
1403#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001404 if (!attaching) {
1405#ifdef MIPS
1406 /*
1407 * The SGI PRSABORT doesn't work for pause() so
1408 * we send it a caught signal to wake it up.
1409 */
1410 kill(tcp->pid, SIGINT);
1411#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +00001412#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001413 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001414 arg = PRSABORT;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001415 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001416 perror("PIOCRUN");
1417 return -1;
1418 }
Roland McGrath553a6092002-12-16 20:40:39 +00001419#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001420#endif /* !MIPS*/
1421#ifdef FREEBSD
1422 /* wake up the child if it received the SIGSTOP */
1423 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001424#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001425 for (;;) {
1426 /* Wait for the child to do something. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001427 if (IOCTL_WSTOP(tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001428 perror("PIOCWSTOP");
1429 return -1;
1430 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001431 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001432 tcp->flags &= ~TCB_INSYSCALL;
1433 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001434 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001435 break;
1436 }
1437 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001438#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001439 arg = 0;
1440 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001441#else /* FREEBSD */
1442 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001443#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001444 perror("PIOCRUN");
1445 return -1;
1446 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001447#ifdef FREEBSD
1448 /* handle the case where we "opened" the child before
1449 it did the kill -STOP */
1450 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1451 tcp->status.PR_WHAT == SIGSTOP)
1452 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001453#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001454 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001455#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001456 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001457#else /* FREEBSD */
1458 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001459 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001460 /* We are attaching to an already running process.
1461 * Try to figure out the state of the process in syscalls,
1462 * to handle the first event well.
1463 * This is done by having a look at the "wchan" property of the
1464 * process, which tells where it is stopped (if it is). */
1465 FILE * status;
1466 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001467
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001468 sprintf(proc, "/proc/%d/status", tcp->pid);
1469 status = fopen(proc, "r");
1470 if (status &&
1471 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1472 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1473 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1474 strcmp(wchan, "stopevent")) {
1475 /* The process is asleep in the middle of a syscall.
1476 Fake the syscall entry event */
1477 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1478 tcp->status.PR_WHY = PR_SYSENTRY;
1479 trace_syscall(tcp);
1480 }
1481 if (status)
1482 fclose(status);
1483 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001484 }
1485#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001486#ifndef HAVE_POLLABLE_PROCFS
1487 if (proc_poll_pipe[0] != -1)
1488 proc_poller(tcp->pfd);
1489 else if (nprocs > 1) {
1490 proc_poll_open();
1491 proc_poller(last_pfd);
1492 proc_poller(tcp->pfd);
1493 }
1494 last_pfd = tcp->pfd;
1495#endif /* !HAVE_POLLABLE_PROCFS */
1496 return 0;
1497}
1498
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001499#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001500
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001501struct tcb *
Roland McGrath54e931f2010-09-14 18:59:20 -07001502pid2tcb(int pid)
1503{
1504 int i;
1505
1506 if (pid <= 0)
1507 return NULL;
1508
1509 for (i = 0; i < tcbtabsize; i++) {
1510 struct tcb *tcp = tcbtab[i];
1511 if (tcp->pid == pid && (tcp->flags & TCB_INUSE))
1512 return tcp;
1513 }
1514
1515 return NULL;
1516}
1517
1518#ifdef USE_PROCFS
1519
1520static struct tcb *
1521first_used_tcb(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001522{
1523 int i;
1524 struct tcb *tcp;
Roland McGrathee9d4352002-12-18 04:16:10 +00001525 for (i = 0; i < tcbtabsize; i++) {
1526 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001527 if (tcp->flags & TCB_INUSE)
1528 return tcp;
1529 }
1530 return NULL;
1531}
1532
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001533static struct tcb *
Denys Vlasenko12014262011-05-30 14:00:14 +02001534pfd2tcb(int pfd)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001535{
1536 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001537
Roland McGrathca16be82003-01-10 19:55:28 +00001538 for (i = 0; i < tcbtabsize; i++) {
1539 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001540 if (tcp->pfd != pfd)
1541 continue;
1542 if (tcp->flags & TCB_INUSE)
1543 return tcp;
1544 }
1545 return NULL;
1546}
1547
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001548#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001549
1550void
Denys Vlasenko12014262011-05-30 14:00:14 +02001551droptcb(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001552{
1553 if (tcp->pid == 0)
1554 return;
Denys Vlasenko19cdada2011-08-17 10:45:32 +02001555
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001556 nprocs--;
Denys Vlasenko1d5f12e2011-06-24 16:41:35 +02001557 if (debug)
1558 fprintf(stderr, "dropped tcb for pid %d, %d remain\n", tcp->pid, nprocs);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001559
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001560 if (tcp->pfd != -1) {
1561 close(tcp->pfd);
1562 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001563#ifdef FREEBSD
1564 if (tcp->pfd_reg != -1) {
1565 close(tcp->pfd_reg);
1566 tcp->pfd_reg = -1;
1567 }
1568 if (tcp->pfd_status != -1) {
1569 close(tcp->pfd_status);
1570 tcp->pfd_status = -1;
1571 }
Roland McGrath553a6092002-12-16 20:40:39 +00001572#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001573#ifdef USE_PROCFS
Denys Vlasenko19cdada2011-08-17 10:45:32 +02001574 tcp->flags = 0; /* rebuild_pollv needs it */
1575 rebuild_pollv();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001576#endif
1577 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001578
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001579 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001580 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001581
Denys Vlasenko19cdada2011-08-17 10:45:32 +02001582 memset(tcp, 0, sizeof(*tcp));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001583}
1584
Roland McGrath0a463882007-07-05 18:43:16 +00001585/* detach traced process; continue with sig
1586 Never call DETACH twice on the same process as both unattached and
1587 attached-unstopped processes give the same ESRCH. For unattached process we
1588 would SIGSTOP it and wait for its SIGSTOP notification forever. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001589
1590static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001591detach(struct tcb *tcp, int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001592{
1593 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001594#ifdef LINUX
Roland McGrath1bfd3102007-08-03 10:02:00 +00001595 int status, catch_sigstop;
Roland McGrathca16be82003-01-10 19:55:28 +00001596#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001597
1598 if (tcp->flags & TCB_BPTSET)
Andreas Schwab840d85b2010-01-12 11:16:32 +01001599 clearbpt(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001600
1601#ifdef LINUX
1602 /*
1603 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001604 * before detaching. Arghh. We go through hoops
1605 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001606 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001607#if defined(SPARC)
1608#undef PTRACE_DETACH
1609#define PTRACE_DETACH PTRACE_SUNDETACH
1610#endif
Roland McGrath02203312007-06-11 22:06:31 +00001611 /*
1612 * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
1613 * expected SIGSTOP. We must catch exactly one as otherwise the
1614 * detached process would be left stopped (process state T).
1615 */
1616 catch_sigstop = (tcp->flags & TCB_STARTUP);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001617 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1618 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001619 }
1620 else if (errno != ESRCH) {
1621 /* Shouldn't happen. */
1622 perror("detach: ptrace(PTRACE_DETACH, ...)");
1623 }
Roland McGrath134813a2007-06-02 00:07:33 +00001624 else if (my_tgkill((tcp->flags & TCB_CLONE_THREAD ? tcp->parent->pid
1625 : tcp->pid),
1626 tcp->pid, 0) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001627 if (errno != ESRCH)
1628 perror("detach: checking sanity");
1629 }
Roland McGrath02203312007-06-11 22:06:31 +00001630 else if (!catch_sigstop && my_tgkill((tcp->flags & TCB_CLONE_THREAD
1631 ? tcp->parent->pid : tcp->pid),
1632 tcp->pid, SIGSTOP) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001633 if (errno != ESRCH)
1634 perror("detach: stopping child");
1635 }
Roland McGrath02203312007-06-11 22:06:31 +00001636 else
1637 catch_sigstop = 1;
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001638 if (catch_sigstop) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001639 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001640#ifdef __WALL
1641 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1642 if (errno == ECHILD) /* Already gone. */
1643 break;
1644 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001645 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001646 break;
1647 }
1648#endif /* __WALL */
1649 /* No __WALL here. */
1650 if (waitpid(tcp->pid, &status, 0) < 0) {
1651 if (errno != ECHILD) {
1652 perror("detach: waiting");
1653 break;
1654 }
1655#ifdef __WCLONE
1656 /* If no processes, try clones. */
1657 if (wait4(tcp->pid, &status, __WCLONE,
1658 NULL) < 0) {
1659 if (errno != ECHILD)
1660 perror("detach: waiting");
1661 break;
1662 }
1663#endif /* __WCLONE */
1664 }
1665#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001666 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001667#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001668 if (!WIFSTOPPED(status)) {
1669 /* Au revoir, mon ami. */
1670 break;
1671 }
1672 if (WSTOPSIG(status) == SIGSTOP) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001673 ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001674 break;
1675 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001676 error = ptrace_restart(PTRACE_CONT, tcp,
Denys Vlasenko75422762011-05-27 14:36:01 +02001677 WSTOPSIG(status) == syscall_trap_sig ? 0
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001678 : WSTOPSIG(status));
1679 if (error < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001680 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001681 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001682 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001683#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001684
1685#if defined(SUNOS4)
1686 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1687 if (sig && kill(tcp->pid, sig) < 0)
1688 perror("detach: kill");
1689 sig = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001690 error = ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001691#endif /* SUNOS4 */
1692
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001693 if (!qflag)
1694 fprintf(stderr, "Process %u detached\n", tcp->pid);
1695
1696 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001697
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001698 return error;
1699}
1700
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001701#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001702
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001703static void reaper(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001704{
1705 int pid;
1706 int status;
1707
1708 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001709 }
1710}
1711
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001712#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001713
1714static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001715cleanup(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001716{
1717 int i;
1718 struct tcb *tcp;
1719
Roland McGrathee9d4352002-12-18 04:16:10 +00001720 for (i = 0; i < tcbtabsize; i++) {
1721 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001722 if (!(tcp->flags & TCB_INUSE))
1723 continue;
1724 if (debug)
1725 fprintf(stderr,
1726 "cleanup: looking at pid %u\n", tcp->pid);
1727 if (tcp_last &&
1728 (!outfname || followfork < 2 || tcp_last == tcp)) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001729 tprintf(" <unfinished ...>");
1730 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001731 }
1732 if (tcp->flags & TCB_ATTACHED)
1733 detach(tcp, 0);
1734 else {
1735 kill(tcp->pid, SIGCONT);
1736 kill(tcp->pid, SIGTERM);
1737 }
1738 }
1739 if (cflag)
1740 call_summary(outf);
1741}
1742
1743static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001744interrupt(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001745{
1746 interrupted = 1;
1747}
1748
1749#ifndef HAVE_STRERROR
1750
Roland McGrath6d2b3492002-12-30 00:51:30 +00001751#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001752extern int sys_nerr;
1753extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001754#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001755
1756const char *
Denys Vlasenko12014262011-05-30 14:00:14 +02001757strerror(int err_no)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001758{
1759 static char buf[64];
1760
Denys Vlasenko35aba6a2011-05-25 15:33:26 +02001761 if (err_no < 1 || err_no >= sys_nerr) {
1762 sprintf(buf, "Unknown error %d", err_no);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001763 return buf;
1764 }
Denys Vlasenko35aba6a2011-05-25 15:33:26 +02001765 return sys_errlist[err_no];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001766}
1767
1768#endif /* HAVE_STERRROR */
1769
1770#ifndef HAVE_STRSIGNAL
1771
Roland McGrath8f474e02003-01-14 07:53:33 +00001772#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001773extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001774#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001775#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1776extern char *_sys_siglist[];
1777#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001778
1779const char *
Denys Vlasenko12014262011-05-30 14:00:14 +02001780strsignal(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001781{
1782 static char buf[64];
1783
1784 if (sig < 1 || sig >= NSIG) {
1785 sprintf(buf, "Unknown signal %d", sig);
1786 return buf;
1787 }
1788#ifdef HAVE__SYS_SIGLIST
1789 return _sys_siglist[sig];
1790#else
1791 return sys_siglist[sig];
1792#endif
1793}
1794
1795#endif /* HAVE_STRSIGNAL */
1796
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001797#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001798
1799static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001800rebuild_pollv(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001801{
1802 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001803
Roland McGrathee9d4352002-12-18 04:16:10 +00001804 if (pollv != NULL)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001805 free(pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001806 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001807 if (pollv == NULL) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001808 error_msg_and_die("Out of memory");
Roland McGrathee9d4352002-12-18 04:16:10 +00001809 }
1810
Roland McGrathca16be82003-01-10 19:55:28 +00001811 for (i = j = 0; i < tcbtabsize; i++) {
1812 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001813 if (!(tcp->flags & TCB_INUSE))
1814 continue;
1815 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001816 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001817 j++;
1818 }
1819 if (j != nprocs) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001820 error_msg_and_die("proc miscount");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001821 }
1822}
1823
1824#ifndef HAVE_POLLABLE_PROCFS
1825
1826static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001827proc_poll_open(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001828{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001829 int i;
1830
1831 if (pipe(proc_poll_pipe) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001832 perror_msg_and_die("pipe");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001833 }
1834 for (i = 0; i < 2; i++) {
Denys Vlasenko1f532ab2011-06-22 13:11:23 +02001835 set_cloexec_flag(proc_poll_pipe[i]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001836 }
1837}
1838
1839static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001840proc_poll(struct pollfd *pollv, int nfds, int timeout)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001841{
1842 int i;
1843 int n;
1844 struct proc_pollfd pollinfo;
1845
1846 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1847 return n;
1848 if (n != sizeof(struct proc_pollfd)) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001849 error_msg_and_die("panic: short read: %d", n);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001850 }
1851 for (i = 0; i < nprocs; i++) {
1852 if (pollv[i].fd == pollinfo.fd)
1853 pollv[i].revents = pollinfo.revents;
1854 else
1855 pollv[i].revents = 0;
1856 }
1857 poller_pid = pollinfo.pid;
1858 return 1;
1859}
1860
1861static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001862wakeup_handler(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001863{
1864}
1865
1866static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001867proc_poller(int pfd)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001868{
1869 struct proc_pollfd pollinfo;
1870 struct sigaction sa;
1871 sigset_t blocked_set, empty_set;
1872 int i;
1873 int n;
1874 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001875#ifdef FREEBSD
1876 struct procfs_status pfs;
1877#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001878
1879 switch (fork()) {
1880 case -1:
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001881 perror_msg_and_die("fork");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001882 case 0:
1883 break;
1884 default:
1885 return;
1886 }
1887
1888 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1889 sa.sa_flags = 0;
1890 sigemptyset(&sa.sa_mask);
1891 sigaction(SIGHUP, &sa, NULL);
1892 sigaction(SIGINT, &sa, NULL);
1893 sigaction(SIGQUIT, &sa, NULL);
1894 sigaction(SIGPIPE, &sa, NULL);
1895 sigaction(SIGTERM, &sa, NULL);
1896 sa.sa_handler = wakeup_handler;
1897 sigaction(SIGUSR1, &sa, NULL);
1898 sigemptyset(&blocked_set);
1899 sigaddset(&blocked_set, SIGUSR1);
1900 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1901 sigemptyset(&empty_set);
1902
1903 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001904 perror_msg_and_die("getrlimit(RLIMIT_NOFILE, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001905 }
1906 n = rl.rlim_cur;
1907 for (i = 0; i < n; i++) {
1908 if (i != pfd && i != proc_poll_pipe[1])
1909 close(i);
1910 }
1911
1912 pollinfo.fd = pfd;
1913 pollinfo.pid = getpid();
1914 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001915#ifndef FREEBSD
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001916 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1917#else
1918 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1919#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001920 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001921 switch (errno) {
1922 case EINTR:
1923 continue;
1924 case EBADF:
1925 pollinfo.revents = POLLERR;
1926 break;
1927 case ENOENT:
1928 pollinfo.revents = POLLHUP;
1929 break;
1930 default:
1931 perror("proc_poller: PIOCWSTOP");
1932 }
1933 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1934 _exit(0);
1935 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001936 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001937 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1938 sigsuspend(&empty_set);
1939 }
1940}
1941
1942#endif /* !HAVE_POLLABLE_PROCFS */
1943
1944static int
1945choose_pfd()
1946{
1947 int i, j;
1948 struct tcb *tcp;
1949
1950 static int last;
1951
1952 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001953 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001954 /*
1955 * The previous process is ready to run again. We'll
1956 * let it do so if it is currently in a syscall. This
1957 * heuristic improves the readability of the trace.
1958 */
1959 tcp = pfd2tcb(pollv[last].fd);
1960 if (tcp && (tcp->flags & TCB_INSYSCALL))
1961 return pollv[last].fd;
1962 }
1963
1964 for (i = 0; i < nprocs; i++) {
1965 /* Let competing children run round robin. */
1966 j = (i + last + 1) % nprocs;
1967 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1968 tcp = pfd2tcb(pollv[j].fd);
1969 if (!tcp) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001970 error_msg_and_die("lost proc");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001971 }
1972 droptcb(tcp);
1973 return -1;
1974 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001975 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001976 last = j;
1977 return pollv[j].fd;
1978 }
1979 }
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001980 error_msg_and_die("nothing ready");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001981}
1982
1983static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001984trace(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001985{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001986#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001987 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001988#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001989 struct tcb *tcp;
1990 int pfd;
1991 int what;
1992 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001993 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001994
1995 for (;;) {
1996 if (interactive)
1997 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1998
1999 if (nprocs == 0)
2000 break;
2001
2002 switch (nprocs) {
2003 case 1:
2004#ifndef HAVE_POLLABLE_PROCFS
2005 if (proc_poll_pipe[0] == -1) {
2006#endif
Roland McGrath54e931f2010-09-14 18:59:20 -07002007 tcp = first_used_tcb();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002008 if (!tcp)
2009 continue;
2010 pfd = tcp->pfd;
2011 if (pfd == -1)
2012 continue;
2013 break;
2014#ifndef HAVE_POLLABLE_PROCFS
2015 }
2016 /* fall through ... */
2017#endif /* !HAVE_POLLABLE_PROCFS */
2018 default:
2019#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002020#ifdef POLL_HACK
2021 /* On some systems (e.g. UnixWare) we get too much ugly
2022 "unfinished..." stuff when multiple proceses are in
2023 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00002024
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002025 if (in_syscall) {
2026 struct pollfd pv;
2027 tcp = in_syscall;
2028 in_syscall = NULL;
2029 pv.fd = tcp->pfd;
2030 pv.events = POLLWANT;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002031 if ((what = poll(&pv, 1, 1)) < 0) {
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002032 if (interrupted)
2033 return 0;
2034 continue;
2035 }
2036 else if (what == 1 && pv.revents & POLLWANT) {
2037 goto FOUND;
2038 }
2039 }
2040#endif
2041
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002042 if (poll(pollv, nprocs, INFTIM) < 0) {
2043 if (interrupted)
2044 return 0;
2045 continue;
2046 }
2047#else /* !HAVE_POLLABLE_PROCFS */
2048 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
2049 if (interrupted)
2050 return 0;
2051 continue;
2052 }
2053#endif /* !HAVE_POLLABLE_PROCFS */
2054 pfd = choose_pfd();
2055 if (pfd == -1)
2056 continue;
2057 break;
2058 }
2059
2060 /* Look up `pfd' in our table. */
2061 if ((tcp = pfd2tcb(pfd)) == NULL) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002062 error_msg_and_die("unknown pfd: %u", pfd);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002063 }
John Hughesb6643082002-05-23 11:02:22 +00002064#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002065 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00002066#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002067 /* Get the status of the process. */
2068 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002069#ifndef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002070 ioctl_result = IOCTL_WSTOP(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002071#else /* FREEBSD */
2072 /* Thanks to some scheduling mystery, the first poller
2073 sometimes waits for the already processed end of fork
2074 event. Doing a non blocking poll here solves the problem. */
2075 if (proc_poll_pipe[0] != -1)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002076 ioctl_result = IOCTL_STATUS(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002077 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002078 ioctl_result = IOCTL_WSTOP(tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00002079#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002080 ioctl_errno = errno;
2081#ifndef HAVE_POLLABLE_PROCFS
2082 if (proc_poll_pipe[0] != -1) {
2083 if (ioctl_result < 0)
2084 kill(poller_pid, SIGKILL);
2085 else
2086 kill(poller_pid, SIGUSR1);
2087 }
2088#endif /* !HAVE_POLLABLE_PROCFS */
2089 }
2090 if (interrupted)
2091 return 0;
2092
2093 if (interactive)
2094 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2095
2096 if (ioctl_result < 0) {
2097 /* Find out what happened if it failed. */
2098 switch (ioctl_errno) {
2099 case EINTR:
2100 case EBADF:
2101 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002102#ifdef FREEBSD
2103 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00002104#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002105 case ENOENT:
2106 droptcb(tcp);
2107 continue;
2108 default:
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002109 perror_msg_and_die("PIOCWSTOP");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002110 }
2111 }
2112
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002113#ifdef FREEBSD
2114 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2115 /* discard first event for a syscall we never entered */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002116 IOCTL(tcp->pfd, PIOCRUN, 0);
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002117 continue;
2118 }
Roland McGrath553a6092002-12-16 20:40:39 +00002119#endif
2120
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002121 /* clear the just started flag */
2122 tcp->flags &= ~TCB_STARTUP;
2123
2124 /* set current output file */
2125 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002126 curcol = tcp->curcol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002127
2128 if (cflag) {
2129 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002130#ifdef FREEBSD
2131 char buf[1024];
2132 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002133
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002134 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
2135 buf[len] = '\0';
2136 sscanf(buf,
2137 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2138 &stime.tv_sec, &stime.tv_usec);
2139 } else
2140 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002141#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002142 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2143 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002144#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002145 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2146 tcp->stime = stime;
2147 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002148 what = tcp->status.PR_WHAT;
2149 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002150#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002151 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002152 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2153 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002154 if (trace_syscall(tcp) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002155 error_msg_and_die("syscall trouble");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002156 }
2157 }
2158 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002159#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002160 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002161#ifdef POLL_HACK
2162 in_syscall = tcp;
2163#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002164 case PR_SYSEXIT:
2165 if (trace_syscall(tcp) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002166 error_msg_and_die("syscall trouble");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002167 }
2168 break;
2169 case PR_SIGNALLED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002170 if (cflag != CFLAG_ONLY_STATS
2171 && (qual_flags[what] & QUAL_SIGNAL)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002172 printleader(tcp);
2173 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002174 signame(what), strsignal(what));
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002175 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002176#ifdef PR_INFO
2177 if (tcp->status.PR_INFO.si_signo == what) {
2178 printleader(tcp);
2179 tprintf(" siginfo=");
2180 printsiginfo(&tcp->status.PR_INFO, 1);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002181 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002182 }
2183#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002184 }
2185 break;
2186 case PR_FAULTED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002187 if (cflag != CFLAGS_ONLY_STATS
2188 && (qual_flags[what] & QUAL_FAULT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002189 printleader(tcp);
2190 tprintf("=== FAULT %d ===", what);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002191 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002192 }
2193 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002194#ifdef FREEBSD
2195 case 0: /* handle case we polled for nothing */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002196 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00002197#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002198 default:
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002199 error_msg_and_die("odd stop %d", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002200 break;
2201 }
Andreas Schwabccdff482009-10-27 16:27:13 +01002202 /* Remember current print column before continuing. */
2203 tcp->curcol = curcol;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002204 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002205#ifndef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002206 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002207#else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002208 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002209#endif
Andreas Schwab372cc842010-07-09 11:49:27 +02002210 {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002211 perror_msg_and_die("PIOCRUN");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002212 }
2213 }
2214 return 0;
2215}
2216
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002217#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002218
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002219#ifdef LINUX
2220static int
2221handle_ptrace_event(int status, struct tcb *tcp)
2222{
2223 if (status >> 16 == PTRACE_EVENT_VFORK ||
2224 status >> 16 == PTRACE_EVENT_CLONE ||
2225 status >> 16 == PTRACE_EVENT_FORK) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +00002226 long childpid;
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002227
2228 if (do_ptrace(PTRACE_GETEVENTMSG, tcp, NULL, &childpid) < 0) {
2229 if (errno != ESRCH) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002230 error_msg_and_die("Cannot get new child's pid");
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002231 }
2232 return -1;
2233 }
2234 return handle_new_child(tcp, childpid, 0);
2235 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002236 if (status >> 16 == PTRACE_EVENT_EXEC) {
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002237 return 0;
2238 }
Denys Vlasenko75422762011-05-27 14:36:01 +02002239 /* Some PTRACE_EVENT_foo we didn't ask for?! */
2240 error_msg("Unexpected status %x on pid %d", status, tcp->pid);
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002241 return 1;
2242}
2243#endif
2244
Roland McGratheb9e2e82009-06-02 16:49:22 -07002245static int
2246trace()
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002247{
2248 int pid;
2249 int wait_errno;
2250 int status;
2251 struct tcb *tcp;
2252#ifdef LINUX
2253 struct rusage ru;
Denys Vlasenko26d1b1e2011-08-15 12:24:14 +02002254 struct rusage *rup = cflag ? &ru : NULL;
2255# ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002256 static int wait4_options = __WALL;
Denys Vlasenko26d1b1e2011-08-15 12:24:14 +02002257# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002258#endif /* LINUX */
2259
Roland McGratheb9e2e82009-06-02 16:49:22 -07002260 while (nprocs != 0) {
Denys Vlasenko222713a2009-03-17 14:29:59 +00002261 if (interrupted)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002262 return 0;
2263 if (interactive)
2264 sigprocmask(SIG_SETMASK, &empty_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002265#ifdef LINUX
Denys Vlasenko26d1b1e2011-08-15 12:24:14 +02002266# ifdef __WALL
2267 pid = wait4(-1, &status, wait4_options, rup);
Roland McGrath5bc05552002-12-17 04:50:47 +00002268 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002269 /* this kernel does not support __WALL */
2270 wait4_options &= ~__WALL;
Denys Vlasenko26d1b1e2011-08-15 12:24:14 +02002271 pid = wait4(-1, &status, wait4_options, rup);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002272 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002273 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002274 /* most likely a "cloned" process */
Denys Vlasenko26d1b1e2011-08-15 12:24:14 +02002275 pid = wait4(-1, &status, __WCLONE, rup);
2276 if (pid < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002277 perror_msg("wait4(__WCLONE) failed");
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002278 }
2279 }
Denys Vlasenko26d1b1e2011-08-15 12:24:14 +02002280# else
2281 pid = wait4(-1, &status, 0, rup);
2282# endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002283#endif /* LINUX */
2284#ifdef SUNOS4
2285 pid = wait(&status);
Denys Vlasenko26d1b1e2011-08-15 12:24:14 +02002286#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002287 wait_errno = errno;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002288 if (interactive)
2289 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002290
Denys Vlasenko26d1b1e2011-08-15 12:24:14 +02002291 if (pid < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002292 switch (wait_errno) {
2293 case EINTR:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002294 continue;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002295 case ECHILD:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002296 /*
2297 * We would like to verify this case
2298 * but sometimes a race in Solbourne's
2299 * version of SunOS sometimes reports
2300 * ECHILD before sending us SIGCHILD.
2301 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002302 return 0;
2303 default:
2304 errno = wait_errno;
2305 perror("strace: wait");
2306 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002307 }
2308 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002309 if (pid == popen_pid) {
2310 if (WIFEXITED(status) || WIFSIGNALED(status))
Denys Vlasenko7dd23382011-06-22 13:03:56 +02002311 popen_pid = 0;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002312 continue;
2313 }
Denys Vlasenko1d5f12e2011-06-24 16:41:35 +02002314 if (debug) {
2315 char buf[sizeof("WIFEXITED,exitcode=%u") + sizeof(int)*3 /*paranoia:*/ + 16];
2316#ifdef LINUX
2317 unsigned ev = (unsigned)status >> 16;
2318 if (ev) {
2319 static const char *const event_names[] = {
2320 [PTRACE_EVENT_CLONE] = "CLONE",
2321 [PTRACE_EVENT_FORK] = "FORK",
2322 [PTRACE_EVENT_VFORK] = "VFORK",
2323 [PTRACE_EVENT_VFORK_DONE] = "VFORK_DONE",
2324 [PTRACE_EVENT_EXEC] = "EXEC",
2325 [PTRACE_EVENT_EXIT] = "EXIT",
2326 };
2327 const char *e;
2328 if (ev < ARRAY_SIZE(event_names))
2329 e = event_names[ev];
2330 else {
2331 sprintf(buf, "?? (%u)", ev);
2332 e = buf;
2333 }
2334 fprintf(stderr, " PTRACE_EVENT_%s", e);
2335 }
2336#endif
2337 strcpy(buf, "???");
2338 if (WIFSIGNALED(status))
2339#ifdef WCOREDUMP
2340 sprintf(buf, "WIFSIGNALED,%ssig=%s",
2341 WCOREDUMP(status) ? "core," : "",
2342 signame(WTERMSIG(status)));
2343#else
2344 sprintf(buf, "WIFSIGNALED,sig=%s",
2345 signame(WTERMSIG(status)));
2346#endif
2347 if (WIFEXITED(status))
2348 sprintf(buf, "WIFEXITED,exitcode=%u", WEXITSTATUS(status));
2349 if (WIFSTOPPED(status))
2350 sprintf(buf, "WIFSTOPPED,sig=%s", signame(WSTOPSIG(status)));
Denys Vlasenko5bd67c82011-08-15 11:36:09 +02002351#ifdef WIFCONTINUED
Denys Vlasenko1d5f12e2011-06-24 16:41:35 +02002352 if (WIFCONTINUED(status))
2353 strcpy(buf, "WIFCONTINUED");
Denys Vlasenko5bd67c82011-08-15 11:36:09 +02002354#endif
Denys Vlasenko1d5f12e2011-06-24 16:41:35 +02002355 fprintf(stderr, " [wait(0x%04x) = %u] %s\n", status, pid, buf);
2356 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002357
2358 /* Look up `pid' in our table. */
2359 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002360#ifdef LINUX
Roland McGrath41c48222008-07-18 00:25:10 +00002361 if (followfork) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002362 /* This is needed to go with the CLONE_PTRACE
2363 changes in process.c/util.c: we might see
2364 the child's initial trap before we see the
2365 parent return from the clone syscall.
2366 Leave the child suspended until the parent
2367 returns from its system call. Only then
2368 will we have the association of parent and
2369 child so that we know how to do clearbpt
2370 in the child. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +00002371 tcp = alloctcb(pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002372 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002373 if (!qflag)
2374 fprintf(stderr, "\
2375Process %d attached (waiting for parent)\n",
2376 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002377 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002378 else
2379 /* This can happen if a clone call used
2380 CLONE_PTRACE itself. */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002381#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002382 {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002383 if (WIFSTOPPED(status))
2384 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002385 error_msg_and_die("Unknown pid: %u", pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002386 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002387 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002388 /* set current output file */
2389 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002390 curcol = tcp->curcol;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002391#ifdef LINUX
Denys Vlasenko13d22f12011-06-24 23:01:57 +02002392 if (cflag) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002393 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2394 tcp->stime = ru.ru_stime;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002395 }
Denys Vlasenko13d22f12011-06-24 23:01:57 +02002396#endif
Roland McGratheb9e2e82009-06-02 16:49:22 -07002397
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002398 if (tcp->flags & TCB_SUSPENDED) {
2399 /*
2400 * Apparently, doing any ptrace() call on a stopped
2401 * process, provokes the kernel to report the process
2402 * status again on a subsequent wait(), even if the
2403 * process has not been actually restarted.
2404 * Since we have inspected the arguments of suspended
2405 * processes we end up here testing for this case.
2406 */
2407 continue;
2408 }
2409 if (WIFSIGNALED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002410 if (pid == strace_child)
2411 exit_code = 0x100 | WTERMSIG(status);
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002412 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002413 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2414 printleader(tcp);
Denys Vlasenko13d22f12011-06-24 23:01:57 +02002415#ifdef WCOREDUMP
Roland McGrath2efe8792004-01-13 09:59:45 +00002416 tprintf("+++ killed by %s %s+++",
2417 signame(WTERMSIG(status)),
Denys Vlasenko13d22f12011-06-24 23:01:57 +02002418 WCOREDUMP(status) ? "(core dumped) " : "");
2419#else
2420 tprintf("+++ killed by %s +++",
2421 signame(WTERMSIG(status)));
Roland McGrath2efe8792004-01-13 09:59:45 +00002422#endif
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002423 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002424 }
2425 droptcb(tcp);
2426 continue;
2427 }
2428 if (WIFEXITED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002429 if (pid == strace_child)
2430 exit_code = WEXITSTATUS(status);
Roland McGrath0a396902003-06-10 03:05:53 +00002431 if (tcp == tcp_last) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002432 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT)) == TCB_INSYSCALL)
Roland McGrath0a396902003-06-10 03:05:53 +00002433 tprintf(" <unfinished ... exit status %d>\n",
2434 WEXITSTATUS(status));
2435 tcp_last = NULL;
2436 }
Denys Vlasenko19cdada2011-08-17 10:45:32 +02002437 if (!cflag /* && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL) */ ) {
2438 printleader(tcp);
2439 tprintf("+++ exited with %d +++", WEXITSTATUS(status));
2440 printtrailer();
2441 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002442 droptcb(tcp);
2443 continue;
2444 }
2445 if (!WIFSTOPPED(status)) {
2446 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2447 droptcb(tcp);
2448 continue;
2449 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002450
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002451 if (status >> 16) {
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002452 if (handle_ptrace_event(status, tcp) != 1)
2453 goto tracing;
2454 }
2455
Roland McGrath02203312007-06-11 22:06:31 +00002456 /*
2457 * Interestingly, the process may stop
2458 * with STOPSIG equal to some other signal
Roland McGratheb9e2e82009-06-02 16:49:22 -07002459 * than SIGSTOP if we happend to attach
Roland McGrath02203312007-06-11 22:06:31 +00002460 * just before the process takes a signal.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002461 * A no-MMU vforked child won't send up a signal,
2462 * so skip the first (lost) execve notification.
Roland McGrath02203312007-06-11 22:06:31 +00002463 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002464 if ((tcp->flags & TCB_STARTUP) &&
2465 (WSTOPSIG(status) == SIGSTOP || strace_vforked)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002466 /*
2467 * This flag is there to keep us in sync.
2468 * Next time this process stops it should
2469 * really be entering a system call.
2470 */
2471 tcp->flags &= ~TCB_STARTUP;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002472 if (tcp->flags & TCB_BPTSET) {
Roland McGrath02203312007-06-11 22:06:31 +00002473 /*
2474 * One example is a breakpoint inherited from
2475 * parent through fork ().
2476 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002477 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2478 droptcb(tcp);
2479 cleanup();
2480 return -1;
2481 }
2482 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002483#ifdef LINUX
Denys Vlasenkof44cce42011-06-21 14:34:10 +02002484 /* If options were not set for this tracee yet */
2485 if (tcp->parent == NULL) {
2486 if (ptrace_setoptions) {
2487 if (debug)
2488 fprintf(stderr, "setting opts %x on pid %d\n", ptrace_setoptions, tcp->pid);
2489 if (ptrace(PTRACE_SETOPTIONS, tcp->pid, NULL, ptrace_setoptions) < 0) {
2490 if (errno != ESRCH) {
2491 /* Should never happen, really */
2492 perror_msg_and_die("PTRACE_SETOPTIONS");
2493 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002494 }
2495 }
2496 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002497#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002498 goto tracing;
2499 }
2500
Denys Vlasenko75422762011-05-27 14:36:01 +02002501 if (WSTOPSIG(status) != syscall_trap_sig) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002502 if (WSTOPSIG(status) == SIGSTOP &&
2503 (tcp->flags & TCB_SIGTRAPPED)) {
2504 /*
2505 * Trapped attempt to block SIGTRAP
2506 * Hope we are back in control now.
2507 */
2508 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002509 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002510 cleanup();
2511 return -1;
2512 }
2513 continue;
2514 }
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002515 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002516 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Dmitry V. Levinc15dfc72011-03-10 14:44:45 +00002517 siginfo_t si;
2518#if defined(PT_CR_IPSR) && defined(PT_CR_IIP)
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002519 long pc = 0;
2520 long psr = 0;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002521
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002522 upeek(tcp, PT_CR_IPSR, &psr);
2523 upeek(tcp, PT_CR_IIP, &pc);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002524
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002525# define PSR_RI 41
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002526 pc += (psr >> PSR_RI) & 0x3;
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002527# define PC_FORMAT_STR " @ %lx"
2528# define PC_FORMAT_ARG pc
2529#else
2530# define PC_FORMAT_STR "%s"
2531# define PC_FORMAT_ARG ""
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002532#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002533 printleader(tcp);
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002534 if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
2535 tprintf("--- ");
2536 printsiginfo(&si, verbose(tcp));
2537 tprintf(" (%s)" PC_FORMAT_STR " ---",
2538 strsignal(WSTOPSIG(status)),
2539 PC_FORMAT_ARG);
2540 } else
2541 tprintf("--- %s by %s" PC_FORMAT_STR " ---",
2542 strsignal(WSTOPSIG(status)),
2543 signame(WSTOPSIG(status)),
2544 PC_FORMAT_ARG);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002545 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002546 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002547 if (ptrace_restart(PTRACE_SYSCALL, tcp, WSTOPSIG(status)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002548 cleanup();
2549 return -1;
2550 }
2551 tcp->flags &= ~TCB_SUSPENDED;
2552 continue;
2553 }
Roland McGrath02203312007-06-11 22:06:31 +00002554 /* we handled the STATUS, we are permitted to interrupt now. */
2555 if (interrupted)
2556 return 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002557 if (trace_syscall(tcp) < 0 && !tcp->ptrace_errno) {
2558 /* ptrace() failed in trace_syscall() with ESRCH.
2559 * Likely a result of process disappearing mid-flight.
2560 * Observed case: exit_group() terminating
2561 * all processes in thread group. In this case, threads
2562 * "disappear" in an unpredictable moment without any
2563 * notification to strace via wait().
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002564 */
2565 if (tcp->flags & TCB_ATTACHED) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002566 if (tcp_last) {
2567 /* Do we have dangling line "syscall(param, param"?
Denys Vlasenko178de002011-06-24 22:54:25 +02002568 * Finish the line then.
Roland McGratheb9e2e82009-06-02 16:49:22 -07002569 */
2570 tcp_last->flags |= TCB_REPRINT;
2571 tprintf(" <unfinished ...>");
2572 printtrailer();
2573 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002574 detach(tcp, 0);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002575 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002576 ptrace(PTRACE_KILL,
2577 tcp->pid, (char *) 1, SIGTERM);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002578 droptcb(tcp);
2579 }
2580 continue;
2581 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002582 if (tcp->flags & TCB_SUSPENDED) {
2583 if (!qflag)
2584 fprintf(stderr, "Process %u suspended\n", pid);
2585 continue;
2586 }
2587 tracing:
Andreas Schwabccdff482009-10-27 16:27:13 +01002588 /* Remember current print column before continuing. */
2589 tcp->curcol = curcol;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002590 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002591 cleanup();
2592 return -1;
2593 }
2594 }
2595 return 0;
2596}
2597
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002598#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002599
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002600void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002601tprintf(const char *fmt, ...)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002602{
2603 va_list args;
2604
Andreas Schwabe5355de2009-10-27 16:56:43 +01002605 va_start(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002606 if (outf) {
2607 int n = vfprintf(outf, fmt, args);
Andreas Schwabccdff482009-10-27 16:27:13 +01002608 if (n < 0) {
2609 if (outf != stderr)
2610 perror(outfname == NULL
2611 ? "<writing to pipe>" : outfname);
2612 } else
Roland McGrathb310a0c2003-11-06 23:41:22 +00002613 curcol += n;
2614 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002615 va_end(args);
2616 return;
2617}
2618
2619void
Denys Vlasenko12014262011-05-30 14:00:14 +02002620printleader(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002621{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002622 if (tcp_last) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002623 if (tcp_last->ptrace_errno) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002624 if (tcp_last->flags & TCB_INSYSCALL) {
Denys Vlasenkoe62df002011-06-08 16:15:04 +02002625 tprintf(" <unavailable>) ");
Roland McGratheb9e2e82009-06-02 16:49:22 -07002626 tabto(acolumn);
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002627 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002628 tprintf("= ? <unavailable>\n");
2629 tcp_last->ptrace_errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002630 } else if (!outfname || followfork < 2 || tcp_last == tcp) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002631 tcp_last->flags |= TCB_REPRINT;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002632 tprintf(" <unfinished ...>\n");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002633 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002634 }
2635 curcol = 0;
2636 if ((followfork == 1 || pflag_seen > 1) && outfname)
2637 tprintf("%-5d ", tcp->pid);
2638 else if (nprocs > 1 && !outfname)
2639 tprintf("[pid %5u] ", tcp->pid);
2640 if (tflag) {
2641 char str[sizeof("HH:MM:SS")];
2642 struct timeval tv, dtv;
2643 static struct timeval otv;
2644
2645 gettimeofday(&tv, NULL);
2646 if (rflag) {
2647 if (otv.tv_sec == 0)
2648 otv = tv;
2649 tv_sub(&dtv, &tv, &otv);
2650 tprintf("%6ld.%06ld ",
2651 (long) dtv.tv_sec, (long) dtv.tv_usec);
2652 otv = tv;
2653 }
2654 else if (tflag > 2) {
2655 tprintf("%ld.%06ld ",
2656 (long) tv.tv_sec, (long) tv.tv_usec);
2657 }
2658 else {
2659 time_t local = tv.tv_sec;
2660 strftime(str, sizeof(str), "%T", localtime(&local));
2661 if (tflag > 1)
2662 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2663 else
2664 tprintf("%s ", str);
2665 }
2666 }
2667 if (iflag)
2668 printcall(tcp);
2669}
2670
2671void
Denys Vlasenko12014262011-05-30 14:00:14 +02002672tabto(int col)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002673{
2674 if (curcol < col)
2675 tprintf("%*s", col - curcol, "");
2676}
2677
2678void
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002679printtrailer(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002680{
2681 tprintf("\n");
2682 tcp_last = NULL;
2683}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002684
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002685#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002686
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002687int
2688mp_ioctl(int fd, int cmd, void *arg, int size)
2689{
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002690 struct iovec iov[2];
2691 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002692
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002693 iov[0].iov_base = &cmd;
2694 iov[0].iov_len = sizeof cmd;
2695 if (arg) {
2696 ++n;
2697 iov[1].iov_base = arg;
2698 iov[1].iov_len = size;
2699 }
Roland McGrath553a6092002-12-16 20:40:39 +00002700
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002701 return writev(fd, iov, n);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002702}
2703
2704#endif