blob: 42d436e1a45c46559630ba417de86337ad8967d1 [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
Dmitry V. Levina6809652008-11-10 17:14:58 +0000107static int exit_code = 0;
108static int strace_child = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700109
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +0000110static char *username = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000111uid_t run_uid;
112gid_t run_gid;
113
114int acolumn = DEFAULT_ACOLUMN;
115int max_strlen = DEFAULT_STRLEN;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +0000116static char *outfname = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000117FILE *outf;
Andreas Schwabccdff482009-10-27 16:27:13 +0100118static int curcol;
Roland McGrathee9d4352002-12-18 04:16:10 +0000119struct tcb **tcbtab;
120unsigned int nprocs, tcbtabsize;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000121const char *progname;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700122extern char **environ;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000123
Andreas Schwabe5355de2009-10-27 16:56:43 +0100124static int detach(struct tcb *tcp, int sig);
125static int trace(void);
126static void cleanup(void);
127static void interrupt(int sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000128static sigset_t empty_set, blocked_set;
129
130#ifdef HAVE_SIG_ATOMIC_T
131static volatile sig_atomic_t interrupted;
132#else /* !HAVE_SIG_ATOMIC_T */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000133static volatile int interrupted;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000134#endif /* !HAVE_SIG_ATOMIC_T */
135
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000136#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000137
Andreas Schwabe5355de2009-10-27 16:56:43 +0100138static struct tcb *pfd2tcb(int pfd);
139static void reaper(int sig);
140static void rebuild_pollv(void);
Roland McGrathee9d4352002-12-18 04:16:10 +0000141static struct pollfd *pollv;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000142
143#ifndef HAVE_POLLABLE_PROCFS
144
Andreas Schwabe5355de2009-10-27 16:56:43 +0100145static void proc_poll_open(void);
146static void proc_poller(int pfd);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000147
148struct proc_pollfd {
149 int fd;
150 int revents;
151 int pid;
152};
153
154static int poller_pid;
155static int proc_poll_pipe[2] = { -1, -1 };
156
157#endif /* !HAVE_POLLABLE_PROCFS */
158
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000159#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000160#define POLLWANT POLLWRNORM
161#else
162#define POLLWANT POLLPRI
163#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000164#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000165
166static void
167usage(ofp, exitval)
168FILE *ofp;
169int exitval;
170{
171 fprintf(ofp, "\
Andreas Schwabb87d30c2010-06-11 15:49:36 +0200172usage: strace [-CdDffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000173 [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n\
174 [command [arg ...]]\n\
Andreas Schwabb87d30c2010-06-11 15:49:36 +0200175 or: strace -c [-D] [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000176 [command [arg ...]]\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000177-c -- count time, calls, and errors for each syscall and report summary\n\
Andreas Schwabb87d30c2010-06-11 15:49:36 +0200178-C -- like -c but also print regular output while processes are running\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000179-f -- follow forks, -ff -- with output into separate files\n\
180-F -- attempt to follow vforks, -h -- print help message\n\
181-i -- print instruction pointer at time of syscall\n\
182-q -- suppress messages about attaching, detaching, etc.\n\
183-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
184-T -- print time spent in each syscall, -V -- print version\n\
185-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
186-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
187-a column -- alignment COLUMN for printing syscall results (default %d)\n\
188-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
189 options: trace, abbrev, verbose, raw, signal, read, or write\n\
190-o file -- send trace output to FILE instead of stderr\n\
191-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
192-p pid -- trace process with process id PID, may be repeated\n\
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000193-D -- run tracer process as a detached grandchild, not as parent\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000194-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
195-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
196-u username -- run command as username handling setuid and/or setgid\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000197-E var=val -- put var=val in the environment for command\n\
198-E var -- remove var from the environment for command\n\
199" /* this is broken, so don't document it
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000200-z -- print only succeeding syscalls\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000201 */
202, DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000203 exit(exitval);
204}
205
206#ifdef SVR4
207#ifdef MIPS
208void
209foobar()
210{
211}
212#endif /* MIPS */
213#endif /* SVR4 */
214
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400215/* Glue for systems without a MMU that cannot provide fork() */
216#ifdef HAVE_FORK
217# define strace_vforked 0
218#else
219# define strace_vforked 1
220# define fork() vfork()
221#endif
222
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000223static int
224set_cloexec_flag(int fd)
225{
226 int flags, newflags;
227
228 if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
229 {
230 fprintf(stderr, "%s: fcntl F_GETFD: %s\n",
231 progname, strerror(errno));
232 return -1;
233 }
234
235 newflags = flags | FD_CLOEXEC;
236 if (flags == newflags)
237 return 0;
238
239 if (fcntl(fd, F_SETFD, newflags) < 0)
240 {
241 fprintf(stderr, "%s: fcntl F_SETFD: %s\n",
242 progname, strerror(errno));
243 return -1;
244 }
245
246 return 0;
247}
248
249/*
250 * When strace is setuid executable, we have to swap uids
251 * before and after filesystem and process management operations.
252 */
253static void
254swap_uid(void)
255{
256#ifndef SVR4
257 int euid = geteuid(), uid = getuid();
258
259 if (euid != uid && setreuid(euid, uid) < 0)
260 {
261 fprintf(stderr, "%s: setreuid: %s\n",
262 progname, strerror(errno));
263 exit(1);
264 }
265#endif
266}
267
Roland McGrath4bfa6262007-07-05 20:03:16 +0000268#if _LFS64_LARGEFILE
269# define fopen_for_output fopen64
270#else
271# define fopen_for_output fopen
272#endif
273
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000274static FILE *
275strace_fopen(const char *path, const char *mode)
276{
277 FILE *fp;
278
279 swap_uid();
Roland McGrath4bfa6262007-07-05 20:03:16 +0000280 if ((fp = fopen_for_output(path, mode)) == NULL)
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000281 fprintf(stderr, "%s: can't fopen '%s': %s\n",
282 progname, path, strerror(errno));
283 swap_uid();
284 if (fp && set_cloexec_flag(fileno(fp)) < 0)
285 {
286 fclose(fp);
287 fp = NULL;
288 }
289 return fp;
290}
291
292static int popen_pid = -1;
293
294#ifndef _PATH_BSHELL
295# define _PATH_BSHELL "/bin/sh"
296#endif
297
298/*
299 * We cannot use standard popen(3) here because we have to distinguish
300 * popen child process from other processes we trace, and standard popen(3)
301 * does not export its child's pid.
302 */
303static FILE *
304strace_popen(const char *command)
305{
306 int fds[2];
307
308 swap_uid();
309 if (pipe(fds) < 0)
310 {
311 fprintf(stderr, "%s: pipe: %s\n",
312 progname, strerror(errno));
313 swap_uid();
314 return NULL;
315 }
316
317 if (set_cloexec_flag(fds[1]) < 0)
318 {
319 close(fds[0]);
320 close(fds[1]);
321 swap_uid();
322 return NULL;
323 }
324
325 if ((popen_pid = fork()) == -1)
326 {
327 fprintf(stderr, "%s: fork: %s\n",
328 progname, strerror(errno));
329 close(fds[0]);
330 close(fds[1]);
331 swap_uid();
332 return NULL;
333 }
334
335 if (popen_pid)
336 {
337 /* parent */
338 close(fds[0]);
339 swap_uid();
340 return fdopen(fds[1], "w");
341 } else
342 {
343 /* child */
344 close(fds[1]);
345 if (fds[0] && (dup2(fds[0], 0) || close(fds[0])))
346 {
347 fprintf(stderr, "%s: dup2: %s\n",
348 progname, strerror(errno));
349 _exit(1);
350 }
351 execl(_PATH_BSHELL, "sh", "-c", command, NULL);
352 fprintf(stderr, "%s: execl: %s: %s\n",
353 progname, _PATH_BSHELL, strerror(errno));
354 _exit(1);
355 }
356}
357
358static int
359newoutf(struct tcb *tcp)
360{
361 if (outfname && followfork > 1) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000362 char name[520 + sizeof(int) * 3];
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000363 FILE *fp;
364
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000365 sprintf(name, "%.512s.%u", outfname, tcp->pid);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000366 if ((fp = strace_fopen(name, "w")) == NULL)
367 return -1;
368 tcp->outf = fp;
369 }
370 return 0;
371}
372
Roland McGrath02203312007-06-11 22:06:31 +0000373static void
374startup_attach(void)
375{
376 int tcbi;
377 struct tcb *tcp;
378
379 /*
380 * Block user interruptions as we would leave the traced
381 * process stopped (process state T) if we would terminate in
382 * between PTRACE_ATTACH and wait4 () on SIGSTOP.
383 * We rely on cleanup () from this point on.
384 */
385 if (interactive)
386 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
387
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000388 if (daemonized_tracer) {
389 pid_t pid = fork();
390 if (pid < 0) {
391 _exit(1);
392 }
393 if (pid) { /* parent */
394 /*
395 * Wait for child to attach to straced process
396 * (our parent). Child SIGKILLs us after it attached.
397 * Parent's wait() is unblocked by our death,
398 * it proceeds to exec the straced program.
399 */
400 pause();
401 _exit(0); /* paranoia */
402 }
403 }
404
Roland McGrath02203312007-06-11 22:06:31 +0000405 for (tcbi = 0; tcbi < tcbtabsize; tcbi++) {
406 tcp = tcbtab[tcbi];
407 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
408 continue;
409#ifdef LINUX
410 if (tcp->flags & TCB_CLONE_THREAD)
411 continue;
412#endif
413 /* Reinitialize the output since it may have changed. */
414 tcp->outf = outf;
415 if (newoutf(tcp) < 0)
416 exit(1);
417
418#ifdef USE_PROCFS
419 if (proc_open(tcp, 1) < 0) {
420 fprintf(stderr, "trouble opening proc file\n");
421 droptcb(tcp);
422 continue;
423 }
424#else /* !USE_PROCFS */
425# ifdef LINUX
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000426 if (followfork && !daemonized_tracer) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000427 char procdir[sizeof("/proc/%d/task") + sizeof(int) * 3];
Roland McGrath02203312007-06-11 22:06:31 +0000428 DIR *dir;
429
430 sprintf(procdir, "/proc/%d/task", tcp->pid);
431 dir = opendir(procdir);
432 if (dir != NULL) {
433 unsigned int ntid = 0, nerr = 0;
434 struct dirent *de;
435 int tid;
436 while ((de = readdir(dir)) != NULL) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000437 if (de->d_fileno == 0)
Roland McGrath02203312007-06-11 22:06:31 +0000438 continue;
439 tid = atoi(de->d_name);
440 if (tid <= 0)
441 continue;
442 ++ntid;
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000443 if (ptrace(PTRACE_ATTACH, tid, (char *) 1, 0) < 0)
Roland McGrath02203312007-06-11 22:06:31 +0000444 ++nerr;
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000445 else if (tid != tcbtab[tcbi]->pid) {
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000446 tcp = alloctcb(tid);
Wang Chao21b8db42010-08-27 17:43:16 +0800447 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_FOLLOWFORK;
Roland McGrath02203312007-06-11 22:06:31 +0000448 tcbtab[tcbi]->nchildren++;
449 tcbtab[tcbi]->nclone_threads++;
Roland McGrath02203312007-06-11 22:06:31 +0000450 tcp->parent = tcbtab[tcbi];
451 }
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000452 if (interactive) {
453 sigprocmask(SIG_SETMASK, &empty_set, NULL);
454 if (interrupted)
455 return;
456 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
457 }
Roland McGrath02203312007-06-11 22:06:31 +0000458 }
459 closedir(dir);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000460 ntid -= nerr;
461 if (ntid == 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000462 perror("attach: ptrace(PTRACE_ATTACH, ...)");
463 droptcb(tcp);
464 continue;
465 }
466 if (!qflag) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000467 fprintf(stderr, ntid > 1
468? "Process %u attached with %u threads - interrupt to quit\n"
469: "Process %u attached - interrupt to quit\n",
470 tcbtab[tcbi]->pid, ntid);
Roland McGrath02203312007-06-11 22:06:31 +0000471 }
472 continue;
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000473 } /* if (opendir worked) */
474 } /* if (-f) */
Roland McGrath02203312007-06-11 22:06:31 +0000475# endif
476 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
477 perror("attach: ptrace(PTRACE_ATTACH, ...)");
478 droptcb(tcp);
479 continue;
480 }
481 /* INTERRUPTED is going to be checked at the top of TRACE. */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000482
483 if (daemonized_tracer) {
484 /*
485 * It is our grandparent we trace, not a -p PID.
486 * Don't want to just detach on exit, so...
487 */
488 tcp->flags &= ~TCB_ATTACHED;
489 /*
490 * Make parent go away.
491 * Also makes grandparent's wait() unblock.
492 */
493 kill(getppid(), SIGKILL);
494 }
495
Roland McGrath02203312007-06-11 22:06:31 +0000496#endif /* !USE_PROCFS */
497 if (!qflag)
498 fprintf(stderr,
499 "Process %u attached - interrupt to quit\n",
500 tcp->pid);
501 }
502
503 if (interactive)
504 sigprocmask(SIG_SETMASK, &empty_set, NULL);
505}
506
507static void
508startup_child (char **argv)
509{
510 struct stat statbuf;
511 const char *filename;
512 char pathname[MAXPATHLEN];
513 int pid = 0;
514 struct tcb *tcp;
515
516 filename = argv[0];
517 if (strchr(filename, '/')) {
518 if (strlen(filename) > sizeof pathname - 1) {
519 errno = ENAMETOOLONG;
520 perror("strace: exec");
521 exit(1);
522 }
523 strcpy(pathname, filename);
524 }
525#ifdef USE_DEBUGGING_EXEC
526 /*
527 * Debuggers customarily check the current directory
528 * first regardless of the path but doing that gives
529 * security geeks a panic attack.
530 */
531 else if (stat(filename, &statbuf) == 0)
532 strcpy(pathname, filename);
533#endif /* USE_DEBUGGING_EXEC */
534 else {
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000535 const char *path;
Roland McGrath02203312007-06-11 22:06:31 +0000536 int m, n, len;
537
538 for (path = getenv("PATH"); path && *path; path += m) {
539 if (strchr(path, ':')) {
540 n = strchr(path, ':') - path;
541 m = n + 1;
542 }
543 else
544 m = n = strlen(path);
545 if (n == 0) {
546 if (!getcwd(pathname, MAXPATHLEN))
547 continue;
548 len = strlen(pathname);
549 }
550 else if (n > sizeof pathname - 1)
551 continue;
552 else {
553 strncpy(pathname, path, n);
554 len = n;
555 }
556 if (len && pathname[len - 1] != '/')
557 pathname[len++] = '/';
558 strcpy(pathname + len, filename);
559 if (stat(pathname, &statbuf) == 0 &&
560 /* Accept only regular files
561 with some execute bits set.
562 XXX not perfect, might still fail */
563 S_ISREG(statbuf.st_mode) &&
564 (statbuf.st_mode & 0111))
565 break;
566 }
567 }
568 if (stat(pathname, &statbuf) < 0) {
569 fprintf(stderr, "%s: %s: command not found\n",
570 progname, filename);
571 exit(1);
572 }
Dmitry V. Levina6809652008-11-10 17:14:58 +0000573 strace_child = pid = fork();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000574 if (pid < 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000575 perror("strace: fork");
576 cleanup();
577 exit(1);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000578 }
579 if ((pid != 0 && daemonized_tracer) /* parent: to become a traced process */
580 || (pid == 0 && !daemonized_tracer) /* child: to become a traced process */
581 ) {
582 pid = getpid();
Roland McGrath02203312007-06-11 22:06:31 +0000583#ifdef USE_PROCFS
584 if (outf != stderr) close (fileno (outf));
585#ifdef MIPS
586 /* Kludge for SGI, see proc_open for details. */
587 sa.sa_handler = foobar;
588 sa.sa_flags = 0;
589 sigemptyset(&sa.sa_mask);
590 sigaction(SIGINT, &sa, NULL);
591#endif /* MIPS */
592#ifndef FREEBSD
593 pause();
594#else /* FREEBSD */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000595 kill(pid, SIGSTOP); /* stop HERE */
Roland McGrath02203312007-06-11 22:06:31 +0000596#endif /* FREEBSD */
597#else /* !USE_PROCFS */
598 if (outf!=stderr)
599 close(fileno (outf));
600
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000601 if (!daemonized_tracer) {
602 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
603 perror("strace: ptrace(PTRACE_TRACEME, ...)");
604 exit(1);
605 }
606 if (debug)
607 kill(pid, SIGSTOP);
Roland McGrath02203312007-06-11 22:06:31 +0000608 }
Roland McGrath02203312007-06-11 22:06:31 +0000609
610 if (username != NULL || geteuid() == 0) {
611 uid_t run_euid = run_uid;
612 gid_t run_egid = run_gid;
613
614 if (statbuf.st_mode & S_ISUID)
615 run_euid = statbuf.st_uid;
616 if (statbuf.st_mode & S_ISGID)
617 run_egid = statbuf.st_gid;
618
619 /*
620 * It is important to set groups before we
621 * lose privileges on setuid.
622 */
623 if (username != NULL) {
624 if (initgroups(username, run_gid) < 0) {
625 perror("initgroups");
626 exit(1);
627 }
628 if (setregid(run_gid, run_egid) < 0) {
629 perror("setregid");
630 exit(1);
631 }
632 if (setreuid(run_uid, run_euid) < 0) {
633 perror("setreuid");
634 exit(1);
635 }
636 }
637 }
638 else
639 setreuid(run_uid, run_uid);
640
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000641 if (!daemonized_tracer) {
642 /*
643 * Induce an immediate stop so that the parent
644 * will resume us with PTRACE_SYSCALL and display
645 * this execve call normally.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400646 * Unless of course we're on a no-MMU system where
647 * we vfork()-ed, so we cannot stop the child.
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000648 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400649 if (!strace_vforked)
650 kill(getpid(), SIGSTOP);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000651 } else {
652 struct sigaction sv_sigchld;
653 sigaction(SIGCHLD, NULL, &sv_sigchld);
654 /*
655 * Make sure it is not SIG_IGN, otherwise wait
656 * will not block.
657 */
658 signal(SIGCHLD, SIG_DFL);
659 /*
660 * Wait for grandchild to attach to us.
661 * It kills child after that, and wait() unblocks.
662 */
663 alarm(3);
664 wait(NULL);
665 alarm(0);
666 sigaction(SIGCHLD, &sv_sigchld, NULL);
667 }
Roland McGrath02203312007-06-11 22:06:31 +0000668#endif /* !USE_PROCFS */
669
670 execv(pathname, argv);
671 perror("strace: exec");
672 _exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000673 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000674
675 /* We are the tracer. */
676 tcp = alloctcb(daemonized_tracer ? getppid() : pid);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000677 if (daemonized_tracer) {
678 /* We want subsequent startup_attach() to attach to it. */
679 tcp->flags |= TCB_ATTACHED;
680 }
Roland McGrath02203312007-06-11 22:06:31 +0000681#ifdef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000682 if (proc_open(tcp, 0) < 0) {
683 fprintf(stderr, "trouble opening proc file\n");
684 cleanup();
685 exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000686 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000687#endif /* USE_PROCFS */
Roland McGrath02203312007-06-11 22:06:31 +0000688}
689
Wang Chaob13c0de2010-11-12 17:25:19 +0800690#ifdef LINUX
691/*
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000692 * Test whether the kernel support PTRACE_O_TRACECLONE et al options.
Wang Chaob13c0de2010-11-12 17:25:19 +0800693 * First fork a new child, call ptrace with PTRACE_SETOPTIONS on it,
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000694 * and then see which options are supported by the kernel.
Wang Chaob13c0de2010-11-12 17:25:19 +0800695 */
696static int
697test_ptrace_setoptions(void)
698{
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000699 int pid, expected_grandchild = 0, found_grandchild = 0;
700 const unsigned int test_options = PTRACE_O_TRACECLONE |
701 PTRACE_O_TRACEFORK |
702 PTRACE_O_TRACEVFORK;
Wang Chaob13c0de2010-11-12 17:25:19 +0800703
704 if ((pid = fork()) < 0)
705 return -1;
706 else if (pid == 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000707 if (ptrace(PTRACE_TRACEME, 0, (char *)1, 0) < 0)
Wang Chaob13c0de2010-11-12 17:25:19 +0800708 _exit(1);
Wang Chaob13c0de2010-11-12 17:25:19 +0800709 kill(getpid(), SIGSTOP);
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000710 _exit(fork() < 0);
Wang Chaob13c0de2010-11-12 17:25:19 +0800711 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000712
713 while (1) {
714 int status, tracee_pid;
715
716 tracee_pid = wait(&status);
717 if (tracee_pid == -1) {
718 if (errno == EINTR)
719 continue;
720 else if (errno == ECHILD)
721 break;
722 perror("test_ptrace_setoptions");
723 return -1;
724 }
725 if (tracee_pid != pid) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000726 found_grandchild = tracee_pid;
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000727 if (ptrace(PTRACE_CONT, tracee_pid, 0, 0) < 0 &&
728 errno != ESRCH)
729 kill(tracee_pid, SIGKILL);
730 }
731 else if (WIFSTOPPED(status)) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000732 switch (WSTOPSIG(status)) {
733 case SIGSTOP:
734 if (ptrace(PTRACE_SETOPTIONS, pid,
735 NULL, test_options) < 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000736 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800737 return -1;
738 }
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000739 break;
740 case SIGTRAP:
741 if (status >> 16 == PTRACE_EVENT_FORK) {
742 long msg = 0;
743
744 if (ptrace(PTRACE_GETEVENTMSG, pid,
745 NULL, (long) &msg) == 0)
746 expected_grandchild = msg;
747 }
748 break;
Wang Chaob13c0de2010-11-12 17:25:19 +0800749 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000750 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0 &&
751 errno != ESRCH)
752 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800753 }
754 }
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +0000755 if (expected_grandchild && expected_grandchild == found_grandchild)
756 ptrace_setoptions |= test_options;
Wang Chaob13c0de2010-11-12 17:25:19 +0800757 return 0;
758}
759#endif
760
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000761int
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000762main(int argc, char *argv[])
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000763{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000764 struct tcb *tcp;
765 int c, pid = 0;
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000766 int optF = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000767 struct sigaction sa;
768
769 static char buf[BUFSIZ];
770
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000771 progname = argv[0] ? argv[0] : "strace";
772
Roland McGrathee9d4352002-12-18 04:16:10 +0000773 /* Allocate the initial tcbtab. */
774 tcbtabsize = argc; /* Surely enough for all -p args. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000775 if ((tcbtab = calloc(tcbtabsize, sizeof tcbtab[0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000776 fprintf(stderr, "%s: out of memory\n", progname);
777 exit(1);
778 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000779 if ((tcbtab[0] = calloc(tcbtabsize, sizeof tcbtab[0][0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000780 fprintf(stderr, "%s: out of memory\n", progname);
781 exit(1);
782 }
Roland McGrathee9d4352002-12-18 04:16:10 +0000783 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
784 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
785
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000786 outf = stderr;
787 interactive = 1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000788 set_sortby(DEFAULT_SORTBY);
789 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000790 qualify("trace=all");
791 qualify("abbrev=all");
792 qualify("verbose=all");
793 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000794 while ((c = getopt(argc, argv,
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000795 "+cCdfFhiqrtTvVxz"
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000796#ifndef USE_PROCFS
797 "D"
798#endif
799 "a:e:o:O:p:s:S:u:E:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000800 switch (c) {
801 case 'c':
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000802 if (cflag == CFLAG_BOTH) {
803 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
804 progname);
805 exit(1);
806 }
807 cflag = CFLAG_ONLY_STATS;
808 break;
809 case 'C':
810 if (cflag == CFLAG_ONLY_STATS) {
811 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
812 progname);
813 exit(1);
814 }
815 cflag = CFLAG_BOTH;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000816 break;
817 case 'd':
818 debug++;
819 break;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000820#ifndef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000821 case 'D':
822 daemonized_tracer = 1;
823 break;
824#endif
Roland McGrath41c48222008-07-18 00:25:10 +0000825 case 'F':
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000826 optF = 1;
827 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000828 case 'f':
829 followfork++;
830 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000831 case 'h':
832 usage(stdout, 0);
833 break;
834 case 'i':
835 iflag++;
836 break;
837 case 'q':
838 qflag++;
839 break;
840 case 'r':
841 rflag++;
842 tflag++;
843 break;
844 case 't':
845 tflag++;
846 break;
847 case 'T':
848 dtime++;
849 break;
850 case 'x':
851 xflag++;
852 break;
853 case 'v':
854 qualify("abbrev=none");
855 break;
856 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +0000857 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000858 exit(0);
859 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000860 case 'z':
861 not_failing_only = 1;
862 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000863 case 'a':
864 acolumn = atoi(optarg);
865 break;
866 case 'e':
867 qualify(optarg);
868 break;
869 case 'o':
870 outfname = strdup(optarg);
871 break;
872 case 'O':
873 set_overhead(atoi(optarg));
874 break;
875 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +0000876 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000877 fprintf(stderr, "%s: Invalid process id: %s\n",
878 progname, optarg);
879 break;
880 }
881 if (pid == getpid()) {
Wichert Akkerman54a47671999-10-17 00:57:34 +0000882 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000883 break;
884 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000885 tcp = alloc_tcb(pid, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000886 tcp->flags |= TCB_ATTACHED;
887 pflag_seen++;
888 break;
889 case 's':
890 max_strlen = atoi(optarg);
Roland McGrathdccec722005-05-09 07:45:47 +0000891 if (max_strlen < 0) {
892 fprintf(stderr,
893 "%s: invalid -s argument: %s\n",
894 progname, optarg);
895 exit(1);
896 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000897 break;
898 case 'S':
899 set_sortby(optarg);
900 break;
901 case 'u':
902 username = strdup(optarg);
903 break;
Roland McGrathde6e5332003-01-24 04:31:23 +0000904 case 'E':
905 if (putenv(optarg) < 0) {
906 fprintf(stderr, "%s: out of memory\n",
907 progname);
908 exit(1);
909 }
910 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000911 default:
912 usage(stderr, 1);
913 break;
914 }
915 }
916
Roland McGrathd0c4c0c2006-04-25 07:39:40 +0000917 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +0000918 usage(stderr, 1);
919
Wang Chaod322a4b2010-08-05 14:30:11 +0800920 if (pflag_seen && daemonized_tracer) {
921 fprintf(stderr,
922 "%s: -D and -p are mutually exclusive options\n",
923 progname);
924 exit(1);
925 }
926
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000927 if (!followfork)
928 followfork = optF;
929
Roland McGrathcb9def62006-04-25 07:48:03 +0000930 if (followfork > 1 && cflag) {
931 fprintf(stderr,
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000932 "%s: (-c or -C) and -ff are mutually exclusive options\n",
Roland McGrathcb9def62006-04-25 07:48:03 +0000933 progname);
934 exit(1);
935 }
936
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000937 /* See if they want to run as another user. */
938 if (username != NULL) {
939 struct passwd *pent;
940
941 if (getuid() != 0 || geteuid() != 0) {
942 fprintf(stderr,
943 "%s: you must be root to use the -u option\n",
944 progname);
945 exit(1);
946 }
947 if ((pent = getpwnam(username)) == NULL) {
948 fprintf(stderr, "%s: cannot find user `%s'\n",
Roland McGrath09553f82007-07-05 19:31:49 +0000949 progname, username);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000950 exit(1);
951 }
952 run_uid = pent->pw_uid;
953 run_gid = pent->pw_gid;
954 }
955 else {
956 run_uid = getuid();
957 run_gid = getgid();
958 }
959
Dmitry V. Levin8044bc12010-12-07 12:50:49 +0000960#ifdef LINUX
961 if (followfork) {
962 if (test_ptrace_setoptions() < 0) {
963 fprintf(stderr,
964 "Test for options supported by PTRACE_SETOPTIONS "
965 "failed, giving up using this feature.\n");
966 ptrace_setoptions = 0;
967 }
968 if (debug)
969 fprintf(stderr, "ptrace_setoptions = %#x\n",
970 ptrace_setoptions);
971 }
972#endif
973
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000974 /* Check if they want to redirect the output. */
975 if (outfname) {
Roland McGrath37b9a662003-11-07 02:26:54 +0000976 /* See if they want to pipe the output. */
977 if (outfname[0] == '|' || outfname[0] == '!') {
978 /*
979 * We can't do the <outfname>.PID funny business
980 * when using popen, so prohibit it.
981 */
982 if (followfork > 1) {
983 fprintf(stderr, "\
984%s: piping the output and -ff are mutually exclusive options\n",
985 progname);
986 exit(1);
987 }
988
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000989 if ((outf = strace_popen(outfname + 1)) == NULL)
Roland McGrath37b9a662003-11-07 02:26:54 +0000990 exit(1);
Roland McGrath37b9a662003-11-07 02:26:54 +0000991 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000992 else if (followfork <= 1 &&
993 (outf = strace_fopen(outfname, "w")) == NULL)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000994 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000995 }
996
Roland McGrath37b9a662003-11-07 02:26:54 +0000997 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000998 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +0000999 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001000 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001001 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +00001002 }
Wang Chaob13c0de2010-11-12 17:25:19 +08001003
Roland McGrath54cc1c82007-11-03 23:34:11 +00001004 /* Valid states here:
1005 optind < argc pflag_seen outfname interactive
1006 1 0 0 1
1007 0 1 0 1
1008 1 0 1 0
1009 0 1 1 1
1010 */
1011
1012 /* STARTUP_CHILD must be called before the signal handlers get
1013 installed below as they are inherited into the spawned process.
1014 Also we do not need to be protected by them as during interruption
1015 in the STARTUP_CHILD mode we kill the spawned process anyway. */
1016 if (!pflag_seen)
1017 startup_child(&argv[optind]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001018
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001019 sigemptyset(&empty_set);
1020 sigemptyset(&blocked_set);
1021 sa.sa_handler = SIG_IGN;
1022 sigemptyset(&sa.sa_mask);
1023 sa.sa_flags = 0;
1024 sigaction(SIGTTOU, &sa, NULL);
1025 sigaction(SIGTTIN, &sa, NULL);
1026 if (interactive) {
1027 sigaddset(&blocked_set, SIGHUP);
1028 sigaddset(&blocked_set, SIGINT);
1029 sigaddset(&blocked_set, SIGQUIT);
1030 sigaddset(&blocked_set, SIGPIPE);
1031 sigaddset(&blocked_set, SIGTERM);
1032 sa.sa_handler = interrupt;
1033#ifdef SUNOS4
1034 /* POSIX signals on sunos4.1 are a little broken. */
1035 sa.sa_flags = SA_INTERRUPT;
1036#endif /* SUNOS4 */
1037 }
1038 sigaction(SIGHUP, &sa, NULL);
1039 sigaction(SIGINT, &sa, NULL);
1040 sigaction(SIGQUIT, &sa, NULL);
1041 sigaction(SIGPIPE, &sa, NULL);
1042 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001043#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001044 sa.sa_handler = reaper;
1045 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +00001046#else
1047 /* Make sure SIGCHLD has the default action so that waitpid
1048 definitely works without losing track of children. The user
1049 should not have given us a bogus state to inherit, but he might
1050 have. Arguably we should detect SIG_IGN here and pass it on
1051 to children, but probably noone really needs that. */
1052 sa.sa_handler = SIG_DFL;
1053 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001054#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001055
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +00001056 if (pflag_seen || daemonized_tracer)
Roland McGrath02203312007-06-11 22:06:31 +00001057 startup_attach();
Roland McGrath02203312007-06-11 22:06:31 +00001058
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001059 if (trace() < 0)
1060 exit(1);
1061 cleanup();
Dmitry V. Levina6809652008-11-10 17:14:58 +00001062 fflush(NULL);
1063 if (exit_code > 0xff) {
1064 /* Child was killed by a signal, mimic that. */
1065 exit_code &= 0xff;
1066 signal(exit_code, SIG_DFL);
1067 raise(exit_code);
1068 /* Paranoia - what if this signal is not fatal?
1069 Exit with 128 + signo then. */
1070 exit_code += 128;
1071 }
1072 exit(exit_code);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001073}
1074
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001075void
1076expand_tcbtab(void)
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001077{
1078 /* Allocate some more TCBs and expand the table.
1079 We don't want to relocate the TCBs because our
1080 callers have pointers and it would be a pain.
1081 So tcbtab is a table of pointers. Since we never
1082 free the TCBs, we allocate a single chunk of many. */
1083 struct tcb **newtab = (struct tcb **)
1084 realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
1085 struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
1086 sizeof *newtcbs);
1087 int i;
1088 if (newtab == NULL || newtcbs == NULL) {
Dmitry V. Levin76860f62006-10-11 22:55:25 +00001089 fprintf(stderr, "%s: expand_tcbtab: out of memory\n",
1090 progname);
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001091 cleanup();
1092 exit(1);
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001093 }
1094 for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
1095 newtab[i] = &newtcbs[i - tcbtabsize];
1096 tcbtabsize *= 2;
1097 tcbtab = newtab;
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001098}
1099
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001100struct tcb *
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001101alloc_tcb(int pid, int command_options_parsed)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001102{
1103 int i;
1104 struct tcb *tcp;
1105
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001106 if (nprocs == tcbtabsize)
1107 expand_tcbtab();
1108
Roland McGrathee9d4352002-12-18 04:16:10 +00001109 for (i = 0; i < tcbtabsize; i++) {
1110 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001111 if ((tcp->flags & TCB_INUSE) == 0) {
1112 tcp->pid = pid;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001113 tcp->parent = NULL;
1114 tcp->nchildren = 0;
1115 tcp->nzombies = 0;
1116#ifdef TCB_CLONE_THREAD
Wang Chao21b8db42010-08-27 17:43:16 +08001117 tcp->nclone_threads = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001118 tcp->nclone_waiting = 0;
1119#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001120 tcp->flags = TCB_INUSE | TCB_STARTUP;
1121 tcp->outf = outf; /* Initialise to current out file */
Andreas Schwabccdff482009-10-27 16:27:13 +01001122 tcp->curcol = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001123 tcp->stime.tv_sec = 0;
1124 tcp->stime.tv_usec = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001125 tcp->pfd = -1;
1126 nprocs++;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001127 if (command_options_parsed)
1128 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001129 return tcp;
1130 }
1131 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001132 fprintf(stderr, "%s: bug in alloc_tcb\n", progname);
1133 cleanup();
1134 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001135}
1136
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001137#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001138int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001139proc_open(struct tcb *tcp, int attaching)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001140{
1141 char proc[32];
1142 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001143#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +00001144 int i;
1145 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001146 sigset_t signals;
1147 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001148#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001149#ifndef HAVE_POLLABLE_PROCFS
1150 static int last_pfd;
1151#endif
1152
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001153#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001154 /* Open the process pseudo-files in /proc. */
1155 sprintf(proc, "/proc/%d/ctl", tcp->pid);
1156 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001157 perror("strace: open(\"/proc/...\", ...)");
1158 return -1;
1159 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001160 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001161 return -1;
1162 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001163 sprintf(proc, "/proc/%d/status", tcp->pid);
1164 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
1165 perror("strace: open(\"/proc/...\", ...)");
1166 return -1;
1167 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001168 if (set_cloexec_flag(tcp->pfd_stat) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001169 return -1;
1170 }
1171 sprintf(proc, "/proc/%d/as", tcp->pid);
1172 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
1173 perror("strace: open(\"/proc/...\", ...)");
1174 return -1;
1175 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001176 if (set_cloexec_flag(tcp->pfd_as) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001177 return -1;
1178 }
1179#else
1180 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001181#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001182 sprintf(proc, "/proc/%d", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001183 tcp->pfd = open(proc, O_RDWR|O_EXCL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001184#else /* FREEBSD */
1185 sprintf(proc, "/proc/%d/mem", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001186 tcp->pfd = open(proc, O_RDWR);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001187#endif /* FREEBSD */
Andreas Schwab372cc842010-07-09 11:49:27 +02001188 if (tcp->pfd < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001189 perror("strace: open(\"/proc/...\", ...)");
1190 return -1;
1191 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001192 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001193 return -1;
1194 }
1195#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001196#ifdef FREEBSD
1197 sprintf(proc, "/proc/%d/regs", tcp->pid);
1198 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
1199 perror("strace: open(\"/proc/.../regs\", ...)");
1200 return -1;
1201 }
1202 if (cflag) {
1203 sprintf(proc, "/proc/%d/status", tcp->pid);
1204 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
1205 perror("strace: open(\"/proc/.../status\", ...)");
1206 return -1;
1207 }
1208 } else
1209 tcp->pfd_status = -1;
1210#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001211 rebuild_pollv();
1212 if (!attaching) {
1213 /*
1214 * Wait for the child to pause. Because of a race
1215 * condition we have to poll for the event.
1216 */
1217 for (;;) {
1218 if (IOCTL_STATUS (tcp) < 0) {
1219 perror("strace: PIOCSTATUS");
1220 return -1;
1221 }
1222 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001223 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001224 }
1225 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001226#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001227 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001228 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001229 perror("strace: PIOCSTOP");
1230 return -1;
1231 }
Roland McGrath553a6092002-12-16 20:40:39 +00001232#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001233#ifdef PIOCSET
1234 /* Set Run-on-Last-Close. */
1235 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001236 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001237 perror("PIOCSET PR_RLC");
1238 return -1;
1239 }
1240 /* Set or Reset Inherit-on-Fork. */
1241 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001242 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001243 perror("PIOC{SET,RESET} PR_FORK");
1244 return -1;
1245 }
1246#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +00001247#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001248 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
1249 perror("PIOCSRLC");
1250 return -1;
1251 }
1252 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
1253 perror("PIOC{S,R}FORK");
1254 return -1;
1255 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001256#else /* FREEBSD */
1257 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
1258 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
1259 perror("PIOCGFL");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001260 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001261 }
1262 arg &= ~PF_LINGER;
1263 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001264 perror("PIOCSFL");
1265 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001266 }
1267#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001268#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001269#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +00001270 /* Enable all syscall entries we care about. */
1271 premptyset(&syscalls);
1272 for (i = 1; i < MAX_QUALS; ++i) {
1273 if (i > (sizeof syscalls) * CHAR_BIT) break;
1274 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
1275 }
1276 praddset (&syscalls, SYS_execve);
1277 if (followfork) {
1278 praddset (&syscalls, SYS_fork);
1279#ifdef SYS_forkall
1280 praddset (&syscalls, SYS_forkall);
1281#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001282#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +00001283 praddset (&syscalls, SYS_fork1);
1284#endif
1285#ifdef SYS_rfork1
1286 praddset (&syscalls, SYS_rfork1);
1287#endif
1288#ifdef SYS_rforkall
1289 praddset (&syscalls, SYS_rforkall);
1290#endif
1291 }
1292 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001293 perror("PIOCSENTRY");
1294 return -1;
1295 }
John Hughes19e49982001-10-19 08:59:12 +00001296 /* Enable the syscall exits. */
1297 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001298 perror("PIOSEXIT");
1299 return -1;
1300 }
John Hughes19e49982001-10-19 08:59:12 +00001301 /* Enable signals we care about. */
1302 premptyset(&signals);
1303 for (i = 1; i < MAX_QUALS; ++i) {
1304 if (i > (sizeof signals) * CHAR_BIT) break;
1305 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
1306 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001307 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001308 perror("PIOCSTRACE");
1309 return -1;
1310 }
John Hughes19e49982001-10-19 08:59:12 +00001311 /* Enable faults we care about */
1312 premptyset(&faults);
1313 for (i = 1; i < MAX_QUALS; ++i) {
1314 if (i > (sizeof faults) * CHAR_BIT) break;
1315 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
1316 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001317 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001318 perror("PIOCSFAULT");
1319 return -1;
1320 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001321#else /* FREEBSD */
1322 /* set events flags. */
1323 arg = S_SIG | S_SCE | S_SCX ;
1324 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
1325 perror("PIOCBIS");
1326 return -1;
1327 }
1328#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001329 if (!attaching) {
1330#ifdef MIPS
1331 /*
1332 * The SGI PRSABORT doesn't work for pause() so
1333 * we send it a caught signal to wake it up.
1334 */
1335 kill(tcp->pid, SIGINT);
1336#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +00001337#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001338 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001339 arg = PRSABORT;
1340 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001341 perror("PIOCRUN");
1342 return -1;
1343 }
Roland McGrath553a6092002-12-16 20:40:39 +00001344#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001345#endif /* !MIPS*/
1346#ifdef FREEBSD
1347 /* wake up the child if it received the SIGSTOP */
1348 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001349#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001350 for (;;) {
1351 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001352 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001353 perror("PIOCWSTOP");
1354 return -1;
1355 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001356 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001357 tcp->flags &= ~TCB_INSYSCALL;
1358 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001359 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001360 break;
1361 }
1362 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001363#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001364 arg = 0;
1365 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001366#else /* FREEBSD */
1367 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001368#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001369 perror("PIOCRUN");
1370 return -1;
1371 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001372#ifdef FREEBSD
1373 /* handle the case where we "opened" the child before
1374 it did the kill -STOP */
1375 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1376 tcp->status.PR_WHAT == SIGSTOP)
1377 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001378#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001379 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001380#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001381 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001382#else /* FREEBSD */
1383 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001384 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001385 /* We are attaching to an already running process.
1386 * Try to figure out the state of the process in syscalls,
1387 * to handle the first event well.
1388 * This is done by having a look at the "wchan" property of the
1389 * process, which tells where it is stopped (if it is). */
1390 FILE * status;
1391 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001392
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001393 sprintf(proc, "/proc/%d/status", tcp->pid);
1394 status = fopen(proc, "r");
1395 if (status &&
1396 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1397 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1398 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1399 strcmp(wchan, "stopevent")) {
1400 /* The process is asleep in the middle of a syscall.
1401 Fake the syscall entry event */
1402 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1403 tcp->status.PR_WHY = PR_SYSENTRY;
1404 trace_syscall(tcp);
1405 }
1406 if (status)
1407 fclose(status);
1408 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001409 }
1410#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001411#ifndef HAVE_POLLABLE_PROCFS
1412 if (proc_poll_pipe[0] != -1)
1413 proc_poller(tcp->pfd);
1414 else if (nprocs > 1) {
1415 proc_poll_open();
1416 proc_poller(last_pfd);
1417 proc_poller(tcp->pfd);
1418 }
1419 last_pfd = tcp->pfd;
1420#endif /* !HAVE_POLLABLE_PROCFS */
1421 return 0;
1422}
1423
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001424#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001425
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001426struct tcb *
Roland McGrath54e931f2010-09-14 18:59:20 -07001427pid2tcb(int pid)
1428{
1429 int i;
1430
1431 if (pid <= 0)
1432 return NULL;
1433
1434 for (i = 0; i < tcbtabsize; i++) {
1435 struct tcb *tcp = tcbtab[i];
1436 if (tcp->pid == pid && (tcp->flags & TCB_INUSE))
1437 return tcp;
1438 }
1439
1440 return NULL;
1441}
1442
1443#ifdef USE_PROCFS
1444
1445static struct tcb *
1446first_used_tcb(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001447{
1448 int i;
1449 struct tcb *tcp;
Roland McGrathee9d4352002-12-18 04:16:10 +00001450 for (i = 0; i < tcbtabsize; i++) {
1451 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001452 if (tcp->flags & TCB_INUSE)
1453 return tcp;
1454 }
1455 return NULL;
1456}
1457
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001458static struct tcb *
1459pfd2tcb(pfd)
1460int pfd;
1461{
1462 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001463
Roland McGrathca16be82003-01-10 19:55:28 +00001464 for (i = 0; i < tcbtabsize; i++) {
1465 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001466 if (tcp->pfd != pfd)
1467 continue;
1468 if (tcp->flags & TCB_INUSE)
1469 return tcp;
1470 }
1471 return NULL;
1472}
1473
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001474#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001475
1476void
1477droptcb(tcp)
1478struct tcb *tcp;
1479{
1480 if (tcp->pid == 0)
1481 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001482#ifdef TCB_CLONE_THREAD
1483 if (tcp->nclone_threads > 0) {
1484 /* There are other threads left in this process, but this
1485 is the one whose PID represents the whole process.
1486 We need to keep this record around as a zombie until
1487 all the threads die. */
1488 tcp->flags |= TCB_EXITING;
1489 return;
1490 }
1491#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001492 nprocs--;
1493 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001494
Roland McGrathe29341c2003-01-10 20:14:20 +00001495 if (tcp->parent != NULL) {
1496 tcp->parent->nchildren--;
1497#ifdef TCB_CLONE_THREAD
Roland McGrathe29341c2003-01-10 20:14:20 +00001498 if (tcp->flags & TCB_CLONE_THREAD)
1499 tcp->parent->nclone_threads--;
1500#endif
Wang Chao21b8db42010-08-27 17:43:16 +08001501 tcp->parent->nzombies++;
Roland McGrath276ceb32007-11-13 08:12:12 +00001502#ifdef LINUX
1503 /* Update `tcp->parent->parent->nchildren' and the other fields
1504 like NCLONE_DETACHED, only for zombie group leader that has
1505 already reported and been short-circuited at the top of this
1506 function. The same condition as at the top of DETACH. */
1507 if ((tcp->flags & TCB_CLONE_THREAD) &&
1508 tcp->parent->nclone_threads == 0 &&
1509 (tcp->parent->flags & TCB_EXITING))
1510 droptcb(tcp->parent);
1511#endif
Roland McGrathe29341c2003-01-10 20:14:20 +00001512 tcp->parent = NULL;
1513 }
1514
1515 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001516 if (tcp->pfd != -1) {
1517 close(tcp->pfd);
1518 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001519#ifdef FREEBSD
1520 if (tcp->pfd_reg != -1) {
1521 close(tcp->pfd_reg);
1522 tcp->pfd_reg = -1;
1523 }
1524 if (tcp->pfd_status != -1) {
1525 close(tcp->pfd_status);
1526 tcp->pfd_status = -1;
1527 }
Roland McGrath553a6092002-12-16 20:40:39 +00001528#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001529#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001530 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001531#endif
1532 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001533
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001534 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001535 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001536
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001537 tcp->outf = 0;
1538}
1539
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001540#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001541
1542static int
1543resume(tcp)
1544struct tcb *tcp;
1545{
1546 if (tcp == NULL)
1547 return -1;
1548
1549 if (!(tcp->flags & TCB_SUSPENDED)) {
1550 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1551 return -1;
1552 }
1553 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001554#ifdef TCB_CLONE_THREAD
1555 if (tcp->flags & TCB_CLONE_THREAD)
1556 tcp->parent->nclone_waiting--;
1557#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001558
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001559 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001560 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001561
1562 if (!qflag)
1563 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1564 return 0;
1565}
1566
Roland McGrath1bfd3102007-08-03 10:02:00 +00001567static int
1568resume_from_tcp (struct tcb *tcp)
1569{
1570 int error = 0;
1571 int resumed = 0;
1572
1573 /* XXX This won't always be quite right (but it never was).
1574 A waiter with argument 0 or < -1 is waiting for any pid in
1575 a particular pgrp, which this child might or might not be
1576 in. The waiter will only wake up if it's argument is -1
1577 or if it's waiting for tcp->pid's pgrp. It makes a
1578 difference to wake up a waiter when there might be more
1579 traced children, because it could get a false ECHILD
1580 error. OTOH, if this was the last child in the pgrp, then
1581 it ought to wake up and get ECHILD. We would have to
1582 search the system for all pid's in the pgrp to be sure.
1583
1584 && (t->waitpid == -1 ||
1585 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1586 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1587 */
1588
1589 if (tcp->parent &&
1590 (tcp->parent->flags & TCB_SUSPENDED) &&
1591 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001592 error = resume(tcp->parent);
Roland McGrath1bfd3102007-08-03 10:02:00 +00001593 ++resumed;
1594 }
1595#ifdef TCB_CLONE_THREAD
1596 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1597 /* Some other threads of our parent are waiting too. */
1598 unsigned int i;
1599
1600 /* Resume all the threads that were waiting for this PID. */
1601 for (i = 0; i < tcbtabsize; i++) {
1602 struct tcb *t = tcbtab[i];
1603 if (t->parent == tcp->parent && t != tcp
1604 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1605 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1606 && t->waitpid == tcp->pid) {
1607 error |= resume (t);
1608 ++resumed;
1609 }
1610 }
1611 if (resumed == 0)
1612 /* Noone was waiting for this PID in particular,
1613 so now we might need to resume some wildcarders. */
1614 for (i = 0; i < tcbtabsize; i++) {
1615 struct tcb *t = tcbtab[i];
1616 if (t->parent == tcp->parent && t != tcp
1617 && ((t->flags
1618 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1619 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1620 && t->waitpid <= 0
1621 ) {
1622 error |= resume (t);
1623 break;
1624 }
1625 }
1626 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001627#endif
Roland McGrath1bfd3102007-08-03 10:02:00 +00001628
1629 return error;
1630}
Roland McGrath1bfd3102007-08-03 10:02:00 +00001631
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001632#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001633
Roland McGrath0a463882007-07-05 18:43:16 +00001634/* detach traced process; continue with sig
1635 Never call DETACH twice on the same process as both unattached and
1636 attached-unstopped processes give the same ESRCH. For unattached process we
1637 would SIGSTOP it and wait for its SIGSTOP notification forever. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001638
1639static int
1640detach(tcp, sig)
1641struct tcb *tcp;
1642int sig;
1643{
1644 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001645#ifdef LINUX
Roland McGrath1bfd3102007-08-03 10:02:00 +00001646 int status, catch_sigstop;
Roland McGratha08a97e2005-08-03 11:23:46 +00001647 struct tcb *zombie = NULL;
1648
1649 /* If the group leader is lingering only because of this other
1650 thread now dying, then detach the leader as well. */
1651 if ((tcp->flags & TCB_CLONE_THREAD) &&
1652 tcp->parent->nclone_threads == 1 &&
1653 (tcp->parent->flags & TCB_EXITING))
1654 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001655#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001656
1657 if (tcp->flags & TCB_BPTSET)
Andreas Schwab840d85b2010-01-12 11:16:32 +01001658 clearbpt(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001659
1660#ifdef LINUX
1661 /*
1662 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001663 * before detaching. Arghh. We go through hoops
1664 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001665 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001666#if defined(SPARC)
1667#undef PTRACE_DETACH
1668#define PTRACE_DETACH PTRACE_SUNDETACH
1669#endif
Roland McGrath02203312007-06-11 22:06:31 +00001670 /*
1671 * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
1672 * expected SIGSTOP. We must catch exactly one as otherwise the
1673 * detached process would be left stopped (process state T).
1674 */
1675 catch_sigstop = (tcp->flags & TCB_STARTUP);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001676 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1677 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001678 }
1679 else if (errno != ESRCH) {
1680 /* Shouldn't happen. */
1681 perror("detach: ptrace(PTRACE_DETACH, ...)");
1682 }
Roland McGrath134813a2007-06-02 00:07:33 +00001683 else if (my_tgkill((tcp->flags & TCB_CLONE_THREAD ? tcp->parent->pid
1684 : tcp->pid),
1685 tcp->pid, 0) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001686 if (errno != ESRCH)
1687 perror("detach: checking sanity");
1688 }
Roland McGrath02203312007-06-11 22:06:31 +00001689 else if (!catch_sigstop && my_tgkill((tcp->flags & TCB_CLONE_THREAD
1690 ? tcp->parent->pid : tcp->pid),
1691 tcp->pid, SIGSTOP) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001692 if (errno != ESRCH)
1693 perror("detach: stopping child");
1694 }
Roland McGrath02203312007-06-11 22:06:31 +00001695 else
1696 catch_sigstop = 1;
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001697 if (catch_sigstop) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001698 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001699#ifdef __WALL
1700 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1701 if (errno == ECHILD) /* Already gone. */
1702 break;
1703 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001704 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001705 break;
1706 }
1707#endif /* __WALL */
1708 /* No __WALL here. */
1709 if (waitpid(tcp->pid, &status, 0) < 0) {
1710 if (errno != ECHILD) {
1711 perror("detach: waiting");
1712 break;
1713 }
1714#ifdef __WCLONE
1715 /* If no processes, try clones. */
1716 if (wait4(tcp->pid, &status, __WCLONE,
1717 NULL) < 0) {
1718 if (errno != ECHILD)
1719 perror("detach: waiting");
1720 break;
1721 }
1722#endif /* __WCLONE */
1723 }
1724#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001725 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001726#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001727 if (!WIFSTOPPED(status)) {
1728 /* Au revoir, mon ami. */
1729 break;
1730 }
1731 if (WSTOPSIG(status) == SIGSTOP) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001732 ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001733 break;
1734 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001735 error = ptrace_restart(PTRACE_CONT, tcp,
Roland McGratheb9e2e82009-06-02 16:49:22 -07001736 WSTOPSIG(status) == SIGTRAP ? 0
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001737 : WSTOPSIG(status));
1738 if (error < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001739 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001740 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001741 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001742#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001743
1744#if defined(SUNOS4)
1745 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1746 if (sig && kill(tcp->pid, sig) < 0)
1747 perror("detach: kill");
1748 sig = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001749 error = ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001750#endif /* SUNOS4 */
1751
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001752#ifndef USE_PROCFS
Roland McGrath1bfd3102007-08-03 10:02:00 +00001753 error |= resume_from_tcp (tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001754#endif
1755
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001756 if (!qflag)
1757 fprintf(stderr, "Process %u detached\n", tcp->pid);
1758
1759 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001760
1761#ifdef LINUX
Roland McGrath0a463882007-07-05 18:43:16 +00001762 if (zombie != NULL) {
1763 /* TCP no longer exists therefore you must not detach () it. */
1764 droptcb(zombie);
1765 }
Roland McGratha08a97e2005-08-03 11:23:46 +00001766#endif
1767
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001768 return error;
1769}
1770
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001771#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001772
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001773static void reaper(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001774{
1775 int pid;
1776 int status;
1777
1778 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001779 }
1780}
1781
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001782#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001783
1784static void
1785cleanup()
1786{
1787 int i;
1788 struct tcb *tcp;
1789
Roland McGrathee9d4352002-12-18 04:16:10 +00001790 for (i = 0; i < tcbtabsize; i++) {
1791 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001792 if (!(tcp->flags & TCB_INUSE))
1793 continue;
1794 if (debug)
1795 fprintf(stderr,
1796 "cleanup: looking at pid %u\n", tcp->pid);
1797 if (tcp_last &&
1798 (!outfname || followfork < 2 || tcp_last == tcp)) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001799 tprintf(" <unfinished ...>");
1800 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001801 }
1802 if (tcp->flags & TCB_ATTACHED)
1803 detach(tcp, 0);
1804 else {
1805 kill(tcp->pid, SIGCONT);
1806 kill(tcp->pid, SIGTERM);
1807 }
1808 }
1809 if (cflag)
1810 call_summary(outf);
1811}
1812
1813static void
1814interrupt(sig)
1815int sig;
1816{
1817 interrupted = 1;
1818}
1819
1820#ifndef HAVE_STRERROR
1821
Roland McGrath6d2b3492002-12-30 00:51:30 +00001822#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001823extern int sys_nerr;
1824extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001825#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001826
1827const char *
1828strerror(errno)
1829int errno;
1830{
1831 static char buf[64];
1832
1833 if (errno < 1 || errno >= sys_nerr) {
1834 sprintf(buf, "Unknown error %d", errno);
1835 return buf;
1836 }
1837 return sys_errlist[errno];
1838}
1839
1840#endif /* HAVE_STERRROR */
1841
1842#ifndef HAVE_STRSIGNAL
1843
Roland McGrath8f474e02003-01-14 07:53:33 +00001844#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001845extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001846#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001847#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1848extern char *_sys_siglist[];
1849#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001850
1851const char *
1852strsignal(sig)
1853int sig;
1854{
1855 static char buf[64];
1856
1857 if (sig < 1 || sig >= NSIG) {
1858 sprintf(buf, "Unknown signal %d", sig);
1859 return buf;
1860 }
1861#ifdef HAVE__SYS_SIGLIST
1862 return _sys_siglist[sig];
1863#else
1864 return sys_siglist[sig];
1865#endif
1866}
1867
1868#endif /* HAVE_STRSIGNAL */
1869
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001870#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001871
1872static void
1873rebuild_pollv()
1874{
1875 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001876
Roland McGrathee9d4352002-12-18 04:16:10 +00001877 if (pollv != NULL)
1878 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001879 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001880 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001881 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00001882 exit(1);
1883 }
1884
Roland McGrathca16be82003-01-10 19:55:28 +00001885 for (i = j = 0; i < tcbtabsize; i++) {
1886 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001887 if (!(tcp->flags & TCB_INUSE))
1888 continue;
1889 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001890 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001891 j++;
1892 }
1893 if (j != nprocs) {
1894 fprintf(stderr, "strace: proc miscount\n");
1895 exit(1);
1896 }
1897}
1898
1899#ifndef HAVE_POLLABLE_PROCFS
1900
1901static void
1902proc_poll_open()
1903{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001904 int i;
1905
1906 if (pipe(proc_poll_pipe) < 0) {
1907 perror("pipe");
1908 exit(1);
1909 }
1910 for (i = 0; i < 2; i++) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001911 if (set_cloexec_flag(proc_poll_pipe[i]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001912 exit(1);
1913 }
1914 }
1915}
1916
1917static int
1918proc_poll(pollv, nfds, timeout)
1919struct pollfd *pollv;
1920int nfds;
1921int timeout;
1922{
1923 int i;
1924 int n;
1925 struct proc_pollfd pollinfo;
1926
1927 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1928 return n;
1929 if (n != sizeof(struct proc_pollfd)) {
1930 fprintf(stderr, "panic: short read: %d\n", n);
1931 exit(1);
1932 }
1933 for (i = 0; i < nprocs; i++) {
1934 if (pollv[i].fd == pollinfo.fd)
1935 pollv[i].revents = pollinfo.revents;
1936 else
1937 pollv[i].revents = 0;
1938 }
1939 poller_pid = pollinfo.pid;
1940 return 1;
1941}
1942
1943static void
1944wakeup_handler(sig)
1945int sig;
1946{
1947}
1948
1949static void
1950proc_poller(pfd)
1951int pfd;
1952{
1953 struct proc_pollfd pollinfo;
1954 struct sigaction sa;
1955 sigset_t blocked_set, empty_set;
1956 int i;
1957 int n;
1958 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001959#ifdef FREEBSD
1960 struct procfs_status pfs;
1961#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001962
1963 switch (fork()) {
1964 case -1:
1965 perror("fork");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001966 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001967 case 0:
1968 break;
1969 default:
1970 return;
1971 }
1972
1973 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1974 sa.sa_flags = 0;
1975 sigemptyset(&sa.sa_mask);
1976 sigaction(SIGHUP, &sa, NULL);
1977 sigaction(SIGINT, &sa, NULL);
1978 sigaction(SIGQUIT, &sa, NULL);
1979 sigaction(SIGPIPE, &sa, NULL);
1980 sigaction(SIGTERM, &sa, NULL);
1981 sa.sa_handler = wakeup_handler;
1982 sigaction(SIGUSR1, &sa, NULL);
1983 sigemptyset(&blocked_set);
1984 sigaddset(&blocked_set, SIGUSR1);
1985 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1986 sigemptyset(&empty_set);
1987
1988 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1989 perror("getrlimit(RLIMIT_NOFILE, ...)");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001990 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001991 }
1992 n = rl.rlim_cur;
1993 for (i = 0; i < n; i++) {
1994 if (i != pfd && i != proc_poll_pipe[1])
1995 close(i);
1996 }
1997
1998 pollinfo.fd = pfd;
1999 pollinfo.pid = getpid();
2000 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002001#ifndef FREEBSD
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002002 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
2003#else
2004 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
2005#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002006 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002007 switch (errno) {
2008 case EINTR:
2009 continue;
2010 case EBADF:
2011 pollinfo.revents = POLLERR;
2012 break;
2013 case ENOENT:
2014 pollinfo.revents = POLLHUP;
2015 break;
2016 default:
2017 perror("proc_poller: PIOCWSTOP");
2018 }
2019 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2020 _exit(0);
2021 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002022 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002023 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2024 sigsuspend(&empty_set);
2025 }
2026}
2027
2028#endif /* !HAVE_POLLABLE_PROCFS */
2029
2030static int
2031choose_pfd()
2032{
2033 int i, j;
2034 struct tcb *tcp;
2035
2036 static int last;
2037
2038 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002039 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002040 /*
2041 * The previous process is ready to run again. We'll
2042 * let it do so if it is currently in a syscall. This
2043 * heuristic improves the readability of the trace.
2044 */
2045 tcp = pfd2tcb(pollv[last].fd);
2046 if (tcp && (tcp->flags & TCB_INSYSCALL))
2047 return pollv[last].fd;
2048 }
2049
2050 for (i = 0; i < nprocs; i++) {
2051 /* Let competing children run round robin. */
2052 j = (i + last + 1) % nprocs;
2053 if (pollv[j].revents & (POLLHUP | POLLERR)) {
2054 tcp = pfd2tcb(pollv[j].fd);
2055 if (!tcp) {
2056 fprintf(stderr, "strace: lost proc\n");
2057 exit(1);
2058 }
2059 droptcb(tcp);
2060 return -1;
2061 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002062 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002063 last = j;
2064 return pollv[j].fd;
2065 }
2066 }
2067 fprintf(stderr, "strace: nothing ready\n");
2068 exit(1);
2069}
2070
2071static int
2072trace()
2073{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002074#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00002075 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002076#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002077 struct tcb *tcp;
2078 int pfd;
2079 int what;
2080 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002081 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002082
2083 for (;;) {
2084 if (interactive)
2085 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2086
2087 if (nprocs == 0)
2088 break;
2089
2090 switch (nprocs) {
2091 case 1:
2092#ifndef HAVE_POLLABLE_PROCFS
2093 if (proc_poll_pipe[0] == -1) {
2094#endif
Roland McGrath54e931f2010-09-14 18:59:20 -07002095 tcp = first_used_tcb();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002096 if (!tcp)
2097 continue;
2098 pfd = tcp->pfd;
2099 if (pfd == -1)
2100 continue;
2101 break;
2102#ifndef HAVE_POLLABLE_PROCFS
2103 }
2104 /* fall through ... */
2105#endif /* !HAVE_POLLABLE_PROCFS */
2106 default:
2107#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002108#ifdef POLL_HACK
2109 /* On some systems (e.g. UnixWare) we get too much ugly
2110 "unfinished..." stuff when multiple proceses are in
2111 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00002112
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002113 if (in_syscall) {
2114 struct pollfd pv;
2115 tcp = in_syscall;
2116 in_syscall = NULL;
2117 pv.fd = tcp->pfd;
2118 pv.events = POLLWANT;
2119 if ((what = poll (&pv, 1, 1)) < 0) {
2120 if (interrupted)
2121 return 0;
2122 continue;
2123 }
2124 else if (what == 1 && pv.revents & POLLWANT) {
2125 goto FOUND;
2126 }
2127 }
2128#endif
2129
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002130 if (poll(pollv, nprocs, INFTIM) < 0) {
2131 if (interrupted)
2132 return 0;
2133 continue;
2134 }
2135#else /* !HAVE_POLLABLE_PROCFS */
2136 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
2137 if (interrupted)
2138 return 0;
2139 continue;
2140 }
2141#endif /* !HAVE_POLLABLE_PROCFS */
2142 pfd = choose_pfd();
2143 if (pfd == -1)
2144 continue;
2145 break;
2146 }
2147
2148 /* Look up `pfd' in our table. */
2149 if ((tcp = pfd2tcb(pfd)) == NULL) {
2150 fprintf(stderr, "unknown pfd: %u\n", pfd);
2151 exit(1);
2152 }
John Hughesb6643082002-05-23 11:02:22 +00002153#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002154 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00002155#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002156 /* Get the status of the process. */
2157 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002158#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002159 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002160#else /* FREEBSD */
2161 /* Thanks to some scheduling mystery, the first poller
2162 sometimes waits for the already processed end of fork
2163 event. Doing a non blocking poll here solves the problem. */
2164 if (proc_poll_pipe[0] != -1)
2165 ioctl_result = IOCTL_STATUS (tcp);
2166 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002167 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00002168#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002169 ioctl_errno = errno;
2170#ifndef HAVE_POLLABLE_PROCFS
2171 if (proc_poll_pipe[0] != -1) {
2172 if (ioctl_result < 0)
2173 kill(poller_pid, SIGKILL);
2174 else
2175 kill(poller_pid, SIGUSR1);
2176 }
2177#endif /* !HAVE_POLLABLE_PROCFS */
2178 }
2179 if (interrupted)
2180 return 0;
2181
2182 if (interactive)
2183 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2184
2185 if (ioctl_result < 0) {
2186 /* Find out what happened if it failed. */
2187 switch (ioctl_errno) {
2188 case EINTR:
2189 case EBADF:
2190 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002191#ifdef FREEBSD
2192 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00002193#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002194 case ENOENT:
2195 droptcb(tcp);
2196 continue;
2197 default:
2198 perror("PIOCWSTOP");
2199 exit(1);
2200 }
2201 }
2202
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002203#ifdef FREEBSD
2204 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2205 /* discard first event for a syscall we never entered */
2206 IOCTL (tcp->pfd, PIOCRUN, 0);
2207 continue;
2208 }
Roland McGrath553a6092002-12-16 20:40:39 +00002209#endif
2210
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002211 /* clear the just started flag */
2212 tcp->flags &= ~TCB_STARTUP;
2213
2214 /* set current output file */
2215 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002216 curcol = tcp->curcol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002217
2218 if (cflag) {
2219 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002220#ifdef FREEBSD
2221 char buf[1024];
2222 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002223
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002224 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
2225 buf[len] = '\0';
2226 sscanf(buf,
2227 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2228 &stime.tv_sec, &stime.tv_usec);
2229 } else
2230 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002231#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002232 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2233 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002234#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002235 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2236 tcp->stime = stime;
2237 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002238 what = tcp->status.PR_WHAT;
2239 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002240#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002241 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002242 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2243 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002244 if (trace_syscall(tcp) < 0) {
2245 fprintf(stderr, "syscall trouble\n");
2246 exit(1);
2247 }
2248 }
2249 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002250#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002251 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002252#ifdef POLL_HACK
2253 in_syscall = tcp;
2254#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002255 case PR_SYSEXIT:
2256 if (trace_syscall(tcp) < 0) {
2257 fprintf(stderr, "syscall trouble\n");
2258 exit(1);
2259 }
2260 break;
2261 case PR_SIGNALLED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002262 if (cflag != CFLAG_ONLY_STATS
2263 && (qual_flags[what] & QUAL_SIGNAL)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002264 printleader(tcp);
2265 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002266 signame(what), strsignal(what));
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002267 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002268#ifdef PR_INFO
2269 if (tcp->status.PR_INFO.si_signo == what) {
2270 printleader(tcp);
2271 tprintf(" siginfo=");
2272 printsiginfo(&tcp->status.PR_INFO, 1);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002273 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002274 }
2275#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002276 }
2277 break;
2278 case PR_FAULTED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002279 if (cflag != CFLAGS_ONLY_STATS
2280 && (qual_flags[what] & QUAL_FAULT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002281 printleader(tcp);
2282 tprintf("=== FAULT %d ===", what);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002283 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002284 }
2285 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002286#ifdef FREEBSD
2287 case 0: /* handle case we polled for nothing */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002288 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00002289#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002290 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002291 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002292 exit(1);
2293 break;
2294 }
Andreas Schwabccdff482009-10-27 16:27:13 +01002295 /* Remember current print column before continuing. */
2296 tcp->curcol = curcol;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002297 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002298#ifndef FREEBSD
Andreas Schwab372cc842010-07-09 11:49:27 +02002299 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002300#else
Andreas Schwab372cc842010-07-09 11:49:27 +02002301 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002302#endif
Andreas Schwab372cc842010-07-09 11:49:27 +02002303 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002304 perror("PIOCRUN");
2305 exit(1);
2306 }
2307 }
2308 return 0;
2309}
2310
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002311#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002312
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002313#ifdef TCB_GROUP_EXITING
2314/* Handle an exit detach or death signal that is taking all the
2315 related clone threads with it. This is called in three circumstances:
2316 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
2317 SIG == 0 Continuing TCP will perform an exit_group syscall.
2318 SIG == other Continuing TCP with SIG will kill the process.
2319*/
2320static int
2321handle_group_exit(struct tcb *tcp, int sig)
2322{
2323 /* We need to locate our records of all the clone threads
2324 related to TCP, either its children or siblings. */
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002325 struct tcb *leader = NULL;
2326
2327 if (tcp->flags & TCB_CLONE_THREAD)
2328 leader = tcp->parent;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002329
2330 if (sig < 0) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002331 if (leader != NULL && leader != tcp
2332 && !(leader->flags & TCB_GROUP_EXITING)
2333 && !(tcp->flags & TCB_STARTUP)
2334 ) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002335 fprintf(stderr,
2336 "PANIC: handle_group_exit: %d leader %d\n",
2337 tcp->pid, leader ? leader->pid : -1);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002338 }
2339 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath1bfd3102007-08-03 10:02:00 +00002340#ifndef USE_PROCFS
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002341 resume_from_tcp(tcp);
Roland McGrath1bfd3102007-08-03 10:02:00 +00002342#endif
Roland McGrath0a463882007-07-05 18:43:16 +00002343 droptcb(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002344 }
2345 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00002346 /* Mark that we are taking the process down. */
2347 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002348 if (tcp->flags & TCB_ATTACHED) {
Roland McGrathd6a32f12007-07-11 08:35:11 +00002349 detach(tcp, sig);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002350 if (leader != NULL && leader != tcp)
Roland McGrath1bfd3102007-08-03 10:02:00 +00002351 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002352 } else {
2353 if (ptrace_restart(PTRACE_CONT, tcp, sig) < 0) {
2354 cleanup();
2355 return -1;
2356 }
2357 if (leader != NULL) {
Roland McGrath05690952004-10-20 01:00:27 +00002358 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002359 if (leader != tcp)
2360 droptcb(tcp);
2361 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002362 /* The leader will report to us as parent now,
2363 and then we'll get to the SIG==-1 case. */
2364 return 0;
2365 }
2366 }
2367
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002368 return 0;
2369}
2370#endif
2371
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002372#ifdef LINUX
2373static int
2374handle_ptrace_event(int status, struct tcb *tcp)
2375{
2376 if (status >> 16 == PTRACE_EVENT_VFORK ||
2377 status >> 16 == PTRACE_EVENT_CLONE ||
2378 status >> 16 == PTRACE_EVENT_FORK) {
Dmitry V. Levin2fabd0e2011-02-19 21:33:50 +00002379 long childpid;
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002380
2381 if (do_ptrace(PTRACE_GETEVENTMSG, tcp, NULL, &childpid) < 0) {
2382 if (errno != ESRCH) {
2383 fprintf(stderr, "\
2384%s: handle_ptrace_event: ptrace cannot get new child's pid\n",
2385 progname);
2386 cleanup();
2387 exit(1);
2388 }
2389 return -1;
2390 }
2391 return handle_new_child(tcp, childpid, 0);
2392 }
2393 return 1;
2394}
2395#endif
2396
Roland McGratheb9e2e82009-06-02 16:49:22 -07002397static int
2398trace()
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002399{
2400 int pid;
2401 int wait_errno;
2402 int status;
2403 struct tcb *tcp;
2404#ifdef LINUX
2405 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002406#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002407 static int wait4_options = __WALL;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002408#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002409#endif /* LINUX */
2410
Roland McGratheb9e2e82009-06-02 16:49:22 -07002411 while (nprocs != 0) {
Denys Vlasenko222713a2009-03-17 14:29:59 +00002412 if (interrupted)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002413 return 0;
2414 if (interactive)
2415 sigprocmask(SIG_SETMASK, &empty_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002416#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002417#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002418 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002419 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002420 /* this kernel does not support __WALL */
2421 wait4_options &= ~__WALL;
2422 errno = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002423 pid = wait4(-1, &status, wait4_options,
2424 cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002425 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002426 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002427 /* most likely a "cloned" process */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002428 pid = wait4(-1, &status, __WCLONE,
2429 cflag ? &ru : NULL);
2430 if (pid == -1) {
2431 fprintf(stderr, "strace: clone wait4 "
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002432 "failed: %s\n", strerror(errno));
2433 }
2434 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002435#else
2436 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
2437#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002438#endif /* LINUX */
2439#ifdef SUNOS4
2440 pid = wait(&status);
2441#endif /* SUNOS4 */
2442 wait_errno = errno;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002443 if (interactive)
2444 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002445
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002446 if (pid == -1) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002447 switch (wait_errno) {
2448 case EINTR:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002449 continue;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002450 case ECHILD:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002451 /*
2452 * We would like to verify this case
2453 * but sometimes a race in Solbourne's
2454 * version of SunOS sometimes reports
2455 * ECHILD before sending us SIGCHILD.
2456 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002457 return 0;
2458 default:
2459 errno = wait_errno;
2460 perror("strace: wait");
2461 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002462 }
2463 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002464 if (pid == popen_pid) {
2465 if (WIFEXITED(status) || WIFSIGNALED(status))
2466 popen_pid = -1;
2467 continue;
2468 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002469 if (debug)
2470 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2471
2472 /* Look up `pid' in our table. */
2473 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002474#ifdef LINUX
Roland McGrath41c48222008-07-18 00:25:10 +00002475 if (followfork) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002476 /* This is needed to go with the CLONE_PTRACE
2477 changes in process.c/util.c: we might see
2478 the child's initial trap before we see the
2479 parent return from the clone syscall.
2480 Leave the child suspended until the parent
2481 returns from its system call. Only then
2482 will we have the association of parent and
2483 child so that we know how to do clearbpt
2484 in the child. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +00002485 tcp = alloctcb(pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002486 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002487 if (!qflag)
2488 fprintf(stderr, "\
2489Process %d attached (waiting for parent)\n",
2490 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002491 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002492 else
2493 /* This can happen if a clone call used
2494 CLONE_PTRACE itself. */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002495#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002496 {
2497 fprintf(stderr, "unknown pid: %u\n", pid);
2498 if (WIFSTOPPED(status))
2499 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2500 exit(1);
2501 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002502 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002503 /* set current output file */
2504 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002505 curcol = tcp->curcol;
Denys Vlasenko84e20af2009-02-10 16:03:20 +00002506 if (cflag) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002507#ifdef LINUX
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002508 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2509 tcp->stime = ru.ru_stime;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002510#endif /* !LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002511 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002512
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002513 if (tcp->flags & TCB_SUSPENDED) {
2514 /*
2515 * Apparently, doing any ptrace() call on a stopped
2516 * process, provokes the kernel to report the process
2517 * status again on a subsequent wait(), even if the
2518 * process has not been actually restarted.
2519 * Since we have inspected the arguments of suspended
2520 * processes we end up here testing for this case.
2521 */
2522 continue;
2523 }
2524 if (WIFSIGNALED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002525 if (pid == strace_child)
2526 exit_code = 0x100 | WTERMSIG(status);
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002527 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002528 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2529 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002530 tprintf("+++ killed by %s %s+++",
2531 signame(WTERMSIG(status)),
2532#ifdef WCOREDUMP
2533 WCOREDUMP(status) ? "(core dumped) " :
2534#endif
2535 "");
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002536 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002537 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002538#ifdef TCB_GROUP_EXITING
2539 handle_group_exit(tcp, -1);
2540#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002541 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002542#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002543 continue;
2544 }
2545 if (WIFEXITED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002546 if (pid == strace_child)
2547 exit_code = WEXITSTATUS(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002548 if (debug)
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002549 fprintf(stderr, "pid %u exited with %d\n", pid, WEXITSTATUS(status));
2550 if ((tcp->flags & (TCB_ATTACHED|TCB_STARTUP)) == TCB_ATTACHED
Roland McGrath05690952004-10-20 01:00:27 +00002551#ifdef TCB_GROUP_EXITING
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002552 && !(tcp->parent && (tcp->parent->flags & TCB_GROUP_EXITING))
Roland McGrath1bfd3102007-08-03 10:02:00 +00002553 && !(tcp->flags & TCB_GROUP_EXITING)
Roland McGrath05690952004-10-20 01:00:27 +00002554#endif
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002555 ) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002556 fprintf(stderr,
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002557 "PANIC: attached pid %u exited with %d\n",
2558 pid, WEXITSTATUS(status));
2559 }
Roland McGrath0a396902003-06-10 03:05:53 +00002560 if (tcp == tcp_last) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002561 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT)) == TCB_INSYSCALL)
Roland McGrath0a396902003-06-10 03:05:53 +00002562 tprintf(" <unfinished ... exit status %d>\n",
2563 WEXITSTATUS(status));
2564 tcp_last = NULL;
2565 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002566#ifdef TCB_GROUP_EXITING
2567 handle_group_exit(tcp, -1);
2568#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002569 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002570#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002571 continue;
2572 }
2573 if (!WIFSTOPPED(status)) {
2574 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2575 droptcb(tcp);
2576 continue;
2577 }
2578 if (debug)
2579 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002580 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002581
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002582 if (ptrace_setoptions && (status >> 16)) {
2583 if (handle_ptrace_event(status, tcp) != 1)
2584 goto tracing;
2585 }
2586
Roland McGrath02203312007-06-11 22:06:31 +00002587 /*
2588 * Interestingly, the process may stop
2589 * with STOPSIG equal to some other signal
Roland McGratheb9e2e82009-06-02 16:49:22 -07002590 * than SIGSTOP if we happend to attach
Roland McGrath02203312007-06-11 22:06:31 +00002591 * just before the process takes a signal.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002592 * A no-MMU vforked child won't send up a signal,
2593 * so skip the first (lost) execve notification.
Roland McGrath02203312007-06-11 22:06:31 +00002594 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002595 if ((tcp->flags & TCB_STARTUP) &&
2596 (WSTOPSIG(status) == SIGSTOP || strace_vforked)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002597 /*
2598 * This flag is there to keep us in sync.
2599 * Next time this process stops it should
2600 * really be entering a system call.
2601 */
2602 tcp->flags &= ~TCB_STARTUP;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002603 if (tcp->flags & TCB_BPTSET) {
Roland McGrath02203312007-06-11 22:06:31 +00002604 /*
2605 * One example is a breakpoint inherited from
2606 * parent through fork ().
2607 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002608 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2609 droptcb(tcp);
2610 cleanup();
2611 return -1;
2612 }
2613 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002614#ifdef LINUX
2615 if (followfork && (tcp->parent == NULL) && ptrace_setoptions)
2616 if (ptrace(PTRACE_SETOPTIONS, tcp->pid,
2617 NULL, ptrace_setoptions) < 0 &&
2618 errno != ESRCH)
2619 ptrace_setoptions = 0;
2620#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002621 goto tracing;
2622 }
2623
Roland McGratheb9e2e82009-06-02 16:49:22 -07002624 if (WSTOPSIG(status) != SIGTRAP) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002625 if (WSTOPSIG(status) == SIGSTOP &&
2626 (tcp->flags & TCB_SIGTRAPPED)) {
2627 /*
2628 * Trapped attempt to block SIGTRAP
2629 * Hope we are back in control now.
2630 */
2631 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002632 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002633 cleanup();
2634 return -1;
2635 }
2636 continue;
2637 }
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002638 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002639 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00002640 unsigned long addr = 0;
2641 long pc = 0;
Dmitry V. Levinc15dfc72011-03-10 14:44:45 +00002642 siginfo_t si;
2643#if defined(PT_CR_IPSR) && defined(PT_CR_IIP)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002644# define PSR_RI 41
Jan Kratochvil1f942712008-08-06 21:38:52 +00002645 long psr;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002646
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002647 upeek(tcp, PT_CR_IPSR, &psr);
2648 upeek(tcp, PT_CR_IIP, &pc);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002649
2650 pc += (psr >> PSR_RI) & 0x3;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002651#endif
Dmitry V. Levinc15dfc72011-03-10 14:44:45 +00002652 si.si_addr = NULL;
2653 if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0)
2654 addr = (unsigned long) si.si_addr;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002655 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002656 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002657 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002658 strsignal(WSTOPSIG(status)), pc, addr);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002659 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002660 }
Roland McGrath05690952004-10-20 01:00:27 +00002661 if (((tcp->flags & TCB_ATTACHED) ||
2662 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002663 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002664#ifdef TCB_GROUP_EXITING
2665 handle_group_exit(tcp, WSTOPSIG(status));
2666#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002667 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002668#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002669 continue;
2670 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002671 if (ptrace_restart(PTRACE_SYSCALL, tcp, WSTOPSIG(status)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002672 cleanup();
2673 return -1;
2674 }
2675 tcp->flags &= ~TCB_SUSPENDED;
2676 continue;
2677 }
Roland McGrath02203312007-06-11 22:06:31 +00002678 /* we handled the STATUS, we are permitted to interrupt now. */
2679 if (interrupted)
2680 return 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002681 if (trace_syscall(tcp) < 0 && !tcp->ptrace_errno) {
2682 /* ptrace() failed in trace_syscall() with ESRCH.
2683 * Likely a result of process disappearing mid-flight.
2684 * Observed case: exit_group() terminating
2685 * all processes in thread group. In this case, threads
2686 * "disappear" in an unpredictable moment without any
2687 * notification to strace via wait().
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002688 */
2689 if (tcp->flags & TCB_ATTACHED) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002690 if (tcp_last) {
2691 /* Do we have dangling line "syscall(param, param"?
2692 * Finish the line then. We cannot
2693 */
2694 tcp_last->flags |= TCB_REPRINT;
2695 tprintf(" <unfinished ...>");
2696 printtrailer();
2697 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002698 detach(tcp, 0);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002699 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002700 ptrace(PTRACE_KILL,
2701 tcp->pid, (char *) 1, SIGTERM);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002702 droptcb(tcp);
2703 }
2704 continue;
2705 }
2706 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002707#ifdef TCB_GROUP_EXITING
2708 if (tcp->flags & TCB_GROUP_EXITING) {
2709 if (handle_group_exit(tcp, 0) < 0)
2710 return -1;
2711 continue;
2712 }
2713#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002714 if (tcp->flags & TCB_ATTACHED)
2715 detach(tcp, 0);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002716 else if (ptrace_restart(PTRACE_CONT, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002717 cleanup();
2718 return -1;
2719 }
2720 continue;
2721 }
2722 if (tcp->flags & TCB_SUSPENDED) {
2723 if (!qflag)
2724 fprintf(stderr, "Process %u suspended\n", pid);
2725 continue;
2726 }
2727 tracing:
Andreas Schwabccdff482009-10-27 16:27:13 +01002728 /* Remember current print column before continuing. */
2729 tcp->curcol = curcol;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002730 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002731 cleanup();
2732 return -1;
2733 }
2734 }
2735 return 0;
2736}
2737
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002738#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002739
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002740#include <stdarg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002741
2742void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002743tprintf(const char *fmt, ...)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002744{
2745 va_list args;
2746
Andreas Schwabe5355de2009-10-27 16:56:43 +01002747 va_start(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002748 if (outf) {
2749 int n = vfprintf(outf, fmt, args);
Andreas Schwabccdff482009-10-27 16:27:13 +01002750 if (n < 0) {
2751 if (outf != stderr)
2752 perror(outfname == NULL
2753 ? "<writing to pipe>" : outfname);
2754 } else
Roland McGrathb310a0c2003-11-06 23:41:22 +00002755 curcol += n;
2756 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002757 va_end(args);
2758 return;
2759}
2760
2761void
Roland McGratheb9e2e82009-06-02 16:49:22 -07002762printleader(tcp)
2763struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002764{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002765 if (tcp_last) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002766 if (tcp_last->ptrace_errno) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002767 if (tcp_last->flags & TCB_INSYSCALL) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002768 tprintf(" <unavailable>)");
2769 tabto(acolumn);
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002770 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002771 tprintf("= ? <unavailable>\n");
2772 tcp_last->ptrace_errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002773 } else if (!outfname || followfork < 2 || tcp_last == tcp) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002774 tcp_last->flags |= TCB_REPRINT;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002775 tprintf(" <unfinished ...>\n");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002776 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002777 }
2778 curcol = 0;
2779 if ((followfork == 1 || pflag_seen > 1) && outfname)
2780 tprintf("%-5d ", tcp->pid);
2781 else if (nprocs > 1 && !outfname)
2782 tprintf("[pid %5u] ", tcp->pid);
2783 if (tflag) {
2784 char str[sizeof("HH:MM:SS")];
2785 struct timeval tv, dtv;
2786 static struct timeval otv;
2787
2788 gettimeofday(&tv, NULL);
2789 if (rflag) {
2790 if (otv.tv_sec == 0)
2791 otv = tv;
2792 tv_sub(&dtv, &tv, &otv);
2793 tprintf("%6ld.%06ld ",
2794 (long) dtv.tv_sec, (long) dtv.tv_usec);
2795 otv = tv;
2796 }
2797 else if (tflag > 2) {
2798 tprintf("%ld.%06ld ",
2799 (long) tv.tv_sec, (long) tv.tv_usec);
2800 }
2801 else {
2802 time_t local = tv.tv_sec;
2803 strftime(str, sizeof(str), "%T", localtime(&local));
2804 if (tflag > 1)
2805 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2806 else
2807 tprintf("%s ", str);
2808 }
2809 }
2810 if (iflag)
2811 printcall(tcp);
2812}
2813
2814void
2815tabto(col)
2816int col;
2817{
2818 if (curcol < col)
2819 tprintf("%*s", col - curcol, "");
2820}
2821
2822void
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002823printtrailer(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002824{
2825 tprintf("\n");
2826 tcp_last = NULL;
2827}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002828
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002829#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002830
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002831int
2832mp_ioctl(int fd, int cmd, void *arg, int size)
2833{
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002834 struct iovec iov[2];
2835 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002836
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002837 iov[0].iov_base = &cmd;
2838 iov[0].iov_len = sizeof cmd;
2839 if (arg) {
2840 ++n;
2841 iov[1].iov_base = arg;
2842 iov[1].iov_len = size;
2843 }
Roland McGrath553a6092002-12-16 20:40:39 +00002844
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002845 return writev(fd, iov, n);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002846}
2847
2848#endif