blob: 6b0ebacf79e75b3866caf351e83af5ba92478a64 [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{
699 int pid;
700
701 if ((pid = fork()) < 0)
702 return -1;
703 else if (pid == 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000704 if (ptrace(PTRACE_TRACEME, 0, (char *)1, 0) < 0)
Wang Chaob13c0de2010-11-12 17:25:19 +0800705 _exit(1);
Wang Chaob13c0de2010-11-12 17:25:19 +0800706 kill(getpid(), SIGSTOP);
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000707 _exit(fork() < 0);
Wang Chaob13c0de2010-11-12 17:25:19 +0800708 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000709
710 while (1) {
711 int status, tracee_pid;
712
713 tracee_pid = wait(&status);
714 if (tracee_pid == -1) {
715 if (errno == EINTR)
716 continue;
717 else if (errno == ECHILD)
718 break;
719 perror("test_ptrace_setoptions");
720 return -1;
721 }
722 if (tracee_pid != pid) {
723 /* the grandchild */
724 if (ptrace(PTRACE_CONT, tracee_pid, 0, 0) < 0 &&
725 errno != ESRCH)
726 kill(tracee_pid, SIGKILL);
727 }
728 else if (WIFSTOPPED(status)) {
Dmitry V. Levin21ccf5e2011-01-13 14:49:39 +0000729 const unsigned int test_options = PTRACE_O_TRACECLONE |
730 PTRACE_O_TRACEFORK |
731 PTRACE_O_TRACEVFORK;
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000732 if (status >> 16 == PTRACE_EVENT_FORK)
Dmitry V. Levin21ccf5e2011-01-13 14:49:39 +0000733 ptrace_setoptions |= test_options;
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000734 if (WSTOPSIG(status) == SIGSTOP) {
735 if (ptrace(PTRACE_SETOPTIONS, pid, NULL,
Dmitry V. Levin21ccf5e2011-01-13 14:49:39 +0000736 test_options) < 0) {
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000737 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800738 return -1;
739 }
740 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000741 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0 &&
742 errno != ESRCH)
743 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800744 }
745 }
746 return 0;
747}
748#endif
749
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000750int
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000751main(int argc, char *argv[])
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000752{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000753 struct tcb *tcp;
754 int c, pid = 0;
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000755 int optF = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000756 struct sigaction sa;
757
758 static char buf[BUFSIZ];
759
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000760 progname = argv[0] ? argv[0] : "strace";
761
Roland McGrathee9d4352002-12-18 04:16:10 +0000762 /* Allocate the initial tcbtab. */
763 tcbtabsize = argc; /* Surely enough for all -p args. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000764 if ((tcbtab = calloc(tcbtabsize, sizeof tcbtab[0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000765 fprintf(stderr, "%s: out of memory\n", progname);
766 exit(1);
767 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000768 if ((tcbtab[0] = calloc(tcbtabsize, sizeof tcbtab[0][0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000769 fprintf(stderr, "%s: out of memory\n", progname);
770 exit(1);
771 }
Roland McGrathee9d4352002-12-18 04:16:10 +0000772 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
773 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
774
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000775 outf = stderr;
776 interactive = 1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000777 set_sortby(DEFAULT_SORTBY);
778 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000779 qualify("trace=all");
780 qualify("abbrev=all");
781 qualify("verbose=all");
782 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000783 while ((c = getopt(argc, argv,
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000784 "+cCdfFhiqrtTvVxz"
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000785#ifndef USE_PROCFS
786 "D"
787#endif
788 "a:e:o:O:p:s:S:u:E:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000789 switch (c) {
790 case 'c':
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000791 if (cflag == CFLAG_BOTH) {
792 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
793 progname);
794 exit(1);
795 }
796 cflag = CFLAG_ONLY_STATS;
797 break;
798 case 'C':
799 if (cflag == CFLAG_ONLY_STATS) {
800 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
801 progname);
802 exit(1);
803 }
804 cflag = CFLAG_BOTH;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000805 break;
806 case 'd':
807 debug++;
808 break;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000809#ifndef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000810 case 'D':
811 daemonized_tracer = 1;
812 break;
813#endif
Roland McGrath41c48222008-07-18 00:25:10 +0000814 case 'F':
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000815 optF = 1;
816 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000817 case 'f':
818 followfork++;
819 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000820 case 'h':
821 usage(stdout, 0);
822 break;
823 case 'i':
824 iflag++;
825 break;
826 case 'q':
827 qflag++;
828 break;
829 case 'r':
830 rflag++;
831 tflag++;
832 break;
833 case 't':
834 tflag++;
835 break;
836 case 'T':
837 dtime++;
838 break;
839 case 'x':
840 xflag++;
841 break;
842 case 'v':
843 qualify("abbrev=none");
844 break;
845 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +0000846 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000847 exit(0);
848 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000849 case 'z':
850 not_failing_only = 1;
851 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000852 case 'a':
853 acolumn = atoi(optarg);
854 break;
855 case 'e':
856 qualify(optarg);
857 break;
858 case 'o':
859 outfname = strdup(optarg);
860 break;
861 case 'O':
862 set_overhead(atoi(optarg));
863 break;
864 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +0000865 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000866 fprintf(stderr, "%s: Invalid process id: %s\n",
867 progname, optarg);
868 break;
869 }
870 if (pid == getpid()) {
Wichert Akkerman54a47671999-10-17 00:57:34 +0000871 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000872 break;
873 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000874 tcp = alloc_tcb(pid, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000875 tcp->flags |= TCB_ATTACHED;
876 pflag_seen++;
877 break;
878 case 's':
879 max_strlen = atoi(optarg);
Roland McGrathdccec722005-05-09 07:45:47 +0000880 if (max_strlen < 0) {
881 fprintf(stderr,
882 "%s: invalid -s argument: %s\n",
883 progname, optarg);
884 exit(1);
885 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000886 break;
887 case 'S':
888 set_sortby(optarg);
889 break;
890 case 'u':
891 username = strdup(optarg);
892 break;
Roland McGrathde6e5332003-01-24 04:31:23 +0000893 case 'E':
894 if (putenv(optarg) < 0) {
895 fprintf(stderr, "%s: out of memory\n",
896 progname);
897 exit(1);
898 }
899 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000900 default:
901 usage(stderr, 1);
902 break;
903 }
904 }
905
Roland McGrathd0c4c0c2006-04-25 07:39:40 +0000906 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +0000907 usage(stderr, 1);
908
Wang Chaod322a4b2010-08-05 14:30:11 +0800909 if (pflag_seen && daemonized_tracer) {
910 fprintf(stderr,
911 "%s: -D and -p are mutually exclusive options\n",
912 progname);
913 exit(1);
914 }
915
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000916 if (!followfork)
917 followfork = optF;
918
Roland McGrathcb9def62006-04-25 07:48:03 +0000919 if (followfork > 1 && cflag) {
920 fprintf(stderr,
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000921 "%s: (-c or -C) and -ff are mutually exclusive options\n",
Roland McGrathcb9def62006-04-25 07:48:03 +0000922 progname);
923 exit(1);
924 }
925
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000926 /* See if they want to run as another user. */
927 if (username != NULL) {
928 struct passwd *pent;
929
930 if (getuid() != 0 || geteuid() != 0) {
931 fprintf(stderr,
932 "%s: you must be root to use the -u option\n",
933 progname);
934 exit(1);
935 }
936 if ((pent = getpwnam(username)) == NULL) {
937 fprintf(stderr, "%s: cannot find user `%s'\n",
Roland McGrath09553f82007-07-05 19:31:49 +0000938 progname, username);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000939 exit(1);
940 }
941 run_uid = pent->pw_uid;
942 run_gid = pent->pw_gid;
943 }
944 else {
945 run_uid = getuid();
946 run_gid = getgid();
947 }
948
Dmitry V. Levin8044bc12010-12-07 12:50:49 +0000949#ifdef LINUX
950 if (followfork) {
951 if (test_ptrace_setoptions() < 0) {
952 fprintf(stderr,
953 "Test for options supported by PTRACE_SETOPTIONS "
954 "failed, giving up using this feature.\n");
955 ptrace_setoptions = 0;
956 }
957 if (debug)
958 fprintf(stderr, "ptrace_setoptions = %#x\n",
959 ptrace_setoptions);
960 }
961#endif
962
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000963 /* Check if they want to redirect the output. */
964 if (outfname) {
Roland McGrath37b9a662003-11-07 02:26:54 +0000965 /* See if they want to pipe the output. */
966 if (outfname[0] == '|' || outfname[0] == '!') {
967 /*
968 * We can't do the <outfname>.PID funny business
969 * when using popen, so prohibit it.
970 */
971 if (followfork > 1) {
972 fprintf(stderr, "\
973%s: piping the output and -ff are mutually exclusive options\n",
974 progname);
975 exit(1);
976 }
977
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000978 if ((outf = strace_popen(outfname + 1)) == NULL)
Roland McGrath37b9a662003-11-07 02:26:54 +0000979 exit(1);
Roland McGrath37b9a662003-11-07 02:26:54 +0000980 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000981 else if (followfork <= 1 &&
982 (outf = strace_fopen(outfname, "w")) == NULL)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000983 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000984 }
985
Roland McGrath37b9a662003-11-07 02:26:54 +0000986 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000987 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +0000988 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000989 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000990 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +0000991 }
Wang Chaob13c0de2010-11-12 17:25:19 +0800992
Roland McGrath54cc1c82007-11-03 23:34:11 +0000993 /* Valid states here:
994 optind < argc pflag_seen outfname interactive
995 1 0 0 1
996 0 1 0 1
997 1 0 1 0
998 0 1 1 1
999 */
1000
1001 /* STARTUP_CHILD must be called before the signal handlers get
1002 installed below as they are inherited into the spawned process.
1003 Also we do not need to be protected by them as during interruption
1004 in the STARTUP_CHILD mode we kill the spawned process anyway. */
1005 if (!pflag_seen)
1006 startup_child(&argv[optind]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001007
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001008 sigemptyset(&empty_set);
1009 sigemptyset(&blocked_set);
1010 sa.sa_handler = SIG_IGN;
1011 sigemptyset(&sa.sa_mask);
1012 sa.sa_flags = 0;
1013 sigaction(SIGTTOU, &sa, NULL);
1014 sigaction(SIGTTIN, &sa, NULL);
1015 if (interactive) {
1016 sigaddset(&blocked_set, SIGHUP);
1017 sigaddset(&blocked_set, SIGINT);
1018 sigaddset(&blocked_set, SIGQUIT);
1019 sigaddset(&blocked_set, SIGPIPE);
1020 sigaddset(&blocked_set, SIGTERM);
1021 sa.sa_handler = interrupt;
1022#ifdef SUNOS4
1023 /* POSIX signals on sunos4.1 are a little broken. */
1024 sa.sa_flags = SA_INTERRUPT;
1025#endif /* SUNOS4 */
1026 }
1027 sigaction(SIGHUP, &sa, NULL);
1028 sigaction(SIGINT, &sa, NULL);
1029 sigaction(SIGQUIT, &sa, NULL);
1030 sigaction(SIGPIPE, &sa, NULL);
1031 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001032#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001033 sa.sa_handler = reaper;
1034 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +00001035#else
1036 /* Make sure SIGCHLD has the default action so that waitpid
1037 definitely works without losing track of children. The user
1038 should not have given us a bogus state to inherit, but he might
1039 have. Arguably we should detect SIG_IGN here and pass it on
1040 to children, but probably noone really needs that. */
1041 sa.sa_handler = SIG_DFL;
1042 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001043#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001044
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +00001045 if (pflag_seen || daemonized_tracer)
Roland McGrath02203312007-06-11 22:06:31 +00001046 startup_attach();
Roland McGrath02203312007-06-11 22:06:31 +00001047
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001048 if (trace() < 0)
1049 exit(1);
1050 cleanup();
Dmitry V. Levina6809652008-11-10 17:14:58 +00001051 fflush(NULL);
1052 if (exit_code > 0xff) {
1053 /* Child was killed by a signal, mimic that. */
1054 exit_code &= 0xff;
1055 signal(exit_code, SIG_DFL);
1056 raise(exit_code);
1057 /* Paranoia - what if this signal is not fatal?
1058 Exit with 128 + signo then. */
1059 exit_code += 128;
1060 }
1061 exit(exit_code);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001062}
1063
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001064void
1065expand_tcbtab(void)
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001066{
1067 /* Allocate some more TCBs and expand the table.
1068 We don't want to relocate the TCBs because our
1069 callers have pointers and it would be a pain.
1070 So tcbtab is a table of pointers. Since we never
1071 free the TCBs, we allocate a single chunk of many. */
1072 struct tcb **newtab = (struct tcb **)
1073 realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
1074 struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
1075 sizeof *newtcbs);
1076 int i;
1077 if (newtab == NULL || newtcbs == NULL) {
Dmitry V. Levin76860f62006-10-11 22:55:25 +00001078 fprintf(stderr, "%s: expand_tcbtab: out of memory\n",
1079 progname);
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001080 cleanup();
1081 exit(1);
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001082 }
1083 for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
1084 newtab[i] = &newtcbs[i - tcbtabsize];
1085 tcbtabsize *= 2;
1086 tcbtab = newtab;
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001087}
1088
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001089struct tcb *
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001090alloc_tcb(int pid, int command_options_parsed)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001091{
1092 int i;
1093 struct tcb *tcp;
1094
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001095 if (nprocs == tcbtabsize)
1096 expand_tcbtab();
1097
Roland McGrathee9d4352002-12-18 04:16:10 +00001098 for (i = 0; i < tcbtabsize; i++) {
1099 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001100 if ((tcp->flags & TCB_INUSE) == 0) {
1101 tcp->pid = pid;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001102 tcp->parent = NULL;
1103 tcp->nchildren = 0;
1104 tcp->nzombies = 0;
1105#ifdef TCB_CLONE_THREAD
Wang Chao21b8db42010-08-27 17:43:16 +08001106 tcp->nclone_threads = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001107 tcp->nclone_waiting = 0;
1108#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001109 tcp->flags = TCB_INUSE | TCB_STARTUP;
1110 tcp->outf = outf; /* Initialise to current out file */
Andreas Schwabccdff482009-10-27 16:27:13 +01001111 tcp->curcol = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001112 tcp->stime.tv_sec = 0;
1113 tcp->stime.tv_usec = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001114 tcp->pfd = -1;
1115 nprocs++;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001116 if (command_options_parsed)
1117 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001118 return tcp;
1119 }
1120 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001121 fprintf(stderr, "%s: bug in alloc_tcb\n", progname);
1122 cleanup();
1123 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001124}
1125
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001126#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001127int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001128proc_open(struct tcb *tcp, int attaching)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001129{
1130 char proc[32];
1131 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001132#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +00001133 int i;
1134 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001135 sigset_t signals;
1136 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001137#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001138#ifndef HAVE_POLLABLE_PROCFS
1139 static int last_pfd;
1140#endif
1141
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001142#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001143 /* Open the process pseudo-files in /proc. */
1144 sprintf(proc, "/proc/%d/ctl", tcp->pid);
1145 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001146 perror("strace: open(\"/proc/...\", ...)");
1147 return -1;
1148 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001149 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001150 return -1;
1151 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001152 sprintf(proc, "/proc/%d/status", tcp->pid);
1153 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
1154 perror("strace: open(\"/proc/...\", ...)");
1155 return -1;
1156 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001157 if (set_cloexec_flag(tcp->pfd_stat) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001158 return -1;
1159 }
1160 sprintf(proc, "/proc/%d/as", tcp->pid);
1161 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
1162 perror("strace: open(\"/proc/...\", ...)");
1163 return -1;
1164 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001165 if (set_cloexec_flag(tcp->pfd_as) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001166 return -1;
1167 }
1168#else
1169 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001170#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001171 sprintf(proc, "/proc/%d", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001172 tcp->pfd = open(proc, O_RDWR|O_EXCL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001173#else /* FREEBSD */
1174 sprintf(proc, "/proc/%d/mem", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001175 tcp->pfd = open(proc, O_RDWR);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001176#endif /* FREEBSD */
Andreas Schwab372cc842010-07-09 11:49:27 +02001177 if (tcp->pfd < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001178 perror("strace: open(\"/proc/...\", ...)");
1179 return -1;
1180 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001181 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001182 return -1;
1183 }
1184#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001185#ifdef FREEBSD
1186 sprintf(proc, "/proc/%d/regs", tcp->pid);
1187 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
1188 perror("strace: open(\"/proc/.../regs\", ...)");
1189 return -1;
1190 }
1191 if (cflag) {
1192 sprintf(proc, "/proc/%d/status", tcp->pid);
1193 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
1194 perror("strace: open(\"/proc/.../status\", ...)");
1195 return -1;
1196 }
1197 } else
1198 tcp->pfd_status = -1;
1199#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001200 rebuild_pollv();
1201 if (!attaching) {
1202 /*
1203 * Wait for the child to pause. Because of a race
1204 * condition we have to poll for the event.
1205 */
1206 for (;;) {
1207 if (IOCTL_STATUS (tcp) < 0) {
1208 perror("strace: PIOCSTATUS");
1209 return -1;
1210 }
1211 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001212 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001213 }
1214 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001215#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001216 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001217 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001218 perror("strace: PIOCSTOP");
1219 return -1;
1220 }
Roland McGrath553a6092002-12-16 20:40:39 +00001221#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001222#ifdef PIOCSET
1223 /* Set Run-on-Last-Close. */
1224 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001225 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001226 perror("PIOCSET PR_RLC");
1227 return -1;
1228 }
1229 /* Set or Reset Inherit-on-Fork. */
1230 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001231 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001232 perror("PIOC{SET,RESET} PR_FORK");
1233 return -1;
1234 }
1235#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +00001236#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001237 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
1238 perror("PIOCSRLC");
1239 return -1;
1240 }
1241 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
1242 perror("PIOC{S,R}FORK");
1243 return -1;
1244 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001245#else /* FREEBSD */
1246 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
1247 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
1248 perror("PIOCGFL");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001249 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001250 }
1251 arg &= ~PF_LINGER;
1252 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001253 perror("PIOCSFL");
1254 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001255 }
1256#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001257#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001258#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +00001259 /* Enable all syscall entries we care about. */
1260 premptyset(&syscalls);
1261 for (i = 1; i < MAX_QUALS; ++i) {
1262 if (i > (sizeof syscalls) * CHAR_BIT) break;
1263 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
1264 }
1265 praddset (&syscalls, SYS_execve);
1266 if (followfork) {
1267 praddset (&syscalls, SYS_fork);
1268#ifdef SYS_forkall
1269 praddset (&syscalls, SYS_forkall);
1270#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001271#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +00001272 praddset (&syscalls, SYS_fork1);
1273#endif
1274#ifdef SYS_rfork1
1275 praddset (&syscalls, SYS_rfork1);
1276#endif
1277#ifdef SYS_rforkall
1278 praddset (&syscalls, SYS_rforkall);
1279#endif
1280 }
1281 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001282 perror("PIOCSENTRY");
1283 return -1;
1284 }
John Hughes19e49982001-10-19 08:59:12 +00001285 /* Enable the syscall exits. */
1286 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001287 perror("PIOSEXIT");
1288 return -1;
1289 }
John Hughes19e49982001-10-19 08:59:12 +00001290 /* Enable signals we care about. */
1291 premptyset(&signals);
1292 for (i = 1; i < MAX_QUALS; ++i) {
1293 if (i > (sizeof signals) * CHAR_BIT) break;
1294 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
1295 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001296 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001297 perror("PIOCSTRACE");
1298 return -1;
1299 }
John Hughes19e49982001-10-19 08:59:12 +00001300 /* Enable faults we care about */
1301 premptyset(&faults);
1302 for (i = 1; i < MAX_QUALS; ++i) {
1303 if (i > (sizeof faults) * CHAR_BIT) break;
1304 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
1305 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001306 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001307 perror("PIOCSFAULT");
1308 return -1;
1309 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001310#else /* FREEBSD */
1311 /* set events flags. */
1312 arg = S_SIG | S_SCE | S_SCX ;
1313 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
1314 perror("PIOCBIS");
1315 return -1;
1316 }
1317#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001318 if (!attaching) {
1319#ifdef MIPS
1320 /*
1321 * The SGI PRSABORT doesn't work for pause() so
1322 * we send it a caught signal to wake it up.
1323 */
1324 kill(tcp->pid, SIGINT);
1325#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +00001326#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001327 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001328 arg = PRSABORT;
1329 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001330 perror("PIOCRUN");
1331 return -1;
1332 }
Roland McGrath553a6092002-12-16 20:40:39 +00001333#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001334#endif /* !MIPS*/
1335#ifdef FREEBSD
1336 /* wake up the child if it received the SIGSTOP */
1337 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001338#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001339 for (;;) {
1340 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001341 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001342 perror("PIOCWSTOP");
1343 return -1;
1344 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001345 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001346 tcp->flags &= ~TCB_INSYSCALL;
1347 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001348 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001349 break;
1350 }
1351 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001352#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001353 arg = 0;
1354 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001355#else /* FREEBSD */
1356 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001357#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001358 perror("PIOCRUN");
1359 return -1;
1360 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001361#ifdef FREEBSD
1362 /* handle the case where we "opened" the child before
1363 it did the kill -STOP */
1364 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1365 tcp->status.PR_WHAT == SIGSTOP)
1366 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001367#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001368 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001369#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001370 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001371#else /* FREEBSD */
1372 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001373 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001374 /* We are attaching to an already running process.
1375 * Try to figure out the state of the process in syscalls,
1376 * to handle the first event well.
1377 * This is done by having a look at the "wchan" property of the
1378 * process, which tells where it is stopped (if it is). */
1379 FILE * status;
1380 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001381
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001382 sprintf(proc, "/proc/%d/status", tcp->pid);
1383 status = fopen(proc, "r");
1384 if (status &&
1385 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1386 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1387 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1388 strcmp(wchan, "stopevent")) {
1389 /* The process is asleep in the middle of a syscall.
1390 Fake the syscall entry event */
1391 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1392 tcp->status.PR_WHY = PR_SYSENTRY;
1393 trace_syscall(tcp);
1394 }
1395 if (status)
1396 fclose(status);
1397 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001398 }
1399#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001400#ifndef HAVE_POLLABLE_PROCFS
1401 if (proc_poll_pipe[0] != -1)
1402 proc_poller(tcp->pfd);
1403 else if (nprocs > 1) {
1404 proc_poll_open();
1405 proc_poller(last_pfd);
1406 proc_poller(tcp->pfd);
1407 }
1408 last_pfd = tcp->pfd;
1409#endif /* !HAVE_POLLABLE_PROCFS */
1410 return 0;
1411}
1412
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001413#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001414
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001415struct tcb *
Roland McGrath54e931f2010-09-14 18:59:20 -07001416pid2tcb(int pid)
1417{
1418 int i;
1419
1420 if (pid <= 0)
1421 return NULL;
1422
1423 for (i = 0; i < tcbtabsize; i++) {
1424 struct tcb *tcp = tcbtab[i];
1425 if (tcp->pid == pid && (tcp->flags & TCB_INUSE))
1426 return tcp;
1427 }
1428
1429 return NULL;
1430}
1431
1432#ifdef USE_PROCFS
1433
1434static struct tcb *
1435first_used_tcb(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001436{
1437 int i;
1438 struct tcb *tcp;
Roland McGrathee9d4352002-12-18 04:16:10 +00001439 for (i = 0; i < tcbtabsize; i++) {
1440 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001441 if (tcp->flags & TCB_INUSE)
1442 return tcp;
1443 }
1444 return NULL;
1445}
1446
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001447static struct tcb *
1448pfd2tcb(pfd)
1449int pfd;
1450{
1451 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001452
Roland McGrathca16be82003-01-10 19:55:28 +00001453 for (i = 0; i < tcbtabsize; i++) {
1454 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001455 if (tcp->pfd != pfd)
1456 continue;
1457 if (tcp->flags & TCB_INUSE)
1458 return tcp;
1459 }
1460 return NULL;
1461}
1462
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001463#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001464
1465void
1466droptcb(tcp)
1467struct tcb *tcp;
1468{
1469 if (tcp->pid == 0)
1470 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001471#ifdef TCB_CLONE_THREAD
1472 if (tcp->nclone_threads > 0) {
1473 /* There are other threads left in this process, but this
1474 is the one whose PID represents the whole process.
1475 We need to keep this record around as a zombie until
1476 all the threads die. */
1477 tcp->flags |= TCB_EXITING;
1478 return;
1479 }
1480#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001481 nprocs--;
1482 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001483
Roland McGrathe29341c2003-01-10 20:14:20 +00001484 if (tcp->parent != NULL) {
1485 tcp->parent->nchildren--;
1486#ifdef TCB_CLONE_THREAD
Roland McGrathe29341c2003-01-10 20:14:20 +00001487 if (tcp->flags & TCB_CLONE_THREAD)
1488 tcp->parent->nclone_threads--;
1489#endif
Wang Chao21b8db42010-08-27 17:43:16 +08001490 tcp->parent->nzombies++;
Roland McGrath276ceb32007-11-13 08:12:12 +00001491#ifdef LINUX
1492 /* Update `tcp->parent->parent->nchildren' and the other fields
1493 like NCLONE_DETACHED, only for zombie group leader that has
1494 already reported and been short-circuited at the top of this
1495 function. The same condition as at the top of DETACH. */
1496 if ((tcp->flags & TCB_CLONE_THREAD) &&
1497 tcp->parent->nclone_threads == 0 &&
1498 (tcp->parent->flags & TCB_EXITING))
1499 droptcb(tcp->parent);
1500#endif
Roland McGrathe29341c2003-01-10 20:14:20 +00001501 tcp->parent = NULL;
1502 }
1503
1504 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001505 if (tcp->pfd != -1) {
1506 close(tcp->pfd);
1507 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001508#ifdef FREEBSD
1509 if (tcp->pfd_reg != -1) {
1510 close(tcp->pfd_reg);
1511 tcp->pfd_reg = -1;
1512 }
1513 if (tcp->pfd_status != -1) {
1514 close(tcp->pfd_status);
1515 tcp->pfd_status = -1;
1516 }
Roland McGrath553a6092002-12-16 20:40:39 +00001517#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001518#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001519 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001520#endif
1521 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001522
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001523 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001524 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001525
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001526 tcp->outf = 0;
1527}
1528
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001529#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001530
1531static int
1532resume(tcp)
1533struct tcb *tcp;
1534{
1535 if (tcp == NULL)
1536 return -1;
1537
1538 if (!(tcp->flags & TCB_SUSPENDED)) {
1539 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1540 return -1;
1541 }
1542 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001543#ifdef TCB_CLONE_THREAD
1544 if (tcp->flags & TCB_CLONE_THREAD)
1545 tcp->parent->nclone_waiting--;
1546#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001547
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001548 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001549 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001550
1551 if (!qflag)
1552 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1553 return 0;
1554}
1555
Roland McGrath1bfd3102007-08-03 10:02:00 +00001556static int
1557resume_from_tcp (struct tcb *tcp)
1558{
1559 int error = 0;
1560 int resumed = 0;
1561
1562 /* XXX This won't always be quite right (but it never was).
1563 A waiter with argument 0 or < -1 is waiting for any pid in
1564 a particular pgrp, which this child might or might not be
1565 in. The waiter will only wake up if it's argument is -1
1566 or if it's waiting for tcp->pid's pgrp. It makes a
1567 difference to wake up a waiter when there might be more
1568 traced children, because it could get a false ECHILD
1569 error. OTOH, if this was the last child in the pgrp, then
1570 it ought to wake up and get ECHILD. We would have to
1571 search the system for all pid's in the pgrp to be sure.
1572
1573 && (t->waitpid == -1 ||
1574 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1575 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1576 */
1577
1578 if (tcp->parent &&
1579 (tcp->parent->flags & TCB_SUSPENDED) &&
1580 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001581 error = resume(tcp->parent);
Roland McGrath1bfd3102007-08-03 10:02:00 +00001582 ++resumed;
1583 }
1584#ifdef TCB_CLONE_THREAD
1585 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1586 /* Some other threads of our parent are waiting too. */
1587 unsigned int i;
1588
1589 /* Resume all the threads that were waiting for this PID. */
1590 for (i = 0; i < tcbtabsize; i++) {
1591 struct tcb *t = tcbtab[i];
1592 if (t->parent == tcp->parent && t != tcp
1593 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1594 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1595 && t->waitpid == tcp->pid) {
1596 error |= resume (t);
1597 ++resumed;
1598 }
1599 }
1600 if (resumed == 0)
1601 /* Noone was waiting for this PID in particular,
1602 so now we might need to resume some wildcarders. */
1603 for (i = 0; i < tcbtabsize; i++) {
1604 struct tcb *t = tcbtab[i];
1605 if (t->parent == tcp->parent && t != tcp
1606 && ((t->flags
1607 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1608 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1609 && t->waitpid <= 0
1610 ) {
1611 error |= resume (t);
1612 break;
1613 }
1614 }
1615 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001616#endif
Roland McGrath1bfd3102007-08-03 10:02:00 +00001617
1618 return error;
1619}
Roland McGrath1bfd3102007-08-03 10:02:00 +00001620
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001621#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001622
Roland McGrath0a463882007-07-05 18:43:16 +00001623/* detach traced process; continue with sig
1624 Never call DETACH twice on the same process as both unattached and
1625 attached-unstopped processes give the same ESRCH. For unattached process we
1626 would SIGSTOP it and wait for its SIGSTOP notification forever. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001627
1628static int
1629detach(tcp, sig)
1630struct tcb *tcp;
1631int sig;
1632{
1633 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001634#ifdef LINUX
Roland McGrath1bfd3102007-08-03 10:02:00 +00001635 int status, catch_sigstop;
Roland McGratha08a97e2005-08-03 11:23:46 +00001636 struct tcb *zombie = NULL;
1637
1638 /* If the group leader is lingering only because of this other
1639 thread now dying, then detach the leader as well. */
1640 if ((tcp->flags & TCB_CLONE_THREAD) &&
1641 tcp->parent->nclone_threads == 1 &&
1642 (tcp->parent->flags & TCB_EXITING))
1643 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001644#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001645
1646 if (tcp->flags & TCB_BPTSET)
Andreas Schwab840d85b2010-01-12 11:16:32 +01001647 clearbpt(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001648
1649#ifdef LINUX
1650 /*
1651 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001652 * before detaching. Arghh. We go through hoops
1653 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001654 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001655#if defined(SPARC)
1656#undef PTRACE_DETACH
1657#define PTRACE_DETACH PTRACE_SUNDETACH
1658#endif
Roland McGrath02203312007-06-11 22:06:31 +00001659 /*
1660 * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
1661 * expected SIGSTOP. We must catch exactly one as otherwise the
1662 * detached process would be left stopped (process state T).
1663 */
1664 catch_sigstop = (tcp->flags & TCB_STARTUP);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001665 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1666 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001667 }
1668 else if (errno != ESRCH) {
1669 /* Shouldn't happen. */
1670 perror("detach: ptrace(PTRACE_DETACH, ...)");
1671 }
Roland McGrath134813a2007-06-02 00:07:33 +00001672 else if (my_tgkill((tcp->flags & TCB_CLONE_THREAD ? tcp->parent->pid
1673 : tcp->pid),
1674 tcp->pid, 0) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001675 if (errno != ESRCH)
1676 perror("detach: checking sanity");
1677 }
Roland McGrath02203312007-06-11 22:06:31 +00001678 else if (!catch_sigstop && my_tgkill((tcp->flags & TCB_CLONE_THREAD
1679 ? tcp->parent->pid : tcp->pid),
1680 tcp->pid, SIGSTOP) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001681 if (errno != ESRCH)
1682 perror("detach: stopping child");
1683 }
Roland McGrath02203312007-06-11 22:06:31 +00001684 else
1685 catch_sigstop = 1;
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001686 if (catch_sigstop) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001687 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001688#ifdef __WALL
1689 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1690 if (errno == ECHILD) /* Already gone. */
1691 break;
1692 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001693 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001694 break;
1695 }
1696#endif /* __WALL */
1697 /* No __WALL here. */
1698 if (waitpid(tcp->pid, &status, 0) < 0) {
1699 if (errno != ECHILD) {
1700 perror("detach: waiting");
1701 break;
1702 }
1703#ifdef __WCLONE
1704 /* If no processes, try clones. */
1705 if (wait4(tcp->pid, &status, __WCLONE,
1706 NULL) < 0) {
1707 if (errno != ECHILD)
1708 perror("detach: waiting");
1709 break;
1710 }
1711#endif /* __WCLONE */
1712 }
1713#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001714 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001715#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001716 if (!WIFSTOPPED(status)) {
1717 /* Au revoir, mon ami. */
1718 break;
1719 }
1720 if (WSTOPSIG(status) == SIGSTOP) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001721 ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001722 break;
1723 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001724 error = ptrace_restart(PTRACE_CONT, tcp,
Roland McGratheb9e2e82009-06-02 16:49:22 -07001725 WSTOPSIG(status) == SIGTRAP ? 0
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001726 : WSTOPSIG(status));
1727 if (error < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001728 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001729 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001730 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001731#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001732
1733#if defined(SUNOS4)
1734 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1735 if (sig && kill(tcp->pid, sig) < 0)
1736 perror("detach: kill");
1737 sig = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001738 error = ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001739#endif /* SUNOS4 */
1740
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001741#ifndef USE_PROCFS
Roland McGrath1bfd3102007-08-03 10:02:00 +00001742 error |= resume_from_tcp (tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001743#endif
1744
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001745 if (!qflag)
1746 fprintf(stderr, "Process %u detached\n", tcp->pid);
1747
1748 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001749
1750#ifdef LINUX
Roland McGrath0a463882007-07-05 18:43:16 +00001751 if (zombie != NULL) {
1752 /* TCP no longer exists therefore you must not detach () it. */
1753 droptcb(zombie);
1754 }
Roland McGratha08a97e2005-08-03 11:23:46 +00001755#endif
1756
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001757 return error;
1758}
1759
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001760#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001761
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001762static void reaper(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001763{
1764 int pid;
1765 int status;
1766
1767 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001768 }
1769}
1770
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001771#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001772
1773static void
1774cleanup()
1775{
1776 int i;
1777 struct tcb *tcp;
1778
Roland McGrathee9d4352002-12-18 04:16:10 +00001779 for (i = 0; i < tcbtabsize; i++) {
1780 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001781 if (!(tcp->flags & TCB_INUSE))
1782 continue;
1783 if (debug)
1784 fprintf(stderr,
1785 "cleanup: looking at pid %u\n", tcp->pid);
1786 if (tcp_last &&
1787 (!outfname || followfork < 2 || tcp_last == tcp)) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001788 tprintf(" <unfinished ...>");
1789 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001790 }
1791 if (tcp->flags & TCB_ATTACHED)
1792 detach(tcp, 0);
1793 else {
1794 kill(tcp->pid, SIGCONT);
1795 kill(tcp->pid, SIGTERM);
1796 }
1797 }
1798 if (cflag)
1799 call_summary(outf);
1800}
1801
1802static void
1803interrupt(sig)
1804int sig;
1805{
1806 interrupted = 1;
1807}
1808
1809#ifndef HAVE_STRERROR
1810
Roland McGrath6d2b3492002-12-30 00:51:30 +00001811#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001812extern int sys_nerr;
1813extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001814#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001815
1816const char *
1817strerror(errno)
1818int errno;
1819{
1820 static char buf[64];
1821
1822 if (errno < 1 || errno >= sys_nerr) {
1823 sprintf(buf, "Unknown error %d", errno);
1824 return buf;
1825 }
1826 return sys_errlist[errno];
1827}
1828
1829#endif /* HAVE_STERRROR */
1830
1831#ifndef HAVE_STRSIGNAL
1832
Roland McGrath8f474e02003-01-14 07:53:33 +00001833#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001834extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001835#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001836#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1837extern char *_sys_siglist[];
1838#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001839
1840const char *
1841strsignal(sig)
1842int sig;
1843{
1844 static char buf[64];
1845
1846 if (sig < 1 || sig >= NSIG) {
1847 sprintf(buf, "Unknown signal %d", sig);
1848 return buf;
1849 }
1850#ifdef HAVE__SYS_SIGLIST
1851 return _sys_siglist[sig];
1852#else
1853 return sys_siglist[sig];
1854#endif
1855}
1856
1857#endif /* HAVE_STRSIGNAL */
1858
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001859#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001860
1861static void
1862rebuild_pollv()
1863{
1864 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001865
Roland McGrathee9d4352002-12-18 04:16:10 +00001866 if (pollv != NULL)
1867 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001868 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001869 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001870 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00001871 exit(1);
1872 }
1873
Roland McGrathca16be82003-01-10 19:55:28 +00001874 for (i = j = 0; i < tcbtabsize; i++) {
1875 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001876 if (!(tcp->flags & TCB_INUSE))
1877 continue;
1878 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001879 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001880 j++;
1881 }
1882 if (j != nprocs) {
1883 fprintf(stderr, "strace: proc miscount\n");
1884 exit(1);
1885 }
1886}
1887
1888#ifndef HAVE_POLLABLE_PROCFS
1889
1890static void
1891proc_poll_open()
1892{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001893 int i;
1894
1895 if (pipe(proc_poll_pipe) < 0) {
1896 perror("pipe");
1897 exit(1);
1898 }
1899 for (i = 0; i < 2; i++) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001900 if (set_cloexec_flag(proc_poll_pipe[i]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001901 exit(1);
1902 }
1903 }
1904}
1905
1906static int
1907proc_poll(pollv, nfds, timeout)
1908struct pollfd *pollv;
1909int nfds;
1910int timeout;
1911{
1912 int i;
1913 int n;
1914 struct proc_pollfd pollinfo;
1915
1916 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1917 return n;
1918 if (n != sizeof(struct proc_pollfd)) {
1919 fprintf(stderr, "panic: short read: %d\n", n);
1920 exit(1);
1921 }
1922 for (i = 0; i < nprocs; i++) {
1923 if (pollv[i].fd == pollinfo.fd)
1924 pollv[i].revents = pollinfo.revents;
1925 else
1926 pollv[i].revents = 0;
1927 }
1928 poller_pid = pollinfo.pid;
1929 return 1;
1930}
1931
1932static void
1933wakeup_handler(sig)
1934int sig;
1935{
1936}
1937
1938static void
1939proc_poller(pfd)
1940int pfd;
1941{
1942 struct proc_pollfd pollinfo;
1943 struct sigaction sa;
1944 sigset_t blocked_set, empty_set;
1945 int i;
1946 int n;
1947 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001948#ifdef FREEBSD
1949 struct procfs_status pfs;
1950#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001951
1952 switch (fork()) {
1953 case -1:
1954 perror("fork");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001955 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001956 case 0:
1957 break;
1958 default:
1959 return;
1960 }
1961
1962 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1963 sa.sa_flags = 0;
1964 sigemptyset(&sa.sa_mask);
1965 sigaction(SIGHUP, &sa, NULL);
1966 sigaction(SIGINT, &sa, NULL);
1967 sigaction(SIGQUIT, &sa, NULL);
1968 sigaction(SIGPIPE, &sa, NULL);
1969 sigaction(SIGTERM, &sa, NULL);
1970 sa.sa_handler = wakeup_handler;
1971 sigaction(SIGUSR1, &sa, NULL);
1972 sigemptyset(&blocked_set);
1973 sigaddset(&blocked_set, SIGUSR1);
1974 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1975 sigemptyset(&empty_set);
1976
1977 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1978 perror("getrlimit(RLIMIT_NOFILE, ...)");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001979 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001980 }
1981 n = rl.rlim_cur;
1982 for (i = 0; i < n; i++) {
1983 if (i != pfd && i != proc_poll_pipe[1])
1984 close(i);
1985 }
1986
1987 pollinfo.fd = pfd;
1988 pollinfo.pid = getpid();
1989 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001990#ifndef FREEBSD
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001991 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1992#else
1993 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1994#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001995 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001996 switch (errno) {
1997 case EINTR:
1998 continue;
1999 case EBADF:
2000 pollinfo.revents = POLLERR;
2001 break;
2002 case ENOENT:
2003 pollinfo.revents = POLLHUP;
2004 break;
2005 default:
2006 perror("proc_poller: PIOCWSTOP");
2007 }
2008 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2009 _exit(0);
2010 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002011 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002012 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2013 sigsuspend(&empty_set);
2014 }
2015}
2016
2017#endif /* !HAVE_POLLABLE_PROCFS */
2018
2019static int
2020choose_pfd()
2021{
2022 int i, j;
2023 struct tcb *tcp;
2024
2025 static int last;
2026
2027 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002028 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002029 /*
2030 * The previous process is ready to run again. We'll
2031 * let it do so if it is currently in a syscall. This
2032 * heuristic improves the readability of the trace.
2033 */
2034 tcp = pfd2tcb(pollv[last].fd);
2035 if (tcp && (tcp->flags & TCB_INSYSCALL))
2036 return pollv[last].fd;
2037 }
2038
2039 for (i = 0; i < nprocs; i++) {
2040 /* Let competing children run round robin. */
2041 j = (i + last + 1) % nprocs;
2042 if (pollv[j].revents & (POLLHUP | POLLERR)) {
2043 tcp = pfd2tcb(pollv[j].fd);
2044 if (!tcp) {
2045 fprintf(stderr, "strace: lost proc\n");
2046 exit(1);
2047 }
2048 droptcb(tcp);
2049 return -1;
2050 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002051 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002052 last = j;
2053 return pollv[j].fd;
2054 }
2055 }
2056 fprintf(stderr, "strace: nothing ready\n");
2057 exit(1);
2058}
2059
2060static int
2061trace()
2062{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002063#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00002064 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002065#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002066 struct tcb *tcp;
2067 int pfd;
2068 int what;
2069 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002070 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002071
2072 for (;;) {
2073 if (interactive)
2074 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2075
2076 if (nprocs == 0)
2077 break;
2078
2079 switch (nprocs) {
2080 case 1:
2081#ifndef HAVE_POLLABLE_PROCFS
2082 if (proc_poll_pipe[0] == -1) {
2083#endif
Roland McGrath54e931f2010-09-14 18:59:20 -07002084 tcp = first_used_tcb();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002085 if (!tcp)
2086 continue;
2087 pfd = tcp->pfd;
2088 if (pfd == -1)
2089 continue;
2090 break;
2091#ifndef HAVE_POLLABLE_PROCFS
2092 }
2093 /* fall through ... */
2094#endif /* !HAVE_POLLABLE_PROCFS */
2095 default:
2096#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002097#ifdef POLL_HACK
2098 /* On some systems (e.g. UnixWare) we get too much ugly
2099 "unfinished..." stuff when multiple proceses are in
2100 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00002101
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002102 if (in_syscall) {
2103 struct pollfd pv;
2104 tcp = in_syscall;
2105 in_syscall = NULL;
2106 pv.fd = tcp->pfd;
2107 pv.events = POLLWANT;
2108 if ((what = poll (&pv, 1, 1)) < 0) {
2109 if (interrupted)
2110 return 0;
2111 continue;
2112 }
2113 else if (what == 1 && pv.revents & POLLWANT) {
2114 goto FOUND;
2115 }
2116 }
2117#endif
2118
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002119 if (poll(pollv, nprocs, INFTIM) < 0) {
2120 if (interrupted)
2121 return 0;
2122 continue;
2123 }
2124#else /* !HAVE_POLLABLE_PROCFS */
2125 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
2126 if (interrupted)
2127 return 0;
2128 continue;
2129 }
2130#endif /* !HAVE_POLLABLE_PROCFS */
2131 pfd = choose_pfd();
2132 if (pfd == -1)
2133 continue;
2134 break;
2135 }
2136
2137 /* Look up `pfd' in our table. */
2138 if ((tcp = pfd2tcb(pfd)) == NULL) {
2139 fprintf(stderr, "unknown pfd: %u\n", pfd);
2140 exit(1);
2141 }
John Hughesb6643082002-05-23 11:02:22 +00002142#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002143 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00002144#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002145 /* Get the status of the process. */
2146 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002147#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002148 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002149#else /* FREEBSD */
2150 /* Thanks to some scheduling mystery, the first poller
2151 sometimes waits for the already processed end of fork
2152 event. Doing a non blocking poll here solves the problem. */
2153 if (proc_poll_pipe[0] != -1)
2154 ioctl_result = IOCTL_STATUS (tcp);
2155 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002156 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00002157#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002158 ioctl_errno = errno;
2159#ifndef HAVE_POLLABLE_PROCFS
2160 if (proc_poll_pipe[0] != -1) {
2161 if (ioctl_result < 0)
2162 kill(poller_pid, SIGKILL);
2163 else
2164 kill(poller_pid, SIGUSR1);
2165 }
2166#endif /* !HAVE_POLLABLE_PROCFS */
2167 }
2168 if (interrupted)
2169 return 0;
2170
2171 if (interactive)
2172 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2173
2174 if (ioctl_result < 0) {
2175 /* Find out what happened if it failed. */
2176 switch (ioctl_errno) {
2177 case EINTR:
2178 case EBADF:
2179 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002180#ifdef FREEBSD
2181 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00002182#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002183 case ENOENT:
2184 droptcb(tcp);
2185 continue;
2186 default:
2187 perror("PIOCWSTOP");
2188 exit(1);
2189 }
2190 }
2191
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002192#ifdef FREEBSD
2193 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2194 /* discard first event for a syscall we never entered */
2195 IOCTL (tcp->pfd, PIOCRUN, 0);
2196 continue;
2197 }
Roland McGrath553a6092002-12-16 20:40:39 +00002198#endif
2199
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002200 /* clear the just started flag */
2201 tcp->flags &= ~TCB_STARTUP;
2202
2203 /* set current output file */
2204 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002205 curcol = tcp->curcol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002206
2207 if (cflag) {
2208 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002209#ifdef FREEBSD
2210 char buf[1024];
2211 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002212
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002213 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
2214 buf[len] = '\0';
2215 sscanf(buf,
2216 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2217 &stime.tv_sec, &stime.tv_usec);
2218 } else
2219 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002220#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002221 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2222 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002223#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002224 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2225 tcp->stime = stime;
2226 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002227 what = tcp->status.PR_WHAT;
2228 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002229#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002230 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002231 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2232 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002233 if (trace_syscall(tcp) < 0) {
2234 fprintf(stderr, "syscall trouble\n");
2235 exit(1);
2236 }
2237 }
2238 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002239#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002240 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002241#ifdef POLL_HACK
2242 in_syscall = tcp;
2243#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002244 case PR_SYSEXIT:
2245 if (trace_syscall(tcp) < 0) {
2246 fprintf(stderr, "syscall trouble\n");
2247 exit(1);
2248 }
2249 break;
2250 case PR_SIGNALLED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002251 if (cflag != CFLAG_ONLY_STATS
2252 && (qual_flags[what] & QUAL_SIGNAL)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002253 printleader(tcp);
2254 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002255 signame(what), strsignal(what));
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002256 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002257#ifdef PR_INFO
2258 if (tcp->status.PR_INFO.si_signo == what) {
2259 printleader(tcp);
2260 tprintf(" siginfo=");
2261 printsiginfo(&tcp->status.PR_INFO, 1);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002262 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002263 }
2264#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002265 }
2266 break;
2267 case PR_FAULTED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002268 if (cflag != CFLAGS_ONLY_STATS
2269 && (qual_flags[what] & QUAL_FAULT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002270 printleader(tcp);
2271 tprintf("=== FAULT %d ===", what);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002272 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002273 }
2274 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002275#ifdef FREEBSD
2276 case 0: /* handle case we polled for nothing */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002277 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00002278#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002279 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002280 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002281 exit(1);
2282 break;
2283 }
Andreas Schwabccdff482009-10-27 16:27:13 +01002284 /* Remember current print column before continuing. */
2285 tcp->curcol = curcol;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002286 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002287#ifndef FREEBSD
Andreas Schwab372cc842010-07-09 11:49:27 +02002288 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002289#else
Andreas Schwab372cc842010-07-09 11:49:27 +02002290 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002291#endif
Andreas Schwab372cc842010-07-09 11:49:27 +02002292 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002293 perror("PIOCRUN");
2294 exit(1);
2295 }
2296 }
2297 return 0;
2298}
2299
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002300#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002301
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002302#ifdef TCB_GROUP_EXITING
2303/* Handle an exit detach or death signal that is taking all the
2304 related clone threads with it. This is called in three circumstances:
2305 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
2306 SIG == 0 Continuing TCP will perform an exit_group syscall.
2307 SIG == other Continuing TCP with SIG will kill the process.
2308*/
2309static int
2310handle_group_exit(struct tcb *tcp, int sig)
2311{
2312 /* We need to locate our records of all the clone threads
2313 related to TCP, either its children or siblings. */
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002314 struct tcb *leader = NULL;
2315
2316 if (tcp->flags & TCB_CLONE_THREAD)
2317 leader = tcp->parent;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002318
2319 if (sig < 0) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002320 if (leader != NULL && leader != tcp
2321 && !(leader->flags & TCB_GROUP_EXITING)
2322 && !(tcp->flags & TCB_STARTUP)
2323 ) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002324 fprintf(stderr,
2325 "PANIC: handle_group_exit: %d leader %d\n",
2326 tcp->pid, leader ? leader->pid : -1);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002327 }
2328 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath1bfd3102007-08-03 10:02:00 +00002329#ifndef USE_PROCFS
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002330 resume_from_tcp(tcp);
Roland McGrath1bfd3102007-08-03 10:02:00 +00002331#endif
Roland McGrath0a463882007-07-05 18:43:16 +00002332 droptcb(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002333 }
2334 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00002335 /* Mark that we are taking the process down. */
2336 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002337 if (tcp->flags & TCB_ATTACHED) {
Roland McGrathd6a32f12007-07-11 08:35:11 +00002338 detach(tcp, sig);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002339 if (leader != NULL && leader != tcp)
Roland McGrath1bfd3102007-08-03 10:02:00 +00002340 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002341 } else {
2342 if (ptrace_restart(PTRACE_CONT, tcp, sig) < 0) {
2343 cleanup();
2344 return -1;
2345 }
2346 if (leader != NULL) {
Roland McGrath05690952004-10-20 01:00:27 +00002347 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002348 if (leader != tcp)
2349 droptcb(tcp);
2350 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002351 /* The leader will report to us as parent now,
2352 and then we'll get to the SIG==-1 case. */
2353 return 0;
2354 }
2355 }
2356
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002357 return 0;
2358}
2359#endif
2360
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002361#ifdef LINUX
2362static int
2363handle_ptrace_event(int status, struct tcb *tcp)
2364{
2365 if (status >> 16 == PTRACE_EVENT_VFORK ||
2366 status >> 16 == PTRACE_EVENT_CLONE ||
2367 status >> 16 == PTRACE_EVENT_FORK) {
2368 int childpid;
2369
2370 if (do_ptrace(PTRACE_GETEVENTMSG, tcp, NULL, &childpid) < 0) {
2371 if (errno != ESRCH) {
2372 fprintf(stderr, "\
2373%s: handle_ptrace_event: ptrace cannot get new child's pid\n",
2374 progname);
2375 cleanup();
2376 exit(1);
2377 }
2378 return -1;
2379 }
2380 return handle_new_child(tcp, childpid, 0);
2381 }
2382 return 1;
2383}
2384#endif
2385
Roland McGratheb9e2e82009-06-02 16:49:22 -07002386static int
2387trace()
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002388{
2389 int pid;
2390 int wait_errno;
2391 int status;
2392 struct tcb *tcp;
2393#ifdef LINUX
2394 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002395#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002396 static int wait4_options = __WALL;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002397#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002398#endif /* LINUX */
2399
Roland McGratheb9e2e82009-06-02 16:49:22 -07002400 while (nprocs != 0) {
Denys Vlasenko222713a2009-03-17 14:29:59 +00002401 if (interrupted)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002402 return 0;
2403 if (interactive)
2404 sigprocmask(SIG_SETMASK, &empty_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002405#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002406#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002407 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002408 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002409 /* this kernel does not support __WALL */
2410 wait4_options &= ~__WALL;
2411 errno = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002412 pid = wait4(-1, &status, wait4_options,
2413 cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002414 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002415 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002416 /* most likely a "cloned" process */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002417 pid = wait4(-1, &status, __WCLONE,
2418 cflag ? &ru : NULL);
2419 if (pid == -1) {
2420 fprintf(stderr, "strace: clone wait4 "
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002421 "failed: %s\n", strerror(errno));
2422 }
2423 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002424#else
2425 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
2426#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002427#endif /* LINUX */
2428#ifdef SUNOS4
2429 pid = wait(&status);
2430#endif /* SUNOS4 */
2431 wait_errno = errno;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002432 if (interactive)
2433 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002434
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002435 if (pid == -1) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002436 switch (wait_errno) {
2437 case EINTR:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002438 continue;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002439 case ECHILD:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002440 /*
2441 * We would like to verify this case
2442 * but sometimes a race in Solbourne's
2443 * version of SunOS sometimes reports
2444 * ECHILD before sending us SIGCHILD.
2445 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002446 return 0;
2447 default:
2448 errno = wait_errno;
2449 perror("strace: wait");
2450 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002451 }
2452 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002453 if (pid == popen_pid) {
2454 if (WIFEXITED(status) || WIFSIGNALED(status))
2455 popen_pid = -1;
2456 continue;
2457 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002458 if (debug)
2459 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2460
2461 /* Look up `pid' in our table. */
2462 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002463#ifdef LINUX
Roland McGrath41c48222008-07-18 00:25:10 +00002464 if (followfork) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002465 /* This is needed to go with the CLONE_PTRACE
2466 changes in process.c/util.c: we might see
2467 the child's initial trap before we see the
2468 parent return from the clone syscall.
2469 Leave the child suspended until the parent
2470 returns from its system call. Only then
2471 will we have the association of parent and
2472 child so that we know how to do clearbpt
2473 in the child. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +00002474 tcp = alloctcb(pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002475 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002476 if (!qflag)
2477 fprintf(stderr, "\
2478Process %d attached (waiting for parent)\n",
2479 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002480 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002481 else
2482 /* This can happen if a clone call used
2483 CLONE_PTRACE itself. */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002484#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002485 {
2486 fprintf(stderr, "unknown pid: %u\n", pid);
2487 if (WIFSTOPPED(status))
2488 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2489 exit(1);
2490 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002491 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002492 /* set current output file */
2493 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002494 curcol = tcp->curcol;
Denys Vlasenko84e20af2009-02-10 16:03:20 +00002495 if (cflag) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002496#ifdef LINUX
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002497 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2498 tcp->stime = ru.ru_stime;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002499#endif /* !LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002500 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002501
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002502 if (tcp->flags & TCB_SUSPENDED) {
2503 /*
2504 * Apparently, doing any ptrace() call on a stopped
2505 * process, provokes the kernel to report the process
2506 * status again on a subsequent wait(), even if the
2507 * process has not been actually restarted.
2508 * Since we have inspected the arguments of suspended
2509 * processes we end up here testing for this case.
2510 */
2511 continue;
2512 }
2513 if (WIFSIGNALED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002514 if (pid == strace_child)
2515 exit_code = 0x100 | WTERMSIG(status);
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002516 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002517 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2518 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002519 tprintf("+++ killed by %s %s+++",
2520 signame(WTERMSIG(status)),
2521#ifdef WCOREDUMP
2522 WCOREDUMP(status) ? "(core dumped) " :
2523#endif
2524 "");
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002525 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002526 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002527#ifdef TCB_GROUP_EXITING
2528 handle_group_exit(tcp, -1);
2529#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002530 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002531#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002532 continue;
2533 }
2534 if (WIFEXITED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002535 if (pid == strace_child)
2536 exit_code = WEXITSTATUS(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002537 if (debug)
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002538 fprintf(stderr, "pid %u exited with %d\n", pid, WEXITSTATUS(status));
2539 if ((tcp->flags & (TCB_ATTACHED|TCB_STARTUP)) == TCB_ATTACHED
Roland McGrath05690952004-10-20 01:00:27 +00002540#ifdef TCB_GROUP_EXITING
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002541 && !(tcp->parent && (tcp->parent->flags & TCB_GROUP_EXITING))
Roland McGrath1bfd3102007-08-03 10:02:00 +00002542 && !(tcp->flags & TCB_GROUP_EXITING)
Roland McGrath05690952004-10-20 01:00:27 +00002543#endif
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002544 ) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002545 fprintf(stderr,
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002546 "PANIC: attached pid %u exited with %d\n",
2547 pid, WEXITSTATUS(status));
2548 }
Roland McGrath0a396902003-06-10 03:05:53 +00002549 if (tcp == tcp_last) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002550 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT)) == TCB_INSYSCALL)
Roland McGrath0a396902003-06-10 03:05:53 +00002551 tprintf(" <unfinished ... exit status %d>\n",
2552 WEXITSTATUS(status));
2553 tcp_last = NULL;
2554 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002555#ifdef TCB_GROUP_EXITING
2556 handle_group_exit(tcp, -1);
2557#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002558 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002559#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002560 continue;
2561 }
2562 if (!WIFSTOPPED(status)) {
2563 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2564 droptcb(tcp);
2565 continue;
2566 }
2567 if (debug)
2568 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002569 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002570
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002571 if (ptrace_setoptions && (status >> 16)) {
2572 if (handle_ptrace_event(status, tcp) != 1)
2573 goto tracing;
2574 }
2575
Roland McGrath02203312007-06-11 22:06:31 +00002576 /*
2577 * Interestingly, the process may stop
2578 * with STOPSIG equal to some other signal
Roland McGratheb9e2e82009-06-02 16:49:22 -07002579 * than SIGSTOP if we happend to attach
Roland McGrath02203312007-06-11 22:06:31 +00002580 * just before the process takes a signal.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002581 * A no-MMU vforked child won't send up a signal,
2582 * so skip the first (lost) execve notification.
Roland McGrath02203312007-06-11 22:06:31 +00002583 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002584 if ((tcp->flags & TCB_STARTUP) &&
2585 (WSTOPSIG(status) == SIGSTOP || strace_vforked)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002586 /*
2587 * This flag is there to keep us in sync.
2588 * Next time this process stops it should
2589 * really be entering a system call.
2590 */
2591 tcp->flags &= ~TCB_STARTUP;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002592 if (tcp->flags & TCB_BPTSET) {
Roland McGrath02203312007-06-11 22:06:31 +00002593 /*
2594 * One example is a breakpoint inherited from
2595 * parent through fork ().
2596 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002597 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2598 droptcb(tcp);
2599 cleanup();
2600 return -1;
2601 }
2602 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002603#ifdef LINUX
2604 if (followfork && (tcp->parent == NULL) && ptrace_setoptions)
2605 if (ptrace(PTRACE_SETOPTIONS, tcp->pid,
2606 NULL, ptrace_setoptions) < 0 &&
2607 errno != ESRCH)
2608 ptrace_setoptions = 0;
2609#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002610 goto tracing;
2611 }
2612
Roland McGratheb9e2e82009-06-02 16:49:22 -07002613 if (WSTOPSIG(status) != SIGTRAP) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002614 if (WSTOPSIG(status) == SIGSTOP &&
2615 (tcp->flags & TCB_SIGTRAPPED)) {
2616 /*
2617 * Trapped attempt to block SIGTRAP
2618 * Hope we are back in control now.
2619 */
2620 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002621 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002622 cleanup();
2623 return -1;
2624 }
2625 continue;
2626 }
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002627 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002628 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00002629 unsigned long addr = 0;
2630 long pc = 0;
Dmitry V. Levin96339422006-10-11 23:11:43 +00002631#if defined(PT_CR_IPSR) && defined(PT_CR_IIP) && defined(PT_GETSIGINFO)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002632# define PSR_RI 41
2633 struct siginfo si;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002634 long psr;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002635
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002636 upeek(tcp, PT_CR_IPSR, &psr);
2637 upeek(tcp, PT_CR_IIP, &pc);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002638
2639 pc += (psr >> PSR_RI) & 0x3;
2640 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2641 addr = (unsigned long) si.si_addr;
Roland McGrath3a055d72005-03-06 22:24:29 +00002642#elif defined PTRACE_GETSIGINFO
2643 if (WSTOPSIG(status) == SIGSEGV ||
2644 WSTOPSIG(status) == SIGBUS) {
2645 siginfo_t si;
2646 if (ptrace(PTRACE_GETSIGINFO, pid,
2647 0, &si) == 0)
2648 addr = (unsigned long)
2649 si.si_addr;
2650 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002651#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002652 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002653 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002654 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002655 strsignal(WSTOPSIG(status)), pc, addr);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002656 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002657 }
Roland McGrath05690952004-10-20 01:00:27 +00002658 if (((tcp->flags & TCB_ATTACHED) ||
2659 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002660 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002661#ifdef TCB_GROUP_EXITING
2662 handle_group_exit(tcp, WSTOPSIG(status));
2663#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002664 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002665#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002666 continue;
2667 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002668 if (ptrace_restart(PTRACE_SYSCALL, tcp, WSTOPSIG(status)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002669 cleanup();
2670 return -1;
2671 }
2672 tcp->flags &= ~TCB_SUSPENDED;
2673 continue;
2674 }
Roland McGrath02203312007-06-11 22:06:31 +00002675 /* we handled the STATUS, we are permitted to interrupt now. */
2676 if (interrupted)
2677 return 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002678 if (trace_syscall(tcp) < 0 && !tcp->ptrace_errno) {
2679 /* ptrace() failed in trace_syscall() with ESRCH.
2680 * Likely a result of process disappearing mid-flight.
2681 * Observed case: exit_group() terminating
2682 * all processes in thread group. In this case, threads
2683 * "disappear" in an unpredictable moment without any
2684 * notification to strace via wait().
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002685 */
2686 if (tcp->flags & TCB_ATTACHED) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002687 if (tcp_last) {
2688 /* Do we have dangling line "syscall(param, param"?
2689 * Finish the line then. We cannot
2690 */
2691 tcp_last->flags |= TCB_REPRINT;
2692 tprintf(" <unfinished ...>");
2693 printtrailer();
2694 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002695 detach(tcp, 0);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002696 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002697 ptrace(PTRACE_KILL,
2698 tcp->pid, (char *) 1, SIGTERM);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002699 droptcb(tcp);
2700 }
2701 continue;
2702 }
2703 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002704#ifdef TCB_GROUP_EXITING
2705 if (tcp->flags & TCB_GROUP_EXITING) {
2706 if (handle_group_exit(tcp, 0) < 0)
2707 return -1;
2708 continue;
2709 }
2710#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002711 if (tcp->flags & TCB_ATTACHED)
2712 detach(tcp, 0);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002713 else if (ptrace_restart(PTRACE_CONT, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002714 cleanup();
2715 return -1;
2716 }
2717 continue;
2718 }
2719 if (tcp->flags & TCB_SUSPENDED) {
2720 if (!qflag)
2721 fprintf(stderr, "Process %u suspended\n", pid);
2722 continue;
2723 }
2724 tracing:
Andreas Schwabccdff482009-10-27 16:27:13 +01002725 /* Remember current print column before continuing. */
2726 tcp->curcol = curcol;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002727 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002728 cleanup();
2729 return -1;
2730 }
2731 }
2732 return 0;
2733}
2734
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002735#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002736
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002737#include <stdarg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002738
2739void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002740tprintf(const char *fmt, ...)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002741{
2742 va_list args;
2743
Andreas Schwabe5355de2009-10-27 16:56:43 +01002744 va_start(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002745 if (outf) {
2746 int n = vfprintf(outf, fmt, args);
Andreas Schwabccdff482009-10-27 16:27:13 +01002747 if (n < 0) {
2748 if (outf != stderr)
2749 perror(outfname == NULL
2750 ? "<writing to pipe>" : outfname);
2751 } else
Roland McGrathb310a0c2003-11-06 23:41:22 +00002752 curcol += n;
2753 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002754 va_end(args);
2755 return;
2756}
2757
2758void
Roland McGratheb9e2e82009-06-02 16:49:22 -07002759printleader(tcp)
2760struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002761{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002762 if (tcp_last) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002763 if (tcp_last->ptrace_errno) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002764 if (tcp_last->flags & TCB_INSYSCALL) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002765 tprintf(" <unavailable>)");
2766 tabto(acolumn);
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002767 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002768 tprintf("= ? <unavailable>\n");
2769 tcp_last->ptrace_errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002770 } else if (!outfname || followfork < 2 || tcp_last == tcp) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002771 tcp_last->flags |= TCB_REPRINT;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002772 tprintf(" <unfinished ...>\n");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002773 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002774 }
2775 curcol = 0;
2776 if ((followfork == 1 || pflag_seen > 1) && outfname)
2777 tprintf("%-5d ", tcp->pid);
2778 else if (nprocs > 1 && !outfname)
2779 tprintf("[pid %5u] ", tcp->pid);
2780 if (tflag) {
2781 char str[sizeof("HH:MM:SS")];
2782 struct timeval tv, dtv;
2783 static struct timeval otv;
2784
2785 gettimeofday(&tv, NULL);
2786 if (rflag) {
2787 if (otv.tv_sec == 0)
2788 otv = tv;
2789 tv_sub(&dtv, &tv, &otv);
2790 tprintf("%6ld.%06ld ",
2791 (long) dtv.tv_sec, (long) dtv.tv_usec);
2792 otv = tv;
2793 }
2794 else if (tflag > 2) {
2795 tprintf("%ld.%06ld ",
2796 (long) tv.tv_sec, (long) tv.tv_usec);
2797 }
2798 else {
2799 time_t local = tv.tv_sec;
2800 strftime(str, sizeof(str), "%T", localtime(&local));
2801 if (tflag > 1)
2802 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2803 else
2804 tprintf("%s ", str);
2805 }
2806 }
2807 if (iflag)
2808 printcall(tcp);
2809}
2810
2811void
2812tabto(col)
2813int col;
2814{
2815 if (curcol < col)
2816 tprintf("%*s", col - curcol, "");
2817}
2818
2819void
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002820printtrailer(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002821{
2822 tprintf("\n");
2823 tcp_last = NULL;
2824}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002825
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002826#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002827
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002828int
2829mp_ioctl(int fd, int cmd, void *arg, int size)
2830{
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002831 struct iovec iov[2];
2832 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002833
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002834 iov[0].iov_base = &cmd;
2835 iov[0].iov_len = sizeof cmd;
2836 if (arg) {
2837 ++n;
2838 iov[1].iov_base = arg;
2839 iov[1].iov_len = size;
2840 }
Roland McGrath553a6092002-12-16 20:40:39 +00002841
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002842 return writev(fd, iov, n);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002843}
2844
2845#endif