blob: 6f63ee9a7fa2bcc9feb3e4068fac097330f07f14 [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00006 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * $Id$
31 */
32
33#include "defs.h"
34
Roland McGrath795edb12005-02-02 04:44:57 +000035#include <sys/types.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000036#include <signal.h>
37#include <errno.h>
38#include <sys/param.h>
39#include <fcntl.h>
40#include <sys/resource.h>
41#include <sys/wait.h>
42#include <sys/stat.h>
43#include <pwd.h>
44#include <grp.h>
45#include <string.h>
John Hughes19e49982001-10-19 08:59:12 +000046#include <limits.h>
Roland McGrath70b08532004-04-09 00:25:21 +000047#include <dirent.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000048
Roland McGrath134813a2007-06-02 00:07:33 +000049#ifdef LINUX
50# include <asm/unistd.h>
51# if defined __NR_tgkill
52# define my_tgkill(pid, tid, sig) syscall (__NR_tgkill, (pid), (tid), (sig))
53# elif defined __NR_tkill
54# define my_tgkill(pid, tid, sig) syscall (__NR_tkill, (tid), (sig))
55# else
56 /* kill() may choose arbitrarily the target task of the process group
57 while we later wait on a that specific TID. PID process waits become
58 TID task specific waits for a process under ptrace(2). */
59# warning "Neither tkill(2) nor tgkill(2) available, risk of strace hangs!"
60# define my_tgkill(pid, tid, sig) kill ((tid), (sig))
61# endif
62#endif
63
Wichert Akkerman7b3346b2001-10-09 23:47:38 +000064#if defined(IA64) && defined(LINUX)
65# include <asm/ptrace_offsets.h>
66#endif
67
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +000068#ifdef USE_PROCFS
69#include <poll.h>
70#endif
71
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000072#ifdef SVR4
73#include <sys/stropts.h>
Wichert Akkermanea78f0f1999-11-29 15:34:02 +000074#ifdef HAVE_MP_PROCFS
John Hughes1d08dcf2001-07-10 13:48:44 +000075#ifdef HAVE_SYS_UIO_H
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000076#include <sys/uio.h>
77#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000078#endif
John Hughes1d08dcf2001-07-10 13:48:44 +000079#endif
Denys Vlasenko96d5a762008-12-29 19:13:27 +000080extern char **environ;
Denys Vlasenko418d66a2009-01-17 01:52:54 +000081extern int optind;
82extern char *optarg;
Denys Vlasenko96d5a762008-12-29 19:13:27 +000083
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000084
Roland McGrath41c48222008-07-18 00:25:10 +000085int debug = 0, followfork = 0;
Wang Chaob13c0de2010-11-12 17:25:19 +080086unsigned int ptrace_setoptions = 0;
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +000087int dtime = 0, xflag = 0, qflag = 0;
88cflag_t cflag = CFLAG_NONE;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +000089static int iflag = 0, interactive = 0, pflag_seen = 0, rflag = 0, tflag = 0;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +000090/*
91 * daemonized_tracer supports -D option.
92 * With this option, strace forks twice.
93 * Unlike normal case, with -D *grandparent* process exec's,
94 * becoming a traced process. Child exits (this prevents traced process
95 * from having children it doesn't expect to have), and grandchild
96 * attaches to grandparent similarly to strace -p PID.
97 * This allows for more transparent interaction in cases
98 * when process and its parent are communicating via signals,
99 * wait() etc. Without -D, strace process gets lodged in between,
100 * disrupting parent<->child link.
101 */
102static bool daemonized_tracer = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000103
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000104/* Sometimes we want to print only succeeding syscalls. */
105int not_failing_only = 0;
106
Dmitry V. Levina6809652008-11-10 17:14:58 +0000107static int exit_code = 0;
108static int strace_child = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700109
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +0000110static char *username = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000111uid_t run_uid;
112gid_t run_gid;
113
114int acolumn = DEFAULT_ACOLUMN;
115int max_strlen = DEFAULT_STRLEN;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +0000116static char *outfname = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000117FILE *outf;
Andreas Schwabccdff482009-10-27 16:27:13 +0100118static int curcol;
Roland McGrathee9d4352002-12-18 04:16:10 +0000119struct tcb **tcbtab;
120unsigned int nprocs, tcbtabsize;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000121const char *progname;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700122extern char **environ;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000123
Andreas Schwabe5355de2009-10-27 16:56:43 +0100124static int detach(struct tcb *tcp, int sig);
125static int trace(void);
126static void cleanup(void);
127static void interrupt(int sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000128static sigset_t empty_set, blocked_set;
129
130#ifdef HAVE_SIG_ATOMIC_T
131static volatile sig_atomic_t interrupted;
132#else /* !HAVE_SIG_ATOMIC_T */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000133static volatile int interrupted;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000134#endif /* !HAVE_SIG_ATOMIC_T */
135
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000136#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000137
Andreas Schwabe5355de2009-10-27 16:56:43 +0100138static struct tcb *pfd2tcb(int pfd);
139static void reaper(int sig);
140static void rebuild_pollv(void);
Roland McGrathee9d4352002-12-18 04:16:10 +0000141static struct pollfd *pollv;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000142
143#ifndef HAVE_POLLABLE_PROCFS
144
Andreas Schwabe5355de2009-10-27 16:56:43 +0100145static void proc_poll_open(void);
146static void proc_poller(int pfd);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000147
148struct proc_pollfd {
149 int fd;
150 int revents;
151 int pid;
152};
153
154static int poller_pid;
155static int proc_poll_pipe[2] = { -1, -1 };
156
157#endif /* !HAVE_POLLABLE_PROCFS */
158
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000159#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000160#define POLLWANT POLLWRNORM
161#else
162#define POLLWANT POLLPRI
163#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000164#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000165
166static void
167usage(ofp, exitval)
168FILE *ofp;
169int exitval;
170{
171 fprintf(ofp, "\
Andreas Schwabb87d30c2010-06-11 15:49:36 +0200172usage: strace [-CdDffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000173 [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n\
174 [command [arg ...]]\n\
Andreas Schwabb87d30c2010-06-11 15:49:36 +0200175 or: strace -c [-D] [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000176 [command [arg ...]]\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000177-c -- count time, calls, and errors for each syscall and report summary\n\
Andreas Schwabb87d30c2010-06-11 15:49:36 +0200178-C -- like -c but also print regular output while processes are running\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000179-f -- follow forks, -ff -- with output into separate files\n\
180-F -- attempt to follow vforks, -h -- print help message\n\
181-i -- print instruction pointer at time of syscall\n\
182-q -- suppress messages about attaching, detaching, etc.\n\
183-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
184-T -- print time spent in each syscall, -V -- print version\n\
185-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
186-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
187-a column -- alignment COLUMN for printing syscall results (default %d)\n\
188-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
189 options: trace, abbrev, verbose, raw, signal, read, or write\n\
190-o file -- send trace output to FILE instead of stderr\n\
191-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
192-p pid -- trace process with process id PID, may be repeated\n\
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000193-D -- run tracer process as a detached grandchild, not as parent\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000194-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
195-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
196-u username -- run command as username handling setuid and/or setgid\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000197-E var=val -- put var=val in the environment for command\n\
198-E var -- remove var from the environment for command\n\
199" /* this is broken, so don't document it
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000200-z -- print only succeeding syscalls\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000201 */
202, DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000203 exit(exitval);
204}
205
206#ifdef SVR4
207#ifdef MIPS
208void
209foobar()
210{
211}
212#endif /* MIPS */
213#endif /* SVR4 */
214
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400215/* Glue for systems without a MMU that cannot provide fork() */
216#ifdef HAVE_FORK
217# define strace_vforked 0
218#else
219# define strace_vforked 1
220# define fork() vfork()
221#endif
222
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000223static int
224set_cloexec_flag(int fd)
225{
226 int flags, newflags;
227
228 if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
229 {
230 fprintf(stderr, "%s: fcntl F_GETFD: %s\n",
231 progname, strerror(errno));
232 return -1;
233 }
234
235 newflags = flags | FD_CLOEXEC;
236 if (flags == newflags)
237 return 0;
238
239 if (fcntl(fd, F_SETFD, newflags) < 0)
240 {
241 fprintf(stderr, "%s: fcntl F_SETFD: %s\n",
242 progname, strerror(errno));
243 return -1;
244 }
245
246 return 0;
247}
248
249/*
250 * When strace is setuid executable, we have to swap uids
251 * before and after filesystem and process management operations.
252 */
253static void
254swap_uid(void)
255{
256#ifndef SVR4
257 int euid = geteuid(), uid = getuid();
258
259 if (euid != uid && setreuid(euid, uid) < 0)
260 {
261 fprintf(stderr, "%s: setreuid: %s\n",
262 progname, strerror(errno));
263 exit(1);
264 }
265#endif
266}
267
Roland McGrath4bfa6262007-07-05 20:03:16 +0000268#if _LFS64_LARGEFILE
269# define fopen_for_output fopen64
270#else
271# define fopen_for_output fopen
272#endif
273
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000274static FILE *
275strace_fopen(const char *path, const char *mode)
276{
277 FILE *fp;
278
279 swap_uid();
Roland McGrath4bfa6262007-07-05 20:03:16 +0000280 if ((fp = fopen_for_output(path, mode)) == NULL)
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000281 fprintf(stderr, "%s: can't fopen '%s': %s\n",
282 progname, path, strerror(errno));
283 swap_uid();
284 if (fp && set_cloexec_flag(fileno(fp)) < 0)
285 {
286 fclose(fp);
287 fp = NULL;
288 }
289 return fp;
290}
291
292static int popen_pid = -1;
293
294#ifndef _PATH_BSHELL
295# define _PATH_BSHELL "/bin/sh"
296#endif
297
298/*
299 * We cannot use standard popen(3) here because we have to distinguish
300 * popen child process from other processes we trace, and standard popen(3)
301 * does not export its child's pid.
302 */
303static FILE *
304strace_popen(const char *command)
305{
306 int fds[2];
307
308 swap_uid();
309 if (pipe(fds) < 0)
310 {
311 fprintf(stderr, "%s: pipe: %s\n",
312 progname, strerror(errno));
313 swap_uid();
314 return NULL;
315 }
316
317 if (set_cloexec_flag(fds[1]) < 0)
318 {
319 close(fds[0]);
320 close(fds[1]);
321 swap_uid();
322 return NULL;
323 }
324
325 if ((popen_pid = fork()) == -1)
326 {
327 fprintf(stderr, "%s: fork: %s\n",
328 progname, strerror(errno));
329 close(fds[0]);
330 close(fds[1]);
331 swap_uid();
332 return NULL;
333 }
334
335 if (popen_pid)
336 {
337 /* parent */
338 close(fds[0]);
339 swap_uid();
340 return fdopen(fds[1], "w");
341 } else
342 {
343 /* child */
344 close(fds[1]);
345 if (fds[0] && (dup2(fds[0], 0) || close(fds[0])))
346 {
347 fprintf(stderr, "%s: dup2: %s\n",
348 progname, strerror(errno));
349 _exit(1);
350 }
351 execl(_PATH_BSHELL, "sh", "-c", command, NULL);
352 fprintf(stderr, "%s: execl: %s: %s\n",
353 progname, _PATH_BSHELL, strerror(errno));
354 _exit(1);
355 }
356}
357
358static int
359newoutf(struct tcb *tcp)
360{
361 if (outfname && followfork > 1) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000362 char name[520 + sizeof(int) * 3];
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000363 FILE *fp;
364
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000365 sprintf(name, "%.512s.%u", outfname, tcp->pid);
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000366 if ((fp = strace_fopen(name, "w")) == NULL)
367 return -1;
368 tcp->outf = fp;
369 }
370 return 0;
371}
372
Roland McGrath02203312007-06-11 22:06:31 +0000373static void
374startup_attach(void)
375{
376 int tcbi;
377 struct tcb *tcp;
378
379 /*
380 * Block user interruptions as we would leave the traced
381 * process stopped (process state T) if we would terminate in
382 * between PTRACE_ATTACH and wait4 () on SIGSTOP.
383 * We rely on cleanup () from this point on.
384 */
385 if (interactive)
386 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
387
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000388 if (daemonized_tracer) {
389 pid_t pid = fork();
390 if (pid < 0) {
391 _exit(1);
392 }
393 if (pid) { /* parent */
394 /*
395 * Wait for child to attach to straced process
396 * (our parent). Child SIGKILLs us after it attached.
397 * Parent's wait() is unblocked by our death,
398 * it proceeds to exec the straced program.
399 */
400 pause();
401 _exit(0); /* paranoia */
402 }
403 }
404
Roland McGrath02203312007-06-11 22:06:31 +0000405 for (tcbi = 0; tcbi < tcbtabsize; tcbi++) {
406 tcp = tcbtab[tcbi];
407 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
408 continue;
409#ifdef LINUX
410 if (tcp->flags & TCB_CLONE_THREAD)
411 continue;
412#endif
413 /* Reinitialize the output since it may have changed. */
414 tcp->outf = outf;
415 if (newoutf(tcp) < 0)
416 exit(1);
417
418#ifdef USE_PROCFS
419 if (proc_open(tcp, 1) < 0) {
420 fprintf(stderr, "trouble opening proc file\n");
421 droptcb(tcp);
422 continue;
423 }
424#else /* !USE_PROCFS */
425# ifdef LINUX
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000426 if (followfork && !daemonized_tracer) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000427 char procdir[sizeof("/proc/%d/task") + sizeof(int) * 3];
Roland McGrath02203312007-06-11 22:06:31 +0000428 DIR *dir;
429
430 sprintf(procdir, "/proc/%d/task", tcp->pid);
431 dir = opendir(procdir);
432 if (dir != NULL) {
433 unsigned int ntid = 0, nerr = 0;
434 struct dirent *de;
435 int tid;
436 while ((de = readdir(dir)) != NULL) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000437 if (de->d_fileno == 0)
Roland McGrath02203312007-06-11 22:06:31 +0000438 continue;
439 tid = atoi(de->d_name);
440 if (tid <= 0)
441 continue;
442 ++ntid;
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000443 if (ptrace(PTRACE_ATTACH, tid, (char *) 1, 0) < 0)
Roland McGrath02203312007-06-11 22:06:31 +0000444 ++nerr;
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000445 else if (tid != tcbtab[tcbi]->pid) {
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000446 tcp = alloctcb(tid);
Wang Chao21b8db42010-08-27 17:43:16 +0800447 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_FOLLOWFORK;
Roland McGrath02203312007-06-11 22:06:31 +0000448 tcbtab[tcbi]->nchildren++;
449 tcbtab[tcbi]->nclone_threads++;
Roland McGrath02203312007-06-11 22:06:31 +0000450 tcp->parent = tcbtab[tcbi];
451 }
Denys Vlasenkoaab52ca2009-03-17 14:46:54 +0000452 if (interactive) {
453 sigprocmask(SIG_SETMASK, &empty_set, NULL);
454 if (interrupted)
455 return;
456 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
457 }
Roland McGrath02203312007-06-11 22:06:31 +0000458 }
459 closedir(dir);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000460 ntid -= nerr;
461 if (ntid == 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000462 perror("attach: ptrace(PTRACE_ATTACH, ...)");
463 droptcb(tcp);
464 continue;
465 }
466 if (!qflag) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000467 fprintf(stderr, ntid > 1
468? "Process %u attached with %u threads - interrupt to quit\n"
469: "Process %u attached - interrupt to quit\n",
470 tcbtab[tcbi]->pid, ntid);
Roland McGrath02203312007-06-11 22:06:31 +0000471 }
472 continue;
Denys Vlasenko7a8bf062009-01-29 20:38:20 +0000473 } /* if (opendir worked) */
474 } /* if (-f) */
Roland McGrath02203312007-06-11 22:06:31 +0000475# endif
476 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
477 perror("attach: ptrace(PTRACE_ATTACH, ...)");
478 droptcb(tcp);
479 continue;
480 }
481 /* INTERRUPTED is going to be checked at the top of TRACE. */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000482
483 if (daemonized_tracer) {
484 /*
485 * It is our grandparent we trace, not a -p PID.
486 * Don't want to just detach on exit, so...
487 */
488 tcp->flags &= ~TCB_ATTACHED;
489 /*
490 * Make parent go away.
491 * Also makes grandparent's wait() unblock.
492 */
493 kill(getppid(), SIGKILL);
494 }
495
Roland McGrath02203312007-06-11 22:06:31 +0000496#endif /* !USE_PROCFS */
497 if (!qflag)
498 fprintf(stderr,
499 "Process %u attached - interrupt to quit\n",
500 tcp->pid);
501 }
502
503 if (interactive)
504 sigprocmask(SIG_SETMASK, &empty_set, NULL);
505}
506
507static void
508startup_child (char **argv)
509{
510 struct stat statbuf;
511 const char *filename;
512 char pathname[MAXPATHLEN];
513 int pid = 0;
514 struct tcb *tcp;
515
516 filename = argv[0];
517 if (strchr(filename, '/')) {
518 if (strlen(filename) > sizeof pathname - 1) {
519 errno = ENAMETOOLONG;
520 perror("strace: exec");
521 exit(1);
522 }
523 strcpy(pathname, filename);
524 }
525#ifdef USE_DEBUGGING_EXEC
526 /*
527 * Debuggers customarily check the current directory
528 * first regardless of the path but doing that gives
529 * security geeks a panic attack.
530 */
531 else if (stat(filename, &statbuf) == 0)
532 strcpy(pathname, filename);
533#endif /* USE_DEBUGGING_EXEC */
534 else {
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000535 const char *path;
Roland McGrath02203312007-06-11 22:06:31 +0000536 int m, n, len;
537
538 for (path = getenv("PATH"); path && *path; path += m) {
539 if (strchr(path, ':')) {
540 n = strchr(path, ':') - path;
541 m = n + 1;
542 }
543 else
544 m = n = strlen(path);
545 if (n == 0) {
546 if (!getcwd(pathname, MAXPATHLEN))
547 continue;
548 len = strlen(pathname);
549 }
550 else if (n > sizeof pathname - 1)
551 continue;
552 else {
553 strncpy(pathname, path, n);
554 len = n;
555 }
556 if (len && pathname[len - 1] != '/')
557 pathname[len++] = '/';
558 strcpy(pathname + len, filename);
559 if (stat(pathname, &statbuf) == 0 &&
560 /* Accept only regular files
561 with some execute bits set.
562 XXX not perfect, might still fail */
563 S_ISREG(statbuf.st_mode) &&
564 (statbuf.st_mode & 0111))
565 break;
566 }
567 }
568 if (stat(pathname, &statbuf) < 0) {
569 fprintf(stderr, "%s: %s: command not found\n",
570 progname, filename);
571 exit(1);
572 }
Dmitry V. Levina6809652008-11-10 17:14:58 +0000573 strace_child = pid = fork();
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000574 if (pid < 0) {
Roland McGrath02203312007-06-11 22:06:31 +0000575 perror("strace: fork");
576 cleanup();
577 exit(1);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000578 }
579 if ((pid != 0 && daemonized_tracer) /* parent: to become a traced process */
580 || (pid == 0 && !daemonized_tracer) /* child: to become a traced process */
581 ) {
582 pid = getpid();
Roland McGrath02203312007-06-11 22:06:31 +0000583#ifdef USE_PROCFS
584 if (outf != stderr) close (fileno (outf));
585#ifdef MIPS
586 /* Kludge for SGI, see proc_open for details. */
587 sa.sa_handler = foobar;
588 sa.sa_flags = 0;
589 sigemptyset(&sa.sa_mask);
590 sigaction(SIGINT, &sa, NULL);
591#endif /* MIPS */
592#ifndef FREEBSD
593 pause();
594#else /* FREEBSD */
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000595 kill(pid, SIGSTOP); /* stop HERE */
Roland McGrath02203312007-06-11 22:06:31 +0000596#endif /* FREEBSD */
597#else /* !USE_PROCFS */
598 if (outf!=stderr)
599 close(fileno (outf));
600
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000601 if (!daemonized_tracer) {
602 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
603 perror("strace: ptrace(PTRACE_TRACEME, ...)");
604 exit(1);
605 }
606 if (debug)
607 kill(pid, SIGSTOP);
Roland McGrath02203312007-06-11 22:06:31 +0000608 }
Roland McGrath02203312007-06-11 22:06:31 +0000609
610 if (username != NULL || geteuid() == 0) {
611 uid_t run_euid = run_uid;
612 gid_t run_egid = run_gid;
613
614 if (statbuf.st_mode & S_ISUID)
615 run_euid = statbuf.st_uid;
616 if (statbuf.st_mode & S_ISGID)
617 run_egid = statbuf.st_gid;
618
619 /*
620 * It is important to set groups before we
621 * lose privileges on setuid.
622 */
623 if (username != NULL) {
624 if (initgroups(username, run_gid) < 0) {
625 perror("initgroups");
626 exit(1);
627 }
628 if (setregid(run_gid, run_egid) < 0) {
629 perror("setregid");
630 exit(1);
631 }
632 if (setreuid(run_uid, run_euid) < 0) {
633 perror("setreuid");
634 exit(1);
635 }
636 }
637 }
638 else
639 setreuid(run_uid, run_uid);
640
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000641 if (!daemonized_tracer) {
642 /*
643 * Induce an immediate stop so that the parent
644 * will resume us with PTRACE_SYSCALL and display
645 * this execve call normally.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400646 * Unless of course we're on a no-MMU system where
647 * we vfork()-ed, so we cannot stop the child.
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000648 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -0400649 if (!strace_vforked)
650 kill(getpid(), SIGSTOP);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000651 } else {
652 struct sigaction sv_sigchld;
653 sigaction(SIGCHLD, NULL, &sv_sigchld);
654 /*
655 * Make sure it is not SIG_IGN, otherwise wait
656 * will not block.
657 */
658 signal(SIGCHLD, SIG_DFL);
659 /*
660 * Wait for grandchild to attach to us.
661 * It kills child after that, and wait() unblocks.
662 */
663 alarm(3);
664 wait(NULL);
665 alarm(0);
666 sigaction(SIGCHLD, &sv_sigchld, NULL);
667 }
Roland McGrath02203312007-06-11 22:06:31 +0000668#endif /* !USE_PROCFS */
669
670 execv(pathname, argv);
671 perror("strace: exec");
672 _exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000673 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000674
675 /* We are the tracer. */
676 tcp = alloctcb(daemonized_tracer ? getppid() : pid);
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000677 if (daemonized_tracer) {
678 /* We want subsequent startup_attach() to attach to it. */
679 tcp->flags |= TCB_ATTACHED;
680 }
Roland McGrath02203312007-06-11 22:06:31 +0000681#ifdef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000682 if (proc_open(tcp, 0) < 0) {
683 fprintf(stderr, "trouble opening proc file\n");
684 cleanup();
685 exit(1);
Roland McGrath02203312007-06-11 22:06:31 +0000686 }
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000687#endif /* USE_PROCFS */
Roland McGrath02203312007-06-11 22:06:31 +0000688}
689
Wang Chaob13c0de2010-11-12 17:25:19 +0800690#ifdef LINUX
691/*
692 * Test whether kernel support PTRACE_O_TRACECLONE et al options.
693 * First fork a new child, call ptrace with PTRACE_SETOPTIONS on it,
694 * and then see which options are supported on this kernel.
695 */
696static int
697test_ptrace_setoptions(void)
698{
699 int pid;
700
701 if ((pid = fork()) < 0)
702 return -1;
703 else if (pid == 0) {
704 if (ptrace(PTRACE_TRACEME, 0, (char *)1, 0) < 0) {
705 _exit(1);
706 }
707 kill(getpid(), SIGSTOP);
708 if ((pid = fork()) < 0) {
709 _exit(1);
710 }
711 _exit(0);
712 }
713 else {
714 int status, tracee_pid, error;
715 int no_child = 0;
716 while (1) {
717 tracee_pid = wait4(-1, &status, 0, NULL);
718 error = errno;
719 if (tracee_pid == -1) {
720 switch (error) {
721 case EINTR:
722 continue;
723 case ECHILD:
724 no_child = 1;
725 break;
726 default:
727 errno = error;
728 perror("test_ptrace_setoptions");
729 return -1;
730 }
731 }
732 if (no_child)
733 break;
734 if (tracee_pid != pid) {
735 if (ptrace(PTRACE_CONT, tracee_pid, 0, 0) < 0 &&
736 errno != ESRCH)
737 kill(tracee_pid, SIGKILL);
738 }
739 else if (WIFSTOPPED(status)) {
740 if (status >> 16 == PTRACE_EVENT_FORK)
741 ptrace_setoptions |= (PTRACE_O_TRACEVFORK |
742 PTRACE_O_TRACECLONE |
743 PTRACE_O_TRACEFORK);
744 if (WSTOPSIG(status) == SIGSTOP) {
745 if (ptrace(PTRACE_SETOPTIONS, pid, NULL,
746 PTRACE_O_TRACEFORK) < 0) {
747 kill(pid, SIGKILL);
748 return -1;
749 }
750 }
751 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0 &&
752 errno != ESRCH)
753 kill(pid, SIGKILL);
754 }
755 }
756 }
757 return 0;
758}
759#endif
760
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000761int
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000762main(int argc, char *argv[])
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000763{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000764 struct tcb *tcp;
765 int c, pid = 0;
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000766 int optF = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000767 struct sigaction sa;
768
769 static char buf[BUFSIZ];
770
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000771 progname = argv[0] ? argv[0] : "strace";
772
Roland McGrathee9d4352002-12-18 04:16:10 +0000773 /* Allocate the initial tcbtab. */
774 tcbtabsize = argc; /* Surely enough for all -p args. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000775 if ((tcbtab = calloc(tcbtabsize, sizeof tcbtab[0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000776 fprintf(stderr, "%s: out of memory\n", progname);
777 exit(1);
778 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000779 if ((tcbtab[0] = calloc(tcbtabsize, sizeof tcbtab[0][0])) == NULL) {
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000780 fprintf(stderr, "%s: out of memory\n", progname);
781 exit(1);
782 }
Roland McGrathee9d4352002-12-18 04:16:10 +0000783 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
784 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
785
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000786 outf = stderr;
787 interactive = 1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000788 set_sortby(DEFAULT_SORTBY);
789 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000790 qualify("trace=all");
791 qualify("abbrev=all");
792 qualify("verbose=all");
793 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000794 while ((c = getopt(argc, argv,
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000795 "+cCdfFhiqrtTvVxz"
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000796#ifndef USE_PROCFS
797 "D"
798#endif
799 "a:e:o:O:p:s:S:u:E:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000800 switch (c) {
801 case 'c':
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000802 if (cflag == CFLAG_BOTH) {
803 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
804 progname);
805 exit(1);
806 }
807 cflag = CFLAG_ONLY_STATS;
808 break;
809 case 'C':
810 if (cflag == CFLAG_ONLY_STATS) {
811 fprintf(stderr, "%s: -c and -C are mutually exclusive options\n",
812 progname);
813 exit(1);
814 }
815 cflag = CFLAG_BOTH;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000816 break;
817 case 'd':
818 debug++;
819 break;
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000820#ifndef USE_PROCFS
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +0000821 case 'D':
822 daemonized_tracer = 1;
823 break;
824#endif
Roland McGrath41c48222008-07-18 00:25:10 +0000825 case 'F':
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000826 optF = 1;
827 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000828 case 'f':
829 followfork++;
830 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000831 case 'h':
832 usage(stdout, 0);
833 break;
834 case 'i':
835 iflag++;
836 break;
837 case 'q':
838 qflag++;
839 break;
840 case 'r':
841 rflag++;
842 tflag++;
843 break;
844 case 't':
845 tflag++;
846 break;
847 case 'T':
848 dtime++;
849 break;
850 case 'x':
851 xflag++;
852 break;
853 case 'v':
854 qualify("abbrev=none");
855 break;
856 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +0000857 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000858 exit(0);
859 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000860 case 'z':
861 not_failing_only = 1;
862 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000863 case 'a':
864 acolumn = atoi(optarg);
865 break;
866 case 'e':
867 qualify(optarg);
868 break;
869 case 'o':
870 outfname = strdup(optarg);
871 break;
872 case 'O':
873 set_overhead(atoi(optarg));
874 break;
875 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +0000876 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000877 fprintf(stderr, "%s: Invalid process id: %s\n",
878 progname, optarg);
879 break;
880 }
881 if (pid == getpid()) {
Wichert Akkerman54a47671999-10-17 00:57:34 +0000882 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000883 break;
884 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +0000885 tcp = alloc_tcb(pid, 0);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000886 tcp->flags |= TCB_ATTACHED;
887 pflag_seen++;
888 break;
889 case 's':
890 max_strlen = atoi(optarg);
Roland McGrathdccec722005-05-09 07:45:47 +0000891 if (max_strlen < 0) {
892 fprintf(stderr,
893 "%s: invalid -s argument: %s\n",
894 progname, optarg);
895 exit(1);
896 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000897 break;
898 case 'S':
899 set_sortby(optarg);
900 break;
901 case 'u':
902 username = strdup(optarg);
903 break;
Roland McGrathde6e5332003-01-24 04:31:23 +0000904 case 'E':
905 if (putenv(optarg) < 0) {
906 fprintf(stderr, "%s: out of memory\n",
907 progname);
908 exit(1);
909 }
910 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000911 default:
912 usage(stderr, 1);
913 break;
914 }
915 }
916
Roland McGrathd0c4c0c2006-04-25 07:39:40 +0000917 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +0000918 usage(stderr, 1);
919
Wang Chaod322a4b2010-08-05 14:30:11 +0800920 if (pflag_seen && daemonized_tracer) {
921 fprintf(stderr,
922 "%s: -D and -p are mutually exclusive options\n",
923 progname);
924 exit(1);
925 }
926
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000927 if (!followfork)
928 followfork = optF;
929
Roland McGrathcb9def62006-04-25 07:48:03 +0000930 if (followfork > 1 && cflag) {
931 fprintf(stderr,
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +0000932 "%s: (-c or -C) and -ff are mutually exclusive options\n",
Roland McGrathcb9def62006-04-25 07:48:03 +0000933 progname);
934 exit(1);
935 }
936
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000937 /* See if they want to run as another user. */
938 if (username != NULL) {
939 struct passwd *pent;
940
941 if (getuid() != 0 || geteuid() != 0) {
942 fprintf(stderr,
943 "%s: you must be root to use the -u option\n",
944 progname);
945 exit(1);
946 }
947 if ((pent = getpwnam(username)) == NULL) {
948 fprintf(stderr, "%s: cannot find user `%s'\n",
Roland McGrath09553f82007-07-05 19:31:49 +0000949 progname, username);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000950 exit(1);
951 }
952 run_uid = pent->pw_uid;
953 run_gid = pent->pw_gid;
954 }
955 else {
956 run_uid = getuid();
957 run_gid = getgid();
958 }
959
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000960 /* Check if they want to redirect the output. */
961 if (outfname) {
Roland McGrath37b9a662003-11-07 02:26:54 +0000962 /* See if they want to pipe the output. */
963 if (outfname[0] == '|' || outfname[0] == '!') {
964 /*
965 * We can't do the <outfname>.PID funny business
966 * when using popen, so prohibit it.
967 */
968 if (followfork > 1) {
969 fprintf(stderr, "\
970%s: piping the output and -ff are mutually exclusive options\n",
971 progname);
972 exit(1);
973 }
974
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000975 if ((outf = strace_popen(outfname + 1)) == NULL)
Roland McGrath37b9a662003-11-07 02:26:54 +0000976 exit(1);
Roland McGrath37b9a662003-11-07 02:26:54 +0000977 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000978 else if (followfork <= 1 &&
979 (outf = strace_fopen(outfname, "w")) == NULL)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000980 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000981 }
982
Roland McGrath37b9a662003-11-07 02:26:54 +0000983 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000984 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +0000985 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000986 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000987 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +0000988 }
Wang Chaob13c0de2010-11-12 17:25:19 +0800989
990#ifdef LINUX
991 if (followfork && test_ptrace_setoptions() < 0) {
992 fprintf(stderr, "Test for options supported by PTRACE_SETOPTIONS\
993 failed, give up using this feature\n");
994 ptrace_setoptions = 0;
995 }
996#endif
997
Roland McGrath54cc1c82007-11-03 23:34:11 +0000998 /* Valid states here:
999 optind < argc pflag_seen outfname interactive
1000 1 0 0 1
1001 0 1 0 1
1002 1 0 1 0
1003 0 1 1 1
1004 */
1005
1006 /* STARTUP_CHILD must be called before the signal handlers get
1007 installed below as they are inherited into the spawned process.
1008 Also we do not need to be protected by them as during interruption
1009 in the STARTUP_CHILD mode we kill the spawned process anyway. */
1010 if (!pflag_seen)
1011 startup_child(&argv[optind]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001012
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001013 sigemptyset(&empty_set);
1014 sigemptyset(&blocked_set);
1015 sa.sa_handler = SIG_IGN;
1016 sigemptyset(&sa.sa_mask);
1017 sa.sa_flags = 0;
1018 sigaction(SIGTTOU, &sa, NULL);
1019 sigaction(SIGTTIN, &sa, NULL);
1020 if (interactive) {
1021 sigaddset(&blocked_set, SIGHUP);
1022 sigaddset(&blocked_set, SIGINT);
1023 sigaddset(&blocked_set, SIGQUIT);
1024 sigaddset(&blocked_set, SIGPIPE);
1025 sigaddset(&blocked_set, SIGTERM);
1026 sa.sa_handler = interrupt;
1027#ifdef SUNOS4
1028 /* POSIX signals on sunos4.1 are a little broken. */
1029 sa.sa_flags = SA_INTERRUPT;
1030#endif /* SUNOS4 */
1031 }
1032 sigaction(SIGHUP, &sa, NULL);
1033 sigaction(SIGINT, &sa, NULL);
1034 sigaction(SIGQUIT, &sa, NULL);
1035 sigaction(SIGPIPE, &sa, NULL);
1036 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001037#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001038 sa.sa_handler = reaper;
1039 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +00001040#else
1041 /* Make sure SIGCHLD has the default action so that waitpid
1042 definitely works without losing track of children. The user
1043 should not have given us a bogus state to inherit, but he might
1044 have. Arguably we should detect SIG_IGN here and pass it on
1045 to children, but probably noone really needs that. */
1046 sa.sa_handler = SIG_DFL;
1047 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001048#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001049
Denys Vlasenkoecfe2f12008-12-30 20:51:30 +00001050 if (pflag_seen || daemonized_tracer)
Roland McGrath02203312007-06-11 22:06:31 +00001051 startup_attach();
Roland McGrath02203312007-06-11 22:06:31 +00001052
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001053 if (trace() < 0)
1054 exit(1);
1055 cleanup();
Dmitry V. Levina6809652008-11-10 17:14:58 +00001056 fflush(NULL);
1057 if (exit_code > 0xff) {
1058 /* Child was killed by a signal, mimic that. */
1059 exit_code &= 0xff;
1060 signal(exit_code, SIG_DFL);
1061 raise(exit_code);
1062 /* Paranoia - what if this signal is not fatal?
1063 Exit with 128 + signo then. */
1064 exit_code += 128;
1065 }
1066 exit(exit_code);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001067}
1068
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001069void
1070expand_tcbtab(void)
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001071{
1072 /* Allocate some more TCBs and expand the table.
1073 We don't want to relocate the TCBs because our
1074 callers have pointers and it would be a pain.
1075 So tcbtab is a table of pointers. Since we never
1076 free the TCBs, we allocate a single chunk of many. */
1077 struct tcb **newtab = (struct tcb **)
1078 realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
1079 struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
1080 sizeof *newtcbs);
1081 int i;
1082 if (newtab == NULL || newtcbs == NULL) {
Dmitry V. Levin76860f62006-10-11 22:55:25 +00001083 fprintf(stderr, "%s: expand_tcbtab: out of memory\n",
1084 progname);
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001085 cleanup();
1086 exit(1);
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001087 }
1088 for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
1089 newtab[i] = &newtcbs[i - tcbtabsize];
1090 tcbtabsize *= 2;
1091 tcbtab = newtab;
Roland McGrath7b54a7a2004-06-04 01:50:45 +00001092}
1093
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001094struct tcb *
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001095alloc_tcb(int pid, int command_options_parsed)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001096{
1097 int i;
1098 struct tcb *tcp;
1099
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001100 if (nprocs == tcbtabsize)
1101 expand_tcbtab();
1102
Roland McGrathee9d4352002-12-18 04:16:10 +00001103 for (i = 0; i < tcbtabsize; i++) {
1104 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001105 if ((tcp->flags & TCB_INUSE) == 0) {
1106 tcp->pid = pid;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001107 tcp->parent = NULL;
1108 tcp->nchildren = 0;
1109 tcp->nzombies = 0;
1110#ifdef TCB_CLONE_THREAD
Wang Chao21b8db42010-08-27 17:43:16 +08001111 tcp->nclone_threads = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001112 tcp->nclone_waiting = 0;
1113#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001114 tcp->flags = TCB_INUSE | TCB_STARTUP;
1115 tcp->outf = outf; /* Initialise to current out file */
Andreas Schwabccdff482009-10-27 16:27:13 +01001116 tcp->curcol = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001117 tcp->stime.tv_sec = 0;
1118 tcp->stime.tv_usec = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001119 tcp->pfd = -1;
1120 nprocs++;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001121 if (command_options_parsed)
1122 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001123 return tcp;
1124 }
1125 }
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001126 fprintf(stderr, "%s: bug in alloc_tcb\n", progname);
1127 cleanup();
1128 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001129}
1130
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001131#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001132int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001133proc_open(struct tcb *tcp, int attaching)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001134{
1135 char proc[32];
1136 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001137#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +00001138 int i;
1139 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001140 sigset_t signals;
1141 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001142#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001143#ifndef HAVE_POLLABLE_PROCFS
1144 static int last_pfd;
1145#endif
1146
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001147#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001148 /* Open the process pseudo-files in /proc. */
1149 sprintf(proc, "/proc/%d/ctl", tcp->pid);
1150 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001151 perror("strace: open(\"/proc/...\", ...)");
1152 return -1;
1153 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001154 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001155 return -1;
1156 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001157 sprintf(proc, "/proc/%d/status", tcp->pid);
1158 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
1159 perror("strace: open(\"/proc/...\", ...)");
1160 return -1;
1161 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001162 if (set_cloexec_flag(tcp->pfd_stat) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001163 return -1;
1164 }
1165 sprintf(proc, "/proc/%d/as", tcp->pid);
1166 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
1167 perror("strace: open(\"/proc/...\", ...)");
1168 return -1;
1169 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001170 if (set_cloexec_flag(tcp->pfd_as) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001171 return -1;
1172 }
1173#else
1174 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001175#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001176 sprintf(proc, "/proc/%d", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001177 tcp->pfd = open(proc, O_RDWR|O_EXCL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001178#else /* FREEBSD */
1179 sprintf(proc, "/proc/%d/mem", tcp->pid);
Andreas Schwab372cc842010-07-09 11:49:27 +02001180 tcp->pfd = open(proc, O_RDWR);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001181#endif /* FREEBSD */
Andreas Schwab372cc842010-07-09 11:49:27 +02001182 if (tcp->pfd < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001183 perror("strace: open(\"/proc/...\", ...)");
1184 return -1;
1185 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001186 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001187 return -1;
1188 }
1189#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001190#ifdef FREEBSD
1191 sprintf(proc, "/proc/%d/regs", tcp->pid);
1192 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
1193 perror("strace: open(\"/proc/.../regs\", ...)");
1194 return -1;
1195 }
1196 if (cflag) {
1197 sprintf(proc, "/proc/%d/status", tcp->pid);
1198 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
1199 perror("strace: open(\"/proc/.../status\", ...)");
1200 return -1;
1201 }
1202 } else
1203 tcp->pfd_status = -1;
1204#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001205 rebuild_pollv();
1206 if (!attaching) {
1207 /*
1208 * Wait for the child to pause. Because of a race
1209 * condition we have to poll for the event.
1210 */
1211 for (;;) {
1212 if (IOCTL_STATUS (tcp) < 0) {
1213 perror("strace: PIOCSTATUS");
1214 return -1;
1215 }
1216 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001217 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001218 }
1219 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001220#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001221 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001222 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001223 perror("strace: PIOCSTOP");
1224 return -1;
1225 }
Roland McGrath553a6092002-12-16 20:40:39 +00001226#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001227#ifdef PIOCSET
1228 /* Set Run-on-Last-Close. */
1229 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001230 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001231 perror("PIOCSET PR_RLC");
1232 return -1;
1233 }
1234 /* Set or Reset Inherit-on-Fork. */
1235 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001236 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001237 perror("PIOC{SET,RESET} PR_FORK");
1238 return -1;
1239 }
1240#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +00001241#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001242 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
1243 perror("PIOCSRLC");
1244 return -1;
1245 }
1246 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
1247 perror("PIOC{S,R}FORK");
1248 return -1;
1249 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001250#else /* FREEBSD */
1251 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
1252 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
1253 perror("PIOCGFL");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001254 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001255 }
1256 arg &= ~PF_LINGER;
1257 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001258 perror("PIOCSFL");
1259 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001260 }
1261#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001262#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001263#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +00001264 /* Enable all syscall entries we care about. */
1265 premptyset(&syscalls);
1266 for (i = 1; i < MAX_QUALS; ++i) {
1267 if (i > (sizeof syscalls) * CHAR_BIT) break;
1268 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
1269 }
1270 praddset (&syscalls, SYS_execve);
1271 if (followfork) {
1272 praddset (&syscalls, SYS_fork);
1273#ifdef SYS_forkall
1274 praddset (&syscalls, SYS_forkall);
1275#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001276#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +00001277 praddset (&syscalls, SYS_fork1);
1278#endif
1279#ifdef SYS_rfork1
1280 praddset (&syscalls, SYS_rfork1);
1281#endif
1282#ifdef SYS_rforkall
1283 praddset (&syscalls, SYS_rforkall);
1284#endif
1285 }
1286 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001287 perror("PIOCSENTRY");
1288 return -1;
1289 }
John Hughes19e49982001-10-19 08:59:12 +00001290 /* Enable the syscall exits. */
1291 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001292 perror("PIOSEXIT");
1293 return -1;
1294 }
John Hughes19e49982001-10-19 08:59:12 +00001295 /* Enable signals we care about. */
1296 premptyset(&signals);
1297 for (i = 1; i < MAX_QUALS; ++i) {
1298 if (i > (sizeof signals) * CHAR_BIT) break;
1299 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
1300 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001301 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001302 perror("PIOCSTRACE");
1303 return -1;
1304 }
John Hughes19e49982001-10-19 08:59:12 +00001305 /* Enable faults we care about */
1306 premptyset(&faults);
1307 for (i = 1; i < MAX_QUALS; ++i) {
1308 if (i > (sizeof faults) * CHAR_BIT) break;
1309 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
1310 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001311 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001312 perror("PIOCSFAULT");
1313 return -1;
1314 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001315#else /* FREEBSD */
1316 /* set events flags. */
1317 arg = S_SIG | S_SCE | S_SCX ;
1318 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
1319 perror("PIOCBIS");
1320 return -1;
1321 }
1322#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001323 if (!attaching) {
1324#ifdef MIPS
1325 /*
1326 * The SGI PRSABORT doesn't work for pause() so
1327 * we send it a caught signal to wake it up.
1328 */
1329 kill(tcp->pid, SIGINT);
1330#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +00001331#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001332 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001333 arg = PRSABORT;
1334 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001335 perror("PIOCRUN");
1336 return -1;
1337 }
Roland McGrath553a6092002-12-16 20:40:39 +00001338#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001339#endif /* !MIPS*/
1340#ifdef FREEBSD
1341 /* wake up the child if it received the SIGSTOP */
1342 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001343#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001344 for (;;) {
1345 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001346 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001347 perror("PIOCWSTOP");
1348 return -1;
1349 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001350 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001351 tcp->flags &= ~TCB_INSYSCALL;
1352 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001353 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001354 break;
1355 }
1356 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001357#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001358 arg = 0;
1359 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001360#else /* FREEBSD */
1361 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001362#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001363 perror("PIOCRUN");
1364 return -1;
1365 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001366#ifdef FREEBSD
1367 /* handle the case where we "opened" the child before
1368 it did the kill -STOP */
1369 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1370 tcp->status.PR_WHAT == SIGSTOP)
1371 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001372#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001373 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001374#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001375 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001376#else /* FREEBSD */
1377 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001378 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001379 /* We are attaching to an already running process.
1380 * Try to figure out the state of the process in syscalls,
1381 * to handle the first event well.
1382 * This is done by having a look at the "wchan" property of the
1383 * process, which tells where it is stopped (if it is). */
1384 FILE * status;
1385 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001386
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001387 sprintf(proc, "/proc/%d/status", tcp->pid);
1388 status = fopen(proc, "r");
1389 if (status &&
1390 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1391 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1392 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1393 strcmp(wchan, "stopevent")) {
1394 /* The process is asleep in the middle of a syscall.
1395 Fake the syscall entry event */
1396 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1397 tcp->status.PR_WHY = PR_SYSENTRY;
1398 trace_syscall(tcp);
1399 }
1400 if (status)
1401 fclose(status);
1402 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001403 }
1404#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001405#ifndef HAVE_POLLABLE_PROCFS
1406 if (proc_poll_pipe[0] != -1)
1407 proc_poller(tcp->pfd);
1408 else if (nprocs > 1) {
1409 proc_poll_open();
1410 proc_poller(last_pfd);
1411 proc_poller(tcp->pfd);
1412 }
1413 last_pfd = tcp->pfd;
1414#endif /* !HAVE_POLLABLE_PROCFS */
1415 return 0;
1416}
1417
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001418#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001419
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001420struct tcb *
Roland McGrath54e931f2010-09-14 18:59:20 -07001421pid2tcb(int pid)
1422{
1423 int i;
1424
1425 if (pid <= 0)
1426 return NULL;
1427
1428 for (i = 0; i < tcbtabsize; i++) {
1429 struct tcb *tcp = tcbtab[i];
1430 if (tcp->pid == pid && (tcp->flags & TCB_INUSE))
1431 return tcp;
1432 }
1433
1434 return NULL;
1435}
1436
1437#ifdef USE_PROCFS
1438
1439static struct tcb *
1440first_used_tcb(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001441{
1442 int i;
1443 struct tcb *tcp;
Roland McGrathee9d4352002-12-18 04:16:10 +00001444 for (i = 0; i < tcbtabsize; i++) {
1445 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001446 if (tcp->flags & TCB_INUSE)
1447 return tcp;
1448 }
1449 return NULL;
1450}
1451
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001452static struct tcb *
1453pfd2tcb(pfd)
1454int pfd;
1455{
1456 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001457
Roland McGrathca16be82003-01-10 19:55:28 +00001458 for (i = 0; i < tcbtabsize; i++) {
1459 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001460 if (tcp->pfd != pfd)
1461 continue;
1462 if (tcp->flags & TCB_INUSE)
1463 return tcp;
1464 }
1465 return NULL;
1466}
1467
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001468#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001469
1470void
1471droptcb(tcp)
1472struct tcb *tcp;
1473{
1474 if (tcp->pid == 0)
1475 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001476#ifdef TCB_CLONE_THREAD
1477 if (tcp->nclone_threads > 0) {
1478 /* There are other threads left in this process, but this
1479 is the one whose PID represents the whole process.
1480 We need to keep this record around as a zombie until
1481 all the threads die. */
1482 tcp->flags |= TCB_EXITING;
1483 return;
1484 }
1485#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001486 nprocs--;
1487 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001488
Roland McGrathe29341c2003-01-10 20:14:20 +00001489 if (tcp->parent != NULL) {
1490 tcp->parent->nchildren--;
1491#ifdef TCB_CLONE_THREAD
Roland McGrathe29341c2003-01-10 20:14:20 +00001492 if (tcp->flags & TCB_CLONE_THREAD)
1493 tcp->parent->nclone_threads--;
1494#endif
Wang Chao21b8db42010-08-27 17:43:16 +08001495 tcp->parent->nzombies++;
Roland McGrath276ceb32007-11-13 08:12:12 +00001496#ifdef LINUX
1497 /* Update `tcp->parent->parent->nchildren' and the other fields
1498 like NCLONE_DETACHED, only for zombie group leader that has
1499 already reported and been short-circuited at the top of this
1500 function. The same condition as at the top of DETACH. */
1501 if ((tcp->flags & TCB_CLONE_THREAD) &&
1502 tcp->parent->nclone_threads == 0 &&
1503 (tcp->parent->flags & TCB_EXITING))
1504 droptcb(tcp->parent);
1505#endif
Roland McGrathe29341c2003-01-10 20:14:20 +00001506 tcp->parent = NULL;
1507 }
1508
1509 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001510 if (tcp->pfd != -1) {
1511 close(tcp->pfd);
1512 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001513#ifdef FREEBSD
1514 if (tcp->pfd_reg != -1) {
1515 close(tcp->pfd_reg);
1516 tcp->pfd_reg = -1;
1517 }
1518 if (tcp->pfd_status != -1) {
1519 close(tcp->pfd_status);
1520 tcp->pfd_status = -1;
1521 }
Roland McGrath553a6092002-12-16 20:40:39 +00001522#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001523#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001524 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001525#endif
1526 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001527
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001528 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001529 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001530
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001531 tcp->outf = 0;
1532}
1533
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001534#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001535
1536static int
1537resume(tcp)
1538struct tcb *tcp;
1539{
1540 if (tcp == NULL)
1541 return -1;
1542
1543 if (!(tcp->flags & TCB_SUSPENDED)) {
1544 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1545 return -1;
1546 }
1547 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001548#ifdef TCB_CLONE_THREAD
1549 if (tcp->flags & TCB_CLONE_THREAD)
1550 tcp->parent->nclone_waiting--;
1551#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001552
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001553 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001554 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001555
1556 if (!qflag)
1557 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1558 return 0;
1559}
1560
Roland McGrath1bfd3102007-08-03 10:02:00 +00001561static int
1562resume_from_tcp (struct tcb *tcp)
1563{
1564 int error = 0;
1565 int resumed = 0;
1566
1567 /* XXX This won't always be quite right (but it never was).
1568 A waiter with argument 0 or < -1 is waiting for any pid in
1569 a particular pgrp, which this child might or might not be
1570 in. The waiter will only wake up if it's argument is -1
1571 or if it's waiting for tcp->pid's pgrp. It makes a
1572 difference to wake up a waiter when there might be more
1573 traced children, because it could get a false ECHILD
1574 error. OTOH, if this was the last child in the pgrp, then
1575 it ought to wake up and get ECHILD. We would have to
1576 search the system for all pid's in the pgrp to be sure.
1577
1578 && (t->waitpid == -1 ||
1579 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1580 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1581 */
1582
1583 if (tcp->parent &&
1584 (tcp->parent->flags & TCB_SUSPENDED) &&
1585 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001586 error = resume(tcp->parent);
Roland McGrath1bfd3102007-08-03 10:02:00 +00001587 ++resumed;
1588 }
1589#ifdef TCB_CLONE_THREAD
1590 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1591 /* Some other threads of our parent are waiting too. */
1592 unsigned int i;
1593
1594 /* Resume all the threads that were waiting for this PID. */
1595 for (i = 0; i < tcbtabsize; i++) {
1596 struct tcb *t = tcbtab[i];
1597 if (t->parent == tcp->parent && t != tcp
1598 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1599 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1600 && t->waitpid == tcp->pid) {
1601 error |= resume (t);
1602 ++resumed;
1603 }
1604 }
1605 if (resumed == 0)
1606 /* Noone was waiting for this PID in particular,
1607 so now we might need to resume some wildcarders. */
1608 for (i = 0; i < tcbtabsize; i++) {
1609 struct tcb *t = tcbtab[i];
1610 if (t->parent == tcp->parent && t != tcp
1611 && ((t->flags
1612 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1613 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1614 && t->waitpid <= 0
1615 ) {
1616 error |= resume (t);
1617 break;
1618 }
1619 }
1620 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001621#endif
Roland McGrath1bfd3102007-08-03 10:02:00 +00001622
1623 return error;
1624}
Roland McGrath1bfd3102007-08-03 10:02:00 +00001625
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001626#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001627
Roland McGrath0a463882007-07-05 18:43:16 +00001628/* detach traced process; continue with sig
1629 Never call DETACH twice on the same process as both unattached and
1630 attached-unstopped processes give the same ESRCH. For unattached process we
1631 would SIGSTOP it and wait for its SIGSTOP notification forever. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001632
1633static int
1634detach(tcp, sig)
1635struct tcb *tcp;
1636int sig;
1637{
1638 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001639#ifdef LINUX
Roland McGrath1bfd3102007-08-03 10:02:00 +00001640 int status, catch_sigstop;
Roland McGratha08a97e2005-08-03 11:23:46 +00001641 struct tcb *zombie = NULL;
1642
1643 /* If the group leader is lingering only because of this other
1644 thread now dying, then detach the leader as well. */
1645 if ((tcp->flags & TCB_CLONE_THREAD) &&
1646 tcp->parent->nclone_threads == 1 &&
1647 (tcp->parent->flags & TCB_EXITING))
1648 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001649#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001650
1651 if (tcp->flags & TCB_BPTSET)
Andreas Schwab840d85b2010-01-12 11:16:32 +01001652 clearbpt(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001653
1654#ifdef LINUX
1655 /*
1656 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001657 * before detaching. Arghh. We go through hoops
1658 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001659 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001660#if defined(SPARC)
1661#undef PTRACE_DETACH
1662#define PTRACE_DETACH PTRACE_SUNDETACH
1663#endif
Roland McGrath02203312007-06-11 22:06:31 +00001664 /*
1665 * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
1666 * expected SIGSTOP. We must catch exactly one as otherwise the
1667 * detached process would be left stopped (process state T).
1668 */
1669 catch_sigstop = (tcp->flags & TCB_STARTUP);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001670 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1671 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001672 }
1673 else if (errno != ESRCH) {
1674 /* Shouldn't happen. */
1675 perror("detach: ptrace(PTRACE_DETACH, ...)");
1676 }
Roland McGrath134813a2007-06-02 00:07:33 +00001677 else if (my_tgkill((tcp->flags & TCB_CLONE_THREAD ? tcp->parent->pid
1678 : tcp->pid),
1679 tcp->pid, 0) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001680 if (errno != ESRCH)
1681 perror("detach: checking sanity");
1682 }
Roland McGrath02203312007-06-11 22:06:31 +00001683 else if (!catch_sigstop && my_tgkill((tcp->flags & TCB_CLONE_THREAD
1684 ? tcp->parent->pid : tcp->pid),
1685 tcp->pid, SIGSTOP) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001686 if (errno != ESRCH)
1687 perror("detach: stopping child");
1688 }
Roland McGrath02203312007-06-11 22:06:31 +00001689 else
1690 catch_sigstop = 1;
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001691 if (catch_sigstop) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001692 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001693#ifdef __WALL
1694 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1695 if (errno == ECHILD) /* Already gone. */
1696 break;
1697 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001698 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001699 break;
1700 }
1701#endif /* __WALL */
1702 /* No __WALL here. */
1703 if (waitpid(tcp->pid, &status, 0) < 0) {
1704 if (errno != ECHILD) {
1705 perror("detach: waiting");
1706 break;
1707 }
1708#ifdef __WCLONE
1709 /* If no processes, try clones. */
1710 if (wait4(tcp->pid, &status, __WCLONE,
1711 NULL) < 0) {
1712 if (errno != ECHILD)
1713 perror("detach: waiting");
1714 break;
1715 }
1716#endif /* __WCLONE */
1717 }
1718#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001719 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001720#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001721 if (!WIFSTOPPED(status)) {
1722 /* Au revoir, mon ami. */
1723 break;
1724 }
1725 if (WSTOPSIG(status) == SIGSTOP) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001726 ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001727 break;
1728 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001729 error = ptrace_restart(PTRACE_CONT, tcp,
Roland McGratheb9e2e82009-06-02 16:49:22 -07001730 WSTOPSIG(status) == SIGTRAP ? 0
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001731 : WSTOPSIG(status));
1732 if (error < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001733 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001734 }
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001735 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001736#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001737
1738#if defined(SUNOS4)
1739 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1740 if (sig && kill(tcp->pid, sig) < 0)
1741 perror("detach: kill");
1742 sig = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001743 error = ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001744#endif /* SUNOS4 */
1745
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001746#ifndef USE_PROCFS
Roland McGrath1bfd3102007-08-03 10:02:00 +00001747 error |= resume_from_tcp (tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001748#endif
1749
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001750 if (!qflag)
1751 fprintf(stderr, "Process %u detached\n", tcp->pid);
1752
1753 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001754
1755#ifdef LINUX
Roland McGrath0a463882007-07-05 18:43:16 +00001756 if (zombie != NULL) {
1757 /* TCP no longer exists therefore you must not detach () it. */
1758 droptcb(zombie);
1759 }
Roland McGratha08a97e2005-08-03 11:23:46 +00001760#endif
1761
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001762 return error;
1763}
1764
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001765#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001766
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001767static void reaper(int sig)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001768{
1769 int pid;
1770 int status;
1771
1772 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001773 }
1774}
1775
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001776#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001777
1778static void
1779cleanup()
1780{
1781 int i;
1782 struct tcb *tcp;
1783
Roland McGrathee9d4352002-12-18 04:16:10 +00001784 for (i = 0; i < tcbtabsize; i++) {
1785 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001786 if (!(tcp->flags & TCB_INUSE))
1787 continue;
1788 if (debug)
1789 fprintf(stderr,
1790 "cleanup: looking at pid %u\n", tcp->pid);
1791 if (tcp_last &&
1792 (!outfname || followfork < 2 || tcp_last == tcp)) {
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00001793 tprintf(" <unfinished ...>");
1794 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001795 }
1796 if (tcp->flags & TCB_ATTACHED)
1797 detach(tcp, 0);
1798 else {
1799 kill(tcp->pid, SIGCONT);
1800 kill(tcp->pid, SIGTERM);
1801 }
1802 }
1803 if (cflag)
1804 call_summary(outf);
1805}
1806
1807static void
1808interrupt(sig)
1809int sig;
1810{
1811 interrupted = 1;
1812}
1813
1814#ifndef HAVE_STRERROR
1815
Roland McGrath6d2b3492002-12-30 00:51:30 +00001816#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001817extern int sys_nerr;
1818extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001819#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001820
1821const char *
1822strerror(errno)
1823int errno;
1824{
1825 static char buf[64];
1826
1827 if (errno < 1 || errno >= sys_nerr) {
1828 sprintf(buf, "Unknown error %d", errno);
1829 return buf;
1830 }
1831 return sys_errlist[errno];
1832}
1833
1834#endif /* HAVE_STERRROR */
1835
1836#ifndef HAVE_STRSIGNAL
1837
Roland McGrath8f474e02003-01-14 07:53:33 +00001838#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001839extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001840#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001841#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1842extern char *_sys_siglist[];
1843#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001844
1845const char *
1846strsignal(sig)
1847int sig;
1848{
1849 static char buf[64];
1850
1851 if (sig < 1 || sig >= NSIG) {
1852 sprintf(buf, "Unknown signal %d", sig);
1853 return buf;
1854 }
1855#ifdef HAVE__SYS_SIGLIST
1856 return _sys_siglist[sig];
1857#else
1858 return sys_siglist[sig];
1859#endif
1860}
1861
1862#endif /* HAVE_STRSIGNAL */
1863
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001864#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001865
1866static void
1867rebuild_pollv()
1868{
1869 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001870
Roland McGrathee9d4352002-12-18 04:16:10 +00001871 if (pollv != NULL)
1872 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001873 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001874 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001875 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00001876 exit(1);
1877 }
1878
Roland McGrathca16be82003-01-10 19:55:28 +00001879 for (i = j = 0; i < tcbtabsize; i++) {
1880 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001881 if (!(tcp->flags & TCB_INUSE))
1882 continue;
1883 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001884 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001885 j++;
1886 }
1887 if (j != nprocs) {
1888 fprintf(stderr, "strace: proc miscount\n");
1889 exit(1);
1890 }
1891}
1892
1893#ifndef HAVE_POLLABLE_PROCFS
1894
1895static void
1896proc_poll_open()
1897{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001898 int i;
1899
1900 if (pipe(proc_poll_pipe) < 0) {
1901 perror("pipe");
1902 exit(1);
1903 }
1904 for (i = 0; i < 2; i++) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001905 if (set_cloexec_flag(proc_poll_pipe[i]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001906 exit(1);
1907 }
1908 }
1909}
1910
1911static int
1912proc_poll(pollv, nfds, timeout)
1913struct pollfd *pollv;
1914int nfds;
1915int timeout;
1916{
1917 int i;
1918 int n;
1919 struct proc_pollfd pollinfo;
1920
1921 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1922 return n;
1923 if (n != sizeof(struct proc_pollfd)) {
1924 fprintf(stderr, "panic: short read: %d\n", n);
1925 exit(1);
1926 }
1927 for (i = 0; i < nprocs; i++) {
1928 if (pollv[i].fd == pollinfo.fd)
1929 pollv[i].revents = pollinfo.revents;
1930 else
1931 pollv[i].revents = 0;
1932 }
1933 poller_pid = pollinfo.pid;
1934 return 1;
1935}
1936
1937static void
1938wakeup_handler(sig)
1939int sig;
1940{
1941}
1942
1943static void
1944proc_poller(pfd)
1945int pfd;
1946{
1947 struct proc_pollfd pollinfo;
1948 struct sigaction sa;
1949 sigset_t blocked_set, empty_set;
1950 int i;
1951 int n;
1952 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001953#ifdef FREEBSD
1954 struct procfs_status pfs;
1955#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001956
1957 switch (fork()) {
1958 case -1:
1959 perror("fork");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001960 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001961 case 0:
1962 break;
1963 default:
1964 return;
1965 }
1966
1967 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1968 sa.sa_flags = 0;
1969 sigemptyset(&sa.sa_mask);
1970 sigaction(SIGHUP, &sa, NULL);
1971 sigaction(SIGINT, &sa, NULL);
1972 sigaction(SIGQUIT, &sa, NULL);
1973 sigaction(SIGPIPE, &sa, NULL);
1974 sigaction(SIGTERM, &sa, NULL);
1975 sa.sa_handler = wakeup_handler;
1976 sigaction(SIGUSR1, &sa, NULL);
1977 sigemptyset(&blocked_set);
1978 sigaddset(&blocked_set, SIGUSR1);
1979 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1980 sigemptyset(&empty_set);
1981
1982 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1983 perror("getrlimit(RLIMIT_NOFILE, ...)");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001984 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001985 }
1986 n = rl.rlim_cur;
1987 for (i = 0; i < n; i++) {
1988 if (i != pfd && i != proc_poll_pipe[1])
1989 close(i);
1990 }
1991
1992 pollinfo.fd = pfd;
1993 pollinfo.pid = getpid();
1994 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001995#ifndef FREEBSD
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001996 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1997#else
1998 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1999#endif
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002000 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002001 switch (errno) {
2002 case EINTR:
2003 continue;
2004 case EBADF:
2005 pollinfo.revents = POLLERR;
2006 break;
2007 case ENOENT:
2008 pollinfo.revents = POLLHUP;
2009 break;
2010 default:
2011 perror("proc_poller: PIOCWSTOP");
2012 }
2013 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2014 _exit(0);
2015 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002016 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002017 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2018 sigsuspend(&empty_set);
2019 }
2020}
2021
2022#endif /* !HAVE_POLLABLE_PROCFS */
2023
2024static int
2025choose_pfd()
2026{
2027 int i, j;
2028 struct tcb *tcp;
2029
2030 static int last;
2031
2032 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002033 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002034 /*
2035 * The previous process is ready to run again. We'll
2036 * let it do so if it is currently in a syscall. This
2037 * heuristic improves the readability of the trace.
2038 */
2039 tcp = pfd2tcb(pollv[last].fd);
2040 if (tcp && (tcp->flags & TCB_INSYSCALL))
2041 return pollv[last].fd;
2042 }
2043
2044 for (i = 0; i < nprocs; i++) {
2045 /* Let competing children run round robin. */
2046 j = (i + last + 1) % nprocs;
2047 if (pollv[j].revents & (POLLHUP | POLLERR)) {
2048 tcp = pfd2tcb(pollv[j].fd);
2049 if (!tcp) {
2050 fprintf(stderr, "strace: lost proc\n");
2051 exit(1);
2052 }
2053 droptcb(tcp);
2054 return -1;
2055 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002056 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002057 last = j;
2058 return pollv[j].fd;
2059 }
2060 }
2061 fprintf(stderr, "strace: nothing ready\n");
2062 exit(1);
2063}
2064
2065static int
2066trace()
2067{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002068#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00002069 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002070#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002071 struct tcb *tcp;
2072 int pfd;
2073 int what;
2074 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002075 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002076
2077 for (;;) {
2078 if (interactive)
2079 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2080
2081 if (nprocs == 0)
2082 break;
2083
2084 switch (nprocs) {
2085 case 1:
2086#ifndef HAVE_POLLABLE_PROCFS
2087 if (proc_poll_pipe[0] == -1) {
2088#endif
Roland McGrath54e931f2010-09-14 18:59:20 -07002089 tcp = first_used_tcb();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002090 if (!tcp)
2091 continue;
2092 pfd = tcp->pfd;
2093 if (pfd == -1)
2094 continue;
2095 break;
2096#ifndef HAVE_POLLABLE_PROCFS
2097 }
2098 /* fall through ... */
2099#endif /* !HAVE_POLLABLE_PROCFS */
2100 default:
2101#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002102#ifdef POLL_HACK
2103 /* On some systems (e.g. UnixWare) we get too much ugly
2104 "unfinished..." stuff when multiple proceses are in
2105 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00002106
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002107 if (in_syscall) {
2108 struct pollfd pv;
2109 tcp = in_syscall;
2110 in_syscall = NULL;
2111 pv.fd = tcp->pfd;
2112 pv.events = POLLWANT;
2113 if ((what = poll (&pv, 1, 1)) < 0) {
2114 if (interrupted)
2115 return 0;
2116 continue;
2117 }
2118 else if (what == 1 && pv.revents & POLLWANT) {
2119 goto FOUND;
2120 }
2121 }
2122#endif
2123
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002124 if (poll(pollv, nprocs, INFTIM) < 0) {
2125 if (interrupted)
2126 return 0;
2127 continue;
2128 }
2129#else /* !HAVE_POLLABLE_PROCFS */
2130 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
2131 if (interrupted)
2132 return 0;
2133 continue;
2134 }
2135#endif /* !HAVE_POLLABLE_PROCFS */
2136 pfd = choose_pfd();
2137 if (pfd == -1)
2138 continue;
2139 break;
2140 }
2141
2142 /* Look up `pfd' in our table. */
2143 if ((tcp = pfd2tcb(pfd)) == NULL) {
2144 fprintf(stderr, "unknown pfd: %u\n", pfd);
2145 exit(1);
2146 }
John Hughesb6643082002-05-23 11:02:22 +00002147#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002148 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00002149#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002150 /* Get the status of the process. */
2151 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002152#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002153 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002154#else /* FREEBSD */
2155 /* Thanks to some scheduling mystery, the first poller
2156 sometimes waits for the already processed end of fork
2157 event. Doing a non blocking poll here solves the problem. */
2158 if (proc_poll_pipe[0] != -1)
2159 ioctl_result = IOCTL_STATUS (tcp);
2160 else
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002161 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00002162#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002163 ioctl_errno = errno;
2164#ifndef HAVE_POLLABLE_PROCFS
2165 if (proc_poll_pipe[0] != -1) {
2166 if (ioctl_result < 0)
2167 kill(poller_pid, SIGKILL);
2168 else
2169 kill(poller_pid, SIGUSR1);
2170 }
2171#endif /* !HAVE_POLLABLE_PROCFS */
2172 }
2173 if (interrupted)
2174 return 0;
2175
2176 if (interactive)
2177 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2178
2179 if (ioctl_result < 0) {
2180 /* Find out what happened if it failed. */
2181 switch (ioctl_errno) {
2182 case EINTR:
2183 case EBADF:
2184 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002185#ifdef FREEBSD
2186 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00002187#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002188 case ENOENT:
2189 droptcb(tcp);
2190 continue;
2191 default:
2192 perror("PIOCWSTOP");
2193 exit(1);
2194 }
2195 }
2196
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002197#ifdef FREEBSD
2198 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2199 /* discard first event for a syscall we never entered */
2200 IOCTL (tcp->pfd, PIOCRUN, 0);
2201 continue;
2202 }
Roland McGrath553a6092002-12-16 20:40:39 +00002203#endif
2204
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002205 /* clear the just started flag */
2206 tcp->flags &= ~TCB_STARTUP;
2207
2208 /* set current output file */
2209 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002210 curcol = tcp->curcol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002211
2212 if (cflag) {
2213 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002214#ifdef FREEBSD
2215 char buf[1024];
2216 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002217
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002218 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
2219 buf[len] = '\0';
2220 sscanf(buf,
2221 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2222 &stime.tv_sec, &stime.tv_usec);
2223 } else
2224 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002225#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002226 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2227 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002228#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002229 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2230 tcp->stime = stime;
2231 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002232 what = tcp->status.PR_WHAT;
2233 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002234#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002235 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002236 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2237 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002238 if (trace_syscall(tcp) < 0) {
2239 fprintf(stderr, "syscall trouble\n");
2240 exit(1);
2241 }
2242 }
2243 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002244#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002245 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002246#ifdef POLL_HACK
2247 in_syscall = tcp;
2248#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002249 case PR_SYSEXIT:
2250 if (trace_syscall(tcp) < 0) {
2251 fprintf(stderr, "syscall trouble\n");
2252 exit(1);
2253 }
2254 break;
2255 case PR_SIGNALLED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002256 if (cflag != CFLAG_ONLY_STATS
2257 && (qual_flags[what] & QUAL_SIGNAL)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002258 printleader(tcp);
2259 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002260 signame(what), strsignal(what));
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002261 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002262#ifdef PR_INFO
2263 if (tcp->status.PR_INFO.si_signo == what) {
2264 printleader(tcp);
2265 tprintf(" siginfo=");
2266 printsiginfo(&tcp->status.PR_INFO, 1);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002267 printtrailer();
John Hughes58265892001-10-18 15:13:53 +00002268 }
2269#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002270 }
2271 break;
2272 case PR_FAULTED:
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002273 if (cflag != CFLAGS_ONLY_STATS
2274 && (qual_flags[what] & QUAL_FAULT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002275 printleader(tcp);
2276 tprintf("=== FAULT %d ===", what);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002277 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002278 }
2279 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002280#ifdef FREEBSD
2281 case 0: /* handle case we polled for nothing */
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002282 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00002283#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002284 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002285 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002286 exit(1);
2287 break;
2288 }
Andreas Schwabccdff482009-10-27 16:27:13 +01002289 /* Remember current print column before continuing. */
2290 tcp->curcol = curcol;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002291 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002292#ifndef FREEBSD
Andreas Schwab372cc842010-07-09 11:49:27 +02002293 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002294#else
Andreas Schwab372cc842010-07-09 11:49:27 +02002295 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0)
Roland McGrath553a6092002-12-16 20:40:39 +00002296#endif
Andreas Schwab372cc842010-07-09 11:49:27 +02002297 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002298 perror("PIOCRUN");
2299 exit(1);
2300 }
2301 }
2302 return 0;
2303}
2304
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002305#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002306
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002307#ifdef TCB_GROUP_EXITING
2308/* Handle an exit detach or death signal that is taking all the
2309 related clone threads with it. This is called in three circumstances:
2310 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
2311 SIG == 0 Continuing TCP will perform an exit_group syscall.
2312 SIG == other Continuing TCP with SIG will kill the process.
2313*/
2314static int
2315handle_group_exit(struct tcb *tcp, int sig)
2316{
2317 /* We need to locate our records of all the clone threads
2318 related to TCP, either its children or siblings. */
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002319 struct tcb *leader = NULL;
2320
2321 if (tcp->flags & TCB_CLONE_THREAD)
2322 leader = tcp->parent;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002323
2324 if (sig < 0) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002325 if (leader != NULL && leader != tcp
2326 && !(leader->flags & TCB_GROUP_EXITING)
2327 && !(tcp->flags & TCB_STARTUP)
2328 ) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002329 fprintf(stderr,
2330 "PANIC: handle_group_exit: %d leader %d\n",
2331 tcp->pid, leader ? leader->pid : -1);
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002332 }
2333 /* TCP no longer exists therefore you must not detach() it. */
Roland McGrath1bfd3102007-08-03 10:02:00 +00002334#ifndef USE_PROCFS
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002335 resume_from_tcp(tcp);
Roland McGrath1bfd3102007-08-03 10:02:00 +00002336#endif
Roland McGrath0a463882007-07-05 18:43:16 +00002337 droptcb(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002338 }
2339 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00002340 /* Mark that we are taking the process down. */
2341 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002342 if (tcp->flags & TCB_ATTACHED) {
Roland McGrathd6a32f12007-07-11 08:35:11 +00002343 detach(tcp, sig);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00002344 if (leader != NULL && leader != tcp)
Roland McGrath1bfd3102007-08-03 10:02:00 +00002345 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002346 } else {
2347 if (ptrace_restart(PTRACE_CONT, tcp, sig) < 0) {
2348 cleanup();
2349 return -1;
2350 }
2351 if (leader != NULL) {
Roland McGrath05690952004-10-20 01:00:27 +00002352 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002353 if (leader != tcp)
2354 droptcb(tcp);
2355 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002356 /* The leader will report to us as parent now,
2357 and then we'll get to the SIG==-1 case. */
2358 return 0;
2359 }
2360 }
2361
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002362 return 0;
2363}
2364#endif
2365
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002366#ifdef LINUX
2367static int
2368handle_ptrace_event(int status, struct tcb *tcp)
2369{
2370 if (status >> 16 == PTRACE_EVENT_VFORK ||
2371 status >> 16 == PTRACE_EVENT_CLONE ||
2372 status >> 16 == PTRACE_EVENT_FORK) {
2373 int childpid;
2374
2375 if (do_ptrace(PTRACE_GETEVENTMSG, tcp, NULL, &childpid) < 0) {
2376 if (errno != ESRCH) {
2377 fprintf(stderr, "\
2378%s: handle_ptrace_event: ptrace cannot get new child's pid\n",
2379 progname);
2380 cleanup();
2381 exit(1);
2382 }
2383 return -1;
2384 }
2385 return handle_new_child(tcp, childpid, 0);
2386 }
2387 return 1;
2388}
2389#endif
2390
Roland McGratheb9e2e82009-06-02 16:49:22 -07002391static int
2392trace()
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002393{
2394 int pid;
2395 int wait_errno;
2396 int status;
2397 struct tcb *tcp;
2398#ifdef LINUX
2399 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002400#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002401 static int wait4_options = __WALL;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002402#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002403#endif /* LINUX */
2404
Roland McGratheb9e2e82009-06-02 16:49:22 -07002405 while (nprocs != 0) {
Denys Vlasenko222713a2009-03-17 14:29:59 +00002406 if (interrupted)
Roland McGratheb9e2e82009-06-02 16:49:22 -07002407 return 0;
2408 if (interactive)
2409 sigprocmask(SIG_SETMASK, &empty_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002410#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002411#ifdef __WALL
Roland McGratheb9e2e82009-06-02 16:49:22 -07002412 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002413 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002414 /* this kernel does not support __WALL */
2415 wait4_options &= ~__WALL;
2416 errno = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002417 pid = wait4(-1, &status, wait4_options,
2418 cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002419 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002420 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002421 /* most likely a "cloned" process */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002422 pid = wait4(-1, &status, __WCLONE,
2423 cflag ? &ru : NULL);
2424 if (pid == -1) {
2425 fprintf(stderr, "strace: clone wait4 "
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002426 "failed: %s\n", strerror(errno));
2427 }
2428 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002429#else
2430 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
2431#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002432#endif /* LINUX */
2433#ifdef SUNOS4
2434 pid = wait(&status);
2435#endif /* SUNOS4 */
2436 wait_errno = errno;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002437 if (interactive)
2438 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002439
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002440 if (pid == -1) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002441 switch (wait_errno) {
2442 case EINTR:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002443 continue;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002444 case ECHILD:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002445 /*
2446 * We would like to verify this case
2447 * but sometimes a race in Solbourne's
2448 * version of SunOS sometimes reports
2449 * ECHILD before sending us SIGCHILD.
2450 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002451 return 0;
2452 default:
2453 errno = wait_errno;
2454 perror("strace: wait");
2455 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002456 }
2457 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002458 if (pid == popen_pid) {
2459 if (WIFEXITED(status) || WIFSIGNALED(status))
2460 popen_pid = -1;
2461 continue;
2462 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002463 if (debug)
2464 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2465
2466 /* Look up `pid' in our table. */
2467 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002468#ifdef LINUX
Roland McGrath41c48222008-07-18 00:25:10 +00002469 if (followfork) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002470 /* This is needed to go with the CLONE_PTRACE
2471 changes in process.c/util.c: we might see
2472 the child's initial trap before we see the
2473 parent return from the clone syscall.
2474 Leave the child suspended until the parent
2475 returns from its system call. Only then
2476 will we have the association of parent and
2477 child so that we know how to do clearbpt
2478 in the child. */
Denys Vlasenko418d66a2009-01-17 01:52:54 +00002479 tcp = alloctcb(pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002480 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002481 if (!qflag)
2482 fprintf(stderr, "\
2483Process %d attached (waiting for parent)\n",
2484 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002485 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002486 else
2487 /* This can happen if a clone call used
2488 CLONE_PTRACE itself. */
Roland McGratheb9e2e82009-06-02 16:49:22 -07002489#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002490 {
2491 fprintf(stderr, "unknown pid: %u\n", pid);
2492 if (WIFSTOPPED(status))
2493 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2494 exit(1);
2495 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002496 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002497 /* set current output file */
2498 outf = tcp->outf;
Andreas Schwabccdff482009-10-27 16:27:13 +01002499 curcol = tcp->curcol;
Denys Vlasenko84e20af2009-02-10 16:03:20 +00002500 if (cflag) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002501#ifdef LINUX
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002502 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2503 tcp->stime = ru.ru_stime;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002504#endif /* !LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002505 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002506
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002507 if (tcp->flags & TCB_SUSPENDED) {
2508 /*
2509 * Apparently, doing any ptrace() call on a stopped
2510 * process, provokes the kernel to report the process
2511 * status again on a subsequent wait(), even if the
2512 * process has not been actually restarted.
2513 * Since we have inspected the arguments of suspended
2514 * processes we end up here testing for this case.
2515 */
2516 continue;
2517 }
2518 if (WIFSIGNALED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002519 if (pid == strace_child)
2520 exit_code = 0x100 | WTERMSIG(status);
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002521 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002522 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2523 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002524 tprintf("+++ killed by %s %s+++",
2525 signame(WTERMSIG(status)),
2526#ifdef WCOREDUMP
2527 WCOREDUMP(status) ? "(core dumped) " :
2528#endif
2529 "");
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002530 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002531 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002532#ifdef TCB_GROUP_EXITING
2533 handle_group_exit(tcp, -1);
2534#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002535 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002536#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002537 continue;
2538 }
2539 if (WIFEXITED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002540 if (pid == strace_child)
2541 exit_code = WEXITSTATUS(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002542 if (debug)
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002543 fprintf(stderr, "pid %u exited with %d\n", pid, WEXITSTATUS(status));
2544 if ((tcp->flags & (TCB_ATTACHED|TCB_STARTUP)) == TCB_ATTACHED
Roland McGrath05690952004-10-20 01:00:27 +00002545#ifdef TCB_GROUP_EXITING
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002546 && !(tcp->parent && (tcp->parent->flags & TCB_GROUP_EXITING))
Roland McGrath1bfd3102007-08-03 10:02:00 +00002547 && !(tcp->flags & TCB_GROUP_EXITING)
Roland McGrath05690952004-10-20 01:00:27 +00002548#endif
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002549 ) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002550 fprintf(stderr,
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002551 "PANIC: attached pid %u exited with %d\n",
2552 pid, WEXITSTATUS(status));
2553 }
Roland McGrath0a396902003-06-10 03:05:53 +00002554 if (tcp == tcp_last) {
Denys Vlasenko7a8bf062009-01-29 20:38:20 +00002555 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT)) == TCB_INSYSCALL)
Roland McGrath0a396902003-06-10 03:05:53 +00002556 tprintf(" <unfinished ... exit status %d>\n",
2557 WEXITSTATUS(status));
2558 tcp_last = NULL;
2559 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002560#ifdef TCB_GROUP_EXITING
2561 handle_group_exit(tcp, -1);
2562#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002563 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002564#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002565 continue;
2566 }
2567 if (!WIFSTOPPED(status)) {
2568 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2569 droptcb(tcp);
2570 continue;
2571 }
2572 if (debug)
2573 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002574 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002575
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002576 if (ptrace_setoptions && (status >> 16)) {
2577 if (handle_ptrace_event(status, tcp) != 1)
2578 goto tracing;
2579 }
2580
Roland McGrath02203312007-06-11 22:06:31 +00002581 /*
2582 * Interestingly, the process may stop
2583 * with STOPSIG equal to some other signal
Roland McGratheb9e2e82009-06-02 16:49:22 -07002584 * than SIGSTOP if we happend to attach
Roland McGrath02203312007-06-11 22:06:31 +00002585 * just before the process takes a signal.
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002586 * A no-MMU vforked child won't send up a signal,
2587 * so skip the first (lost) execve notification.
Roland McGrath02203312007-06-11 22:06:31 +00002588 */
Mike Frysingerc1a5b7e2009-10-07 20:41:29 -04002589 if ((tcp->flags & TCB_STARTUP) &&
2590 (WSTOPSIG(status) == SIGSTOP || strace_vforked)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002591 /*
2592 * This flag is there to keep us in sync.
2593 * Next time this process stops it should
2594 * really be entering a system call.
2595 */
2596 tcp->flags &= ~TCB_STARTUP;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002597 if (tcp->flags & TCB_BPTSET) {
Roland McGrath02203312007-06-11 22:06:31 +00002598 /*
2599 * One example is a breakpoint inherited from
2600 * parent through fork ().
2601 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002602 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2603 droptcb(tcp);
2604 cleanup();
2605 return -1;
2606 }
2607 }
Wang Chaoca8ab8d2010-11-12 17:26:08 +08002608#ifdef LINUX
2609 if (followfork && (tcp->parent == NULL) && ptrace_setoptions)
2610 if (ptrace(PTRACE_SETOPTIONS, tcp->pid,
2611 NULL, ptrace_setoptions) < 0 &&
2612 errno != ESRCH)
2613 ptrace_setoptions = 0;
2614#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002615 goto tracing;
2616 }
2617
Roland McGratheb9e2e82009-06-02 16:49:22 -07002618 if (WSTOPSIG(status) != SIGTRAP) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002619 if (WSTOPSIG(status) == SIGSTOP &&
2620 (tcp->flags & TCB_SIGTRAPPED)) {
2621 /*
2622 * Trapped attempt to block SIGTRAP
2623 * Hope we are back in control now.
2624 */
2625 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002626 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002627 cleanup();
2628 return -1;
2629 }
2630 continue;
2631 }
Dmitry V. Levine3a7ef52010-03-28 19:24:54 +00002632 if (cflag != CFLAG_ONLY_STATS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002633 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00002634 unsigned long addr = 0;
2635 long pc = 0;
Dmitry V. Levin96339422006-10-11 23:11:43 +00002636#if defined(PT_CR_IPSR) && defined(PT_CR_IIP) && defined(PT_GETSIGINFO)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002637# define PSR_RI 41
2638 struct siginfo si;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002639 long psr;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002640
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002641 upeek(tcp, PT_CR_IPSR, &psr);
2642 upeek(tcp, PT_CR_IIP, &pc);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002643
2644 pc += (psr >> PSR_RI) & 0x3;
2645 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2646 addr = (unsigned long) si.si_addr;
Roland McGrath3a055d72005-03-06 22:24:29 +00002647#elif defined PTRACE_GETSIGINFO
2648 if (WSTOPSIG(status) == SIGSEGV ||
2649 WSTOPSIG(status) == SIGBUS) {
2650 siginfo_t si;
2651 if (ptrace(PTRACE_GETSIGINFO, pid,
2652 0, &si) == 0)
2653 addr = (unsigned long)
2654 si.si_addr;
2655 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002656#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002657 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002658 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002659 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002660 strsignal(WSTOPSIG(status)), pc, addr);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002661 printtrailer();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002662 }
Roland McGrath05690952004-10-20 01:00:27 +00002663 if (((tcp->flags & TCB_ATTACHED) ||
2664 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002665 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002666#ifdef TCB_GROUP_EXITING
2667 handle_group_exit(tcp, WSTOPSIG(status));
2668#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002669 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002670#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002671 continue;
2672 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002673 if (ptrace_restart(PTRACE_SYSCALL, tcp, WSTOPSIG(status)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002674 cleanup();
2675 return -1;
2676 }
2677 tcp->flags &= ~TCB_SUSPENDED;
2678 continue;
2679 }
Roland McGrath02203312007-06-11 22:06:31 +00002680 /* we handled the STATUS, we are permitted to interrupt now. */
2681 if (interrupted)
2682 return 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002683 if (trace_syscall(tcp) < 0 && !tcp->ptrace_errno) {
2684 /* ptrace() failed in trace_syscall() with ESRCH.
2685 * Likely a result of process disappearing mid-flight.
2686 * Observed case: exit_group() terminating
2687 * all processes in thread group. In this case, threads
2688 * "disappear" in an unpredictable moment without any
2689 * notification to strace via wait().
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002690 */
2691 if (tcp->flags & TCB_ATTACHED) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002692 if (tcp_last) {
2693 /* Do we have dangling line "syscall(param, param"?
2694 * Finish the line then. We cannot
2695 */
2696 tcp_last->flags |= TCB_REPRINT;
2697 tprintf(" <unfinished ...>");
2698 printtrailer();
2699 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002700 detach(tcp, 0);
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002701 } else {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002702 ptrace(PTRACE_KILL,
2703 tcp->pid, (char *) 1, SIGTERM);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002704 droptcb(tcp);
2705 }
2706 continue;
2707 }
2708 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002709#ifdef TCB_GROUP_EXITING
2710 if (tcp->flags & TCB_GROUP_EXITING) {
2711 if (handle_group_exit(tcp, 0) < 0)
2712 return -1;
2713 continue;
2714 }
2715#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002716 if (tcp->flags & TCB_ATTACHED)
2717 detach(tcp, 0);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002718 else if (ptrace_restart(PTRACE_CONT, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002719 cleanup();
2720 return -1;
2721 }
2722 continue;
2723 }
2724 if (tcp->flags & TCB_SUSPENDED) {
2725 if (!qflag)
2726 fprintf(stderr, "Process %u suspended\n", pid);
2727 continue;
2728 }
2729 tracing:
Andreas Schwabccdff482009-10-27 16:27:13 +01002730 /* Remember current print column before continuing. */
2731 tcp->curcol = curcol;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002732 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002733 cleanup();
2734 return -1;
2735 }
2736 }
2737 return 0;
2738}
2739
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002740#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002741
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002742#include <stdarg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002743
2744void
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002745tprintf(const char *fmt, ...)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002746{
2747 va_list args;
2748
Andreas Schwabe5355de2009-10-27 16:56:43 +01002749 va_start(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002750 if (outf) {
2751 int n = vfprintf(outf, fmt, args);
Andreas Schwabccdff482009-10-27 16:27:13 +01002752 if (n < 0) {
2753 if (outf != stderr)
2754 perror(outfname == NULL
2755 ? "<writing to pipe>" : outfname);
2756 } else
Roland McGrathb310a0c2003-11-06 23:41:22 +00002757 curcol += n;
2758 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002759 va_end(args);
2760 return;
2761}
2762
2763void
Roland McGratheb9e2e82009-06-02 16:49:22 -07002764printleader(tcp)
2765struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002766{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002767 if (tcp_last) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002768 if (tcp_last->ptrace_errno) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002769 if (tcp_last->flags & TCB_INSYSCALL) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07002770 tprintf(" <unavailable>)");
2771 tabto(acolumn);
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002772 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07002773 tprintf("= ? <unavailable>\n");
2774 tcp_last->ptrace_errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002775 } else if (!outfname || followfork < 2 || tcp_last == tcp) {
Denys Vlasenko7e0615f2009-01-28 19:00:54 +00002776 tcp_last->flags |= TCB_REPRINT;
Roland McGratheb9e2e82009-06-02 16:49:22 -07002777 tprintf(" <unfinished ...>\n");
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002778 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002779 }
2780 curcol = 0;
2781 if ((followfork == 1 || pflag_seen > 1) && outfname)
2782 tprintf("%-5d ", tcp->pid);
2783 else if (nprocs > 1 && !outfname)
2784 tprintf("[pid %5u] ", tcp->pid);
2785 if (tflag) {
2786 char str[sizeof("HH:MM:SS")];
2787 struct timeval tv, dtv;
2788 static struct timeval otv;
2789
2790 gettimeofday(&tv, NULL);
2791 if (rflag) {
2792 if (otv.tv_sec == 0)
2793 otv = tv;
2794 tv_sub(&dtv, &tv, &otv);
2795 tprintf("%6ld.%06ld ",
2796 (long) dtv.tv_sec, (long) dtv.tv_usec);
2797 otv = tv;
2798 }
2799 else if (tflag > 2) {
2800 tprintf("%ld.%06ld ",
2801 (long) tv.tv_sec, (long) tv.tv_usec);
2802 }
2803 else {
2804 time_t local = tv.tv_sec;
2805 strftime(str, sizeof(str), "%T", localtime(&local));
2806 if (tflag > 1)
2807 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2808 else
2809 tprintf("%s ", str);
2810 }
2811 }
2812 if (iflag)
2813 printcall(tcp);
2814}
2815
2816void
2817tabto(col)
2818int col;
2819{
2820 if (curcol < col)
2821 tprintf("%*s", col - curcol, "");
2822}
2823
2824void
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002825printtrailer(void)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002826{
2827 tprintf("\n");
2828 tcp_last = NULL;
2829}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002830
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002831#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002832
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002833int
2834mp_ioctl(int fd, int cmd, void *arg, int size)
2835{
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002836 struct iovec iov[2];
2837 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002838
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002839 iov[0].iov_base = &cmd;
2840 iov[0].iov_len = sizeof cmd;
2841 if (arg) {
2842 ++n;
2843 iov[1].iov_base = arg;
2844 iov[1].iov_len = size;
2845 }
Roland McGrath553a6092002-12-16 20:40:39 +00002846
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +00002847 return writev(fd, iov, n);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002848}
2849
2850#endif