blob: e1ae8f1783a1d9cf82fe918fe3ae5c0893177f18 [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)) {
729 if (status >> 16 == PTRACE_EVENT_FORK)
730 ptrace_setoptions |= (PTRACE_O_TRACEVFORK |
731 PTRACE_O_TRACECLONE |
732 PTRACE_O_TRACEFORK);
733 if (WSTOPSIG(status) == SIGSTOP) {
734 if (ptrace(PTRACE_SETOPTIONS, pid, NULL,
735 PTRACE_O_TRACEFORK) < 0) {
736 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800737 return -1;
738 }
739 }
Dmitry V. Levinb1467442010-12-02 20:56:43 +0000740 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0 &&
741 errno != ESRCH)
742 kill(pid, SIGKILL);
Wang Chaob13c0de2010-11-12 17:25:19 +0800743 }
744 }
745 return 0;
746}
747#endif
748
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000749int
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000750main(int argc, char *argv[])
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000751{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000752 struct tcb *tcp;
753 int c, pid = 0;
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000754 int optF = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000755 struct sigaction sa;
756
757 static char buf[BUFSIZ];
758
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000759 progname = argv[0] ? argv[0] : "strace";
760
Roland McGrathee9d4352002-12-18 04:16:10 +0000761 /* Allocate the initial tcbtab. */
762 tcbtabsize = argc; /* Surely enough for all -p args. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000763 if ((tcbtab = calloc(tcbtabsize, sizeof tcbtab[0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000764 fprintf(stderr, "%s: out of memory\n", progname);
765 exit(1);
766 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000767 if ((tcbtab[0] = calloc(tcbtabsize, sizeof tcbtab[0][0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000768 fprintf(stderr, "%s: out of memory\n", progname);
769 exit(1);
770 }
Roland McGrathee9d4352002-12-18 04:16:10 +0000771 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
772 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
773
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000774 outf = stderr;
775 interactive = 1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000776 set_sortby(DEFAULT_SORTBY);
777 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000778 qualify("trace=all");
779 qualify("abbrev=all");
780 qualify("verbose=all");
781 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000782 while ((c = getopt(argc, argv,
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000783 "+cCdfFhiqrtTvVxz"
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000784#ifndef USE_PROCFS
785 "D"
786#endif
787 "a:e:o:O:p:s:S:u:E:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000788 switch (c) {
789 case 'c':
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000790 if (cflag == CFLAG_BOTH) {
791 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
792 progname);
793 exit(1);
794 }
795 cflag = CFLAG_ONLY_STATS;
796 break;
797 case 'C':
798 if (cflag == CFLAG_ONLY_STATS) {
799 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
800 progname);
801 exit(1);
802 }
803 cflag = CFLAG_BOTH;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000804 break;
805 case 'd':
806 debug++;
807 break;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000808#ifndef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000809 case 'D':
810 daemonized_tracer = 1;
811 break;
812#endif
Roland McGrath41c48222008-07-18 00:25:10 +0000813 case 'F':
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000814 optF = 1;
815 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000816 case 'f':
817 followfork++;
818 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000819 case 'h':
820 usage(stdout, 0);
821 break;
822 case 'i':
823 iflag++;
824 break;
825 case 'q':
826 qflag++;
827 break;
828 case 'r':
829 rflag++;
830 tflag++;
831 break;
832 case 't':
833 tflag++;
834 break;
835 case 'T':
836 dtime++;
837 break;
838 case 'x':
839 xflag++;
840 break;
841 case 'v':
842 qualify("abbrev=none");
843 break;
844 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +0000845 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000846 exit(0);
847 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000848 case 'z':
849 not_failing_only = 1;
850 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000851 case 'a':
852 acolumn = atoi(optarg);
853 break;
854 case 'e':
855 qualify(optarg);
856 break;
857 case 'o':
858 outfname = strdup(optarg);
859 break;
860 case 'O':
861 set_overhead(atoi(optarg));
862 break;
863 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +0000864 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000865 fprintf(stderr, "%s: Invalid process id: %s\n",
866 progname, optarg);
867 break;
868 }
869 if (pid == getpid()) {
Wichert Akkerman54a47671999-10-17 00:57:34 +0000870 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000871 break;
872 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000873 tcp = alloc_tcb(pid, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000874 tcp->flags |= TCB_ATTACHED;
875 pflag_seen++;
876 break;
877 case 's':
878 max_strlen = atoi(optarg);
Roland McGrathdccec722005-05-09 07:45:47 +0000879 if (max_strlen < 0) {
880 fprintf(stderr,
881 "%s: invalid -s argument: %s\n",
882 progname, optarg);
883 exit(1);
884 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000885 break;
886 case 'S':
887 set_sortby(optarg);
888 break;
889 case 'u':
890 username = strdup(optarg);
891 break;
Roland McGrathde6e5332003-01-24 04:31:23 +0000892 case 'E':
893 if (putenv(optarg) < 0) {
894 fprintf(stderr, "%s: out of memory\n",
895 progname);
896 exit(1);
897 }
898 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000899 default:
900 usage(stderr, 1);
901 break;
902 }
903 }
904
Roland McGrathd0c4c0c2006-04-25 07:39:40 +0000905 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +0000906 usage(stderr, 1);
907
Wang Chaod322a4b2010-08-05 14:30:11 +0800908 if (pflag_seen && daemonized_tracer) {
909 fprintf(stderr,
910 "%s: -D and -p are mutually exclusive options\n",
911 progname);
912 exit(1);
913 }
914
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000915 if (!followfork)
916 followfork = optF;
917
Roland McGrathcb9def62006-04-25 07:48:03 +0000918 if (followfork > 1 && cflag) {
919 fprintf(stderr,
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000920 "%s: (-c or -C) and -ff are mutually exclusive options\n",
Roland McGrathcb9def62006-04-25 07:48:03 +0000921 progname);
922 exit(1);
923 }
924
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000925 /* See if they want to run as another user. */
926 if (username != NULL) {
927 struct passwd *pent;
928
929 if (getuid() != 0 || geteuid() != 0) {
930 fprintf(stderr,
931 "%s: you must be root to use the -u option\n",
932 progname);
933 exit(1);
934 }
935 if ((pent = getpwnam(username)) == NULL) {
936 fprintf(stderr, "%s: cannot find user `%s'\n",
Roland McGrath09553f82007-07-05 19:31:49 +0000937 progname, username);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000938 exit(1);
939 }
940 run_uid = pent->pw_uid;
941 run_gid = pent->pw_gid;
942 }
943 else {
944 run_uid = getuid();
945 run_gid = getgid();
946 }
947
Dmitry V. Levin8044bc12010-12-07 12:50:49 +0000948#ifdef LINUX
949 if (followfork) {
950 if (test_ptrace_setoptions() < 0) {
951 fprintf(stderr,
952 "Test for options supported by PTRACE_SETOPTIONS "
953 "failed, giving up using this feature.\n");
954 ptrace_setoptions = 0;
955 }
956 if (debug)
957 fprintf(stderr, "ptrace_setoptions = %#x\n",
958 ptrace_setoptions);
959 }
960#endif
961
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000962 /* Check if they want to redirect the output. */
963 if (outfname) {
Roland McGrath37b9a662003-11-07 02:26:54 +0000964 /* See if they want to pipe the output. */
965 if (outfname[0] == '|' || outfname[0] == '!') {
966 /*
967 * We can't do the <outfname>.PID funny business
968 * when using popen, so prohibit it.
969 */
970 if (followfork > 1) {
971 fprintf(stderr, "\
972%s: piping the output and -ff are mutually exclusive options\n",
973 progname);
974 exit(1);
975 }
976
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000977 if ((outf = strace_popen(outfname + 1)) == NULL)
Roland McGrath37b9a662003-11-07 02:26:54 +0000978 exit(1);
Roland McGrath37b9a662003-11-07 02:26:54 +0000979 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000980 else if (followfork <= 1 &&
981 (outf = strace_fopen(outfname, "w")) == NULL)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000982 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000983 }
984
Roland McGrath37b9a662003-11-07 02:26:54 +0000985 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000986 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +0000987 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000988 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000989 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +0000990 }
Wang Chaob13c0de2010-11-12 17:25:19 +0800991
Roland McGrath54cc1c82007-11-03 23:34:11 +0000992 /* Valid states here:
993 optind < argc pflag_seen outfname interactive
994 1 0 0 1
995 0 1 0 1
996 1 0 1 0
997 0 1 1 1
998 */
999
1000 /* STARTUP_CHILD must be called before the signal handlers get
1001 installed below as they are inherited into the spawned process.
1002 Also we do not need to be protected by them as during interruption
1003 in the STARTUP_CHILD mode we kill the spawned process anyway. */
1004 if (!pflag_seen)
1005 startup_child(&argv[optind]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001006
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001007 sigemptyset(&empty_set);
1008 sigemptyset(&blocked_set);
1009 sa.sa_handler = SIG_IGN;
1010 sigemptyset(&sa.sa_mask);
1011 sa.sa_flags = 0;
1012 sigaction(SIGTTOU, &sa, NULL);
1013 sigaction(SIGTTIN, &sa, NULL);
1014 if (interactive) {
1015 sigaddset(&blocked_set, SIGHUP);
1016 sigaddset(&blocked_set, SIGINT);
1017 sigaddset(&blocked_set, SIGQUIT);
1018 sigaddset(&blocked_set, SIGPIPE);
1019 sigaddset(&blocked_set, SIGTERM);
1020 sa.sa_handler = interrupt;
1021#ifdef SUNOS4
1022 /* POSIX signals on sunos4.1 are a little broken. */
1023 sa.sa_flags = SA_INTERRUPT;
1024#endif /* SUNOS4 */
1025 }
1026 sigaction(SIGHUP, &sa, NULL);
1027 sigaction(SIGINT, &sa, NULL);
1028 sigaction(SIGQUIT, &sa, NULL);
1029 sigaction(SIGPIPE, &sa, NULL);
1030 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001031#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001032 sa.sa_handler = reaper;
1033 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +00001034#else
1035 /* Make sure SIGCHLD has the default action so that waitpid
1036 definitely works without losing track of children. The user
1037 should not have given us a bogus state to inherit, but he might
1038 have. Arguably we should detect SIG_IGN here and pass it on
1039 to children, but probably noone really needs that. */
1040 sa.sa_handler = SIG_DFL;
1041 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001042#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001043
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +00001044 if (pflag_seen || daemonized_tracer)
Roland McGrath02203312007-06-11 22:06:31 +00001045 startup_attach();
Roland McGrath02203312007-06-11 22:06:31 +00001046
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001047 if (trace() < 0)
1048 exit(1);
1049 cleanup();
Dmitry V. Levina6809652008-11-10 17:14:58 +00001050 fflush(NULL);
1051 if (exit_code > 0xff) {
1052 /* Child was killed by a signal, mimic that. */
1053 exit_code &= 0xff;
1054 signal(exit_code, SIG_DFL);
1055 raise(exit_code);
1056 /* Paranoia - what if this signal is not fatal?
1057 Exit with 128 + signo then. */
1058 exit_code += 128;
1059 }
1060 exit(exit_code);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001061}
1062
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001063void
1064expand_tcbtab(void)
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001065{
1066 /* Allocate some more TCBs and expand the table.
1067 We don't want to relocate the TCBs because our
1068 callers have pointers and it would be a pain.
1069 So tcbtab is a table of pointers. Since we never
1070 free the TCBs, we allocate a single chunk of many. */
1071 struct tcb **newtab = (struct tcb **)
1072 realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
1073 struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
1074 sizeof *newtcbs);
1075 int i;
1076 if (newtab == NULL || newtcbs == NULL) {
Dmitry V. Levin76860f62006-10-11 22:55:25 +00001077 fprintf(stderr, "%s: expand_tcbtab: out of memory\n",
1078 progname);
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001079 cleanup();
1080 exit(1);
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001081 }
1082 for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
1083 newtab[i] = &newtcbs[i - tcbtabsize];
1084 tcbtabsize *= 2;
1085 tcbtab = newtab;
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001086}
1087
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001088struct tcb *
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001089alloc_tcb(int pid, int command_options_parsed)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001090{
1091 int i;
1092 struct tcb *tcp;
1093
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001094 if (nprocs == tcbtabsize)
1095 expand_tcbtab();
1096
Roland McGrathee9d4352002-12-18 04:16:10 +00001097 for (i = 0; i < tcbtabsize; i++) {
1098 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001099 if ((tcp->flags & TCB_INUSE) == 0) {
1100 tcp->pid = pid;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001101 tcp->parent = NULL;
1102 tcp->nchildren = 0;
1103 tcp->nzombies = 0;
1104#ifdef TCB_CLONE_THREAD
Wang Chao21b8db42010-08-27 17:43:16 +08001105 tcp->nclone_threads = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001106 tcp->nclone_waiting = 0;
1107#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001108 tcp->flags = TCB_INUSE | TCB_STARTUP;
1109 tcp->outf = outf; /* Initialise to current out file */
Andreas Schwabccdff482009-10-27 16:27:13 +01001110 tcp->curcol = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001111 tcp->stime.tv_sec = 0;
1112 tcp->stime.tv_usec = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001113 tcp->pfd = -1;
1114 nprocs++;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001115 if (command_options_parsed)
1116 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001117 return tcp;
1118 }
1119 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001120 fprintf(stderr, "%s: bug in alloc_tcb\n", progname);
1121 cleanup();
1122 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001123}
1124
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001125#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001126int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001127proc_open(struct tcb *tcp, int attaching)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001128{
1129 char proc[32];
1130 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001131#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +00001132 int i;
1133 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001134 sigset_t signals;
1135 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001136#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001137#ifndef HAVE_POLLABLE_PROCFS
1138 static int last_pfd;
1139#endif
1140
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001141#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001142 /* Open the process pseudo-files in /proc. */
1143 sprintf(proc, "/proc/%d/ctl", tcp->pid);
1144 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001145 perror("strace: open(\"/proc/...\", ...)");
1146 return -1;
1147 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001148 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001149 return -1;
1150 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001151 sprintf(proc, "/proc/%d/status", tcp->pid);
1152 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
1153 perror("strace: open(\"/proc/...\", ...)");
1154 return -1;
1155 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001156 if (set_cloexec_flag(tcp->pfd_stat) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001157 return -1;
1158 }
1159 sprintf(proc, "/proc/%d/as", tcp->pid);
1160 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
1161 perror("strace: open(\"/proc/...\", ...)");
1162 return -1;
1163 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001164 if (set_cloexec_flag(tcp->pfd_as) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001165 return -1;
1166 }
1167#else
1168 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001169#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001170 sprintf(proc, "/proc/%d", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001171 tcp->pfd = open(proc, O_RDWR|O_EXCL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001172#else /* FREEBSD */
1173 sprintf(proc, "/proc/%d/mem", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001174 tcp->pfd = open(proc, O_RDWR);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001175#endif /* FREEBSD */
Andreas Schwab372cc842010-07-09 11:49:27 +02001176 if (tcp->pfd < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001177 perror("strace: open(\"/proc/...\", ...)");
1178 return -1;
1179 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001180 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001181 return -1;
1182 }
1183#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001184#ifdef FREEBSD
1185 sprintf(proc, "/proc/%d/regs", tcp->pid);
1186 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
1187 perror("strace: open(\"/proc/.../regs\", ...)");
1188 return -1;
1189 }
1190 if (cflag) {
1191 sprintf(proc, "/proc/%d/status", tcp->pid);
1192 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
1193 perror("strace: open(\"/proc/.../status\", ...)");
1194 return -1;
1195 }
1196 } else
1197 tcp->pfd_status = -1;
1198#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001199 rebuild_pollv();
1200 if (!attaching) {
1201 /*
1202 * Wait for the child to pause. Because of a race
1203 * condition we have to poll for the event.
1204 */
1205 for (;;) {
1206 if (IOCTL_STATUS (tcp) < 0) {
1207 perror("strace: PIOCSTATUS");
1208 return -1;
1209 }
1210 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001211 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001212 }
1213 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001214#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001215 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001216 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001217 perror("strace: PIOCSTOP");
1218 return -1;
1219 }
Roland McGrath553a6092002-12-16 20:40:39 +00001220#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001221#ifdef PIOCSET
1222 /* Set Run-on-Last-Close. */
1223 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001224 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001225 perror("PIOCSET PR_RLC");
1226 return -1;
1227 }
1228 /* Set or Reset Inherit-on-Fork. */
1229 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001230 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001231 perror("PIOC{SET,RESET} PR_FORK");
1232 return -1;
1233 }
1234#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +00001235#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001236 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
1237 perror("PIOCSRLC");
1238 return -1;
1239 }
1240 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
1241 perror("PIOC{S,R}FORK");
1242 return -1;
1243 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001244#else /* FREEBSD */
1245 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
1246 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
1247 perror("PIOCGFL");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001248 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001249 }
1250 arg &= ~PF_LINGER;
1251 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001252 perror("PIOCSFL");
1253 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001254 }
1255#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001256#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001257#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +00001258 /* Enable all syscall entries we care about. */
1259 premptyset(&syscalls);
1260 for (i = 1; i < MAX_QUALS; ++i) {
1261 if (i > (sizeof syscalls) * CHAR_BIT) break;
1262 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
1263 }
1264 praddset (&syscalls, SYS_execve);
1265 if (followfork) {
1266 praddset (&syscalls, SYS_fork);
1267#ifdef SYS_forkall
1268 praddset (&syscalls, SYS_forkall);
1269#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001270#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +00001271 praddset (&syscalls, SYS_fork1);
1272#endif
1273#ifdef SYS_rfork1
1274 praddset (&syscalls, SYS_rfork1);
1275#endif
1276#ifdef SYS_rforkall
1277 praddset (&syscalls, SYS_rforkall);
1278#endif
1279 }
1280 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001281 perror("PIOCSENTRY");
1282 return -1;
1283 }
John Hughes19e49982001-10-19 08:59:12 +00001284 /* Enable the syscall exits. */
1285 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001286 perror("PIOSEXIT");
1287 return -1;
1288 }
John Hughes19e49982001-10-19 08:59:12 +00001289 /* Enable signals we care about. */
1290 premptyset(&signals);
1291 for (i = 1; i < MAX_QUALS; ++i) {
1292 if (i > (sizeof signals) * CHAR_BIT) break;
1293 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
1294 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001295 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001296 perror("PIOCSTRACE");
1297 return -1;
1298 }
John Hughes19e49982001-10-19 08:59:12 +00001299 /* Enable faults we care about */
1300 premptyset(&faults);
1301 for (i = 1; i < MAX_QUALS; ++i) {
1302 if (i > (sizeof faults) * CHAR_BIT) break;
1303 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
1304 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001305 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001306 perror("PIOCSFAULT");
1307 return -1;
1308 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001309#else /* FREEBSD */
1310 /* set events flags. */
1311 arg = S_SIG | S_SCE | S_SCX ;
1312 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
1313 perror("PIOCBIS");
1314 return -1;
1315 }
1316#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001317 if (!attaching) {
1318#ifdef MIPS
1319 /*
1320 * The SGI PRSABORT doesn't work for pause() so
1321 * we send it a caught signal to wake it up.
1322 */
1323 kill(tcp->pid, SIGINT);
1324#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +00001325#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001326 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001327 arg = PRSABORT;
1328 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001329 perror("PIOCRUN");
1330 return -1;
1331 }
Roland McGrath553a6092002-12-16 20:40:39 +00001332#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001333#endif /* !MIPS*/
1334#ifdef FREEBSD
1335 /* wake up the child if it received the SIGSTOP */
1336 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001337#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001338 for (;;) {
1339 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001340 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001341 perror("PIOCWSTOP");
1342 return -1;
1343 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001344 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001345 tcp->flags &= ~TCB_INSYSCALL;
1346 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001347 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001348 break;
1349 }
1350 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001351#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001352 arg = 0;
1353 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001354#else /* FREEBSD */
1355 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001356#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001357 perror("PIOCRUN");
1358 return -1;
1359 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001360#ifdef FREEBSD
1361 /* handle the case where we "opened" the child before
1362 it did the kill -STOP */
1363 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1364 tcp->status.PR_WHAT == SIGSTOP)
1365 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001366#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001367 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001368#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001369 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001370#else /* FREEBSD */
1371 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001372 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001373 /* We are attaching to an already running process.
1374 * Try to figure out the state of the process in syscalls,
1375 * to handle the first event well.
1376 * This is done by having a look at the "wchan" property of the
1377 * process, which tells where it is stopped (if it is). */
1378 FILE * status;
1379 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001380
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001381 sprintf(proc, "/proc/%d/status", tcp->pid);
1382 status = fopen(proc, "r");
1383 if (status &&
1384 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1385 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1386 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1387 strcmp(wchan, "stopevent")) {
1388 /* The process is asleep in the middle of a syscall.
1389 Fake the syscall entry event */
1390 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1391 tcp->status.PR_WHY = PR_SYSENTRY;
1392 trace_syscall(tcp);
1393 }
1394 if (status)
1395 fclose(status);
1396 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001397 }
1398#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001399#ifndef HAVE_POLLABLE_PROCFS
1400 if (proc_poll_pipe[0] != -1)
1401 proc_poller(tcp->pfd);
1402 else if (nprocs > 1) {
1403 proc_poll_open();
1404 proc_poller(last_pfd);
1405 proc_poller(tcp->pfd);
1406 }
1407 last_pfd = tcp->pfd;
1408#endif /* !HAVE_POLLABLE_PROCFS */
1409 return 0;
1410}
1411
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001412#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001413
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001414struct tcb *
Roland McGrath54e931f2010-09-14 18:59:20 -07001415pid2tcb(int pid)
1416{
1417 int i;
1418
1419 if (pid <= 0)
1420 return NULL;
1421
1422 for (i = 0; i < tcbtabsize; i++) {
1423 struct tcb *tcp = tcbtab[i];
1424 if (tcp->pid == pid && (tcp->flags & TCB_INUSE))
1425 return tcp;
1426 }
1427
1428 return NULL;
1429}
1430
1431#ifdef USE_PROCFS
1432
1433static struct tcb *
1434first_used_tcb(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001435{
1436 int i;
1437 struct tcb *tcp;
Roland McGrathee9d4352002-12-18 04:16:10 +00001438 for (i = 0; i < tcbtabsize; i++) {
1439 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001440 if (tcp->flags & TCB_INUSE)
1441 return tcp;
1442 }
1443 return NULL;
1444}
1445
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001446static struct tcb *
1447pfd2tcb(pfd)
1448int pfd;
1449{
1450 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001451
Roland McGrathca16be82003-01-10 19:55:28 +00001452 for (i = 0; i < tcbtabsize; i++) {
1453 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001454 if (tcp->pfd != pfd)
1455 continue;
1456 if (tcp->flags & TCB_INUSE)
1457 return tcp;
1458 }
1459 return NULL;
1460}
1461
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001462#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001463
1464void
1465droptcb(tcp)
1466struct tcb *tcp;
1467{
1468 if (tcp->pid == 0)
1469 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001470#ifdef TCB_CLONE_THREAD
1471 if (tcp->nclone_threads > 0) {
1472 /* There are other threads left in this process, but this
1473 is the one whose PID represents the whole process.
1474 We need to keep this record around as a zombie until
1475 all the threads die. */
1476 tcp->flags |= TCB_EXITING;
1477 return;
1478 }
1479#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001480 nprocs--;
1481 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001482
Roland McGrathe29341c2003-01-10 20:14:20 +00001483 if (tcp->parent != NULL) {
1484 tcp->parent->nchildren--;
1485#ifdef TCB_CLONE_THREAD
Roland McGrathe29341c2003-01-10 20:14:20 +00001486 if (tcp->flags & TCB_CLONE_THREAD)
1487 tcp->parent->nclone_threads--;
1488#endif
Wang Chao21b8db42010-08-27 17:43:16 +08001489 tcp->parent->nzombies++;
Roland McGrath276ceb32007-11-13 08:12:12 +00001490#ifdef LINUX
1491 /* Update `tcp->parent->parent->nchildren' and the other fields
1492 like NCLONE_DETACHED, only for zombie group leader that has
1493 already reported and been short-circuited at the top of this
1494 function. The same condition as at the top of DETACH. */
1495 if ((tcp->flags & TCB_CLONE_THREAD) &&
1496 tcp->parent->nclone_threads == 0 &&
1497 (tcp->parent->flags & TCB_EXITING))
1498 droptcb(tcp->parent);
1499#endif
Roland McGrathe29341c2003-01-10 20:14:20 +00001500 tcp->parent = NULL;
1501 }
1502
1503 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001504 if (tcp->pfd != -1) {
1505 close(tcp->pfd);
1506 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001507#ifdef FREEBSD
1508 if (tcp->pfd_reg != -1) {
1509 close(tcp->pfd_reg);
1510 tcp->pfd_reg = -1;
1511 }
1512 if (tcp->pfd_status != -1) {
1513 close(tcp->pfd_status);
1514 tcp->pfd_status = -1;
1515 }
Roland McGrath553a6092002-12-16 20:40:39 +00001516#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001517#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001518 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001519#endif
1520 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001521
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001522 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001523 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001524
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001525 tcp->outf = 0;
1526}
1527
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001528#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001529
1530static int
1531resume(tcp)
1532struct tcb *tcp;
1533{
1534 if (tcp == NULL)
1535 return -1;
1536
1537 if (!(tcp->flags & TCB_SUSPENDED)) {
1538 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1539 return -1;
1540 }
1541 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001542#ifdef TCB_CLONE_THREAD
1543 if (tcp->flags & TCB_CLONE_THREAD)
1544 tcp->parent->nclone_waiting--;
1545#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001546
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001547 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001548 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001549
1550 if (!qflag)
1551 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1552 return 0;
1553}
1554
Roland McGrath1bfd3102007-08-03 10:02:00 +00001555static int
1556resume_from_tcp (struct tcb *tcp)
1557{
1558 int error = 0;
1559 int resumed = 0;
1560
1561 /* XXX This won't always be quite right (but it never was).
1562 A waiter with argument 0 or < -1 is waiting for any pid in
1563 a particular pgrp, which this child might or might not be
1564 in. The waiter will only wake up if it's argument is -1
1565 or if it's waiting for tcp->pid's pgrp. It makes a
1566 difference to wake up a waiter when there might be more
1567 traced children, because it could get a false ECHILD
1568 error. OTOH, if this was the last child in the pgrp, then
1569 it ought to wake up and get ECHILD. We would have to
1570 search the system for all pid's in the pgrp to be sure.
1571
1572 && (t->waitpid == -1 ||
1573 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1574 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1575 */
1576
1577 if (tcp->parent &&
1578 (tcp->parent->flags & TCB_SUSPENDED) &&
1579 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001580 error = resume(tcp->parent);
Roland McGrath1bfd3102007-08-03 10:02:00 +00001581 ++resumed;
1582 }
1583#ifdef TCB_CLONE_THREAD
1584 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1585 /* Some other threads of our parent are waiting too. */
1586 unsigned int i;
1587
1588 /* Resume all the threads that were waiting for this PID. */
1589 for (i = 0; i < tcbtabsize; i++) {
1590 struct tcb *t = tcbtab[i];
1591 if (t->parent == tcp->parent && t != tcp
1592 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1593 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1594 && t->waitpid == tcp->pid) {
1595 error |= resume (t);
1596 ++resumed;
1597 }
1598 }
1599 if (resumed == 0)
1600 /* Noone was waiting for this PID in particular,
1601 so now we might need to resume some wildcarders. */
1602 for (i = 0; i < tcbtabsize; i++) {
1603 struct tcb *t = tcbtab[i];
1604 if (t->parent == tcp->parent && t != tcp
1605 && ((t->flags
1606 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1607 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1608 && t->waitpid <= 0
1609 ) {
1610 error |= resume (t);
1611 break;
1612 }
1613 }
1614 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001615#endif
Roland McGrath1bfd3102007-08-03 10:02:00 +00001616
1617 return error;
1618}
Roland McGrath1bfd3102007-08-03 10:02:00 +00001619
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001620#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001621
Roland McGrath0a463882007-07-05 18:43:16 +00001622/* detach traced process; continue with sig
1623 Never call DETACH twice on the same process as both unattached and
1624 attached-unstopped processes give the same ESRCH. For unattached process we
1625 would SIGSTOP it and wait for its SIGSTOP notification forever. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001626
1627static int
1628detach(tcp, sig)
1629struct tcb *tcp;
1630int sig;
1631{
1632 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001633#ifdef LINUX
Roland McGrath1bfd3102007-08-03 10:02:00 +00001634 int status, catch_sigstop;
Roland McGratha08a97e2005-08-03 11:23:46 +00001635 struct tcb *zombie = NULL;
1636
1637 /* If the group leader is lingering only because of this other
1638 thread now dying, then detach the leader as well. */
1639 if ((tcp->flags & TCB_CLONE_THREAD) &&
1640 tcp->parent->nclone_threads == 1 &&
1641 (tcp->parent->flags & TCB_EXITING))
1642 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001643#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001644
1645 if (tcp->flags & TCB_BPTSET)
Andreas Schwab840d85b2010-01-12 11:16:32 +01001646 clearbpt(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001647
1648#ifdef LINUX
1649 /*
1650 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001651 * before detaching. Arghh. We go through hoops
1652 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001653 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001654#if defined(SPARC)
1655#undef PTRACE_DETACH
1656#define PTRACE_DETACH PTRACE_SUNDETACH
1657#endif
Roland McGrath02203312007-06-11 22:06:31 +00001658 /*
1659 * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
1660 * expected SIGSTOP. We must catch exactly one as otherwise the
1661 * detached process would be left stopped (process state T).
1662 */
1663 catch_sigstop = (tcp->flags & TCB_STARTUP);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001664 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1665 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001666 }
1667 else if (errno != ESRCH) {
1668 /* Shouldn't happen. */
1669 perror("detach: ptrace(PTRACE_DETACH, ...)");
1670 }
Roland McGrath134813a2007-06-02 00:07:33 +00001671 else if (my_tgkill((tcp->flags & TCB_CLONE_THREAD ? tcp->parent->pid
1672 : tcp->pid),
1673 tcp->pid, 0) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001674 if (errno != ESRCH)
1675 perror("detach: checking sanity");
1676 }
Roland McGrath02203312007-06-11 22:06:31 +00001677 else if (!catch_sigstop && my_tgkill((tcp->flags & TCB_CLONE_THREAD
1678 ? tcp->parent->pid : tcp->pid),
1679 tcp->pid, SIGSTOP) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001680 if (errno != ESRCH)
1681 perror("detach: stopping child");
1682 }
Roland McGrath02203312007-06-11 22:06:31 +00001683 else
1684 catch_sigstop = 1;
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001685 if (catch_sigstop) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001686 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001687#ifdef __WALL
1688 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1689 if (errno == ECHILD) /* Already gone. */
1690 break;
1691 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001692 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001693 break;
1694 }
1695#endif /* __WALL */
1696 /* No __WALL here. */
1697 if (waitpid(tcp->pid, &status, 0) < 0) {
1698 if (errno != ECHILD) {
1699 perror("detach: waiting");
1700 break;
1701 }
1702#ifdef __WCLONE
1703 /* If no processes, try clones. */
1704 if (wait4(tcp->pid, &status, __WCLONE,
1705 NULL) < 0) {
1706 if (errno != ECHILD)
1707 perror("detach: waiting");
1708 break;
1709 }
1710#endif /* __WCLONE */
1711 }
1712#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001713 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001714#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001715 if (!WIFSTOPPED(status)) {
1716 /* Au revoir, mon ami. */
1717 break;
1718 }
1719 if (WSTOPSIG(status) == SIGSTOP) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001720 ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001721 break;
1722 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001723 error = ptrace_restart(PTRACE_CONT, tcp,
Roland McGratheb9e2e82009-06-02 16:49:22 -07001724 WSTOPSIG(status) == SIGTRAP ? 0
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001725 : WSTOPSIG(status));
1726 if (error < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001727 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001728 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001729 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001730#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001731
1732#if defined(SUNOS4)
1733 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1734 if (sig && kill(tcp->pid, sig) < 0)
1735 perror("detach: kill");
1736 sig = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001737 error = ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001738#endif /* SUNOS4 */
1739
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001740#ifndef USE_PROCFS
Roland McGrath1bfd3102007-08-03 10:02:00 +00001741 error |= resume_from_tcp (tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001742#endif
1743
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001744 if (!qflag)
1745 fprintf(stderr, "Process %u detached\n", tcp->pid);
1746
1747 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001748
1749#ifdef LINUX
Roland McGrath0a463882007-07-05 18:43:16 +00001750 if (zombie != NULL) {
1751 /* TCP no longer exists therefore you must not detach () it. */
1752 droptcb(zombie);
1753 }
Roland McGratha08a97e2005-08-03 11:23:46 +00001754#endif
1755
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001756 return error;
1757}
1758
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001759#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001760
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001761static void reaper(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001762{
1763 int pid;
1764 int status;
1765
1766 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001767 }
1768}
1769
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001770#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001771
1772static void
1773cleanup()
1774{
1775 int i;
1776 struct tcb *tcp;
1777
Roland McGrathee9d4352002-12-18 04:16:10 +00001778 for (i = 0; i < tcbtabsize; i++) {
1779 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001780 if (!(tcp->flags & TCB_INUSE))
1781 continue;
1782 if (debug)
1783 fprintf(stderr,
1784 "cleanup: looking at pid %u\n", tcp->pid);
1785 if (tcp_last &&
1786 (!outfname || followfork < 2 || tcp_last == tcp)) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001787 tprintf(" <unfinished ...>");
1788 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001789 }
1790 if (tcp->flags & TCB_ATTACHED)
1791 detach(tcp, 0);
1792 else {
1793 kill(tcp->pid, SIGCONT);
1794 kill(tcp->pid, SIGTERM);
1795 }
1796 }
1797 if (cflag)
1798 call_summary(outf);
1799}
1800
1801static void
1802interrupt(sig)
1803int sig;
1804{
1805 interrupted = 1;
1806}
1807
1808#ifndef HAVE_STRERROR
1809
Roland McGrath6d2b3492002-12-30 00:51:30 +00001810#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001811extern int sys_nerr;
1812extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001813#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001814
1815const char *
1816strerror(errno)
1817int errno;
1818{
1819 static char buf[64];
1820
1821 if (errno < 1 || errno >= sys_nerr) {
1822 sprintf(buf, "Unknown error %d", errno);
1823 return buf;
1824 }
1825 return sys_errlist[errno];
1826}
1827
1828#endif /* HAVE_STERRROR */
1829
1830#ifndef HAVE_STRSIGNAL
1831
Roland McGrath8f474e02003-01-14 07:53:33 +00001832#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001833extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001834#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001835#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1836extern char *_sys_siglist[];
1837#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001838
1839const char *
1840strsignal(sig)
1841int sig;
1842{
1843 static char buf[64];
1844
1845 if (sig < 1 || sig >= NSIG) {
1846 sprintf(buf, "Unknown signal %d", sig);
1847 return buf;
1848 }
1849#ifdef HAVE__SYS_SIGLIST
1850 return _sys_siglist[sig];
1851#else
1852 return sys_siglist[sig];
1853#endif
1854}
1855
1856#endif /* HAVE_STRSIGNAL */
1857
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001858#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001859
1860static void
1861rebuild_pollv()
1862{
1863 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001864
Roland McGrathee9d4352002-12-18 04:16:10 +00001865 if (pollv != NULL)
1866 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001867 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001868 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001869 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00001870 exit(1);
1871 }
1872
Roland McGrathca16be82003-01-10 19:55:28 +00001873 for (i = j = 0; i < tcbtabsize; i++) {
1874 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001875 if (!(tcp->flags & TCB_INUSE))
1876 continue;
1877 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001878 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001879 j++;
1880 }
1881 if (j != nprocs) {
1882 fprintf(stderr, "strace: proc miscount\n");
1883 exit(1);
1884 }
1885}
1886
1887#ifndef HAVE_POLLABLE_PROCFS
1888
1889static void
1890proc_poll_open()
1891{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001892 int i;
1893
1894 if (pipe(proc_poll_pipe) < 0) {
1895 perror("pipe");
1896 exit(1);
1897 }
1898 for (i = 0; i < 2; i++) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001899 if (set_cloexec_flag(proc_poll_pipe[i]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001900 exit(1);
1901 }
1902 }
1903}
1904
1905static int
1906proc_poll(pollv, nfds, timeout)
1907struct pollfd *pollv;
1908int nfds;
1909int timeout;
1910{
1911 int i;
1912 int n;
1913 struct proc_pollfd pollinfo;
1914
1915 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1916 return n;
1917 if (n != sizeof(struct proc_pollfd)) {
1918 fprintf(stderr, "panic: short read: %d\n", n);
1919 exit(1);
1920 }
1921 for (i = 0; i < nprocs; i++) {
1922 if (pollv[i].fd == pollinfo.fd)
1923 pollv[i].revents = pollinfo.revents;
1924 else
1925 pollv[i].revents = 0;
1926 }
1927 poller_pid = pollinfo.pid;
1928 return 1;
1929}
1930
1931static void
1932wakeup_handler(sig)
1933int sig;
1934{
1935}
1936
1937static void
1938proc_poller(pfd)
1939int pfd;
1940{
1941 struct proc_pollfd pollinfo;
1942 struct sigaction sa;
1943 sigset_t blocked_set, empty_set;
1944 int i;
1945 int n;
1946 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001947#ifdef FREEBSD
1948 struct procfs_status pfs;
1949#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001950
1951 switch (fork()) {
1952 case -1:
1953 perror("fork");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001954 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001955 case 0:
1956 break;
1957 default:
1958 return;
1959 }
1960
1961 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1962 sa.sa_flags = 0;
1963 sigemptyset(&sa.sa_mask);
1964 sigaction(SIGHUP, &sa, NULL);
1965 sigaction(SIGINT, &sa, NULL);
1966 sigaction(SIGQUIT, &sa, NULL);
1967 sigaction(SIGPIPE, &sa, NULL);
1968 sigaction(SIGTERM, &sa, NULL);
1969 sa.sa_handler = wakeup_handler;
1970 sigaction(SIGUSR1, &sa, NULL);
1971 sigemptyset(&blocked_set);
1972 sigaddset(&blocked_set, SIGUSR1);
1973 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1974 sigemptyset(&empty_set);
1975
1976 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1977 perror("getrlimit(RLIMIT_NOFILE, ...)");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001978 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001979 }
1980 n = rl.rlim_cur;
1981 for (i = 0; i < n; i++) {
1982 if (i != pfd && i != proc_poll_pipe[1])
1983 close(i);
1984 }
1985
1986 pollinfo.fd = pfd;
1987 pollinfo.pid = getpid();
1988 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001989#ifndef FREEBSD
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001990 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1991#else
1992 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1993#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001994 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001995 switch (errno) {
1996 case EINTR:
1997 continue;
1998 case EBADF:
1999 pollinfo.revents = POLLERR;
2000 break;
2001 case ENOENT:
2002 pollinfo.revents = POLLHUP;
2003 break;
2004 default:
2005 perror("proc_poller: PIOCWSTOP");
2006 }
2007 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2008 _exit(0);
2009 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002010 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002011 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2012 sigsuspend(&empty_set);
2013 }
2014}
2015
2016#endif /* !HAVE_POLLABLE_PROCFS */
2017
2018static int
2019choose_pfd()
2020{
2021 int i, j;
2022 struct tcb *tcp;
2023
2024 static int last;
2025
2026 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002027 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002028 /*
2029 * The previous process is ready to run again. We'll
2030 * let it do so if it is currently in a syscall. This
2031 * heuristic improves the readability of the trace.
2032 */
2033 tcp = pfd2tcb(pollv[last].fd);
2034 if (tcp && (tcp->flags & TCB_INSYSCALL))
2035 return pollv[last].fd;
2036 }
2037
2038 for (i = 0; i < nprocs; i++) {
2039 /* Let competing children run round robin. */
2040 j = (i + last + 1) % nprocs;
2041 if (pollv[j].revents & (POLLHUP | POLLERR)) {
2042 tcp = pfd2tcb(pollv[j].fd);
2043 if (!tcp) {
2044 fprintf(stderr, "strace: lost proc\n");
2045 exit(1);
2046 }
2047 droptcb(tcp);
2048 return -1;
2049 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002050 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002051 last = j;
2052 return pollv[j].fd;
2053 }
2054 }
2055 fprintf(stderr, "strace: nothing ready\n");
2056 exit(1);
2057}
2058
2059static int
2060trace()
2061{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002062#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00002063 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002064#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002065 struct tcb *tcp;
2066 int pfd;
2067 int what;
2068 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002069 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002070
2071 for (;;) {
2072 if (interactive)
2073 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2074
2075 if (nprocs == 0)
2076 break;
2077
2078 switch (nprocs) {
2079 case 1:
2080#ifndef HAVE_POLLABLE_PROCFS
2081 if (proc_poll_pipe[0] == -1) {
2082#endif
Roland McGrath54e931f2010-09-14 18:59:20 -07002083 tcp = first_used_tcb();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002084 if (!tcp)
2085 continue;
2086 pfd = tcp->pfd;
2087 if (pfd == -1)
2088 continue;
2089 break;
2090#ifndef HAVE_POLLABLE_PROCFS
2091 }
2092 /* fall through ... */
2093#endif /* !HAVE_POLLABLE_PROCFS */
2094 default:
2095#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002096#ifdef POLL_HACK
2097 /* On some systems (e.g. UnixWare) we get too much ugly
2098 "unfinished..." stuff when multiple proceses are in
2099 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00002100
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002101 if (in_syscall) {
2102 struct pollfd pv;
2103 tcp = in_syscall;
2104 in_syscall = NULL;
2105 pv.fd = tcp->pfd;
2106 pv.events = POLLWANT;
2107 if ((what = poll (&pv, 1, 1)) < 0) {
2108 if (interrupted)
2109 return 0;
2110 continue;
2111 }
2112 else if (what == 1 && pv.revents & POLLWANT) {
2113 goto FOUND;
2114 }
2115 }
2116#endif
2117
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002118 if (poll(pollv, nprocs, INFTIM) < 0) {
2119 if (interrupted)
2120 return 0;
2121 continue;
2122 }
2123#else /* !HAVE_POLLABLE_PROCFS */
2124 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
2125 if (interrupted)
2126 return 0;
2127 continue;
2128 }
2129#endif /* !HAVE_POLLABLE_PROCFS */
2130 pfd = choose_pfd();
2131 if (pfd == -1)
2132 continue;
2133 break;
2134 }
2135
2136 /* Look up `pfd' in our table. */
2137 if ((tcp = pfd2tcb(pfd)) == NULL) {
2138 fprintf(stderr, "unknown pfd: %u\n", pfd);
2139 exit(1);
2140 }
John Hughesb6643082002-05-23 11:02:22 +00002141#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002142 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00002143#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002144 /* Get the status of the process. */
2145 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002146#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002147 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002148#else /* FREEBSD */
2149 /* Thanks to some scheduling mystery, the first poller
2150 sometimes waits for the already processed end of fork
2151 event. Doing a non blocking poll here solves the problem. */
2152 if (proc_poll_pipe[0] != -1)
2153 ioctl_result = IOCTL_STATUS (tcp);
2154 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002155 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00002156#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002157 ioctl_errno = errno;
2158#ifndef HAVE_POLLABLE_PROCFS
2159 if (proc_poll_pipe[0] != -1) {
2160 if (ioctl_result < 0)
2161 kill(poller_pid, SIGKILL);
2162 else
2163 kill(poller_pid, SIGUSR1);
2164 }
2165#endif /* !HAVE_POLLABLE_PROCFS */
2166 }
2167 if (interrupted)
2168 return 0;
2169
2170 if (interactive)
2171 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2172
2173 if (ioctl_result < 0) {
2174 /* Find out what happened if it failed. */
2175 switch (ioctl_errno) {
2176 case EINTR:
2177 case EBADF:
2178 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002179#ifdef FREEBSD
2180 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00002181#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002182 case ENOENT:
2183 droptcb(tcp);
2184 continue;
2185 default:
2186 perror("PIOCWSTOP");
2187 exit(1);
2188 }
2189 }
2190
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002191#ifdef FREEBSD
2192 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2193 /* discard first event for a syscall we never entered */
2194 IOCTL (tcp->pfd, PIOCRUN, 0);
2195 continue;
2196 }
Roland McGrath553a6092002-12-16 20:40:39 +00002197#endif
2198
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002199 /* clear the just started flag */
2200 tcp->flags &= ~TCB_STARTUP;
2201
2202 /* set current output file */
2203 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002204 curcol = tcp->curcol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002205
2206 if (cflag) {
2207 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002208#ifdef FREEBSD
2209 char buf[1024];
2210 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002211
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002212 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
2213 buf[len] = '\0';
2214 sscanf(buf,
2215 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2216 &stime.tv_sec, &stime.tv_usec);
2217 } else
2218 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002219#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002220 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2221 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002222#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002223 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2224 tcp->stime = stime;
2225 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002226 what = tcp->status.PR_WHAT;
2227 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002228#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002229 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002230 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2231 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002232 if (trace_syscall(tcp) < 0) {
2233 fprintf(stderr, "syscall trouble\n");
2234 exit(1);
2235 }
2236 }
2237 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002238#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002239 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002240#ifdef POLL_HACK
2241 in_syscall = tcp;
2242#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002243 case PR_SYSEXIT:
2244 if (trace_syscall(tcp) < 0) {
2245 fprintf(stderr, "syscall trouble\n");
2246 exit(1);
2247 }
2248 break;
2249 case PR_SIGNALLED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002250 if (cflag != CFLAG_ONLY_STATS
2251 && (qual_flags[what] & QUAL_SIGNAL)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002252 printleader(tcp);
2253 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002254 signame(what), strsignal(what));
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002255 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002256#ifdef PR_INFO
2257 if (tcp->status.PR_INFO.si_signo == what) {
2258 printleader(tcp);
2259 tprintf(" siginfo=");
2260 printsiginfo(&tcp->status.PR_INFO, 1);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002261 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002262 }
2263#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002264 }
2265 break;
2266 case PR_FAULTED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002267 if (cflag != CFLAGS_ONLY_STATS
2268 && (qual_flags[what] & QUAL_FAULT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002269 printleader(tcp);
2270 tprintf("=== FAULT %d ===", what);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002271 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002272 }
2273 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002274#ifdef FREEBSD
2275 case 0: /* handle case we polled for nothing */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002276 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00002277#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002278 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002279 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002280 exit(1);
2281 break;
2282 }
Andreas Schwabccdff482009-10-27 16:27:13 +01002283 /* Remember current print column before continuing. */
2284 tcp->curcol = curcol;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002285 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002286#ifndef FREEBSD
Andreas Schwab372cc842010-07-09 11:49:27 +02002287 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002288#else
Andreas Schwab372cc842010-07-09 11:49:27 +02002289 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002290#endif
Andreas Schwab372cc842010-07-09 11:49:27 +02002291 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002292 perror("PIOCRUN");
2293 exit(1);
2294 }
2295 }
2296 return 0;
2297}
2298
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002299#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002300
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002301#ifdef TCB_GROUP_EXITING
2302/* Handle an exit detach or death signal that is taking all the
2303 related clone threads with it. This is called in three circumstances:
2304 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
2305 SIG == 0 Continuing TCP will perform an exit_group syscall.
2306 SIG == other Continuing TCP with SIG will kill the process.
2307*/
2308static int
2309handle_group_exit(struct tcb *tcp, int sig)
2310{
2311 /* We need to locate our records of all the clone threads
2312 related to TCP, either its children or siblings. */
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002313 struct tcb *leader = NULL;
2314
2315 if (tcp->flags & TCB_CLONE_THREAD)
2316 leader = tcp->parent;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002317
2318 if (sig < 0) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002319 if (leader != NULL && leader != tcp
2320 && !(leader->flags & TCB_GROUP_EXITING)
2321 && !(tcp->flags & TCB_STARTUP)
2322 ) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002323 fprintf(stderr,
2324 "PANIC: handle_group_exit: %d leader %d\n",
2325 tcp->pid, leader ? leader->pid : -1);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002326 }
2327 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath1bfd3102007-08-03 10:02:00 +00002328#ifndef USE_PROCFS
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002329 resume_from_tcp(tcp);
Roland McGrath1bfd3102007-08-03 10:02:00 +00002330#endif
Roland McGrath0a463882007-07-05 18:43:16 +00002331 droptcb(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002332 }
2333 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00002334 /* Mark that we are taking the process down. */
2335 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002336 if (tcp->flags & TCB_ATTACHED) {
Roland McGrathd6a32f12007-07-11 08:35:11 +00002337 detach(tcp, sig);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002338 if (leader != NULL && leader != tcp)
Roland McGrath1bfd3102007-08-03 10:02:00 +00002339 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002340 } else {
2341 if (ptrace_restart(PTRACE_CONT, tcp, sig) < 0) {
2342 cleanup();
2343 return -1;
2344 }
2345 if (leader != NULL) {
Roland McGrath05690952004-10-20 01:00:27 +00002346 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002347 if (leader != tcp)
2348 droptcb(tcp);
2349 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002350 /* The leader will report to us as parent now,
2351 and then we'll get to the SIG==-1 case. */
2352 return 0;
2353 }
2354 }
2355
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002356 return 0;
2357}
2358#endif
2359
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002360#ifdef LINUX
2361static int
2362handle_ptrace_event(int status, struct tcb *tcp)
2363{
2364 if (status >> 16 == PTRACE_EVENT_VFORK ||
2365 status >> 16 == PTRACE_EVENT_CLONE ||
2366 status >> 16 == PTRACE_EVENT_FORK) {
2367 int childpid;
2368
2369 if (do_ptrace(PTRACE_GETEVENTMSG, tcp, NULL, &childpid) < 0) {
2370 if (errno != ESRCH) {
2371 fprintf(stderr, "\
2372%s: handle_ptrace_event: ptrace cannot get new child's pid\n",
2373 progname);
2374 cleanup();
2375 exit(1);
2376 }
2377 return -1;
2378 }
2379 return handle_new_child(tcp, childpid, 0);
2380 }
2381 return 1;
2382}
2383#endif
2384
Roland McGratheb9e2e82009-06-02 16:49:22 -07002385static int
2386trace()
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002387{
2388 int pid;
2389 int wait_errno;
2390 int status;
2391 struct tcb *tcp;
2392#ifdef LINUX
2393 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002394#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002395 static int wait4_options = __WALL;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002396#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002397#endif /* LINUX */
2398
Roland McGratheb9e2e82009-06-02 16:49:22 -07002399 while (nprocs != 0) {
Denys Vlasenko222713a2009-03-17 14:29:59 +00002400 if (interrupted)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002401 return 0;
2402 if (interactive)
2403 sigprocmask(SIG_SETMASK, &empty_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002404#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002405#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002406 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002407 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002408 /* this kernel does not support __WALL */
2409 wait4_options &= ~__WALL;
2410 errno = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002411 pid = wait4(-1, &status, wait4_options,
2412 cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002413 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002414 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002415 /* most likely a "cloned" process */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002416 pid = wait4(-1, &status, __WCLONE,
2417 cflag ? &ru : NULL);
2418 if (pid == -1) {
2419 fprintf(stderr, "strace: clone wait4 "
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002420 "failed: %s\n", strerror(errno));
2421 }
2422 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002423#else
2424 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
2425#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002426#endif /* LINUX */
2427#ifdef SUNOS4
2428 pid = wait(&status);
2429#endif /* SUNOS4 */
2430 wait_errno = errno;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002431 if (interactive)
2432 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002433
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002434 if (pid == -1) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002435 switch (wait_errno) {
2436 case EINTR:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002437 continue;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002438 case ECHILD:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002439 /*
2440 * We would like to verify this case
2441 * but sometimes a race in Solbourne's
2442 * version of SunOS sometimes reports
2443 * ECHILD before sending us SIGCHILD.
2444 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002445 return 0;
2446 default:
2447 errno = wait_errno;
2448 perror("strace: wait");
2449 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002450 }
2451 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002452 if (pid == popen_pid) {
2453 if (WIFEXITED(status) || WIFSIGNALED(status))
2454 popen_pid = -1;
2455 continue;
2456 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002457 if (debug)
2458 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2459
2460 /* Look up `pid' in our table. */
2461 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002462#ifdef LINUX
Roland McGrath41c48222008-07-18 00:25:10 +00002463 if (followfork) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002464 /* This is needed to go with the CLONE_PTRACE
2465 changes in process.c/util.c: we might see
2466 the child's initial trap before we see the
2467 parent return from the clone syscall.
2468 Leave the child suspended until the parent
2469 returns from its system call. Only then
2470 will we have the association of parent and
2471 child so that we know how to do clearbpt
2472 in the child. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +00002473 tcp = alloctcb(pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002474 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002475 if (!qflag)
2476 fprintf(stderr, "\
2477Process %d attached (waiting for parent)\n",
2478 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002479 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002480 else
2481 /* This can happen if a clone call used
2482 CLONE_PTRACE itself. */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002483#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002484 {
2485 fprintf(stderr, "unknown pid: %u\n", pid);
2486 if (WIFSTOPPED(status))
2487 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2488 exit(1);
2489 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002490 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002491 /* set current output file */
2492 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002493 curcol = tcp->curcol;
Denys Vlasenko84e20af2009-02-10 16:03:20 +00002494 if (cflag) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002495#ifdef LINUX
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002496 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2497 tcp->stime = ru.ru_stime;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002498#endif /* !LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002499 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002500
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002501 if (tcp->flags & TCB_SUSPENDED) {
2502 /*
2503 * Apparently, doing any ptrace() call on a stopped
2504 * process, provokes the kernel to report the process
2505 * status again on a subsequent wait(), even if the
2506 * process has not been actually restarted.
2507 * Since we have inspected the arguments of suspended
2508 * processes we end up here testing for this case.
2509 */
2510 continue;
2511 }
2512 if (WIFSIGNALED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002513 if (pid == strace_child)
2514 exit_code = 0x100 | WTERMSIG(status);
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002515 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002516 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2517 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002518 tprintf("+++ killed by %s %s+++",
2519 signame(WTERMSIG(status)),
2520#ifdef WCOREDUMP
2521 WCOREDUMP(status) ? "(core dumped) " :
2522#endif
2523 "");
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002524 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002525 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002526#ifdef TCB_GROUP_EXITING
2527 handle_group_exit(tcp, -1);
2528#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002529 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002530#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002531 continue;
2532 }
2533 if (WIFEXITED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002534 if (pid == strace_child)
2535 exit_code = WEXITSTATUS(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002536 if (debug)
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002537 fprintf(stderr, "pid %u exited with %d\n", pid, WEXITSTATUS(status));
2538 if ((tcp->flags & (TCB_ATTACHED|TCB_STARTUP)) == TCB_ATTACHED
Roland McGrath05690952004-10-20 01:00:27 +00002539#ifdef TCB_GROUP_EXITING
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002540 && !(tcp->parent && (tcp->parent->flags & TCB_GROUP_EXITING))
Roland McGrath1bfd3102007-08-03 10:02:00 +00002541 && !(tcp->flags & TCB_GROUP_EXITING)
Roland McGrath05690952004-10-20 01:00:27 +00002542#endif
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002543 ) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002544 fprintf(stderr,
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002545 "PANIC: attached pid %u exited with %d\n",
2546 pid, WEXITSTATUS(status));
2547 }
Roland McGrath0a396902003-06-10 03:05:53 +00002548 if (tcp == tcp_last) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002549 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT)) == TCB_INSYSCALL)
Roland McGrath0a396902003-06-10 03:05:53 +00002550 tprintf(" <unfinished ... exit status %d>\n",
2551 WEXITSTATUS(status));
2552 tcp_last = NULL;
2553 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002554#ifdef TCB_GROUP_EXITING
2555 handle_group_exit(tcp, -1);
2556#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002557 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002558#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002559 continue;
2560 }
2561 if (!WIFSTOPPED(status)) {
2562 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2563 droptcb(tcp);
2564 continue;
2565 }
2566 if (debug)
2567 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002568 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002569
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002570 if (ptrace_setoptions && (status >> 16)) {
2571 if (handle_ptrace_event(status, tcp) != 1)
2572 goto tracing;
2573 }
2574
Roland McGrath02203312007-06-11 22:06:31 +00002575 /*
2576 * Interestingly, the process may stop
2577 * with STOPSIG equal to some other signal
Roland McGratheb9e2e82009-06-02 16:49:22 -07002578 * than SIGSTOP if we happend to attach
Roland McGrath02203312007-06-11 22:06:31 +00002579 * just before the process takes a signal.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002580 * A no-MMU vforked child won't send up a signal,
2581 * so skip the first (lost) execve notification.
Roland McGrath02203312007-06-11 22:06:31 +00002582 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002583 if ((tcp->flags & TCB_STARTUP) &&
2584 (WSTOPSIG(status) == SIGSTOP || strace_vforked)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002585 /*
2586 * This flag is there to keep us in sync.
2587 * Next time this process stops it should
2588 * really be entering a system call.
2589 */
2590 tcp->flags &= ~TCB_STARTUP;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002591 if (tcp->flags & TCB_BPTSET) {
Roland McGrath02203312007-06-11 22:06:31 +00002592 /*
2593 * One example is a breakpoint inherited from
2594 * parent through fork ().
2595 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002596 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2597 droptcb(tcp);
2598 cleanup();
2599 return -1;
2600 }
2601 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002602#ifdef LINUX
2603 if (followfork && (tcp->parent == NULL) && ptrace_setoptions)
2604 if (ptrace(PTRACE_SETOPTIONS, tcp->pid,
2605 NULL, ptrace_setoptions) < 0 &&
2606 errno != ESRCH)
2607 ptrace_setoptions = 0;
2608#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002609 goto tracing;
2610 }
2611
Roland McGratheb9e2e82009-06-02 16:49:22 -07002612 if (WSTOPSIG(status) != SIGTRAP) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002613 if (WSTOPSIG(status) == SIGSTOP &&
2614 (tcp->flags & TCB_SIGTRAPPED)) {
2615 /*
2616 * Trapped attempt to block SIGTRAP
2617 * Hope we are back in control now.
2618 */
2619 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002620 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002621 cleanup();
2622 return -1;
2623 }
2624 continue;
2625 }
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002626 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002627 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00002628 unsigned long addr = 0;
2629 long pc = 0;
Dmitry V. Levin96339422006-10-11 23:11:43 +00002630#if defined(PT_CR_IPSR) && defined(PT_CR_IIP) && defined(PT_GETSIGINFO)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002631# define PSR_RI 41
2632 struct siginfo si;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002633 long psr;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002634
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002635 upeek(tcp, PT_CR_IPSR, &psr);
2636 upeek(tcp, PT_CR_IIP, &pc);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002637
2638 pc += (psr >> PSR_RI) & 0x3;
2639 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2640 addr = (unsigned long) si.si_addr;
Roland McGrath3a055d72005-03-06 22:24:29 +00002641#elif defined PTRACE_GETSIGINFO
2642 if (WSTOPSIG(status) == SIGSEGV ||
2643 WSTOPSIG(status) == SIGBUS) {
2644 siginfo_t si;
2645 if (ptrace(PTRACE_GETSIGINFO, pid,
2646 0, &si) == 0)
2647 addr = (unsigned long)
2648 si.si_addr;
2649 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002650#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002651 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002652 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002653 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002654 strsignal(WSTOPSIG(status)), pc, addr);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002655 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002656 }
Roland McGrath05690952004-10-20 01:00:27 +00002657 if (((tcp->flags & TCB_ATTACHED) ||
2658 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002659 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002660#ifdef TCB_GROUP_EXITING
2661 handle_group_exit(tcp, WSTOPSIG(status));
2662#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002663 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002664#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002665 continue;
2666 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002667 if (ptrace_restart(PTRACE_SYSCALL, tcp, WSTOPSIG(status)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002668 cleanup();
2669 return -1;
2670 }
2671 tcp->flags &= ~TCB_SUSPENDED;
2672 continue;
2673 }
Roland McGrath02203312007-06-11 22:06:31 +00002674 /* we handled the STATUS, we are permitted to interrupt now. */
2675 if (interrupted)
2676 return 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002677 if (trace_syscall(tcp) < 0 && !tcp->ptrace_errno) {
2678 /* ptrace() failed in trace_syscall() with ESRCH.
2679 * Likely a result of process disappearing mid-flight.
2680 * Observed case: exit_group() terminating
2681 * all processes in thread group. In this case, threads
2682 * "disappear" in an unpredictable moment without any
2683 * notification to strace via wait().
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002684 */
2685 if (tcp->flags & TCB_ATTACHED) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002686 if (tcp_last) {
2687 /* Do we have dangling line "syscall(param, param"?
2688 * Finish the line then. We cannot
2689 */
2690 tcp_last->flags |= TCB_REPRINT;
2691 tprintf(" <unfinished ...>");
2692 printtrailer();
2693 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002694 detach(tcp, 0);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002695 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002696 ptrace(PTRACE_KILL,
2697 tcp->pid, (char *) 1, SIGTERM);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002698 droptcb(tcp);
2699 }
2700 continue;
2701 }
2702 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002703#ifdef TCB_GROUP_EXITING
2704 if (tcp->flags & TCB_GROUP_EXITING) {
2705 if (handle_group_exit(tcp, 0) < 0)
2706 return -1;
2707 continue;
2708 }
2709#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002710 if (tcp->flags & TCB_ATTACHED)
2711 detach(tcp, 0);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002712 else if (ptrace_restart(PTRACE_CONT, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002713 cleanup();
2714 return -1;
2715 }
2716 continue;
2717 }
2718 if (tcp->flags & TCB_SUSPENDED) {
2719 if (!qflag)
2720 fprintf(stderr, "Process %u suspended\n", pid);
2721 continue;
2722 }
2723 tracing:
Andreas Schwabccdff482009-10-27 16:27:13 +01002724 /* Remember current print column before continuing. */
2725 tcp->curcol = curcol;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002726 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002727 cleanup();
2728 return -1;
2729 }
2730 }
2731 return 0;
2732}
2733
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002734#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002735
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002736#include <stdarg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002737
2738void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002739tprintf(const char *fmt, ...)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002740{
2741 va_list args;
2742
Andreas Schwabe5355de2009-10-27 16:56:43 +01002743 va_start(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002744 if (outf) {
2745 int n = vfprintf(outf, fmt, args);
Andreas Schwabccdff482009-10-27 16:27:13 +01002746 if (n < 0) {
2747 if (outf != stderr)
2748 perror(outfname == NULL
2749 ? "<writing to pipe>" : outfname);
2750 } else
Roland McGrathb310a0c2003-11-06 23:41:22 +00002751 curcol += n;
2752 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002753 va_end(args);
2754 return;
2755}
2756
2757void
Roland McGratheb9e2e82009-06-02 16:49:22 -07002758printleader(tcp)
2759struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002760{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002761 if (tcp_last) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002762 if (tcp_last->ptrace_errno) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002763 if (tcp_last->flags & TCB_INSYSCALL) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002764 tprintf(" <unavailable>)");
2765 tabto(acolumn);
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002766 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002767 tprintf("= ? <unavailable>\n");
2768 tcp_last->ptrace_errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002769 } else if (!outfname || followfork < 2 || tcp_last == tcp) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002770 tcp_last->flags |= TCB_REPRINT;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002771 tprintf(" <unfinished ...>\n");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002772 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002773 }
2774 curcol = 0;
2775 if ((followfork == 1 || pflag_seen > 1) && outfname)
2776 tprintf("%-5d ", tcp->pid);
2777 else if (nprocs > 1 && !outfname)
2778 tprintf("[pid %5u] ", tcp->pid);
2779 if (tflag) {
2780 char str[sizeof("HH:MM:SS")];
2781 struct timeval tv, dtv;
2782 static struct timeval otv;
2783
2784 gettimeofday(&tv, NULL);
2785 if (rflag) {
2786 if (otv.tv_sec == 0)
2787 otv = tv;
2788 tv_sub(&dtv, &tv, &otv);
2789 tprintf("%6ld.%06ld ",
2790 (long) dtv.tv_sec, (long) dtv.tv_usec);
2791 otv = tv;
2792 }
2793 else if (tflag > 2) {
2794 tprintf("%ld.%06ld ",
2795 (long) tv.tv_sec, (long) tv.tv_usec);
2796 }
2797 else {
2798 time_t local = tv.tv_sec;
2799 strftime(str, sizeof(str), "%T", localtime(&local));
2800 if (tflag > 1)
2801 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2802 else
2803 tprintf("%s ", str);
2804 }
2805 }
2806 if (iflag)
2807 printcall(tcp);
2808}
2809
2810void
2811tabto(col)
2812int col;
2813{
2814 if (curcol < col)
2815 tprintf("%*s", col - curcol, "");
2816}
2817
2818void
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002819printtrailer(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002820{
2821 tprintf("\n");
2822 tcp_last = NULL;
2823}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002824
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002825#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002826
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002827int
2828mp_ioctl(int fd, int cmd, void *arg, int size)
2829{
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002830 struct iovec iov[2];
2831 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002832
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002833 iov[0].iov_base = &cmd;
2834 iov[0].iov_len = sizeof cmd;
2835 if (arg) {
2836 ++n;
2837 iov[1].iov_base = arg;
2838 iov[1].iov_len = size;
2839 }
Roland McGrath553a6092002-12-16 20:40:39 +00002840
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002841 return writev(fd, iov, n);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002842}
2843
2844#endif