blob: 8dd73bea1a0c398f4868fd78256cf834918e883f [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>
Denys Vlasenko7e0615f2009-01-28 19:00:54 +000043#include <sys/utsname.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000044#include <pwd.h>
45#include <grp.h>
46#include <string.h>
John Hughes19e49982001-10-19 08:59:12 +000047#include <limits.h>
Roland McGrath70b08532004-04-09 00:25:21 +000048#include <dirent.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000049
Roland McGrath134813a2007-06-02 00:07:33 +000050#ifdef LINUX
51# include <asm/unistd.h>
52# if defined __NR_tgkill
53# define my_tgkill(pid, tid, sig) syscall (__NR_tgkill, (pid), (tid), (sig))
54# elif defined __NR_tkill
55# define my_tgkill(pid, tid, sig) syscall (__NR_tkill, (tid), (sig))
56# else
57 /* kill() may choose arbitrarily the target task of the process group
58 while we later wait on a that specific TID. PID process waits become
59 TID task specific waits for a process under ptrace(2). */
60# warning "Neither tkill(2) nor tgkill(2) available, risk of strace hangs!"
61# define my_tgkill(pid, tid, sig) kill ((tid), (sig))
62# endif
63#endif
64
Wichert Akkerman7b3346b2001-10-09 23:47:38 +000065#if defined(IA64) && defined(LINUX)
66# include <asm/ptrace_offsets.h>
67#endif
68
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +000069#ifdef USE_PROCFS
70#include <poll.h>
71#endif
72
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000073#ifdef SVR4
74#include <sys/stropts.h>
Wichert Akkermanea78f0f1999-11-29 15:34:02 +000075#ifdef HAVE_MP_PROCFS
John Hughes1d08dcf2001-07-10 13:48:44 +000076#ifdef HAVE_SYS_UIO_H
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000077#include <sys/uio.h>
78#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000079#endif
John Hughes1d08dcf2001-07-10 13:48:44 +000080#endif
Denys Vlasenko96d5a762008-12-29 19:13:27 +000081extern char **environ;
Denys Vlasenko418d66a2009-01-17 01:52:54 +000082extern int optind;
83extern char *optarg;
Denys Vlasenko96d5a762008-12-29 19:13:27 +000084
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000085
Roland McGrath41c48222008-07-18 00:25:10 +000086int debug = 0, followfork = 0;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +000087int dtime = 0, cflag = 0, xflag = 0, qflag = 0;
88static int iflag = 0, interactive = 0, pflag_seen = 0, rflag = 0, tflag = 0;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +000089/*
90 * daemonized_tracer supports -D option.
91 * With this option, strace forks twice.
92 * Unlike normal case, with -D *grandparent* process exec's,
93 * becoming a traced process. Child exits (this prevents traced process
94 * from having children it doesn't expect to have), and grandchild
95 * attaches to grandparent similarly to strace -p PID.
96 * This allows for more transparent interaction in cases
97 * when process and its parent are communicating via signals,
98 * wait() etc. Without -D, strace process gets lodged in between,
99 * disrupting parent<->child link.
100 */
101static bool daemonized_tracer = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000102
Denys Vlasenko7e0615f2009-01-28 19:00:54 +0000103static struct utsname utsname_buf;
104
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000105/* Sometimes we want to print only succeeding syscalls. */
106int not_failing_only = 0;
107
Dmitry V. Levina6809652008-11-10 17:14:58 +0000108static int exit_code = 0;
109static int strace_child = 0;
Denys Vlasenko96d5a762008-12-29 19:13:27 +0000110static int ptrace_stop_sig = SIGTRAP;
111static bool ptrace_opts_set;
Dmitry V. Levina6809652008-11-10 17:14:58 +0000112
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +0000113static char *username = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000114uid_t run_uid;
115gid_t run_gid;
116
117int acolumn = DEFAULT_ACOLUMN;
118int max_strlen = DEFAULT_STRLEN;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +0000119static char *outfname = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000120FILE *outf;
Roland McGrathee9d4352002-12-18 04:16:10 +0000121struct tcb **tcbtab;
122unsigned int nprocs, tcbtabsize;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000123char *progname;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000124
Roland McGrath0a463882007-07-05 18:43:16 +0000125static int detach P((struct tcb *tcp, int sig));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000126static int trace P((void));
127static void cleanup P((void));
128static void interrupt P((int sig));
129static sigset_t empty_set, blocked_set;
130
131#ifdef HAVE_SIG_ATOMIC_T
132static volatile sig_atomic_t interrupted;
133#else /* !HAVE_SIG_ATOMIC_T */
134#ifdef __STDC__
135static volatile int interrupted;
136#else /* !__STDC__ */
137static int interrupted;
138#endif /* !__STDC__ */
139#endif /* !HAVE_SIG_ATOMIC_T */
140
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000141#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000142
143static struct tcb *pfd2tcb P((int pfd));
144static void reaper P((int sig));
145static void rebuild_pollv P((void));
Roland McGrathee9d4352002-12-18 04:16:10 +0000146static struct pollfd *pollv;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000147
148#ifndef HAVE_POLLABLE_PROCFS
149
150static void proc_poll_open P((void));
151static void proc_poller P((int pfd));
152
153struct proc_pollfd {
154 int fd;
155 int revents;
156 int pid;
157};
158
159static int poller_pid;
160static int proc_poll_pipe[2] = { -1, -1 };
161
162#endif /* !HAVE_POLLABLE_PROCFS */
163
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000164#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000165#define POLLWANT POLLWRNORM
166#else
167#define POLLWANT POLLPRI
168#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000169#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000170
171static void
172usage(ofp, exitval)
173FILE *ofp;
174int exitval;
175{
176 fprintf(ofp, "\
177usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000178 [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n\
179 [command [arg ...]]\n\
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000180 or: strace -c -D [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000181 [command [arg ...]]\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000182-c -- count time, calls, and errors for each syscall and report summary\n\
183-f -- follow forks, -ff -- with output into separate files\n\
184-F -- attempt to follow vforks, -h -- print help message\n\
185-i -- print instruction pointer at time of syscall\n\
186-q -- suppress messages about attaching, detaching, etc.\n\
187-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
188-T -- print time spent in each syscall, -V -- print version\n\
189-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
190-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
191-a column -- alignment COLUMN for printing syscall results (default %d)\n\
192-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
193 options: trace, abbrev, verbose, raw, signal, read, or write\n\
194-o file -- send trace output to FILE instead of stderr\n\
195-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
196-p pid -- trace process with process id PID, may be repeated\n\
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000197-D -- run tracer process as a detached grandchild, not as parent\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000198-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
199-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
200-u username -- run command as username handling setuid and/or setgid\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000201-E var=val -- put var=val in the environment for command\n\
202-E var -- remove var from the environment for command\n\
203" /* this is broken, so don't document it
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000204-z -- print only succeeding syscalls\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000205 */
206, DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000207 exit(exitval);
208}
209
210#ifdef SVR4
211#ifdef MIPS
212void
213foobar()
214{
215}
216#endif /* MIPS */
217#endif /* SVR4 */
218
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000219static int
220set_cloexec_flag(int fd)
221{
222 int flags, newflags;
223
224 if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
225 {
226 fprintf(stderr, "%s: fcntl F_GETFD: %s\n",
227 progname, strerror(errno));
228 return -1;
229 }
230
231 newflags = flags | FD_CLOEXEC;
232 if (flags == newflags)
233 return 0;
234
235 if (fcntl(fd, F_SETFD, newflags) < 0)
236 {
237 fprintf(stderr, "%s: fcntl F_SETFD: %s\n",
238 progname, strerror(errno));
239 return -1;
240 }
241
242 return 0;
243}
244
245/*
246 * When strace is setuid executable, we have to swap uids
247 * before and after filesystem and process management operations.
248 */
249static void
250swap_uid(void)
251{
252#ifndef SVR4
253 int euid = geteuid(), uid = getuid();
254
255 if (euid != uid && setreuid(euid, uid) < 0)
256 {
257 fprintf(stderr, "%s: setreuid: %s\n",
258 progname, strerror(errno));
259 exit(1);
260 }
261#endif
262}
263
Roland McGrath4bfa6262007-07-05 20:03:16 +0000264#if _LFS64_LARGEFILE
265# define fopen_for_output fopen64
266#else
267# define fopen_for_output fopen
268#endif
269
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000270static FILE *
271strace_fopen(const char *path, const char *mode)
272{
273 FILE *fp;
274
275 swap_uid();
Roland McGrath4bfa6262007-07-05 20:03:16 +0000276 if ((fp = fopen_for_output(path, mode)) == NULL)
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000277 fprintf(stderr, "%s: can't fopen '%s': %s\n",
278 progname, path, strerror(errno));
279 swap_uid();
280 if (fp && set_cloexec_flag(fileno(fp)) < 0)
281 {
282 fclose(fp);
283 fp = NULL;
284 }
285 return fp;
286}
287
288static int popen_pid = -1;
289
290#ifndef _PATH_BSHELL
291# define _PATH_BSHELL "/bin/sh"
292#endif
293
294/*
295 * We cannot use standard popen(3) here because we have to distinguish
296 * popen child process from other processes we trace, and standard popen(3)
297 * does not export its child's pid.
298 */
299static FILE *
300strace_popen(const char *command)
301{
302 int fds[2];
303
304 swap_uid();
305 if (pipe(fds) < 0)
306 {
307 fprintf(stderr, "%s: pipe: %s\n",
308 progname, strerror(errno));
309 swap_uid();
310 return NULL;
311 }
312
313 if (set_cloexec_flag(fds[1]) < 0)
314 {
315 close(fds[0]);
316 close(fds[1]);
317 swap_uid();
318 return NULL;
319 }
320
321 if ((popen_pid = fork()) == -1)
322 {
323 fprintf(stderr, "%s: fork: %s\n",
324 progname, strerror(errno));
325 close(fds[0]);
326 close(fds[1]);
327 swap_uid();
328 return NULL;
329 }
330
331 if (popen_pid)
332 {
333 /* parent */
334 close(fds[0]);
335 swap_uid();
336 return fdopen(fds[1], "w");
337 } else
338 {
339 /* child */
340 close(fds[1]);
341 if (fds[0] && (dup2(fds[0], 0) || close(fds[0])))
342 {
343 fprintf(stderr, "%s: dup2: %s\n",
344 progname, strerror(errno));
345 _exit(1);
346 }
347 execl(_PATH_BSHELL, "sh", "-c", command, NULL);
348 fprintf(stderr, "%s: execl: %s: %s\n",
349 progname, _PATH_BSHELL, strerror(errno));
350 _exit(1);
351 }
352}
353
354static int
355newoutf(struct tcb *tcp)
356{
357 if (outfname && followfork > 1) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000358 char name[520 + sizeof(int) * 3];
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000359 FILE *fp;
360
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000361 sprintf(name, "%.512s.%u", outfname, tcp->pid);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000362 if ((fp = strace_fopen(name, "w")) == NULL)
363 return -1;
364 tcp->outf = fp;
365 }
366 return 0;
367}
368
Roland McGrath02203312007-06-11 22:06:31 +0000369static void
370startup_attach(void)
371{
372 int tcbi;
373 struct tcb *tcp;
374
375 /*
376 * Block user interruptions as we would leave the traced
377 * process stopped (process state T) if we would terminate in
378 * between PTRACE_ATTACH and wait4 () on SIGSTOP.
379 * We rely on cleanup () from this point on.
380 */
381 if (interactive)
382 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
383
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000384 if (daemonized_tracer) {
385 pid_t pid = fork();
386 if (pid < 0) {
387 _exit(1);
388 }
389 if (pid) { /* parent */
390 /*
391 * Wait for child to attach to straced process
392 * (our parent). Child SIGKILLs us after it attached.
393 * Parent's wait() is unblocked by our death,
394 * it proceeds to exec the straced program.
395 */
396 pause();
397 _exit(0); /* paranoia */
398 }
399 }
400
Roland McGrath02203312007-06-11 22:06:31 +0000401 for (tcbi = 0; tcbi < tcbtabsize; tcbi++) {
402 tcp = tcbtab[tcbi];
403 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
404 continue;
405#ifdef LINUX
406 if (tcp->flags & TCB_CLONE_THREAD)
407 continue;
408#endif
409 /* Reinitialize the output since it may have changed. */
410 tcp->outf = outf;
411 if (newoutf(tcp) < 0)
412 exit(1);
413
414#ifdef USE_PROCFS
415 if (proc_open(tcp, 1) < 0) {
416 fprintf(stderr, "trouble opening proc file\n");
417 droptcb(tcp);
418 continue;
419 }
420#else /* !USE_PROCFS */
421# ifdef LINUX
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000422 if (followfork && !daemonized_tracer) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000423 char procdir[sizeof("/proc/%d/task") + sizeof(int) * 3];
Roland McGrath02203312007-06-11 22:06:31 +0000424 DIR *dir;
425
426 sprintf(procdir, "/proc/%d/task", tcp->pid);
427 dir = opendir(procdir);
428 if (dir != NULL) {
429 unsigned int ntid = 0, nerr = 0;
430 struct dirent *de;
431 int tid;
432 while ((de = readdir(dir)) != NULL) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000433 if (de->d_fileno == 0)
Roland McGrath02203312007-06-11 22:06:31 +0000434 continue;
435 tid = atoi(de->d_name);
436 if (tid <= 0)
437 continue;
438 ++ntid;
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000439 if (ptrace(PTRACE_ATTACH, tid, (char *) 1, 0) < 0)
Roland McGrath02203312007-06-11 22:06:31 +0000440 ++nerr;
441 else if (tid != tcbtab[tcbi]->pid) {
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000442 tcp = alloctcb(tid);
Roland McGrath02203312007-06-11 22:06:31 +0000443 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_CLONE_DETACHED|TCB_FOLLOWFORK;
444 tcbtab[tcbi]->nchildren++;
445 tcbtab[tcbi]->nclone_threads++;
446 tcbtab[tcbi]->nclone_detached++;
447 tcp->parent = tcbtab[tcbi];
448 }
449 if (interactive) {
450 sigprocmask(SIG_SETMASK, &empty_set, NULL);
451 if (interrupted)
452 return;
453 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
454 }
455 }
456 closedir(dir);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000457 ntid -= nerr;
458 if (ntid == 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000459 perror("attach: ptrace(PTRACE_ATTACH, ...)");
460 droptcb(tcp);
461 continue;
462 }
463 if (!qflag) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000464 fprintf(stderr, ntid > 1
465? "Process %u attached with %u threads - interrupt to quit\n"
466: "Process %u attached - interrupt to quit\n",
467 tcbtab[tcbi]->pid, ntid);
Roland McGrath02203312007-06-11 22:06:31 +0000468 }
469 continue;
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000470 } /* if (opendir worked) */
471 } /* if (-f) */
Roland McGrath02203312007-06-11 22:06:31 +0000472# endif
473 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
474 perror("attach: ptrace(PTRACE_ATTACH, ...)");
475 droptcb(tcp);
476 continue;
477 }
478 /* INTERRUPTED is going to be checked at the top of TRACE. */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000479
480 if (daemonized_tracer) {
481 /*
482 * It is our grandparent we trace, not a -p PID.
483 * Don't want to just detach on exit, so...
484 */
485 tcp->flags &= ~TCB_ATTACHED;
486 /*
487 * Make parent go away.
488 * Also makes grandparent's wait() unblock.
489 */
490 kill(getppid(), SIGKILL);
491 }
492
Roland McGrath02203312007-06-11 22:06:31 +0000493#endif /* !USE_PROCFS */
494 if (!qflag)
495 fprintf(stderr,
496 "Process %u attached - interrupt to quit\n",
497 tcp->pid);
498 }
499
500 if (interactive)
501 sigprocmask(SIG_SETMASK, &empty_set, NULL);
502}
503
504static void
505startup_child (char **argv)
506{
507 struct stat statbuf;
508 const char *filename;
509 char pathname[MAXPATHLEN];
510 int pid = 0;
511 struct tcb *tcp;
512
513 filename = argv[0];
514 if (strchr(filename, '/')) {
515 if (strlen(filename) > sizeof pathname - 1) {
516 errno = ENAMETOOLONG;
517 perror("strace: exec");
518 exit(1);
519 }
520 strcpy(pathname, filename);
521 }
522#ifdef USE_DEBUGGING_EXEC
523 /*
524 * Debuggers customarily check the current directory
525 * first regardless of the path but doing that gives
526 * security geeks a panic attack.
527 */
528 else if (stat(filename, &statbuf) == 0)
529 strcpy(pathname, filename);
530#endif /* USE_DEBUGGING_EXEC */
531 else {
532 char *path;
533 int m, n, len;
534
535 for (path = getenv("PATH"); path && *path; path += m) {
536 if (strchr(path, ':')) {
537 n = strchr(path, ':') - path;
538 m = n + 1;
539 }
540 else
541 m = n = strlen(path);
542 if (n == 0) {
543 if (!getcwd(pathname, MAXPATHLEN))
544 continue;
545 len = strlen(pathname);
546 }
547 else if (n > sizeof pathname - 1)
548 continue;
549 else {
550 strncpy(pathname, path, n);
551 len = n;
552 }
553 if (len && pathname[len - 1] != '/')
554 pathname[len++] = '/';
555 strcpy(pathname + len, filename);
556 if (stat(pathname, &statbuf) == 0 &&
557 /* Accept only regular files
558 with some execute bits set.
559 XXX not perfect, might still fail */
560 S_ISREG(statbuf.st_mode) &&
561 (statbuf.st_mode & 0111))
562 break;
563 }
564 }
565 if (stat(pathname, &statbuf) < 0) {
566 fprintf(stderr, "%s: %s: command not found\n",
567 progname, filename);
568 exit(1);
569 }
Dmitry V. Levina6809652008-11-10 17:14:58 +0000570 strace_child = pid = fork();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000571 if (pid < 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000572 perror("strace: fork");
573 cleanup();
574 exit(1);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000575 }
576 if ((pid != 0 && daemonized_tracer) /* parent: to become a traced process */
577 || (pid == 0 && !daemonized_tracer) /* child: to become a traced process */
578 ) {
579 pid = getpid();
Roland McGrath02203312007-06-11 22:06:31 +0000580#ifdef USE_PROCFS
581 if (outf != stderr) close (fileno (outf));
582#ifdef MIPS
583 /* Kludge for SGI, see proc_open for details. */
584 sa.sa_handler = foobar;
585 sa.sa_flags = 0;
586 sigemptyset(&sa.sa_mask);
587 sigaction(SIGINT, &sa, NULL);
588#endif /* MIPS */
589#ifndef FREEBSD
590 pause();
591#else /* FREEBSD */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000592 kill(pid, SIGSTOP); /* stop HERE */
Roland McGrath02203312007-06-11 22:06:31 +0000593#endif /* FREEBSD */
594#else /* !USE_PROCFS */
595 if (outf!=stderr)
596 close(fileno (outf));
597
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000598 if (!daemonized_tracer) {
599 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
600 perror("strace: ptrace(PTRACE_TRACEME, ...)");
601 exit(1);
602 }
603 if (debug)
604 kill(pid, SIGSTOP);
Roland McGrath02203312007-06-11 22:06:31 +0000605 }
Roland McGrath02203312007-06-11 22:06:31 +0000606
607 if (username != NULL || geteuid() == 0) {
608 uid_t run_euid = run_uid;
609 gid_t run_egid = run_gid;
610
611 if (statbuf.st_mode & S_ISUID)
612 run_euid = statbuf.st_uid;
613 if (statbuf.st_mode & S_ISGID)
614 run_egid = statbuf.st_gid;
615
616 /*
617 * It is important to set groups before we
618 * lose privileges on setuid.
619 */
620 if (username != NULL) {
621 if (initgroups(username, run_gid) < 0) {
622 perror("initgroups");
623 exit(1);
624 }
625 if (setregid(run_gid, run_egid) < 0) {
626 perror("setregid");
627 exit(1);
628 }
629 if (setreuid(run_uid, run_euid) < 0) {
630 perror("setreuid");
631 exit(1);
632 }
633 }
634 }
635 else
636 setreuid(run_uid, run_uid);
637
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000638 if (!daemonized_tracer) {
639 /*
640 * Induce an immediate stop so that the parent
641 * will resume us with PTRACE_SYSCALL and display
642 * this execve call normally.
643 */
644 kill(getpid(), SIGSTOP);
645 } else {
646 struct sigaction sv_sigchld;
647 sigaction(SIGCHLD, NULL, &sv_sigchld);
648 /*
649 * Make sure it is not SIG_IGN, otherwise wait
650 * will not block.
651 */
652 signal(SIGCHLD, SIG_DFL);
653 /*
654 * Wait for grandchild to attach to us.
655 * It kills child after that, and wait() unblocks.
656 */
657 alarm(3);
658 wait(NULL);
659 alarm(0);
660 sigaction(SIGCHLD, &sv_sigchld, NULL);
661 }
Roland McGrath02203312007-06-11 22:06:31 +0000662#endif /* !USE_PROCFS */
663
664 execv(pathname, argv);
665 perror("strace: exec");
666 _exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000667 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000668
669 /* We are the tracer. */
670 tcp = alloctcb(daemonized_tracer ? getppid() : pid);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000671 if (daemonized_tracer) {
672 /* We want subsequent startup_attach() to attach to it. */
673 tcp->flags |= TCB_ATTACHED;
674 }
Roland McGrath02203312007-06-11 22:06:31 +0000675#ifdef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000676 if (proc_open(tcp, 0) < 0) {
677 fprintf(stderr, "trouble opening proc file\n");
678 cleanup();
679 exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000680 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000681#endif /* USE_PROCFS */
Roland McGrath02203312007-06-11 22:06:31 +0000682}
683
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000684int
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000685main(int argc, char *argv[])
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000686{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000687 struct tcb *tcp;
688 int c, pid = 0;
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000689 int optF = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000690 struct sigaction sa;
691
692 static char buf[BUFSIZ];
693
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000694 progname = argv[0] ? argv[0] : "strace";
695
Denys Vlasenko7e0615f2009-01-28 19:00:54 +0000696 uname(&utsname_buf);
697
Roland McGrathee9d4352002-12-18 04:16:10 +0000698 /* Allocate the initial tcbtab. */
699 tcbtabsize = argc; /* Surely enough for all -p args. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000700 if ((tcbtab = calloc(tcbtabsize, sizeof tcbtab[0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000701 fprintf(stderr, "%s: out of memory\n", progname);
702 exit(1);
703 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000704 if ((tcbtab[0] = calloc(tcbtabsize, sizeof tcbtab[0][0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000705 fprintf(stderr, "%s: out of memory\n", progname);
706 exit(1);
707 }
Roland McGrathee9d4352002-12-18 04:16:10 +0000708 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
709 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
710
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000711 outf = stderr;
712 interactive = 1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000713 set_sortby(DEFAULT_SORTBY);
714 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000715 qualify("trace=all");
716 qualify("abbrev=all");
717 qualify("verbose=all");
718 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000719 while ((c = getopt(argc, argv,
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000720 "+cdfFhiqrtTvVxz"
721#ifndef USE_PROCFS
722 "D"
723#endif
724 "a:e:o:O:p:s:S:u:E:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000725 switch (c) {
726 case 'c':
727 cflag++;
728 dtime++;
729 break;
730 case 'd':
731 debug++;
732 break;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000733#ifndef USE_PROCFS
734 /* Experimental, not documented in manpage yet. */
735 case 'D':
736 daemonized_tracer = 1;
737 break;
738#endif
Roland McGrath41c48222008-07-18 00:25:10 +0000739 case 'F':
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000740 optF = 1;
741 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000742 case 'f':
743 followfork++;
744 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000745 case 'h':
746 usage(stdout, 0);
747 break;
748 case 'i':
749 iflag++;
750 break;
751 case 'q':
752 qflag++;
753 break;
754 case 'r':
755 rflag++;
756 tflag++;
757 break;
758 case 't':
759 tflag++;
760 break;
761 case 'T':
762 dtime++;
763 break;
764 case 'x':
765 xflag++;
766 break;
767 case 'v':
768 qualify("abbrev=none");
769 break;
770 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +0000771 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000772 exit(0);
773 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000774 case 'z':
775 not_failing_only = 1;
776 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000777 case 'a':
778 acolumn = atoi(optarg);
779 break;
780 case 'e':
781 qualify(optarg);
782 break;
783 case 'o':
784 outfname = strdup(optarg);
785 break;
786 case 'O':
787 set_overhead(atoi(optarg));
788 break;
789 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +0000790 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000791 fprintf(stderr, "%s: Invalid process id: %s\n",
792 progname, optarg);
793 break;
794 }
795 if (pid == getpid()) {
Wichert Akkerman54a47671999-10-17 00:57:34 +0000796 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000797 break;
798 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000799 tcp = alloc_tcb(pid, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000800 tcp->flags |= TCB_ATTACHED;
801 pflag_seen++;
802 break;
803 case 's':
804 max_strlen = atoi(optarg);
Roland McGrathdccec722005-05-09 07:45:47 +0000805 if (max_strlen < 0) {
806 fprintf(stderr,
807 "%s: invalid -s argument: %s\n",
808 progname, optarg);
809 exit(1);
810 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000811 break;
812 case 'S':
813 set_sortby(optarg);
814 break;
815 case 'u':
816 username = strdup(optarg);
817 break;
Roland McGrathde6e5332003-01-24 04:31:23 +0000818 case 'E':
819 if (putenv(optarg) < 0) {
820 fprintf(stderr, "%s: out of memory\n",
821 progname);
822 exit(1);
823 }
824 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000825 default:
826 usage(stderr, 1);
827 break;
828 }
829 }
830
Roland McGrathd0c4c0c2006-04-25 07:39:40 +0000831 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +0000832 usage(stderr, 1);
833
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000834 if (!followfork)
835 followfork = optF;
836
Roland McGrathcb9def62006-04-25 07:48:03 +0000837 if (followfork > 1 && cflag) {
838 fprintf(stderr,
839 "%s: -c and -ff are mutually exclusive options\n",
840 progname);
841 exit(1);
842 }
843
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000844 /* See if they want to run as another user. */
845 if (username != NULL) {
846 struct passwd *pent;
847
848 if (getuid() != 0 || geteuid() != 0) {
849 fprintf(stderr,
850 "%s: you must be root to use the -u option\n",
851 progname);
852 exit(1);
853 }
854 if ((pent = getpwnam(username)) == NULL) {
855 fprintf(stderr, "%s: cannot find user `%s'\n",
Roland McGrath09553f82007-07-05 19:31:49 +0000856 progname, username);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000857 exit(1);
858 }
859 run_uid = pent->pw_uid;
860 run_gid = pent->pw_gid;
861 }
862 else {
863 run_uid = getuid();
864 run_gid = getgid();
865 }
866
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000867 /* Check if they want to redirect the output. */
868 if (outfname) {
Roland McGrath37b9a662003-11-07 02:26:54 +0000869 /* See if they want to pipe the output. */
870 if (outfname[0] == '|' || outfname[0] == '!') {
871 /*
872 * We can't do the <outfname>.PID funny business
873 * when using popen, so prohibit it.
874 */
875 if (followfork > 1) {
876 fprintf(stderr, "\
877%s: piping the output and -ff are mutually exclusive options\n",
878 progname);
879 exit(1);
880 }
881
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000882 if ((outf = strace_popen(outfname + 1)) == NULL)
Roland McGrath37b9a662003-11-07 02:26:54 +0000883 exit(1);
Roland McGrath37b9a662003-11-07 02:26:54 +0000884 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000885 else if (followfork <= 1 &&
886 (outf = strace_fopen(outfname, "w")) == NULL)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000887 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000888 }
889
Roland McGrath37b9a662003-11-07 02:26:54 +0000890 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000891 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +0000892 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000893 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000894 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +0000895 }
Roland McGrath54cc1c82007-11-03 23:34:11 +0000896 /* Valid states here:
897 optind < argc pflag_seen outfname interactive
898 1 0 0 1
899 0 1 0 1
900 1 0 1 0
901 0 1 1 1
902 */
903
904 /* STARTUP_CHILD must be called before the signal handlers get
905 installed below as they are inherited into the spawned process.
906 Also we do not need to be protected by them as during interruption
907 in the STARTUP_CHILD mode we kill the spawned process anyway. */
908 if (!pflag_seen)
909 startup_child(&argv[optind]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000910
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000911 sigemptyset(&empty_set);
912 sigemptyset(&blocked_set);
913 sa.sa_handler = SIG_IGN;
914 sigemptyset(&sa.sa_mask);
915 sa.sa_flags = 0;
916 sigaction(SIGTTOU, &sa, NULL);
917 sigaction(SIGTTIN, &sa, NULL);
918 if (interactive) {
919 sigaddset(&blocked_set, SIGHUP);
920 sigaddset(&blocked_set, SIGINT);
921 sigaddset(&blocked_set, SIGQUIT);
922 sigaddset(&blocked_set, SIGPIPE);
923 sigaddset(&blocked_set, SIGTERM);
924 sa.sa_handler = interrupt;
925#ifdef SUNOS4
926 /* POSIX signals on sunos4.1 are a little broken. */
927 sa.sa_flags = SA_INTERRUPT;
928#endif /* SUNOS4 */
929 }
930 sigaction(SIGHUP, &sa, NULL);
931 sigaction(SIGINT, &sa, NULL);
932 sigaction(SIGQUIT, &sa, NULL);
933 sigaction(SIGPIPE, &sa, NULL);
934 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000935#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000936 sa.sa_handler = reaper;
937 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000938#else
939 /* Make sure SIGCHLD has the default action so that waitpid
940 definitely works without losing track of children. The user
941 should not have given us a bogus state to inherit, but he might
942 have. Arguably we should detect SIG_IGN here and pass it on
943 to children, but probably noone really needs that. */
944 sa.sa_handler = SIG_DFL;
945 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000946#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000947
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000948 if (pflag_seen || daemonized_tracer)
Roland McGrath02203312007-06-11 22:06:31 +0000949 startup_attach();
Roland McGrath02203312007-06-11 22:06:31 +0000950
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000951 if (trace() < 0)
952 exit(1);
953 cleanup();
Dmitry V. Levina6809652008-11-10 17:14:58 +0000954 fflush(NULL);
955 if (exit_code > 0xff) {
956 /* Child was killed by a signal, mimic that. */
957 exit_code &= 0xff;
958 signal(exit_code, SIG_DFL);
959 raise(exit_code);
960 /* Paranoia - what if this signal is not fatal?
961 Exit with 128 + signo then. */
962 exit_code += 128;
963 }
964 exit(exit_code);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000965}
966
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000967void
968expand_tcbtab(void)
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000969{
970 /* Allocate some more TCBs and expand the table.
971 We don't want to relocate the TCBs because our
972 callers have pointers and it would be a pain.
973 So tcbtab is a table of pointers. Since we never
974 free the TCBs, we allocate a single chunk of many. */
975 struct tcb **newtab = (struct tcb **)
976 realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
977 struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
978 sizeof *newtcbs);
979 int i;
980 if (newtab == NULL || newtcbs == NULL) {
Dmitry V. Levin76860f62006-10-11 22:55:25 +0000981 fprintf(stderr, "%s: expand_tcbtab: out of memory\n",
982 progname);
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000983 cleanup();
984 exit(1);
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000985 }
986 for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
987 newtab[i] = &newtcbs[i - tcbtabsize];
988 tcbtabsize *= 2;
989 tcbtab = newtab;
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000990}
991
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000992struct tcb *
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000993alloc_tcb(int pid, int command_options_parsed)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000994{
995 int i;
996 struct tcb *tcp;
997
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000998 if (nprocs == tcbtabsize)
999 expand_tcbtab();
1000
Roland McGrathee9d4352002-12-18 04:16:10 +00001001 for (i = 0; i < tcbtabsize; i++) {
1002 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001003 if ((tcp->flags & TCB_INUSE) == 0) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00001004 memset(tcp, 0, sizeof(*tcp));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001005 tcp->pid = pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001006 tcp->flags = TCB_INUSE | TCB_STARTUP;
1007 tcp->outf = outf; /* Initialise to current out file */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001008 tcp->pfd = -1;
1009 nprocs++;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001010 if (command_options_parsed)
1011 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001012 return tcp;
1013 }
1014 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001015 fprintf(stderr, "%s: bug in alloc_tcb\n", progname);
1016 cleanup();
1017 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001018}
1019
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001020#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001021int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001022proc_open(struct tcb *tcp, int attaching)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001023{
1024 char proc[32];
1025 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001026#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +00001027 int i;
1028 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001029 sigset_t signals;
1030 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001031#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001032#ifndef HAVE_POLLABLE_PROCFS
1033 static int last_pfd;
1034#endif
1035
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001036#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001037 /* Open the process pseudo-files in /proc. */
1038 sprintf(proc, "/proc/%d/ctl", tcp->pid);
1039 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001040 perror("strace: open(\"/proc/...\", ...)");
1041 return -1;
1042 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001043 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001044 return -1;
1045 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001046 sprintf(proc, "/proc/%d/status", tcp->pid);
1047 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
1048 perror("strace: open(\"/proc/...\", ...)");
1049 return -1;
1050 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001051 if (set_cloexec_flag(tcp->pfd_stat) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001052 return -1;
1053 }
1054 sprintf(proc, "/proc/%d/as", tcp->pid);
1055 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
1056 perror("strace: open(\"/proc/...\", ...)");
1057 return -1;
1058 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001059 if (set_cloexec_flag(tcp->pfd_as) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001060 return -1;
1061 }
1062#else
1063 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001064#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001065 sprintf(proc, "/proc/%d", tcp->pid);
1066 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001067#else /* FREEBSD */
1068 sprintf(proc, "/proc/%d/mem", tcp->pid);
1069 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
1070#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001071 perror("strace: open(\"/proc/...\", ...)");
1072 return -1;
1073 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001074 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001075 return -1;
1076 }
1077#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001078#ifdef FREEBSD
1079 sprintf(proc, "/proc/%d/regs", tcp->pid);
1080 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
1081 perror("strace: open(\"/proc/.../regs\", ...)");
1082 return -1;
1083 }
1084 if (cflag) {
1085 sprintf(proc, "/proc/%d/status", tcp->pid);
1086 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
1087 perror("strace: open(\"/proc/.../status\", ...)");
1088 return -1;
1089 }
1090 } else
1091 tcp->pfd_status = -1;
1092#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001093 rebuild_pollv();
1094 if (!attaching) {
1095 /*
1096 * Wait for the child to pause. Because of a race
1097 * condition we have to poll for the event.
1098 */
1099 for (;;) {
1100 if (IOCTL_STATUS (tcp) < 0) {
1101 perror("strace: PIOCSTATUS");
1102 return -1;
1103 }
1104 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001105 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001106 }
1107 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001108#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001109 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001110 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001111 perror("strace: PIOCSTOP");
1112 return -1;
1113 }
Roland McGrath553a6092002-12-16 20:40:39 +00001114#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001115#ifdef PIOCSET
1116 /* Set Run-on-Last-Close. */
1117 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001118 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001119 perror("PIOCSET PR_RLC");
1120 return -1;
1121 }
1122 /* Set or Reset Inherit-on-Fork. */
1123 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001124 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001125 perror("PIOC{SET,RESET} PR_FORK");
1126 return -1;
1127 }
1128#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +00001129#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001130 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
1131 perror("PIOCSRLC");
1132 return -1;
1133 }
1134 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
1135 perror("PIOC{S,R}FORK");
1136 return -1;
1137 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001138#else /* FREEBSD */
1139 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
1140 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
1141 perror("PIOCGFL");
1142 return -1;
1143 }
1144 arg &= ~PF_LINGER;
1145 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
1146 perror("PIOCSFL");
1147 return -1;
1148 }
1149#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001150#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001151#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +00001152 /* Enable all syscall entries we care about. */
1153 premptyset(&syscalls);
1154 for (i = 1; i < MAX_QUALS; ++i) {
1155 if (i > (sizeof syscalls) * CHAR_BIT) break;
1156 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
1157 }
1158 praddset (&syscalls, SYS_execve);
1159 if (followfork) {
1160 praddset (&syscalls, SYS_fork);
1161#ifdef SYS_forkall
1162 praddset (&syscalls, SYS_forkall);
1163#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001164#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +00001165 praddset (&syscalls, SYS_fork1);
1166#endif
1167#ifdef SYS_rfork1
1168 praddset (&syscalls, SYS_rfork1);
1169#endif
1170#ifdef SYS_rforkall
1171 praddset (&syscalls, SYS_rforkall);
1172#endif
1173 }
1174 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001175 perror("PIOCSENTRY");
1176 return -1;
1177 }
John Hughes19e49982001-10-19 08:59:12 +00001178 /* Enable the syscall exits. */
1179 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001180 perror("PIOSEXIT");
1181 return -1;
1182 }
John Hughes19e49982001-10-19 08:59:12 +00001183 /* Enable signals we care about. */
1184 premptyset(&signals);
1185 for (i = 1; i < MAX_QUALS; ++i) {
1186 if (i > (sizeof signals) * CHAR_BIT) break;
1187 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
1188 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001189 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001190 perror("PIOCSTRACE");
1191 return -1;
1192 }
John Hughes19e49982001-10-19 08:59:12 +00001193 /* Enable faults we care about */
1194 premptyset(&faults);
1195 for (i = 1; i < MAX_QUALS; ++i) {
1196 if (i > (sizeof faults) * CHAR_BIT) break;
1197 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
1198 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001199 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001200 perror("PIOCSFAULT");
1201 return -1;
1202 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001203#else /* FREEBSD */
1204 /* set events flags. */
1205 arg = S_SIG | S_SCE | S_SCX ;
1206 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
1207 perror("PIOCBIS");
1208 return -1;
1209 }
1210#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001211 if (!attaching) {
1212#ifdef MIPS
1213 /*
1214 * The SGI PRSABORT doesn't work for pause() so
1215 * we send it a caught signal to wake it up.
1216 */
1217 kill(tcp->pid, SIGINT);
1218#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +00001219#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001220 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001221 arg = PRSABORT;
1222 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001223 perror("PIOCRUN");
1224 return -1;
1225 }
Roland McGrath553a6092002-12-16 20:40:39 +00001226#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001227#endif /* !MIPS*/
1228#ifdef FREEBSD
1229 /* wake up the child if it received the SIGSTOP */
1230 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001231#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001232 for (;;) {
1233 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001234 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001235 perror("PIOCWSTOP");
1236 return -1;
1237 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001238 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001239 tcp->flags &= ~TCB_INSYSCALL;
1240 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001241 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001242 break;
1243 }
1244 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001245#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001246 arg = 0;
1247 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001248#else /* FREEBSD */
1249 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001250#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001251 perror("PIOCRUN");
1252 return -1;
1253 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001254#ifdef FREEBSD
1255 /* handle the case where we "opened" the child before
1256 it did the kill -STOP */
1257 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1258 tcp->status.PR_WHAT == SIGSTOP)
1259 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001260#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001261 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001262#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001263 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001264#else /* FREEBSD */
1265 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001266 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001267 /* We are attaching to an already running process.
1268 * Try to figure out the state of the process in syscalls,
1269 * to handle the first event well.
1270 * This is done by having a look at the "wchan" property of the
1271 * process, which tells where it is stopped (if it is). */
1272 FILE * status;
1273 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001274
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001275 sprintf(proc, "/proc/%d/status", tcp->pid);
1276 status = fopen(proc, "r");
1277 if (status &&
1278 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1279 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1280 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1281 strcmp(wchan, "stopevent")) {
1282 /* The process is asleep in the middle of a syscall.
1283 Fake the syscall entry event */
1284 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1285 tcp->status.PR_WHY = PR_SYSENTRY;
1286 trace_syscall(tcp);
1287 }
1288 if (status)
1289 fclose(status);
1290 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001291 }
1292#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001293#ifndef HAVE_POLLABLE_PROCFS
1294 if (proc_poll_pipe[0] != -1)
1295 proc_poller(tcp->pfd);
1296 else if (nprocs > 1) {
1297 proc_poll_open();
1298 proc_poller(last_pfd);
1299 proc_poller(tcp->pfd);
1300 }
1301 last_pfd = tcp->pfd;
1302#endif /* !HAVE_POLLABLE_PROCFS */
1303 return 0;
1304}
1305
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001306#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001307
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001308struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001309pid2tcb(pid)
1310int pid;
1311{
1312 int i;
1313 struct tcb *tcp;
1314
Roland McGrathee9d4352002-12-18 04:16:10 +00001315 for (i = 0; i < tcbtabsize; i++) {
1316 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001317 if (pid && tcp->pid != pid)
1318 continue;
1319 if (tcp->flags & TCB_INUSE)
1320 return tcp;
1321 }
1322 return NULL;
1323}
1324
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001325#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001326
1327static struct tcb *
1328pfd2tcb(pfd)
1329int pfd;
1330{
1331 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001332
Roland McGrathca16be82003-01-10 19:55:28 +00001333 for (i = 0; i < tcbtabsize; i++) {
1334 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001335 if (tcp->pfd != pfd)
1336 continue;
1337 if (tcp->flags & TCB_INUSE)
1338 return tcp;
1339 }
1340 return NULL;
1341}
1342
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001343#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001344
1345void
1346droptcb(tcp)
1347struct tcb *tcp;
1348{
1349 if (tcp->pid == 0)
1350 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001351#ifdef TCB_CLONE_THREAD
1352 if (tcp->nclone_threads > 0) {
1353 /* There are other threads left in this process, but this
1354 is the one whose PID represents the whole process.
1355 We need to keep this record around as a zombie until
1356 all the threads die. */
1357 tcp->flags |= TCB_EXITING;
1358 return;
1359 }
1360#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001361 nprocs--;
1362 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001363
Roland McGrathe29341c2003-01-10 20:14:20 +00001364 if (tcp->parent != NULL) {
1365 tcp->parent->nchildren--;
1366#ifdef TCB_CLONE_THREAD
1367 if (tcp->flags & TCB_CLONE_DETACHED)
1368 tcp->parent->nclone_detached--;
1369 if (tcp->flags & TCB_CLONE_THREAD)
1370 tcp->parent->nclone_threads--;
1371#endif
Roland McGrath09623452003-05-23 02:27:13 +00001372#ifdef TCB_CLONE_DETACHED
1373 if (!(tcp->flags & TCB_CLONE_DETACHED))
1374#endif
1375 tcp->parent->nzombies++;
Roland McGrath276ceb32007-11-13 08:12:12 +00001376#ifdef LINUX
1377 /* Update `tcp->parent->parent->nchildren' and the other fields
1378 like NCLONE_DETACHED, only for zombie group leader that has
1379 already reported and been short-circuited at the top of this
1380 function. The same condition as at the top of DETACH. */
1381 if ((tcp->flags & TCB_CLONE_THREAD) &&
1382 tcp->parent->nclone_threads == 0 &&
1383 (tcp->parent->flags & TCB_EXITING))
1384 droptcb(tcp->parent);
1385#endif
Roland McGrathe29341c2003-01-10 20:14:20 +00001386 tcp->parent = NULL;
1387 }
1388
1389 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001390 if (tcp->pfd != -1) {
1391 close(tcp->pfd);
1392 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001393#ifdef FREEBSD
1394 if (tcp->pfd_reg != -1) {
1395 close(tcp->pfd_reg);
1396 tcp->pfd_reg = -1;
1397 }
1398 if (tcp->pfd_status != -1) {
1399 close(tcp->pfd_status);
1400 tcp->pfd_status = -1;
1401 }
Roland McGrath553a6092002-12-16 20:40:39 +00001402#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001403#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001404 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001405#endif
1406 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001407
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001408 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001409 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001410
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001411 tcp->outf = 0;
1412}
1413
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001414#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001415
1416static int
1417resume(tcp)
1418struct tcb *tcp;
1419{
1420 if (tcp == NULL)
1421 return -1;
1422
1423 if (!(tcp->flags & TCB_SUSPENDED)) {
1424 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1425 return -1;
1426 }
1427 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001428#ifdef TCB_CLONE_THREAD
1429 if (tcp->flags & TCB_CLONE_THREAD)
1430 tcp->parent->nclone_waiting--;
1431#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001432
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001433 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001434 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001435
1436 if (!qflag)
1437 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1438 return 0;
1439}
1440
Roland McGrath1bfd3102007-08-03 10:02:00 +00001441static int
1442resume_from_tcp (struct tcb *tcp)
1443{
1444 int error = 0;
1445 int resumed = 0;
1446
1447 /* XXX This won't always be quite right (but it never was).
1448 A waiter with argument 0 or < -1 is waiting for any pid in
1449 a particular pgrp, which this child might or might not be
1450 in. The waiter will only wake up if it's argument is -1
1451 or if it's waiting for tcp->pid's pgrp. It makes a
1452 difference to wake up a waiter when there might be more
1453 traced children, because it could get a false ECHILD
1454 error. OTOH, if this was the last child in the pgrp, then
1455 it ought to wake up and get ECHILD. We would have to
1456 search the system for all pid's in the pgrp to be sure.
1457
1458 && (t->waitpid == -1 ||
1459 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1460 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1461 */
1462
1463 if (tcp->parent &&
1464 (tcp->parent->flags & TCB_SUSPENDED) &&
1465 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1466 error = resume(tcp->parent);
1467 ++resumed;
1468 }
1469#ifdef TCB_CLONE_THREAD
1470 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1471 /* Some other threads of our parent are waiting too. */
1472 unsigned int i;
1473
1474 /* Resume all the threads that were waiting for this PID. */
1475 for (i = 0; i < tcbtabsize; i++) {
1476 struct tcb *t = tcbtab[i];
1477 if (t->parent == tcp->parent && t != tcp
1478 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1479 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1480 && t->waitpid == tcp->pid) {
1481 error |= resume (t);
1482 ++resumed;
1483 }
1484 }
1485 if (resumed == 0)
1486 /* Noone was waiting for this PID in particular,
1487 so now we might need to resume some wildcarders. */
1488 for (i = 0; i < tcbtabsize; i++) {
1489 struct tcb *t = tcbtab[i];
1490 if (t->parent == tcp->parent && t != tcp
1491 && ((t->flags
1492 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1493 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1494 && t->waitpid <= 0
1495 ) {
1496 error |= resume (t);
1497 break;
1498 }
1499 }
1500 }
1501
1502 return error;
1503}
1504#endif
1505
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001506#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001507
Roland McGrath0a463882007-07-05 18:43:16 +00001508/* detach traced process; continue with sig
1509 Never call DETACH twice on the same process as both unattached and
1510 attached-unstopped processes give the same ESRCH. For unattached process we
1511 would SIGSTOP it and wait for its SIGSTOP notification forever. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001512
1513static int
1514detach(tcp, sig)
1515struct tcb *tcp;
1516int sig;
1517{
1518 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001519#ifdef LINUX
Roland McGrath1bfd3102007-08-03 10:02:00 +00001520 int status, catch_sigstop;
Roland McGratha08a97e2005-08-03 11:23:46 +00001521 struct tcb *zombie = NULL;
1522
1523 /* If the group leader is lingering only because of this other
1524 thread now dying, then detach the leader as well. */
1525 if ((tcp->flags & TCB_CLONE_THREAD) &&
1526 tcp->parent->nclone_threads == 1 &&
1527 (tcp->parent->flags & TCB_EXITING))
1528 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001529#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001530
1531 if (tcp->flags & TCB_BPTSET)
1532 sig = SIGKILL;
1533
1534#ifdef LINUX
1535 /*
1536 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001537 * before detaching. Arghh. We go through hoops
1538 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001539 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001540#if defined(SPARC)
1541#undef PTRACE_DETACH
1542#define PTRACE_DETACH PTRACE_SUNDETACH
1543#endif
Roland McGrath02203312007-06-11 22:06:31 +00001544 /*
1545 * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
1546 * expected SIGSTOP. We must catch exactly one as otherwise the
1547 * detached process would be left stopped (process state T).
1548 */
1549 catch_sigstop = (tcp->flags & TCB_STARTUP);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001550 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1551 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001552 }
1553 else if (errno != ESRCH) {
1554 /* Shouldn't happen. */
1555 perror("detach: ptrace(PTRACE_DETACH, ...)");
1556 }
Roland McGrath134813a2007-06-02 00:07:33 +00001557 else if (my_tgkill((tcp->flags & TCB_CLONE_THREAD ? tcp->parent->pid
1558 : tcp->pid),
1559 tcp->pid, 0) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001560 if (errno != ESRCH)
1561 perror("detach: checking sanity");
1562 }
Roland McGrath02203312007-06-11 22:06:31 +00001563 else if (!catch_sigstop && my_tgkill((tcp->flags & TCB_CLONE_THREAD
1564 ? tcp->parent->pid : tcp->pid),
1565 tcp->pid, SIGSTOP) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001566 if (errno != ESRCH)
1567 perror("detach: stopping child");
1568 }
Roland McGrath02203312007-06-11 22:06:31 +00001569 else
1570 catch_sigstop = 1;
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001571 if (catch_sigstop) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001572 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001573#ifdef __WALL
1574 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1575 if (errno == ECHILD) /* Already gone. */
1576 break;
1577 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001578 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001579 break;
1580 }
1581#endif /* __WALL */
1582 /* No __WALL here. */
1583 if (waitpid(tcp->pid, &status, 0) < 0) {
1584 if (errno != ECHILD) {
1585 perror("detach: waiting");
1586 break;
1587 }
1588#ifdef __WCLONE
1589 /* If no processes, try clones. */
1590 if (wait4(tcp->pid, &status, __WCLONE,
1591 NULL) < 0) {
1592 if (errno != ECHILD)
1593 perror("detach: waiting");
1594 break;
1595 }
1596#endif /* __WCLONE */
1597 }
1598#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001599 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001600#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001601 if (!WIFSTOPPED(status)) {
1602 /* Au revoir, mon ami. */
1603 break;
1604 }
1605 if (WSTOPSIG(status) == SIGSTOP) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001606 ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001607 break;
1608 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001609 error = ptrace_restart(PTRACE_CONT, tcp,
Denys Vlasenko96d5a762008-12-29 19:13:27 +00001610 WSTOPSIG(status) == ptrace_stop_sig ? 0
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001611 : WSTOPSIG(status));
1612 if (error < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001613 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001614 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001615 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001616#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001617
1618#if defined(SUNOS4)
1619 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1620 if (sig && kill(tcp->pid, sig) < 0)
1621 perror("detach: kill");
1622 sig = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001623 error = ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001624#endif /* SUNOS4 */
1625
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001626#ifndef USE_PROCFS
Roland McGrath1bfd3102007-08-03 10:02:00 +00001627 error |= resume_from_tcp (tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001628#endif
1629
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001630 if (!qflag)
1631 fprintf(stderr, "Process %u detached\n", tcp->pid);
1632
1633 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001634
1635#ifdef LINUX
Roland McGrath0a463882007-07-05 18:43:16 +00001636 if (zombie != NULL) {
1637 /* TCP no longer exists therefore you must not detach () it. */
1638 droptcb(zombie);
1639 }
Roland McGratha08a97e2005-08-03 11:23:46 +00001640#endif
1641
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001642 return error;
1643}
1644
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001645#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001646
1647static void
1648reaper(sig)
1649int sig;
1650{
1651 int pid;
1652 int status;
1653
1654 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1655#if 0
1656 struct tcb *tcp;
1657
1658 tcp = pid2tcb(pid);
1659 if (tcp)
1660 droptcb(tcp);
1661#endif
1662 }
1663}
1664
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001665#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001666
1667static void
1668cleanup()
1669{
1670 int i;
1671 struct tcb *tcp;
1672
Roland McGrathee9d4352002-12-18 04:16:10 +00001673 for (i = 0; i < tcbtabsize; i++) {
1674 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001675 if (!(tcp->flags & TCB_INUSE))
1676 continue;
1677 if (debug)
1678 fprintf(stderr,
1679 "cleanup: looking at pid %u\n", tcp->pid);
1680 if (tcp_last &&
1681 (!outfname || followfork < 2 || tcp_last == tcp)) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001682 tprintf(" <unfinished ...>");
1683 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001684 }
1685 if (tcp->flags & TCB_ATTACHED)
1686 detach(tcp, 0);
1687 else {
1688 kill(tcp->pid, SIGCONT);
1689 kill(tcp->pid, SIGTERM);
1690 }
1691 }
1692 if (cflag)
1693 call_summary(outf);
1694}
1695
1696static void
1697interrupt(sig)
1698int sig;
1699{
1700 interrupted = 1;
1701}
1702
1703#ifndef HAVE_STRERROR
1704
Roland McGrath6d2b3492002-12-30 00:51:30 +00001705#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001706extern int sys_nerr;
1707extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001708#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001709
1710const char *
1711strerror(errno)
1712int errno;
1713{
1714 static char buf[64];
1715
1716 if (errno < 1 || errno >= sys_nerr) {
1717 sprintf(buf, "Unknown error %d", errno);
1718 return buf;
1719 }
1720 return sys_errlist[errno];
1721}
1722
1723#endif /* HAVE_STERRROR */
1724
1725#ifndef HAVE_STRSIGNAL
1726
Roland McGrath8f474e02003-01-14 07:53:33 +00001727#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001728extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001729#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001730#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1731extern char *_sys_siglist[];
1732#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001733
1734const char *
1735strsignal(sig)
1736int sig;
1737{
1738 static char buf[64];
1739
1740 if (sig < 1 || sig >= NSIG) {
1741 sprintf(buf, "Unknown signal %d", sig);
1742 return buf;
1743 }
1744#ifdef HAVE__SYS_SIGLIST
1745 return _sys_siglist[sig];
1746#else
1747 return sys_siglist[sig];
1748#endif
1749}
1750
1751#endif /* HAVE_STRSIGNAL */
1752
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001753#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001754
1755static void
1756rebuild_pollv()
1757{
1758 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001759
Roland McGrathee9d4352002-12-18 04:16:10 +00001760 if (pollv != NULL)
1761 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001762 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001763 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001764 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00001765 exit(1);
1766 }
1767
Roland McGrathca16be82003-01-10 19:55:28 +00001768 for (i = j = 0; i < tcbtabsize; i++) {
1769 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001770 if (!(tcp->flags & TCB_INUSE))
1771 continue;
1772 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001773 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001774 j++;
1775 }
1776 if (j != nprocs) {
1777 fprintf(stderr, "strace: proc miscount\n");
1778 exit(1);
1779 }
1780}
1781
1782#ifndef HAVE_POLLABLE_PROCFS
1783
1784static void
1785proc_poll_open()
1786{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001787 int i;
1788
1789 if (pipe(proc_poll_pipe) < 0) {
1790 perror("pipe");
1791 exit(1);
1792 }
1793 for (i = 0; i < 2; i++) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001794 if (set_cloexec_flag(proc_poll_pipe[i]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001795 exit(1);
1796 }
1797 }
1798}
1799
1800static int
1801proc_poll(pollv, nfds, timeout)
1802struct pollfd *pollv;
1803int nfds;
1804int timeout;
1805{
1806 int i;
1807 int n;
1808 struct proc_pollfd pollinfo;
1809
1810 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1811 return n;
1812 if (n != sizeof(struct proc_pollfd)) {
1813 fprintf(stderr, "panic: short read: %d\n", n);
1814 exit(1);
1815 }
1816 for (i = 0; i < nprocs; i++) {
1817 if (pollv[i].fd == pollinfo.fd)
1818 pollv[i].revents = pollinfo.revents;
1819 else
1820 pollv[i].revents = 0;
1821 }
1822 poller_pid = pollinfo.pid;
1823 return 1;
1824}
1825
1826static void
1827wakeup_handler(sig)
1828int sig;
1829{
1830}
1831
1832static void
1833proc_poller(pfd)
1834int pfd;
1835{
1836 struct proc_pollfd pollinfo;
1837 struct sigaction sa;
1838 sigset_t blocked_set, empty_set;
1839 int i;
1840 int n;
1841 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001842#ifdef FREEBSD
1843 struct procfs_status pfs;
1844#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001845
1846 switch (fork()) {
1847 case -1:
1848 perror("fork");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001849 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001850 case 0:
1851 break;
1852 default:
1853 return;
1854 }
1855
1856 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1857 sa.sa_flags = 0;
1858 sigemptyset(&sa.sa_mask);
1859 sigaction(SIGHUP, &sa, NULL);
1860 sigaction(SIGINT, &sa, NULL);
1861 sigaction(SIGQUIT, &sa, NULL);
1862 sigaction(SIGPIPE, &sa, NULL);
1863 sigaction(SIGTERM, &sa, NULL);
1864 sa.sa_handler = wakeup_handler;
1865 sigaction(SIGUSR1, &sa, NULL);
1866 sigemptyset(&blocked_set);
1867 sigaddset(&blocked_set, SIGUSR1);
1868 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1869 sigemptyset(&empty_set);
1870
1871 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1872 perror("getrlimit(RLIMIT_NOFILE, ...)");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001873 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001874 }
1875 n = rl.rlim_cur;
1876 for (i = 0; i < n; i++) {
1877 if (i != pfd && i != proc_poll_pipe[1])
1878 close(i);
1879 }
1880
1881 pollinfo.fd = pfd;
1882 pollinfo.pid = getpid();
1883 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001884#ifndef FREEBSD
1885 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1886#else /* FREEBSD */
1887 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1888#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001889 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001890 switch (errno) {
1891 case EINTR:
1892 continue;
1893 case EBADF:
1894 pollinfo.revents = POLLERR;
1895 break;
1896 case ENOENT:
1897 pollinfo.revents = POLLHUP;
1898 break;
1899 default:
1900 perror("proc_poller: PIOCWSTOP");
1901 }
1902 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1903 _exit(0);
1904 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001905 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001906 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1907 sigsuspend(&empty_set);
1908 }
1909}
1910
1911#endif /* !HAVE_POLLABLE_PROCFS */
1912
1913static int
1914choose_pfd()
1915{
1916 int i, j;
1917 struct tcb *tcp;
1918
1919 static int last;
1920
1921 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001922 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001923 /*
1924 * The previous process is ready to run again. We'll
1925 * let it do so if it is currently in a syscall. This
1926 * heuristic improves the readability of the trace.
1927 */
1928 tcp = pfd2tcb(pollv[last].fd);
1929 if (tcp && (tcp->flags & TCB_INSYSCALL))
1930 return pollv[last].fd;
1931 }
1932
1933 for (i = 0; i < nprocs; i++) {
1934 /* Let competing children run round robin. */
1935 j = (i + last + 1) % nprocs;
1936 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1937 tcp = pfd2tcb(pollv[j].fd);
1938 if (!tcp) {
1939 fprintf(stderr, "strace: lost proc\n");
1940 exit(1);
1941 }
1942 droptcb(tcp);
1943 return -1;
1944 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001945 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001946 last = j;
1947 return pollv[j].fd;
1948 }
1949 }
1950 fprintf(stderr, "strace: nothing ready\n");
1951 exit(1);
1952}
1953
1954static int
1955trace()
1956{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001957#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001958 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001959#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001960 struct tcb *tcp;
1961 int pfd;
1962 int what;
1963 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001964 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001965
1966 for (;;) {
1967 if (interactive)
1968 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1969
1970 if (nprocs == 0)
1971 break;
1972
1973 switch (nprocs) {
1974 case 1:
1975#ifndef HAVE_POLLABLE_PROCFS
1976 if (proc_poll_pipe[0] == -1) {
1977#endif
1978 tcp = pid2tcb(0);
1979 if (!tcp)
1980 continue;
1981 pfd = tcp->pfd;
1982 if (pfd == -1)
1983 continue;
1984 break;
1985#ifndef HAVE_POLLABLE_PROCFS
1986 }
1987 /* fall through ... */
1988#endif /* !HAVE_POLLABLE_PROCFS */
1989 default:
1990#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001991#ifdef POLL_HACK
1992 /* On some systems (e.g. UnixWare) we get too much ugly
1993 "unfinished..." stuff when multiple proceses are in
1994 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001995
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001996 if (in_syscall) {
1997 struct pollfd pv;
1998 tcp = in_syscall;
1999 in_syscall = NULL;
2000 pv.fd = tcp->pfd;
2001 pv.events = POLLWANT;
2002 if ((what = poll (&pv, 1, 1)) < 0) {
2003 if (interrupted)
2004 return 0;
2005 continue;
2006 }
2007 else if (what == 1 && pv.revents & POLLWANT) {
2008 goto FOUND;
2009 }
2010 }
2011#endif
2012
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002013 if (poll(pollv, nprocs, INFTIM) < 0) {
2014 if (interrupted)
2015 return 0;
2016 continue;
2017 }
2018#else /* !HAVE_POLLABLE_PROCFS */
2019 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
2020 if (interrupted)
2021 return 0;
2022 continue;
2023 }
2024#endif /* !HAVE_POLLABLE_PROCFS */
2025 pfd = choose_pfd();
2026 if (pfd == -1)
2027 continue;
2028 break;
2029 }
2030
2031 /* Look up `pfd' in our table. */
2032 if ((tcp = pfd2tcb(pfd)) == NULL) {
2033 fprintf(stderr, "unknown pfd: %u\n", pfd);
2034 exit(1);
2035 }
John Hughesb6643082002-05-23 11:02:22 +00002036#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002037 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00002038#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002039 /* Get the status of the process. */
2040 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002041#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002042 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002043#else /* FREEBSD */
2044 /* Thanks to some scheduling mystery, the first poller
2045 sometimes waits for the already processed end of fork
2046 event. Doing a non blocking poll here solves the problem. */
2047 if (proc_poll_pipe[0] != -1)
2048 ioctl_result = IOCTL_STATUS (tcp);
2049 else
2050 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00002051#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002052 ioctl_errno = errno;
2053#ifndef HAVE_POLLABLE_PROCFS
2054 if (proc_poll_pipe[0] != -1) {
2055 if (ioctl_result < 0)
2056 kill(poller_pid, SIGKILL);
2057 else
2058 kill(poller_pid, SIGUSR1);
2059 }
2060#endif /* !HAVE_POLLABLE_PROCFS */
2061 }
2062 if (interrupted)
2063 return 0;
2064
2065 if (interactive)
2066 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2067
2068 if (ioctl_result < 0) {
2069 /* Find out what happened if it failed. */
2070 switch (ioctl_errno) {
2071 case EINTR:
2072 case EBADF:
2073 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002074#ifdef FREEBSD
2075 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00002076#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002077 case ENOENT:
2078 droptcb(tcp);
2079 continue;
2080 default:
2081 perror("PIOCWSTOP");
2082 exit(1);
2083 }
2084 }
2085
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002086#ifdef FREEBSD
2087 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2088 /* discard first event for a syscall we never entered */
2089 IOCTL (tcp->pfd, PIOCRUN, 0);
2090 continue;
2091 }
Roland McGrath553a6092002-12-16 20:40:39 +00002092#endif
2093
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002094 /* clear the just started flag */
2095 tcp->flags &= ~TCB_STARTUP;
2096
2097 /* set current output file */
2098 outf = tcp->outf;
2099
2100 if (cflag) {
2101 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002102#ifdef FREEBSD
2103 char buf[1024];
2104 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002105
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002106 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
2107 buf[len] = '\0';
2108 sscanf(buf,
2109 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2110 &stime.tv_sec, &stime.tv_usec);
2111 } else
2112 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002113#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002114 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2115 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002116#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002117 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2118 tcp->stime = stime;
2119 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002120 what = tcp->status.PR_WHAT;
2121 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002122#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002123 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002124 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2125 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002126 if (trace_syscall(tcp) < 0) {
2127 fprintf(stderr, "syscall trouble\n");
2128 exit(1);
2129 }
2130 }
2131 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002132#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002133 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002134#ifdef POLL_HACK
2135 in_syscall = tcp;
2136#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002137 case PR_SYSEXIT:
2138 if (trace_syscall(tcp) < 0) {
2139 fprintf(stderr, "syscall trouble\n");
2140 exit(1);
2141 }
2142 break;
2143 case PR_SIGNALLED:
2144 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
2145 printleader(tcp);
2146 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002147 signame(what), strsignal(what));
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002148 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002149#ifdef PR_INFO
2150 if (tcp->status.PR_INFO.si_signo == what) {
2151 printleader(tcp);
2152 tprintf(" siginfo=");
2153 printsiginfo(&tcp->status.PR_INFO, 1);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002154 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002155 }
2156#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002157 }
2158 break;
2159 case PR_FAULTED:
2160 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
2161 printleader(tcp);
2162 tprintf("=== FAULT %d ===", what);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002163 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002164 }
2165 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002166#ifdef FREEBSD
2167 case 0: /* handle case we polled for nothing */
2168 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00002169#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002170 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002171 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002172 exit(1);
2173 break;
2174 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002175 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002176#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002177 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00002178#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002179 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00002180#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002181 perror("PIOCRUN");
2182 exit(1);
2183 }
2184 }
2185 return 0;
2186}
2187
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002188#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002189
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002190#ifdef TCB_GROUP_EXITING
2191/* Handle an exit detach or death signal that is taking all the
2192 related clone threads with it. This is called in three circumstances:
2193 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
2194 SIG == 0 Continuing TCP will perform an exit_group syscall.
2195 SIG == other Continuing TCP with SIG will kill the process.
2196*/
2197static int
2198handle_group_exit(struct tcb *tcp, int sig)
2199{
2200 /* We need to locate our records of all the clone threads
2201 related to TCP, either its children or siblings. */
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002202 struct tcb *leader = NULL;
2203
2204 if (tcp->flags & TCB_CLONE_THREAD)
2205 leader = tcp->parent;
2206 else if (tcp->nclone_detached > 0)
2207 leader = tcp;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002208
2209 if (sig < 0) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002210 if (leader != NULL && leader != tcp
2211 && !(leader->flags & TCB_GROUP_EXITING)
2212 && !(tcp->flags & TCB_STARTUP)
2213 ) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002214 fprintf(stderr,
2215 "PANIC: handle_group_exit: %d leader %d\n",
2216 tcp->pid, leader ? leader->pid : -1);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002217 }
2218 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath1bfd3102007-08-03 10:02:00 +00002219#ifndef USE_PROCFS
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002220 resume_from_tcp(tcp);
Roland McGrath1bfd3102007-08-03 10:02:00 +00002221#endif
Roland McGrath0a463882007-07-05 18:43:16 +00002222 droptcb(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002223 }
2224 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00002225 /* Mark that we are taking the process down. */
2226 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002227 if (tcp->flags & TCB_ATTACHED) {
Roland McGrathd6a32f12007-07-11 08:35:11 +00002228 detach(tcp, sig);
Roland McGrath1bfd3102007-08-03 10:02:00 +00002229 if (leader != NULL && leader != tcp)
2230 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002231 } else {
2232 if (ptrace_restart(PTRACE_CONT, tcp, sig) < 0) {
2233 cleanup();
2234 return -1;
2235 }
2236 if (leader != NULL) {
Roland McGrath05690952004-10-20 01:00:27 +00002237 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002238 if (leader != tcp)
2239 droptcb(tcp);
2240 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002241 /* The leader will report to us as parent now,
2242 and then we'll get to the SIG==-1 case. */
2243 return 0;
2244 }
2245 }
2246
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002247 return 0;
2248}
2249#endif
2250
Denys Vlasenko215cc272009-01-09 17:22:56 +00002251static struct tcb *
2252collect_stopped_tcbs(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002253{
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002254#ifdef LINUX
2255 static int remembered_pid;
2256 static int remembered_status;
2257#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002258 int pid;
2259 int wait_errno;
2260 int status;
2261 struct tcb *tcp;
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002262 struct tcb *found_tcps;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002263#ifdef LINUX
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002264 struct tcb **nextp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002265 struct rusage ru;
Denys Vlasenko215cc272009-01-09 17:22:56 +00002266 struct rusage* ru_ptr = cflag ? &ru : NULL;
2267 int wnohang = 0;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002268#ifdef __WALL
Denys Vlasenko215cc272009-01-09 17:22:56 +00002269 int wait4_options = __WALL;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002270#endif
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002271
2272 if (remembered_pid > 0) {
2273 pid = remembered_pid;
2274 remembered_pid = 0;
2275 if (debug)
2276 fprintf(stderr, " [remembered wait(%#x) = %u]\n",
2277 remembered_status, pid);
2278 tcp = pid2tcb(pid); /* can't be NULL */
2279 tcp->wait_status = remembered_status;
2280 tcp->next_need_service = NULL;
2281 return tcp;
2282 }
2283 nextp = &found_tcps;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002284#endif /* LINUX */
2285
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002286 found_tcps = NULL;
Denys Vlasenko215cc272009-01-09 17:22:56 +00002287 while (1) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002288#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002289#ifdef __WALL
Denys Vlasenko215cc272009-01-09 17:22:56 +00002290 pid = wait4(-1, &status, wait4_options | wnohang, ru_ptr);
Roland McGrath5bc05552002-12-17 04:50:47 +00002291 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002292 /* this kernel does not support __WALL */
2293 wait4_options &= ~__WALL;
2294 errno = 0;
Denys Vlasenko215cc272009-01-09 17:22:56 +00002295 pid = wait4(-1, &status, wait4_options | wnohang, ru_ptr);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002296 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002297 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002298 /* most likely a "cloned" process */
Denys Vlasenko215cc272009-01-09 17:22:56 +00002299 pid = wait4(-1, &status, __WCLONE | wnohang, ru_ptr);
2300 if (pid < 0 && errno != ECHILD) {
2301 fprintf(stderr, "strace: wait4(WCLONE) "
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002302 "failed: %s\n", strerror(errno));
2303 }
2304 }
Denys Vlasenko215cc272009-01-09 17:22:56 +00002305#else /* !__WALL */
2306 pid = wait4(-1, &status, wnohang, ru_ptr);
2307#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002308#endif /* LINUX */
2309#ifdef SUNOS4
2310 pid = wait(&status);
2311#endif /* SUNOS4 */
2312 wait_errno = errno;
2313 if (interactive)
2314 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2315
Denys Vlasenko215cc272009-01-09 17:22:56 +00002316 if (pid == 0 && wnohang) {
2317 /* We had at least one successful
2318 * wait() before. We waited
2319 * with WNOHANG second time.
2320 * Stop collecting more tracees,
2321 * process what we already have.
2322 */
2323 break;
2324 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002325 if (pid == -1) {
Denys Vlasenko2c8a2582009-01-21 19:05:43 +00002326 if (wait_errno == EINTR)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002327 continue;
Denys Vlasenko2c8a2582009-01-21 19:05:43 +00002328 if (wait_errno == ECHILD) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002329 /*
2330 * We would like to verify this case
2331 * but sometimes a race in Solbourne's
2332 * version of SunOS sometimes reports
2333 * ECHILD before sending us SIGCHILD.
2334 */
2335#if 0
Denys Vlasenko2c8a2582009-01-21 19:05:43 +00002336 if (nprocs != 0) {
2337 fprintf(stderr, "strace: proc miscount\n");
2338 exit(1);
2339 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002340#endif
Denys Vlasenko2c8a2582009-01-21 19:05:43 +00002341 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002342 }
Denys Vlasenko2c8a2582009-01-21 19:05:43 +00002343 errno = wait_errno;
2344 perror("strace: wait");
2345 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002346 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002347 if (pid == popen_pid) {
2348 if (WIFEXITED(status) || WIFSIGNALED(status))
2349 popen_pid = -1;
2350 continue;
2351 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002352 if (debug)
2353 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2354
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002355 /* RHEL5 bug workaround.
2356 * It can re-report stopped tasks. Happens on SIGSTOPs here.
2357 * Second (bogus) report has signal# set to 0.
2358 * Stop collecting and process what we have.
2359 */
2360 if (WIFSTOPPED(status) && WSTOPSIG(status) == 0)
2361 break;
2362
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002363 /* Look up `pid' in our table. */
2364 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002365#ifdef LINUX
Roland McGrath41c48222008-07-18 00:25:10 +00002366 if (followfork) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002367 /* This is needed to go with the CLONE_PTRACE
2368 changes in process.c/util.c: we might see
2369 the child's initial trap before we see the
2370 parent return from the clone syscall.
2371 Leave the child suspended until the parent
2372 returns from its system call. Only then
2373 will we have the association of parent and
2374 child so that we know how to do clearbpt
2375 in the child. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +00002376 tcp = alloctcb(pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002377 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002378 if (!qflag)
2379 fprintf(stderr, "\
2380Process %d attached (waiting for parent)\n",
2381 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002382 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002383 else
2384 /* This can happen if a clone call used
2385 CLONE_PTRACE itself. */
Denys Vlasenko215cc272009-01-09 17:22:56 +00002386#endif /* LINUX */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002387 {
2388 fprintf(stderr, "unknown pid: %u\n", pid);
2389 if (WIFSTOPPED(status))
2390 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2391 exit(1);
2392 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002393 }
Denys Vlasenko215cc272009-01-09 17:22:56 +00002394
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002395 if (cflag) {
2396#ifdef LINUX
2397 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2398 tcp->stime = ru.ru_stime;
Denys Vlasenko215cc272009-01-09 17:22:56 +00002399#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002400 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002401 if (tcp->flags & TCB_SUSPENDED) {
2402 /*
2403 * Apparently, doing any ptrace() call on a stopped
2404 * process, provokes the kernel to report the process
2405 * status again on a subsequent wait(), even if the
2406 * process has not been actually restarted.
2407 * Since we have inspected the arguments of suspended
2408 * processes we end up here testing for this case.
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002409 *
2410 * We also end up here when we catch new pid of
2411 * CLONE_PTRACEd process. Do not process/restart it
2412 * until we see corresponding clone() syscall exit
2413 * in its parent.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002414 */
2415 continue;
2416 }
Denys Vlasenko215cc272009-01-09 17:22:56 +00002417
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002418#ifdef LINUX
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002419 /* So far observed only on RHEL5 ia64, but I imagine this
2420 * can legitimately happen elsewhere.
2421 * If we waited and got a stopped task notification,
2422 * subsequent wait may return the same pid again, for example,
2423 * with SIGKILL notification. SIGKILL kills even stopped tasks.
2424 * We must not add it to the list
2425 * (one task can't be inserted twice in the list).
2426 */
2427 {
2428 struct tcb *f = found_tcps;
2429 while (f) {
2430 if (f == tcp) {
2431 remembered_pid = pid;
2432 remembered_status = status;
2433 return found_tcps;
2434 }
2435 f = f->next_need_service;
2436 }
2437 }
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002438 /* It is important to not invert the order of tasks
2439 * to process. For one, alloc_tcb() above picks newly forked
2440 * threads in some order, processing of them and their parent
2441 * should be in the same order, otherwise bad things happen
2442 * (misinterpreted SIGSTOPs and such).
2443 */
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002444 tcp->wait_status = status;
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002445 *nextp = tcp;
2446 nextp = &tcp->next_need_service;
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002447 *nextp = NULL;
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002448 wnohang = WNOHANG;
2449#endif
2450#ifdef SUNOS4
2451 /* Probably need to replace wait with waitpid
2452 * and loop on Sun too, but I can't test it. Volunteers?
2453 */
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002454 tcp->wait_status = status;
2455 tcp->next_need_service = NULL;
2456 found_tcps = tcp;
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002457 break;
2458#endif
Denys Vlasenko47ce6df2009-01-27 19:38:44 +00002459 } /* while (1) - collecting all stopped/exited tracees */
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002460
Denys Vlasenkof9a7e632009-01-17 00:21:31 +00002461 return found_tcps;
2462}
2463
2464static int
2465handle_stopped_tcbs(struct tcb *tcp)
2466{
2467 for (; tcp; tcp = tcp->next_need_service) {
2468 int pid;
2469 int status;
2470
Denys Vlasenko215cc272009-01-09 17:22:56 +00002471 outf = tcp->outf;
2472 status = tcp->wait_status;
2473 pid = tcp->pid;
2474
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002475 if (WIFSIGNALED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002476 if (pid == strace_child)
2477 exit_code = 0x100 | WTERMSIG(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002478 if (!cflag
2479 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2480 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002481 tprintf("+++ killed by %s %s+++",
2482 signame(WTERMSIG(status)),
2483#ifdef WCOREDUMP
2484 WCOREDUMP(status) ? "(core dumped) " :
2485#endif
2486 "");
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002487 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002488 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002489#ifdef TCB_GROUP_EXITING
2490 handle_group_exit(tcp, -1);
2491#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002492 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002493#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002494 continue;
2495 }
2496 if (WIFEXITED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002497 if (pid == strace_child)
2498 exit_code = WEXITSTATUS(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002499 if (debug)
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002500 fprintf(stderr, "pid %u exited with %d\n", pid, WEXITSTATUS(status));
2501 if ((tcp->flags & (TCB_ATTACHED|TCB_STARTUP)) == TCB_ATTACHED
Roland McGrath05690952004-10-20 01:00:27 +00002502#ifdef TCB_GROUP_EXITING
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002503 && !(tcp->parent && (tcp->parent->flags & TCB_GROUP_EXITING))
Roland McGrath1bfd3102007-08-03 10:02:00 +00002504 && !(tcp->flags & TCB_GROUP_EXITING)
Roland McGrath05690952004-10-20 01:00:27 +00002505#endif
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002506 ) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002507 fprintf(stderr,
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002508 "PANIC: attached pid %u exited with %d\n",
2509 pid, WEXITSTATUS(status));
2510 }
Roland McGrath0a396902003-06-10 03:05:53 +00002511 if (tcp == tcp_last) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002512 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT)) == TCB_INSYSCALL)
Roland McGrath0a396902003-06-10 03:05:53 +00002513 tprintf(" <unfinished ... exit status %d>\n",
2514 WEXITSTATUS(status));
2515 tcp_last = NULL;
2516 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002517#ifdef TCB_GROUP_EXITING
2518 handle_group_exit(tcp, -1);
2519#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002520 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002521#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002522 continue;
2523 }
2524 if (!WIFSTOPPED(status)) {
2525 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2526 droptcb(tcp);
2527 continue;
2528 }
2529 if (debug)
2530 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002531 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002532
Roland McGrath02203312007-06-11 22:06:31 +00002533 /*
2534 * Interestingly, the process may stop
2535 * with STOPSIG equal to some other signal
2536 * than SIGSTOP if we happend to attach
2537 * just before the process takes a signal.
2538 */
2539 if ((tcp->flags & TCB_STARTUP) && WSTOPSIG(status) == SIGSTOP) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002540 /*
2541 * This flag is there to keep us in sync.
2542 * Next time this process stops it should
2543 * really be entering a system call.
2544 */
2545 tcp->flags &= ~TCB_STARTUP;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002546 if (tcp->flags & TCB_BPTSET) {
Roland McGrath02203312007-06-11 22:06:31 +00002547 /*
2548 * One example is a breakpoint inherited from
2549 * parent through fork ().
2550 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002551 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2552 droptcb(tcp);
2553 cleanup();
2554 return -1;
2555 }
2556 }
Denys Vlasenkob1efe532008-12-23 16:14:42 +00002557/* Add more OSes after you verified it works for them. */
Denys Vlasenkof535b542009-01-13 18:30:55 +00002558/* PTRACE_SETOPTIONS may be an enum, not a #define.
2559 * But sometimes we can test for it by checking PT_SETOPTIONS.
2560 */
2561#if defined LINUX && (defined PTRACE_SETOPTIONS || defined PT_SETOPTIONS)
Denys Vlasenko0861ecb2009-01-02 16:55:24 +00002562# ifndef PTRACE_O_TRACESYSGOOD
2563# define PTRACE_O_TRACESYSGOOD 0x00000001
2564# endif
2565# ifndef PTRACE_O_TRACEEXEC
2566# define PTRACE_O_TRACEEXEC 0x00000010
2567# endif
2568# ifndef PTRACE_EVENT_EXEC
2569# define PTRACE_EVENT_EXEC 4
2570# endif
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002571 /*
2572 * Ask kernel to set signo to SIGTRAP | 0x80
2573 * on ptrace-generated SIGTRAPs, and mark
2574 * execve's SIGTRAP with PTRACE_EVENT_EXEC.
2575 */
Denys Vlasenko96d5a762008-12-29 19:13:27 +00002576 if (!ptrace_opts_set) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002577 char *p;
Denys Vlasenko96d5a762008-12-29 19:13:27 +00002578 ptrace_opts_set = 1;
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002579
2580 /* RHEL 2.6.18 definitely has crippling bugs */
2581 /* Vanilla and Fedora 2.6.29 seems to work */
2582 p = utsname_buf.release;
2583 if (strtoul(p, &p, 10) < 2 || *p != '.')
2584 goto tracing;
2585 if (strtoul(++p, &p, 10) < 6 || *p != '.')
2586 goto tracing;
2587 if (strtoul(++p, &p, 10) < 29)
2588 goto tracing;
Denys Vlasenko96d5a762008-12-29 19:13:27 +00002589 /*
2590 * NB: even if this "succeeds", we can
2591 * revert back to SIGTRAP if we later see
2592 * that it didnt really work.
2593 * Old kernels are known to lie here.
2594 */
2595 if (ptrace(PTRACE_SETOPTIONS, pid, (char *) 0,
2596 (void *) (PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC)) == 0)
2597 ptrace_stop_sig = SIGTRAP | 0x80;
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002598 }
2599#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002600 goto tracing;
2601 }
2602
Denys Vlasenkof535b542009-01-13 18:30:55 +00002603#if defined LINUX && (defined PTRACE_SETOPTIONS || defined PT_SETOPTIONS)
Denys Vlasenko96d5a762008-12-29 19:13:27 +00002604 if (ptrace_stop_sig != SIGTRAP && WSTOPSIG(status) == SIGTRAP) {
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002605 /*
2606 * We told ptrace to report SIGTRAP | 0x80 on this process
2607 * but got bare SIGTRAP. This can be a genuine SIGTRAP:
2608 * kill(pid, SIGTRAP), trap insn, etc;
2609 * but be paranoid about it.
2610 */
2611 if (((unsigned)status >> 16) == PTRACE_EVENT_EXEC) {
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00002612 /* It's post-exec ptrace stop. Ignore it,
2613 * we will get syscall exit ptrace stop later.
2614 */
2615#ifdef TCB_WAITEXECVE
2616 tcp->flags &= ~TCB_WAITEXECVE;
2617#endif
2618 goto tracing;
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002619 } else {
2620 /* Take a better look... */
2621 siginfo_t si;
Denys Vlasenko1d5b1132009-01-17 01:06:18 +00002622 si.si_signo = 0;
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002623 ptrace(PTRACE_GETSIGINFO, pid, (void*) 0, (void*) &si);
2624 /*
2625 * Check some fields to make sure we see
2626 * real SIGTRAP.
2627 * Otherwise interpret it as ptrace stop.
2628 * Real SIGTRAPs (int3 insn on x86, kill() etc)
2629 * have these values:
2630 * int3: kill -TRAP $pid:
2631 * si_signo:5 (SIGTRAP) si_signo:5 (SIGTRAP)
2632 * si_errno:0 si_errno:(?)
2633 * si_code:128 (SI_KERNEL) si_code:0 (SI_USER)
2634 * si_pid:0 si_pid:(>0?)
2635 * si_band:0 si_band:(?)
2636 * Ptrace stops have garbage there instead.
2637 */
2638 if (si.si_signo != SIGTRAP
2639 || (si.si_code != SI_KERNEL && si.si_code != SI_USER)
2640 ) {
Denys Vlasenko96d5a762008-12-29 19:13:27 +00002641 fprintf(stderr, "bogus SIGTRAP (si_code:%x), assuming old kernel\n", si.si_code);
2642 ptrace_stop_sig = SIGTRAP;
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002643 }
2644 }
2645 }
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002646#endif
2647
Denys Vlasenko96d5a762008-12-29 19:13:27 +00002648 if (WSTOPSIG(status) != ptrace_stop_sig) {
Denys Vlasenko1e3ce322008-12-22 19:14:47 +00002649 /* This isn't a ptrace stop. */
2650
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002651 if (WSTOPSIG(status) == SIGSTOP &&
2652 (tcp->flags & TCB_SIGTRAPPED)) {
2653 /*
2654 * Trapped attempt to block SIGTRAP
2655 * Hope we are back in control now.
2656 */
2657 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002658 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002659 cleanup();
2660 return -1;
2661 }
2662 continue;
2663 }
2664 if (!cflag
2665 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00002666 unsigned long addr = 0;
2667 long pc = 0;
Dmitry V. Levin96339422006-10-11 23:11:43 +00002668#if defined(PT_CR_IPSR) && defined(PT_CR_IIP) && defined(PT_GETSIGINFO)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002669# define PSR_RI 41
2670 struct siginfo si;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002671 long psr;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002672
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002673 upeek(tcp, PT_CR_IPSR, &psr);
2674 upeek(tcp, PT_CR_IIP, &pc);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002675
2676 pc += (psr >> PSR_RI) & 0x3;
2677 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2678 addr = (unsigned long) si.si_addr;
Roland McGrath3a055d72005-03-06 22:24:29 +00002679#elif defined PTRACE_GETSIGINFO
2680 if (WSTOPSIG(status) == SIGSEGV ||
2681 WSTOPSIG(status) == SIGBUS) {
2682 siginfo_t si;
2683 if (ptrace(PTRACE_GETSIGINFO, pid,
2684 0, &si) == 0)
2685 addr = (unsigned long)
2686 si.si_addr;
2687 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002688#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002689 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002690 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002691 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002692 strsignal(WSTOPSIG(status)), pc, addr);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002693 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002694 }
Roland McGrath05690952004-10-20 01:00:27 +00002695 if (((tcp->flags & TCB_ATTACHED) ||
2696 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002697 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002698#ifdef TCB_GROUP_EXITING
2699 handle_group_exit(tcp, WSTOPSIG(status));
2700#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002701 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002702#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002703 continue;
2704 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002705 if (ptrace_restart(PTRACE_SYSCALL, tcp, WSTOPSIG(status)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002706 cleanup();
2707 return -1;
2708 }
2709 tcp->flags &= ~TCB_SUSPENDED;
2710 continue;
2711 }
Roland McGrath02203312007-06-11 22:06:31 +00002712 /* we handled the STATUS, we are permitted to interrupt now. */
2713 if (interrupted)
2714 return 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002715 if (trace_syscall(tcp) < 0 && !tcp->ptrace_errno) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002716 /* ptrace() failed in trace_syscall() with ESRCH.
2717 * Likely a result of process disappearing mid-flight.
2718 * Observed case: exit_group() terminating
2719 * all processes in thread group. In this case, threads
2720 * "disappear" in an unpredictable moment without any
2721 * notification to strace via wait().
2722 */
2723 if (tcp->flags & TCB_ATTACHED) {
2724 if (tcp_last) {
2725 /* Do we have dangling line "syscall(param, param"?
2726 * Finish the line then. We cannot
2727 */
2728 tcp_last->flags |= TCB_REPRINT;
2729 tprintf(" <unfinished ...>");
2730 printtrailer();
2731 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002732 detach(tcp, 0);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002733 } else {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002734 ptrace(PTRACE_KILL,
2735 tcp->pid, (char *) 1, SIGTERM);
2736 droptcb(tcp);
2737 }
2738 continue;
2739 }
2740 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002741#ifdef TCB_GROUP_EXITING
2742 if (tcp->flags & TCB_GROUP_EXITING) {
2743 if (handle_group_exit(tcp, 0) < 0)
2744 return -1;
2745 continue;
2746 }
2747#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002748 if (tcp->flags & TCB_ATTACHED)
2749 detach(tcp, 0);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002750 else if (ptrace_restart(PTRACE_CONT, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002751 cleanup();
2752 return -1;
2753 }
2754 continue;
2755 }
2756 if (tcp->flags & TCB_SUSPENDED) {
2757 if (!qflag)
2758 fprintf(stderr, "Process %u suspended\n", pid);
2759 continue;
2760 }
2761 tracing:
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002762 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002763 cleanup();
2764 return -1;
2765 }
Denys Vlasenko215cc272009-01-09 17:22:56 +00002766 } /* for each tcp */
2767
2768 return 0;
2769}
2770
2771static int
2772trace()
2773{
2774 int rc;
2775 struct tcb *tcbs;
2776
2777 while (nprocs != 0) {
2778 if (interrupted)
2779 return 0;
2780 if (interactive)
2781 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2782
2783 /* The loop of "wait for one tracee, serve it, repeat"
2784 * may leave some tracees never served.
2785 * Kernel provides no guarantees of fairness when you have
2786 * many waitable tasks.
2787 * Try strace -f with test/many_looping_threads.c example.
2788 * To fix it, we collect *all* waitable tasks, then handle
2789 * them all, then repeat.
2790 */
2791 tcbs = collect_stopped_tcbs();
2792 if (!tcbs)
2793 break;
2794 rc = handle_stopped_tcbs(tcbs);
2795 if (rc)
2796 return rc;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002797 }
2798 return 0;
2799}
2800
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002801#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002802
2803static int curcol;
2804
2805#ifdef __STDC__
2806#include <stdarg.h>
2807#define VA_START(a, b) va_start(a, b)
2808#else
2809#include <varargs.h>
2810#define VA_START(a, b) va_start(a)
2811#endif
2812
2813void
2814#ifdef __STDC__
2815tprintf(const char *fmt, ...)
2816#else
2817tprintf(fmt, va_alist)
2818char *fmt;
2819va_dcl
2820#endif
2821{
2822 va_list args;
2823
2824 VA_START(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002825 if (outf) {
2826 int n = vfprintf(outf, fmt, args);
2827 if (n < 0 && outf != stderr)
2828 perror(outfname == NULL
2829 ? "<writing to pipe>" : outfname);
2830 else
2831 curcol += n;
2832 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002833 va_end(args);
2834 return;
2835}
2836
2837void
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002838printleader(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002839{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002840 if (tcp_last) {
2841 if (tcp_last->ptrace_errno) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002842 tcp_last->ptrace_errno = 0;
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002843 if (tcp_last->flags & TCB_INSYSCALL) {
2844 tprintf(" <unavailable ...>\n");
2845 tcp_last->flags |= TCB_REPRINT;
2846 } else {
2847 tprintf("= ? <unavailable>\n");
2848 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002849 } else if (!outfname || followfork < 2 || tcp_last == tcp) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002850 tprintf(" <unfinished ...>\n");
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002851 tcp_last->flags |= TCB_REPRINT;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002852 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002853 }
2854 curcol = 0;
2855 if ((followfork == 1 || pflag_seen > 1) && outfname)
2856 tprintf("%-5d ", tcp->pid);
2857 else if (nprocs > 1 && !outfname)
2858 tprintf("[pid %5u] ", tcp->pid);
2859 if (tflag) {
2860 char str[sizeof("HH:MM:SS")];
2861 struct timeval tv, dtv;
2862 static struct timeval otv;
2863
2864 gettimeofday(&tv, NULL);
2865 if (rflag) {
2866 if (otv.tv_sec == 0)
2867 otv = tv;
2868 tv_sub(&dtv, &tv, &otv);
2869 tprintf("%6ld.%06ld ",
2870 (long) dtv.tv_sec, (long) dtv.tv_usec);
2871 otv = tv;
2872 }
2873 else if (tflag > 2) {
2874 tprintf("%ld.%06ld ",
2875 (long) tv.tv_sec, (long) tv.tv_usec);
2876 }
2877 else {
2878 time_t local = tv.tv_sec;
2879 strftime(str, sizeof(str), "%T", localtime(&local));
2880 if (tflag > 1)
2881 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2882 else
2883 tprintf("%s ", str);
2884 }
2885 }
2886 if (iflag)
2887 printcall(tcp);
2888}
2889
2890void
2891tabto(col)
2892int col;
2893{
2894 if (curcol < col)
2895 tprintf("%*s", col - curcol, "");
2896}
2897
2898void
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002899printtrailer(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002900{
2901 tprintf("\n");
2902 tcp_last = NULL;
2903}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002904
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002905#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002906
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002907int
2908mp_ioctl(int fd, int cmd, void *arg, int size)
2909{
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002910 struct iovec iov[2];
2911 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002912
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002913 iov[0].iov_base = &cmd;
2914 iov[0].iov_len = sizeof cmd;
2915 if (arg) {
2916 ++n;
2917 iov[1].iov_base = arg;
2918 iov[1].iov_len = size;
2919 }
Roland McGrath553a6092002-12-16 20:40:39 +00002920
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002921 return writev(fd, iov, n);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002922}
2923
2924#endif