blob: 9f3c7247c65914c40d34cbcde6a274947c23a524 [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00006 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * $Id$
31 */
32
33#include "defs.h"
34
Roland McGrath795edb12005-02-02 04:44:57 +000035#include <sys/types.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000036#include <signal.h>
37#include <errno.h>
38#include <sys/param.h>
39#include <fcntl.h>
40#include <sys/resource.h>
41#include <sys/wait.h>
42#include <sys/stat.h>
43#include <pwd.h>
44#include <grp.h>
45#include <string.h>
John Hughes19e49982001-10-19 08:59:12 +000046#include <limits.h>
Roland McGrath70b08532004-04-09 00:25:21 +000047#include <dirent.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000048
Roland McGrath134813a2007-06-02 00:07:33 +000049#ifdef LINUX
50# include <asm/unistd.h>
51# if defined __NR_tgkill
52# define my_tgkill(pid, tid, sig) syscall (__NR_tgkill, (pid), (tid), (sig))
53# elif defined __NR_tkill
54# define my_tgkill(pid, tid, sig) syscall (__NR_tkill, (tid), (sig))
55# else
56 /* kill() may choose arbitrarily the target task of the process group
57 while we later wait on a that specific TID. PID process waits become
58 TID task specific waits for a process under ptrace(2). */
59# warning "Neither tkill(2) nor tgkill(2) available, risk of strace hangs!"
60# define my_tgkill(pid, tid, sig) kill ((tid), (sig))
61# endif
62#endif
63
Wichert Akkerman7b3346b2001-10-09 23:47:38 +000064#if defined(IA64) && defined(LINUX)
65# include <asm/ptrace_offsets.h>
66#endif
67
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +000068#ifdef USE_PROCFS
69#include <poll.h>
70#endif
71
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000072#ifdef SVR4
73#include <sys/stropts.h>
Wichert Akkermanea78f0f1999-11-29 15:34:02 +000074#ifdef HAVE_MP_PROCFS
John Hughes1d08dcf2001-07-10 13:48:44 +000075#ifdef HAVE_SYS_UIO_H
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000076#include <sys/uio.h>
77#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000078#endif
John Hughes1d08dcf2001-07-10 13:48:44 +000079#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000080
Roland McGrath41c48222008-07-18 00:25:10 +000081int debug = 0, followfork = 0;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +000082int dtime = 0, cflag = 0, xflag = 0, qflag = 0;
83static int iflag = 0, interactive = 0, pflag_seen = 0, rflag = 0, tflag = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000084
Michal Ludvig17f8fb32002-11-06 13:17:21 +000085/* Sometimes we want to print only succeeding syscalls. */
86int not_failing_only = 0;
87
Dmitry V. Levina6809652008-11-10 17:14:58 +000088static int exit_code = 0;
89static int strace_child = 0;
90
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +000091static char *username = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000092uid_t run_uid;
93gid_t run_gid;
94
95int acolumn = DEFAULT_ACOLUMN;
96int max_strlen = DEFAULT_STRLEN;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +000097static char *outfname = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000098FILE *outf;
Roland McGrathee9d4352002-12-18 04:16:10 +000099struct tcb **tcbtab;
100unsigned int nprocs, tcbtabsize;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000101char *progname;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000102extern char **environ;
103
Roland McGrath0a463882007-07-05 18:43:16 +0000104static int detach P((struct tcb *tcp, int sig));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000105static int trace P((void));
106static void cleanup P((void));
107static void interrupt P((int sig));
108static sigset_t empty_set, blocked_set;
109
110#ifdef HAVE_SIG_ATOMIC_T
111static volatile sig_atomic_t interrupted;
112#else /* !HAVE_SIG_ATOMIC_T */
113#ifdef __STDC__
114static volatile int interrupted;
115#else /* !__STDC__ */
116static int interrupted;
117#endif /* !__STDC__ */
118#endif /* !HAVE_SIG_ATOMIC_T */
119
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000120#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000121
122static struct tcb *pfd2tcb P((int pfd));
123static void reaper P((int sig));
124static void rebuild_pollv P((void));
Roland McGrathee9d4352002-12-18 04:16:10 +0000125static struct pollfd *pollv;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000126
127#ifndef HAVE_POLLABLE_PROCFS
128
129static void proc_poll_open P((void));
130static void proc_poller P((int pfd));
131
132struct proc_pollfd {
133 int fd;
134 int revents;
135 int pid;
136};
137
138static int poller_pid;
139static int proc_poll_pipe[2] = { -1, -1 };
140
141#endif /* !HAVE_POLLABLE_PROCFS */
142
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000143#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000144#define POLLWANT POLLWRNORM
145#else
146#define POLLWANT POLLPRI
147#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000148#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000149
150static void
151usage(ofp, exitval)
152FILE *ofp;
153int exitval;
154{
155 fprintf(ofp, "\
156usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000157 [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n\
158 [command [arg ...]]\n\
159 or: strace -c [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n\
160 [command [arg ...]]\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000161-c -- count time, calls, and errors for each syscall and report summary\n\
162-f -- follow forks, -ff -- with output into separate files\n\
163-F -- attempt to follow vforks, -h -- print help message\n\
164-i -- print instruction pointer at time of syscall\n\
165-q -- suppress messages about attaching, detaching, etc.\n\
166-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
167-T -- print time spent in each syscall, -V -- print version\n\
168-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
169-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
170-a column -- alignment COLUMN for printing syscall results (default %d)\n\
171-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
172 options: trace, abbrev, verbose, raw, signal, read, or write\n\
173-o file -- send trace output to FILE instead of stderr\n\
174-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
175-p pid -- trace process with process id PID, may be repeated\n\
176-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
177-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
178-u username -- run command as username handling setuid and/or setgid\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000179-E var=val -- put var=val in the environment for command\n\
180-E var -- remove var from the environment for command\n\
181" /* this is broken, so don't document it
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000182-z -- print only succeeding syscalls\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000183 */
184, DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000185 exit(exitval);
186}
187
188#ifdef SVR4
189#ifdef MIPS
190void
191foobar()
192{
193}
194#endif /* MIPS */
195#endif /* SVR4 */
196
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000197static int
198set_cloexec_flag(int fd)
199{
200 int flags, newflags;
201
202 if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
203 {
204 fprintf(stderr, "%s: fcntl F_GETFD: %s\n",
205 progname, strerror(errno));
206 return -1;
207 }
208
209 newflags = flags | FD_CLOEXEC;
210 if (flags == newflags)
211 return 0;
212
213 if (fcntl(fd, F_SETFD, newflags) < 0)
214 {
215 fprintf(stderr, "%s: fcntl F_SETFD: %s\n",
216 progname, strerror(errno));
217 return -1;
218 }
219
220 return 0;
221}
222
223/*
224 * When strace is setuid executable, we have to swap uids
225 * before and after filesystem and process management operations.
226 */
227static void
228swap_uid(void)
229{
230#ifndef SVR4
231 int euid = geteuid(), uid = getuid();
232
233 if (euid != uid && setreuid(euid, uid) < 0)
234 {
235 fprintf(stderr, "%s: setreuid: %s\n",
236 progname, strerror(errno));
237 exit(1);
238 }
239#endif
240}
241
Roland McGrath4bfa6262007-07-05 20:03:16 +0000242#if _LFS64_LARGEFILE
243# define fopen_for_output fopen64
244#else
245# define fopen_for_output fopen
246#endif
247
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000248static FILE *
249strace_fopen(const char *path, const char *mode)
250{
251 FILE *fp;
252
253 swap_uid();
Roland McGrath4bfa6262007-07-05 20:03:16 +0000254 if ((fp = fopen_for_output(path, mode)) == NULL)
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000255 fprintf(stderr, "%s: can't fopen '%s': %s\n",
256 progname, path, strerror(errno));
257 swap_uid();
258 if (fp && set_cloexec_flag(fileno(fp)) < 0)
259 {
260 fclose(fp);
261 fp = NULL;
262 }
263 return fp;
264}
265
266static int popen_pid = -1;
267
268#ifndef _PATH_BSHELL
269# define _PATH_BSHELL "/bin/sh"
270#endif
271
272/*
273 * We cannot use standard popen(3) here because we have to distinguish
274 * popen child process from other processes we trace, and standard popen(3)
275 * does not export its child's pid.
276 */
277static FILE *
278strace_popen(const char *command)
279{
280 int fds[2];
281
282 swap_uid();
283 if (pipe(fds) < 0)
284 {
285 fprintf(stderr, "%s: pipe: %s\n",
286 progname, strerror(errno));
287 swap_uid();
288 return NULL;
289 }
290
291 if (set_cloexec_flag(fds[1]) < 0)
292 {
293 close(fds[0]);
294 close(fds[1]);
295 swap_uid();
296 return NULL;
297 }
298
299 if ((popen_pid = fork()) == -1)
300 {
301 fprintf(stderr, "%s: fork: %s\n",
302 progname, strerror(errno));
303 close(fds[0]);
304 close(fds[1]);
305 swap_uid();
306 return NULL;
307 }
308
309 if (popen_pid)
310 {
311 /* parent */
312 close(fds[0]);
313 swap_uid();
314 return fdopen(fds[1], "w");
315 } else
316 {
317 /* child */
318 close(fds[1]);
319 if (fds[0] && (dup2(fds[0], 0) || close(fds[0])))
320 {
321 fprintf(stderr, "%s: dup2: %s\n",
322 progname, strerror(errno));
323 _exit(1);
324 }
325 execl(_PATH_BSHELL, "sh", "-c", command, NULL);
326 fprintf(stderr, "%s: execl: %s: %s\n",
327 progname, _PATH_BSHELL, strerror(errno));
328 _exit(1);
329 }
330}
331
332static int
333newoutf(struct tcb *tcp)
334{
335 if (outfname && followfork > 1) {
336 char name[MAXPATHLEN];
337 FILE *fp;
338
339 sprintf(name, "%s.%u", outfname, tcp->pid);
340 if ((fp = strace_fopen(name, "w")) == NULL)
341 return -1;
342 tcp->outf = fp;
343 }
344 return 0;
345}
346
Roland McGrath02203312007-06-11 22:06:31 +0000347static void
348startup_attach(void)
349{
350 int tcbi;
351 struct tcb *tcp;
352
353 /*
354 * Block user interruptions as we would leave the traced
355 * process stopped (process state T) if we would terminate in
356 * between PTRACE_ATTACH and wait4 () on SIGSTOP.
357 * We rely on cleanup () from this point on.
358 */
359 if (interactive)
360 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
361
362 for (tcbi = 0; tcbi < tcbtabsize; tcbi++) {
363 tcp = tcbtab[tcbi];
364 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
365 continue;
366#ifdef LINUX
367 if (tcp->flags & TCB_CLONE_THREAD)
368 continue;
369#endif
370 /* Reinitialize the output since it may have changed. */
371 tcp->outf = outf;
372 if (newoutf(tcp) < 0)
373 exit(1);
374
375#ifdef USE_PROCFS
376 if (proc_open(tcp, 1) < 0) {
377 fprintf(stderr, "trouble opening proc file\n");
378 droptcb(tcp);
379 continue;
380 }
381#else /* !USE_PROCFS */
382# ifdef LINUX
383 if (followfork) {
384 char procdir[MAXPATHLEN];
385 DIR *dir;
386
387 sprintf(procdir, "/proc/%d/task", tcp->pid);
388 dir = opendir(procdir);
389 if (dir != NULL) {
390 unsigned int ntid = 0, nerr = 0;
391 struct dirent *de;
392 int tid;
393 while ((de = readdir(dir)) != NULL) {
394 if (de->d_fileno == 0 ||
395 de->d_name[0] == '.')
396 continue;
397 tid = atoi(de->d_name);
398 if (tid <= 0)
399 continue;
400 ++ntid;
401 if (ptrace(PTRACE_ATTACH, tid,
402 (char *) 1, 0) < 0)
403 ++nerr;
404 else if (tid != tcbtab[tcbi]->pid) {
405 if (nprocs == tcbtabsize &&
406 expand_tcbtab())
407 tcp = NULL;
408 else
409 tcp = alloctcb(tid);
410 if (tcp == NULL)
411 exit(1);
412 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_CLONE_DETACHED|TCB_FOLLOWFORK;
413 tcbtab[tcbi]->nchildren++;
414 tcbtab[tcbi]->nclone_threads++;
415 tcbtab[tcbi]->nclone_detached++;
416 tcp->parent = tcbtab[tcbi];
417 }
418 if (interactive) {
419 sigprocmask(SIG_SETMASK, &empty_set, NULL);
420 if (interrupted)
421 return;
422 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
423 }
424 }
425 closedir(dir);
426 if (nerr == ntid) {
427 perror("attach: ptrace(PTRACE_ATTACH, ...)");
428 droptcb(tcp);
429 continue;
430 }
431 if (!qflag) {
432 ntid -= nerr;
433 if (ntid > 1)
434 fprintf(stderr, "\
435Process %u attached with %u threads - interrupt to quit\n",
436 tcp->pid, ntid);
437 else
438 fprintf(stderr, "\
439Process %u attached - interrupt to quit\n",
440 tcp->pid);
441 }
442 continue;
443 }
444 }
445# endif
446 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
447 perror("attach: ptrace(PTRACE_ATTACH, ...)");
448 droptcb(tcp);
449 continue;
450 }
451 /* INTERRUPTED is going to be checked at the top of TRACE. */
452#endif /* !USE_PROCFS */
453 if (!qflag)
454 fprintf(stderr,
455 "Process %u attached - interrupt to quit\n",
456 tcp->pid);
457 }
458
459 if (interactive)
460 sigprocmask(SIG_SETMASK, &empty_set, NULL);
461}
462
463static void
464startup_child (char **argv)
465{
466 struct stat statbuf;
467 const char *filename;
468 char pathname[MAXPATHLEN];
469 int pid = 0;
470 struct tcb *tcp;
471
472 filename = argv[0];
473 if (strchr(filename, '/')) {
474 if (strlen(filename) > sizeof pathname - 1) {
475 errno = ENAMETOOLONG;
476 perror("strace: exec");
477 exit(1);
478 }
479 strcpy(pathname, filename);
480 }
481#ifdef USE_DEBUGGING_EXEC
482 /*
483 * Debuggers customarily check the current directory
484 * first regardless of the path but doing that gives
485 * security geeks a panic attack.
486 */
487 else if (stat(filename, &statbuf) == 0)
488 strcpy(pathname, filename);
489#endif /* USE_DEBUGGING_EXEC */
490 else {
491 char *path;
492 int m, n, len;
493
494 for (path = getenv("PATH"); path && *path; path += m) {
495 if (strchr(path, ':')) {
496 n = strchr(path, ':') - path;
497 m = n + 1;
498 }
499 else
500 m = n = strlen(path);
501 if (n == 0) {
502 if (!getcwd(pathname, MAXPATHLEN))
503 continue;
504 len = strlen(pathname);
505 }
506 else if (n > sizeof pathname - 1)
507 continue;
508 else {
509 strncpy(pathname, path, n);
510 len = n;
511 }
512 if (len && pathname[len - 1] != '/')
513 pathname[len++] = '/';
514 strcpy(pathname + len, filename);
515 if (stat(pathname, &statbuf) == 0 &&
516 /* Accept only regular files
517 with some execute bits set.
518 XXX not perfect, might still fail */
519 S_ISREG(statbuf.st_mode) &&
520 (statbuf.st_mode & 0111))
521 break;
522 }
523 }
524 if (stat(pathname, &statbuf) < 0) {
525 fprintf(stderr, "%s: %s: command not found\n",
526 progname, filename);
527 exit(1);
528 }
Dmitry V. Levina6809652008-11-10 17:14:58 +0000529 strace_child = pid = fork();
530 switch (pid) {
Roland McGrath02203312007-06-11 22:06:31 +0000531 case -1:
532 perror("strace: fork");
533 cleanup();
534 exit(1);
535 break;
536 case 0: {
537#ifdef USE_PROCFS
538 if (outf != stderr) close (fileno (outf));
539#ifdef MIPS
540 /* Kludge for SGI, see proc_open for details. */
541 sa.sa_handler = foobar;
542 sa.sa_flags = 0;
543 sigemptyset(&sa.sa_mask);
544 sigaction(SIGINT, &sa, NULL);
545#endif /* MIPS */
546#ifndef FREEBSD
547 pause();
548#else /* FREEBSD */
549 kill(getpid(), SIGSTOP); /* stop HERE */
550#endif /* FREEBSD */
551#else /* !USE_PROCFS */
552 if (outf!=stderr)
553 close(fileno (outf));
554
555 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
556 perror("strace: ptrace(PTRACE_TRACEME, ...)");
557 exit(1);
558 }
559 if (debug)
560 kill(getpid(), SIGSTOP);
561
562 if (username != NULL || geteuid() == 0) {
563 uid_t run_euid = run_uid;
564 gid_t run_egid = run_gid;
565
566 if (statbuf.st_mode & S_ISUID)
567 run_euid = statbuf.st_uid;
568 if (statbuf.st_mode & S_ISGID)
569 run_egid = statbuf.st_gid;
570
571 /*
572 * It is important to set groups before we
573 * lose privileges on setuid.
574 */
575 if (username != NULL) {
576 if (initgroups(username, run_gid) < 0) {
577 perror("initgroups");
578 exit(1);
579 }
580 if (setregid(run_gid, run_egid) < 0) {
581 perror("setregid");
582 exit(1);
583 }
584 if (setreuid(run_uid, run_euid) < 0) {
585 perror("setreuid");
586 exit(1);
587 }
588 }
589 }
590 else
591 setreuid(run_uid, run_uid);
592
593 /*
594 * Induce an immediate stop so that the parent
595 * will resume us with PTRACE_SYSCALL and display
596 * this execve call normally.
597 */
598 kill(getpid(), SIGSTOP);
599#endif /* !USE_PROCFS */
600
601 execv(pathname, argv);
602 perror("strace: exec");
603 _exit(1);
604 break;
605 }
606 default:
607 if ((tcp = alloctcb(pid)) == NULL) {
608 cleanup();
609 exit(1);
610 }
611#ifdef USE_PROCFS
612 if (proc_open(tcp, 0) < 0) {
613 fprintf(stderr, "trouble opening proc file\n");
614 cleanup();
615 exit(1);
616 }
617#endif /* USE_PROCFS */
618 break;
619 }
620}
621
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000622int
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000623main(int argc, char *argv[])
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000624{
625 extern int optind;
626 extern char *optarg;
627 struct tcb *tcp;
628 int c, pid = 0;
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000629 int optF = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000630 struct sigaction sa;
631
632 static char buf[BUFSIZ];
633
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000634 progname = argv[0] ? argv[0] : "strace";
635
Roland McGrathee9d4352002-12-18 04:16:10 +0000636 /* Allocate the initial tcbtab. */
637 tcbtabsize = argc; /* Surely enough for all -p args. */
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000638 if ((tcbtab = calloc (tcbtabsize, sizeof tcbtab[0])) == NULL) {
639 fprintf(stderr, "%s: out of memory\n", progname);
640 exit(1);
641 }
642 if ((tcbtab[0] = calloc (tcbtabsize, sizeof tcbtab[0][0])) == NULL) {
643 fprintf(stderr, "%s: out of memory\n", progname);
644 exit(1);
645 }
Roland McGrathee9d4352002-12-18 04:16:10 +0000646 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
647 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
648
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000649 outf = stderr;
650 interactive = 1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000651 set_sortby(DEFAULT_SORTBY);
652 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000653 qualify("trace=all");
654 qualify("abbrev=all");
655 qualify("verbose=all");
656 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000657 while ((c = getopt(argc, argv,
Roland McGrathde6e5332003-01-24 04:31:23 +0000658 "+cdfFhiqrtTvVxza:e:o:O:p:s:S:u:E:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000659 switch (c) {
660 case 'c':
661 cflag++;
662 dtime++;
663 break;
664 case 'd':
665 debug++;
666 break;
Roland McGrath41c48222008-07-18 00:25:10 +0000667 case 'F':
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000668 optF = 1;
669 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000670 case 'f':
671 followfork++;
672 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000673 case 'h':
674 usage(stdout, 0);
675 break;
676 case 'i':
677 iflag++;
678 break;
679 case 'q':
680 qflag++;
681 break;
682 case 'r':
683 rflag++;
684 tflag++;
685 break;
686 case 't':
687 tflag++;
688 break;
689 case 'T':
690 dtime++;
691 break;
692 case 'x':
693 xflag++;
694 break;
695 case 'v':
696 qualify("abbrev=none");
697 break;
698 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +0000699 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000700 exit(0);
701 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000702 case 'z':
703 not_failing_only = 1;
704 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000705 case 'a':
706 acolumn = atoi(optarg);
707 break;
708 case 'e':
709 qualify(optarg);
710 break;
711 case 'o':
712 outfname = strdup(optarg);
713 break;
714 case 'O':
715 set_overhead(atoi(optarg));
716 break;
717 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +0000718 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000719 fprintf(stderr, "%s: Invalid process id: %s\n",
720 progname, optarg);
721 break;
722 }
723 if (pid == getpid()) {
Wichert Akkerman54a47671999-10-17 00:57:34 +0000724 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000725 break;
726 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000727 if ((tcp = alloc_tcb(pid, 0)) == NULL) {
Roland McGrathde6e5332003-01-24 04:31:23 +0000728 fprintf(stderr, "%s: out of memory\n",
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000729 progname);
730 exit(1);
731 }
732 tcp->flags |= TCB_ATTACHED;
733 pflag_seen++;
734 break;
735 case 's':
736 max_strlen = atoi(optarg);
Roland McGrathdccec722005-05-09 07:45:47 +0000737 if (max_strlen < 0) {
738 fprintf(stderr,
739 "%s: invalid -s argument: %s\n",
740 progname, optarg);
741 exit(1);
742 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000743 break;
744 case 'S':
745 set_sortby(optarg);
746 break;
747 case 'u':
748 username = strdup(optarg);
749 break;
Roland McGrathde6e5332003-01-24 04:31:23 +0000750 case 'E':
751 if (putenv(optarg) < 0) {
752 fprintf(stderr, "%s: out of memory\n",
753 progname);
754 exit(1);
755 }
756 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000757 default:
758 usage(stderr, 1);
759 break;
760 }
761 }
762
Roland McGrathd0c4c0c2006-04-25 07:39:40 +0000763 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +0000764 usage(stderr, 1);
765
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000766 if (!followfork)
767 followfork = optF;
768
Roland McGrathcb9def62006-04-25 07:48:03 +0000769 if (followfork > 1 && cflag) {
770 fprintf(stderr,
771 "%s: -c and -ff are mutually exclusive options\n",
772 progname);
773 exit(1);
774 }
775
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000776 /* See if they want to run as another user. */
777 if (username != NULL) {
778 struct passwd *pent;
779
780 if (getuid() != 0 || geteuid() != 0) {
781 fprintf(stderr,
782 "%s: you must be root to use the -u option\n",
783 progname);
784 exit(1);
785 }
786 if ((pent = getpwnam(username)) == NULL) {
787 fprintf(stderr, "%s: cannot find user `%s'\n",
Roland McGrath09553f82007-07-05 19:31:49 +0000788 progname, username);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000789 exit(1);
790 }
791 run_uid = pent->pw_uid;
792 run_gid = pent->pw_gid;
793 }
794 else {
795 run_uid = getuid();
796 run_gid = getgid();
797 }
798
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000799 /* Check if they want to redirect the output. */
800 if (outfname) {
Roland McGrath37b9a662003-11-07 02:26:54 +0000801 /* See if they want to pipe the output. */
802 if (outfname[0] == '|' || outfname[0] == '!') {
803 /*
804 * We can't do the <outfname>.PID funny business
805 * when using popen, so prohibit it.
806 */
807 if (followfork > 1) {
808 fprintf(stderr, "\
809%s: piping the output and -ff are mutually exclusive options\n",
810 progname);
811 exit(1);
812 }
813
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000814 if ((outf = strace_popen(outfname + 1)) == NULL)
Roland McGrath37b9a662003-11-07 02:26:54 +0000815 exit(1);
Roland McGrath37b9a662003-11-07 02:26:54 +0000816 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000817 else if (followfork <= 1 &&
818 (outf = strace_fopen(outfname, "w")) == NULL)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000819 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000820 }
821
Roland McGrath37b9a662003-11-07 02:26:54 +0000822 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000823 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +0000824 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000825 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000826 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +0000827 }
Roland McGrath54cc1c82007-11-03 23:34:11 +0000828 /* Valid states here:
829 optind < argc pflag_seen outfname interactive
830 1 0 0 1
831 0 1 0 1
832 1 0 1 0
833 0 1 1 1
834 */
835
836 /* STARTUP_CHILD must be called before the signal handlers get
837 installed below as they are inherited into the spawned process.
838 Also we do not need to be protected by them as during interruption
839 in the STARTUP_CHILD mode we kill the spawned process anyway. */
840 if (!pflag_seen)
841 startup_child(&argv[optind]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000842
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000843 sigemptyset(&empty_set);
844 sigemptyset(&blocked_set);
845 sa.sa_handler = SIG_IGN;
846 sigemptyset(&sa.sa_mask);
847 sa.sa_flags = 0;
848 sigaction(SIGTTOU, &sa, NULL);
849 sigaction(SIGTTIN, &sa, NULL);
850 if (interactive) {
851 sigaddset(&blocked_set, SIGHUP);
852 sigaddset(&blocked_set, SIGINT);
853 sigaddset(&blocked_set, SIGQUIT);
854 sigaddset(&blocked_set, SIGPIPE);
855 sigaddset(&blocked_set, SIGTERM);
856 sa.sa_handler = interrupt;
857#ifdef SUNOS4
858 /* POSIX signals on sunos4.1 are a little broken. */
859 sa.sa_flags = SA_INTERRUPT;
860#endif /* SUNOS4 */
861 }
862 sigaction(SIGHUP, &sa, NULL);
863 sigaction(SIGINT, &sa, NULL);
864 sigaction(SIGQUIT, &sa, NULL);
865 sigaction(SIGPIPE, &sa, NULL);
866 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000867#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000868 sa.sa_handler = reaper;
869 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000870#else
871 /* Make sure SIGCHLD has the default action so that waitpid
872 definitely works without losing track of children. The user
873 should not have given us a bogus state to inherit, but he might
874 have. Arguably we should detect SIG_IGN here and pass it on
875 to children, but probably noone really needs that. */
876 sa.sa_handler = SIG_DFL;
877 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000878#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000879
Roland McGrath02203312007-06-11 22:06:31 +0000880 if (pflag_seen)
881 startup_attach();
Roland McGrath02203312007-06-11 22:06:31 +0000882
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000883 if (trace() < 0)
884 exit(1);
885 cleanup();
Dmitry V. Levina6809652008-11-10 17:14:58 +0000886 fflush(NULL);
887 if (exit_code > 0xff) {
888 /* Child was killed by a signal, mimic that. */
889 exit_code &= 0xff;
890 signal(exit_code, SIG_DFL);
891 raise(exit_code);
892 /* Paranoia - what if this signal is not fatal?
893 Exit with 128 + signo then. */
894 exit_code += 128;
895 }
896 exit(exit_code);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000897}
898
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000899int
900expand_tcbtab()
901{
902 /* Allocate some more TCBs and expand the table.
903 We don't want to relocate the TCBs because our
904 callers have pointers and it would be a pain.
905 So tcbtab is a table of pointers. Since we never
906 free the TCBs, we allocate a single chunk of many. */
907 struct tcb **newtab = (struct tcb **)
908 realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
909 struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
910 sizeof *newtcbs);
911 int i;
912 if (newtab == NULL || newtcbs == NULL) {
913 if (newtab != NULL)
914 free(newtab);
Dmitry V. Levin76860f62006-10-11 22:55:25 +0000915 fprintf(stderr, "%s: expand_tcbtab: out of memory\n",
916 progname);
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000917 return 1;
918 }
919 for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
920 newtab[i] = &newtcbs[i - tcbtabsize];
921 tcbtabsize *= 2;
922 tcbtab = newtab;
923
924 return 0;
925}
926
927
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000928struct tcb *
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000929alloc_tcb(int pid, int command_options_parsed)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000930{
931 int i;
932 struct tcb *tcp;
933
Roland McGrathee9d4352002-12-18 04:16:10 +0000934 for (i = 0; i < tcbtabsize; i++) {
935 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000936 if ((tcp->flags & TCB_INUSE) == 0) {
937 tcp->pid = pid;
938 tcp->parent = NULL;
939 tcp->nchildren = 0;
Roland McGrath09623452003-05-23 02:27:13 +0000940 tcp->nzombies = 0;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000941#ifdef TCB_CLONE_THREAD
942 tcp->nclone_threads = tcp->nclone_detached = 0;
943 tcp->nclone_waiting = 0;
944#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000945 tcp->flags = TCB_INUSE | TCB_STARTUP;
946 tcp->outf = outf; /* Initialise to current out file */
947 tcp->stime.tv_sec = 0;
948 tcp->stime.tv_usec = 0;
949 tcp->pfd = -1;
950 nprocs++;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000951 if (command_options_parsed)
952 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000953 return tcp;
954 }
955 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000956 fprintf(stderr, "%s: alloc_tcb: tcb table full\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000957 return NULL;
958}
959
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000960#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000961int
962proc_open(tcp, attaching)
963struct tcb *tcp;
964int attaching;
965{
966 char proc[32];
967 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000968#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +0000969 int i;
970 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000971 sigset_t signals;
972 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000973#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000974#ifndef HAVE_POLLABLE_PROCFS
975 static int last_pfd;
976#endif
977
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000978#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000979 /* Open the process pseudo-files in /proc. */
980 sprintf(proc, "/proc/%d/ctl", tcp->pid);
981 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000982 perror("strace: open(\"/proc/...\", ...)");
983 return -1;
984 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000985 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000986 return -1;
987 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000988 sprintf(proc, "/proc/%d/status", tcp->pid);
989 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
990 perror("strace: open(\"/proc/...\", ...)");
991 return -1;
992 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000993 if (set_cloexec_flag(tcp->pfd_stat) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000994 return -1;
995 }
996 sprintf(proc, "/proc/%d/as", tcp->pid);
997 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
998 perror("strace: open(\"/proc/...\", ...)");
999 return -1;
1000 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001001 if (set_cloexec_flag(tcp->pfd_as) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001002 return -1;
1003 }
1004#else
1005 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001006#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001007 sprintf(proc, "/proc/%d", tcp->pid);
1008 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001009#else /* FREEBSD */
1010 sprintf(proc, "/proc/%d/mem", tcp->pid);
1011 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
1012#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001013 perror("strace: open(\"/proc/...\", ...)");
1014 return -1;
1015 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001016 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001017 return -1;
1018 }
1019#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001020#ifdef FREEBSD
1021 sprintf(proc, "/proc/%d/regs", tcp->pid);
1022 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
1023 perror("strace: open(\"/proc/.../regs\", ...)");
1024 return -1;
1025 }
1026 if (cflag) {
1027 sprintf(proc, "/proc/%d/status", tcp->pid);
1028 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
1029 perror("strace: open(\"/proc/.../status\", ...)");
1030 return -1;
1031 }
1032 } else
1033 tcp->pfd_status = -1;
1034#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001035 rebuild_pollv();
1036 if (!attaching) {
1037 /*
1038 * Wait for the child to pause. Because of a race
1039 * condition we have to poll for the event.
1040 */
1041 for (;;) {
1042 if (IOCTL_STATUS (tcp) < 0) {
1043 perror("strace: PIOCSTATUS");
1044 return -1;
1045 }
1046 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001047 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001048 }
1049 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001050#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001051 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001052 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001053 perror("strace: PIOCSTOP");
1054 return -1;
1055 }
Roland McGrath553a6092002-12-16 20:40:39 +00001056#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001057#ifdef PIOCSET
1058 /* Set Run-on-Last-Close. */
1059 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001060 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001061 perror("PIOCSET PR_RLC");
1062 return -1;
1063 }
1064 /* Set or Reset Inherit-on-Fork. */
1065 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001066 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001067 perror("PIOC{SET,RESET} PR_FORK");
1068 return -1;
1069 }
1070#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +00001071#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001072 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
1073 perror("PIOCSRLC");
1074 return -1;
1075 }
1076 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
1077 perror("PIOC{S,R}FORK");
1078 return -1;
1079 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001080#else /* FREEBSD */
1081 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
1082 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
1083 perror("PIOCGFL");
1084 return -1;
1085 }
1086 arg &= ~PF_LINGER;
1087 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
1088 perror("PIOCSFL");
1089 return -1;
1090 }
1091#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001092#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001093#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +00001094 /* Enable all syscall entries we care about. */
1095 premptyset(&syscalls);
1096 for (i = 1; i < MAX_QUALS; ++i) {
1097 if (i > (sizeof syscalls) * CHAR_BIT) break;
1098 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
1099 }
1100 praddset (&syscalls, SYS_execve);
1101 if (followfork) {
1102 praddset (&syscalls, SYS_fork);
1103#ifdef SYS_forkall
1104 praddset (&syscalls, SYS_forkall);
1105#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001106#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +00001107 praddset (&syscalls, SYS_fork1);
1108#endif
1109#ifdef SYS_rfork1
1110 praddset (&syscalls, SYS_rfork1);
1111#endif
1112#ifdef SYS_rforkall
1113 praddset (&syscalls, SYS_rforkall);
1114#endif
1115 }
1116 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001117 perror("PIOCSENTRY");
1118 return -1;
1119 }
John Hughes19e49982001-10-19 08:59:12 +00001120 /* Enable the syscall exits. */
1121 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001122 perror("PIOSEXIT");
1123 return -1;
1124 }
John Hughes19e49982001-10-19 08:59:12 +00001125 /* Enable signals we care about. */
1126 premptyset(&signals);
1127 for (i = 1; i < MAX_QUALS; ++i) {
1128 if (i > (sizeof signals) * CHAR_BIT) break;
1129 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
1130 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001131 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001132 perror("PIOCSTRACE");
1133 return -1;
1134 }
John Hughes19e49982001-10-19 08:59:12 +00001135 /* Enable faults we care about */
1136 premptyset(&faults);
1137 for (i = 1; i < MAX_QUALS; ++i) {
1138 if (i > (sizeof faults) * CHAR_BIT) break;
1139 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
1140 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001141 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001142 perror("PIOCSFAULT");
1143 return -1;
1144 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001145#else /* FREEBSD */
1146 /* set events flags. */
1147 arg = S_SIG | S_SCE | S_SCX ;
1148 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
1149 perror("PIOCBIS");
1150 return -1;
1151 }
1152#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001153 if (!attaching) {
1154#ifdef MIPS
1155 /*
1156 * The SGI PRSABORT doesn't work for pause() so
1157 * we send it a caught signal to wake it up.
1158 */
1159 kill(tcp->pid, SIGINT);
1160#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +00001161#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001162 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001163 arg = PRSABORT;
1164 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001165 perror("PIOCRUN");
1166 return -1;
1167 }
Roland McGrath553a6092002-12-16 20:40:39 +00001168#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001169#endif /* !MIPS*/
1170#ifdef FREEBSD
1171 /* wake up the child if it received the SIGSTOP */
1172 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001173#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001174 for (;;) {
1175 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001176 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001177 perror("PIOCWSTOP");
1178 return -1;
1179 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001180 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001181 tcp->flags &= ~TCB_INSYSCALL;
1182 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001183 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001184 break;
1185 }
1186 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001187#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001188 arg = 0;
1189 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001190#else /* FREEBSD */
1191 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001192#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001193 perror("PIOCRUN");
1194 return -1;
1195 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001196#ifdef FREEBSD
1197 /* handle the case where we "opened" the child before
1198 it did the kill -STOP */
1199 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1200 tcp->status.PR_WHAT == SIGSTOP)
1201 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001202#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001203 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001204#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001205 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001206#else /* FREEBSD */
1207 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001208 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001209 /* We are attaching to an already running process.
1210 * Try to figure out the state of the process in syscalls,
1211 * to handle the first event well.
1212 * This is done by having a look at the "wchan" property of the
1213 * process, which tells where it is stopped (if it is). */
1214 FILE * status;
1215 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001216
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001217 sprintf(proc, "/proc/%d/status", tcp->pid);
1218 status = fopen(proc, "r");
1219 if (status &&
1220 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1221 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1222 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1223 strcmp(wchan, "stopevent")) {
1224 /* The process is asleep in the middle of a syscall.
1225 Fake the syscall entry event */
1226 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1227 tcp->status.PR_WHY = PR_SYSENTRY;
1228 trace_syscall(tcp);
1229 }
1230 if (status)
1231 fclose(status);
1232 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001233 }
1234#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001235#ifndef HAVE_POLLABLE_PROCFS
1236 if (proc_poll_pipe[0] != -1)
1237 proc_poller(tcp->pfd);
1238 else if (nprocs > 1) {
1239 proc_poll_open();
1240 proc_poller(last_pfd);
1241 proc_poller(tcp->pfd);
1242 }
1243 last_pfd = tcp->pfd;
1244#endif /* !HAVE_POLLABLE_PROCFS */
1245 return 0;
1246}
1247
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001248#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001249
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001250struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001251pid2tcb(pid)
1252int pid;
1253{
1254 int i;
1255 struct tcb *tcp;
1256
Roland McGrathee9d4352002-12-18 04:16:10 +00001257 for (i = 0; i < tcbtabsize; i++) {
1258 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001259 if (pid && tcp->pid != pid)
1260 continue;
1261 if (tcp->flags & TCB_INUSE)
1262 return tcp;
1263 }
1264 return NULL;
1265}
1266
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001267#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001268
1269static struct tcb *
1270pfd2tcb(pfd)
1271int pfd;
1272{
1273 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001274
Roland McGrathca16be82003-01-10 19:55:28 +00001275 for (i = 0; i < tcbtabsize; i++) {
1276 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001277 if (tcp->pfd != pfd)
1278 continue;
1279 if (tcp->flags & TCB_INUSE)
1280 return tcp;
1281 }
1282 return NULL;
1283}
1284
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001285#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001286
1287void
1288droptcb(tcp)
1289struct tcb *tcp;
1290{
1291 if (tcp->pid == 0)
1292 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001293#ifdef TCB_CLONE_THREAD
1294 if (tcp->nclone_threads > 0) {
1295 /* There are other threads left in this process, but this
1296 is the one whose PID represents the whole process.
1297 We need to keep this record around as a zombie until
1298 all the threads die. */
1299 tcp->flags |= TCB_EXITING;
1300 return;
1301 }
1302#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001303 nprocs--;
1304 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001305
Roland McGrathe29341c2003-01-10 20:14:20 +00001306 if (tcp->parent != NULL) {
1307 tcp->parent->nchildren--;
1308#ifdef TCB_CLONE_THREAD
1309 if (tcp->flags & TCB_CLONE_DETACHED)
1310 tcp->parent->nclone_detached--;
1311 if (tcp->flags & TCB_CLONE_THREAD)
1312 tcp->parent->nclone_threads--;
1313#endif
Roland McGrath09623452003-05-23 02:27:13 +00001314#ifdef TCB_CLONE_DETACHED
1315 if (!(tcp->flags & TCB_CLONE_DETACHED))
1316#endif
1317 tcp->parent->nzombies++;
Roland McGrath276ceb32007-11-13 08:12:12 +00001318#ifdef LINUX
1319 /* Update `tcp->parent->parent->nchildren' and the other fields
1320 like NCLONE_DETACHED, only for zombie group leader that has
1321 already reported and been short-circuited at the top of this
1322 function. The same condition as at the top of DETACH. */
1323 if ((tcp->flags & TCB_CLONE_THREAD) &&
1324 tcp->parent->nclone_threads == 0 &&
1325 (tcp->parent->flags & TCB_EXITING))
1326 droptcb(tcp->parent);
1327#endif
Roland McGrathe29341c2003-01-10 20:14:20 +00001328 tcp->parent = NULL;
1329 }
1330
1331 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001332 if (tcp->pfd != -1) {
1333 close(tcp->pfd);
1334 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001335#ifdef FREEBSD
1336 if (tcp->pfd_reg != -1) {
1337 close(tcp->pfd_reg);
1338 tcp->pfd_reg = -1;
1339 }
1340 if (tcp->pfd_status != -1) {
1341 close(tcp->pfd_status);
1342 tcp->pfd_status = -1;
1343 }
Roland McGrath553a6092002-12-16 20:40:39 +00001344#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001345#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001346 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001347#endif
1348 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001349
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001350 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001351 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001352
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001353 tcp->outf = 0;
1354}
1355
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001356#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001357
1358static int
1359resume(tcp)
1360struct tcb *tcp;
1361{
1362 if (tcp == NULL)
1363 return -1;
1364
1365 if (!(tcp->flags & TCB_SUSPENDED)) {
1366 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1367 return -1;
1368 }
1369 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001370#ifdef TCB_CLONE_THREAD
1371 if (tcp->flags & TCB_CLONE_THREAD)
1372 tcp->parent->nclone_waiting--;
1373#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001374
1375 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
1376 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
1377 return -1;
1378 }
1379
1380 if (!qflag)
1381 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1382 return 0;
1383}
1384
Roland McGrath1bfd3102007-08-03 10:02:00 +00001385static int
1386resume_from_tcp (struct tcb *tcp)
1387{
1388 int error = 0;
1389 int resumed = 0;
1390
1391 /* XXX This won't always be quite right (but it never was).
1392 A waiter with argument 0 or < -1 is waiting for any pid in
1393 a particular pgrp, which this child might or might not be
1394 in. The waiter will only wake up if it's argument is -1
1395 or if it's waiting for tcp->pid's pgrp. It makes a
1396 difference to wake up a waiter when there might be more
1397 traced children, because it could get a false ECHILD
1398 error. OTOH, if this was the last child in the pgrp, then
1399 it ought to wake up and get ECHILD. We would have to
1400 search the system for all pid's in the pgrp to be sure.
1401
1402 && (t->waitpid == -1 ||
1403 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1404 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1405 */
1406
1407 if (tcp->parent &&
1408 (tcp->parent->flags & TCB_SUSPENDED) &&
1409 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1410 error = resume(tcp->parent);
1411 ++resumed;
1412 }
1413#ifdef TCB_CLONE_THREAD
1414 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1415 /* Some other threads of our parent are waiting too. */
1416 unsigned int i;
1417
1418 /* Resume all the threads that were waiting for this PID. */
1419 for (i = 0; i < tcbtabsize; i++) {
1420 struct tcb *t = tcbtab[i];
1421 if (t->parent == tcp->parent && t != tcp
1422 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1423 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1424 && t->waitpid == tcp->pid) {
1425 error |= resume (t);
1426 ++resumed;
1427 }
1428 }
1429 if (resumed == 0)
1430 /* Noone was waiting for this PID in particular,
1431 so now we might need to resume some wildcarders. */
1432 for (i = 0; i < tcbtabsize; i++) {
1433 struct tcb *t = tcbtab[i];
1434 if (t->parent == tcp->parent && t != tcp
1435 && ((t->flags
1436 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1437 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1438 && t->waitpid <= 0
1439 ) {
1440 error |= resume (t);
1441 break;
1442 }
1443 }
1444 }
1445
1446 return error;
1447}
1448#endif
1449
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001450#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001451
Roland McGrath0a463882007-07-05 18:43:16 +00001452/* detach traced process; continue with sig
1453 Never call DETACH twice on the same process as both unattached and
1454 attached-unstopped processes give the same ESRCH. For unattached process we
1455 would SIGSTOP it and wait for its SIGSTOP notification forever. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001456
1457static int
1458detach(tcp, sig)
1459struct tcb *tcp;
1460int sig;
1461{
1462 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001463#ifdef LINUX
Roland McGrath1bfd3102007-08-03 10:02:00 +00001464 int status, catch_sigstop;
Roland McGratha08a97e2005-08-03 11:23:46 +00001465 struct tcb *zombie = NULL;
1466
1467 /* If the group leader is lingering only because of this other
1468 thread now dying, then detach the leader as well. */
1469 if ((tcp->flags & TCB_CLONE_THREAD) &&
1470 tcp->parent->nclone_threads == 1 &&
1471 (tcp->parent->flags & TCB_EXITING))
1472 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001473#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001474
1475 if (tcp->flags & TCB_BPTSET)
1476 sig = SIGKILL;
1477
1478#ifdef LINUX
1479 /*
1480 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001481 * before detaching. Arghh. We go through hoops
1482 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001483 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001484#if defined(SPARC)
1485#undef PTRACE_DETACH
1486#define PTRACE_DETACH PTRACE_SUNDETACH
1487#endif
Roland McGrath02203312007-06-11 22:06:31 +00001488 /*
1489 * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
1490 * expected SIGSTOP. We must catch exactly one as otherwise the
1491 * detached process would be left stopped (process state T).
1492 */
1493 catch_sigstop = (tcp->flags & TCB_STARTUP);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001494 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1495 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001496 }
1497 else if (errno != ESRCH) {
1498 /* Shouldn't happen. */
1499 perror("detach: ptrace(PTRACE_DETACH, ...)");
1500 }
Roland McGrath134813a2007-06-02 00:07:33 +00001501 else if (my_tgkill((tcp->flags & TCB_CLONE_THREAD ? tcp->parent->pid
1502 : tcp->pid),
1503 tcp->pid, 0) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001504 if (errno != ESRCH)
1505 perror("detach: checking sanity");
1506 }
Roland McGrath02203312007-06-11 22:06:31 +00001507 else if (!catch_sigstop && my_tgkill((tcp->flags & TCB_CLONE_THREAD
1508 ? tcp->parent->pid : tcp->pid),
1509 tcp->pid, SIGSTOP) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001510 if (errno != ESRCH)
1511 perror("detach: stopping child");
1512 }
Roland McGrath02203312007-06-11 22:06:31 +00001513 else
1514 catch_sigstop = 1;
1515 if (catch_sigstop)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001516 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001517#ifdef __WALL
1518 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1519 if (errno == ECHILD) /* Already gone. */
1520 break;
1521 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001522 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001523 break;
1524 }
1525#endif /* __WALL */
1526 /* No __WALL here. */
1527 if (waitpid(tcp->pid, &status, 0) < 0) {
1528 if (errno != ECHILD) {
1529 perror("detach: waiting");
1530 break;
1531 }
1532#ifdef __WCLONE
1533 /* If no processes, try clones. */
1534 if (wait4(tcp->pid, &status, __WCLONE,
1535 NULL) < 0) {
1536 if (errno != ECHILD)
1537 perror("detach: waiting");
1538 break;
1539 }
1540#endif /* __WCLONE */
1541 }
1542#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001543 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001544#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001545 if (!WIFSTOPPED(status)) {
1546 /* Au revoir, mon ami. */
1547 break;
1548 }
1549 if (WSTOPSIG(status) == SIGSTOP) {
1550 if ((error = ptrace(PTRACE_DETACH,
Roland McGrath7bf10472002-12-16 20:42:50 +00001551 tcp->pid, (char *) 1, sig)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001552 if (errno != ESRCH)
1553 perror("detach: ptrace(PTRACE_DETACH, ...)");
1554 /* I died trying. */
1555 }
1556 break;
1557 }
1558 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
Roland McGrath7bf10472002-12-16 20:42:50 +00001559 WSTOPSIG(status) == SIGTRAP ?
1560 0 : WSTOPSIG(status))) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001561 if (errno != ESRCH)
1562 perror("detach: ptrace(PTRACE_CONT, ...)");
1563 break;
1564 }
1565 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001566#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001567
1568#if defined(SUNOS4)
1569 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1570 if (sig && kill(tcp->pid, sig) < 0)
1571 perror("detach: kill");
1572 sig = 0;
1573 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1574 perror("detach: ptrace(PTRACE_DETACH, ...)");
1575#endif /* SUNOS4 */
1576
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001577#ifndef USE_PROCFS
Roland McGrath1bfd3102007-08-03 10:02:00 +00001578 error |= resume_from_tcp (tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001579#endif
1580
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001581 if (!qflag)
1582 fprintf(stderr, "Process %u detached\n", tcp->pid);
1583
1584 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001585
1586#ifdef LINUX
Roland McGrath0a463882007-07-05 18:43:16 +00001587 if (zombie != NULL) {
1588 /* TCP no longer exists therefore you must not detach () it. */
1589 droptcb(zombie);
1590 }
Roland McGratha08a97e2005-08-03 11:23:46 +00001591#endif
1592
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001593 return error;
1594}
1595
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001596#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001597
1598static void
1599reaper(sig)
1600int sig;
1601{
1602 int pid;
1603 int status;
1604
1605 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1606#if 0
1607 struct tcb *tcp;
1608
1609 tcp = pid2tcb(pid);
1610 if (tcp)
1611 droptcb(tcp);
1612#endif
1613 }
1614}
1615
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001616#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001617
1618static void
1619cleanup()
1620{
1621 int i;
1622 struct tcb *tcp;
1623
Roland McGrathee9d4352002-12-18 04:16:10 +00001624 for (i = 0; i < tcbtabsize; i++) {
1625 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001626 if (!(tcp->flags & TCB_INUSE))
1627 continue;
1628 if (debug)
1629 fprintf(stderr,
1630 "cleanup: looking at pid %u\n", tcp->pid);
1631 if (tcp_last &&
1632 (!outfname || followfork < 2 || tcp_last == tcp)) {
1633 tprintf(" <unfinished ...>\n");
1634 tcp_last = NULL;
1635 }
1636 if (tcp->flags & TCB_ATTACHED)
1637 detach(tcp, 0);
1638 else {
1639 kill(tcp->pid, SIGCONT);
1640 kill(tcp->pid, SIGTERM);
1641 }
1642 }
1643 if (cflag)
1644 call_summary(outf);
1645}
1646
1647static void
1648interrupt(sig)
1649int sig;
1650{
1651 interrupted = 1;
1652}
1653
1654#ifndef HAVE_STRERROR
1655
Roland McGrath6d2b3492002-12-30 00:51:30 +00001656#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001657extern int sys_nerr;
1658extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001659#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001660
1661const char *
1662strerror(errno)
1663int errno;
1664{
1665 static char buf[64];
1666
1667 if (errno < 1 || errno >= sys_nerr) {
1668 sprintf(buf, "Unknown error %d", errno);
1669 return buf;
1670 }
1671 return sys_errlist[errno];
1672}
1673
1674#endif /* HAVE_STERRROR */
1675
1676#ifndef HAVE_STRSIGNAL
1677
Roland McGrath8f474e02003-01-14 07:53:33 +00001678#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001679extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001680#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001681#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1682extern char *_sys_siglist[];
1683#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001684
1685const char *
1686strsignal(sig)
1687int sig;
1688{
1689 static char buf[64];
1690
1691 if (sig < 1 || sig >= NSIG) {
1692 sprintf(buf, "Unknown signal %d", sig);
1693 return buf;
1694 }
1695#ifdef HAVE__SYS_SIGLIST
1696 return _sys_siglist[sig];
1697#else
1698 return sys_siglist[sig];
1699#endif
1700}
1701
1702#endif /* HAVE_STRSIGNAL */
1703
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001704#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001705
1706static void
1707rebuild_pollv()
1708{
1709 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001710
Roland McGrathee9d4352002-12-18 04:16:10 +00001711 if (pollv != NULL)
1712 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001713 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001714 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001715 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00001716 exit(1);
1717 }
1718
Roland McGrathca16be82003-01-10 19:55:28 +00001719 for (i = j = 0; i < tcbtabsize; i++) {
1720 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001721 if (!(tcp->flags & TCB_INUSE))
1722 continue;
1723 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001724 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001725 j++;
1726 }
1727 if (j != nprocs) {
1728 fprintf(stderr, "strace: proc miscount\n");
1729 exit(1);
1730 }
1731}
1732
1733#ifndef HAVE_POLLABLE_PROCFS
1734
1735static void
1736proc_poll_open()
1737{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001738 int i;
1739
1740 if (pipe(proc_poll_pipe) < 0) {
1741 perror("pipe");
1742 exit(1);
1743 }
1744 for (i = 0; i < 2; i++) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001745 if (set_cloexec_flag(proc_poll_pipe[i]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001746 exit(1);
1747 }
1748 }
1749}
1750
1751static int
1752proc_poll(pollv, nfds, timeout)
1753struct pollfd *pollv;
1754int nfds;
1755int timeout;
1756{
1757 int i;
1758 int n;
1759 struct proc_pollfd pollinfo;
1760
1761 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1762 return n;
1763 if (n != sizeof(struct proc_pollfd)) {
1764 fprintf(stderr, "panic: short read: %d\n", n);
1765 exit(1);
1766 }
1767 for (i = 0; i < nprocs; i++) {
1768 if (pollv[i].fd == pollinfo.fd)
1769 pollv[i].revents = pollinfo.revents;
1770 else
1771 pollv[i].revents = 0;
1772 }
1773 poller_pid = pollinfo.pid;
1774 return 1;
1775}
1776
1777static void
1778wakeup_handler(sig)
1779int sig;
1780{
1781}
1782
1783static void
1784proc_poller(pfd)
1785int pfd;
1786{
1787 struct proc_pollfd pollinfo;
1788 struct sigaction sa;
1789 sigset_t blocked_set, empty_set;
1790 int i;
1791 int n;
1792 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001793#ifdef FREEBSD
1794 struct procfs_status pfs;
1795#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001796
1797 switch (fork()) {
1798 case -1:
1799 perror("fork");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001800 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001801 case 0:
1802 break;
1803 default:
1804 return;
1805 }
1806
1807 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1808 sa.sa_flags = 0;
1809 sigemptyset(&sa.sa_mask);
1810 sigaction(SIGHUP, &sa, NULL);
1811 sigaction(SIGINT, &sa, NULL);
1812 sigaction(SIGQUIT, &sa, NULL);
1813 sigaction(SIGPIPE, &sa, NULL);
1814 sigaction(SIGTERM, &sa, NULL);
1815 sa.sa_handler = wakeup_handler;
1816 sigaction(SIGUSR1, &sa, NULL);
1817 sigemptyset(&blocked_set);
1818 sigaddset(&blocked_set, SIGUSR1);
1819 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1820 sigemptyset(&empty_set);
1821
1822 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1823 perror("getrlimit(RLIMIT_NOFILE, ...)");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001824 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001825 }
1826 n = rl.rlim_cur;
1827 for (i = 0; i < n; i++) {
1828 if (i != pfd && i != proc_poll_pipe[1])
1829 close(i);
1830 }
1831
1832 pollinfo.fd = pfd;
1833 pollinfo.pid = getpid();
1834 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001835#ifndef FREEBSD
1836 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1837#else /* FREEBSD */
1838 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1839#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001840 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001841 switch (errno) {
1842 case EINTR:
1843 continue;
1844 case EBADF:
1845 pollinfo.revents = POLLERR;
1846 break;
1847 case ENOENT:
1848 pollinfo.revents = POLLHUP;
1849 break;
1850 default:
1851 perror("proc_poller: PIOCWSTOP");
1852 }
1853 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1854 _exit(0);
1855 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001856 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001857 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1858 sigsuspend(&empty_set);
1859 }
1860}
1861
1862#endif /* !HAVE_POLLABLE_PROCFS */
1863
1864static int
1865choose_pfd()
1866{
1867 int i, j;
1868 struct tcb *tcp;
1869
1870 static int last;
1871
1872 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001873 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001874 /*
1875 * The previous process is ready to run again. We'll
1876 * let it do so if it is currently in a syscall. This
1877 * heuristic improves the readability of the trace.
1878 */
1879 tcp = pfd2tcb(pollv[last].fd);
1880 if (tcp && (tcp->flags & TCB_INSYSCALL))
1881 return pollv[last].fd;
1882 }
1883
1884 for (i = 0; i < nprocs; i++) {
1885 /* Let competing children run round robin. */
1886 j = (i + last + 1) % nprocs;
1887 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1888 tcp = pfd2tcb(pollv[j].fd);
1889 if (!tcp) {
1890 fprintf(stderr, "strace: lost proc\n");
1891 exit(1);
1892 }
1893 droptcb(tcp);
1894 return -1;
1895 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001896 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001897 last = j;
1898 return pollv[j].fd;
1899 }
1900 }
1901 fprintf(stderr, "strace: nothing ready\n");
1902 exit(1);
1903}
1904
1905static int
1906trace()
1907{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001908#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001909 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001910#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001911 struct tcb *tcp;
1912 int pfd;
1913 int what;
1914 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001915 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001916
1917 for (;;) {
1918 if (interactive)
1919 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1920
1921 if (nprocs == 0)
1922 break;
1923
1924 switch (nprocs) {
1925 case 1:
1926#ifndef HAVE_POLLABLE_PROCFS
1927 if (proc_poll_pipe[0] == -1) {
1928#endif
1929 tcp = pid2tcb(0);
1930 if (!tcp)
1931 continue;
1932 pfd = tcp->pfd;
1933 if (pfd == -1)
1934 continue;
1935 break;
1936#ifndef HAVE_POLLABLE_PROCFS
1937 }
1938 /* fall through ... */
1939#endif /* !HAVE_POLLABLE_PROCFS */
1940 default:
1941#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001942#ifdef POLL_HACK
1943 /* On some systems (e.g. UnixWare) we get too much ugly
1944 "unfinished..." stuff when multiple proceses are in
1945 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001946
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001947 if (in_syscall) {
1948 struct pollfd pv;
1949 tcp = in_syscall;
1950 in_syscall = NULL;
1951 pv.fd = tcp->pfd;
1952 pv.events = POLLWANT;
1953 if ((what = poll (&pv, 1, 1)) < 0) {
1954 if (interrupted)
1955 return 0;
1956 continue;
1957 }
1958 else if (what == 1 && pv.revents & POLLWANT) {
1959 goto FOUND;
1960 }
1961 }
1962#endif
1963
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001964 if (poll(pollv, nprocs, INFTIM) < 0) {
1965 if (interrupted)
1966 return 0;
1967 continue;
1968 }
1969#else /* !HAVE_POLLABLE_PROCFS */
1970 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1971 if (interrupted)
1972 return 0;
1973 continue;
1974 }
1975#endif /* !HAVE_POLLABLE_PROCFS */
1976 pfd = choose_pfd();
1977 if (pfd == -1)
1978 continue;
1979 break;
1980 }
1981
1982 /* Look up `pfd' in our table. */
1983 if ((tcp = pfd2tcb(pfd)) == NULL) {
1984 fprintf(stderr, "unknown pfd: %u\n", pfd);
1985 exit(1);
1986 }
John Hughesb6643082002-05-23 11:02:22 +00001987#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001988 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001989#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001990 /* Get the status of the process. */
1991 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001992#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001993 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001994#else /* FREEBSD */
1995 /* Thanks to some scheduling mystery, the first poller
1996 sometimes waits for the already processed end of fork
1997 event. Doing a non blocking poll here solves the problem. */
1998 if (proc_poll_pipe[0] != -1)
1999 ioctl_result = IOCTL_STATUS (tcp);
2000 else
2001 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00002002#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002003 ioctl_errno = errno;
2004#ifndef HAVE_POLLABLE_PROCFS
2005 if (proc_poll_pipe[0] != -1) {
2006 if (ioctl_result < 0)
2007 kill(poller_pid, SIGKILL);
2008 else
2009 kill(poller_pid, SIGUSR1);
2010 }
2011#endif /* !HAVE_POLLABLE_PROCFS */
2012 }
2013 if (interrupted)
2014 return 0;
2015
2016 if (interactive)
2017 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2018
2019 if (ioctl_result < 0) {
2020 /* Find out what happened if it failed. */
2021 switch (ioctl_errno) {
2022 case EINTR:
2023 case EBADF:
2024 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002025#ifdef FREEBSD
2026 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00002027#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002028 case ENOENT:
2029 droptcb(tcp);
2030 continue;
2031 default:
2032 perror("PIOCWSTOP");
2033 exit(1);
2034 }
2035 }
2036
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002037#ifdef FREEBSD
2038 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2039 /* discard first event for a syscall we never entered */
2040 IOCTL (tcp->pfd, PIOCRUN, 0);
2041 continue;
2042 }
Roland McGrath553a6092002-12-16 20:40:39 +00002043#endif
2044
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002045 /* clear the just started flag */
2046 tcp->flags &= ~TCB_STARTUP;
2047
2048 /* set current output file */
2049 outf = tcp->outf;
2050
2051 if (cflag) {
2052 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002053#ifdef FREEBSD
2054 char buf[1024];
2055 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002056
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002057 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
2058 buf[len] = '\0';
2059 sscanf(buf,
2060 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2061 &stime.tv_sec, &stime.tv_usec);
2062 } else
2063 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002064#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002065 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2066 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002067#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002068 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2069 tcp->stime = stime;
2070 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002071 what = tcp->status.PR_WHAT;
2072 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002073#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002074 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002075 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2076 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002077 if (trace_syscall(tcp) < 0) {
2078 fprintf(stderr, "syscall trouble\n");
2079 exit(1);
2080 }
2081 }
2082 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002083#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002084 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002085#ifdef POLL_HACK
2086 in_syscall = tcp;
2087#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002088 case PR_SYSEXIT:
2089 if (trace_syscall(tcp) < 0) {
2090 fprintf(stderr, "syscall trouble\n");
2091 exit(1);
2092 }
2093 break;
2094 case PR_SIGNALLED:
2095 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
2096 printleader(tcp);
2097 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002098 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002099 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00002100#ifdef PR_INFO
2101 if (tcp->status.PR_INFO.si_signo == what) {
2102 printleader(tcp);
2103 tprintf(" siginfo=");
2104 printsiginfo(&tcp->status.PR_INFO, 1);
2105 printtrailer(tcp);
2106 }
2107#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002108 }
2109 break;
2110 case PR_FAULTED:
2111 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
2112 printleader(tcp);
2113 tprintf("=== FAULT %d ===", what);
2114 printtrailer(tcp);
2115 }
2116 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002117#ifdef FREEBSD
2118 case 0: /* handle case we polled for nothing */
2119 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00002120#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002121 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002122 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002123 exit(1);
2124 break;
2125 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002126 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002127#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002128 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00002129#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002130 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00002131#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002132 perror("PIOCRUN");
2133 exit(1);
2134 }
2135 }
2136 return 0;
2137}
2138
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002139#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002140
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002141#ifdef TCB_GROUP_EXITING
2142/* Handle an exit detach or death signal that is taking all the
2143 related clone threads with it. This is called in three circumstances:
2144 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
2145 SIG == 0 Continuing TCP will perform an exit_group syscall.
2146 SIG == other Continuing TCP with SIG will kill the process.
2147*/
2148static int
2149handle_group_exit(struct tcb *tcp, int sig)
2150{
2151 /* We need to locate our records of all the clone threads
2152 related to TCP, either its children or siblings. */
2153 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
2154 ? tcp->parent
2155 : tcp->nclone_detached > 0
2156 ? tcp : NULL);
2157
2158 if (sig < 0) {
Roland McGrath05690952004-10-20 01:00:27 +00002159 if (leader != NULL && leader != tcp &&
2160 !(leader->flags & TCB_GROUP_EXITING))
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002161 fprintf(stderr,
2162 "PANIC: handle_group_exit: %d leader %d\n",
2163 tcp->pid, leader ? leader->pid : -1);
Roland McGrath0a463882007-07-05 18:43:16 +00002164 /* TCP no longer exists therefore you must not detach () it. */
Roland McGrath1bfd3102007-08-03 10:02:00 +00002165#ifndef USE_PROCFS
2166 resume_from_tcp (tcp);
2167#endif
Roland McGrath0a463882007-07-05 18:43:16 +00002168 droptcb(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002169 }
2170 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00002171 /* Mark that we are taking the process down. */
2172 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002173 if (tcp->flags & TCB_ATTACHED) {
Roland McGrathd6a32f12007-07-11 08:35:11 +00002174 detach(tcp, sig);
Roland McGrath1bfd3102007-08-03 10:02:00 +00002175 if (leader != NULL && leader != tcp)
2176 leader->flags |= TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002177 }
2178 else if (ptrace(PTRACE_CONT, tcp->pid, (char *) 1, sig) < 0) {
2179 perror("strace: ptrace(PTRACE_CONT, ...)");
2180 cleanup();
2181 return -1;
2182 }
2183 else {
Roland McGrath05690952004-10-20 01:00:27 +00002184 if (leader != NULL)
2185 leader->flags |= TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002186 if (leader != NULL && leader != tcp)
2187 droptcb(tcp);
2188 /* The leader will report to us as parent now,
2189 and then we'll get to the SIG==-1 case. */
2190 return 0;
2191 }
2192 }
2193
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002194 return 0;
2195}
2196#endif
2197
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002198static int
2199trace()
2200{
2201 int pid;
2202 int wait_errno;
2203 int status;
2204 struct tcb *tcp;
2205#ifdef LINUX
2206 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002207#ifdef __WALL
2208 static int wait4_options = __WALL;
2209#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002210#endif /* LINUX */
2211
2212 while (nprocs != 0) {
Roland McGrath02203312007-06-11 22:06:31 +00002213 if (interrupted)
2214 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002215 if (interactive)
2216 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2217#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002218#ifdef __WALL
2219 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002220 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002221 /* this kernel does not support __WALL */
2222 wait4_options &= ~__WALL;
2223 errno = 0;
2224 pid = wait4(-1, &status, wait4_options,
2225 cflag ? &ru : NULL);
2226 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002227 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002228 /* most likely a "cloned" process */
2229 pid = wait4(-1, &status, __WCLONE,
2230 cflag ? &ru : NULL);
2231 if (pid == -1) {
2232 fprintf(stderr, "strace: clone wait4 "
2233 "failed: %s\n", strerror(errno));
2234 }
2235 }
2236#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002237 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002238#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002239#endif /* LINUX */
2240#ifdef SUNOS4
2241 pid = wait(&status);
2242#endif /* SUNOS4 */
2243 wait_errno = errno;
2244 if (interactive)
2245 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2246
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002247 if (pid == -1) {
2248 switch (wait_errno) {
2249 case EINTR:
2250 continue;
2251 case ECHILD:
2252 /*
2253 * We would like to verify this case
2254 * but sometimes a race in Solbourne's
2255 * version of SunOS sometimes reports
2256 * ECHILD before sending us SIGCHILD.
2257 */
2258#if 0
2259 if (nprocs == 0)
2260 return 0;
2261 fprintf(stderr, "strace: proc miscount\n");
2262 exit(1);
2263#endif
2264 return 0;
2265 default:
2266 errno = wait_errno;
2267 perror("strace: wait");
2268 return -1;
2269 }
2270 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002271 if (pid == popen_pid) {
2272 if (WIFEXITED(status) || WIFSIGNALED(status))
2273 popen_pid = -1;
2274 continue;
2275 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002276 if (debug)
2277 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2278
2279 /* Look up `pid' in our table. */
2280 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002281#ifdef LINUX
Roland McGrath41c48222008-07-18 00:25:10 +00002282 if (followfork) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002283 /* This is needed to go with the CLONE_PTRACE
2284 changes in process.c/util.c: we might see
2285 the child's initial trap before we see the
2286 parent return from the clone syscall.
2287 Leave the child suspended until the parent
2288 returns from its system call. Only then
2289 will we have the association of parent and
2290 child so that we know how to do clearbpt
2291 in the child. */
Dmitry V. Levin76860f62006-10-11 22:55:25 +00002292 if (nprocs == tcbtabsize &&
2293 expand_tcbtab())
2294 tcp = NULL;
2295 else
2296 tcp = alloctcb(pid);
2297 if (tcp == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002298 kill(pid, SIGKILL); /* XXX */
2299 return 0;
2300 }
2301 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002302 if (!qflag)
2303 fprintf(stderr, "\
2304Process %d attached (waiting for parent)\n",
2305 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002306 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002307 else
2308 /* This can happen if a clone call used
2309 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002310#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002311 {
2312 fprintf(stderr, "unknown pid: %u\n", pid);
2313 if (WIFSTOPPED(status))
2314 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2315 exit(1);
2316 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002317 }
2318 /* set current output file */
2319 outf = tcp->outf;
2320 if (cflag) {
2321#ifdef LINUX
2322 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2323 tcp->stime = ru.ru_stime;
2324#endif /* !LINUX */
2325 }
2326
2327 if (tcp->flags & TCB_SUSPENDED) {
2328 /*
2329 * Apparently, doing any ptrace() call on a stopped
2330 * process, provokes the kernel to report the process
2331 * status again on a subsequent wait(), even if the
2332 * process has not been actually restarted.
2333 * Since we have inspected the arguments of suspended
2334 * processes we end up here testing for this case.
2335 */
2336 continue;
2337 }
2338 if (WIFSIGNALED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002339 if (pid == strace_child)
2340 exit_code = 0x100 | WTERMSIG(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002341 if (!cflag
2342 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2343 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002344 tprintf("+++ killed by %s %s+++",
2345 signame(WTERMSIG(status)),
2346#ifdef WCOREDUMP
2347 WCOREDUMP(status) ? "(core dumped) " :
2348#endif
2349 "");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002350 printtrailer(tcp);
2351 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002352#ifdef TCB_GROUP_EXITING
2353 handle_group_exit(tcp, -1);
2354#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002355 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002356#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002357 continue;
2358 }
2359 if (WIFEXITED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002360 if (pid == strace_child)
2361 exit_code = WEXITSTATUS(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002362 if (debug)
2363 fprintf(stderr, "pid %u exited\n", pid);
Roland McGrath05690952004-10-20 01:00:27 +00002364 if ((tcp->flags & TCB_ATTACHED)
2365#ifdef TCB_GROUP_EXITING
2366 && !(tcp->parent && (tcp->parent->flags &
2367 TCB_GROUP_EXITING))
Roland McGrath1bfd3102007-08-03 10:02:00 +00002368 && !(tcp->flags & TCB_GROUP_EXITING)
Roland McGrath05690952004-10-20 01:00:27 +00002369#endif
2370 )
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002371 fprintf(stderr,
2372 "PANIC: attached pid %u exited\n",
2373 pid);
Roland McGrath0a396902003-06-10 03:05:53 +00002374 if (tcp == tcp_last) {
2375 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT))
2376 == TCB_INSYSCALL)
2377 tprintf(" <unfinished ... exit status %d>\n",
2378 WEXITSTATUS(status));
2379 tcp_last = NULL;
2380 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002381#ifdef TCB_GROUP_EXITING
2382 handle_group_exit(tcp, -1);
2383#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002384 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002385#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002386 continue;
2387 }
2388 if (!WIFSTOPPED(status)) {
2389 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2390 droptcb(tcp);
2391 continue;
2392 }
2393 if (debug)
2394 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002395 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002396
Roland McGrath02203312007-06-11 22:06:31 +00002397 /*
2398 * Interestingly, the process may stop
2399 * with STOPSIG equal to some other signal
2400 * than SIGSTOP if we happend to attach
2401 * just before the process takes a signal.
2402 */
2403 if ((tcp->flags & TCB_STARTUP) && WSTOPSIG(status) == SIGSTOP) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002404 /*
2405 * This flag is there to keep us in sync.
2406 * Next time this process stops it should
2407 * really be entering a system call.
2408 */
2409 tcp->flags &= ~TCB_STARTUP;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002410 if (tcp->flags & TCB_BPTSET) {
Roland McGrath02203312007-06-11 22:06:31 +00002411 /*
2412 * One example is a breakpoint inherited from
2413 * parent through fork ().
2414 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002415 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2416 droptcb(tcp);
2417 cleanup();
2418 return -1;
2419 }
2420 }
2421 goto tracing;
2422 }
2423
2424 if (WSTOPSIG(status) != SIGTRAP) {
2425 if (WSTOPSIG(status) == SIGSTOP &&
2426 (tcp->flags & TCB_SIGTRAPPED)) {
2427 /*
2428 * Trapped attempt to block SIGTRAP
2429 * Hope we are back in control now.
2430 */
2431 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
2432 if (ptrace(PTRACE_SYSCALL,
2433 pid, (char *) 1, 0) < 0) {
2434 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2435 cleanup();
2436 return -1;
2437 }
2438 continue;
2439 }
2440 if (!cflag
2441 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00002442 unsigned long addr = 0;
2443 long pc = 0;
Dmitry V. Levin96339422006-10-11 23:11:43 +00002444#if defined(PT_CR_IPSR) && defined(PT_CR_IIP) && defined(PT_GETSIGINFO)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002445# define PSR_RI 41
2446 struct siginfo si;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002447 long psr;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002448
2449 upeek(pid, PT_CR_IPSR, &psr);
2450 upeek(pid, PT_CR_IIP, &pc);
2451
2452 pc += (psr >> PSR_RI) & 0x3;
2453 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2454 addr = (unsigned long) si.si_addr;
Roland McGrath3a055d72005-03-06 22:24:29 +00002455#elif defined PTRACE_GETSIGINFO
2456 if (WSTOPSIG(status) == SIGSEGV ||
2457 WSTOPSIG(status) == SIGBUS) {
2458 siginfo_t si;
2459 if (ptrace(PTRACE_GETSIGINFO, pid,
2460 0, &si) == 0)
2461 addr = (unsigned long)
2462 si.si_addr;
2463 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002464#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002465 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002466 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002467 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002468 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002469 printtrailer(tcp);
2470 }
Roland McGrath05690952004-10-20 01:00:27 +00002471 if (((tcp->flags & TCB_ATTACHED) ||
2472 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002473 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002474#ifdef TCB_GROUP_EXITING
2475 handle_group_exit(tcp, WSTOPSIG(status));
2476#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002477 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002478#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002479 continue;
2480 }
2481 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
2482 WSTOPSIG(status)) < 0) {
2483 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2484 cleanup();
2485 return -1;
2486 }
2487 tcp->flags &= ~TCB_SUSPENDED;
2488 continue;
2489 }
Roland McGrath02203312007-06-11 22:06:31 +00002490 /* we handled the STATUS, we are permitted to interrupt now. */
2491 if (interrupted)
2492 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002493 if (trace_syscall(tcp) < 0) {
2494 if (tcp->flags & TCB_ATTACHED)
2495 detach(tcp, 0);
2496 else {
2497 ptrace(PTRACE_KILL,
2498 tcp->pid, (char *) 1, SIGTERM);
2499 droptcb(tcp);
2500 }
2501 continue;
2502 }
2503 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002504#ifdef TCB_GROUP_EXITING
2505 if (tcp->flags & TCB_GROUP_EXITING) {
2506 if (handle_group_exit(tcp, 0) < 0)
2507 return -1;
2508 continue;
2509 }
2510#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002511 if (tcp->flags & TCB_ATTACHED)
2512 detach(tcp, 0);
2513 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
2514 perror("strace: ptrace(PTRACE_CONT, ...)");
2515 cleanup();
2516 return -1;
2517 }
2518 continue;
2519 }
2520 if (tcp->flags & TCB_SUSPENDED) {
2521 if (!qflag)
2522 fprintf(stderr, "Process %u suspended\n", pid);
2523 continue;
2524 }
2525 tracing:
2526 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
2527 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2528 cleanup();
2529 return -1;
2530 }
2531 }
2532 return 0;
2533}
2534
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002535#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002536
2537static int curcol;
2538
2539#ifdef __STDC__
2540#include <stdarg.h>
2541#define VA_START(a, b) va_start(a, b)
2542#else
2543#include <varargs.h>
2544#define VA_START(a, b) va_start(a)
2545#endif
2546
2547void
2548#ifdef __STDC__
2549tprintf(const char *fmt, ...)
2550#else
2551tprintf(fmt, va_alist)
2552char *fmt;
2553va_dcl
2554#endif
2555{
2556 va_list args;
2557
2558 VA_START(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002559 if (outf) {
2560 int n = vfprintf(outf, fmt, args);
2561 if (n < 0 && outf != stderr)
2562 perror(outfname == NULL
2563 ? "<writing to pipe>" : outfname);
2564 else
2565 curcol += n;
2566 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002567 va_end(args);
2568 return;
2569}
2570
2571void
2572printleader(tcp)
2573struct tcb *tcp;
2574{
2575 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
2576 tcp_last->flags |= TCB_REPRINT;
2577 tprintf(" <unfinished ...>\n");
2578 }
2579 curcol = 0;
2580 if ((followfork == 1 || pflag_seen > 1) && outfname)
2581 tprintf("%-5d ", tcp->pid);
2582 else if (nprocs > 1 && !outfname)
2583 tprintf("[pid %5u] ", tcp->pid);
2584 if (tflag) {
2585 char str[sizeof("HH:MM:SS")];
2586 struct timeval tv, dtv;
2587 static struct timeval otv;
2588
2589 gettimeofday(&tv, NULL);
2590 if (rflag) {
2591 if (otv.tv_sec == 0)
2592 otv = tv;
2593 tv_sub(&dtv, &tv, &otv);
2594 tprintf("%6ld.%06ld ",
2595 (long) dtv.tv_sec, (long) dtv.tv_usec);
2596 otv = tv;
2597 }
2598 else if (tflag > 2) {
2599 tprintf("%ld.%06ld ",
2600 (long) tv.tv_sec, (long) tv.tv_usec);
2601 }
2602 else {
2603 time_t local = tv.tv_sec;
2604 strftime(str, sizeof(str), "%T", localtime(&local));
2605 if (tflag > 1)
2606 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2607 else
2608 tprintf("%s ", str);
2609 }
2610 }
2611 if (iflag)
2612 printcall(tcp);
2613}
2614
2615void
2616tabto(col)
2617int col;
2618{
2619 if (curcol < col)
2620 tprintf("%*s", col - curcol, "");
2621}
2622
2623void
2624printtrailer(tcp)
2625struct tcb *tcp;
2626{
2627 tprintf("\n");
2628 tcp_last = NULL;
2629}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002630
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002631#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002632
2633int mp_ioctl (int fd, int cmd, void *arg, int size) {
2634
2635 struct iovec iov[2];
2636 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002637
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002638 iov[0].iov_base = &cmd;
2639 iov[0].iov_len = sizeof cmd;
2640 if (arg) {
2641 ++n;
2642 iov[1].iov_base = arg;
2643 iov[1].iov_len = size;
2644 }
Roland McGrath553a6092002-12-16 20:40:39 +00002645
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002646 return writev (fd, iov, n);
2647}
2648
2649#endif