blob: 0da9afb09d71f793908f7d9524a9315203649e26 [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>
Roland McGrath70b08532004-04-09 00:25:21 +000047#include <dirent.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000048
Roland McGrath134813a2007-06-02 00:07:33 +000049#ifdef LINUX
50# include <asm/unistd.h>
Denys Vlasenko44f87ef2011-08-17 15:18:21 +020051# if defined __NR_tkill
52# define my_tkill(tid, sig) syscall(__NR_tkill, (tid), (sig))
Roland McGrath134813a2007-06-02 00:07:33 +000053# else
54 /* kill() may choose arbitrarily the target task of the process group
55 while we later wait on a that specific TID. PID process waits become
56 TID task specific waits for a process under ptrace(2). */
57# warning "Neither tkill(2) nor tgkill(2) available, risk of strace hangs!"
Denys Vlasenko44f87ef2011-08-17 15:18:21 +020058# define my_tkill(tid, sig) kill((tid), (sig))
Roland McGrath134813a2007-06-02 00:07:33 +000059# endif
60#endif
61
Wichert Akkerman7b3346b2001-10-09 23:47:38 +000062#if defined(IA64) && defined(LINUX)
63# include <asm/ptrace_offsets.h>
64#endif
65
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +000066#ifdef USE_PROCFS
67#include <poll.h>
68#endif
69
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000070#ifdef SVR4
71#include <sys/stropts.h>
Wichert Akkermanea78f0f1999-11-29 15:34:02 +000072#ifdef HAVE_MP_PROCFS
John Hughes1d08dcf2001-07-10 13:48:44 +000073#ifdef HAVE_SYS_UIO_H
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000074#include <sys/uio.h>
75#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000076#endif
John Hughes1d08dcf2001-07-10 13:48:44 +000077#endif
Denys Vlasenko96d5a762008-12-29 19:13:27 +000078extern char **environ;
Denys Vlasenko418d66a2009-01-17 01:52:54 +000079extern int optind;
80extern char *optarg;
Denys Vlasenko96d5a762008-12-29 19:13:27 +000081
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000082
Roland McGrath41c48222008-07-18 00:25:10 +000083int debug = 0, followfork = 0;
Denys Vlasenkof44cce42011-06-21 14:34:10 +020084unsigned int ptrace_setoptions = 0;
Denys Vlasenko3454e4b2011-05-23 21:29:03 +020085/* Which WSTOPSIG(status) value marks syscall traps? */
Denys Vlasenko75422762011-05-27 14:36:01 +020086static unsigned int syscall_trap_sig = SIGTRAP;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +000087int dtime = 0, xflag = 0, qflag = 0;
88cflag_t cflag = CFLAG_NONE;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +000089static int iflag = 0, interactive = 0, pflag_seen = 0, rflag = 0, tflag = 0;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +000090/*
91 * daemonized_tracer supports -D option.
92 * With this option, strace forks twice.
93 * Unlike normal case, with -D *grandparent* process exec's,
94 * becoming a traced process. Child exits (this prevents traced process
95 * from having children it doesn't expect to have), and grandchild
96 * attaches to grandparent similarly to strace -p PID.
97 * This allows for more transparent interaction in cases
98 * when process and its parent are communicating via signals,
99 * wait() etc. Without -D, strace process gets lodged in between,
100 * disrupting parent<->child link.
101 */
102static bool daemonized_tracer = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000103
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000104/* Sometimes we want to print only succeeding syscalls. */
105int not_failing_only = 0;
106
Grant Edwards8a082772011-04-07 20:25:40 +0000107/* Show path associated with fd arguments */
108int show_fd_path = 0;
109
110/* are we filtering traces based on paths? */
111int tracing_paths = 0;
112
Dmitry V. Levina6809652008-11-10 17:14:58 +0000113static int exit_code = 0;
114static int strace_child = 0;
Denys Vlasenko75422762011-05-27 14:36:01 +0200115static int strace_tracer_pid = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700116
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +0000117static char *username = NULL;
Denys Vlasenkoead73bd2011-06-24 22:49:58 +0200118static uid_t run_uid;
119static gid_t run_gid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000120
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000121int max_strlen = DEFAULT_STRLEN;
Denys Vlasenko102ec492011-08-25 01:27:59 +0200122static int acolumn = DEFAULT_ACOLUMN;
123static char *acolumn_spaces;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +0000124static char *outfname = NULL;
Denys Vlasenkoead73bd2011-06-24 22:49:58 +0200125static FILE *outf;
Andreas Schwabccdff482009-10-27 16:27:13 +0100126static int curcol;
Denys Vlasenkoead73bd2011-06-24 22:49:58 +0200127static struct tcb **tcbtab;
Denys Vlasenko2b60c352011-06-22 12:45:25 +0200128static unsigned int nprocs, tcbtabsize;
Denys Vlasenkoead73bd2011-06-24 22:49:58 +0200129static const char *progname;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000130
Denys Vlasenko4c196382012-01-04 15:11:09 +0100131static int detach(struct tcb *tcp);
Andreas Schwabe5355de2009-10-27 16:56:43 +0100132static int trace(void);
133static void cleanup(void);
134static void interrupt(int sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000135static sigset_t empty_set, blocked_set;
136
137#ifdef HAVE_SIG_ATOMIC_T
138static volatile sig_atomic_t interrupted;
139#else /* !HAVE_SIG_ATOMIC_T */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000140static volatile int interrupted;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000141#endif /* !HAVE_SIG_ATOMIC_T */
142
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000143#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000144
Andreas Schwabe5355de2009-10-27 16:56:43 +0100145static struct tcb *pfd2tcb(int pfd);
146static void reaper(int sig);
147static void rebuild_pollv(void);
Roland McGrathee9d4352002-12-18 04:16:10 +0000148static struct pollfd *pollv;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000149
150#ifndef HAVE_POLLABLE_PROCFS
151
Andreas Schwabe5355de2009-10-27 16:56:43 +0100152static void proc_poll_open(void);
153static void proc_poller(int pfd);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000154
155struct proc_pollfd {
156 int fd;
157 int revents;
158 int pid;
159};
160
161static int poller_pid;
162static int proc_poll_pipe[2] = { -1, -1 };
163
164#endif /* !HAVE_POLLABLE_PROCFS */
165
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000166#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000167#define POLLWANT POLLWRNORM
168#else
169#define POLLWANT POLLPRI
170#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000171#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000172
173static void
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200174usage(FILE *ofp, int exitval)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000175{
176 fprintf(ofp, "\
Grant Edwards8a082772011-04-07 20:25:40 +0000177usage: strace [-CdDffhiqrtttTvVxxy] [-a column] [-e expr] ... [-o file]\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000178 [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n\
Grant Edwards8a082772011-04-07 20:25:40 +0000179 [-P path] [command [arg ...]]\n\
Andreas Schwabb87d30c2010-06-11 15:49:36 +0200180 or: strace -c [-D] [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000181 [command [arg ...]]\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000182-c -- count time, calls, and errors for each syscall and report summary\n\
Andreas Schwabb87d30c2010-06-11 15:49:36 +0200183-C -- like -c but also print regular output while processes are running\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000184-f -- follow forks, -ff -- with output into separate files\n\
185-F -- attempt to follow vforks, -h -- print help message\n\
186-i -- print instruction pointer at time of syscall\n\
187-q -- suppress messages about attaching, detaching, etc.\n\
188-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
189-T -- print time spent in each syscall, -V -- print version\n\
190-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
191-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
Grant Edwards8a082772011-04-07 20:25:40 +0000192-y -- print paths associated with file descriptor arguments\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000193-a column -- alignment COLUMN for printing syscall results (default %d)\n\
194-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
195 options: trace, abbrev, verbose, raw, signal, read, or write\n\
196-o file -- send trace output to FILE instead of stderr\n\
197-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
198-p pid -- trace process with process id PID, may be repeated\n\
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000199-D -- run tracer process as a detached grandchild, not as parent\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000200-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
201-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
202-u username -- run command as username handling setuid and/or setgid\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000203-E var=val -- put var=val in the environment for command\n\
204-E var -- remove var from the environment for command\n\
Grant Edwards8a082772011-04-07 20:25:40 +0000205-P path -- trace accesses to path\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000206" /* this is broken, so don't document it
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000207-z -- print only succeeding syscalls\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000208 */
209, DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000210 exit(exitval);
211}
212
Denys Vlasenko75422762011-05-27 14:36:01 +0200213static void die(void) __attribute__ ((noreturn));
214static void die(void)
215{
216 if (strace_tracer_pid == getpid()) {
217 cflag = 0;
218 cleanup();
219 }
220 exit(1);
221}
222
223static void verror_msg(int err_no, const char *fmt, va_list p)
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200224{
Denys Vlasenko82bb78c2012-01-24 10:17:18 +0100225 char *msg;
226
Dmitry V. Levin44d05322011-06-09 15:50:41 +0000227 fflush(NULL);
Denys Vlasenko82bb78c2012-01-24 10:17:18 +0100228
229 /* We want to print entire message with single fprintf to ensure
230 * message integrity if stderr is shared with other programs.
231 * Thus we use vasprintf + single fprintf.
232 */
233 msg = NULL;
234 vasprintf(&msg, fmt, p);
235 if (msg) {
236 if (err_no)
237 fprintf(stderr, "%s: %s: %s\n", progname, msg, strerror(err_no));
238 else
239 fprintf(stderr, "%s: %s\n", progname, msg);
240 free(msg);
241 } else {
242 /* malloc in vasprintf failed, try it without malloc */
243 fprintf(stderr, "%s: ", progname);
244 vfprintf(stderr, fmt, p);
245 if (err_no)
246 fprintf(stderr, ": %s\n", strerror(err_no));
247 else
248 putc('\n', stderr);
249 }
250 /* We don't switch stderr to buffered, thus fprintf(stderr)
251 * always flushes its output and this is not necessary: */
252 /* fflush(stderr); */
Denys Vlasenko75422762011-05-27 14:36:01 +0200253}
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200254
Denys Vlasenko75422762011-05-27 14:36:01 +0200255void error_msg(const char *fmt, ...)
256{
257 va_list p;
258 va_start(p, fmt);
259 verror_msg(0, fmt, p);
260 va_end(p);
261}
262
263void error_msg_and_die(const char *fmt, ...)
264{
265 va_list p;
266 va_start(p, fmt);
267 verror_msg(0, fmt, p);
268 die();
269}
270
271void perror_msg(const char *fmt, ...)
272{
273 va_list p;
274 va_start(p, fmt);
275 verror_msg(errno, fmt, p);
276 va_end(p);
277}
278
279void perror_msg_and_die(const char *fmt, ...)
280{
281 va_list p;
282 va_start(p, fmt);
283 verror_msg(errno, fmt, p);
284 die();
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200285}
286
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200287void die_out_of_memory(void)
288{
289 static bool recursed = 0;
290 if (recursed)
291 exit(1);
292 recursed = 1;
293 error_msg_and_die("Out of memory");
294}
295
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000296#ifdef SVR4
297#ifdef MIPS
298void
299foobar()
300{
301}
302#endif /* MIPS */
303#endif /* SVR4 */
304
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400305/* Glue for systems without a MMU that cannot provide fork() */
306#ifdef HAVE_FORK
307# define strace_vforked 0
308#else
309# define strace_vforked 1
310# define fork() vfork()
311#endif
312
Denys Vlasenko1f532ab2011-06-22 13:11:23 +0200313static void
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000314set_cloexec_flag(int fd)
315{
Denys Vlasenko1f532ab2011-06-22 13:11:23 +0200316 int flags, newflags;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000317
Denys Vlasenko1f532ab2011-06-22 13:11:23 +0200318 flags = fcntl(fd, F_GETFD);
319 if (flags < 0) {
320 /* Can happen only if fd is bad.
321 * Should never happen: if it does, we have a bug
322 * in the caller. Therefore we just abort
323 * instead of propagating the error.
324 */
325 perror_msg_and_die("fcntl(%d, F_GETFD)", fd);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000326 }
327
328 newflags = flags | FD_CLOEXEC;
329 if (flags == newflags)
Denys Vlasenko1f532ab2011-06-22 13:11:23 +0200330 return;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000331
Denys Vlasenko1f532ab2011-06-22 13:11:23 +0200332 fcntl(fd, F_SETFD, newflags); /* never fails */
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000333}
334
335/*
336 * When strace is setuid executable, we have to swap uids
337 * before and after filesystem and process management operations.
338 */
339static void
340swap_uid(void)
341{
342#ifndef SVR4
343 int euid = geteuid(), uid = getuid();
344
Denys Vlasenko7b609d52011-06-22 14:32:43 +0200345 if (euid != uid && setreuid(euid, uid) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200346 perror_msg_and_die("setreuid");
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000347 }
348#endif
349}
350
Roland McGrath4bfa6262007-07-05 20:03:16 +0000351#if _LFS64_LARGEFILE
352# define fopen_for_output fopen64
353#else
354# define fopen_for_output fopen
355#endif
356
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000357static FILE *
Denys Vlasenko3d5ed412011-06-22 13:17:16 +0200358strace_fopen(const char *path)
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000359{
360 FILE *fp;
361
362 swap_uid();
Denys Vlasenko3d5ed412011-06-22 13:17:16 +0200363 fp = fopen_for_output(path, "w");
364 if (!fp)
365 perror_msg_and_die("Can't fopen '%s'", path);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000366 swap_uid();
Denys Vlasenko3d5ed412011-06-22 13:17:16 +0200367 set_cloexec_flag(fileno(fp));
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000368 return fp;
369}
370
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200371static int popen_pid = 0;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000372
373#ifndef _PATH_BSHELL
374# define _PATH_BSHELL "/bin/sh"
375#endif
376
377/*
378 * We cannot use standard popen(3) here because we have to distinguish
379 * popen child process from other processes we trace, and standard popen(3)
380 * does not export its child's pid.
381 */
382static FILE *
383strace_popen(const char *command)
384{
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200385 FILE *fp;
386 int fds[2];
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000387
388 swap_uid();
389 if (pipe(fds) < 0)
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200390 perror_msg_and_die("pipe");
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000391
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200392 set_cloexec_flag(fds[1]); /* never fails */
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000393
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200394 popen_pid = vfork();
395 if (popen_pid == -1)
396 perror_msg_and_die("vfork");
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000397
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200398 if (popen_pid == 0) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000399 /* child */
400 close(fds[1]);
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200401 if (fds[0] != 0) {
402 if (dup2(fds[0], 0))
403 perror_msg_and_die("dup2");
404 close(fds[0]);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000405 }
406 execl(_PATH_BSHELL, "sh", "-c", command, NULL);
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200407 perror_msg_and_die("Can't execute '%s'", _PATH_BSHELL);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000408 }
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200409
410 /* parent */
411 close(fds[0]);
412 swap_uid();
413 fp = fdopen(fds[1], "w");
414 if (!fp)
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200415 die_out_of_memory();
Denys Vlasenko7dd23382011-06-22 13:03:56 +0200416 return fp;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000417}
418
Denys Vlasenko3d5ed412011-06-22 13:17:16 +0200419static void
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000420newoutf(struct tcb *tcp)
421{
422 if (outfname && followfork > 1) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000423 char name[520 + sizeof(int) * 3];
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000424 sprintf(name, "%.512s.%u", outfname, tcp->pid);
Denys Vlasenko3d5ed412011-06-22 13:17:16 +0200425 tcp->outf = strace_fopen(name);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000426 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000427}
428
Roland McGrath02203312007-06-11 22:06:31 +0000429static void
430startup_attach(void)
431{
432 int tcbi;
433 struct tcb *tcp;
434
435 /*
436 * Block user interruptions as we would leave the traced
437 * process stopped (process state T) if we would terminate in
Denys Vlasenko2e968c02011-09-01 10:23:09 +0200438 * between PTRACE_ATTACH and wait4() on SIGSTOP.
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200439 * We rely on cleanup() from this point on.
Roland McGrath02203312007-06-11 22:06:31 +0000440 */
441 if (interactive)
442 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
443
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000444 if (daemonized_tracer) {
445 pid_t pid = fork();
446 if (pid < 0) {
Denys Vlasenko014ca3a2011-09-02 16:19:30 +0200447 perror_msg_and_die("fork");
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000448 }
449 if (pid) { /* parent */
450 /*
Denys Vlasenko75422762011-05-27 14:36:01 +0200451 * Wait for grandchild to attach to straced process
452 * (grandparent). Grandchild SIGKILLs us after it attached.
453 * Grandparent's wait() is unblocked by our death,
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000454 * it proceeds to exec the straced program.
455 */
456 pause();
457 _exit(0); /* paranoia */
458 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200459 /* grandchild */
460 /* We will be the tracer process. Remember our new pid: */
461 strace_tracer_pid = getpid();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000462 }
463
Roland McGrath02203312007-06-11 22:06:31 +0000464 for (tcbi = 0; tcbi < tcbtabsize; tcbi++) {
465 tcp = tcbtab[tcbi];
Denys Vlasenko44f87ef2011-08-17 15:18:21 +0200466
Denys Vlasenkod116a732011-09-05 14:01:33 +0200467 /* Is this a process we should attach to, but not yet attached? */
468 if ((tcp->flags & (TCB_ATTACHED | TCB_STARTUP)) != TCB_ATTACHED)
469 continue; /* no */
470
471 /* Reinitialize the output since it may have changed */
Roland McGrath02203312007-06-11 22:06:31 +0000472 tcp->outf = outf;
Denys Vlasenko3d5ed412011-06-22 13:17:16 +0200473 newoutf(tcp);
Roland McGrath02203312007-06-11 22:06:31 +0000474
475#ifdef USE_PROCFS
476 if (proc_open(tcp, 1) < 0) {
477 fprintf(stderr, "trouble opening proc file\n");
478 droptcb(tcp);
479 continue;
480 }
481#else /* !USE_PROCFS */
482# ifdef LINUX
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000483 if (followfork && !daemonized_tracer) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000484 char procdir[sizeof("/proc/%d/task") + sizeof(int) * 3];
Roland McGrath02203312007-06-11 22:06:31 +0000485 DIR *dir;
486
487 sprintf(procdir, "/proc/%d/task", tcp->pid);
488 dir = opendir(procdir);
489 if (dir != NULL) {
490 unsigned int ntid = 0, nerr = 0;
491 struct dirent *de;
Denys Vlasenko381dbc22011-09-05 13:59:39 +0200492
Roland McGrath02203312007-06-11 22:06:31 +0000493 while ((de = readdir(dir)) != NULL) {
Denys Vlasenko381dbc22011-09-05 13:59:39 +0200494 struct tcb *cur_tcp;
495 int tid;
496
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000497 if (de->d_fileno == 0)
Roland McGrath02203312007-06-11 22:06:31 +0000498 continue;
499 tid = atoi(de->d_name);
500 if (tid <= 0)
501 continue;
502 ++ntid;
Denys Vlasenkof95397a2011-06-24 16:51:16 +0200503 if (ptrace(PTRACE_ATTACH, tid, (char *) 1, 0) < 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000504 ++nerr;
Denys Vlasenkof95397a2011-06-24 16:51:16 +0200505 if (debug)
506 fprintf(stderr, "attach to pid %d failed\n", tid);
Denys Vlasenko381dbc22011-09-05 13:59:39 +0200507 continue;
Denys Vlasenkof95397a2011-06-24 16:51:16 +0200508 }
Denys Vlasenko381dbc22011-09-05 13:59:39 +0200509 if (debug)
510 fprintf(stderr, "attach to pid %d succeeded\n", tid);
511 cur_tcp = tcp;
512 if (tid != tcp->pid)
513 cur_tcp = alloctcb(tid);
Denys Vlasenkof88837a2011-09-05 14:05:46 +0200514 cur_tcp->flags |= TCB_ATTACHED | TCB_STARTUP | TCB_IGNORE_ONE_SIGSTOP;
Roland McGrath02203312007-06-11 22:06:31 +0000515 }
516 closedir(dir);
Denys Vlasenko381dbc22011-09-05 13:59:39 +0200517 if (interactive) {
518 sigprocmask(SIG_SETMASK, &empty_set, NULL);
519 if (interrupted)
520 goto ret;
521 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
522 }
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000523 ntid -= nerr;
524 if (ntid == 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000525 perror("attach: ptrace(PTRACE_ATTACH, ...)");
526 droptcb(tcp);
527 continue;
528 }
529 if (!qflag) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000530 fprintf(stderr, ntid > 1
531? "Process %u attached with %u threads - interrupt to quit\n"
532: "Process %u attached - interrupt to quit\n",
Denys Vlasenko44f87ef2011-08-17 15:18:21 +0200533 tcp->pid, ntid);
Roland McGrath02203312007-06-11 22:06:31 +0000534 }
Denys Vlasenkof88837a2011-09-05 14:05:46 +0200535 if (!(tcp->flags & TCB_STARTUP)) {
536 /* -p PID, we failed to attach to PID itself
537 * but did attach to some of its sibling threads.
538 * Drop PID's tcp.
539 */
540 droptcb(tcp);
541 }
Roland McGrath02203312007-06-11 22:06:31 +0000542 continue;
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000543 } /* if (opendir worked) */
544 } /* if (-f) */
Denys Vlasenko44f87ef2011-08-17 15:18:21 +0200545# endif /* LINUX */
Roland McGrath02203312007-06-11 22:06:31 +0000546 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
547 perror("attach: ptrace(PTRACE_ATTACH, ...)");
548 droptcb(tcp);
549 continue;
550 }
Denys Vlasenkof88837a2011-09-05 14:05:46 +0200551 tcp->flags |= TCB_STARTUP | TCB_IGNORE_ONE_SIGSTOP;
Denys Vlasenkof95397a2011-06-24 16:51:16 +0200552 if (debug)
553 fprintf(stderr, "attach to pid %d (main) succeeded\n", tcp->pid);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000554
555 if (daemonized_tracer) {
556 /*
557 * It is our grandparent we trace, not a -p PID.
558 * Don't want to just detach on exit, so...
559 */
560 tcp->flags &= ~TCB_ATTACHED;
561 /*
562 * Make parent go away.
563 * Also makes grandparent's wait() unblock.
564 */
565 kill(getppid(), SIGKILL);
566 }
567
Roland McGrath02203312007-06-11 22:06:31 +0000568#endif /* !USE_PROCFS */
569 if (!qflag)
570 fprintf(stderr,
571 "Process %u attached - interrupt to quit\n",
572 tcp->pid);
Denys Vlasenkof95397a2011-06-24 16:51:16 +0200573 } /* for each tcbtab[] */
Roland McGrath02203312007-06-11 22:06:31 +0000574
Denys Vlasenko44f87ef2011-08-17 15:18:21 +0200575 ret:
Roland McGrath02203312007-06-11 22:06:31 +0000576 if (interactive)
577 sigprocmask(SIG_SETMASK, &empty_set, NULL);
578}
579
580static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200581startup_child(char **argv)
Roland McGrath02203312007-06-11 22:06:31 +0000582{
583 struct stat statbuf;
584 const char *filename;
585 char pathname[MAXPATHLEN];
586 int pid = 0;
587 struct tcb *tcp;
588
589 filename = argv[0];
590 if (strchr(filename, '/')) {
591 if (strlen(filename) > sizeof pathname - 1) {
592 errno = ENAMETOOLONG;
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200593 perror_msg_and_die("exec");
Roland McGrath02203312007-06-11 22:06:31 +0000594 }
595 strcpy(pathname, filename);
596 }
597#ifdef USE_DEBUGGING_EXEC
598 /*
599 * Debuggers customarily check the current directory
600 * first regardless of the path but doing that gives
601 * security geeks a panic attack.
602 */
603 else if (stat(filename, &statbuf) == 0)
604 strcpy(pathname, filename);
605#endif /* USE_DEBUGGING_EXEC */
606 else {
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000607 const char *path;
Roland McGrath02203312007-06-11 22:06:31 +0000608 int m, n, len;
609
610 for (path = getenv("PATH"); path && *path; path += m) {
611 if (strchr(path, ':')) {
612 n = strchr(path, ':') - path;
613 m = n + 1;
614 }
615 else
616 m = n = strlen(path);
617 if (n == 0) {
618 if (!getcwd(pathname, MAXPATHLEN))
619 continue;
620 len = strlen(pathname);
621 }
622 else if (n > sizeof pathname - 1)
623 continue;
624 else {
625 strncpy(pathname, path, n);
626 len = n;
627 }
628 if (len && pathname[len - 1] != '/')
629 pathname[len++] = '/';
630 strcpy(pathname + len, filename);
631 if (stat(pathname, &statbuf) == 0 &&
632 /* Accept only regular files
633 with some execute bits set.
634 XXX not perfect, might still fail */
635 S_ISREG(statbuf.st_mode) &&
636 (statbuf.st_mode & 0111))
637 break;
638 }
639 }
640 if (stat(pathname, &statbuf) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200641 perror_msg_and_die("Can't stat '%s'", filename);
Roland McGrath02203312007-06-11 22:06:31 +0000642 }
Dmitry V. Levina6809652008-11-10 17:14:58 +0000643 strace_child = pid = fork();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000644 if (pid < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200645 perror_msg_and_die("fork");
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000646 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200647 if ((pid != 0 && daemonized_tracer) /* -D: parent to become a traced process */
648 || (pid == 0 && !daemonized_tracer) /* not -D: child to become a traced process */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000649 ) {
650 pid = getpid();
Denys Vlasenko2e968c02011-09-01 10:23:09 +0200651 if (outf != stderr)
652 close(fileno(outf));
Roland McGrath02203312007-06-11 22:06:31 +0000653#ifdef USE_PROCFS
Denys Vlasenko2e968c02011-09-01 10:23:09 +0200654# ifdef MIPS
Roland McGrath02203312007-06-11 22:06:31 +0000655 /* Kludge for SGI, see proc_open for details. */
656 sa.sa_handler = foobar;
657 sa.sa_flags = 0;
658 sigemptyset(&sa.sa_mask);
659 sigaction(SIGINT, &sa, NULL);
Denys Vlasenko2e968c02011-09-01 10:23:09 +0200660# endif
661# ifndef FREEBSD
Roland McGrath02203312007-06-11 22:06:31 +0000662 pause();
Denys Vlasenko2e968c02011-09-01 10:23:09 +0200663# else
Denys Vlasenko014ca3a2011-09-02 16:19:30 +0200664 kill(pid, SIGSTOP);
Denys Vlasenko2e968c02011-09-01 10:23:09 +0200665# endif
Roland McGrath02203312007-06-11 22:06:31 +0000666#else /* !USE_PROCFS */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000667 if (!daemonized_tracer) {
668 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200669 perror_msg_and_die("ptrace(PTRACE_TRACEME, ...)");
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000670 }
671 if (debug)
672 kill(pid, SIGSTOP);
Roland McGrath02203312007-06-11 22:06:31 +0000673 }
Roland McGrath02203312007-06-11 22:06:31 +0000674
Denys Vlasenkoab034fb2011-09-01 10:27:42 +0200675 if (username != NULL) {
Roland McGrath02203312007-06-11 22:06:31 +0000676 uid_t run_euid = run_uid;
677 gid_t run_egid = run_gid;
678
679 if (statbuf.st_mode & S_ISUID)
680 run_euid = statbuf.st_uid;
681 if (statbuf.st_mode & S_ISGID)
682 run_egid = statbuf.st_gid;
Roland McGrath02203312007-06-11 22:06:31 +0000683 /*
684 * It is important to set groups before we
685 * lose privileges on setuid.
686 */
Denys Vlasenkoab034fb2011-09-01 10:27:42 +0200687 if (initgroups(username, run_gid) < 0) {
688 perror_msg_and_die("initgroups");
689 }
690 if (setregid(run_gid, run_egid) < 0) {
691 perror_msg_and_die("setregid");
692 }
693 if (setreuid(run_uid, run_euid) < 0) {
694 perror_msg_and_die("setreuid");
Roland McGrath02203312007-06-11 22:06:31 +0000695 }
696 }
Denys Vlasenkoab034fb2011-09-01 10:27:42 +0200697 else if (geteuid() != 0)
Roland McGrath02203312007-06-11 22:06:31 +0000698 setreuid(run_uid, run_uid);
699
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000700 if (!daemonized_tracer) {
701 /*
Denys Vlasenko2e968c02011-09-01 10:23:09 +0200702 * Induce a ptrace stop. Tracer (our parent)
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000703 * will resume us with PTRACE_SYSCALL and display
Denys Vlasenko2e968c02011-09-01 10:23:09 +0200704 * the immediately following execve syscall.
705 * Can't do this on NOMMU systems, we are after
706 * vfork: parent is blocked, stopping would deadlock.
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000707 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400708 if (!strace_vforked)
Denys Vlasenko2e968c02011-09-01 10:23:09 +0200709 kill(pid, SIGSTOP);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000710 } else {
711 struct sigaction sv_sigchld;
712 sigaction(SIGCHLD, NULL, &sv_sigchld);
713 /*
714 * Make sure it is not SIG_IGN, otherwise wait
715 * will not block.
716 */
717 signal(SIGCHLD, SIG_DFL);
718 /*
719 * Wait for grandchild to attach to us.
720 * It kills child after that, and wait() unblocks.
721 */
722 alarm(3);
723 wait(NULL);
724 alarm(0);
725 sigaction(SIGCHLD, &sv_sigchld, NULL);
726 }
Roland McGrath02203312007-06-11 22:06:31 +0000727#endif /* !USE_PROCFS */
728
729 execv(pathname, argv);
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200730 perror_msg_and_die("exec");
Roland McGrath02203312007-06-11 22:06:31 +0000731 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000732
Denys Vlasenko2e968c02011-09-01 10:23:09 +0200733 /* We are the tracer */
Denys Vlasenko75422762011-05-27 14:36:01 +0200734
Denys Vlasenko2e968c02011-09-01 10:23:09 +0200735 if (!daemonized_tracer) {
736 tcp = alloctcb(pid);
Denys Vlasenkof88837a2011-09-05 14:05:46 +0200737 if (!strace_vforked)
738 tcp->flags |= TCB_STARTUP | TCB_IGNORE_ONE_SIGSTOP;
739 else
740 tcp->flags |= TCB_STARTUP;
Denys Vlasenko2e968c02011-09-01 10:23:09 +0200741 }
742 else {
743 /* With -D, *we* are child here, IOW: different pid. Fetch it: */
744 strace_tracer_pid = getpid();
745 /* The tracee is our parent: */
746 pid = getppid();
747 tcp = alloctcb(pid);
748 /* We want subsequent startup_attach() to attach to it: */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000749 tcp->flags |= TCB_ATTACHED;
750 }
Roland McGrath02203312007-06-11 22:06:31 +0000751#ifdef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000752 if (proc_open(tcp, 0) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +0200753 perror_msg_and_die("trouble opening proc file");
Roland McGrath02203312007-06-11 22:06:31 +0000754 }
Denys Vlasenko2e968c02011-09-01 10:23:09 +0200755#endif
Roland McGrath02203312007-06-11 22:06:31 +0000756}
757
Wang Chaob13c0de2010-11-12 17:25:19 +0800758#ifdef LINUX
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000759static void kill_save_errno(pid_t pid, int sig)
760{
761 int saved_errno = errno;
762
763 (void) kill(pid, sig);
764 errno = saved_errno;
765}
766
Wang Chaob13c0de2010-11-12 17:25:19 +0800767/*
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000768 * Test whether the kernel support PTRACE_O_TRACECLONE et al options.
Wang Chaob13c0de2010-11-12 17:25:19 +0800769 * First fork a new child, call ptrace with PTRACE_SETOPTIONS on it,
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000770 * and then see which options are supported by the kernel.
Wang Chaob13c0de2010-11-12 17:25:19 +0800771 */
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000772static void
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200773test_ptrace_setoptions_followfork(void)
Wang Chaob13c0de2010-11-12 17:25:19 +0800774{
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000775 int pid, expected_grandchild = 0, found_grandchild = 0;
776 const unsigned int test_options = PTRACE_O_TRACECLONE |
777 PTRACE_O_TRACEFORK |
778 PTRACE_O_TRACEVFORK;
Wang Chaob13c0de2010-11-12 17:25:19 +0800779
Denys Vlasenko5d645812011-08-20 12:48:18 +0200780 pid = fork();
781 if (pid < 0)
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000782 perror_msg_and_die("fork");
Denys Vlasenko5d645812011-08-20 12:48:18 +0200783 if (pid == 0) {
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000784 pid = getpid();
785 if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
786 perror_msg_and_die("%s: PTRACE_TRACEME doesn't work",
787 __func__);
788 kill(pid, SIGSTOP);
789 if (fork() < 0)
790 perror_msg_and_die("fork");
791 _exit(0);
Wang Chaob13c0de2010-11-12 17:25:19 +0800792 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000793
794 while (1) {
795 int status, tracee_pid;
796
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000797 errno = 0;
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000798 tracee_pid = wait(&status);
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000799 if (tracee_pid <= 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000800 if (errno == EINTR)
801 continue;
802 else if (errno == ECHILD)
803 break;
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000804 kill_save_errno(pid, SIGKILL);
805 perror_msg_and_die("%s: unexpected wait result %d",
806 __func__, tracee_pid);
807 }
808 if (WIFEXITED(status)) {
809 if (WEXITSTATUS(status)) {
810 if (tracee_pid != pid)
811 kill_save_errno(pid, SIGKILL);
812 error_msg_and_die("%s: unexpected exit status %u",
813 __func__, WEXITSTATUS(status));
814 }
815 continue;
816 }
817 if (WIFSIGNALED(status)) {
818 if (tracee_pid != pid)
819 kill_save_errno(pid, SIGKILL);
820 error_msg_and_die("%s: unexpected signal %u",
821 __func__, WTERMSIG(status));
822 }
823 if (!WIFSTOPPED(status)) {
824 if (tracee_pid != pid)
825 kill_save_errno(tracee_pid, SIGKILL);
826 kill(pid, SIGKILL);
827 error_msg_and_die("%s: unexpected wait status %x",
828 __func__, status);
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000829 }
830 if (tracee_pid != pid) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000831 found_grandchild = tracee_pid;
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000832 if (ptrace(PTRACE_CONT, tracee_pid, 0, 0) < 0) {
833 kill_save_errno(tracee_pid, SIGKILL);
834 kill_save_errno(pid, SIGKILL);
835 perror_msg_and_die("PTRACE_CONT doesn't work");
Wang Chaob13c0de2010-11-12 17:25:19 +0800836 }
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000837 continue;
838 }
839 switch (WSTOPSIG(status)) {
840 case SIGSTOP:
841 if (ptrace(PTRACE_SETOPTIONS, pid, 0, test_options) < 0
842 && errno != EINVAL && errno != EIO)
843 perror_msg("PTRACE_SETOPTIONS");
844 break;
845 case SIGTRAP:
846 if (status >> 16 == PTRACE_EVENT_FORK) {
847 long msg = 0;
848
849 if (ptrace(PTRACE_GETEVENTMSG, pid,
850 NULL, (long) &msg) == 0)
851 expected_grandchild = msg;
852 }
853 break;
854 }
855 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) {
856 kill_save_errno(pid, SIGKILL);
857 perror_msg_and_die("PTRACE_SYSCALL doesn't work");
Wang Chaob13c0de2010-11-12 17:25:19 +0800858 }
859 }
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000860 if (expected_grandchild && expected_grandchild == found_grandchild) {
Denys Vlasenkof44cce42011-06-21 14:34:10 +0200861 ptrace_setoptions |= test_options;
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000862 if (debug)
863 fprintf(stderr, "ptrace_setoptions = %#x\n",
864 ptrace_setoptions);
865 return;
866 }
867 error_msg("Test for PTRACE_O_TRACECLONE failed, "
868 "giving up using this feature.");
Wang Chaob13c0de2010-11-12 17:25:19 +0800869}
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200870
871/*
872 * Test whether the kernel support PTRACE_O_TRACESYSGOOD.
873 * First fork a new child, call ptrace(PTRACE_SETOPTIONS) on it,
874 * and then see whether it will stop with (SIGTRAP | 0x80).
875 *
876 * Use of this option enables correct handling of user-generated SIGTRAPs,
877 * and SIGTRAPs generated by special instructions such as int3 on x86:
878 * _start: .globl _start
879 * int3
880 * movl $42, %ebx
881 * movl $1, %eax
882 * int $0x80
883 * (compile with: "gcc -nostartfiles -nostdlib -o int3 int3.S")
884 */
885static void
886test_ptrace_setoptions_for_all(void)
887{
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000888 const unsigned int test_options = PTRACE_O_TRACESYSGOOD |
889 PTRACE_O_TRACEEXEC;
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200890 int pid;
891 int it_worked = 0;
892
893 pid = fork();
894 if (pid < 0)
Denys Vlasenko75422762011-05-27 14:36:01 +0200895 perror_msg_and_die("fork");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200896
897 if (pid == 0) {
898 pid = getpid();
899 if (ptrace(PTRACE_TRACEME, 0L, 0L, 0L) < 0)
Denys Vlasenko75422762011-05-27 14:36:01 +0200900 /* Note: exits with exitcode 1 */
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000901 perror_msg_and_die("%s: PTRACE_TRACEME doesn't work",
902 __func__);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200903 kill(pid, SIGSTOP);
904 _exit(0); /* parent should see entry into this syscall */
905 }
906
907 while (1) {
908 int status, tracee_pid;
909
910 errno = 0;
911 tracee_pid = wait(&status);
912 if (tracee_pid <= 0) {
913 if (errno == EINTR)
914 continue;
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000915 kill_save_errno(pid, SIGKILL);
916 perror_msg_and_die("%s: unexpected wait result %d",
917 __func__, tracee_pid);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200918 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200919 if (WIFEXITED(status)) {
920 if (WEXITSTATUS(status) == 0)
921 break;
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000922 error_msg_and_die("%s: unexpected exit status %u",
923 __func__, WEXITSTATUS(status));
924 }
925 if (WIFSIGNALED(status)) {
926 error_msg_and_die("%s: unexpected signal %u",
927 __func__, WTERMSIG(status));
Denys Vlasenko75422762011-05-27 14:36:01 +0200928 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200929 if (!WIFSTOPPED(status)) {
930 kill(pid, SIGKILL);
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000931 error_msg_and_die("%s: unexpected wait status %x",
932 __func__, status);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200933 }
934 if (WSTOPSIG(status) == SIGSTOP) {
935 /*
936 * We don't check "options aren't accepted" error.
937 * If it happens, we'll never get (SIGTRAP | 0x80),
938 * and thus will decide to not use the option.
939 * IOW: the outcome of the test will be correct.
940 */
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000941 if (ptrace(PTRACE_SETOPTIONS, pid, 0L, test_options) < 0
942 && errno != EINVAL && errno != EIO)
943 perror_msg("PTRACE_SETOPTIONS");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200944 }
945 if (WSTOPSIG(status) == (SIGTRAP | 0x80)) {
946 it_worked = 1;
947 }
948 if (ptrace(PTRACE_SYSCALL, pid, 0L, 0L) < 0) {
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000949 kill_save_errno(pid, SIGKILL);
Denys Vlasenko75422762011-05-27 14:36:01 +0200950 perror_msg_and_die("PTRACE_SYSCALL doesn't work");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200951 }
952 }
953
954 if (it_worked) {
Denys Vlasenko75422762011-05-27 14:36:01 +0200955 syscall_trap_sig = (SIGTRAP | 0x80);
Denys Vlasenkof44cce42011-06-21 14:34:10 +0200956 ptrace_setoptions |= test_options;
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200957 if (debug)
Denys Vlasenkof44cce42011-06-21 14:34:10 +0200958 fprintf(stderr, "ptrace_setoptions = %#x\n",
959 ptrace_setoptions);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200960 return;
961 }
962
Dmitry V. Levin04f8b482011-08-16 18:57:29 +0000963 error_msg("Test for PTRACE_O_TRACESYSGOOD failed, "
964 "giving up using this feature.");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200965}
Wang Chaob13c0de2010-11-12 17:25:19 +0800966#endif
967
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000968int
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000969main(int argc, char *argv[])
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000970{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000971 struct tcb *tcp;
972 int c, pid = 0;
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000973 int optF = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000974 struct sigaction sa;
975
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000976 progname = argv[0] ? argv[0] : "strace";
977
Denys Vlasenko75422762011-05-27 14:36:01 +0200978 strace_tracer_pid = getpid();
979
Roland McGrathee9d4352002-12-18 04:16:10 +0000980 /* Allocate the initial tcbtab. */
981 tcbtabsize = argc; /* Surely enough for all -p args. */
Denys Vlasenko4f12af22011-06-23 13:16:23 +0200982 tcbtab = calloc(tcbtabsize, sizeof(tcbtab[0]));
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200983 if (!tcbtab)
984 die_out_of_memory();
Denys Vlasenko4f12af22011-06-23 13:16:23 +0200985 tcp = calloc(tcbtabsize, sizeof(*tcp));
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200986 if (!tcp)
987 die_out_of_memory();
Denys Vlasenko4f12af22011-06-23 13:16:23 +0200988 for (c = 0; c < tcbtabsize; c++)
989 tcbtab[c] = tcp++;
Roland McGrathee9d4352002-12-18 04:16:10 +0000990
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000991 outf = stderr;
992 interactive = 1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000993 set_sortby(DEFAULT_SORTBY);
994 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000995 qualify("trace=all");
996 qualify("abbrev=all");
997 qualify("verbose=all");
998 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000999 while ((c = getopt(argc, argv,
Grant Edwards8a082772011-04-07 20:25:40 +00001000 "+cCdfFhiqrtTvVxyz"
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +00001001#ifndef USE_PROCFS
1002 "D"
1003#endif
Grant Edwards8a082772011-04-07 20:25:40 +00001004 "a:e:o:O:p:s:S:u:E:P:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001005 switch (c) {
1006 case 'c':
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00001007 if (cflag == CFLAG_BOTH) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001008 error_msg_and_die("-c and -C are mutually exclusive options");
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00001009 }
1010 cflag = CFLAG_ONLY_STATS;
1011 break;
1012 case 'C':
1013 if (cflag == CFLAG_ONLY_STATS) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001014 error_msg_and_die("-c and -C are mutually exclusive options");
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00001015 }
1016 cflag = CFLAG_BOTH;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001017 break;
1018 case 'd':
1019 debug++;
1020 break;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +00001021#ifndef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +00001022 case 'D':
1023 daemonized_tracer = 1;
1024 break;
1025#endif
Roland McGrath41c48222008-07-18 00:25:10 +00001026 case 'F':
Dmitry V. Levin06350db2008-07-25 15:42:34 +00001027 optF = 1;
1028 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001029 case 'f':
1030 followfork++;
1031 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001032 case 'h':
1033 usage(stdout, 0);
1034 break;
1035 case 'i':
1036 iflag++;
1037 break;
1038 case 'q':
1039 qflag++;
1040 break;
1041 case 'r':
1042 rflag++;
1043 tflag++;
1044 break;
1045 case 't':
1046 tflag++;
1047 break;
1048 case 'T':
1049 dtime++;
1050 break;
1051 case 'x':
1052 xflag++;
1053 break;
Grant Edwards8a082772011-04-07 20:25:40 +00001054 case 'y':
1055 show_fd_path = 1;
1056 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001057 case 'v':
1058 qualify("abbrev=none");
1059 break;
1060 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +00001061 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001062 exit(0);
1063 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +00001064 case 'z':
1065 not_failing_only = 1;
1066 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001067 case 'a':
1068 acolumn = atoi(optarg);
Denys Vlasenko102ec492011-08-25 01:27:59 +02001069 if (acolumn < 0)
1070 error_msg_and_die("Bad column width '%s'", optarg);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001071 break;
1072 case 'e':
1073 qualify(optarg);
1074 break;
1075 case 'o':
1076 outfname = strdup(optarg);
1077 break;
1078 case 'O':
1079 set_overhead(atoi(optarg));
1080 break;
1081 case 'p':
Denys Vlasenko5d645812011-08-20 12:48:18 +02001082 pid = atoi(optarg);
1083 if (pid <= 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001084 error_msg("Invalid process id: '%s'", optarg);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001085 break;
1086 }
Denys Vlasenko75422762011-05-27 14:36:01 +02001087 if (pid == strace_tracer_pid) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001088 error_msg("I'm sorry, I can't let you do that, Dave.");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001089 break;
1090 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001091 tcp = alloc_tcb(pid, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001092 tcp->flags |= TCB_ATTACHED;
1093 pflag_seen++;
1094 break;
Grant Edwards8a082772011-04-07 20:25:40 +00001095 case 'P':
1096 tracing_paths = 1;
1097 if (pathtrace_select(optarg)) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001098 error_msg_and_die("Failed to select path '%s'", optarg);
Grant Edwards8a082772011-04-07 20:25:40 +00001099 }
1100 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001101 case 's':
1102 max_strlen = atoi(optarg);
Roland McGrathdccec722005-05-09 07:45:47 +00001103 if (max_strlen < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001104 error_msg_and_die("Invalid -s argument: '%s'", optarg);
Roland McGrathdccec722005-05-09 07:45:47 +00001105 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001106 break;
1107 case 'S':
1108 set_sortby(optarg);
1109 break;
1110 case 'u':
1111 username = strdup(optarg);
1112 break;
Roland McGrathde6e5332003-01-24 04:31:23 +00001113 case 'E':
Denys Vlasenko1d46ba52011-08-31 14:00:02 +02001114 if (putenv(optarg) < 0)
1115 die_out_of_memory();
Roland McGrathde6e5332003-01-24 04:31:23 +00001116 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001117 default:
1118 usage(stderr, 1);
1119 break;
1120 }
1121 }
1122
Denys Vlasenko102ec492011-08-25 01:27:59 +02001123 acolumn_spaces = malloc(acolumn + 1);
1124 if (!acolumn_spaces)
Denys Vlasenko1d46ba52011-08-31 14:00:02 +02001125 die_out_of_memory();
Denys Vlasenko102ec492011-08-25 01:27:59 +02001126 memset(acolumn_spaces, ' ', acolumn);
1127 acolumn_spaces[acolumn] = '\0';
1128
Roland McGrathd0c4c0c2006-04-25 07:39:40 +00001129 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +00001130 usage(stderr, 1);
1131
Wang Chaod322a4b2010-08-05 14:30:11 +08001132 if (pflag_seen && daemonized_tracer) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001133 error_msg_and_die("-D and -p are mutually exclusive options");
Wang Chaod322a4b2010-08-05 14:30:11 +08001134 }
1135
Dmitry V. Levin06350db2008-07-25 15:42:34 +00001136 if (!followfork)
1137 followfork = optF;
1138
Roland McGrathcb9def62006-04-25 07:48:03 +00001139 if (followfork > 1 && cflag) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001140 error_msg_and_die("(-c or -C) and -ff are mutually exclusive options");
Roland McGrathcb9def62006-04-25 07:48:03 +00001141 }
1142
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001143 /* See if they want to run as another user. */
1144 if (username != NULL) {
1145 struct passwd *pent;
1146
1147 if (getuid() != 0 || geteuid() != 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001148 error_msg_and_die("You must be root to use the -u option");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001149 }
Denys Vlasenko5d645812011-08-20 12:48:18 +02001150 pent = getpwnam(username);
1151 if (pent == NULL) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001152 error_msg_and_die("Cannot find user '%s'", username);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001153 }
1154 run_uid = pent->pw_uid;
1155 run_gid = pent->pw_gid;
1156 }
1157 else {
1158 run_uid = getuid();
1159 run_gid = getgid();
1160 }
1161
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001162#ifdef LINUX
Dmitry V. Levin04f8b482011-08-16 18:57:29 +00001163 if (followfork)
1164 test_ptrace_setoptions_followfork();
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02001165 test_ptrace_setoptions_for_all();
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001166#endif
1167
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001168 /* Check if they want to redirect the output. */
1169 if (outfname) {
Roland McGrath37b9a662003-11-07 02:26:54 +00001170 /* See if they want to pipe the output. */
1171 if (outfname[0] == '|' || outfname[0] == '!') {
1172 /*
1173 * We can't do the <outfname>.PID funny business
1174 * when using popen, so prohibit it.
1175 */
Denys Vlasenko7dd23382011-06-22 13:03:56 +02001176 if (followfork > 1)
1177 error_msg_and_die("Piping the output and -ff are mutually exclusive");
1178 outf = strace_popen(outfname + 1);
Roland McGrath37b9a662003-11-07 02:26:54 +00001179 }
Denys Vlasenko3d5ed412011-06-22 13:17:16 +02001180 else if (followfork <= 1)
1181 outf = strace_fopen(outfname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001182 }
1183
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001184 if (!outfname || outfname[0] == '|' || outfname[0] == '!') {
Denys Vlasenkoa677da52012-01-24 11:31:51 +01001185 char *buf = malloc(BUFSIZ);
1186 if (!buf)
1187 die_out_of_memory();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001188 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001189 }
Roland McGrath37b9a662003-11-07 02:26:54 +00001190 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001191 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001192 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +00001193 }
Wang Chaob13c0de2010-11-12 17:25:19 +08001194
Roland McGrath54cc1c82007-11-03 23:34:11 +00001195 /* Valid states here:
1196 optind < argc pflag_seen outfname interactive
1197 1 0 0 1
1198 0 1 0 1
1199 1 0 1 0
1200 0 1 1 1
1201 */
1202
1203 /* STARTUP_CHILD must be called before the signal handlers get
1204 installed below as they are inherited into the spawned process.
1205 Also we do not need to be protected by them as during interruption
1206 in the STARTUP_CHILD mode we kill the spawned process anyway. */
1207 if (!pflag_seen)
1208 startup_child(&argv[optind]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001209
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001210 sigemptyset(&empty_set);
1211 sigemptyset(&blocked_set);
1212 sa.sa_handler = SIG_IGN;
1213 sigemptyset(&sa.sa_mask);
1214 sa.sa_flags = 0;
1215 sigaction(SIGTTOU, &sa, NULL);
1216 sigaction(SIGTTIN, &sa, NULL);
1217 if (interactive) {
1218 sigaddset(&blocked_set, SIGHUP);
1219 sigaddset(&blocked_set, SIGINT);
1220 sigaddset(&blocked_set, SIGQUIT);
1221 sigaddset(&blocked_set, SIGPIPE);
1222 sigaddset(&blocked_set, SIGTERM);
1223 sa.sa_handler = interrupt;
1224#ifdef SUNOS4
1225 /* POSIX signals on sunos4.1 are a little broken. */
1226 sa.sa_flags = SA_INTERRUPT;
1227#endif /* SUNOS4 */
1228 }
1229 sigaction(SIGHUP, &sa, NULL);
1230 sigaction(SIGINT, &sa, NULL);
1231 sigaction(SIGQUIT, &sa, NULL);
1232 sigaction(SIGPIPE, &sa, NULL);
1233 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001234#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001235 sa.sa_handler = reaper;
1236 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +00001237#else
1238 /* Make sure SIGCHLD has the default action so that waitpid
1239 definitely works without losing track of children. The user
1240 should not have given us a bogus state to inherit, but he might
1241 have. Arguably we should detect SIG_IGN here and pass it on
1242 to children, but probably noone really needs that. */
1243 sa.sa_handler = SIG_DFL;
1244 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001245#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001246
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +00001247 if (pflag_seen || daemonized_tracer)
Roland McGrath02203312007-06-11 22:06:31 +00001248 startup_attach();
Roland McGrath02203312007-06-11 22:06:31 +00001249
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001250 if (trace() < 0)
1251 exit(1);
1252 cleanup();
Dmitry V. Levina6809652008-11-10 17:14:58 +00001253 fflush(NULL);
1254 if (exit_code > 0xff) {
1255 /* Child was killed by a signal, mimic that. */
1256 exit_code &= 0xff;
1257 signal(exit_code, SIG_DFL);
1258 raise(exit_code);
1259 /* Paranoia - what if this signal is not fatal?
1260 Exit with 128 + signo then. */
1261 exit_code += 128;
1262 }
1263 exit(exit_code);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001264}
1265
Denys Vlasenko2b60c352011-06-22 12:45:25 +02001266static void
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001267expand_tcbtab(void)
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001268{
1269 /* Allocate some more TCBs and expand the table.
1270 We don't want to relocate the TCBs because our
1271 callers have pointers and it would be a pain.
1272 So tcbtab is a table of pointers. Since we never
1273 free the TCBs, we allocate a single chunk of many. */
Denys Vlasenko18da2732011-06-22 12:41:57 +02001274 int i = tcbtabsize;
1275 struct tcb *newtcbs = calloc(tcbtabsize, sizeof(newtcbs[0]));
1276 struct tcb **newtab = realloc(tcbtab, tcbtabsize * 2 * sizeof(tcbtab[0]));
Denys Vlasenko1d46ba52011-08-31 14:00:02 +02001277 if (!newtab || !newtcbs)
1278 die_out_of_memory();
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001279 tcbtabsize *= 2;
1280 tcbtab = newtab;
Denys Vlasenko18da2732011-06-22 12:41:57 +02001281 while (i < tcbtabsize)
1282 tcbtab[i++] = newtcbs++;
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001283}
1284
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001285struct tcb *
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001286alloc_tcb(int pid, int command_options_parsed)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001287{
1288 int i;
1289 struct tcb *tcp;
1290
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001291 if (nprocs == tcbtabsize)
1292 expand_tcbtab();
1293
Roland McGrathee9d4352002-12-18 04:16:10 +00001294 for (i = 0; i < tcbtabsize; i++) {
1295 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001296 if ((tcp->flags & TCB_INUSE) == 0) {
Denys Vlasenko18da2732011-06-22 12:41:57 +02001297 memset(tcp, 0, sizeof(*tcp));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001298 tcp->pid = pid;
Denys Vlasenko381dbc22011-09-05 13:59:39 +02001299 tcp->flags = TCB_INUSE;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001300 tcp->outf = outf; /* Initialise to current out file */
Dmitry V. Levina5a839a2011-12-23 00:50:49 +00001301#if SUPPORTED_PERSONALITIES > 1
1302 tcp->currpers = current_personality;
1303#endif
Denys Vlasenko8dc0c8c2011-08-20 13:44:56 +02001304#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001305 tcp->pfd = -1;
Denys Vlasenko8dc0c8c2011-08-20 13:44:56 +02001306#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001307 nprocs++;
Denys Vlasenko1d5f12e2011-06-24 16:41:35 +02001308 if (debug)
1309 fprintf(stderr, "new tcb for pid %d, active tcbs:%d\n", tcp->pid, nprocs);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001310 if (command_options_parsed)
1311 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001312 return tcp;
1313 }
1314 }
Denys Vlasenko18da2732011-06-22 12:41:57 +02001315 error_msg_and_die("bug in alloc_tcb");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001316}
1317
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001318#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001319int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001320proc_open(struct tcb *tcp, int attaching)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001321{
1322 char proc[32];
1323 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001324#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +00001325 int i;
1326 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001327 sigset_t signals;
1328 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001329#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001330#ifndef HAVE_POLLABLE_PROCFS
1331 static int last_pfd;
1332#endif
1333
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001334#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001335 /* Open the process pseudo-files in /proc. */
1336 sprintf(proc, "/proc/%d/ctl", tcp->pid);
Denys Vlasenko5d645812011-08-20 12:48:18 +02001337 tcp->pfd = open(proc, O_WRONLY|O_EXCL);
1338 if (tcp->pfd < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001339 perror("strace: open(\"/proc/...\", ...)");
1340 return -1;
1341 }
Denys Vlasenko1f532ab2011-06-22 13:11:23 +02001342 set_cloexec_flag(tcp->pfd);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001343 sprintf(proc, "/proc/%d/status", tcp->pid);
Denys Vlasenko5d645812011-08-20 12:48:18 +02001344 tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL);
1345 if (tcp->pfd_stat < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001346 perror("strace: open(\"/proc/...\", ...)");
1347 return -1;
1348 }
Denys Vlasenko1f532ab2011-06-22 13:11:23 +02001349 set_cloexec_flag(tcp->pfd_stat);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001350 sprintf(proc, "/proc/%d/as", tcp->pid);
Denys Vlasenko5d645812011-08-20 12:48:18 +02001351 tcp->pfd_as = open(proc, O_RDONLY|O_EXCL);
1352 if (tcp->pfd_as < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001353 perror("strace: open(\"/proc/...\", ...)");
1354 return -1;
1355 }
Denys Vlasenko1f532ab2011-06-22 13:11:23 +02001356 set_cloexec_flag(tcp->pfd_as);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001357#else
1358 /* Open the process pseudo-file in /proc. */
Denys Vlasenko0890c8a2011-08-21 00:10:45 +02001359# ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001360 sprintf(proc, "/proc/%d", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001361 tcp->pfd = open(proc, O_RDWR|O_EXCL);
Denys Vlasenko0890c8a2011-08-21 00:10:45 +02001362# else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001363 sprintf(proc, "/proc/%d/mem", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001364 tcp->pfd = open(proc, O_RDWR);
Denys Vlasenko0890c8a2011-08-21 00:10:45 +02001365# endif
Andreas Schwab372cc842010-07-09 11:49:27 +02001366 if (tcp->pfd < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001367 perror("strace: open(\"/proc/...\", ...)");
1368 return -1;
1369 }
Denys Vlasenko1f532ab2011-06-22 13:11:23 +02001370 set_cloexec_flag(tcp->pfd);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001371#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001372#ifdef FREEBSD
1373 sprintf(proc, "/proc/%d/regs", tcp->pid);
Denys Vlasenko5d645812011-08-20 12:48:18 +02001374 tcp->pfd_reg = open(proc, O_RDONLY);
1375 if (tcp->pfd_reg < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001376 perror("strace: open(\"/proc/.../regs\", ...)");
1377 return -1;
1378 }
1379 if (cflag) {
1380 sprintf(proc, "/proc/%d/status", tcp->pid);
Denys Vlasenko5d645812011-08-20 12:48:18 +02001381 tcp->pfd_status = open(proc, O_RDONLY);
1382 if (tcp->pfd_status < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001383 perror("strace: open(\"/proc/.../status\", ...)");
1384 return -1;
1385 }
1386 } else
1387 tcp->pfd_status = -1;
1388#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001389 rebuild_pollv();
1390 if (!attaching) {
1391 /*
1392 * Wait for the child to pause. Because of a race
1393 * condition we have to poll for the event.
1394 */
1395 for (;;) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001396 if (IOCTL_STATUS(tcp) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001397 perror("strace: PIOCSTATUS");
1398 return -1;
1399 }
1400 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001401 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001402 }
1403 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001404#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001405 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001406 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001407 perror("strace: PIOCSTOP");
1408 return -1;
1409 }
Roland McGrath553a6092002-12-16 20:40:39 +00001410#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001411#ifdef PIOCSET
1412 /* Set Run-on-Last-Close. */
1413 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001414 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001415 perror("PIOCSET PR_RLC");
1416 return -1;
1417 }
1418 /* Set or Reset Inherit-on-Fork. */
1419 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001420 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001421 perror("PIOC{SET,RESET} PR_FORK");
1422 return -1;
1423 }
1424#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +00001425#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001426 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
1427 perror("PIOCSRLC");
1428 return -1;
1429 }
1430 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
1431 perror("PIOC{S,R}FORK");
1432 return -1;
1433 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001434#else /* FREEBSD */
1435 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
1436 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
1437 perror("PIOCGFL");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001438 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001439 }
1440 arg &= ~PF_LINGER;
1441 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001442 perror("PIOCSFL");
1443 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001444 }
1445#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001446#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001447#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +00001448 /* Enable all syscall entries we care about. */
1449 premptyset(&syscalls);
1450 for (i = 1; i < MAX_QUALS; ++i) {
1451 if (i > (sizeof syscalls) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001452 if (qual_flags[i] & QUAL_TRACE) praddset(&syscalls, i);
John Hughes19e49982001-10-19 08:59:12 +00001453 }
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001454 praddset(&syscalls, SYS_execve);
John Hughes19e49982001-10-19 08:59:12 +00001455 if (followfork) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001456 praddset(&syscalls, SYS_fork);
John Hughes19e49982001-10-19 08:59:12 +00001457#ifdef SYS_forkall
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001458 praddset(&syscalls, SYS_forkall);
John Hughes19e49982001-10-19 08:59:12 +00001459#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001460#ifdef SYS_fork1
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001461 praddset(&syscalls, SYS_fork1);
John Hughes19e49982001-10-19 08:59:12 +00001462#endif
1463#ifdef SYS_rfork1
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001464 praddset(&syscalls, SYS_rfork1);
John Hughes19e49982001-10-19 08:59:12 +00001465#endif
1466#ifdef SYS_rforkall
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001467 praddset(&syscalls, SYS_rforkall);
John Hughes19e49982001-10-19 08:59:12 +00001468#endif
1469 }
1470 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001471 perror("PIOCSENTRY");
1472 return -1;
1473 }
John Hughes19e49982001-10-19 08:59:12 +00001474 /* Enable the syscall exits. */
1475 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001476 perror("PIOSEXIT");
1477 return -1;
1478 }
John Hughes19e49982001-10-19 08:59:12 +00001479 /* Enable signals we care about. */
1480 premptyset(&signals);
1481 for (i = 1; i < MAX_QUALS; ++i) {
1482 if (i > (sizeof signals) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001483 if (qual_flags[i] & QUAL_SIGNAL) praddset(&signals, i);
John Hughes19e49982001-10-19 08:59:12 +00001484 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001485 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001486 perror("PIOCSTRACE");
1487 return -1;
1488 }
John Hughes19e49982001-10-19 08:59:12 +00001489 /* Enable faults we care about */
1490 premptyset(&faults);
1491 for (i = 1; i < MAX_QUALS; ++i) {
1492 if (i > (sizeof faults) * CHAR_BIT) break;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001493 if (qual_flags[i] & QUAL_FAULT) praddset(&faults, i);
John Hughes19e49982001-10-19 08:59:12 +00001494 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001495 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001496 perror("PIOCSFAULT");
1497 return -1;
1498 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001499#else /* FREEBSD */
1500 /* set events flags. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001501 arg = S_SIG | S_SCE | S_SCX;
1502 if (ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001503 perror("PIOCBIS");
1504 return -1;
1505 }
1506#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001507 if (!attaching) {
1508#ifdef MIPS
1509 /*
1510 * The SGI PRSABORT doesn't work for pause() so
1511 * we send it a caught signal to wake it up.
1512 */
1513 kill(tcp->pid, SIGINT);
1514#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +00001515#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001516 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001517 arg = PRSABORT;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001518 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001519 perror("PIOCRUN");
1520 return -1;
1521 }
Roland McGrath553a6092002-12-16 20:40:39 +00001522#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001523#endif /* !MIPS*/
1524#ifdef FREEBSD
1525 /* wake up the child if it received the SIGSTOP */
1526 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001527#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001528 for (;;) {
1529 /* Wait for the child to do something. */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001530 if (IOCTL_WSTOP(tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001531 perror("PIOCWSTOP");
1532 return -1;
1533 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001534 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001535 tcp->flags &= ~TCB_INSYSCALL;
Denys Vlasenko06602d92011-08-24 17:53:52 +02001536 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001537 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001538 break;
1539 }
1540 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001541#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001542 arg = 0;
Denys Vlasenko0890c8a2011-08-21 00:10:45 +02001543 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0)
1544#else
1545 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0)
1546#endif
1547 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001548 perror("PIOCRUN");
1549 return -1;
1550 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001551#ifdef FREEBSD
1552 /* handle the case where we "opened" the child before
1553 it did the kill -STOP */
1554 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1555 tcp->status.PR_WHAT == SIGSTOP)
1556 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001557#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001558 }
1559 }
Denys Vlasenko0890c8a2011-08-21 00:10:45 +02001560#ifdef FREEBSD
1561 else {
Roland McGrath553a6092002-12-16 20:40:39 +00001562 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001563 /* We are attaching to an already running process.
1564 * Try to figure out the state of the process in syscalls,
1565 * to handle the first event well.
1566 * This is done by having a look at the "wchan" property of the
1567 * process, which tells where it is stopped (if it is). */
1568 FILE * status;
1569 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001570
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001571 sprintf(proc, "/proc/%d/status", tcp->pid);
1572 status = fopen(proc, "r");
1573 if (status &&
1574 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1575 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1576 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1577 strcmp(wchan, "stopevent")) {
1578 /* The process is asleep in the middle of a syscall.
1579 Fake the syscall entry event */
1580 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1581 tcp->status.PR_WHY = PR_SYSENTRY;
1582 trace_syscall(tcp);
1583 }
1584 if (status)
1585 fclose(status);
1586 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001587 }
1588#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001589#ifndef HAVE_POLLABLE_PROCFS
1590 if (proc_poll_pipe[0] != -1)
1591 proc_poller(tcp->pfd);
1592 else if (nprocs > 1) {
1593 proc_poll_open();
1594 proc_poller(last_pfd);
1595 proc_poller(tcp->pfd);
1596 }
1597 last_pfd = tcp->pfd;
1598#endif /* !HAVE_POLLABLE_PROCFS */
1599 return 0;
1600}
1601
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001602#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001603
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001604struct tcb *
Roland McGrath54e931f2010-09-14 18:59:20 -07001605pid2tcb(int pid)
1606{
1607 int i;
1608
1609 if (pid <= 0)
1610 return NULL;
1611
1612 for (i = 0; i < tcbtabsize; i++) {
1613 struct tcb *tcp = tcbtab[i];
1614 if (tcp->pid == pid && (tcp->flags & TCB_INUSE))
1615 return tcp;
1616 }
1617
1618 return NULL;
1619}
1620
1621#ifdef USE_PROCFS
1622
1623static struct tcb *
1624first_used_tcb(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001625{
1626 int i;
1627 struct tcb *tcp;
Roland McGrathee9d4352002-12-18 04:16:10 +00001628 for (i = 0; i < tcbtabsize; i++) {
1629 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001630 if (tcp->flags & TCB_INUSE)
1631 return tcp;
1632 }
1633 return NULL;
1634}
1635
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001636static struct tcb *
Denys Vlasenko12014262011-05-30 14:00:14 +02001637pfd2tcb(int pfd)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001638{
1639 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001640
Roland McGrathca16be82003-01-10 19:55:28 +00001641 for (i = 0; i < tcbtabsize; i++) {
1642 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001643 if (tcp->pfd != pfd)
1644 continue;
1645 if (tcp->flags & TCB_INUSE)
1646 return tcp;
1647 }
1648 return NULL;
1649}
1650
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001651#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001652
1653void
Denys Vlasenko12014262011-05-30 14:00:14 +02001654droptcb(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001655{
1656 if (tcp->pid == 0)
1657 return;
Denys Vlasenko19cdada2011-08-17 10:45:32 +02001658
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001659 nprocs--;
Denys Vlasenko1d5f12e2011-06-24 16:41:35 +02001660 if (debug)
1661 fprintf(stderr, "dropped tcb for pid %d, %d remain\n", tcp->pid, nprocs);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001662
Denys Vlasenko8dc0c8c2011-08-20 13:44:56 +02001663#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001664 if (tcp->pfd != -1) {
1665 close(tcp->pfd);
1666 tcp->pfd = -1;
Denys Vlasenko8dc0c8c2011-08-20 13:44:56 +02001667# ifdef FREEBSD
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001668 if (tcp->pfd_reg != -1) {
1669 close(tcp->pfd_reg);
1670 tcp->pfd_reg = -1;
1671 }
1672 if (tcp->pfd_status != -1) {
1673 close(tcp->pfd_status);
1674 tcp->pfd_status = -1;
1675 }
Denys Vlasenko8dc0c8c2011-08-20 13:44:56 +02001676# endif
Denys Vlasenko19cdada2011-08-17 10:45:32 +02001677 tcp->flags = 0; /* rebuild_pollv needs it */
1678 rebuild_pollv();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001679 }
Denys Vlasenko8dc0c8c2011-08-20 13:44:56 +02001680#endif
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001681
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001682 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001683 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001684
Denys Vlasenko19cdada2011-08-17 10:45:32 +02001685 memset(tcp, 0, sizeof(*tcp));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001686}
1687
Roland McGrath0a463882007-07-05 18:43:16 +00001688/* detach traced process; continue with sig
1689 Never call DETACH twice on the same process as both unattached and
1690 attached-unstopped processes give the same ESRCH. For unattached process we
1691 would SIGSTOP it and wait for its SIGSTOP notification forever. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001692
1693static int
Denys Vlasenko4c196382012-01-04 15:11:09 +01001694detach(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001695{
1696 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001697#ifdef LINUX
Roland McGrath1bfd3102007-08-03 10:02:00 +00001698 int status, catch_sigstop;
Roland McGrathca16be82003-01-10 19:55:28 +00001699#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001700
1701 if (tcp->flags & TCB_BPTSET)
Andreas Schwab840d85b2010-01-12 11:16:32 +01001702 clearbpt(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001703
1704#ifdef LINUX
1705 /*
1706 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001707 * before detaching. Arghh. We go through hoops
1708 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001709 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001710#if defined(SPARC)
1711#undef PTRACE_DETACH
1712#define PTRACE_DETACH PTRACE_SUNDETACH
1713#endif
Roland McGrath02203312007-06-11 22:06:31 +00001714 /*
Denys Vlasenkof88837a2011-09-05 14:05:46 +02001715 * We did PTRACE_ATTACH but possibly didn't see the expected SIGSTOP.
1716 * We must catch exactly one as otherwise the detached process
1717 * would be left stopped (process state T).
Roland McGrath02203312007-06-11 22:06:31 +00001718 */
Denys Vlasenkof88837a2011-09-05 14:05:46 +02001719 catch_sigstop = (tcp->flags & TCB_IGNORE_ONE_SIGSTOP);
Denys Vlasenko4c196382012-01-04 15:11:09 +01001720 error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, 0);
Denys Vlasenko5d645812011-08-20 12:48:18 +02001721 if (error == 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001722 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001723 }
1724 else if (errno != ESRCH) {
1725 /* Shouldn't happen. */
1726 perror("detach: ptrace(PTRACE_DETACH, ...)");
1727 }
Denys Vlasenko44f87ef2011-08-17 15:18:21 +02001728 else if (my_tkill(tcp->pid, 0) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001729 if (errno != ESRCH)
1730 perror("detach: checking sanity");
1731 }
Denys Vlasenko44f87ef2011-08-17 15:18:21 +02001732 else if (!catch_sigstop && my_tkill(tcp->pid, SIGSTOP) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001733 if (errno != ESRCH)
1734 perror("detach: stopping child");
1735 }
Roland McGrath02203312007-06-11 22:06:31 +00001736 else
1737 catch_sigstop = 1;
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001738 if (catch_sigstop) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001739 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001740#ifdef __WALL
1741 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1742 if (errno == ECHILD) /* Already gone. */
1743 break;
1744 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001745 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001746 break;
1747 }
1748#endif /* __WALL */
1749 /* No __WALL here. */
1750 if (waitpid(tcp->pid, &status, 0) < 0) {
1751 if (errno != ECHILD) {
1752 perror("detach: waiting");
1753 break;
1754 }
1755#ifdef __WCLONE
1756 /* If no processes, try clones. */
1757 if (wait4(tcp->pid, &status, __WCLONE,
1758 NULL) < 0) {
1759 if (errno != ECHILD)
1760 perror("detach: waiting");
1761 break;
1762 }
1763#endif /* __WCLONE */
1764 }
1765#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001766 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001767#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001768 if (!WIFSTOPPED(status)) {
1769 /* Au revoir, mon ami. */
1770 break;
1771 }
1772 if (WSTOPSIG(status) == SIGSTOP) {
Denys Vlasenko4c196382012-01-04 15:11:09 +01001773 ptrace_restart(PTRACE_DETACH, tcp, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001774 break;
1775 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001776 error = ptrace_restart(PTRACE_CONT, tcp,
Denys Vlasenko75422762011-05-27 14:36:01 +02001777 WSTOPSIG(status) == syscall_trap_sig ? 0
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001778 : WSTOPSIG(status));
1779 if (error < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001780 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001781 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001782 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001783#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001784
1785#if defined(SUNOS4)
1786 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
Denys Vlasenko4c196382012-01-04 15:11:09 +01001787 error = ptrace_restart(PTRACE_DETACH, tcp, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001788#endif /* SUNOS4 */
1789
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001790 if (!qflag)
1791 fprintf(stderr, "Process %u detached\n", tcp->pid);
1792
1793 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001794
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001795 return error;
1796}
1797
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001798#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001799
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001800static void reaper(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001801{
1802 int pid;
1803 int status;
1804
1805 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001806 }
1807}
1808
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001809#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001810
1811static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001812cleanup(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001813{
1814 int i;
1815 struct tcb *tcp;
1816
Roland McGrathee9d4352002-12-18 04:16:10 +00001817 for (i = 0; i < tcbtabsize; i++) {
1818 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001819 if (!(tcp->flags & TCB_INUSE))
1820 continue;
1821 if (debug)
1822 fprintf(stderr,
1823 "cleanup: looking at pid %u\n", tcp->pid);
1824 if (tcp_last &&
1825 (!outfname || followfork < 2 || tcp_last == tcp)) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001826 tprints(" <unfinished ...>");
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001827 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001828 }
1829 if (tcp->flags & TCB_ATTACHED)
Denys Vlasenko4c196382012-01-04 15:11:09 +01001830 detach(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001831 else {
1832 kill(tcp->pid, SIGCONT);
1833 kill(tcp->pid, SIGTERM);
1834 }
1835 }
1836 if (cflag)
1837 call_summary(outf);
1838}
1839
1840static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001841interrupt(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001842{
1843 interrupted = 1;
1844}
1845
1846#ifndef HAVE_STRERROR
1847
Roland McGrath6d2b3492002-12-30 00:51:30 +00001848#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001849extern int sys_nerr;
1850extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001851#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001852
1853const char *
Denys Vlasenko12014262011-05-30 14:00:14 +02001854strerror(int err_no)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001855{
1856 static char buf[64];
1857
Denys Vlasenko35aba6a2011-05-25 15:33:26 +02001858 if (err_no < 1 || err_no >= sys_nerr) {
1859 sprintf(buf, "Unknown error %d", err_no);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001860 return buf;
1861 }
Denys Vlasenko35aba6a2011-05-25 15:33:26 +02001862 return sys_errlist[err_no];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001863}
1864
1865#endif /* HAVE_STERRROR */
1866
1867#ifndef HAVE_STRSIGNAL
1868
Roland McGrath8f474e02003-01-14 07:53:33 +00001869#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001870extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001871#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001872#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1873extern char *_sys_siglist[];
1874#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001875
1876const char *
Denys Vlasenko12014262011-05-30 14:00:14 +02001877strsignal(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001878{
1879 static char buf[64];
1880
1881 if (sig < 1 || sig >= NSIG) {
1882 sprintf(buf, "Unknown signal %d", sig);
1883 return buf;
1884 }
1885#ifdef HAVE__SYS_SIGLIST
1886 return _sys_siglist[sig];
1887#else
1888 return sys_siglist[sig];
1889#endif
1890}
1891
1892#endif /* HAVE_STRSIGNAL */
1893
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001894#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001895
1896static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001897rebuild_pollv(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001898{
1899 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001900
Denys Vlasenkocfd364b2011-08-20 13:41:13 +02001901 free(pollv);
1902 pollv = malloc(nprocs * sizeof(pollv[0]));
Denys Vlasenko1d46ba52011-08-31 14:00:02 +02001903 if (!pollv)
1904 die_out_of_memory();
Roland McGrathee9d4352002-12-18 04:16:10 +00001905
Roland McGrathca16be82003-01-10 19:55:28 +00001906 for (i = j = 0; i < tcbtabsize; i++) {
1907 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001908 if (!(tcp->flags & TCB_INUSE))
1909 continue;
1910 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001911 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001912 j++;
1913 }
1914 if (j != nprocs) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001915 error_msg_and_die("proc miscount");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001916 }
1917}
1918
1919#ifndef HAVE_POLLABLE_PROCFS
1920
1921static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001922proc_poll_open(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001923{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001924 int i;
1925
1926 if (pipe(proc_poll_pipe) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001927 perror_msg_and_die("pipe");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001928 }
1929 for (i = 0; i < 2; i++) {
Denys Vlasenko1f532ab2011-06-22 13:11:23 +02001930 set_cloexec_flag(proc_poll_pipe[i]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001931 }
1932}
1933
1934static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001935proc_poll(struct pollfd *pollv, int nfds, int timeout)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001936{
1937 int i;
1938 int n;
1939 struct proc_pollfd pollinfo;
1940
Denys Vlasenko5d645812011-08-20 12:48:18 +02001941 n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo));
1942 if (n < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001943 return n;
1944 if (n != sizeof(struct proc_pollfd)) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001945 error_msg_and_die("panic: short read: %d", n);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001946 }
1947 for (i = 0; i < nprocs; i++) {
1948 if (pollv[i].fd == pollinfo.fd)
1949 pollv[i].revents = pollinfo.revents;
1950 else
1951 pollv[i].revents = 0;
1952 }
1953 poller_pid = pollinfo.pid;
1954 return 1;
1955}
1956
1957static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001958wakeup_handler(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001959{
1960}
1961
1962static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001963proc_poller(int pfd)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001964{
1965 struct proc_pollfd pollinfo;
1966 struct sigaction sa;
1967 sigset_t blocked_set, empty_set;
1968 int i;
1969 int n;
1970 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001971#ifdef FREEBSD
1972 struct procfs_status pfs;
1973#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001974
1975 switch (fork()) {
1976 case -1:
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02001977 perror_msg_and_die("fork");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001978 case 0:
1979 break;
1980 default:
1981 return;
1982 }
1983
1984 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1985 sa.sa_flags = 0;
1986 sigemptyset(&sa.sa_mask);
1987 sigaction(SIGHUP, &sa, NULL);
1988 sigaction(SIGINT, &sa, NULL);
1989 sigaction(SIGQUIT, &sa, NULL);
1990 sigaction(SIGPIPE, &sa, NULL);
1991 sigaction(SIGTERM, &sa, NULL);
1992 sa.sa_handler = wakeup_handler;
1993 sigaction(SIGUSR1, &sa, NULL);
1994 sigemptyset(&blocked_set);
1995 sigaddset(&blocked_set, SIGUSR1);
1996 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1997 sigemptyset(&empty_set);
1998
1999 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002000 perror_msg_and_die("getrlimit(RLIMIT_NOFILE, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002001 }
2002 n = rl.rlim_cur;
2003 for (i = 0; i < n; i++) {
2004 if (i != pfd && i != proc_poll_pipe[1])
2005 close(i);
2006 }
2007
2008 pollinfo.fd = pfd;
2009 pollinfo.pid = getpid();
2010 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002011#ifndef FREEBSD
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002012 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
2013#else
2014 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
2015#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002016 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002017 switch (errno) {
2018 case EINTR:
2019 continue;
2020 case EBADF:
2021 pollinfo.revents = POLLERR;
2022 break;
2023 case ENOENT:
2024 pollinfo.revents = POLLHUP;
2025 break;
2026 default:
2027 perror("proc_poller: PIOCWSTOP");
2028 }
2029 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2030 _exit(0);
2031 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002032 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002033 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2034 sigsuspend(&empty_set);
2035 }
2036}
2037
2038#endif /* !HAVE_POLLABLE_PROCFS */
2039
2040static int
2041choose_pfd()
2042{
2043 int i, j;
2044 struct tcb *tcp;
2045
2046 static int last;
2047
2048 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002049 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002050 /*
2051 * The previous process is ready to run again. We'll
2052 * let it do so if it is currently in a syscall. This
2053 * heuristic improves the readability of the trace.
2054 */
2055 tcp = pfd2tcb(pollv[last].fd);
Denys Vlasenkob88f9612011-08-21 18:03:23 +02002056 if (tcp && exiting(tcp))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002057 return pollv[last].fd;
2058 }
2059
2060 for (i = 0; i < nprocs; i++) {
2061 /* Let competing children run round robin. */
2062 j = (i + last + 1) % nprocs;
2063 if (pollv[j].revents & (POLLHUP | POLLERR)) {
2064 tcp = pfd2tcb(pollv[j].fd);
2065 if (!tcp) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002066 error_msg_and_die("lost proc");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002067 }
2068 droptcb(tcp);
2069 return -1;
2070 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002071 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002072 last = j;
2073 return pollv[j].fd;
2074 }
2075 }
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002076 error_msg_and_die("nothing ready");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002077}
2078
2079static int
Denys Vlasenko12014262011-05-30 14:00:14 +02002080trace(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002081{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002082#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00002083 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002084#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002085 struct tcb *tcp;
2086 int pfd;
2087 int what;
2088 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002089 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002090
2091 for (;;) {
2092 if (interactive)
2093 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2094
2095 if (nprocs == 0)
2096 break;
2097
2098 switch (nprocs) {
2099 case 1:
2100#ifndef HAVE_POLLABLE_PROCFS
2101 if (proc_poll_pipe[0] == -1) {
2102#endif
Roland McGrath54e931f2010-09-14 18:59:20 -07002103 tcp = first_used_tcb();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002104 if (!tcp)
2105 continue;
2106 pfd = tcp->pfd;
2107 if (pfd == -1)
2108 continue;
2109 break;
2110#ifndef HAVE_POLLABLE_PROCFS
2111 }
2112 /* fall through ... */
2113#endif /* !HAVE_POLLABLE_PROCFS */
2114 default:
2115#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002116#ifdef POLL_HACK
2117 /* On some systems (e.g. UnixWare) we get too much ugly
2118 "unfinished..." stuff when multiple proceses are in
2119 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00002120
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002121 if (in_syscall) {
2122 struct pollfd pv;
2123 tcp = in_syscall;
2124 in_syscall = NULL;
2125 pv.fd = tcp->pfd;
2126 pv.events = POLLWANT;
Denys Vlasenko5d645812011-08-20 12:48:18 +02002127 what = poll(&pv, 1, 1);
2128 if (what < 0) {
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002129 if (interrupted)
2130 return 0;
2131 continue;
2132 }
2133 else if (what == 1 && pv.revents & POLLWANT) {
2134 goto FOUND;
2135 }
2136 }
2137#endif
2138
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002139 if (poll(pollv, nprocs, INFTIM) < 0) {
2140 if (interrupted)
2141 return 0;
2142 continue;
2143 }
2144#else /* !HAVE_POLLABLE_PROCFS */
2145 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
2146 if (interrupted)
2147 return 0;
2148 continue;
2149 }
2150#endif /* !HAVE_POLLABLE_PROCFS */
2151 pfd = choose_pfd();
2152 if (pfd == -1)
2153 continue;
2154 break;
2155 }
2156
2157 /* Look up `pfd' in our table. */
Denys Vlasenko5d645812011-08-20 12:48:18 +02002158 tcp = pfd2tcb(pfd);
2159 if (tcp == NULL) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002160 error_msg_and_die("unknown pfd: %u", pfd);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002161 }
John Hughesb6643082002-05-23 11:02:22 +00002162#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002163 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00002164#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002165 /* Get the status of the process. */
2166 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002167#ifndef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002168 ioctl_result = IOCTL_WSTOP(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002169#else /* FREEBSD */
2170 /* Thanks to some scheduling mystery, the first poller
2171 sometimes waits for the already processed end of fork
2172 event. Doing a non blocking poll here solves the problem. */
2173 if (proc_poll_pipe[0] != -1)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002174 ioctl_result = IOCTL_STATUS(tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002175 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002176 ioctl_result = IOCTL_WSTOP(tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00002177#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002178 ioctl_errno = errno;
2179#ifndef HAVE_POLLABLE_PROCFS
2180 if (proc_poll_pipe[0] != -1) {
2181 if (ioctl_result < 0)
2182 kill(poller_pid, SIGKILL);
2183 else
2184 kill(poller_pid, SIGUSR1);
2185 }
2186#endif /* !HAVE_POLLABLE_PROCFS */
2187 }
2188 if (interrupted)
2189 return 0;
2190
2191 if (interactive)
2192 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2193
2194 if (ioctl_result < 0) {
2195 /* Find out what happened if it failed. */
2196 switch (ioctl_errno) {
2197 case EINTR:
2198 case EBADF:
2199 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002200#ifdef FREEBSD
2201 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00002202#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002203 case ENOENT:
2204 droptcb(tcp);
2205 continue;
2206 default:
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002207 perror_msg_and_die("PIOCWSTOP");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002208 }
2209 }
2210
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002211#ifdef FREEBSD
2212 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2213 /* discard first event for a syscall we never entered */
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002214 IOCTL(tcp->pfd, PIOCRUN, 0);
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002215 continue;
2216 }
Roland McGrath553a6092002-12-16 20:40:39 +00002217#endif
2218
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002219 /* clear the just started flag */
2220 tcp->flags &= ~TCB_STARTUP;
2221
2222 /* set current output file */
2223 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002224 curcol = tcp->curcol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002225
2226 if (cflag) {
2227 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002228#ifdef FREEBSD
2229 char buf[1024];
2230 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002231
Denys Vlasenko5d645812011-08-20 12:48:18 +02002232 len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0);
2233 if (len > 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002234 buf[len] = '\0';
2235 sscanf(buf,
2236 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2237 &stime.tv_sec, &stime.tv_usec);
2238 } else
2239 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002240#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002241 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2242 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002243#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002244 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2245 tcp->stime = stime;
2246 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002247 what = tcp->status.PR_WHAT;
2248 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002249#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002250 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002251 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2252 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002253 if (trace_syscall(tcp) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002254 error_msg_and_die("syscall trouble");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002255 }
2256 }
2257 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002258#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002259 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002260#ifdef POLL_HACK
2261 in_syscall = tcp;
2262#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002263 case PR_SYSEXIT:
2264 if (trace_syscall(tcp) < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002265 error_msg_and_die("syscall trouble");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002266 }
2267 break;
2268 case PR_SIGNALLED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002269 if (cflag != CFLAG_ONLY_STATS
2270 && (qual_flags[what] & QUAL_SIGNAL)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002271 printleader(tcp);
2272 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002273 signame(what), strsignal(what));
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002274 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002275#ifdef PR_INFO
2276 if (tcp->status.PR_INFO.si_signo == what) {
2277 printleader(tcp);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002278 tprints(" siginfo=");
John Hughes58265892001-10-18 15:13:53 +00002279 printsiginfo(&tcp->status.PR_INFO, 1);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002280 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002281 }
2282#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002283 }
2284 break;
2285 case PR_FAULTED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002286 if (cflag != CFLAGS_ONLY_STATS
2287 && (qual_flags[what] & QUAL_FAULT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002288 printleader(tcp);
2289 tprintf("=== FAULT %d ===", what);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002290 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002291 }
2292 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002293#ifdef FREEBSD
2294 case 0: /* handle case we polled for nothing */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002295 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00002296#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002297 default:
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002298 error_msg_and_die("odd stop %d", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002299 break;
2300 }
Andreas Schwabccdff482009-10-27 16:27:13 +01002301 /* Remember current print column before continuing. */
2302 tcp->curcol = curcol;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002303 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002304#ifndef FREEBSD
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002305 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002306#else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02002307 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002308#endif
Andreas Schwab372cc842010-07-09 11:49:27 +02002309 {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002310 perror_msg_and_die("PIOCRUN");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002311 }
2312 }
2313 return 0;
2314}
2315
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002316#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002317
Roland McGratheb9e2e82009-06-02 16:49:22 -07002318static int
2319trace()
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002320{
2321 int pid;
2322 int wait_errno;
Denys Vlasenko6cda73f2011-09-02 16:23:53 +02002323 int status, sig;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002324 struct tcb *tcp;
2325#ifdef LINUX
2326 struct rusage ru;
Denys Vlasenko26d1b1e2011-08-15 12:24:14 +02002327 struct rusage *rup = cflag ? &ru : NULL;
2328# ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002329 static int wait4_options = __WALL;
Denys Vlasenko26d1b1e2011-08-15 12:24:14 +02002330# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002331#endif /* LINUX */
2332
Roland McGratheb9e2e82009-06-02 16:49:22 -07002333 while (nprocs != 0) {
Denys Vlasenko222713a2009-03-17 14:29:59 +00002334 if (interrupted)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002335 return 0;
2336 if (interactive)
2337 sigprocmask(SIG_SETMASK, &empty_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002338#ifdef LINUX
Denys Vlasenko26d1b1e2011-08-15 12:24:14 +02002339# ifdef __WALL
2340 pid = wait4(-1, &status, wait4_options, rup);
Roland McGrath5bc05552002-12-17 04:50:47 +00002341 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002342 /* this kernel does not support __WALL */
2343 wait4_options &= ~__WALL;
Denys Vlasenko26d1b1e2011-08-15 12:24:14 +02002344 pid = wait4(-1, &status, wait4_options, rup);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002345 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002346 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002347 /* most likely a "cloned" process */
Denys Vlasenko26d1b1e2011-08-15 12:24:14 +02002348 pid = wait4(-1, &status, __WCLONE, rup);
2349 if (pid < 0) {
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002350 perror_msg("wait4(__WCLONE) failed");
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002351 }
2352 }
Denys Vlasenko26d1b1e2011-08-15 12:24:14 +02002353# else
2354 pid = wait4(-1, &status, 0, rup);
2355# endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002356#endif /* LINUX */
2357#ifdef SUNOS4
2358 pid = wait(&status);
Denys Vlasenko26d1b1e2011-08-15 12:24:14 +02002359#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002360 wait_errno = errno;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002361 if (interactive)
2362 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002363
Denys Vlasenko26d1b1e2011-08-15 12:24:14 +02002364 if (pid < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002365 switch (wait_errno) {
2366 case EINTR:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002367 continue;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002368 case ECHILD:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002369 /*
2370 * We would like to verify this case
2371 * but sometimes a race in Solbourne's
2372 * version of SunOS sometimes reports
2373 * ECHILD before sending us SIGCHILD.
2374 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002375 return 0;
2376 default:
2377 errno = wait_errno;
2378 perror("strace: wait");
2379 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002380 }
2381 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002382 if (pid == popen_pid) {
2383 if (WIFEXITED(status) || WIFSIGNALED(status))
Denys Vlasenko7dd23382011-06-22 13:03:56 +02002384 popen_pid = 0;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002385 continue;
2386 }
Denys Vlasenko1d5f12e2011-06-24 16:41:35 +02002387 if (debug) {
2388 char buf[sizeof("WIFEXITED,exitcode=%u") + sizeof(int)*3 /*paranoia:*/ + 16];
2389#ifdef LINUX
2390 unsigned ev = (unsigned)status >> 16;
2391 if (ev) {
2392 static const char *const event_names[] = {
2393 [PTRACE_EVENT_CLONE] = "CLONE",
2394 [PTRACE_EVENT_FORK] = "FORK",
2395 [PTRACE_EVENT_VFORK] = "VFORK",
2396 [PTRACE_EVENT_VFORK_DONE] = "VFORK_DONE",
2397 [PTRACE_EVENT_EXEC] = "EXEC",
2398 [PTRACE_EVENT_EXIT] = "EXIT",
2399 };
2400 const char *e;
2401 if (ev < ARRAY_SIZE(event_names))
2402 e = event_names[ev];
2403 else {
2404 sprintf(buf, "?? (%u)", ev);
2405 e = buf;
2406 }
2407 fprintf(stderr, " PTRACE_EVENT_%s", e);
2408 }
2409#endif
2410 strcpy(buf, "???");
2411 if (WIFSIGNALED(status))
2412#ifdef WCOREDUMP
2413 sprintf(buf, "WIFSIGNALED,%ssig=%s",
2414 WCOREDUMP(status) ? "core," : "",
2415 signame(WTERMSIG(status)));
2416#else
2417 sprintf(buf, "WIFSIGNALED,sig=%s",
2418 signame(WTERMSIG(status)));
2419#endif
2420 if (WIFEXITED(status))
2421 sprintf(buf, "WIFEXITED,exitcode=%u", WEXITSTATUS(status));
2422 if (WIFSTOPPED(status))
2423 sprintf(buf, "WIFSTOPPED,sig=%s", signame(WSTOPSIG(status)));
Denys Vlasenko5bd67c82011-08-15 11:36:09 +02002424#ifdef WIFCONTINUED
Denys Vlasenko1d5f12e2011-06-24 16:41:35 +02002425 if (WIFCONTINUED(status))
2426 strcpy(buf, "WIFCONTINUED");
Denys Vlasenko5bd67c82011-08-15 11:36:09 +02002427#endif
Denys Vlasenko1d5f12e2011-06-24 16:41:35 +02002428 fprintf(stderr, " [wait(0x%04x) = %u] %s\n", status, pid, buf);
2429 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002430
2431 /* Look up `pid' in our table. */
Denys Vlasenko5d645812011-08-20 12:48:18 +02002432 tcp = pid2tcb(pid);
2433 if (tcp == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002434#ifdef LINUX
Roland McGrath41c48222008-07-18 00:25:10 +00002435 if (followfork) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002436 /* This is needed to go with the CLONE_PTRACE
2437 changes in process.c/util.c: we might see
2438 the child's initial trap before we see the
2439 parent return from the clone syscall.
2440 Leave the child suspended until the parent
2441 returns from its system call. Only then
2442 will we have the association of parent and
2443 child so that we know how to do clearbpt
2444 in the child. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +00002445 tcp = alloctcb(pid);
Denys Vlasenkof88837a2011-09-05 14:05:46 +02002446 tcp->flags |= TCB_ATTACHED | TCB_STARTUP | TCB_IGNORE_ONE_SIGSTOP;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002447 if (!qflag)
Denys Vlasenko833fb132011-08-17 11:30:56 +02002448 fprintf(stderr, "Process %d attached\n",
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002449 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002450 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002451 else
2452 /* This can happen if a clone call used
2453 CLONE_PTRACE itself. */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002454#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002455 {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002456 if (WIFSTOPPED(status))
2457 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
Denys Vlasenkocb2ad002011-06-23 13:05:29 +02002458 error_msg_and_die("Unknown pid: %u", pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002459 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002460 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002461 /* set current output file */
2462 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002463 curcol = tcp->curcol;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002464#ifdef LINUX
Denys Vlasenko13d22f12011-06-24 23:01:57 +02002465 if (cflag) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002466 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2467 tcp->stime = ru.ru_stime;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002468 }
Denys Vlasenko13d22f12011-06-24 23:01:57 +02002469#endif
Roland McGratheb9e2e82009-06-02 16:49:22 -07002470
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002471 if (WIFSIGNALED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002472 if (pid == strace_child)
2473 exit_code = 0x100 | WTERMSIG(status);
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002474 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002475 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2476 printleader(tcp);
Denys Vlasenko13d22f12011-06-24 23:01:57 +02002477#ifdef WCOREDUMP
Roland McGrath2efe8792004-01-13 09:59:45 +00002478 tprintf("+++ killed by %s %s+++",
2479 signame(WTERMSIG(status)),
Denys Vlasenko13d22f12011-06-24 23:01:57 +02002480 WCOREDUMP(status) ? "(core dumped) " : "");
2481#else
2482 tprintf("+++ killed by %s +++",
2483 signame(WTERMSIG(status)));
Roland McGrath2efe8792004-01-13 09:59:45 +00002484#endif
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002485 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002486 }
Denys Vlasenko5e09d772012-01-18 16:20:56 +01002487 fflush(tcp->outf);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002488 droptcb(tcp);
2489 continue;
2490 }
2491 if (WIFEXITED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002492 if (pid == strace_child)
2493 exit_code = WEXITSTATUS(status);
Roland McGrath0a396902003-06-10 03:05:53 +00002494 if (tcp == tcp_last) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002495 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT)) == TCB_INSYSCALL)
Roland McGrath0a396902003-06-10 03:05:53 +00002496 tprintf(" <unfinished ... exit status %d>\n",
2497 WEXITSTATUS(status));
2498 tcp_last = NULL;
2499 }
Denys Vlasenko19cdada2011-08-17 10:45:32 +02002500 if (!cflag /* && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL) */ ) {
2501 printleader(tcp);
2502 tprintf("+++ exited with %d +++", WEXITSTATUS(status));
2503 printtrailer();
2504 }
Denys Vlasenko5e09d772012-01-18 16:20:56 +01002505 fflush(tcp->outf);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002506 droptcb(tcp);
2507 continue;
2508 }
2509 if (!WIFSTOPPED(status)) {
2510 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2511 droptcb(tcp);
2512 continue;
2513 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002514
Denys Vlasenkof88837a2011-09-05 14:05:46 +02002515 /* Is this the very first time we see this tracee stopped? */
2516 if (tcp->flags & TCB_STARTUP) {
2517 if (debug)
2518 fprintf(stderr, "pid %d has TCB_STARTUP, initializing it\n", tcp->pid);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002519 tcp->flags &= ~TCB_STARTUP;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002520 if (tcp->flags & TCB_BPTSET) {
Roland McGrath02203312007-06-11 22:06:31 +00002521 /*
2522 * One example is a breakpoint inherited from
Denys Vlasenko2ecba322011-08-21 17:35:39 +02002523 * parent through fork().
Roland McGrath02203312007-06-11 22:06:31 +00002524 */
Denys Vlasenko6cda73f2011-09-02 16:23:53 +02002525 if (clearbpt(tcp) < 0) {
2526 /* Pretty fatal */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002527 droptcb(tcp);
2528 cleanup();
2529 return -1;
2530 }
2531 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002532#ifdef LINUX
Denys Vlasenko44f87ef2011-08-17 15:18:21 +02002533 if (ptrace_setoptions) {
2534 if (debug)
2535 fprintf(stderr, "setting opts %x on pid %d\n", ptrace_setoptions, tcp->pid);
2536 if (ptrace(PTRACE_SETOPTIONS, tcp->pid, NULL, ptrace_setoptions) < 0) {
2537 if (errno != ESRCH) {
2538 /* Should never happen, really */
2539 perror_msg_and_die("PTRACE_SETOPTIONS");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002540 }
2541 }
2542 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002543#endif
Denys Vlasenkof88837a2011-09-05 14:05:46 +02002544 }
2545
2546 if (((unsigned)status >> 16) != 0) {
2547 /* Ptrace event (we ignore all of them for now) */
2548 goto restart_tracee_with_sig_0;
2549 }
2550
2551 sig = WSTOPSIG(status);
2552
2553 /* Is this post-attach SIGSTOP?
2554 * Interestingly, the process may stop
2555 * with STOPSIG equal to some other signal
2556 * than SIGSTOP if we happend to attach
2557 * just before the process takes a signal.
2558 */
2559 if (sig == SIGSTOP && (tcp->flags & TCB_IGNORE_ONE_SIGSTOP)) {
2560 if (debug)
2561 fprintf(stderr, "ignored SIGSTOP on pid %d\n", tcp->pid);
2562 tcp->flags &= ~TCB_IGNORE_ONE_SIGSTOP;
Denys Vlasenko6cda73f2011-09-02 16:23:53 +02002563 goto restart_tracee_with_sig_0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002564 }
2565
Denys Vlasenko6cda73f2011-09-02 16:23:53 +02002566 if (sig != syscall_trap_sig) {
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002567 if (cflag != CFLAG_ONLY_STATS
Denys Vlasenko6cda73f2011-09-02 16:23:53 +02002568 && (qual_flags[sig] & QUAL_SIGNAL)) {
Dmitry V. Levinc15dfc72011-03-10 14:44:45 +00002569 siginfo_t si;
2570#if defined(PT_CR_IPSR) && defined(PT_CR_IIP)
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002571 long pc = 0;
2572 long psr = 0;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002573
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002574 upeek(tcp, PT_CR_IPSR, &psr);
2575 upeek(tcp, PT_CR_IIP, &pc);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002576
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002577# define PSR_RI 41
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002578 pc += (psr >> PSR_RI) & 0x3;
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002579# define PC_FORMAT_STR " @ %lx"
Denys Vlasenko2ecba322011-08-21 17:35:39 +02002580# define PC_FORMAT_ARG , pc
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002581#else
Denys Vlasenko2ecba322011-08-21 17:35:39 +02002582# define PC_FORMAT_STR ""
2583# define PC_FORMAT_ARG /* nothing */
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002584#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002585 printleader(tcp);
Dmitry V. Levin436d8922011-11-29 00:15:59 +00002586 if (ptrace(PTRACE_GETSIGINFO, pid, 0, (long) &si) == 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002587 tprints("--- ");
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002588 printsiginfo(&si, verbose(tcp));
2589 tprintf(" (%s)" PC_FORMAT_STR " ---",
Denys Vlasenko6cda73f2011-09-02 16:23:53 +02002590 strsignal(sig)
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002591 PC_FORMAT_ARG);
2592 } else
2593 tprintf("--- %s by %s" PC_FORMAT_STR " ---",
Denys Vlasenko6cda73f2011-09-02 16:23:53 +02002594 strsignal(sig),
2595 signame(sig)
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002596 PC_FORMAT_ARG);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002597 printtrailer();
Denys Vlasenko5e09d772012-01-18 16:20:56 +01002598 fflush(tcp->outf);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002599 }
Denys Vlasenko6cda73f2011-09-02 16:23:53 +02002600 goto restart_tracee;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002601 }
Denys Vlasenko2ecba322011-08-21 17:35:39 +02002602
2603 /* We handled quick cases, we are permitted to interrupt now. */
Roland McGrath02203312007-06-11 22:06:31 +00002604 if (interrupted)
2605 return 0;
Denys Vlasenko2ecba322011-08-21 17:35:39 +02002606
2607 /* This should be syscall entry or exit.
2608 * (Or it still can be that pesky post-execve SIGTRAP!)
2609 * Handle it.
2610 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002611 if (trace_syscall(tcp) < 0 && !tcp->ptrace_errno) {
2612 /* ptrace() failed in trace_syscall() with ESRCH.
2613 * Likely a result of process disappearing mid-flight.
2614 * Observed case: exit_group() terminating
Denys Vlasenkof1e69032012-01-04 15:15:26 +01002615 * all processes in thread group.
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002616 */
2617 if (tcp->flags & TCB_ATTACHED) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002618 if (tcp_last) {
2619 /* Do we have dangling line "syscall(param, param"?
Denys Vlasenko178de002011-06-24 22:54:25 +02002620 * Finish the line then.
Roland McGratheb9e2e82009-06-02 16:49:22 -07002621 */
2622 tcp_last->flags |= TCB_REPRINT;
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002623 tprints(" <unfinished ...>");
Roland McGratheb9e2e82009-06-02 16:49:22 -07002624 printtrailer();
Denys Vlasenko5e09d772012-01-18 16:20:56 +01002625 fflush(tcp->outf);
Roland McGratheb9e2e82009-06-02 16:49:22 -07002626 }
Denys Vlasenkof1e69032012-01-04 15:15:26 +01002627 /* We assume that ptrace error was caused by process death.
2628 * We used to detach(tcp) here, but since we no longer
2629 * implement "detach before death" policy/hack,
2630 * we can let this process to report its death to us
2631 * normally, via WIFEXITED or WIFSIGNALED wait status.
2632 */
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002633 } else {
Denys Vlasenkof1e69032012-01-04 15:15:26 +01002634 /* It's our real child (and we also trace it) */
2635 /* my_tkill(pid, SIGKILL); - why? */
2636 /* droptcb(tcp); - why? */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002637 }
2638 continue;
2639 }
Denys Vlasenko6cda73f2011-09-02 16:23:53 +02002640 restart_tracee_with_sig_0:
2641 sig = 0;
2642 restart_tracee:
Andreas Schwabccdff482009-10-27 16:27:13 +01002643 /* Remember current print column before continuing. */
2644 tcp->curcol = curcol;
Denys Vlasenko6cda73f2011-09-02 16:23:53 +02002645 if (ptrace_restart(PTRACE_SYSCALL, tcp, sig) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002646 cleanup();
2647 return -1;
2648 }
2649 }
2650 return 0;
2651}
2652
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002653#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002654
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002655void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002656tprintf(const char *fmt, ...)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002657{
2658 va_list args;
2659
Andreas Schwabe5355de2009-10-27 16:56:43 +01002660 va_start(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002661 if (outf) {
2662 int n = vfprintf(outf, fmt, args);
Andreas Schwabccdff482009-10-27 16:27:13 +01002663 if (n < 0) {
2664 if (outf != stderr)
2665 perror(outfname == NULL
2666 ? "<writing to pipe>" : outfname);
2667 } else
Roland McGrathb310a0c2003-11-06 23:41:22 +00002668 curcol += n;
2669 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002670 va_end(args);
Denys Vlasenko5940e652011-09-01 09:55:05 +02002671}
2672
2673void
2674tprints(const char *str)
2675{
2676 if (outf) {
2677 int n = fputs(str, outf);
2678 if (n >= 0) {
2679 curcol += strlen(str);
2680 return;
2681 }
2682 if (outf != stderr)
2683 perror(outfname == NULL
2684 ? "<writing to pipe>" : outfname);
2685 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002686}
2687
2688void
Denys Vlasenko12014262011-05-30 14:00:14 +02002689printleader(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002690{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002691 if (tcp_last) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002692 if (tcp_last->ptrace_errno) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002693 if (tcp_last->flags & TCB_INSYSCALL) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002694 tprints(" <unavailable>) ");
Denys Vlasenko102ec492011-08-25 01:27:59 +02002695 tabto();
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002696 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002697 tprints("= ? <unavailable>\n");
Roland McGratheb9e2e82009-06-02 16:49:22 -07002698 tcp_last->ptrace_errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002699 } else if (!outfname || followfork < 2 || tcp_last == tcp) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002700 tcp_last->flags |= TCB_REPRINT;
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002701 tprints(" <unfinished ...>\n");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002702 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002703 }
2704 curcol = 0;
2705 if ((followfork == 1 || pflag_seen > 1) && outfname)
2706 tprintf("%-5d ", tcp->pid);
2707 else if (nprocs > 1 && !outfname)
2708 tprintf("[pid %5u] ", tcp->pid);
2709 if (tflag) {
2710 char str[sizeof("HH:MM:SS")];
2711 struct timeval tv, dtv;
2712 static struct timeval otv;
2713
2714 gettimeofday(&tv, NULL);
2715 if (rflag) {
2716 if (otv.tv_sec == 0)
2717 otv = tv;
2718 tv_sub(&dtv, &tv, &otv);
2719 tprintf("%6ld.%06ld ",
2720 (long) dtv.tv_sec, (long) dtv.tv_usec);
2721 otv = tv;
2722 }
2723 else if (tflag > 2) {
2724 tprintf("%ld.%06ld ",
2725 (long) tv.tv_sec, (long) tv.tv_usec);
2726 }
2727 else {
2728 time_t local = tv.tv_sec;
2729 strftime(str, sizeof(str), "%T", localtime(&local));
2730 if (tflag > 1)
2731 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2732 else
2733 tprintf("%s ", str);
2734 }
2735 }
2736 if (iflag)
2737 printcall(tcp);
2738}
2739
2740void
Denys Vlasenko102ec492011-08-25 01:27:59 +02002741tabto(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002742{
Denys Vlasenko102ec492011-08-25 01:27:59 +02002743 if (curcol < acolumn)
Denys Vlasenko5940e652011-09-01 09:55:05 +02002744 tprints(acolumn_spaces + curcol);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002745}
2746
2747void
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002748printtrailer(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002749{
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02002750 tprints("\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002751 tcp_last = NULL;
2752}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002753
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002754#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002755
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002756int
2757mp_ioctl(int fd, int cmd, void *arg, int size)
2758{
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002759 struct iovec iov[2];
2760 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002761
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002762 iov[0].iov_base = &cmd;
2763 iov[0].iov_len = sizeof cmd;
2764 if (arg) {
2765 ++n;
2766 iov[1].iov_base = arg;
2767 iov[1].iov_len = size;
2768 }
Roland McGrath553a6092002-12-16 20:40:39 +00002769
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002770 return writev(fd, iov, n);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002771}
2772
2773#endif