blob: a1602cac058c97b7c1850c7ecd11011248d50605 [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00006 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * $Id$
31 */
32
33#include "defs.h"
34
Roland McGrath795edb12005-02-02 04:44:57 +000035#include <sys/types.h>
Denys Vlasenko3454e4b2011-05-23 21:29:03 +020036#include <stdarg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000037#include <signal.h>
38#include <errno.h>
39#include <sys/param.h>
40#include <fcntl.h>
41#include <sys/resource.h>
42#include <sys/wait.h>
43#include <sys/stat.h>
44#include <pwd.h>
45#include <grp.h>
46#include <string.h>
John Hughes19e49982001-10-19 08:59:12 +000047#include <limits.h>
Roland McGrath70b08532004-04-09 00:25:21 +000048#include <dirent.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000049
Roland McGrath134813a2007-06-02 00:07:33 +000050#ifdef LINUX
51# include <asm/unistd.h>
52# if defined __NR_tgkill
53# define my_tgkill(pid, tid, sig) syscall (__NR_tgkill, (pid), (tid), (sig))
54# elif defined __NR_tkill
55# define my_tgkill(pid, tid, sig) syscall (__NR_tkill, (tid), (sig))
56# else
57 /* kill() may choose arbitrarily the target task of the process group
58 while we later wait on a that specific TID. PID process waits become
59 TID task specific waits for a process under ptrace(2). */
60# warning "Neither tkill(2) nor tgkill(2) available, risk of strace hangs!"
61# define my_tgkill(pid, tid, sig) kill ((tid), (sig))
62# endif
63#endif
64
Wichert Akkerman7b3346b2001-10-09 23:47:38 +000065#if defined(IA64) && defined(LINUX)
66# include <asm/ptrace_offsets.h>
67#endif
68
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +000069#ifdef USE_PROCFS
70#include <poll.h>
71#endif
72
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000073#ifdef SVR4
74#include <sys/stropts.h>
Wichert Akkermanea78f0f1999-11-29 15:34:02 +000075#ifdef HAVE_MP_PROCFS
John Hughes1d08dcf2001-07-10 13:48:44 +000076#ifdef HAVE_SYS_UIO_H
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000077#include <sys/uio.h>
78#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000079#endif
John Hughes1d08dcf2001-07-10 13:48:44 +000080#endif
Denys Vlasenko96d5a762008-12-29 19:13:27 +000081extern char **environ;
Denys Vlasenko418d66a2009-01-17 01:52:54 +000082extern int optind;
83extern char *optarg;
Denys Vlasenko96d5a762008-12-29 19:13:27 +000084
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000085
Roland McGrath41c48222008-07-18 00:25:10 +000086int debug = 0, followfork = 0;
Denys Vlasenko3454e4b2011-05-23 21:29:03 +020087unsigned int ptrace_setoptions_followfork = 0;
Denys Vlasenkof8bc0652011-05-24 20:30:24 +020088unsigned int ptrace_setoptions_for_all = 0;
Denys Vlasenko3454e4b2011-05-23 21:29:03 +020089/* Which WSTOPSIG(status) value marks syscall traps? */
Denys Vlasenko75422762011-05-27 14:36:01 +020090static unsigned int syscall_trap_sig = SIGTRAP;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +000091int dtime = 0, xflag = 0, qflag = 0;
92cflag_t cflag = CFLAG_NONE;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +000093static int iflag = 0, interactive = 0, pflag_seen = 0, rflag = 0, tflag = 0;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +000094/*
95 * daemonized_tracer supports -D option.
96 * With this option, strace forks twice.
97 * Unlike normal case, with -D *grandparent* process exec's,
98 * becoming a traced process. Child exits (this prevents traced process
99 * from having children it doesn't expect to have), and grandchild
100 * attaches to grandparent similarly to strace -p PID.
101 * This allows for more transparent interaction in cases
102 * when process and its parent are communicating via signals,
103 * wait() etc. Without -D, strace process gets lodged in between,
104 * disrupting parent<->child link.
105 */
106static bool daemonized_tracer = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000107
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000108/* Sometimes we want to print only succeeding syscalls. */
109int not_failing_only = 0;
110
Grant Edwards8a082772011-04-07 20:25:40 +0000111/* Show path associated with fd arguments */
112int show_fd_path = 0;
113
114/* are we filtering traces based on paths? */
115int tracing_paths = 0;
116
Dmitry V. Levina6809652008-11-10 17:14:58 +0000117static int exit_code = 0;
118static int strace_child = 0;
Denys Vlasenko75422762011-05-27 14:36:01 +0200119static int strace_tracer_pid = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700120
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +0000121static char *username = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000122uid_t run_uid;
123gid_t run_gid;
124
125int acolumn = DEFAULT_ACOLUMN;
126int max_strlen = DEFAULT_STRLEN;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +0000127static char *outfname = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000128FILE *outf;
Andreas Schwabccdff482009-10-27 16:27:13 +0100129static int curcol;
Roland McGrathee9d4352002-12-18 04:16:10 +0000130struct tcb **tcbtab;
131unsigned int nprocs, tcbtabsize;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000132const char *progname;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700133extern char **environ;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000134
Andreas Schwabe5355de2009-10-27 16:56:43 +0100135static int detach(struct tcb *tcp, int sig);
136static int trace(void);
137static void cleanup(void);
138static void interrupt(int sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000139static sigset_t empty_set, blocked_set;
140
141#ifdef HAVE_SIG_ATOMIC_T
142static volatile sig_atomic_t interrupted;
143#else /* !HAVE_SIG_ATOMIC_T */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000144static volatile int interrupted;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000145#endif /* !HAVE_SIG_ATOMIC_T */
146
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000147#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000148
Andreas Schwabe5355de2009-10-27 16:56:43 +0100149static struct tcb *pfd2tcb(int pfd);
150static void reaper(int sig);
151static void rebuild_pollv(void);
Roland McGrathee9d4352002-12-18 04:16:10 +0000152static struct pollfd *pollv;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000153
154#ifndef HAVE_POLLABLE_PROCFS
155
Andreas Schwabe5355de2009-10-27 16:56:43 +0100156static void proc_poll_open(void);
157static void proc_poller(int pfd);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000158
159struct proc_pollfd {
160 int fd;
161 int revents;
162 int pid;
163};
164
165static int poller_pid;
166static int proc_poll_pipe[2] = { -1, -1 };
167
168#endif /* !HAVE_POLLABLE_PROCFS */
169
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000170#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000171#define POLLWANT POLLWRNORM
172#else
173#define POLLWANT POLLPRI
174#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000175#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000176
177static void
178usage(ofp, exitval)
179FILE *ofp;
180int exitval;
181{
182 fprintf(ofp, "\
Grant Edwards8a082772011-04-07 20:25:40 +0000183usage: strace [-CdDffhiqrtttTvVxxy] [-a column] [-e expr] ... [-o file]\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000184 [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n\
Grant Edwards8a082772011-04-07 20:25:40 +0000185 [-P path] [command [arg ...]]\n\
Andreas Schwabb87d30c2010-06-11 15:49:36 +0200186 or: strace -c [-D] [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000187 [command [arg ...]]\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000188-c -- count time, calls, and errors for each syscall and report summary\n\
Andreas Schwabb87d30c2010-06-11 15:49:36 +0200189-C -- like -c but also print regular output while processes are running\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000190-f -- follow forks, -ff -- with output into separate files\n\
191-F -- attempt to follow vforks, -h -- print help message\n\
192-i -- print instruction pointer at time of syscall\n\
193-q -- suppress messages about attaching, detaching, etc.\n\
194-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
195-T -- print time spent in each syscall, -V -- print version\n\
196-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
197-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
Grant Edwards8a082772011-04-07 20:25:40 +0000198-y -- print paths associated with file descriptor arguments\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000199-a column -- alignment COLUMN for printing syscall results (default %d)\n\
200-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
201 options: trace, abbrev, verbose, raw, signal, read, or write\n\
202-o file -- send trace output to FILE instead of stderr\n\
203-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
204-p pid -- trace process with process id PID, may be repeated\n\
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000205-D -- run tracer process as a detached grandchild, not as parent\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000206-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
207-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
208-u username -- run command as username handling setuid and/or setgid\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000209-E var=val -- put var=val in the environment for command\n\
210-E var -- remove var from the environment for command\n\
Grant Edwards8a082772011-04-07 20:25:40 +0000211-P path -- trace accesses to path\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000212" /* this is broken, so don't document it
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000213-z -- print only succeeding syscalls\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000214 */
215, DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000216 exit(exitval);
217}
218
Denys Vlasenko75422762011-05-27 14:36:01 +0200219static void die(void) __attribute__ ((noreturn));
220static void die(void)
221{
222 if (strace_tracer_pid == getpid()) {
223 cflag = 0;
224 cleanup();
225 }
226 exit(1);
227}
228
229static void verror_msg(int err_no, const char *fmt, va_list p)
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200230{
231 char *msg;
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200232
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200233 msg = NULL;
234 vasprintf(&msg, fmt, p);
235 if (msg) {
Denys Vlasenko75422762011-05-27 14:36:01 +0200236 fflush(NULL);
237 if (err_no)
238 fprintf(stderr, "%s: %s: %s\n", progname, msg, strerror(err_no));
239 else
240 fprintf(stderr, "%s: %s\n", progname, msg);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200241 free(msg);
242 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200243}
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200244
Denys Vlasenko75422762011-05-27 14:36:01 +0200245void error_msg(const char *fmt, ...)
246{
247 va_list p;
248 va_start(p, fmt);
249 verror_msg(0, fmt, p);
250 va_end(p);
251}
252
253void error_msg_and_die(const char *fmt, ...)
254{
255 va_list p;
256 va_start(p, fmt);
257 verror_msg(0, fmt, p);
258 die();
259}
260
261void perror_msg(const char *fmt, ...)
262{
263 va_list p;
264 va_start(p, fmt);
265 verror_msg(errno, fmt, p);
266 va_end(p);
267}
268
269void perror_msg_and_die(const char *fmt, ...)
270{
271 va_list p;
272 va_start(p, fmt);
273 verror_msg(errno, fmt, p);
274 die();
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200275}
276
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000277#ifdef SVR4
278#ifdef MIPS
279void
280foobar()
281{
282}
283#endif /* MIPS */
284#endif /* SVR4 */
285
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400286/* Glue for systems without a MMU that cannot provide fork() */
287#ifdef HAVE_FORK
288# define strace_vforked 0
289#else
290# define strace_vforked 1
291# define fork() vfork()
292#endif
293
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000294static int
295set_cloexec_flag(int fd)
296{
297 int flags, newflags;
298
299 if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
300 {
301 fprintf(stderr, "%s: fcntl F_GETFD: %s\n",
302 progname, strerror(errno));
303 return -1;
304 }
305
306 newflags = flags | FD_CLOEXEC;
307 if (flags == newflags)
308 return 0;
309
310 if (fcntl(fd, F_SETFD, newflags) < 0)
311 {
312 fprintf(stderr, "%s: fcntl F_SETFD: %s\n",
313 progname, strerror(errno));
314 return -1;
315 }
316
317 return 0;
318}
319
320/*
321 * When strace is setuid executable, we have to swap uids
322 * before and after filesystem and process management operations.
323 */
324static void
325swap_uid(void)
326{
327#ifndef SVR4
328 int euid = geteuid(), uid = getuid();
329
330 if (euid != uid && setreuid(euid, uid) < 0)
331 {
332 fprintf(stderr, "%s: setreuid: %s\n",
333 progname, strerror(errno));
334 exit(1);
335 }
336#endif
337}
338
Roland McGrath4bfa6262007-07-05 20:03:16 +0000339#if _LFS64_LARGEFILE
340# define fopen_for_output fopen64
341#else
342# define fopen_for_output fopen
343#endif
344
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000345static FILE *
346strace_fopen(const char *path, const char *mode)
347{
348 FILE *fp;
349
350 swap_uid();
Roland McGrath4bfa6262007-07-05 20:03:16 +0000351 if ((fp = fopen_for_output(path, mode)) == NULL)
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000352 fprintf(stderr, "%s: can't fopen '%s': %s\n",
353 progname, path, strerror(errno));
354 swap_uid();
355 if (fp && set_cloexec_flag(fileno(fp)) < 0)
356 {
357 fclose(fp);
358 fp = NULL;
359 }
360 return fp;
361}
362
363static int popen_pid = -1;
364
365#ifndef _PATH_BSHELL
366# define _PATH_BSHELL "/bin/sh"
367#endif
368
369/*
370 * We cannot use standard popen(3) here because we have to distinguish
371 * popen child process from other processes we trace, and standard popen(3)
372 * does not export its child's pid.
373 */
374static FILE *
375strace_popen(const char *command)
376{
377 int fds[2];
378
379 swap_uid();
380 if (pipe(fds) < 0)
381 {
382 fprintf(stderr, "%s: pipe: %s\n",
383 progname, strerror(errno));
384 swap_uid();
385 return NULL;
386 }
387
388 if (set_cloexec_flag(fds[1]) < 0)
389 {
390 close(fds[0]);
391 close(fds[1]);
392 swap_uid();
393 return NULL;
394 }
395
396 if ((popen_pid = fork()) == -1)
397 {
398 fprintf(stderr, "%s: fork: %s\n",
399 progname, strerror(errno));
400 close(fds[0]);
401 close(fds[1]);
402 swap_uid();
403 return NULL;
404 }
405
406 if (popen_pid)
407 {
408 /* parent */
409 close(fds[0]);
410 swap_uid();
411 return fdopen(fds[1], "w");
412 } else
413 {
414 /* child */
415 close(fds[1]);
416 if (fds[0] && (dup2(fds[0], 0) || close(fds[0])))
417 {
418 fprintf(stderr, "%s: dup2: %s\n",
419 progname, strerror(errno));
420 _exit(1);
421 }
422 execl(_PATH_BSHELL, "sh", "-c", command, NULL);
423 fprintf(stderr, "%s: execl: %s: %s\n",
424 progname, _PATH_BSHELL, strerror(errno));
425 _exit(1);
426 }
427}
428
429static int
430newoutf(struct tcb *tcp)
431{
432 if (outfname && followfork > 1) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000433 char name[520 + sizeof(int) * 3];
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000434 FILE *fp;
435
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000436 sprintf(name, "%.512s.%u", outfname, tcp->pid);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000437 if ((fp = strace_fopen(name, "w")) == NULL)
438 return -1;
439 tcp->outf = fp;
440 }
441 return 0;
442}
443
Roland McGrath02203312007-06-11 22:06:31 +0000444static void
445startup_attach(void)
446{
447 int tcbi;
448 struct tcb *tcp;
449
450 /*
451 * Block user interruptions as we would leave the traced
452 * process stopped (process state T) if we would terminate in
453 * between PTRACE_ATTACH and wait4 () on SIGSTOP.
454 * We rely on cleanup () from this point on.
455 */
456 if (interactive)
457 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
458
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000459 if (daemonized_tracer) {
460 pid_t pid = fork();
461 if (pid < 0) {
462 _exit(1);
463 }
464 if (pid) { /* parent */
465 /*
Denys Vlasenko75422762011-05-27 14:36:01 +0200466 * Wait for grandchild to attach to straced process
467 * (grandparent). Grandchild SIGKILLs us after it attached.
468 * Grandparent's wait() is unblocked by our death,
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000469 * it proceeds to exec the straced program.
470 */
471 pause();
472 _exit(0); /* paranoia */
473 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200474 /* grandchild */
475 /* We will be the tracer process. Remember our new pid: */
476 strace_tracer_pid = getpid();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000477 }
478
Roland McGrath02203312007-06-11 22:06:31 +0000479 for (tcbi = 0; tcbi < tcbtabsize; tcbi++) {
480 tcp = tcbtab[tcbi];
481 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
482 continue;
483#ifdef LINUX
484 if (tcp->flags & TCB_CLONE_THREAD)
485 continue;
486#endif
487 /* Reinitialize the output since it may have changed. */
488 tcp->outf = outf;
489 if (newoutf(tcp) < 0)
490 exit(1);
491
492#ifdef USE_PROCFS
493 if (proc_open(tcp, 1) < 0) {
494 fprintf(stderr, "trouble opening proc file\n");
495 droptcb(tcp);
496 continue;
497 }
498#else /* !USE_PROCFS */
499# ifdef LINUX
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000500 if (followfork && !daemonized_tracer) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000501 char procdir[sizeof("/proc/%d/task") + sizeof(int) * 3];
Roland McGrath02203312007-06-11 22:06:31 +0000502 DIR *dir;
503
504 sprintf(procdir, "/proc/%d/task", tcp->pid);
505 dir = opendir(procdir);
506 if (dir != NULL) {
507 unsigned int ntid = 0, nerr = 0;
508 struct dirent *de;
509 int tid;
510 while ((de = readdir(dir)) != NULL) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000511 if (de->d_fileno == 0)
Roland McGrath02203312007-06-11 22:06:31 +0000512 continue;
513 tid = atoi(de->d_name);
514 if (tid <= 0)
515 continue;
516 ++ntid;
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000517 if (ptrace(PTRACE_ATTACH, tid, (char *) 1, 0) < 0)
Roland McGrath02203312007-06-11 22:06:31 +0000518 ++nerr;
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000519 else if (tid != tcbtab[tcbi]->pid) {
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000520 tcp = alloctcb(tid);
Wang Chao21b8db42010-08-27 17:43:16 +0800521 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_FOLLOWFORK;
Roland McGrath02203312007-06-11 22:06:31 +0000522 tcbtab[tcbi]->nchildren++;
523 tcbtab[tcbi]->nclone_threads++;
Roland McGrath02203312007-06-11 22:06:31 +0000524 tcp->parent = tcbtab[tcbi];
525 }
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000526 if (interactive) {
527 sigprocmask(SIG_SETMASK, &empty_set, NULL);
528 if (interrupted)
529 return;
530 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
531 }
Roland McGrath02203312007-06-11 22:06:31 +0000532 }
533 closedir(dir);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000534 ntid -= nerr;
535 if (ntid == 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000536 perror("attach: ptrace(PTRACE_ATTACH, ...)");
537 droptcb(tcp);
538 continue;
539 }
540 if (!qflag) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000541 fprintf(stderr, ntid > 1
542? "Process %u attached with %u threads - interrupt to quit\n"
543: "Process %u attached - interrupt to quit\n",
544 tcbtab[tcbi]->pid, ntid);
Roland McGrath02203312007-06-11 22:06:31 +0000545 }
546 continue;
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000547 } /* if (opendir worked) */
548 } /* if (-f) */
Roland McGrath02203312007-06-11 22:06:31 +0000549# endif
550 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
551 perror("attach: ptrace(PTRACE_ATTACH, ...)");
552 droptcb(tcp);
553 continue;
554 }
555 /* INTERRUPTED is going to be checked at the top of TRACE. */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000556
557 if (daemonized_tracer) {
558 /*
559 * It is our grandparent we trace, not a -p PID.
560 * Don't want to just detach on exit, so...
561 */
562 tcp->flags &= ~TCB_ATTACHED;
563 /*
564 * Make parent go away.
565 * Also makes grandparent's wait() unblock.
566 */
567 kill(getppid(), SIGKILL);
568 }
569
Roland McGrath02203312007-06-11 22:06:31 +0000570#endif /* !USE_PROCFS */
571 if (!qflag)
572 fprintf(stderr,
573 "Process %u attached - interrupt to quit\n",
574 tcp->pid);
575 }
576
577 if (interactive)
578 sigprocmask(SIG_SETMASK, &empty_set, NULL);
579}
580
581static void
Denys Vlasenko12014262011-05-30 14:00:14 +0200582startup_child(char **argv)
Roland McGrath02203312007-06-11 22:06:31 +0000583{
584 struct stat statbuf;
585 const char *filename;
586 char pathname[MAXPATHLEN];
587 int pid = 0;
588 struct tcb *tcp;
589
590 filename = argv[0];
591 if (strchr(filename, '/')) {
592 if (strlen(filename) > sizeof pathname - 1) {
593 errno = ENAMETOOLONG;
594 perror("strace: exec");
595 exit(1);
596 }
597 strcpy(pathname, filename);
598 }
599#ifdef USE_DEBUGGING_EXEC
600 /*
601 * Debuggers customarily check the current directory
602 * first regardless of the path but doing that gives
603 * security geeks a panic attack.
604 */
605 else if (stat(filename, &statbuf) == 0)
606 strcpy(pathname, filename);
607#endif /* USE_DEBUGGING_EXEC */
608 else {
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000609 const char *path;
Roland McGrath02203312007-06-11 22:06:31 +0000610 int m, n, len;
611
612 for (path = getenv("PATH"); path && *path; path += m) {
613 if (strchr(path, ':')) {
614 n = strchr(path, ':') - path;
615 m = n + 1;
616 }
617 else
618 m = n = strlen(path);
619 if (n == 0) {
620 if (!getcwd(pathname, MAXPATHLEN))
621 continue;
622 len = strlen(pathname);
623 }
624 else if (n > sizeof pathname - 1)
625 continue;
626 else {
627 strncpy(pathname, path, n);
628 len = n;
629 }
630 if (len && pathname[len - 1] != '/')
631 pathname[len++] = '/';
632 strcpy(pathname + len, filename);
633 if (stat(pathname, &statbuf) == 0 &&
634 /* Accept only regular files
635 with some execute bits set.
636 XXX not perfect, might still fail */
637 S_ISREG(statbuf.st_mode) &&
638 (statbuf.st_mode & 0111))
639 break;
640 }
641 }
642 if (stat(pathname, &statbuf) < 0) {
643 fprintf(stderr, "%s: %s: command not found\n",
644 progname, filename);
645 exit(1);
646 }
Dmitry V. Levina6809652008-11-10 17:14:58 +0000647 strace_child = pid = fork();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000648 if (pid < 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000649 perror("strace: fork");
650 cleanup();
651 exit(1);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000652 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200653 if ((pid != 0 && daemonized_tracer) /* -D: parent to become a traced process */
654 || (pid == 0 && !daemonized_tracer) /* not -D: child to become a traced process */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000655 ) {
656 pid = getpid();
Roland McGrath02203312007-06-11 22:06:31 +0000657#ifdef USE_PROCFS
658 if (outf != stderr) close (fileno (outf));
659#ifdef MIPS
660 /* Kludge for SGI, see proc_open for details. */
661 sa.sa_handler = foobar;
662 sa.sa_flags = 0;
663 sigemptyset(&sa.sa_mask);
664 sigaction(SIGINT, &sa, NULL);
665#endif /* MIPS */
666#ifndef FREEBSD
667 pause();
668#else /* FREEBSD */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000669 kill(pid, SIGSTOP); /* stop HERE */
Roland McGrath02203312007-06-11 22:06:31 +0000670#endif /* FREEBSD */
671#else /* !USE_PROCFS */
672 if (outf!=stderr)
673 close(fileno (outf));
674
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000675 if (!daemonized_tracer) {
676 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
677 perror("strace: ptrace(PTRACE_TRACEME, ...)");
678 exit(1);
679 }
680 if (debug)
681 kill(pid, SIGSTOP);
Roland McGrath02203312007-06-11 22:06:31 +0000682 }
Roland McGrath02203312007-06-11 22:06:31 +0000683
684 if (username != NULL || geteuid() == 0) {
685 uid_t run_euid = run_uid;
686 gid_t run_egid = run_gid;
687
688 if (statbuf.st_mode & S_ISUID)
689 run_euid = statbuf.st_uid;
690 if (statbuf.st_mode & S_ISGID)
691 run_egid = statbuf.st_gid;
692
693 /*
694 * It is important to set groups before we
695 * lose privileges on setuid.
696 */
697 if (username != NULL) {
698 if (initgroups(username, run_gid) < 0) {
699 perror("initgroups");
700 exit(1);
701 }
702 if (setregid(run_gid, run_egid) < 0) {
703 perror("setregid");
704 exit(1);
705 }
706 if (setreuid(run_uid, run_euid) < 0) {
707 perror("setreuid");
708 exit(1);
709 }
710 }
711 }
712 else
713 setreuid(run_uid, run_uid);
714
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000715 if (!daemonized_tracer) {
716 /*
717 * Induce an immediate stop so that the parent
718 * will resume us with PTRACE_SYSCALL and display
719 * this execve call normally.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400720 * Unless of course we're on a no-MMU system where
721 * we vfork()-ed, so we cannot stop the child.
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000722 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400723 if (!strace_vforked)
724 kill(getpid(), SIGSTOP);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000725 } else {
726 struct sigaction sv_sigchld;
727 sigaction(SIGCHLD, NULL, &sv_sigchld);
728 /*
729 * Make sure it is not SIG_IGN, otherwise wait
730 * will not block.
731 */
732 signal(SIGCHLD, SIG_DFL);
733 /*
734 * Wait for grandchild to attach to us.
735 * It kills child after that, and wait() unblocks.
736 */
737 alarm(3);
738 wait(NULL);
739 alarm(0);
740 sigaction(SIGCHLD, &sv_sigchld, NULL);
741 }
Roland McGrath02203312007-06-11 22:06:31 +0000742#endif /* !USE_PROCFS */
743
744 execv(pathname, argv);
745 perror("strace: exec");
746 _exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000747 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000748
749 /* We are the tracer. */
Denys Vlasenko75422762011-05-27 14:36:01 +0200750 /* With -D, we are *child* here, IOW: different pid. Fetch it. */
751 strace_tracer_pid = getpid();
752
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000753 tcp = alloctcb(daemonized_tracer ? getppid() : pid);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000754 if (daemonized_tracer) {
755 /* We want subsequent startup_attach() to attach to it. */
756 tcp->flags |= TCB_ATTACHED;
757 }
Roland McGrath02203312007-06-11 22:06:31 +0000758#ifdef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000759 if (proc_open(tcp, 0) < 0) {
760 fprintf(stderr, "trouble opening proc file\n");
761 cleanup();
762 exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000763 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000764#endif /* USE_PROCFS */
Roland McGrath02203312007-06-11 22:06:31 +0000765}
766
Wang Chaob13c0de2010-11-12 17:25:19 +0800767#ifdef LINUX
768/*
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000769 * Test whether the kernel support PTRACE_O_TRACECLONE et al options.
Wang Chaob13c0de2010-11-12 17:25:19 +0800770 * First fork a new child, call ptrace with PTRACE_SETOPTIONS on it,
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000771 * and then see which options are supported by the kernel.
Wang Chaob13c0de2010-11-12 17:25:19 +0800772 */
773static int
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200774test_ptrace_setoptions_followfork(void)
Wang Chaob13c0de2010-11-12 17:25:19 +0800775{
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000776 int pid, expected_grandchild = 0, found_grandchild = 0;
777 const unsigned int test_options = PTRACE_O_TRACECLONE |
778 PTRACE_O_TRACEFORK |
779 PTRACE_O_TRACEVFORK;
Wang Chaob13c0de2010-11-12 17:25:19 +0800780
781 if ((pid = fork()) < 0)
782 return -1;
783 else if (pid == 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000784 if (ptrace(PTRACE_TRACEME, 0, (char *)1, 0) < 0)
Wang Chaob13c0de2010-11-12 17:25:19 +0800785 _exit(1);
Wang Chaob13c0de2010-11-12 17:25:19 +0800786 kill(getpid(), SIGSTOP);
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000787 _exit(fork() < 0);
Wang Chaob13c0de2010-11-12 17:25:19 +0800788 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000789
790 while (1) {
791 int status, tracee_pid;
792
793 tracee_pid = wait(&status);
794 if (tracee_pid == -1) {
795 if (errno == EINTR)
796 continue;
797 else if (errno == ECHILD)
798 break;
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200799 perror("test_ptrace_setoptions_followfork");
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000800 return -1;
801 }
802 if (tracee_pid != pid) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000803 found_grandchild = tracee_pid;
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000804 if (ptrace(PTRACE_CONT, tracee_pid, 0, 0) < 0 &&
805 errno != ESRCH)
806 kill(tracee_pid, SIGKILL);
807 }
808 else if (WIFSTOPPED(status)) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000809 switch (WSTOPSIG(status)) {
810 case SIGSTOP:
811 if (ptrace(PTRACE_SETOPTIONS, pid,
812 NULL, test_options) < 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000813 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800814 return -1;
815 }
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000816 break;
817 case SIGTRAP:
818 if (status >> 16 == PTRACE_EVENT_FORK) {
819 long msg = 0;
820
821 if (ptrace(PTRACE_GETEVENTMSG, pid,
822 NULL, (long) &msg) == 0)
823 expected_grandchild = msg;
824 }
825 break;
Wang Chaob13c0de2010-11-12 17:25:19 +0800826 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000827 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0 &&
828 errno != ESRCH)
829 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800830 }
831 }
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000832 if (expected_grandchild && expected_grandchild == found_grandchild)
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200833 ptrace_setoptions_followfork |= test_options;
Wang Chaob13c0de2010-11-12 17:25:19 +0800834 return 0;
835}
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200836
837/*
838 * Test whether the kernel support PTRACE_O_TRACESYSGOOD.
839 * First fork a new child, call ptrace(PTRACE_SETOPTIONS) on it,
840 * and then see whether it will stop with (SIGTRAP | 0x80).
841 *
842 * Use of this option enables correct handling of user-generated SIGTRAPs,
843 * and SIGTRAPs generated by special instructions such as int3 on x86:
844 * _start: .globl _start
845 * int3
846 * movl $42, %ebx
847 * movl $1, %eax
848 * int $0x80
849 * (compile with: "gcc -nostartfiles -nostdlib -o int3 int3.S")
850 */
851static void
852test_ptrace_setoptions_for_all(void)
853{
854 const unsigned int test_options = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC;
855 int pid;
856 int it_worked = 0;
857
858 pid = fork();
859 if (pid < 0)
Denys Vlasenko75422762011-05-27 14:36:01 +0200860 perror_msg_and_die("fork");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200861
862 if (pid == 0) {
863 pid = getpid();
864 if (ptrace(PTRACE_TRACEME, 0L, 0L, 0L) < 0)
Denys Vlasenko75422762011-05-27 14:36:01 +0200865 /* Note: exits with exitcode 1 */
866 perror_msg_and_die("%s: PTRACE_TRACEME doesn't work", __func__);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200867 kill(pid, SIGSTOP);
868 _exit(0); /* parent should see entry into this syscall */
869 }
870
871 while (1) {
872 int status, tracee_pid;
873
874 errno = 0;
875 tracee_pid = wait(&status);
876 if (tracee_pid <= 0) {
877 if (errno == EINTR)
878 continue;
879 kill(pid, SIGKILL);
Denys Vlasenko75422762011-05-27 14:36:01 +0200880 perror_msg_and_die("%s: unexpected wait result %d", __func__, tracee_pid);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200881 }
Denys Vlasenko75422762011-05-27 14:36:01 +0200882 if (WIFEXITED(status)) {
883 if (WEXITSTATUS(status) == 0)
884 break;
885 /* PTRACE_TRACEME failed in child. This is fatal. */
886 exit(1);
887 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200888 if (!WIFSTOPPED(status)) {
889 kill(pid, SIGKILL);
890 error_msg_and_die("%s: unexpected wait status %x", __func__, status);
891 }
892 if (WSTOPSIG(status) == SIGSTOP) {
893 /*
894 * We don't check "options aren't accepted" error.
895 * If it happens, we'll never get (SIGTRAP | 0x80),
896 * and thus will decide to not use the option.
897 * IOW: the outcome of the test will be correct.
898 */
Denys Vlasenko75422762011-05-27 14:36:01 +0200899 if (ptrace(PTRACE_SETOPTIONS, pid, 0L, test_options) < 0)
900 if (errno != EINVAL)
901 perror_msg("PTRACE_SETOPTIONS");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200902 }
903 if (WSTOPSIG(status) == (SIGTRAP | 0x80)) {
904 it_worked = 1;
905 }
906 if (ptrace(PTRACE_SYSCALL, pid, 0L, 0L) < 0) {
907 kill(pid, SIGKILL);
Denys Vlasenko75422762011-05-27 14:36:01 +0200908 perror_msg_and_die("PTRACE_SYSCALL doesn't work");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200909 }
910 }
911
912 if (it_worked) {
Denys Vlasenko75422762011-05-27 14:36:01 +0200913 syscall_trap_sig = (SIGTRAP | 0x80);
Denys Vlasenko3454e4b2011-05-23 21:29:03 +0200914 ptrace_setoptions_for_all = test_options;
915 if (debug)
916 fprintf(stderr, "ptrace_setoptions_for_all = %#x\n",
917 ptrace_setoptions_for_all);
918 return;
919 }
920
921 fprintf(stderr,
922 "Test for PTRACE_O_TRACESYSGOOD failed, giving up using this feature.\n");
923}
Wang Chaob13c0de2010-11-12 17:25:19 +0800924#endif
925
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000926int
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000927main(int argc, char *argv[])
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000928{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000929 struct tcb *tcp;
930 int c, pid = 0;
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000931 int optF = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000932 struct sigaction sa;
933
934 static char buf[BUFSIZ];
935
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000936 progname = argv[0] ? argv[0] : "strace";
937
Denys Vlasenko75422762011-05-27 14:36:01 +0200938 strace_tracer_pid = getpid();
939
Roland McGrathee9d4352002-12-18 04:16:10 +0000940 /* Allocate the initial tcbtab. */
941 tcbtabsize = argc; /* Surely enough for all -p args. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000942 if ((tcbtab = calloc(tcbtabsize, sizeof tcbtab[0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000943 fprintf(stderr, "%s: out of memory\n", progname);
944 exit(1);
945 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000946 if ((tcbtab[0] = calloc(tcbtabsize, sizeof tcbtab[0][0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000947 fprintf(stderr, "%s: out of memory\n", progname);
948 exit(1);
949 }
Roland McGrathee9d4352002-12-18 04:16:10 +0000950 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
951 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
952
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000953 outf = stderr;
954 interactive = 1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000955 set_sortby(DEFAULT_SORTBY);
956 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000957 qualify("trace=all");
958 qualify("abbrev=all");
959 qualify("verbose=all");
960 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000961 while ((c = getopt(argc, argv,
Grant Edwards8a082772011-04-07 20:25:40 +0000962 "+cCdfFhiqrtTvVxyz"
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000963#ifndef USE_PROCFS
964 "D"
965#endif
Grant Edwards8a082772011-04-07 20:25:40 +0000966 "a:e:o:O:p:s:S:u:E:P:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000967 switch (c) {
968 case 'c':
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000969 if (cflag == CFLAG_BOTH) {
970 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
971 progname);
972 exit(1);
973 }
974 cflag = CFLAG_ONLY_STATS;
975 break;
976 case 'C':
977 if (cflag == CFLAG_ONLY_STATS) {
978 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
979 progname);
980 exit(1);
981 }
982 cflag = CFLAG_BOTH;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000983 break;
984 case 'd':
985 debug++;
986 break;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000987#ifndef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000988 case 'D':
989 daemonized_tracer = 1;
990 break;
991#endif
Roland McGrath41c48222008-07-18 00:25:10 +0000992 case 'F':
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000993 optF = 1;
994 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000995 case 'f':
996 followfork++;
997 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000998 case 'h':
999 usage(stdout, 0);
1000 break;
1001 case 'i':
1002 iflag++;
1003 break;
1004 case 'q':
1005 qflag++;
1006 break;
1007 case 'r':
1008 rflag++;
1009 tflag++;
1010 break;
1011 case 't':
1012 tflag++;
1013 break;
1014 case 'T':
1015 dtime++;
1016 break;
1017 case 'x':
1018 xflag++;
1019 break;
Grant Edwards8a082772011-04-07 20:25:40 +00001020 case 'y':
1021 show_fd_path = 1;
1022 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001023 case 'v':
1024 qualify("abbrev=none");
1025 break;
1026 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +00001027 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001028 exit(0);
1029 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +00001030 case 'z':
1031 not_failing_only = 1;
1032 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001033 case 'a':
1034 acolumn = atoi(optarg);
1035 break;
1036 case 'e':
1037 qualify(optarg);
1038 break;
1039 case 'o':
1040 outfname = strdup(optarg);
1041 break;
1042 case 'O':
1043 set_overhead(atoi(optarg));
1044 break;
1045 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +00001046 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001047 fprintf(stderr, "%s: Invalid process id: %s\n",
1048 progname, optarg);
1049 break;
1050 }
Denys Vlasenko75422762011-05-27 14:36:01 +02001051 if (pid == strace_tracer_pid) {
Wichert Akkerman54a47671999-10-17 00:57:34 +00001052 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001053 break;
1054 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001055 tcp = alloc_tcb(pid, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001056 tcp->flags |= TCB_ATTACHED;
1057 pflag_seen++;
1058 break;
Grant Edwards8a082772011-04-07 20:25:40 +00001059 case 'P':
1060 tracing_paths = 1;
1061 if (pathtrace_select(optarg)) {
1062 fprintf(stderr,"%s : failed to select path '%s'\n", progname, optarg);
1063 exit(1);
1064 }
1065 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001066 case 's':
1067 max_strlen = atoi(optarg);
Roland McGrathdccec722005-05-09 07:45:47 +00001068 if (max_strlen < 0) {
1069 fprintf(stderr,
1070 "%s: invalid -s argument: %s\n",
1071 progname, optarg);
1072 exit(1);
1073 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001074 break;
1075 case 'S':
1076 set_sortby(optarg);
1077 break;
1078 case 'u':
1079 username = strdup(optarg);
1080 break;
Roland McGrathde6e5332003-01-24 04:31:23 +00001081 case 'E':
1082 if (putenv(optarg) < 0) {
1083 fprintf(stderr, "%s: out of memory\n",
1084 progname);
1085 exit(1);
1086 }
1087 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001088 default:
1089 usage(stderr, 1);
1090 break;
1091 }
1092 }
1093
Roland McGrathd0c4c0c2006-04-25 07:39:40 +00001094 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +00001095 usage(stderr, 1);
1096
Wang Chaod322a4b2010-08-05 14:30:11 +08001097 if (pflag_seen && daemonized_tracer) {
1098 fprintf(stderr,
1099 "%s: -D and -p are mutually exclusive options\n",
1100 progname);
1101 exit(1);
1102 }
1103
Dmitry V. Levin06350db2008-07-25 15:42:34 +00001104 if (!followfork)
1105 followfork = optF;
1106
Roland McGrathcb9def62006-04-25 07:48:03 +00001107 if (followfork > 1 && cflag) {
1108 fprintf(stderr,
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00001109 "%s: (-c or -C) and -ff are mutually exclusive options\n",
Roland McGrathcb9def62006-04-25 07:48:03 +00001110 progname);
1111 exit(1);
1112 }
1113
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001114 /* See if they want to run as another user. */
1115 if (username != NULL) {
1116 struct passwd *pent;
1117
1118 if (getuid() != 0 || geteuid() != 0) {
1119 fprintf(stderr,
1120 "%s: you must be root to use the -u option\n",
1121 progname);
1122 exit(1);
1123 }
1124 if ((pent = getpwnam(username)) == NULL) {
1125 fprintf(stderr, "%s: cannot find user `%s'\n",
Roland McGrath09553f82007-07-05 19:31:49 +00001126 progname, username);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001127 exit(1);
1128 }
1129 run_uid = pent->pw_uid;
1130 run_gid = pent->pw_gid;
1131 }
1132 else {
1133 run_uid = getuid();
1134 run_gid = getgid();
1135 }
1136
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001137#ifdef LINUX
1138 if (followfork) {
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02001139 if (test_ptrace_setoptions_followfork() < 0) {
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001140 fprintf(stderr,
1141 "Test for options supported by PTRACE_SETOPTIONS "
1142 "failed, giving up using this feature.\n");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02001143 ptrace_setoptions_followfork = 0;
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001144 }
1145 if (debug)
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02001146 fprintf(stderr, "ptrace_setoptions_followfork = %#x\n",
1147 ptrace_setoptions_followfork);
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001148 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02001149 test_ptrace_setoptions_for_all();
Dmitry V. Levin8044bc12010-12-07 12:50:49 +00001150#endif
1151
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001152 /* Check if they want to redirect the output. */
1153 if (outfname) {
Roland McGrath37b9a662003-11-07 02:26:54 +00001154 /* See if they want to pipe the output. */
1155 if (outfname[0] == '|' || outfname[0] == '!') {
1156 /*
1157 * We can't do the <outfname>.PID funny business
1158 * when using popen, so prohibit it.
1159 */
1160 if (followfork > 1) {
1161 fprintf(stderr, "\
1162%s: piping the output and -ff are mutually exclusive options\n",
1163 progname);
1164 exit(1);
1165 }
1166
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001167 if ((outf = strace_popen(outfname + 1)) == NULL)
Roland McGrath37b9a662003-11-07 02:26:54 +00001168 exit(1);
Roland McGrath37b9a662003-11-07 02:26:54 +00001169 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001170 else if (followfork <= 1 &&
1171 (outf = strace_fopen(outfname, "w")) == NULL)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001172 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001173 }
1174
Roland McGrath37b9a662003-11-07 02:26:54 +00001175 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001176 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +00001177 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001178 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001179 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +00001180 }
Wang Chaob13c0de2010-11-12 17:25:19 +08001181
Roland McGrath54cc1c82007-11-03 23:34:11 +00001182 /* Valid states here:
1183 optind < argc pflag_seen outfname interactive
1184 1 0 0 1
1185 0 1 0 1
1186 1 0 1 0
1187 0 1 1 1
1188 */
1189
1190 /* STARTUP_CHILD must be called before the signal handlers get
1191 installed below as they are inherited into the spawned process.
1192 Also we do not need to be protected by them as during interruption
1193 in the STARTUP_CHILD mode we kill the spawned process anyway. */
1194 if (!pflag_seen)
1195 startup_child(&argv[optind]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001196
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001197 sigemptyset(&empty_set);
1198 sigemptyset(&blocked_set);
1199 sa.sa_handler = SIG_IGN;
1200 sigemptyset(&sa.sa_mask);
1201 sa.sa_flags = 0;
1202 sigaction(SIGTTOU, &sa, NULL);
1203 sigaction(SIGTTIN, &sa, NULL);
1204 if (interactive) {
1205 sigaddset(&blocked_set, SIGHUP);
1206 sigaddset(&blocked_set, SIGINT);
1207 sigaddset(&blocked_set, SIGQUIT);
1208 sigaddset(&blocked_set, SIGPIPE);
1209 sigaddset(&blocked_set, SIGTERM);
1210 sa.sa_handler = interrupt;
1211#ifdef SUNOS4
1212 /* POSIX signals on sunos4.1 are a little broken. */
1213 sa.sa_flags = SA_INTERRUPT;
1214#endif /* SUNOS4 */
1215 }
1216 sigaction(SIGHUP, &sa, NULL);
1217 sigaction(SIGINT, &sa, NULL);
1218 sigaction(SIGQUIT, &sa, NULL);
1219 sigaction(SIGPIPE, &sa, NULL);
1220 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001221#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001222 sa.sa_handler = reaper;
1223 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +00001224#else
1225 /* Make sure SIGCHLD has the default action so that waitpid
1226 definitely works without losing track of children. The user
1227 should not have given us a bogus state to inherit, but he might
1228 have. Arguably we should detect SIG_IGN here and pass it on
1229 to children, but probably noone really needs that. */
1230 sa.sa_handler = SIG_DFL;
1231 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001232#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001233
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +00001234 if (pflag_seen || daemonized_tracer)
Roland McGrath02203312007-06-11 22:06:31 +00001235 startup_attach();
Roland McGrath02203312007-06-11 22:06:31 +00001236
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001237 if (trace() < 0)
1238 exit(1);
1239 cleanup();
Dmitry V. Levina6809652008-11-10 17:14:58 +00001240 fflush(NULL);
1241 if (exit_code > 0xff) {
1242 /* Child was killed by a signal, mimic that. */
1243 exit_code &= 0xff;
1244 signal(exit_code, SIG_DFL);
1245 raise(exit_code);
1246 /* Paranoia - what if this signal is not fatal?
1247 Exit with 128 + signo then. */
1248 exit_code += 128;
1249 }
1250 exit(exit_code);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001251}
1252
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001253void
1254expand_tcbtab(void)
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001255{
1256 /* Allocate some more TCBs and expand the table.
1257 We don't want to relocate the TCBs because our
1258 callers have pointers and it would be a pain.
1259 So tcbtab is a table of pointers. Since we never
1260 free the TCBs, we allocate a single chunk of many. */
1261 struct tcb **newtab = (struct tcb **)
1262 realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
1263 struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
1264 sizeof *newtcbs);
1265 int i;
1266 if (newtab == NULL || newtcbs == NULL) {
Dmitry V. Levin76860f62006-10-11 22:55:25 +00001267 fprintf(stderr, "%s: expand_tcbtab: out of memory\n",
1268 progname);
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001269 cleanup();
1270 exit(1);
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001271 }
1272 for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
1273 newtab[i] = &newtcbs[i - tcbtabsize];
1274 tcbtabsize *= 2;
1275 tcbtab = newtab;
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001276}
1277
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001278struct tcb *
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001279alloc_tcb(int pid, int command_options_parsed)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001280{
1281 int i;
1282 struct tcb *tcp;
1283
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001284 if (nprocs == tcbtabsize)
1285 expand_tcbtab();
1286
Roland McGrathee9d4352002-12-18 04:16:10 +00001287 for (i = 0; i < tcbtabsize; i++) {
1288 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001289 if ((tcp->flags & TCB_INUSE) == 0) {
1290 tcp->pid = pid;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001291 tcp->parent = NULL;
1292 tcp->nchildren = 0;
1293 tcp->nzombies = 0;
1294#ifdef TCB_CLONE_THREAD
Wang Chao21b8db42010-08-27 17:43:16 +08001295 tcp->nclone_threads = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001296 tcp->nclone_waiting = 0;
1297#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001298 tcp->flags = TCB_INUSE | TCB_STARTUP;
1299 tcp->outf = outf; /* Initialise to current out file */
Andreas Schwabccdff482009-10-27 16:27:13 +01001300 tcp->curcol = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001301 tcp->stime.tv_sec = 0;
1302 tcp->stime.tv_usec = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001303 tcp->pfd = -1;
1304 nprocs++;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001305 if (command_options_parsed)
1306 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001307 return tcp;
1308 }
1309 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001310 fprintf(stderr, "%s: bug in alloc_tcb\n", progname);
1311 cleanup();
1312 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001313}
1314
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001315#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001316int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001317proc_open(struct tcb *tcp, int attaching)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001318{
1319 char proc[32];
1320 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001321#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +00001322 int i;
1323 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001324 sigset_t signals;
1325 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001326#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001327#ifndef HAVE_POLLABLE_PROCFS
1328 static int last_pfd;
1329#endif
1330
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001331#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001332 /* Open the process pseudo-files in /proc. */
1333 sprintf(proc, "/proc/%d/ctl", tcp->pid);
1334 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001335 perror("strace: open(\"/proc/...\", ...)");
1336 return -1;
1337 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001338 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001339 return -1;
1340 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001341 sprintf(proc, "/proc/%d/status", tcp->pid);
1342 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
1343 perror("strace: open(\"/proc/...\", ...)");
1344 return -1;
1345 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001346 if (set_cloexec_flag(tcp->pfd_stat) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001347 return -1;
1348 }
1349 sprintf(proc, "/proc/%d/as", tcp->pid);
1350 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
1351 perror("strace: open(\"/proc/...\", ...)");
1352 return -1;
1353 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001354 if (set_cloexec_flag(tcp->pfd_as) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001355 return -1;
1356 }
1357#else
1358 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001359#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);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001362#else /* FREEBSD */
1363 sprintf(proc, "/proc/%d/mem", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001364 tcp->pfd = open(proc, O_RDWR);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001365#endif /* FREEBSD */
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 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001370 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001371 return -1;
1372 }
1373#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001374#ifdef FREEBSD
1375 sprintf(proc, "/proc/%d/regs", tcp->pid);
1376 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
1377 perror("strace: open(\"/proc/.../regs\", ...)");
1378 return -1;
1379 }
1380 if (cflag) {
1381 sprintf(proc, "/proc/%d/status", tcp->pid);
1382 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
1383 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 (;;) {
1396 if (IOCTL_STATUS (tcp) < 0) {
1397 perror("strace: PIOCSTATUS");
1398 return -1;
1399 }
1400 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001401 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;
1452 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
1453 }
1454 praddset (&syscalls, SYS_execve);
1455 if (followfork) {
1456 praddset (&syscalls, SYS_fork);
1457#ifdef SYS_forkall
1458 praddset (&syscalls, SYS_forkall);
1459#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001460#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +00001461 praddset (&syscalls, SYS_fork1);
1462#endif
1463#ifdef SYS_rfork1
1464 praddset (&syscalls, SYS_rfork1);
1465#endif
1466#ifdef SYS_rforkall
1467 praddset (&syscalls, SYS_rforkall);
1468#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;
1483 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
1484 }
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;
1493 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
1494 }
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. */
1501 arg = S_SIG | S_SCE | S_SCX ;
1502 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
1503 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;
1518 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. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001530 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;
1536 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;
1543 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001544#else /* FREEBSD */
1545 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001546#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001547 perror("PIOCRUN");
1548 return -1;
1549 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001550#ifdef FREEBSD
1551 /* handle the case where we "opened" the child before
1552 it did the kill -STOP */
1553 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1554 tcp->status.PR_WHAT == SIGSTOP)
1555 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001556#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001557 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001558#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001559 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001560#else /* 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;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001658#ifdef TCB_CLONE_THREAD
1659 if (tcp->nclone_threads > 0) {
1660 /* There are other threads left in this process, but this
1661 is the one whose PID represents the whole process.
1662 We need to keep this record around as a zombie until
1663 all the threads die. */
1664 tcp->flags |= TCB_EXITING;
1665 return;
1666 }
1667#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001668 nprocs--;
1669 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001670
Roland McGrathe29341c2003-01-10 20:14:20 +00001671 if (tcp->parent != NULL) {
1672 tcp->parent->nchildren--;
1673#ifdef TCB_CLONE_THREAD
Roland McGrathe29341c2003-01-10 20:14:20 +00001674 if (tcp->flags & TCB_CLONE_THREAD)
1675 tcp->parent->nclone_threads--;
1676#endif
Wang Chao21b8db42010-08-27 17:43:16 +08001677 tcp->parent->nzombies++;
Roland McGrath276ceb32007-11-13 08:12:12 +00001678#ifdef LINUX
1679 /* Update `tcp->parent->parent->nchildren' and the other fields
1680 like NCLONE_DETACHED, only for zombie group leader that has
1681 already reported and been short-circuited at the top of this
1682 function. The same condition as at the top of DETACH. */
1683 if ((tcp->flags & TCB_CLONE_THREAD) &&
1684 tcp->parent->nclone_threads == 0 &&
1685 (tcp->parent->flags & TCB_EXITING))
1686 droptcb(tcp->parent);
1687#endif
Roland McGrathe29341c2003-01-10 20:14:20 +00001688 tcp->parent = NULL;
1689 }
1690
1691 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001692 if (tcp->pfd != -1) {
1693 close(tcp->pfd);
1694 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001695#ifdef FREEBSD
1696 if (tcp->pfd_reg != -1) {
1697 close(tcp->pfd_reg);
1698 tcp->pfd_reg = -1;
1699 }
1700 if (tcp->pfd_status != -1) {
1701 close(tcp->pfd_status);
1702 tcp->pfd_status = -1;
1703 }
Roland McGrath553a6092002-12-16 20:40:39 +00001704#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001705#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001706 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001707#endif
1708 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001709
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001710 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001711 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001712
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001713 tcp->outf = 0;
1714}
1715
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001716#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001717
1718static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001719resume(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001720{
1721 if (tcp == NULL)
1722 return -1;
1723
1724 if (!(tcp->flags & TCB_SUSPENDED)) {
1725 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1726 return -1;
1727 }
1728 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001729#ifdef TCB_CLONE_THREAD
1730 if (tcp->flags & TCB_CLONE_THREAD)
1731 tcp->parent->nclone_waiting--;
1732#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001733
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001734 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001735 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001736
1737 if (!qflag)
1738 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1739 return 0;
1740}
1741
Roland McGrath1bfd3102007-08-03 10:02:00 +00001742static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001743resume_from_tcp(struct tcb *tcp)
Roland McGrath1bfd3102007-08-03 10:02:00 +00001744{
1745 int error = 0;
1746 int resumed = 0;
1747
1748 /* XXX This won't always be quite right (but it never was).
1749 A waiter with argument 0 or < -1 is waiting for any pid in
1750 a particular pgrp, which this child might or might not be
1751 in. The waiter will only wake up if it's argument is -1
1752 or if it's waiting for tcp->pid's pgrp. It makes a
1753 difference to wake up a waiter when there might be more
1754 traced children, because it could get a false ECHILD
1755 error. OTOH, if this was the last child in the pgrp, then
1756 it ought to wake up and get ECHILD. We would have to
1757 search the system for all pid's in the pgrp to be sure.
1758
1759 && (t->waitpid == -1 ||
1760 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1761 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1762 */
1763
1764 if (tcp->parent &&
1765 (tcp->parent->flags & TCB_SUSPENDED) &&
1766 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001767 error = resume(tcp->parent);
Roland McGrath1bfd3102007-08-03 10:02:00 +00001768 ++resumed;
1769 }
1770#ifdef TCB_CLONE_THREAD
1771 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1772 /* Some other threads of our parent are waiting too. */
1773 unsigned int i;
1774
1775 /* Resume all the threads that were waiting for this PID. */
1776 for (i = 0; i < tcbtabsize; i++) {
1777 struct tcb *t = tcbtab[i];
1778 if (t->parent == tcp->parent && t != tcp
1779 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1780 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1781 && t->waitpid == tcp->pid) {
1782 error |= resume (t);
1783 ++resumed;
1784 }
1785 }
1786 if (resumed == 0)
1787 /* Noone was waiting for this PID in particular,
1788 so now we might need to resume some wildcarders. */
1789 for (i = 0; i < tcbtabsize; i++) {
1790 struct tcb *t = tcbtab[i];
1791 if (t->parent == tcp->parent && t != tcp
1792 && ((t->flags
1793 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1794 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1795 && t->waitpid <= 0
1796 ) {
1797 error |= resume (t);
1798 break;
1799 }
1800 }
1801 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001802#endif
Roland McGrath1bfd3102007-08-03 10:02:00 +00001803
1804 return error;
1805}
Roland McGrath1bfd3102007-08-03 10:02:00 +00001806
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001807#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001808
Roland McGrath0a463882007-07-05 18:43:16 +00001809/* detach traced process; continue with sig
1810 Never call DETACH twice on the same process as both unattached and
1811 attached-unstopped processes give the same ESRCH. For unattached process we
1812 would SIGSTOP it and wait for its SIGSTOP notification forever. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001813
1814static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001815detach(struct tcb *tcp, int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001816{
1817 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001818#ifdef LINUX
Roland McGrath1bfd3102007-08-03 10:02:00 +00001819 int status, catch_sigstop;
Roland McGratha08a97e2005-08-03 11:23:46 +00001820 struct tcb *zombie = NULL;
1821
1822 /* If the group leader is lingering only because of this other
1823 thread now dying, then detach the leader as well. */
1824 if ((tcp->flags & TCB_CLONE_THREAD) &&
1825 tcp->parent->nclone_threads == 1 &&
1826 (tcp->parent->flags & TCB_EXITING))
1827 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001828#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001829
1830 if (tcp->flags & TCB_BPTSET)
Andreas Schwab840d85b2010-01-12 11:16:32 +01001831 clearbpt(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001832
1833#ifdef LINUX
1834 /*
1835 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001836 * before detaching. Arghh. We go through hoops
1837 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001838 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001839#if defined(SPARC)
1840#undef PTRACE_DETACH
1841#define PTRACE_DETACH PTRACE_SUNDETACH
1842#endif
Roland McGrath02203312007-06-11 22:06:31 +00001843 /*
1844 * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
1845 * expected SIGSTOP. We must catch exactly one as otherwise the
1846 * detached process would be left stopped (process state T).
1847 */
1848 catch_sigstop = (tcp->flags & TCB_STARTUP);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001849 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1850 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001851 }
1852 else if (errno != ESRCH) {
1853 /* Shouldn't happen. */
1854 perror("detach: ptrace(PTRACE_DETACH, ...)");
1855 }
Roland McGrath134813a2007-06-02 00:07:33 +00001856 else if (my_tgkill((tcp->flags & TCB_CLONE_THREAD ? tcp->parent->pid
1857 : tcp->pid),
1858 tcp->pid, 0) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001859 if (errno != ESRCH)
1860 perror("detach: checking sanity");
1861 }
Roland McGrath02203312007-06-11 22:06:31 +00001862 else if (!catch_sigstop && my_tgkill((tcp->flags & TCB_CLONE_THREAD
1863 ? tcp->parent->pid : tcp->pid),
1864 tcp->pid, SIGSTOP) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001865 if (errno != ESRCH)
1866 perror("detach: stopping child");
1867 }
Roland McGrath02203312007-06-11 22:06:31 +00001868 else
1869 catch_sigstop = 1;
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001870 if (catch_sigstop) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001871 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001872#ifdef __WALL
1873 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1874 if (errno == ECHILD) /* Already gone. */
1875 break;
1876 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001877 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001878 break;
1879 }
1880#endif /* __WALL */
1881 /* No __WALL here. */
1882 if (waitpid(tcp->pid, &status, 0) < 0) {
1883 if (errno != ECHILD) {
1884 perror("detach: waiting");
1885 break;
1886 }
1887#ifdef __WCLONE
1888 /* If no processes, try clones. */
1889 if (wait4(tcp->pid, &status, __WCLONE,
1890 NULL) < 0) {
1891 if (errno != ECHILD)
1892 perror("detach: waiting");
1893 break;
1894 }
1895#endif /* __WCLONE */
1896 }
1897#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001898 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001899#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001900 if (!WIFSTOPPED(status)) {
1901 /* Au revoir, mon ami. */
1902 break;
1903 }
1904 if (WSTOPSIG(status) == SIGSTOP) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001905 ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001906 break;
1907 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001908 error = ptrace_restart(PTRACE_CONT, tcp,
Denys Vlasenko75422762011-05-27 14:36:01 +02001909 WSTOPSIG(status) == syscall_trap_sig ? 0
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001910 : WSTOPSIG(status));
1911 if (error < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001912 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001913 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001914 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001915#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001916
1917#if defined(SUNOS4)
1918 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1919 if (sig && kill(tcp->pid, sig) < 0)
1920 perror("detach: kill");
1921 sig = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001922 error = ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001923#endif /* SUNOS4 */
1924
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001925#ifndef USE_PROCFS
Roland McGrath1bfd3102007-08-03 10:02:00 +00001926 error |= resume_from_tcp (tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001927#endif
1928
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001929 if (!qflag)
1930 fprintf(stderr, "Process %u detached\n", tcp->pid);
1931
1932 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001933
1934#ifdef LINUX
Roland McGrath0a463882007-07-05 18:43:16 +00001935 if (zombie != NULL) {
1936 /* TCP no longer exists therefore you must not detach () it. */
1937 droptcb(zombie);
1938 }
Roland McGratha08a97e2005-08-03 11:23:46 +00001939#endif
1940
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001941 return error;
1942}
1943
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001944#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001945
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001946static void reaper(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001947{
1948 int pid;
1949 int status;
1950
1951 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001952 }
1953}
1954
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001955#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001956
1957static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001958cleanup(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001959{
1960 int i;
1961 struct tcb *tcp;
1962
Roland McGrathee9d4352002-12-18 04:16:10 +00001963 for (i = 0; i < tcbtabsize; i++) {
1964 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001965 if (!(tcp->flags & TCB_INUSE))
1966 continue;
1967 if (debug)
1968 fprintf(stderr,
1969 "cleanup: looking at pid %u\n", tcp->pid);
1970 if (tcp_last &&
1971 (!outfname || followfork < 2 || tcp_last == tcp)) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001972 tprintf(" <unfinished ...>");
1973 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001974 }
1975 if (tcp->flags & TCB_ATTACHED)
1976 detach(tcp, 0);
1977 else {
1978 kill(tcp->pid, SIGCONT);
1979 kill(tcp->pid, SIGTERM);
1980 }
1981 }
1982 if (cflag)
1983 call_summary(outf);
1984}
1985
1986static void
Denys Vlasenko12014262011-05-30 14:00:14 +02001987interrupt(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001988{
1989 interrupted = 1;
1990}
1991
1992#ifndef HAVE_STRERROR
1993
Roland McGrath6d2b3492002-12-30 00:51:30 +00001994#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001995extern int sys_nerr;
1996extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001997#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001998
1999const char *
Denys Vlasenko12014262011-05-30 14:00:14 +02002000strerror(int err_no)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002001{
2002 static char buf[64];
2003
Denys Vlasenko35aba6a2011-05-25 15:33:26 +02002004 if (err_no < 1 || err_no >= sys_nerr) {
2005 sprintf(buf, "Unknown error %d", err_no);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002006 return buf;
2007 }
Denys Vlasenko35aba6a2011-05-25 15:33:26 +02002008 return sys_errlist[err_no];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002009}
2010
2011#endif /* HAVE_STERRROR */
2012
2013#ifndef HAVE_STRSIGNAL
2014
Roland McGrath8f474e02003-01-14 07:53:33 +00002015#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00002016extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002017#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00002018#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
2019extern char *_sys_siglist[];
2020#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002021
2022const char *
Denys Vlasenko12014262011-05-30 14:00:14 +02002023strsignal(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002024{
2025 static char buf[64];
2026
2027 if (sig < 1 || sig >= NSIG) {
2028 sprintf(buf, "Unknown signal %d", sig);
2029 return buf;
2030 }
2031#ifdef HAVE__SYS_SIGLIST
2032 return _sys_siglist[sig];
2033#else
2034 return sys_siglist[sig];
2035#endif
2036}
2037
2038#endif /* HAVE_STRSIGNAL */
2039
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002040#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002041
2042static void
Denys Vlasenko12014262011-05-30 14:00:14 +02002043rebuild_pollv(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002044{
2045 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002046
Roland McGrathee9d4352002-12-18 04:16:10 +00002047 if (pollv != NULL)
2048 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00002049 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00002050 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00002051 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00002052 exit(1);
2053 }
2054
Roland McGrathca16be82003-01-10 19:55:28 +00002055 for (i = j = 0; i < tcbtabsize; i++) {
2056 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002057 if (!(tcp->flags & TCB_INUSE))
2058 continue;
2059 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002060 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002061 j++;
2062 }
2063 if (j != nprocs) {
2064 fprintf(stderr, "strace: proc miscount\n");
2065 exit(1);
2066 }
2067}
2068
2069#ifndef HAVE_POLLABLE_PROCFS
2070
2071static void
Denys Vlasenko12014262011-05-30 14:00:14 +02002072proc_poll_open(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002073{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002074 int i;
2075
2076 if (pipe(proc_poll_pipe) < 0) {
2077 perror("pipe");
2078 exit(1);
2079 }
2080 for (i = 0; i < 2; i++) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002081 if (set_cloexec_flag(proc_poll_pipe[i]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002082 exit(1);
2083 }
2084 }
2085}
2086
2087static int
Denys Vlasenko12014262011-05-30 14:00:14 +02002088proc_poll(struct pollfd *pollv, int nfds, int timeout)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002089{
2090 int i;
2091 int n;
2092 struct proc_pollfd pollinfo;
2093
2094 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
2095 return n;
2096 if (n != sizeof(struct proc_pollfd)) {
2097 fprintf(stderr, "panic: short read: %d\n", n);
2098 exit(1);
2099 }
2100 for (i = 0; i < nprocs; i++) {
2101 if (pollv[i].fd == pollinfo.fd)
2102 pollv[i].revents = pollinfo.revents;
2103 else
2104 pollv[i].revents = 0;
2105 }
2106 poller_pid = pollinfo.pid;
2107 return 1;
2108}
2109
2110static void
Denys Vlasenko12014262011-05-30 14:00:14 +02002111wakeup_handler(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002112{
2113}
2114
2115static void
Denys Vlasenko12014262011-05-30 14:00:14 +02002116proc_poller(int pfd)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002117{
2118 struct proc_pollfd pollinfo;
2119 struct sigaction sa;
2120 sigset_t blocked_set, empty_set;
2121 int i;
2122 int n;
2123 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002124#ifdef FREEBSD
2125 struct procfs_status pfs;
2126#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002127
2128 switch (fork()) {
2129 case -1:
2130 perror("fork");
Dmitry V. Levina6809652008-11-10 17:14:58 +00002131 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002132 case 0:
2133 break;
2134 default:
2135 return;
2136 }
2137
2138 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
2139 sa.sa_flags = 0;
2140 sigemptyset(&sa.sa_mask);
2141 sigaction(SIGHUP, &sa, NULL);
2142 sigaction(SIGINT, &sa, NULL);
2143 sigaction(SIGQUIT, &sa, NULL);
2144 sigaction(SIGPIPE, &sa, NULL);
2145 sigaction(SIGTERM, &sa, NULL);
2146 sa.sa_handler = wakeup_handler;
2147 sigaction(SIGUSR1, &sa, NULL);
2148 sigemptyset(&blocked_set);
2149 sigaddset(&blocked_set, SIGUSR1);
2150 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2151 sigemptyset(&empty_set);
2152
2153 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
2154 perror("getrlimit(RLIMIT_NOFILE, ...)");
Dmitry V. Levina6809652008-11-10 17:14:58 +00002155 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002156 }
2157 n = rl.rlim_cur;
2158 for (i = 0; i < n; i++) {
2159 if (i != pfd && i != proc_poll_pipe[1])
2160 close(i);
2161 }
2162
2163 pollinfo.fd = pfd;
2164 pollinfo.pid = getpid();
2165 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002166#ifndef FREEBSD
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002167 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
2168#else
2169 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
2170#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002171 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002172 switch (errno) {
2173 case EINTR:
2174 continue;
2175 case EBADF:
2176 pollinfo.revents = POLLERR;
2177 break;
2178 case ENOENT:
2179 pollinfo.revents = POLLHUP;
2180 break;
2181 default:
2182 perror("proc_poller: PIOCWSTOP");
2183 }
2184 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2185 _exit(0);
2186 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002187 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002188 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2189 sigsuspend(&empty_set);
2190 }
2191}
2192
2193#endif /* !HAVE_POLLABLE_PROCFS */
2194
2195static int
2196choose_pfd()
2197{
2198 int i, j;
2199 struct tcb *tcp;
2200
2201 static int last;
2202
2203 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002204 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002205 /*
2206 * The previous process is ready to run again. We'll
2207 * let it do so if it is currently in a syscall. This
2208 * heuristic improves the readability of the trace.
2209 */
2210 tcp = pfd2tcb(pollv[last].fd);
2211 if (tcp && (tcp->flags & TCB_INSYSCALL))
2212 return pollv[last].fd;
2213 }
2214
2215 for (i = 0; i < nprocs; i++) {
2216 /* Let competing children run round robin. */
2217 j = (i + last + 1) % nprocs;
2218 if (pollv[j].revents & (POLLHUP | POLLERR)) {
2219 tcp = pfd2tcb(pollv[j].fd);
2220 if (!tcp) {
2221 fprintf(stderr, "strace: lost proc\n");
2222 exit(1);
2223 }
2224 droptcb(tcp);
2225 return -1;
2226 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002227 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002228 last = j;
2229 return pollv[j].fd;
2230 }
2231 }
2232 fprintf(stderr, "strace: nothing ready\n");
2233 exit(1);
2234}
2235
2236static int
Denys Vlasenko12014262011-05-30 14:00:14 +02002237trace(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002238{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002239#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00002240 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002241#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002242 struct tcb *tcp;
2243 int pfd;
2244 int what;
2245 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002246 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002247
2248 for (;;) {
2249 if (interactive)
2250 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2251
2252 if (nprocs == 0)
2253 break;
2254
2255 switch (nprocs) {
2256 case 1:
2257#ifndef HAVE_POLLABLE_PROCFS
2258 if (proc_poll_pipe[0] == -1) {
2259#endif
Roland McGrath54e931f2010-09-14 18:59:20 -07002260 tcp = first_used_tcb();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002261 if (!tcp)
2262 continue;
2263 pfd = tcp->pfd;
2264 if (pfd == -1)
2265 continue;
2266 break;
2267#ifndef HAVE_POLLABLE_PROCFS
2268 }
2269 /* fall through ... */
2270#endif /* !HAVE_POLLABLE_PROCFS */
2271 default:
2272#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002273#ifdef POLL_HACK
2274 /* On some systems (e.g. UnixWare) we get too much ugly
2275 "unfinished..." stuff when multiple proceses are in
2276 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00002277
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002278 if (in_syscall) {
2279 struct pollfd pv;
2280 tcp = in_syscall;
2281 in_syscall = NULL;
2282 pv.fd = tcp->pfd;
2283 pv.events = POLLWANT;
2284 if ((what = poll (&pv, 1, 1)) < 0) {
2285 if (interrupted)
2286 return 0;
2287 continue;
2288 }
2289 else if (what == 1 && pv.revents & POLLWANT) {
2290 goto FOUND;
2291 }
2292 }
2293#endif
2294
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002295 if (poll(pollv, nprocs, INFTIM) < 0) {
2296 if (interrupted)
2297 return 0;
2298 continue;
2299 }
2300#else /* !HAVE_POLLABLE_PROCFS */
2301 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
2302 if (interrupted)
2303 return 0;
2304 continue;
2305 }
2306#endif /* !HAVE_POLLABLE_PROCFS */
2307 pfd = choose_pfd();
2308 if (pfd == -1)
2309 continue;
2310 break;
2311 }
2312
2313 /* Look up `pfd' in our table. */
2314 if ((tcp = pfd2tcb(pfd)) == NULL) {
2315 fprintf(stderr, "unknown pfd: %u\n", pfd);
2316 exit(1);
2317 }
John Hughesb6643082002-05-23 11:02:22 +00002318#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002319 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00002320#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002321 /* Get the status of the process. */
2322 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002323#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002324 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002325#else /* FREEBSD */
2326 /* Thanks to some scheduling mystery, the first poller
2327 sometimes waits for the already processed end of fork
2328 event. Doing a non blocking poll here solves the problem. */
2329 if (proc_poll_pipe[0] != -1)
2330 ioctl_result = IOCTL_STATUS (tcp);
2331 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002332 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00002333#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002334 ioctl_errno = errno;
2335#ifndef HAVE_POLLABLE_PROCFS
2336 if (proc_poll_pipe[0] != -1) {
2337 if (ioctl_result < 0)
2338 kill(poller_pid, SIGKILL);
2339 else
2340 kill(poller_pid, SIGUSR1);
2341 }
2342#endif /* !HAVE_POLLABLE_PROCFS */
2343 }
2344 if (interrupted)
2345 return 0;
2346
2347 if (interactive)
2348 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2349
2350 if (ioctl_result < 0) {
2351 /* Find out what happened if it failed. */
2352 switch (ioctl_errno) {
2353 case EINTR:
2354 case EBADF:
2355 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002356#ifdef FREEBSD
2357 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00002358#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002359 case ENOENT:
2360 droptcb(tcp);
2361 continue;
2362 default:
2363 perror("PIOCWSTOP");
2364 exit(1);
2365 }
2366 }
2367
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002368#ifdef FREEBSD
2369 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2370 /* discard first event for a syscall we never entered */
2371 IOCTL (tcp->pfd, PIOCRUN, 0);
2372 continue;
2373 }
Roland McGrath553a6092002-12-16 20:40:39 +00002374#endif
2375
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002376 /* clear the just started flag */
2377 tcp->flags &= ~TCB_STARTUP;
2378
2379 /* set current output file */
2380 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002381 curcol = tcp->curcol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002382
2383 if (cflag) {
2384 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002385#ifdef FREEBSD
2386 char buf[1024];
2387 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002388
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002389 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
2390 buf[len] = '\0';
2391 sscanf(buf,
2392 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2393 &stime.tv_sec, &stime.tv_usec);
2394 } else
2395 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002396#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002397 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2398 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002399#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002400 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2401 tcp->stime = stime;
2402 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002403 what = tcp->status.PR_WHAT;
2404 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002405#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002406 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002407 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2408 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002409 if (trace_syscall(tcp) < 0) {
2410 fprintf(stderr, "syscall trouble\n");
2411 exit(1);
2412 }
2413 }
2414 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002415#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002416 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002417#ifdef POLL_HACK
2418 in_syscall = tcp;
2419#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002420 case PR_SYSEXIT:
2421 if (trace_syscall(tcp) < 0) {
2422 fprintf(stderr, "syscall trouble\n");
2423 exit(1);
2424 }
2425 break;
2426 case PR_SIGNALLED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002427 if (cflag != CFLAG_ONLY_STATS
2428 && (qual_flags[what] & QUAL_SIGNAL)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002429 printleader(tcp);
2430 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002431 signame(what), strsignal(what));
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002432 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002433#ifdef PR_INFO
2434 if (tcp->status.PR_INFO.si_signo == what) {
2435 printleader(tcp);
2436 tprintf(" siginfo=");
2437 printsiginfo(&tcp->status.PR_INFO, 1);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002438 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002439 }
2440#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002441 }
2442 break;
2443 case PR_FAULTED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002444 if (cflag != CFLAGS_ONLY_STATS
2445 && (qual_flags[what] & QUAL_FAULT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002446 printleader(tcp);
2447 tprintf("=== FAULT %d ===", what);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002448 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002449 }
2450 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002451#ifdef FREEBSD
2452 case 0: /* handle case we polled for nothing */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002453 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00002454#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002455 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002456 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002457 exit(1);
2458 break;
2459 }
Andreas Schwabccdff482009-10-27 16:27:13 +01002460 /* Remember current print column before continuing. */
2461 tcp->curcol = curcol;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002462 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002463#ifndef FREEBSD
Andreas Schwab372cc842010-07-09 11:49:27 +02002464 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002465#else
Andreas Schwab372cc842010-07-09 11:49:27 +02002466 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002467#endif
Andreas Schwab372cc842010-07-09 11:49:27 +02002468 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002469 perror("PIOCRUN");
2470 exit(1);
2471 }
2472 }
2473 return 0;
2474}
2475
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002476#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002477
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002478#ifdef TCB_GROUP_EXITING
2479/* Handle an exit detach or death signal that is taking all the
2480 related clone threads with it. This is called in three circumstances:
2481 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
2482 SIG == 0 Continuing TCP will perform an exit_group syscall.
2483 SIG == other Continuing TCP with SIG will kill the process.
2484*/
2485static int
2486handle_group_exit(struct tcb *tcp, int sig)
2487{
2488 /* We need to locate our records of all the clone threads
2489 related to TCP, either its children or siblings. */
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002490 struct tcb *leader = NULL;
2491
2492 if (tcp->flags & TCB_CLONE_THREAD)
2493 leader = tcp->parent;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002494
2495 if (sig < 0) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002496 if (leader != NULL && leader != tcp
2497 && !(leader->flags & TCB_GROUP_EXITING)
2498 && !(tcp->flags & TCB_STARTUP)
2499 ) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002500 fprintf(stderr,
2501 "PANIC: handle_group_exit: %d leader %d\n",
2502 tcp->pid, leader ? leader->pid : -1);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002503 }
2504 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath1bfd3102007-08-03 10:02:00 +00002505#ifndef USE_PROCFS
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002506 resume_from_tcp(tcp);
Roland McGrath1bfd3102007-08-03 10:02:00 +00002507#endif
Roland McGrath0a463882007-07-05 18:43:16 +00002508 droptcb(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002509 }
2510 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00002511 /* Mark that we are taking the process down. */
2512 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002513 if (tcp->flags & TCB_ATTACHED) {
Roland McGrathd6a32f12007-07-11 08:35:11 +00002514 detach(tcp, sig);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002515 if (leader != NULL && leader != tcp)
Roland McGrath1bfd3102007-08-03 10:02:00 +00002516 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002517 } else {
2518 if (ptrace_restart(PTRACE_CONT, tcp, sig) < 0) {
2519 cleanup();
2520 return -1;
2521 }
2522 if (leader != NULL) {
Roland McGrath05690952004-10-20 01:00:27 +00002523 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002524 if (leader != tcp)
2525 droptcb(tcp);
2526 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002527 /* The leader will report to us as parent now,
2528 and then we'll get to the SIG==-1 case. */
2529 return 0;
2530 }
2531 }
2532
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002533 return 0;
2534}
2535#endif
2536
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002537#ifdef LINUX
2538static int
2539handle_ptrace_event(int status, struct tcb *tcp)
2540{
2541 if (status >> 16 == PTRACE_EVENT_VFORK ||
2542 status >> 16 == PTRACE_EVENT_CLONE ||
2543 status >> 16 == PTRACE_EVENT_FORK) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +00002544 long childpid;
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002545
2546 if (do_ptrace(PTRACE_GETEVENTMSG, tcp, NULL, &childpid) < 0) {
2547 if (errno != ESRCH) {
2548 fprintf(stderr, "\
2549%s: handle_ptrace_event: ptrace cannot get new child's pid\n",
2550 progname);
2551 cleanup();
2552 exit(1);
2553 }
2554 return -1;
2555 }
2556 return handle_new_child(tcp, childpid, 0);
2557 }
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002558 if (status >> 16 == PTRACE_EVENT_EXEC) {
2559 if (debug)
2560 fprintf(stderr, "PTRACE_EVENT_EXEC on pid %d (ignored)\n", tcp->pid);
2561 return 0;
2562 }
Denys Vlasenko75422762011-05-27 14:36:01 +02002563 /* Some PTRACE_EVENT_foo we didn't ask for?! */
2564 error_msg("Unexpected status %x on pid %d", status, tcp->pid);
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002565 return 1;
2566}
2567#endif
2568
Roland McGratheb9e2e82009-06-02 16:49:22 -07002569static int
2570trace()
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002571{
2572 int pid;
2573 int wait_errno;
2574 int status;
2575 struct tcb *tcp;
2576#ifdef LINUX
2577 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002578#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002579 static int wait4_options = __WALL;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002580#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002581#endif /* LINUX */
2582
Roland McGratheb9e2e82009-06-02 16:49:22 -07002583 while (nprocs != 0) {
Denys Vlasenko222713a2009-03-17 14:29:59 +00002584 if (interrupted)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002585 return 0;
2586 if (interactive)
2587 sigprocmask(SIG_SETMASK, &empty_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002588#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002589#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002590 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002591 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002592 /* this kernel does not support __WALL */
2593 wait4_options &= ~__WALL;
2594 errno = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002595 pid = wait4(-1, &status, wait4_options,
2596 cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002597 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002598 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002599 /* most likely a "cloned" process */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002600 pid = wait4(-1, &status, __WCLONE,
2601 cflag ? &ru : NULL);
2602 if (pid == -1) {
2603 fprintf(stderr, "strace: clone wait4 "
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002604 "failed: %s\n", strerror(errno));
2605 }
2606 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002607#else
2608 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
2609#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002610#endif /* LINUX */
2611#ifdef SUNOS4
2612 pid = wait(&status);
2613#endif /* SUNOS4 */
2614 wait_errno = errno;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002615 if (interactive)
2616 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002617
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002618 if (pid == -1) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002619 switch (wait_errno) {
2620 case EINTR:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002621 continue;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002622 case ECHILD:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002623 /*
2624 * We would like to verify this case
2625 * but sometimes a race in Solbourne's
2626 * version of SunOS sometimes reports
2627 * ECHILD before sending us SIGCHILD.
2628 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002629 return 0;
2630 default:
2631 errno = wait_errno;
2632 perror("strace: wait");
2633 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002634 }
2635 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002636 if (pid == popen_pid) {
2637 if (WIFEXITED(status) || WIFSIGNALED(status))
2638 popen_pid = -1;
2639 continue;
2640 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002641 if (debug)
2642 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2643
2644 /* Look up `pid' in our table. */
2645 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002646#ifdef LINUX
Roland McGrath41c48222008-07-18 00:25:10 +00002647 if (followfork) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002648 /* This is needed to go with the CLONE_PTRACE
2649 changes in process.c/util.c: we might see
2650 the child's initial trap before we see the
2651 parent return from the clone syscall.
2652 Leave the child suspended until the parent
2653 returns from its system call. Only then
2654 will we have the association of parent and
2655 child so that we know how to do clearbpt
2656 in the child. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +00002657 tcp = alloctcb(pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002658 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002659 if (!qflag)
2660 fprintf(stderr, "\
2661Process %d attached (waiting for parent)\n",
2662 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002663 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002664 else
2665 /* This can happen if a clone call used
2666 CLONE_PTRACE itself. */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002667#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002668 {
2669 fprintf(stderr, "unknown pid: %u\n", pid);
2670 if (WIFSTOPPED(status))
2671 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2672 exit(1);
2673 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002674 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002675 /* set current output file */
2676 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002677 curcol = tcp->curcol;
Denys Vlasenko84e20af2009-02-10 16:03:20 +00002678 if (cflag) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002679#ifdef LINUX
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002680 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2681 tcp->stime = ru.ru_stime;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002682#endif /* !LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002683 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002684
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002685 if (tcp->flags & TCB_SUSPENDED) {
2686 /*
2687 * Apparently, doing any ptrace() call on a stopped
2688 * process, provokes the kernel to report the process
2689 * status again on a subsequent wait(), even if the
2690 * process has not been actually restarted.
2691 * Since we have inspected the arguments of suspended
2692 * processes we end up here testing for this case.
2693 */
2694 continue;
2695 }
2696 if (WIFSIGNALED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002697 if (pid == strace_child)
2698 exit_code = 0x100 | WTERMSIG(status);
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002699 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002700 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2701 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002702 tprintf("+++ killed by %s %s+++",
2703 signame(WTERMSIG(status)),
2704#ifdef WCOREDUMP
2705 WCOREDUMP(status) ? "(core dumped) " :
2706#endif
2707 "");
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002708 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002709 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002710#ifdef TCB_GROUP_EXITING
2711 handle_group_exit(tcp, -1);
2712#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002713 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002714#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002715 continue;
2716 }
2717 if (WIFEXITED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002718 if (pid == strace_child)
2719 exit_code = WEXITSTATUS(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002720 if (debug)
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002721 fprintf(stderr, "pid %u exited with %d\n", pid, WEXITSTATUS(status));
2722 if ((tcp->flags & (TCB_ATTACHED|TCB_STARTUP)) == TCB_ATTACHED
Roland McGrath05690952004-10-20 01:00:27 +00002723#ifdef TCB_GROUP_EXITING
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002724 && !(tcp->parent && (tcp->parent->flags & TCB_GROUP_EXITING))
Roland McGrath1bfd3102007-08-03 10:02:00 +00002725 && !(tcp->flags & TCB_GROUP_EXITING)
Roland McGrath05690952004-10-20 01:00:27 +00002726#endif
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002727 ) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002728 fprintf(stderr,
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002729 "PANIC: attached pid %u exited with %d\n",
2730 pid, WEXITSTATUS(status));
2731 }
Roland McGrath0a396902003-06-10 03:05:53 +00002732 if (tcp == tcp_last) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002733 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT)) == TCB_INSYSCALL)
Roland McGrath0a396902003-06-10 03:05:53 +00002734 tprintf(" <unfinished ... exit status %d>\n",
2735 WEXITSTATUS(status));
2736 tcp_last = NULL;
2737 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002738#ifdef TCB_GROUP_EXITING
2739 handle_group_exit(tcp, -1);
2740#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002741 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002742#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002743 continue;
2744 }
2745 if (!WIFSTOPPED(status)) {
2746 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2747 droptcb(tcp);
2748 continue;
2749 }
2750 if (debug)
2751 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002752 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002753
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002754 if (status >> 16) {
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002755 if (handle_ptrace_event(status, tcp) != 1)
2756 goto tracing;
2757 }
2758
Roland McGrath02203312007-06-11 22:06:31 +00002759 /*
2760 * Interestingly, the process may stop
2761 * with STOPSIG equal to some other signal
Roland McGratheb9e2e82009-06-02 16:49:22 -07002762 * than SIGSTOP if we happend to attach
Roland McGrath02203312007-06-11 22:06:31 +00002763 * just before the process takes a signal.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002764 * A no-MMU vforked child won't send up a signal,
2765 * so skip the first (lost) execve notification.
Roland McGrath02203312007-06-11 22:06:31 +00002766 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002767 if ((tcp->flags & TCB_STARTUP) &&
2768 (WSTOPSIG(status) == SIGSTOP || strace_vforked)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002769 /*
2770 * This flag is there to keep us in sync.
2771 * Next time this process stops it should
2772 * really be entering a system call.
2773 */
2774 tcp->flags &= ~TCB_STARTUP;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002775 if (tcp->flags & TCB_BPTSET) {
Roland McGrath02203312007-06-11 22:06:31 +00002776 /*
2777 * One example is a breakpoint inherited from
2778 * parent through fork ().
2779 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002780 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2781 droptcb(tcp);
2782 cleanup();
2783 return -1;
2784 }
2785 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002786#ifdef LINUX
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002787 int options = ptrace_setoptions_for_all;
2788 if (followfork && (tcp->parent == NULL))
2789 options |= ptrace_setoptions_followfork;
2790 if (options) {
2791 if (debug)
2792 fprintf(stderr, "setting opts %x on pid %d\n", options, tcp->pid);
2793 if (ptrace(PTRACE_SETOPTIONS, tcp->pid, NULL, options) < 0) {
2794 if (errno != ESRCH) {
2795 /* Should never happen, really */
Denys Vlasenko75422762011-05-27 14:36:01 +02002796 perror_msg_and_die("PTRACE_SETOPTIONS");
Denys Vlasenko3454e4b2011-05-23 21:29:03 +02002797 }
2798 }
2799 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002800#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002801 goto tracing;
2802 }
2803
Denys Vlasenko75422762011-05-27 14:36:01 +02002804 if (WSTOPSIG(status) != syscall_trap_sig) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002805 if (WSTOPSIG(status) == SIGSTOP &&
2806 (tcp->flags & TCB_SIGTRAPPED)) {
2807 /*
2808 * Trapped attempt to block SIGTRAP
2809 * Hope we are back in control now.
2810 */
2811 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002812 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002813 cleanup();
2814 return -1;
2815 }
2816 continue;
2817 }
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002818 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002819 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Dmitry V. Levinc15dfc72011-03-10 14:44:45 +00002820 siginfo_t si;
2821#if defined(PT_CR_IPSR) && defined(PT_CR_IIP)
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002822 long pc = 0;
2823 long psr = 0;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002824
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002825 upeek(tcp, PT_CR_IPSR, &psr);
2826 upeek(tcp, PT_CR_IIP, &pc);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002827
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002828# define PSR_RI 41
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002829 pc += (psr >> PSR_RI) & 0x3;
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002830# define PC_FORMAT_STR " @ %lx"
2831# define PC_FORMAT_ARG pc
2832#else
2833# define PC_FORMAT_STR "%s"
2834# define PC_FORMAT_ARG ""
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002835#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002836 printleader(tcp);
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002837 if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
2838 tprintf("--- ");
2839 printsiginfo(&si, verbose(tcp));
2840 tprintf(" (%s)" PC_FORMAT_STR " ---",
2841 strsignal(WSTOPSIG(status)),
2842 PC_FORMAT_ARG);
2843 } else
2844 tprintf("--- %s by %s" PC_FORMAT_STR " ---",
2845 strsignal(WSTOPSIG(status)),
2846 signame(WSTOPSIG(status)),
2847 PC_FORMAT_ARG);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002848 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002849 }
Roland McGrath05690952004-10-20 01:00:27 +00002850 if (((tcp->flags & TCB_ATTACHED) ||
2851 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002852 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002853#ifdef TCB_GROUP_EXITING
2854 handle_group_exit(tcp, WSTOPSIG(status));
2855#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002856 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002857#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002858 continue;
2859 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002860 if (ptrace_restart(PTRACE_SYSCALL, tcp, WSTOPSIG(status)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002861 cleanup();
2862 return -1;
2863 }
2864 tcp->flags &= ~TCB_SUSPENDED;
2865 continue;
2866 }
Roland McGrath02203312007-06-11 22:06:31 +00002867 /* we handled the STATUS, we are permitted to interrupt now. */
2868 if (interrupted)
2869 return 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002870 if (trace_syscall(tcp) < 0 && !tcp->ptrace_errno) {
2871 /* ptrace() failed in trace_syscall() with ESRCH.
2872 * Likely a result of process disappearing mid-flight.
2873 * Observed case: exit_group() terminating
2874 * all processes in thread group. In this case, threads
2875 * "disappear" in an unpredictable moment without any
2876 * notification to strace via wait().
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002877 */
2878 if (tcp->flags & TCB_ATTACHED) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002879 if (tcp_last) {
2880 /* Do we have dangling line "syscall(param, param"?
2881 * Finish the line then. We cannot
2882 */
2883 tcp_last->flags |= TCB_REPRINT;
2884 tprintf(" <unfinished ...>");
2885 printtrailer();
2886 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002887 detach(tcp, 0);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002888 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002889 ptrace(PTRACE_KILL,
2890 tcp->pid, (char *) 1, SIGTERM);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002891 droptcb(tcp);
2892 }
2893 continue;
2894 }
2895 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002896#ifdef TCB_GROUP_EXITING
2897 if (tcp->flags & TCB_GROUP_EXITING) {
2898 if (handle_group_exit(tcp, 0) < 0)
2899 return -1;
2900 continue;
2901 }
2902#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002903 if (tcp->flags & TCB_ATTACHED)
2904 detach(tcp, 0);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002905 else if (ptrace_restart(PTRACE_CONT, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002906 cleanup();
2907 return -1;
2908 }
2909 continue;
2910 }
2911 if (tcp->flags & TCB_SUSPENDED) {
2912 if (!qflag)
2913 fprintf(stderr, "Process %u suspended\n", pid);
2914 continue;
2915 }
2916 tracing:
Andreas Schwabccdff482009-10-27 16:27:13 +01002917 /* Remember current print column before continuing. */
2918 tcp->curcol = curcol;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002919 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002920 cleanup();
2921 return -1;
2922 }
2923 }
2924 return 0;
2925}
2926
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002927#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002928
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002929#include <stdarg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002930
2931void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002932tprintf(const char *fmt, ...)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002933{
2934 va_list args;
2935
Andreas Schwabe5355de2009-10-27 16:56:43 +01002936 va_start(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002937 if (outf) {
2938 int n = vfprintf(outf, fmt, args);
Andreas Schwabccdff482009-10-27 16:27:13 +01002939 if (n < 0) {
2940 if (outf != stderr)
2941 perror(outfname == NULL
2942 ? "<writing to pipe>" : outfname);
2943 } else
Roland McGrathb310a0c2003-11-06 23:41:22 +00002944 curcol += n;
2945 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002946 va_end(args);
2947 return;
2948}
2949
2950void
Denys Vlasenko12014262011-05-30 14:00:14 +02002951printleader(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002952{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002953 if (tcp_last) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002954 if (tcp_last->ptrace_errno) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002955 if (tcp_last->flags & TCB_INSYSCALL) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002956 tprintf(" <unavailable>)");
2957 tabto(acolumn);
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002958 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002959 tprintf("= ? <unavailable>\n");
2960 tcp_last->ptrace_errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002961 } else if (!outfname || followfork < 2 || tcp_last == tcp) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002962 tcp_last->flags |= TCB_REPRINT;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002963 tprintf(" <unfinished ...>\n");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002964 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002965 }
2966 curcol = 0;
2967 if ((followfork == 1 || pflag_seen > 1) && outfname)
2968 tprintf("%-5d ", tcp->pid);
2969 else if (nprocs > 1 && !outfname)
2970 tprintf("[pid %5u] ", tcp->pid);
2971 if (tflag) {
2972 char str[sizeof("HH:MM:SS")];
2973 struct timeval tv, dtv;
2974 static struct timeval otv;
2975
2976 gettimeofday(&tv, NULL);
2977 if (rflag) {
2978 if (otv.tv_sec == 0)
2979 otv = tv;
2980 tv_sub(&dtv, &tv, &otv);
2981 tprintf("%6ld.%06ld ",
2982 (long) dtv.tv_sec, (long) dtv.tv_usec);
2983 otv = tv;
2984 }
2985 else if (tflag > 2) {
2986 tprintf("%ld.%06ld ",
2987 (long) tv.tv_sec, (long) tv.tv_usec);
2988 }
2989 else {
2990 time_t local = tv.tv_sec;
2991 strftime(str, sizeof(str), "%T", localtime(&local));
2992 if (tflag > 1)
2993 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2994 else
2995 tprintf("%s ", str);
2996 }
2997 }
2998 if (iflag)
2999 printcall(tcp);
3000}
3001
3002void
Denys Vlasenko12014262011-05-30 14:00:14 +02003003tabto(int col)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00003004{
3005 if (curcol < col)
3006 tprintf("%*s", col - curcol, "");
3007}
3008
3009void
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00003010printtrailer(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00003011{
3012 tprintf("\n");
3013 tcp_last = NULL;
3014}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00003015
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00003016#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00003017
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00003018int
3019mp_ioctl(int fd, int cmd, void *arg, int size)
3020{
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00003021 struct iovec iov[2];
3022 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00003023
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00003024 iov[0].iov_base = &cmd;
3025 iov[0].iov_len = sizeof cmd;
3026 if (arg) {
3027 ++n;
3028 iov[1].iov_base = arg;
3029 iov[1].iov_len = size;
3030 }
Roland McGrath553a6092002-12-16 20:40:39 +00003031
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00003032 return writev(fd, iov, n);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00003033}
3034
3035#endif