blob: 7874d19ed97f87b0fd14df48c3c7e2da041f2e04 [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>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000036#include <signal.h>
37#include <errno.h>
38#include <sys/param.h>
39#include <fcntl.h>
40#include <sys/resource.h>
41#include <sys/wait.h>
42#include <sys/stat.h>
43#include <pwd.h>
44#include <grp.h>
45#include <string.h>
John Hughes19e49982001-10-19 08:59:12 +000046#include <limits.h>
Roland McGrath70b08532004-04-09 00:25:21 +000047#include <dirent.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000048
Roland McGrath134813a2007-06-02 00:07:33 +000049#ifdef LINUX
50# include <asm/unistd.h>
51# if defined __NR_tgkill
52# define my_tgkill(pid, tid, sig) syscall (__NR_tgkill, (pid), (tid), (sig))
53# elif defined __NR_tkill
54# define my_tgkill(pid, tid, sig) syscall (__NR_tkill, (tid), (sig))
55# else
56 /* kill() may choose arbitrarily the target task of the process group
57 while we later wait on a that specific TID. PID process waits become
58 TID task specific waits for a process under ptrace(2). */
59# warning "Neither tkill(2) nor tgkill(2) available, risk of strace hangs!"
60# define my_tgkill(pid, tid, sig) kill ((tid), (sig))
61# endif
62#endif
63
Wichert Akkerman7b3346b2001-10-09 23:47:38 +000064#if defined(IA64) && defined(LINUX)
65# include <asm/ptrace_offsets.h>
66#endif
67
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +000068#ifdef USE_PROCFS
69#include <poll.h>
70#endif
71
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000072#ifdef SVR4
73#include <sys/stropts.h>
Wichert Akkermanea78f0f1999-11-29 15:34:02 +000074#ifdef HAVE_MP_PROCFS
John Hughes1d08dcf2001-07-10 13:48:44 +000075#ifdef HAVE_SYS_UIO_H
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000076#include <sys/uio.h>
77#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000078#endif
John Hughes1d08dcf2001-07-10 13:48:44 +000079#endif
Denys Vlasenko96d5a762008-12-29 19:13:27 +000080extern char **environ;
Denys Vlasenko418d66a2009-01-17 01:52:54 +000081extern int optind;
82extern char *optarg;
Denys Vlasenko96d5a762008-12-29 19:13:27 +000083
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000084
Roland McGrath41c48222008-07-18 00:25:10 +000085int debug = 0, followfork = 0;
Wang Chaob13c0de2010-11-12 17:25:19 +080086unsigned int ptrace_setoptions = 0;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +000087int dtime = 0, xflag = 0, qflag = 0;
88cflag_t cflag = CFLAG_NONE;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +000089static int iflag = 0, interactive = 0, pflag_seen = 0, rflag = 0, tflag = 0;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +000090/*
91 * daemonized_tracer supports -D option.
92 * With this option, strace forks twice.
93 * Unlike normal case, with -D *grandparent* process exec's,
94 * becoming a traced process. Child exits (this prevents traced process
95 * from having children it doesn't expect to have), and grandchild
96 * attaches to grandparent similarly to strace -p PID.
97 * This allows for more transparent interaction in cases
98 * when process and its parent are communicating via signals,
99 * wait() etc. Without -D, strace process gets lodged in between,
100 * disrupting parent<->child link.
101 */
102static bool daemonized_tracer = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000103
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000104/* Sometimes we want to print only succeeding syscalls. */
105int not_failing_only = 0;
106
Grant Edwards8a082772011-04-07 20:25:40 +0000107/* Show path associated with fd arguments */
108int show_fd_path = 0;
109
110/* are we filtering traces based on paths? */
111int tracing_paths = 0;
112
Dmitry V. Levina6809652008-11-10 17:14:58 +0000113static int exit_code = 0;
114static int strace_child = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700115
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +0000116static char *username = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000117uid_t run_uid;
118gid_t run_gid;
119
120int acolumn = DEFAULT_ACOLUMN;
121int max_strlen = DEFAULT_STRLEN;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +0000122static char *outfname = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000123FILE *outf;
Andreas Schwabccdff482009-10-27 16:27:13 +0100124static int curcol;
Roland McGrathee9d4352002-12-18 04:16:10 +0000125struct tcb **tcbtab;
126unsigned int nprocs, tcbtabsize;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000127const char *progname;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700128extern char **environ;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000129
Andreas Schwabe5355de2009-10-27 16:56:43 +0100130static int detach(struct tcb *tcp, int sig);
131static int trace(void);
132static void cleanup(void);
133static void interrupt(int sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000134static sigset_t empty_set, blocked_set;
135
136#ifdef HAVE_SIG_ATOMIC_T
137static volatile sig_atomic_t interrupted;
138#else /* !HAVE_SIG_ATOMIC_T */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000139static volatile int interrupted;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000140#endif /* !HAVE_SIG_ATOMIC_T */
141
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000142#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000143
Andreas Schwabe5355de2009-10-27 16:56:43 +0100144static struct tcb *pfd2tcb(int pfd);
145static void reaper(int sig);
146static void rebuild_pollv(void);
Roland McGrathee9d4352002-12-18 04:16:10 +0000147static struct pollfd *pollv;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000148
149#ifndef HAVE_POLLABLE_PROCFS
150
Andreas Schwabe5355de2009-10-27 16:56:43 +0100151static void proc_poll_open(void);
152static void proc_poller(int pfd);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000153
154struct proc_pollfd {
155 int fd;
156 int revents;
157 int pid;
158};
159
160static int poller_pid;
161static int proc_poll_pipe[2] = { -1, -1 };
162
163#endif /* !HAVE_POLLABLE_PROCFS */
164
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000165#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000166#define POLLWANT POLLWRNORM
167#else
168#define POLLWANT POLLPRI
169#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000170#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000171
172static void
173usage(ofp, exitval)
174FILE *ofp;
175int exitval;
176{
177 fprintf(ofp, "\
Grant Edwards8a082772011-04-07 20:25:40 +0000178usage: strace [-CdDffhiqrtttTvVxxy] [-a column] [-e expr] ... [-o file]\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000179 [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n\
Grant Edwards8a082772011-04-07 20:25:40 +0000180 [-P path] [command [arg ...]]\n\
Andreas Schwabb87d30c2010-06-11 15:49:36 +0200181 or: strace -c [-D] [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000182 [command [arg ...]]\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000183-c -- count time, calls, and errors for each syscall and report summary\n\
Andreas Schwabb87d30c2010-06-11 15:49:36 +0200184-C -- like -c but also print regular output while processes are running\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000185-f -- follow forks, -ff -- with output into separate files\n\
186-F -- attempt to follow vforks, -h -- print help message\n\
187-i -- print instruction pointer at time of syscall\n\
188-q -- suppress messages about attaching, detaching, etc.\n\
189-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
190-T -- print time spent in each syscall, -V -- print version\n\
191-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
192-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
Grant Edwards8a082772011-04-07 20:25:40 +0000193-y -- print paths associated with file descriptor arguments\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000194-a column -- alignment COLUMN for printing syscall results (default %d)\n\
195-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
196 options: trace, abbrev, verbose, raw, signal, read, or write\n\
197-o file -- send trace output to FILE instead of stderr\n\
198-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
199-p pid -- trace process with process id PID, may be repeated\n\
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000200-D -- run tracer process as a detached grandchild, not as parent\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000201-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
202-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
203-u username -- run command as username handling setuid and/or setgid\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000204-E var=val -- put var=val in the environment for command\n\
205-E var -- remove var from the environment for command\n\
Grant Edwards8a082772011-04-07 20:25:40 +0000206-P path -- trace accesses to path\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000207" /* this is broken, so don't document it
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000208-z -- print only succeeding syscalls\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000209 */
210, DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000211 exit(exitval);
212}
213
214#ifdef SVR4
215#ifdef MIPS
216void
217foobar()
218{
219}
220#endif /* MIPS */
221#endif /* SVR4 */
222
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400223/* Glue for systems without a MMU that cannot provide fork() */
224#ifdef HAVE_FORK
225# define strace_vforked 0
226#else
227# define strace_vforked 1
228# define fork() vfork()
229#endif
230
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000231static int
232set_cloexec_flag(int fd)
233{
234 int flags, newflags;
235
236 if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
237 {
238 fprintf(stderr, "%s: fcntl F_GETFD: %s\n",
239 progname, strerror(errno));
240 return -1;
241 }
242
243 newflags = flags | FD_CLOEXEC;
244 if (flags == newflags)
245 return 0;
246
247 if (fcntl(fd, F_SETFD, newflags) < 0)
248 {
249 fprintf(stderr, "%s: fcntl F_SETFD: %s\n",
250 progname, strerror(errno));
251 return -1;
252 }
253
254 return 0;
255}
256
257/*
258 * When strace is setuid executable, we have to swap uids
259 * before and after filesystem and process management operations.
260 */
261static void
262swap_uid(void)
263{
264#ifndef SVR4
265 int euid = geteuid(), uid = getuid();
266
267 if (euid != uid && setreuid(euid, uid) < 0)
268 {
269 fprintf(stderr, "%s: setreuid: %s\n",
270 progname, strerror(errno));
271 exit(1);
272 }
273#endif
274}
275
Roland McGrath4bfa6262007-07-05 20:03:16 +0000276#if _LFS64_LARGEFILE
277# define fopen_for_output fopen64
278#else
279# define fopen_for_output fopen
280#endif
281
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000282static FILE *
283strace_fopen(const char *path, const char *mode)
284{
285 FILE *fp;
286
287 swap_uid();
Roland McGrath4bfa6262007-07-05 20:03:16 +0000288 if ((fp = fopen_for_output(path, mode)) == NULL)
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000289 fprintf(stderr, "%s: can't fopen '%s': %s\n",
290 progname, path, strerror(errno));
291 swap_uid();
292 if (fp && set_cloexec_flag(fileno(fp)) < 0)
293 {
294 fclose(fp);
295 fp = NULL;
296 }
297 return fp;
298}
299
300static int popen_pid = -1;
301
302#ifndef _PATH_BSHELL
303# define _PATH_BSHELL "/bin/sh"
304#endif
305
306/*
307 * We cannot use standard popen(3) here because we have to distinguish
308 * popen child process from other processes we trace, and standard popen(3)
309 * does not export its child's pid.
310 */
311static FILE *
312strace_popen(const char *command)
313{
314 int fds[2];
315
316 swap_uid();
317 if (pipe(fds) < 0)
318 {
319 fprintf(stderr, "%s: pipe: %s\n",
320 progname, strerror(errno));
321 swap_uid();
322 return NULL;
323 }
324
325 if (set_cloexec_flag(fds[1]) < 0)
326 {
327 close(fds[0]);
328 close(fds[1]);
329 swap_uid();
330 return NULL;
331 }
332
333 if ((popen_pid = fork()) == -1)
334 {
335 fprintf(stderr, "%s: fork: %s\n",
336 progname, strerror(errno));
337 close(fds[0]);
338 close(fds[1]);
339 swap_uid();
340 return NULL;
341 }
342
343 if (popen_pid)
344 {
345 /* parent */
346 close(fds[0]);
347 swap_uid();
348 return fdopen(fds[1], "w");
349 } else
350 {
351 /* child */
352 close(fds[1]);
353 if (fds[0] && (dup2(fds[0], 0) || close(fds[0])))
354 {
355 fprintf(stderr, "%s: dup2: %s\n",
356 progname, strerror(errno));
357 _exit(1);
358 }
359 execl(_PATH_BSHELL, "sh", "-c", command, NULL);
360 fprintf(stderr, "%s: execl: %s: %s\n",
361 progname, _PATH_BSHELL, strerror(errno));
362 _exit(1);
363 }
364}
365
366static int
367newoutf(struct tcb *tcp)
368{
369 if (outfname && followfork > 1) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000370 char name[520 + sizeof(int) * 3];
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000371 FILE *fp;
372
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000373 sprintf(name, "%.512s.%u", outfname, tcp->pid);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000374 if ((fp = strace_fopen(name, "w")) == NULL)
375 return -1;
376 tcp->outf = fp;
377 }
378 return 0;
379}
380
Roland McGrath02203312007-06-11 22:06:31 +0000381static void
382startup_attach(void)
383{
384 int tcbi;
385 struct tcb *tcp;
386
387 /*
388 * Block user interruptions as we would leave the traced
389 * process stopped (process state T) if we would terminate in
390 * between PTRACE_ATTACH and wait4 () on SIGSTOP.
391 * We rely on cleanup () from this point on.
392 */
393 if (interactive)
394 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
395
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000396 if (daemonized_tracer) {
397 pid_t pid = fork();
398 if (pid < 0) {
399 _exit(1);
400 }
401 if (pid) { /* parent */
402 /*
403 * Wait for child to attach to straced process
404 * (our parent). Child SIGKILLs us after it attached.
405 * Parent's wait() is unblocked by our death,
406 * it proceeds to exec the straced program.
407 */
408 pause();
409 _exit(0); /* paranoia */
410 }
411 }
412
Roland McGrath02203312007-06-11 22:06:31 +0000413 for (tcbi = 0; tcbi < tcbtabsize; tcbi++) {
414 tcp = tcbtab[tcbi];
415 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
416 continue;
417#ifdef LINUX
418 if (tcp->flags & TCB_CLONE_THREAD)
419 continue;
420#endif
421 /* Reinitialize the output since it may have changed. */
422 tcp->outf = outf;
423 if (newoutf(tcp) < 0)
424 exit(1);
425
426#ifdef USE_PROCFS
427 if (proc_open(tcp, 1) < 0) {
428 fprintf(stderr, "trouble opening proc file\n");
429 droptcb(tcp);
430 continue;
431 }
432#else /* !USE_PROCFS */
433# ifdef LINUX
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000434 if (followfork && !daemonized_tracer) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000435 char procdir[sizeof("/proc/%d/task") + sizeof(int) * 3];
Roland McGrath02203312007-06-11 22:06:31 +0000436 DIR *dir;
437
438 sprintf(procdir, "/proc/%d/task", tcp->pid);
439 dir = opendir(procdir);
440 if (dir != NULL) {
441 unsigned int ntid = 0, nerr = 0;
442 struct dirent *de;
443 int tid;
444 while ((de = readdir(dir)) != NULL) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000445 if (de->d_fileno == 0)
Roland McGrath02203312007-06-11 22:06:31 +0000446 continue;
447 tid = atoi(de->d_name);
448 if (tid <= 0)
449 continue;
450 ++ntid;
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000451 if (ptrace(PTRACE_ATTACH, tid, (char *) 1, 0) < 0)
Roland McGrath02203312007-06-11 22:06:31 +0000452 ++nerr;
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000453 else if (tid != tcbtab[tcbi]->pid) {
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000454 tcp = alloctcb(tid);
Wang Chao21b8db42010-08-27 17:43:16 +0800455 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_FOLLOWFORK;
Roland McGrath02203312007-06-11 22:06:31 +0000456 tcbtab[tcbi]->nchildren++;
457 tcbtab[tcbi]->nclone_threads++;
Roland McGrath02203312007-06-11 22:06:31 +0000458 tcp->parent = tcbtab[tcbi];
459 }
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000460 if (interactive) {
461 sigprocmask(SIG_SETMASK, &empty_set, NULL);
462 if (interrupted)
463 return;
464 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
465 }
Roland McGrath02203312007-06-11 22:06:31 +0000466 }
467 closedir(dir);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000468 ntid -= nerr;
469 if (ntid == 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000470 perror("attach: ptrace(PTRACE_ATTACH, ...)");
471 droptcb(tcp);
472 continue;
473 }
474 if (!qflag) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000475 fprintf(stderr, ntid > 1
476? "Process %u attached with %u threads - interrupt to quit\n"
477: "Process %u attached - interrupt to quit\n",
478 tcbtab[tcbi]->pid, ntid);
Roland McGrath02203312007-06-11 22:06:31 +0000479 }
480 continue;
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000481 } /* if (opendir worked) */
482 } /* if (-f) */
Roland McGrath02203312007-06-11 22:06:31 +0000483# endif
484 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
485 perror("attach: ptrace(PTRACE_ATTACH, ...)");
486 droptcb(tcp);
487 continue;
488 }
489 /* INTERRUPTED is going to be checked at the top of TRACE. */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000490
491 if (daemonized_tracer) {
492 /*
493 * It is our grandparent we trace, not a -p PID.
494 * Don't want to just detach on exit, so...
495 */
496 tcp->flags &= ~TCB_ATTACHED;
497 /*
498 * Make parent go away.
499 * Also makes grandparent's wait() unblock.
500 */
501 kill(getppid(), SIGKILL);
502 }
503
Roland McGrath02203312007-06-11 22:06:31 +0000504#endif /* !USE_PROCFS */
505 if (!qflag)
506 fprintf(stderr,
507 "Process %u attached - interrupt to quit\n",
508 tcp->pid);
509 }
510
511 if (interactive)
512 sigprocmask(SIG_SETMASK, &empty_set, NULL);
513}
514
515static void
516startup_child (char **argv)
517{
518 struct stat statbuf;
519 const char *filename;
520 char pathname[MAXPATHLEN];
521 int pid = 0;
522 struct tcb *tcp;
523
524 filename = argv[0];
525 if (strchr(filename, '/')) {
526 if (strlen(filename) > sizeof pathname - 1) {
527 errno = ENAMETOOLONG;
528 perror("strace: exec");
529 exit(1);
530 }
531 strcpy(pathname, filename);
532 }
533#ifdef USE_DEBUGGING_EXEC
534 /*
535 * Debuggers customarily check the current directory
536 * first regardless of the path but doing that gives
537 * security geeks a panic attack.
538 */
539 else if (stat(filename, &statbuf) == 0)
540 strcpy(pathname, filename);
541#endif /* USE_DEBUGGING_EXEC */
542 else {
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000543 const char *path;
Roland McGrath02203312007-06-11 22:06:31 +0000544 int m, n, len;
545
546 for (path = getenv("PATH"); path && *path; path += m) {
547 if (strchr(path, ':')) {
548 n = strchr(path, ':') - path;
549 m = n + 1;
550 }
551 else
552 m = n = strlen(path);
553 if (n == 0) {
554 if (!getcwd(pathname, MAXPATHLEN))
555 continue;
556 len = strlen(pathname);
557 }
558 else if (n > sizeof pathname - 1)
559 continue;
560 else {
561 strncpy(pathname, path, n);
562 len = n;
563 }
564 if (len && pathname[len - 1] != '/')
565 pathname[len++] = '/';
566 strcpy(pathname + len, filename);
567 if (stat(pathname, &statbuf) == 0 &&
568 /* Accept only regular files
569 with some execute bits set.
570 XXX not perfect, might still fail */
571 S_ISREG(statbuf.st_mode) &&
572 (statbuf.st_mode & 0111))
573 break;
574 }
575 }
576 if (stat(pathname, &statbuf) < 0) {
577 fprintf(stderr, "%s: %s: command not found\n",
578 progname, filename);
579 exit(1);
580 }
Dmitry V. Levina6809652008-11-10 17:14:58 +0000581 strace_child = pid = fork();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000582 if (pid < 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000583 perror("strace: fork");
584 cleanup();
585 exit(1);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000586 }
587 if ((pid != 0 && daemonized_tracer) /* parent: to become a traced process */
588 || (pid == 0 && !daemonized_tracer) /* child: to become a traced process */
589 ) {
590 pid = getpid();
Roland McGrath02203312007-06-11 22:06:31 +0000591#ifdef USE_PROCFS
592 if (outf != stderr) close (fileno (outf));
593#ifdef MIPS
594 /* Kludge for SGI, see proc_open for details. */
595 sa.sa_handler = foobar;
596 sa.sa_flags = 0;
597 sigemptyset(&sa.sa_mask);
598 sigaction(SIGINT, &sa, NULL);
599#endif /* MIPS */
600#ifndef FREEBSD
601 pause();
602#else /* FREEBSD */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000603 kill(pid, SIGSTOP); /* stop HERE */
Roland McGrath02203312007-06-11 22:06:31 +0000604#endif /* FREEBSD */
605#else /* !USE_PROCFS */
606 if (outf!=stderr)
607 close(fileno (outf));
608
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000609 if (!daemonized_tracer) {
610 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
611 perror("strace: ptrace(PTRACE_TRACEME, ...)");
612 exit(1);
613 }
614 if (debug)
615 kill(pid, SIGSTOP);
Roland McGrath02203312007-06-11 22:06:31 +0000616 }
Roland McGrath02203312007-06-11 22:06:31 +0000617
618 if (username != NULL || geteuid() == 0) {
619 uid_t run_euid = run_uid;
620 gid_t run_egid = run_gid;
621
622 if (statbuf.st_mode & S_ISUID)
623 run_euid = statbuf.st_uid;
624 if (statbuf.st_mode & S_ISGID)
625 run_egid = statbuf.st_gid;
626
627 /*
628 * It is important to set groups before we
629 * lose privileges on setuid.
630 */
631 if (username != NULL) {
632 if (initgroups(username, run_gid) < 0) {
633 perror("initgroups");
634 exit(1);
635 }
636 if (setregid(run_gid, run_egid) < 0) {
637 perror("setregid");
638 exit(1);
639 }
640 if (setreuid(run_uid, run_euid) < 0) {
641 perror("setreuid");
642 exit(1);
643 }
644 }
645 }
646 else
647 setreuid(run_uid, run_uid);
648
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000649 if (!daemonized_tracer) {
650 /*
651 * Induce an immediate stop so that the parent
652 * will resume us with PTRACE_SYSCALL and display
653 * this execve call normally.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400654 * Unless of course we're on a no-MMU system where
655 * we vfork()-ed, so we cannot stop the child.
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000656 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400657 if (!strace_vforked)
658 kill(getpid(), SIGSTOP);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000659 } else {
660 struct sigaction sv_sigchld;
661 sigaction(SIGCHLD, NULL, &sv_sigchld);
662 /*
663 * Make sure it is not SIG_IGN, otherwise wait
664 * will not block.
665 */
666 signal(SIGCHLD, SIG_DFL);
667 /*
668 * Wait for grandchild to attach to us.
669 * It kills child after that, and wait() unblocks.
670 */
671 alarm(3);
672 wait(NULL);
673 alarm(0);
674 sigaction(SIGCHLD, &sv_sigchld, NULL);
675 }
Roland McGrath02203312007-06-11 22:06:31 +0000676#endif /* !USE_PROCFS */
677
678 execv(pathname, argv);
679 perror("strace: exec");
680 _exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000681 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000682
683 /* We are the tracer. */
684 tcp = alloctcb(daemonized_tracer ? getppid() : pid);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000685 if (daemonized_tracer) {
686 /* We want subsequent startup_attach() to attach to it. */
687 tcp->flags |= TCB_ATTACHED;
688 }
Roland McGrath02203312007-06-11 22:06:31 +0000689#ifdef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000690 if (proc_open(tcp, 0) < 0) {
691 fprintf(stderr, "trouble opening proc file\n");
692 cleanup();
693 exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000694 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000695#endif /* USE_PROCFS */
Roland McGrath02203312007-06-11 22:06:31 +0000696}
697
Wang Chaob13c0de2010-11-12 17:25:19 +0800698#ifdef LINUX
699/*
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000700 * Test whether the kernel support PTRACE_O_TRACECLONE et al options.
Wang Chaob13c0de2010-11-12 17:25:19 +0800701 * First fork a new child, call ptrace with PTRACE_SETOPTIONS on it,
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000702 * and then see which options are supported by the kernel.
Wang Chaob13c0de2010-11-12 17:25:19 +0800703 */
704static int
705test_ptrace_setoptions(void)
706{
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000707 int pid, expected_grandchild = 0, found_grandchild = 0;
708 const unsigned int test_options = PTRACE_O_TRACECLONE |
709 PTRACE_O_TRACEFORK |
710 PTRACE_O_TRACEVFORK;
Wang Chaob13c0de2010-11-12 17:25:19 +0800711
712 if ((pid = fork()) < 0)
713 return -1;
714 else if (pid == 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000715 if (ptrace(PTRACE_TRACEME, 0, (char *)1, 0) < 0)
Wang Chaob13c0de2010-11-12 17:25:19 +0800716 _exit(1);
Wang Chaob13c0de2010-11-12 17:25:19 +0800717 kill(getpid(), SIGSTOP);
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000718 _exit(fork() < 0);
Wang Chaob13c0de2010-11-12 17:25:19 +0800719 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000720
721 while (1) {
722 int status, tracee_pid;
723
724 tracee_pid = wait(&status);
725 if (tracee_pid == -1) {
726 if (errno == EINTR)
727 continue;
728 else if (errno == ECHILD)
729 break;
730 perror("test_ptrace_setoptions");
731 return -1;
732 }
733 if (tracee_pid != pid) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000734 found_grandchild = tracee_pid;
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000735 if (ptrace(PTRACE_CONT, tracee_pid, 0, 0) < 0 &&
736 errno != ESRCH)
737 kill(tracee_pid, SIGKILL);
738 }
739 else if (WIFSTOPPED(status)) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000740 switch (WSTOPSIG(status)) {
741 case SIGSTOP:
742 if (ptrace(PTRACE_SETOPTIONS, pid,
743 NULL, test_options) < 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000744 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800745 return -1;
746 }
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000747 break;
748 case SIGTRAP:
749 if (status >> 16 == PTRACE_EVENT_FORK) {
750 long msg = 0;
751
752 if (ptrace(PTRACE_GETEVENTMSG, pid,
753 NULL, (long) &msg) == 0)
754 expected_grandchild = msg;
755 }
756 break;
Wang Chaob13c0de2010-11-12 17:25:19 +0800757 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000758 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0 &&
759 errno != ESRCH)
760 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800761 }
762 }
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000763 if (expected_grandchild && expected_grandchild == found_grandchild)
764 ptrace_setoptions |= test_options;
Wang Chaob13c0de2010-11-12 17:25:19 +0800765 return 0;
766}
767#endif
768
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000769int
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000770main(int argc, char *argv[])
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000771{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000772 struct tcb *tcp;
773 int c, pid = 0;
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000774 int optF = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000775 struct sigaction sa;
776
777 static char buf[BUFSIZ];
778
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000779 progname = argv[0] ? argv[0] : "strace";
780
Roland McGrathee9d4352002-12-18 04:16:10 +0000781 /* Allocate the initial tcbtab. */
782 tcbtabsize = argc; /* Surely enough for all -p args. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000783 if ((tcbtab = calloc(tcbtabsize, sizeof tcbtab[0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000784 fprintf(stderr, "%s: out of memory\n", progname);
785 exit(1);
786 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000787 if ((tcbtab[0] = calloc(tcbtabsize, sizeof tcbtab[0][0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000788 fprintf(stderr, "%s: out of memory\n", progname);
789 exit(1);
790 }
Roland McGrathee9d4352002-12-18 04:16:10 +0000791 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
792 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
793
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000794 outf = stderr;
795 interactive = 1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000796 set_sortby(DEFAULT_SORTBY);
797 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000798 qualify("trace=all");
799 qualify("abbrev=all");
800 qualify("verbose=all");
801 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000802 while ((c = getopt(argc, argv,
Grant Edwards8a082772011-04-07 20:25:40 +0000803 "+cCdfFhiqrtTvVxyz"
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000804#ifndef USE_PROCFS
805 "D"
806#endif
Grant Edwards8a082772011-04-07 20:25:40 +0000807 "a:e:o:O:p:s:S:u:E:P:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000808 switch (c) {
809 case 'c':
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000810 if (cflag == CFLAG_BOTH) {
811 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
812 progname);
813 exit(1);
814 }
815 cflag = CFLAG_ONLY_STATS;
816 break;
817 case 'C':
818 if (cflag == CFLAG_ONLY_STATS) {
819 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
820 progname);
821 exit(1);
822 }
823 cflag = CFLAG_BOTH;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000824 break;
825 case 'd':
826 debug++;
827 break;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000828#ifndef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000829 case 'D':
830 daemonized_tracer = 1;
831 break;
832#endif
Roland McGrath41c48222008-07-18 00:25:10 +0000833 case 'F':
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000834 optF = 1;
835 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000836 case 'f':
837 followfork++;
838 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000839 case 'h':
840 usage(stdout, 0);
841 break;
842 case 'i':
843 iflag++;
844 break;
845 case 'q':
846 qflag++;
847 break;
848 case 'r':
849 rflag++;
850 tflag++;
851 break;
852 case 't':
853 tflag++;
854 break;
855 case 'T':
856 dtime++;
857 break;
858 case 'x':
859 xflag++;
860 break;
Grant Edwards8a082772011-04-07 20:25:40 +0000861 case 'y':
862 show_fd_path = 1;
863 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000864 case 'v':
865 qualify("abbrev=none");
866 break;
867 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +0000868 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000869 exit(0);
870 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000871 case 'z':
872 not_failing_only = 1;
873 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000874 case 'a':
875 acolumn = atoi(optarg);
876 break;
877 case 'e':
878 qualify(optarg);
879 break;
880 case 'o':
881 outfname = strdup(optarg);
882 break;
883 case 'O':
884 set_overhead(atoi(optarg));
885 break;
886 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +0000887 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000888 fprintf(stderr, "%s: Invalid process id: %s\n",
889 progname, optarg);
890 break;
891 }
892 if (pid == getpid()) {
Wichert Akkerman54a47671999-10-17 00:57:34 +0000893 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000894 break;
895 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000896 tcp = alloc_tcb(pid, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000897 tcp->flags |= TCB_ATTACHED;
898 pflag_seen++;
899 break;
Grant Edwards8a082772011-04-07 20:25:40 +0000900 case 'P':
901 tracing_paths = 1;
902 if (pathtrace_select(optarg)) {
903 fprintf(stderr,"%s : failed to select path '%s'\n", progname, optarg);
904 exit(1);
905 }
906 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000907 case 's':
908 max_strlen = atoi(optarg);
Roland McGrathdccec722005-05-09 07:45:47 +0000909 if (max_strlen < 0) {
910 fprintf(stderr,
911 "%s: invalid -s argument: %s\n",
912 progname, optarg);
913 exit(1);
914 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000915 break;
916 case 'S':
917 set_sortby(optarg);
918 break;
919 case 'u':
920 username = strdup(optarg);
921 break;
Roland McGrathde6e5332003-01-24 04:31:23 +0000922 case 'E':
923 if (putenv(optarg) < 0) {
924 fprintf(stderr, "%s: out of memory\n",
925 progname);
926 exit(1);
927 }
928 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000929 default:
930 usage(stderr, 1);
931 break;
932 }
933 }
934
Roland McGrathd0c4c0c2006-04-25 07:39:40 +0000935 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +0000936 usage(stderr, 1);
937
Wang Chaod322a4b2010-08-05 14:30:11 +0800938 if (pflag_seen && daemonized_tracer) {
939 fprintf(stderr,
940 "%s: -D and -p are mutually exclusive options\n",
941 progname);
942 exit(1);
943 }
944
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000945 if (!followfork)
946 followfork = optF;
947
Roland McGrathcb9def62006-04-25 07:48:03 +0000948 if (followfork > 1 && cflag) {
949 fprintf(stderr,
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000950 "%s: (-c or -C) and -ff are mutually exclusive options\n",
Roland McGrathcb9def62006-04-25 07:48:03 +0000951 progname);
952 exit(1);
953 }
954
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000955 /* See if they want to run as another user. */
956 if (username != NULL) {
957 struct passwd *pent;
958
959 if (getuid() != 0 || geteuid() != 0) {
960 fprintf(stderr,
961 "%s: you must be root to use the -u option\n",
962 progname);
963 exit(1);
964 }
965 if ((pent = getpwnam(username)) == NULL) {
966 fprintf(stderr, "%s: cannot find user `%s'\n",
Roland McGrath09553f82007-07-05 19:31:49 +0000967 progname, username);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000968 exit(1);
969 }
970 run_uid = pent->pw_uid;
971 run_gid = pent->pw_gid;
972 }
973 else {
974 run_uid = getuid();
975 run_gid = getgid();
976 }
977
Dmitry V. Levin8044bc12010-12-07 12:50:49 +0000978#ifdef LINUX
979 if (followfork) {
980 if (test_ptrace_setoptions() < 0) {
981 fprintf(stderr,
982 "Test for options supported by PTRACE_SETOPTIONS "
983 "failed, giving up using this feature.\n");
984 ptrace_setoptions = 0;
985 }
986 if (debug)
987 fprintf(stderr, "ptrace_setoptions = %#x\n",
988 ptrace_setoptions);
989 }
990#endif
991
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000992 /* Check if they want to redirect the output. */
993 if (outfname) {
Roland McGrath37b9a662003-11-07 02:26:54 +0000994 /* See if they want to pipe the output. */
995 if (outfname[0] == '|' || outfname[0] == '!') {
996 /*
997 * We can't do the <outfname>.PID funny business
998 * when using popen, so prohibit it.
999 */
1000 if (followfork > 1) {
1001 fprintf(stderr, "\
1002%s: piping the output and -ff are mutually exclusive options\n",
1003 progname);
1004 exit(1);
1005 }
1006
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001007 if ((outf = strace_popen(outfname + 1)) == NULL)
Roland McGrath37b9a662003-11-07 02:26:54 +00001008 exit(1);
Roland McGrath37b9a662003-11-07 02:26:54 +00001009 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001010 else if (followfork <= 1 &&
1011 (outf = strace_fopen(outfname, "w")) == NULL)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001012 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001013 }
1014
Roland McGrath37b9a662003-11-07 02:26:54 +00001015 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001016 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +00001017 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001018 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001019 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +00001020 }
Wang Chaob13c0de2010-11-12 17:25:19 +08001021
Roland McGrath54cc1c82007-11-03 23:34:11 +00001022 /* Valid states here:
1023 optind < argc pflag_seen outfname interactive
1024 1 0 0 1
1025 0 1 0 1
1026 1 0 1 0
1027 0 1 1 1
1028 */
1029
1030 /* STARTUP_CHILD must be called before the signal handlers get
1031 installed below as they are inherited into the spawned process.
1032 Also we do not need to be protected by them as during interruption
1033 in the STARTUP_CHILD mode we kill the spawned process anyway. */
1034 if (!pflag_seen)
1035 startup_child(&argv[optind]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001036
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001037 sigemptyset(&empty_set);
1038 sigemptyset(&blocked_set);
1039 sa.sa_handler = SIG_IGN;
1040 sigemptyset(&sa.sa_mask);
1041 sa.sa_flags = 0;
1042 sigaction(SIGTTOU, &sa, NULL);
1043 sigaction(SIGTTIN, &sa, NULL);
1044 if (interactive) {
1045 sigaddset(&blocked_set, SIGHUP);
1046 sigaddset(&blocked_set, SIGINT);
1047 sigaddset(&blocked_set, SIGQUIT);
1048 sigaddset(&blocked_set, SIGPIPE);
1049 sigaddset(&blocked_set, SIGTERM);
1050 sa.sa_handler = interrupt;
1051#ifdef SUNOS4
1052 /* POSIX signals on sunos4.1 are a little broken. */
1053 sa.sa_flags = SA_INTERRUPT;
1054#endif /* SUNOS4 */
1055 }
1056 sigaction(SIGHUP, &sa, NULL);
1057 sigaction(SIGINT, &sa, NULL);
1058 sigaction(SIGQUIT, &sa, NULL);
1059 sigaction(SIGPIPE, &sa, NULL);
1060 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001061#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001062 sa.sa_handler = reaper;
1063 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +00001064#else
1065 /* Make sure SIGCHLD has the default action so that waitpid
1066 definitely works without losing track of children. The user
1067 should not have given us a bogus state to inherit, but he might
1068 have. Arguably we should detect SIG_IGN here and pass it on
1069 to children, but probably noone really needs that. */
1070 sa.sa_handler = SIG_DFL;
1071 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001072#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001073
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +00001074 if (pflag_seen || daemonized_tracer)
Roland McGrath02203312007-06-11 22:06:31 +00001075 startup_attach();
Roland McGrath02203312007-06-11 22:06:31 +00001076
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001077 if (trace() < 0)
1078 exit(1);
1079 cleanup();
Dmitry V. Levina6809652008-11-10 17:14:58 +00001080 fflush(NULL);
1081 if (exit_code > 0xff) {
1082 /* Child was killed by a signal, mimic that. */
1083 exit_code &= 0xff;
1084 signal(exit_code, SIG_DFL);
1085 raise(exit_code);
1086 /* Paranoia - what if this signal is not fatal?
1087 Exit with 128 + signo then. */
1088 exit_code += 128;
1089 }
1090 exit(exit_code);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001091}
1092
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001093void
1094expand_tcbtab(void)
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001095{
1096 /* Allocate some more TCBs and expand the table.
1097 We don't want to relocate the TCBs because our
1098 callers have pointers and it would be a pain.
1099 So tcbtab is a table of pointers. Since we never
1100 free the TCBs, we allocate a single chunk of many. */
1101 struct tcb **newtab = (struct tcb **)
1102 realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
1103 struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
1104 sizeof *newtcbs);
1105 int i;
1106 if (newtab == NULL || newtcbs == NULL) {
Dmitry V. Levin76860f62006-10-11 22:55:25 +00001107 fprintf(stderr, "%s: expand_tcbtab: out of memory\n",
1108 progname);
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001109 cleanup();
1110 exit(1);
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001111 }
1112 for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
1113 newtab[i] = &newtcbs[i - tcbtabsize];
1114 tcbtabsize *= 2;
1115 tcbtab = newtab;
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001116}
1117
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001118struct tcb *
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001119alloc_tcb(int pid, int command_options_parsed)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001120{
1121 int i;
1122 struct tcb *tcp;
1123
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001124 if (nprocs == tcbtabsize)
1125 expand_tcbtab();
1126
Roland McGrathee9d4352002-12-18 04:16:10 +00001127 for (i = 0; i < tcbtabsize; i++) {
1128 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001129 if ((tcp->flags & TCB_INUSE) == 0) {
1130 tcp->pid = pid;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001131 tcp->parent = NULL;
1132 tcp->nchildren = 0;
1133 tcp->nzombies = 0;
1134#ifdef TCB_CLONE_THREAD
Wang Chao21b8db42010-08-27 17:43:16 +08001135 tcp->nclone_threads = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001136 tcp->nclone_waiting = 0;
1137#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001138 tcp->flags = TCB_INUSE | TCB_STARTUP;
1139 tcp->outf = outf; /* Initialise to current out file */
Andreas Schwabccdff482009-10-27 16:27:13 +01001140 tcp->curcol = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001141 tcp->stime.tv_sec = 0;
1142 tcp->stime.tv_usec = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001143 tcp->pfd = -1;
1144 nprocs++;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001145 if (command_options_parsed)
1146 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001147 return tcp;
1148 }
1149 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001150 fprintf(stderr, "%s: bug in alloc_tcb\n", progname);
1151 cleanup();
1152 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001153}
1154
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001155#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001156int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001157proc_open(struct tcb *tcp, int attaching)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001158{
1159 char proc[32];
1160 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001161#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +00001162 int i;
1163 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001164 sigset_t signals;
1165 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001166#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001167#ifndef HAVE_POLLABLE_PROCFS
1168 static int last_pfd;
1169#endif
1170
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001171#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001172 /* Open the process pseudo-files in /proc. */
1173 sprintf(proc, "/proc/%d/ctl", tcp->pid);
1174 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001175 perror("strace: open(\"/proc/...\", ...)");
1176 return -1;
1177 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001178 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001179 return -1;
1180 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001181 sprintf(proc, "/proc/%d/status", tcp->pid);
1182 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
1183 perror("strace: open(\"/proc/...\", ...)");
1184 return -1;
1185 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001186 if (set_cloexec_flag(tcp->pfd_stat) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001187 return -1;
1188 }
1189 sprintf(proc, "/proc/%d/as", tcp->pid);
1190 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
1191 perror("strace: open(\"/proc/...\", ...)");
1192 return -1;
1193 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001194 if (set_cloexec_flag(tcp->pfd_as) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001195 return -1;
1196 }
1197#else
1198 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001199#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001200 sprintf(proc, "/proc/%d", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001201 tcp->pfd = open(proc, O_RDWR|O_EXCL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001202#else /* FREEBSD */
1203 sprintf(proc, "/proc/%d/mem", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001204 tcp->pfd = open(proc, O_RDWR);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001205#endif /* FREEBSD */
Andreas Schwab372cc842010-07-09 11:49:27 +02001206 if (tcp->pfd < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001207 perror("strace: open(\"/proc/...\", ...)");
1208 return -1;
1209 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001210 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001211 return -1;
1212 }
1213#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001214#ifdef FREEBSD
1215 sprintf(proc, "/proc/%d/regs", tcp->pid);
1216 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
1217 perror("strace: open(\"/proc/.../regs\", ...)");
1218 return -1;
1219 }
1220 if (cflag) {
1221 sprintf(proc, "/proc/%d/status", tcp->pid);
1222 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
1223 perror("strace: open(\"/proc/.../status\", ...)");
1224 return -1;
1225 }
1226 } else
1227 tcp->pfd_status = -1;
1228#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001229 rebuild_pollv();
1230 if (!attaching) {
1231 /*
1232 * Wait for the child to pause. Because of a race
1233 * condition we have to poll for the event.
1234 */
1235 for (;;) {
1236 if (IOCTL_STATUS (tcp) < 0) {
1237 perror("strace: PIOCSTATUS");
1238 return -1;
1239 }
1240 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001241 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001242 }
1243 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001244#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001245 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001246 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001247 perror("strace: PIOCSTOP");
1248 return -1;
1249 }
Roland McGrath553a6092002-12-16 20:40:39 +00001250#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001251#ifdef PIOCSET
1252 /* Set Run-on-Last-Close. */
1253 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001254 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001255 perror("PIOCSET PR_RLC");
1256 return -1;
1257 }
1258 /* Set or Reset Inherit-on-Fork. */
1259 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001260 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001261 perror("PIOC{SET,RESET} PR_FORK");
1262 return -1;
1263 }
1264#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +00001265#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001266 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
1267 perror("PIOCSRLC");
1268 return -1;
1269 }
1270 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
1271 perror("PIOC{S,R}FORK");
1272 return -1;
1273 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001274#else /* FREEBSD */
1275 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
1276 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
1277 perror("PIOCGFL");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001278 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001279 }
1280 arg &= ~PF_LINGER;
1281 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001282 perror("PIOCSFL");
1283 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001284 }
1285#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001286#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001287#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +00001288 /* Enable all syscall entries we care about. */
1289 premptyset(&syscalls);
1290 for (i = 1; i < MAX_QUALS; ++i) {
1291 if (i > (sizeof syscalls) * CHAR_BIT) break;
1292 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
1293 }
1294 praddset (&syscalls, SYS_execve);
1295 if (followfork) {
1296 praddset (&syscalls, SYS_fork);
1297#ifdef SYS_forkall
1298 praddset (&syscalls, SYS_forkall);
1299#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001300#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +00001301 praddset (&syscalls, SYS_fork1);
1302#endif
1303#ifdef SYS_rfork1
1304 praddset (&syscalls, SYS_rfork1);
1305#endif
1306#ifdef SYS_rforkall
1307 praddset (&syscalls, SYS_rforkall);
1308#endif
1309 }
1310 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001311 perror("PIOCSENTRY");
1312 return -1;
1313 }
John Hughes19e49982001-10-19 08:59:12 +00001314 /* Enable the syscall exits. */
1315 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001316 perror("PIOSEXIT");
1317 return -1;
1318 }
John Hughes19e49982001-10-19 08:59:12 +00001319 /* Enable signals we care about. */
1320 premptyset(&signals);
1321 for (i = 1; i < MAX_QUALS; ++i) {
1322 if (i > (sizeof signals) * CHAR_BIT) break;
1323 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
1324 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001325 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001326 perror("PIOCSTRACE");
1327 return -1;
1328 }
John Hughes19e49982001-10-19 08:59:12 +00001329 /* Enable faults we care about */
1330 premptyset(&faults);
1331 for (i = 1; i < MAX_QUALS; ++i) {
1332 if (i > (sizeof faults) * CHAR_BIT) break;
1333 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
1334 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001335 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001336 perror("PIOCSFAULT");
1337 return -1;
1338 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001339#else /* FREEBSD */
1340 /* set events flags. */
1341 arg = S_SIG | S_SCE | S_SCX ;
1342 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
1343 perror("PIOCBIS");
1344 return -1;
1345 }
1346#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001347 if (!attaching) {
1348#ifdef MIPS
1349 /*
1350 * The SGI PRSABORT doesn't work for pause() so
1351 * we send it a caught signal to wake it up.
1352 */
1353 kill(tcp->pid, SIGINT);
1354#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +00001355#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001356 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001357 arg = PRSABORT;
1358 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001359 perror("PIOCRUN");
1360 return -1;
1361 }
Roland McGrath553a6092002-12-16 20:40:39 +00001362#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001363#endif /* !MIPS*/
1364#ifdef FREEBSD
1365 /* wake up the child if it received the SIGSTOP */
1366 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001367#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001368 for (;;) {
1369 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001370 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001371 perror("PIOCWSTOP");
1372 return -1;
1373 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001374 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001375 tcp->flags &= ~TCB_INSYSCALL;
1376 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001377 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001378 break;
1379 }
1380 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001381#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001382 arg = 0;
1383 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001384#else /* FREEBSD */
1385 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001386#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001387 perror("PIOCRUN");
1388 return -1;
1389 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001390#ifdef FREEBSD
1391 /* handle the case where we "opened" the child before
1392 it did the kill -STOP */
1393 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1394 tcp->status.PR_WHAT == SIGSTOP)
1395 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001396#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001397 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001398#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001399 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001400#else /* FREEBSD */
1401 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001402 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001403 /* We are attaching to an already running process.
1404 * Try to figure out the state of the process in syscalls,
1405 * to handle the first event well.
1406 * This is done by having a look at the "wchan" property of the
1407 * process, which tells where it is stopped (if it is). */
1408 FILE * status;
1409 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001410
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001411 sprintf(proc, "/proc/%d/status", tcp->pid);
1412 status = fopen(proc, "r");
1413 if (status &&
1414 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1415 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1416 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1417 strcmp(wchan, "stopevent")) {
1418 /* The process is asleep in the middle of a syscall.
1419 Fake the syscall entry event */
1420 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1421 tcp->status.PR_WHY = PR_SYSENTRY;
1422 trace_syscall(tcp);
1423 }
1424 if (status)
1425 fclose(status);
1426 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001427 }
1428#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001429#ifndef HAVE_POLLABLE_PROCFS
1430 if (proc_poll_pipe[0] != -1)
1431 proc_poller(tcp->pfd);
1432 else if (nprocs > 1) {
1433 proc_poll_open();
1434 proc_poller(last_pfd);
1435 proc_poller(tcp->pfd);
1436 }
1437 last_pfd = tcp->pfd;
1438#endif /* !HAVE_POLLABLE_PROCFS */
1439 return 0;
1440}
1441
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001442#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001443
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001444struct tcb *
Roland McGrath54e931f2010-09-14 18:59:20 -07001445pid2tcb(int pid)
1446{
1447 int i;
1448
1449 if (pid <= 0)
1450 return NULL;
1451
1452 for (i = 0; i < tcbtabsize; i++) {
1453 struct tcb *tcp = tcbtab[i];
1454 if (tcp->pid == pid && (tcp->flags & TCB_INUSE))
1455 return tcp;
1456 }
1457
1458 return NULL;
1459}
1460
1461#ifdef USE_PROCFS
1462
1463static struct tcb *
1464first_used_tcb(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001465{
1466 int i;
1467 struct tcb *tcp;
Roland McGrathee9d4352002-12-18 04:16:10 +00001468 for (i = 0; i < tcbtabsize; i++) {
1469 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001470 if (tcp->flags & TCB_INUSE)
1471 return tcp;
1472 }
1473 return NULL;
1474}
1475
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001476static struct tcb *
1477pfd2tcb(pfd)
1478int pfd;
1479{
1480 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001481
Roland McGrathca16be82003-01-10 19:55:28 +00001482 for (i = 0; i < tcbtabsize; i++) {
1483 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001484 if (tcp->pfd != pfd)
1485 continue;
1486 if (tcp->flags & TCB_INUSE)
1487 return tcp;
1488 }
1489 return NULL;
1490}
1491
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001492#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001493
1494void
1495droptcb(tcp)
1496struct tcb *tcp;
1497{
1498 if (tcp->pid == 0)
1499 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001500#ifdef TCB_CLONE_THREAD
1501 if (tcp->nclone_threads > 0) {
1502 /* There are other threads left in this process, but this
1503 is the one whose PID represents the whole process.
1504 We need to keep this record around as a zombie until
1505 all the threads die. */
1506 tcp->flags |= TCB_EXITING;
1507 return;
1508 }
1509#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001510 nprocs--;
1511 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001512
Roland McGrathe29341c2003-01-10 20:14:20 +00001513 if (tcp->parent != NULL) {
1514 tcp->parent->nchildren--;
1515#ifdef TCB_CLONE_THREAD
Roland McGrathe29341c2003-01-10 20:14:20 +00001516 if (tcp->flags & TCB_CLONE_THREAD)
1517 tcp->parent->nclone_threads--;
1518#endif
Wang Chao21b8db42010-08-27 17:43:16 +08001519 tcp->parent->nzombies++;
Roland McGrath276ceb32007-11-13 08:12:12 +00001520#ifdef LINUX
1521 /* Update `tcp->parent->parent->nchildren' and the other fields
1522 like NCLONE_DETACHED, only for zombie group leader that has
1523 already reported and been short-circuited at the top of this
1524 function. The same condition as at the top of DETACH. */
1525 if ((tcp->flags & TCB_CLONE_THREAD) &&
1526 tcp->parent->nclone_threads == 0 &&
1527 (tcp->parent->flags & TCB_EXITING))
1528 droptcb(tcp->parent);
1529#endif
Roland McGrathe29341c2003-01-10 20:14:20 +00001530 tcp->parent = NULL;
1531 }
1532
1533 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001534 if (tcp->pfd != -1) {
1535 close(tcp->pfd);
1536 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001537#ifdef FREEBSD
1538 if (tcp->pfd_reg != -1) {
1539 close(tcp->pfd_reg);
1540 tcp->pfd_reg = -1;
1541 }
1542 if (tcp->pfd_status != -1) {
1543 close(tcp->pfd_status);
1544 tcp->pfd_status = -1;
1545 }
Roland McGrath553a6092002-12-16 20:40:39 +00001546#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001547#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001548 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001549#endif
1550 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001551
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001552 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001553 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001554
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001555 tcp->outf = 0;
1556}
1557
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001558#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001559
1560static int
1561resume(tcp)
1562struct tcb *tcp;
1563{
1564 if (tcp == NULL)
1565 return -1;
1566
1567 if (!(tcp->flags & TCB_SUSPENDED)) {
1568 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1569 return -1;
1570 }
1571 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001572#ifdef TCB_CLONE_THREAD
1573 if (tcp->flags & TCB_CLONE_THREAD)
1574 tcp->parent->nclone_waiting--;
1575#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001576
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001577 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001578 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001579
1580 if (!qflag)
1581 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1582 return 0;
1583}
1584
Roland McGrath1bfd3102007-08-03 10:02:00 +00001585static int
1586resume_from_tcp (struct tcb *tcp)
1587{
1588 int error = 0;
1589 int resumed = 0;
1590
1591 /* XXX This won't always be quite right (but it never was).
1592 A waiter with argument 0 or < -1 is waiting for any pid in
1593 a particular pgrp, which this child might or might not be
1594 in. The waiter will only wake up if it's argument is -1
1595 or if it's waiting for tcp->pid's pgrp. It makes a
1596 difference to wake up a waiter when there might be more
1597 traced children, because it could get a false ECHILD
1598 error. OTOH, if this was the last child in the pgrp, then
1599 it ought to wake up and get ECHILD. We would have to
1600 search the system for all pid's in the pgrp to be sure.
1601
1602 && (t->waitpid == -1 ||
1603 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1604 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1605 */
1606
1607 if (tcp->parent &&
1608 (tcp->parent->flags & TCB_SUSPENDED) &&
1609 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001610 error = resume(tcp->parent);
Roland McGrath1bfd3102007-08-03 10:02:00 +00001611 ++resumed;
1612 }
1613#ifdef TCB_CLONE_THREAD
1614 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1615 /* Some other threads of our parent are waiting too. */
1616 unsigned int i;
1617
1618 /* Resume all the threads that were waiting for this PID. */
1619 for (i = 0; i < tcbtabsize; i++) {
1620 struct tcb *t = tcbtab[i];
1621 if (t->parent == tcp->parent && t != tcp
1622 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1623 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1624 && t->waitpid == tcp->pid) {
1625 error |= resume (t);
1626 ++resumed;
1627 }
1628 }
1629 if (resumed == 0)
1630 /* Noone was waiting for this PID in particular,
1631 so now we might need to resume some wildcarders. */
1632 for (i = 0; i < tcbtabsize; i++) {
1633 struct tcb *t = tcbtab[i];
1634 if (t->parent == tcp->parent && t != tcp
1635 && ((t->flags
1636 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1637 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1638 && t->waitpid <= 0
1639 ) {
1640 error |= resume (t);
1641 break;
1642 }
1643 }
1644 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001645#endif
Roland McGrath1bfd3102007-08-03 10:02:00 +00001646
1647 return error;
1648}
Roland McGrath1bfd3102007-08-03 10:02:00 +00001649
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001650#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001651
Roland McGrath0a463882007-07-05 18:43:16 +00001652/* detach traced process; continue with sig
1653 Never call DETACH twice on the same process as both unattached and
1654 attached-unstopped processes give the same ESRCH. For unattached process we
1655 would SIGSTOP it and wait for its SIGSTOP notification forever. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001656
1657static int
1658detach(tcp, sig)
1659struct tcb *tcp;
1660int sig;
1661{
1662 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001663#ifdef LINUX
Roland McGrath1bfd3102007-08-03 10:02:00 +00001664 int status, catch_sigstop;
Roland McGratha08a97e2005-08-03 11:23:46 +00001665 struct tcb *zombie = NULL;
1666
1667 /* If the group leader is lingering only because of this other
1668 thread now dying, then detach the leader as well. */
1669 if ((tcp->flags & TCB_CLONE_THREAD) &&
1670 tcp->parent->nclone_threads == 1 &&
1671 (tcp->parent->flags & TCB_EXITING))
1672 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001673#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001674
1675 if (tcp->flags & TCB_BPTSET)
Andreas Schwab840d85b2010-01-12 11:16:32 +01001676 clearbpt(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001677
1678#ifdef LINUX
1679 /*
1680 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001681 * before detaching. Arghh. We go through hoops
1682 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001683 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001684#if defined(SPARC)
1685#undef PTRACE_DETACH
1686#define PTRACE_DETACH PTRACE_SUNDETACH
1687#endif
Roland McGrath02203312007-06-11 22:06:31 +00001688 /*
1689 * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
1690 * expected SIGSTOP. We must catch exactly one as otherwise the
1691 * detached process would be left stopped (process state T).
1692 */
1693 catch_sigstop = (tcp->flags & TCB_STARTUP);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001694 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1695 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001696 }
1697 else if (errno != ESRCH) {
1698 /* Shouldn't happen. */
1699 perror("detach: ptrace(PTRACE_DETACH, ...)");
1700 }
Roland McGrath134813a2007-06-02 00:07:33 +00001701 else if (my_tgkill((tcp->flags & TCB_CLONE_THREAD ? tcp->parent->pid
1702 : tcp->pid),
1703 tcp->pid, 0) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001704 if (errno != ESRCH)
1705 perror("detach: checking sanity");
1706 }
Roland McGrath02203312007-06-11 22:06:31 +00001707 else if (!catch_sigstop && my_tgkill((tcp->flags & TCB_CLONE_THREAD
1708 ? tcp->parent->pid : tcp->pid),
1709 tcp->pid, SIGSTOP) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001710 if (errno != ESRCH)
1711 perror("detach: stopping child");
1712 }
Roland McGrath02203312007-06-11 22:06:31 +00001713 else
1714 catch_sigstop = 1;
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001715 if (catch_sigstop) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001716 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001717#ifdef __WALL
1718 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1719 if (errno == ECHILD) /* Already gone. */
1720 break;
1721 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001722 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001723 break;
1724 }
1725#endif /* __WALL */
1726 /* No __WALL here. */
1727 if (waitpid(tcp->pid, &status, 0) < 0) {
1728 if (errno != ECHILD) {
1729 perror("detach: waiting");
1730 break;
1731 }
1732#ifdef __WCLONE
1733 /* If no processes, try clones. */
1734 if (wait4(tcp->pid, &status, __WCLONE,
1735 NULL) < 0) {
1736 if (errno != ECHILD)
1737 perror("detach: waiting");
1738 break;
1739 }
1740#endif /* __WCLONE */
1741 }
1742#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001743 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001744#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001745 if (!WIFSTOPPED(status)) {
1746 /* Au revoir, mon ami. */
1747 break;
1748 }
1749 if (WSTOPSIG(status) == SIGSTOP) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001750 ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001751 break;
1752 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001753 error = ptrace_restart(PTRACE_CONT, tcp,
Roland McGratheb9e2e82009-06-02 16:49:22 -07001754 WSTOPSIG(status) == SIGTRAP ? 0
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001755 : WSTOPSIG(status));
1756 if (error < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001757 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001758 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001759 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001760#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001761
1762#if defined(SUNOS4)
1763 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1764 if (sig && kill(tcp->pid, sig) < 0)
1765 perror("detach: kill");
1766 sig = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001767 error = ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001768#endif /* SUNOS4 */
1769
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001770#ifndef USE_PROCFS
Roland McGrath1bfd3102007-08-03 10:02:00 +00001771 error |= resume_from_tcp (tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001772#endif
1773
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001774 if (!qflag)
1775 fprintf(stderr, "Process %u detached\n", tcp->pid);
1776
1777 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001778
1779#ifdef LINUX
Roland McGrath0a463882007-07-05 18:43:16 +00001780 if (zombie != NULL) {
1781 /* TCP no longer exists therefore you must not detach () it. */
1782 droptcb(zombie);
1783 }
Roland McGratha08a97e2005-08-03 11:23:46 +00001784#endif
1785
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001786 return error;
1787}
1788
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001789#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001790
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001791static void reaper(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001792{
1793 int pid;
1794 int status;
1795
1796 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001797 }
1798}
1799
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001800#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001801
1802static void
1803cleanup()
1804{
1805 int i;
1806 struct tcb *tcp;
1807
Roland McGrathee9d4352002-12-18 04:16:10 +00001808 for (i = 0; i < tcbtabsize; i++) {
1809 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001810 if (!(tcp->flags & TCB_INUSE))
1811 continue;
1812 if (debug)
1813 fprintf(stderr,
1814 "cleanup: looking at pid %u\n", tcp->pid);
1815 if (tcp_last &&
1816 (!outfname || followfork < 2 || tcp_last == tcp)) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001817 tprintf(" <unfinished ...>");
1818 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001819 }
1820 if (tcp->flags & TCB_ATTACHED)
1821 detach(tcp, 0);
1822 else {
1823 kill(tcp->pid, SIGCONT);
1824 kill(tcp->pid, SIGTERM);
1825 }
1826 }
1827 if (cflag)
1828 call_summary(outf);
1829}
1830
1831static void
1832interrupt(sig)
1833int sig;
1834{
1835 interrupted = 1;
1836}
1837
1838#ifndef HAVE_STRERROR
1839
Roland McGrath6d2b3492002-12-30 00:51:30 +00001840#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001841extern int sys_nerr;
1842extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001843#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001844
1845const char *
1846strerror(errno)
1847int errno;
1848{
1849 static char buf[64];
1850
1851 if (errno < 1 || errno >= sys_nerr) {
1852 sprintf(buf, "Unknown error %d", errno);
1853 return buf;
1854 }
1855 return sys_errlist[errno];
1856}
1857
1858#endif /* HAVE_STERRROR */
1859
1860#ifndef HAVE_STRSIGNAL
1861
Roland McGrath8f474e02003-01-14 07:53:33 +00001862#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001863extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001864#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001865#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1866extern char *_sys_siglist[];
1867#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001868
1869const char *
1870strsignal(sig)
1871int sig;
1872{
1873 static char buf[64];
1874
1875 if (sig < 1 || sig >= NSIG) {
1876 sprintf(buf, "Unknown signal %d", sig);
1877 return buf;
1878 }
1879#ifdef HAVE__SYS_SIGLIST
1880 return _sys_siglist[sig];
1881#else
1882 return sys_siglist[sig];
1883#endif
1884}
1885
1886#endif /* HAVE_STRSIGNAL */
1887
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001888#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001889
1890static void
1891rebuild_pollv()
1892{
1893 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001894
Roland McGrathee9d4352002-12-18 04:16:10 +00001895 if (pollv != NULL)
1896 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001897 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001898 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001899 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00001900 exit(1);
1901 }
1902
Roland McGrathca16be82003-01-10 19:55:28 +00001903 for (i = j = 0; i < tcbtabsize; i++) {
1904 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001905 if (!(tcp->flags & TCB_INUSE))
1906 continue;
1907 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001908 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001909 j++;
1910 }
1911 if (j != nprocs) {
1912 fprintf(stderr, "strace: proc miscount\n");
1913 exit(1);
1914 }
1915}
1916
1917#ifndef HAVE_POLLABLE_PROCFS
1918
1919static void
1920proc_poll_open()
1921{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001922 int i;
1923
1924 if (pipe(proc_poll_pipe) < 0) {
1925 perror("pipe");
1926 exit(1);
1927 }
1928 for (i = 0; i < 2; i++) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001929 if (set_cloexec_flag(proc_poll_pipe[i]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001930 exit(1);
1931 }
1932 }
1933}
1934
1935static int
1936proc_poll(pollv, nfds, timeout)
1937struct pollfd *pollv;
1938int nfds;
1939int timeout;
1940{
1941 int i;
1942 int n;
1943 struct proc_pollfd pollinfo;
1944
1945 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1946 return n;
1947 if (n != sizeof(struct proc_pollfd)) {
1948 fprintf(stderr, "panic: short read: %d\n", n);
1949 exit(1);
1950 }
1951 for (i = 0; i < nprocs; i++) {
1952 if (pollv[i].fd == pollinfo.fd)
1953 pollv[i].revents = pollinfo.revents;
1954 else
1955 pollv[i].revents = 0;
1956 }
1957 poller_pid = pollinfo.pid;
1958 return 1;
1959}
1960
1961static void
1962wakeup_handler(sig)
1963int sig;
1964{
1965}
1966
1967static void
1968proc_poller(pfd)
1969int pfd;
1970{
1971 struct proc_pollfd pollinfo;
1972 struct sigaction sa;
1973 sigset_t blocked_set, empty_set;
1974 int i;
1975 int n;
1976 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001977#ifdef FREEBSD
1978 struct procfs_status pfs;
1979#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001980
1981 switch (fork()) {
1982 case -1:
1983 perror("fork");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001984 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001985 case 0:
1986 break;
1987 default:
1988 return;
1989 }
1990
1991 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1992 sa.sa_flags = 0;
1993 sigemptyset(&sa.sa_mask);
1994 sigaction(SIGHUP, &sa, NULL);
1995 sigaction(SIGINT, &sa, NULL);
1996 sigaction(SIGQUIT, &sa, NULL);
1997 sigaction(SIGPIPE, &sa, NULL);
1998 sigaction(SIGTERM, &sa, NULL);
1999 sa.sa_handler = wakeup_handler;
2000 sigaction(SIGUSR1, &sa, NULL);
2001 sigemptyset(&blocked_set);
2002 sigaddset(&blocked_set, SIGUSR1);
2003 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2004 sigemptyset(&empty_set);
2005
2006 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
2007 perror("getrlimit(RLIMIT_NOFILE, ...)");
Dmitry V. Levina6809652008-11-10 17:14:58 +00002008 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002009 }
2010 n = rl.rlim_cur;
2011 for (i = 0; i < n; i++) {
2012 if (i != pfd && i != proc_poll_pipe[1])
2013 close(i);
2014 }
2015
2016 pollinfo.fd = pfd;
2017 pollinfo.pid = getpid();
2018 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002019#ifndef FREEBSD
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002020 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
2021#else
2022 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
2023#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002024 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002025 switch (errno) {
2026 case EINTR:
2027 continue;
2028 case EBADF:
2029 pollinfo.revents = POLLERR;
2030 break;
2031 case ENOENT:
2032 pollinfo.revents = POLLHUP;
2033 break;
2034 default:
2035 perror("proc_poller: PIOCWSTOP");
2036 }
2037 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2038 _exit(0);
2039 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002040 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002041 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2042 sigsuspend(&empty_set);
2043 }
2044}
2045
2046#endif /* !HAVE_POLLABLE_PROCFS */
2047
2048static int
2049choose_pfd()
2050{
2051 int i, j;
2052 struct tcb *tcp;
2053
2054 static int last;
2055
2056 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002057 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002058 /*
2059 * The previous process is ready to run again. We'll
2060 * let it do so if it is currently in a syscall. This
2061 * heuristic improves the readability of the trace.
2062 */
2063 tcp = pfd2tcb(pollv[last].fd);
2064 if (tcp && (tcp->flags & TCB_INSYSCALL))
2065 return pollv[last].fd;
2066 }
2067
2068 for (i = 0; i < nprocs; i++) {
2069 /* Let competing children run round robin. */
2070 j = (i + last + 1) % nprocs;
2071 if (pollv[j].revents & (POLLHUP | POLLERR)) {
2072 tcp = pfd2tcb(pollv[j].fd);
2073 if (!tcp) {
2074 fprintf(stderr, "strace: lost proc\n");
2075 exit(1);
2076 }
2077 droptcb(tcp);
2078 return -1;
2079 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002080 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002081 last = j;
2082 return pollv[j].fd;
2083 }
2084 }
2085 fprintf(stderr, "strace: nothing ready\n");
2086 exit(1);
2087}
2088
2089static int
2090trace()
2091{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002092#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00002093 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002094#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002095 struct tcb *tcp;
2096 int pfd;
2097 int what;
2098 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002099 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002100
2101 for (;;) {
2102 if (interactive)
2103 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2104
2105 if (nprocs == 0)
2106 break;
2107
2108 switch (nprocs) {
2109 case 1:
2110#ifndef HAVE_POLLABLE_PROCFS
2111 if (proc_poll_pipe[0] == -1) {
2112#endif
Roland McGrath54e931f2010-09-14 18:59:20 -07002113 tcp = first_used_tcb();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002114 if (!tcp)
2115 continue;
2116 pfd = tcp->pfd;
2117 if (pfd == -1)
2118 continue;
2119 break;
2120#ifndef HAVE_POLLABLE_PROCFS
2121 }
2122 /* fall through ... */
2123#endif /* !HAVE_POLLABLE_PROCFS */
2124 default:
2125#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002126#ifdef POLL_HACK
2127 /* On some systems (e.g. UnixWare) we get too much ugly
2128 "unfinished..." stuff when multiple proceses are in
2129 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00002130
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002131 if (in_syscall) {
2132 struct pollfd pv;
2133 tcp = in_syscall;
2134 in_syscall = NULL;
2135 pv.fd = tcp->pfd;
2136 pv.events = POLLWANT;
2137 if ((what = poll (&pv, 1, 1)) < 0) {
2138 if (interrupted)
2139 return 0;
2140 continue;
2141 }
2142 else if (what == 1 && pv.revents & POLLWANT) {
2143 goto FOUND;
2144 }
2145 }
2146#endif
2147
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002148 if (poll(pollv, nprocs, INFTIM) < 0) {
2149 if (interrupted)
2150 return 0;
2151 continue;
2152 }
2153#else /* !HAVE_POLLABLE_PROCFS */
2154 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
2155 if (interrupted)
2156 return 0;
2157 continue;
2158 }
2159#endif /* !HAVE_POLLABLE_PROCFS */
2160 pfd = choose_pfd();
2161 if (pfd == -1)
2162 continue;
2163 break;
2164 }
2165
2166 /* Look up `pfd' in our table. */
2167 if ((tcp = pfd2tcb(pfd)) == NULL) {
2168 fprintf(stderr, "unknown pfd: %u\n", pfd);
2169 exit(1);
2170 }
John Hughesb6643082002-05-23 11:02:22 +00002171#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002172 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00002173#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002174 /* Get the status of the process. */
2175 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002176#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002177 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002178#else /* FREEBSD */
2179 /* Thanks to some scheduling mystery, the first poller
2180 sometimes waits for the already processed end of fork
2181 event. Doing a non blocking poll here solves the problem. */
2182 if (proc_poll_pipe[0] != -1)
2183 ioctl_result = IOCTL_STATUS (tcp);
2184 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002185 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00002186#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002187 ioctl_errno = errno;
2188#ifndef HAVE_POLLABLE_PROCFS
2189 if (proc_poll_pipe[0] != -1) {
2190 if (ioctl_result < 0)
2191 kill(poller_pid, SIGKILL);
2192 else
2193 kill(poller_pid, SIGUSR1);
2194 }
2195#endif /* !HAVE_POLLABLE_PROCFS */
2196 }
2197 if (interrupted)
2198 return 0;
2199
2200 if (interactive)
2201 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2202
2203 if (ioctl_result < 0) {
2204 /* Find out what happened if it failed. */
2205 switch (ioctl_errno) {
2206 case EINTR:
2207 case EBADF:
2208 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002209#ifdef FREEBSD
2210 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00002211#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002212 case ENOENT:
2213 droptcb(tcp);
2214 continue;
2215 default:
2216 perror("PIOCWSTOP");
2217 exit(1);
2218 }
2219 }
2220
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002221#ifdef FREEBSD
2222 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2223 /* discard first event for a syscall we never entered */
2224 IOCTL (tcp->pfd, PIOCRUN, 0);
2225 continue;
2226 }
Roland McGrath553a6092002-12-16 20:40:39 +00002227#endif
2228
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002229 /* clear the just started flag */
2230 tcp->flags &= ~TCB_STARTUP;
2231
2232 /* set current output file */
2233 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002234 curcol = tcp->curcol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002235
2236 if (cflag) {
2237 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002238#ifdef FREEBSD
2239 char buf[1024];
2240 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002241
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002242 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
2243 buf[len] = '\0';
2244 sscanf(buf,
2245 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2246 &stime.tv_sec, &stime.tv_usec);
2247 } else
2248 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002249#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002250 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2251 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002252#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002253 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2254 tcp->stime = stime;
2255 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002256 what = tcp->status.PR_WHAT;
2257 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002258#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002259 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002260 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2261 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002262 if (trace_syscall(tcp) < 0) {
2263 fprintf(stderr, "syscall trouble\n");
2264 exit(1);
2265 }
2266 }
2267 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002268#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002269 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002270#ifdef POLL_HACK
2271 in_syscall = tcp;
2272#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002273 case PR_SYSEXIT:
2274 if (trace_syscall(tcp) < 0) {
2275 fprintf(stderr, "syscall trouble\n");
2276 exit(1);
2277 }
2278 break;
2279 case PR_SIGNALLED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002280 if (cflag != CFLAG_ONLY_STATS
2281 && (qual_flags[what] & QUAL_SIGNAL)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002282 printleader(tcp);
2283 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002284 signame(what), strsignal(what));
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002285 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002286#ifdef PR_INFO
2287 if (tcp->status.PR_INFO.si_signo == what) {
2288 printleader(tcp);
2289 tprintf(" siginfo=");
2290 printsiginfo(&tcp->status.PR_INFO, 1);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002291 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002292 }
2293#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002294 }
2295 break;
2296 case PR_FAULTED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002297 if (cflag != CFLAGS_ONLY_STATS
2298 && (qual_flags[what] & QUAL_FAULT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002299 printleader(tcp);
2300 tprintf("=== FAULT %d ===", what);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002301 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002302 }
2303 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002304#ifdef FREEBSD
2305 case 0: /* handle case we polled for nothing */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002306 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00002307#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002308 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002309 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002310 exit(1);
2311 break;
2312 }
Andreas Schwabccdff482009-10-27 16:27:13 +01002313 /* Remember current print column before continuing. */
2314 tcp->curcol = curcol;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002315 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002316#ifndef FREEBSD
Andreas Schwab372cc842010-07-09 11:49:27 +02002317 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002318#else
Andreas Schwab372cc842010-07-09 11:49:27 +02002319 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002320#endif
Andreas Schwab372cc842010-07-09 11:49:27 +02002321 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002322 perror("PIOCRUN");
2323 exit(1);
2324 }
2325 }
2326 return 0;
2327}
2328
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002329#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002330
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002331#ifdef TCB_GROUP_EXITING
2332/* Handle an exit detach or death signal that is taking all the
2333 related clone threads with it. This is called in three circumstances:
2334 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
2335 SIG == 0 Continuing TCP will perform an exit_group syscall.
2336 SIG == other Continuing TCP with SIG will kill the process.
2337*/
2338static int
2339handle_group_exit(struct tcb *tcp, int sig)
2340{
2341 /* We need to locate our records of all the clone threads
2342 related to TCP, either its children or siblings. */
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002343 struct tcb *leader = NULL;
2344
2345 if (tcp->flags & TCB_CLONE_THREAD)
2346 leader = tcp->parent;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002347
2348 if (sig < 0) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002349 if (leader != NULL && leader != tcp
2350 && !(leader->flags & TCB_GROUP_EXITING)
2351 && !(tcp->flags & TCB_STARTUP)
2352 ) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002353 fprintf(stderr,
2354 "PANIC: handle_group_exit: %d leader %d\n",
2355 tcp->pid, leader ? leader->pid : -1);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002356 }
2357 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath1bfd3102007-08-03 10:02:00 +00002358#ifndef USE_PROCFS
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002359 resume_from_tcp(tcp);
Roland McGrath1bfd3102007-08-03 10:02:00 +00002360#endif
Roland McGrath0a463882007-07-05 18:43:16 +00002361 droptcb(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002362 }
2363 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00002364 /* Mark that we are taking the process down. */
2365 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002366 if (tcp->flags & TCB_ATTACHED) {
Roland McGrathd6a32f12007-07-11 08:35:11 +00002367 detach(tcp, sig);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002368 if (leader != NULL && leader != tcp)
Roland McGrath1bfd3102007-08-03 10:02:00 +00002369 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002370 } else {
2371 if (ptrace_restart(PTRACE_CONT, tcp, sig) < 0) {
2372 cleanup();
2373 return -1;
2374 }
2375 if (leader != NULL) {
Roland McGrath05690952004-10-20 01:00:27 +00002376 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002377 if (leader != tcp)
2378 droptcb(tcp);
2379 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002380 /* The leader will report to us as parent now,
2381 and then we'll get to the SIG==-1 case. */
2382 return 0;
2383 }
2384 }
2385
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002386 return 0;
2387}
2388#endif
2389
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002390#ifdef LINUX
2391static int
2392handle_ptrace_event(int status, struct tcb *tcp)
2393{
2394 if (status >> 16 == PTRACE_EVENT_VFORK ||
2395 status >> 16 == PTRACE_EVENT_CLONE ||
2396 status >> 16 == PTRACE_EVENT_FORK) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +00002397 long childpid;
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002398
2399 if (do_ptrace(PTRACE_GETEVENTMSG, tcp, NULL, &childpid) < 0) {
2400 if (errno != ESRCH) {
2401 fprintf(stderr, "\
2402%s: handle_ptrace_event: ptrace cannot get new child's pid\n",
2403 progname);
2404 cleanup();
2405 exit(1);
2406 }
2407 return -1;
2408 }
2409 return handle_new_child(tcp, childpid, 0);
2410 }
2411 return 1;
2412}
2413#endif
2414
Roland McGratheb9e2e82009-06-02 16:49:22 -07002415static int
2416trace()
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002417{
2418 int pid;
2419 int wait_errno;
2420 int status;
2421 struct tcb *tcp;
2422#ifdef LINUX
2423 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002424#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002425 static int wait4_options = __WALL;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002426#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002427#endif /* LINUX */
2428
Roland McGratheb9e2e82009-06-02 16:49:22 -07002429 while (nprocs != 0) {
Denys Vlasenko222713a2009-03-17 14:29:59 +00002430 if (interrupted)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002431 return 0;
2432 if (interactive)
2433 sigprocmask(SIG_SETMASK, &empty_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002434#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002435#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002436 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002437 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002438 /* this kernel does not support __WALL */
2439 wait4_options &= ~__WALL;
2440 errno = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002441 pid = wait4(-1, &status, wait4_options,
2442 cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002443 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002444 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002445 /* most likely a "cloned" process */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002446 pid = wait4(-1, &status, __WCLONE,
2447 cflag ? &ru : NULL);
2448 if (pid == -1) {
2449 fprintf(stderr, "strace: clone wait4 "
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002450 "failed: %s\n", strerror(errno));
2451 }
2452 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002453#else
2454 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
2455#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002456#endif /* LINUX */
2457#ifdef SUNOS4
2458 pid = wait(&status);
2459#endif /* SUNOS4 */
2460 wait_errno = errno;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002461 if (interactive)
2462 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002463
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002464 if (pid == -1) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002465 switch (wait_errno) {
2466 case EINTR:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002467 continue;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002468 case ECHILD:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002469 /*
2470 * We would like to verify this case
2471 * but sometimes a race in Solbourne's
2472 * version of SunOS sometimes reports
2473 * ECHILD before sending us SIGCHILD.
2474 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002475 return 0;
2476 default:
2477 errno = wait_errno;
2478 perror("strace: wait");
2479 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002480 }
2481 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002482 if (pid == popen_pid) {
2483 if (WIFEXITED(status) || WIFSIGNALED(status))
2484 popen_pid = -1;
2485 continue;
2486 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002487 if (debug)
2488 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2489
2490 /* Look up `pid' in our table. */
2491 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002492#ifdef LINUX
Roland McGrath41c48222008-07-18 00:25:10 +00002493 if (followfork) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002494 /* This is needed to go with the CLONE_PTRACE
2495 changes in process.c/util.c: we might see
2496 the child's initial trap before we see the
2497 parent return from the clone syscall.
2498 Leave the child suspended until the parent
2499 returns from its system call. Only then
2500 will we have the association of parent and
2501 child so that we know how to do clearbpt
2502 in the child. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +00002503 tcp = alloctcb(pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002504 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002505 if (!qflag)
2506 fprintf(stderr, "\
2507Process %d attached (waiting for parent)\n",
2508 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002509 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002510 else
2511 /* This can happen if a clone call used
2512 CLONE_PTRACE itself. */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002513#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002514 {
2515 fprintf(stderr, "unknown pid: %u\n", pid);
2516 if (WIFSTOPPED(status))
2517 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2518 exit(1);
2519 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002520 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002521 /* set current output file */
2522 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002523 curcol = tcp->curcol;
Denys Vlasenko84e20af2009-02-10 16:03:20 +00002524 if (cflag) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002525#ifdef LINUX
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002526 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2527 tcp->stime = ru.ru_stime;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002528#endif /* !LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002529 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002530
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002531 if (tcp->flags & TCB_SUSPENDED) {
2532 /*
2533 * Apparently, doing any ptrace() call on a stopped
2534 * process, provokes the kernel to report the process
2535 * status again on a subsequent wait(), even if the
2536 * process has not been actually restarted.
2537 * Since we have inspected the arguments of suspended
2538 * processes we end up here testing for this case.
2539 */
2540 continue;
2541 }
2542 if (WIFSIGNALED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002543 if (pid == strace_child)
2544 exit_code = 0x100 | WTERMSIG(status);
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002545 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002546 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2547 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002548 tprintf("+++ killed by %s %s+++",
2549 signame(WTERMSIG(status)),
2550#ifdef WCOREDUMP
2551 WCOREDUMP(status) ? "(core dumped) " :
2552#endif
2553 "");
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002554 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002555 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002556#ifdef TCB_GROUP_EXITING
2557 handle_group_exit(tcp, -1);
2558#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002559 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002560#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002561 continue;
2562 }
2563 if (WIFEXITED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002564 if (pid == strace_child)
2565 exit_code = WEXITSTATUS(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002566 if (debug)
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002567 fprintf(stderr, "pid %u exited with %d\n", pid, WEXITSTATUS(status));
2568 if ((tcp->flags & (TCB_ATTACHED|TCB_STARTUP)) == TCB_ATTACHED
Roland McGrath05690952004-10-20 01:00:27 +00002569#ifdef TCB_GROUP_EXITING
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002570 && !(tcp->parent && (tcp->parent->flags & TCB_GROUP_EXITING))
Roland McGrath1bfd3102007-08-03 10:02:00 +00002571 && !(tcp->flags & TCB_GROUP_EXITING)
Roland McGrath05690952004-10-20 01:00:27 +00002572#endif
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002573 ) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002574 fprintf(stderr,
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002575 "PANIC: attached pid %u exited with %d\n",
2576 pid, WEXITSTATUS(status));
2577 }
Roland McGrath0a396902003-06-10 03:05:53 +00002578 if (tcp == tcp_last) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002579 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT)) == TCB_INSYSCALL)
Roland McGrath0a396902003-06-10 03:05:53 +00002580 tprintf(" <unfinished ... exit status %d>\n",
2581 WEXITSTATUS(status));
2582 tcp_last = NULL;
2583 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002584#ifdef TCB_GROUP_EXITING
2585 handle_group_exit(tcp, -1);
2586#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002587 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002588#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002589 continue;
2590 }
2591 if (!WIFSTOPPED(status)) {
2592 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2593 droptcb(tcp);
2594 continue;
2595 }
2596 if (debug)
2597 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002598 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002599
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002600 if (ptrace_setoptions && (status >> 16)) {
2601 if (handle_ptrace_event(status, tcp) != 1)
2602 goto tracing;
2603 }
2604
Roland McGrath02203312007-06-11 22:06:31 +00002605 /*
2606 * Interestingly, the process may stop
2607 * with STOPSIG equal to some other signal
Roland McGratheb9e2e82009-06-02 16:49:22 -07002608 * than SIGSTOP if we happend to attach
Roland McGrath02203312007-06-11 22:06:31 +00002609 * just before the process takes a signal.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002610 * A no-MMU vforked child won't send up a signal,
2611 * so skip the first (lost) execve notification.
Roland McGrath02203312007-06-11 22:06:31 +00002612 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002613 if ((tcp->flags & TCB_STARTUP) &&
2614 (WSTOPSIG(status) == SIGSTOP || strace_vforked)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002615 /*
2616 * This flag is there to keep us in sync.
2617 * Next time this process stops it should
2618 * really be entering a system call.
2619 */
2620 tcp->flags &= ~TCB_STARTUP;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002621 if (tcp->flags & TCB_BPTSET) {
Roland McGrath02203312007-06-11 22:06:31 +00002622 /*
2623 * One example is a breakpoint inherited from
2624 * parent through fork ().
2625 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002626 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2627 droptcb(tcp);
2628 cleanup();
2629 return -1;
2630 }
2631 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002632#ifdef LINUX
2633 if (followfork && (tcp->parent == NULL) && ptrace_setoptions)
2634 if (ptrace(PTRACE_SETOPTIONS, tcp->pid,
2635 NULL, ptrace_setoptions) < 0 &&
2636 errno != ESRCH)
2637 ptrace_setoptions = 0;
2638#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002639 goto tracing;
2640 }
2641
Roland McGratheb9e2e82009-06-02 16:49:22 -07002642 if (WSTOPSIG(status) != SIGTRAP) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002643 if (WSTOPSIG(status) == SIGSTOP &&
2644 (tcp->flags & TCB_SIGTRAPPED)) {
2645 /*
2646 * Trapped attempt to block SIGTRAP
2647 * Hope we are back in control now.
2648 */
2649 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002650 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002651 cleanup();
2652 return -1;
2653 }
2654 continue;
2655 }
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002656 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002657 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Dmitry V. Levinc15dfc72011-03-10 14:44:45 +00002658 siginfo_t si;
2659#if defined(PT_CR_IPSR) && defined(PT_CR_IIP)
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002660 long pc = 0;
2661 long psr = 0;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002662
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002663 upeek(tcp, PT_CR_IPSR, &psr);
2664 upeek(tcp, PT_CR_IIP, &pc);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002665
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002666# define PSR_RI 41
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002667 pc += (psr >> PSR_RI) & 0x3;
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002668# define PC_FORMAT_STR " @ %lx"
2669# define PC_FORMAT_ARG pc
2670#else
2671# define PC_FORMAT_STR "%s"
2672# define PC_FORMAT_ARG ""
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002673#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002674 printleader(tcp);
Dmitry V. Levin6b7a2612011-03-10 21:20:35 +00002675 if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
2676 tprintf("--- ");
2677 printsiginfo(&si, verbose(tcp));
2678 tprintf(" (%s)" PC_FORMAT_STR " ---",
2679 strsignal(WSTOPSIG(status)),
2680 PC_FORMAT_ARG);
2681 } else
2682 tprintf("--- %s by %s" PC_FORMAT_STR " ---",
2683 strsignal(WSTOPSIG(status)),
2684 signame(WSTOPSIG(status)),
2685 PC_FORMAT_ARG);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002686 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002687 }
Roland McGrath05690952004-10-20 01:00:27 +00002688 if (((tcp->flags & TCB_ATTACHED) ||
2689 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002690 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002691#ifdef TCB_GROUP_EXITING
2692 handle_group_exit(tcp, WSTOPSIG(status));
2693#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002694 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002695#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002696 continue;
2697 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002698 if (ptrace_restart(PTRACE_SYSCALL, tcp, WSTOPSIG(status)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002699 cleanup();
2700 return -1;
2701 }
2702 tcp->flags &= ~TCB_SUSPENDED;
2703 continue;
2704 }
Roland McGrath02203312007-06-11 22:06:31 +00002705 /* we handled the STATUS, we are permitted to interrupt now. */
2706 if (interrupted)
2707 return 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002708 if (trace_syscall(tcp) < 0 && !tcp->ptrace_errno) {
2709 /* ptrace() failed in trace_syscall() with ESRCH.
2710 * Likely a result of process disappearing mid-flight.
2711 * Observed case: exit_group() terminating
2712 * all processes in thread group. In this case, threads
2713 * "disappear" in an unpredictable moment without any
2714 * notification to strace via wait().
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002715 */
2716 if (tcp->flags & TCB_ATTACHED) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002717 if (tcp_last) {
2718 /* Do we have dangling line "syscall(param, param"?
2719 * Finish the line then. We cannot
2720 */
2721 tcp_last->flags |= TCB_REPRINT;
2722 tprintf(" <unfinished ...>");
2723 printtrailer();
2724 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002725 detach(tcp, 0);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002726 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002727 ptrace(PTRACE_KILL,
2728 tcp->pid, (char *) 1, SIGTERM);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002729 droptcb(tcp);
2730 }
2731 continue;
2732 }
2733 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002734#ifdef TCB_GROUP_EXITING
2735 if (tcp->flags & TCB_GROUP_EXITING) {
2736 if (handle_group_exit(tcp, 0) < 0)
2737 return -1;
2738 continue;
2739 }
2740#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002741 if (tcp->flags & TCB_ATTACHED)
2742 detach(tcp, 0);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002743 else if (ptrace_restart(PTRACE_CONT, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002744 cleanup();
2745 return -1;
2746 }
2747 continue;
2748 }
2749 if (tcp->flags & TCB_SUSPENDED) {
2750 if (!qflag)
2751 fprintf(stderr, "Process %u suspended\n", pid);
2752 continue;
2753 }
2754 tracing:
Andreas Schwabccdff482009-10-27 16:27:13 +01002755 /* Remember current print column before continuing. */
2756 tcp->curcol = curcol;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002757 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002758 cleanup();
2759 return -1;
2760 }
2761 }
2762 return 0;
2763}
2764
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002765#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002766
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002767#include <stdarg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002768
2769void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002770tprintf(const char *fmt, ...)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002771{
2772 va_list args;
2773
Andreas Schwabe5355de2009-10-27 16:56:43 +01002774 va_start(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002775 if (outf) {
2776 int n = vfprintf(outf, fmt, args);
Andreas Schwabccdff482009-10-27 16:27:13 +01002777 if (n < 0) {
2778 if (outf != stderr)
2779 perror(outfname == NULL
2780 ? "<writing to pipe>" : outfname);
2781 } else
Roland McGrathb310a0c2003-11-06 23:41:22 +00002782 curcol += n;
2783 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002784 va_end(args);
2785 return;
2786}
2787
2788void
Roland McGratheb9e2e82009-06-02 16:49:22 -07002789printleader(tcp)
2790struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002791{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002792 if (tcp_last) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002793 if (tcp_last->ptrace_errno) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002794 if (tcp_last->flags & TCB_INSYSCALL) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002795 tprintf(" <unavailable>)");
2796 tabto(acolumn);
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002797 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002798 tprintf("= ? <unavailable>\n");
2799 tcp_last->ptrace_errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002800 } else if (!outfname || followfork < 2 || tcp_last == tcp) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002801 tcp_last->flags |= TCB_REPRINT;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002802 tprintf(" <unfinished ...>\n");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002803 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002804 }
2805 curcol = 0;
2806 if ((followfork == 1 || pflag_seen > 1) && outfname)
2807 tprintf("%-5d ", tcp->pid);
2808 else if (nprocs > 1 && !outfname)
2809 tprintf("[pid %5u] ", tcp->pid);
2810 if (tflag) {
2811 char str[sizeof("HH:MM:SS")];
2812 struct timeval tv, dtv;
2813 static struct timeval otv;
2814
2815 gettimeofday(&tv, NULL);
2816 if (rflag) {
2817 if (otv.tv_sec == 0)
2818 otv = tv;
2819 tv_sub(&dtv, &tv, &otv);
2820 tprintf("%6ld.%06ld ",
2821 (long) dtv.tv_sec, (long) dtv.tv_usec);
2822 otv = tv;
2823 }
2824 else if (tflag > 2) {
2825 tprintf("%ld.%06ld ",
2826 (long) tv.tv_sec, (long) tv.tv_usec);
2827 }
2828 else {
2829 time_t local = tv.tv_sec;
2830 strftime(str, sizeof(str), "%T", localtime(&local));
2831 if (tflag > 1)
2832 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2833 else
2834 tprintf("%s ", str);
2835 }
2836 }
2837 if (iflag)
2838 printcall(tcp);
2839}
2840
2841void
2842tabto(col)
2843int col;
2844{
2845 if (curcol < col)
2846 tprintf("%*s", col - curcol, "");
2847}
2848
2849void
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002850printtrailer(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002851{
2852 tprintf("\n");
2853 tcp_last = NULL;
2854}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002855
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002856#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002857
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002858int
2859mp_ioctl(int fd, int cmd, void *arg, int size)
2860{
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002861 struct iovec iov[2];
2862 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002863
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002864 iov[0].iov_base = &cmd;
2865 iov[0].iov_len = sizeof cmd;
2866 if (arg) {
2867 ++n;
2868 iov[1].iov_base = arg;
2869 iov[1].iov_len = size;
2870 }
Roland McGrath553a6092002-12-16 20:40:39 +00002871
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002872 return writev(fd, iov, n);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002873}
2874
2875#endif