blob: 5e3b8757e6821033d875b5b835a846f2f3878f0d [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
Wichert Akkerman7b3346b2001-10-09 23:47:38 +000049#if defined(IA64) && defined(LINUX)
50# include <asm/ptrace_offsets.h>
51#endif
52
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +000053#ifdef USE_PROCFS
54#include <poll.h>
55#endif
56
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000057#ifdef SVR4
58#include <sys/stropts.h>
Wichert Akkermanea78f0f1999-11-29 15:34:02 +000059#ifdef HAVE_MP_PROCFS
John Hughes1d08dcf2001-07-10 13:48:44 +000060#ifdef HAVE_SYS_UIO_H
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000061#include <sys/uio.h>
62#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000063#endif
John Hughes1d08dcf2001-07-10 13:48:44 +000064#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000065
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +000066int debug = 0, followfork = 0, followvfork = 0;
67int dtime = 0, cflag = 0, xflag = 0, qflag = 0;
68static int iflag = 0, interactive = 0, pflag_seen = 0, rflag = 0, tflag = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000069
Michal Ludvig17f8fb32002-11-06 13:17:21 +000070/* Sometimes we want to print only succeeding syscalls. */
71int not_failing_only = 0;
72
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +000073static char *username = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000074uid_t run_uid;
75gid_t run_gid;
76
77int acolumn = DEFAULT_ACOLUMN;
78int max_strlen = DEFAULT_STRLEN;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +000079static char *outfname = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000080FILE *outf;
Roland McGrathee9d4352002-12-18 04:16:10 +000081struct tcb **tcbtab;
82unsigned int nprocs, tcbtabsize;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000083char *progname;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000084extern char **environ;
85
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000086static int trace P((void));
87static void cleanup P((void));
88static void interrupt P((int sig));
89static sigset_t empty_set, blocked_set;
90
91#ifdef HAVE_SIG_ATOMIC_T
92static volatile sig_atomic_t interrupted;
93#else /* !HAVE_SIG_ATOMIC_T */
94#ifdef __STDC__
95static volatile int interrupted;
96#else /* !__STDC__ */
97static int interrupted;
98#endif /* !__STDC__ */
99#endif /* !HAVE_SIG_ATOMIC_T */
100
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000101#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000102
103static struct tcb *pfd2tcb P((int pfd));
104static void reaper P((int sig));
105static void rebuild_pollv P((void));
Roland McGrathee9d4352002-12-18 04:16:10 +0000106static struct pollfd *pollv;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000107
108#ifndef HAVE_POLLABLE_PROCFS
109
110static void proc_poll_open P((void));
111static void proc_poller P((int pfd));
112
113struct proc_pollfd {
114 int fd;
115 int revents;
116 int pid;
117};
118
119static int poller_pid;
120static int proc_poll_pipe[2] = { -1, -1 };
121
122#endif /* !HAVE_POLLABLE_PROCFS */
123
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000124#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000125#define POLLWANT POLLWRNORM
126#else
127#define POLLWANT POLLPRI
128#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000129#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000130
131static void
132usage(ofp, exitval)
133FILE *ofp;
134int exitval;
135{
136 fprintf(ofp, "\
137usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000138 [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n\
139 [command [arg ...]]\n\
140 or: strace -c [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n\
141 [command [arg ...]]\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000142-c -- count time, calls, and errors for each syscall and report summary\n\
143-f -- follow forks, -ff -- with output into separate files\n\
144-F -- attempt to follow vforks, -h -- print help message\n\
145-i -- print instruction pointer at time of syscall\n\
146-q -- suppress messages about attaching, detaching, etc.\n\
147-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
148-T -- print time spent in each syscall, -V -- print version\n\
149-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
150-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
151-a column -- alignment COLUMN for printing syscall results (default %d)\n\
152-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
153 options: trace, abbrev, verbose, raw, signal, read, or write\n\
154-o file -- send trace output to FILE instead of stderr\n\
155-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
156-p pid -- trace process with process id PID, may be repeated\n\
157-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
158-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
159-u username -- run command as username handling setuid and/or setgid\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000160-E var=val -- put var=val in the environment for command\n\
161-E var -- remove var from the environment for command\n\
162" /* this is broken, so don't document it
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000163-z -- print only succeeding syscalls\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000164 */
165, DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000166 exit(exitval);
167}
168
169#ifdef SVR4
170#ifdef MIPS
171void
172foobar()
173{
174}
175#endif /* MIPS */
176#endif /* SVR4 */
177
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000178static int
179set_cloexec_flag(int fd)
180{
181 int flags, newflags;
182
183 if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
184 {
185 fprintf(stderr, "%s: fcntl F_GETFD: %s\n",
186 progname, strerror(errno));
187 return -1;
188 }
189
190 newflags = flags | FD_CLOEXEC;
191 if (flags == newflags)
192 return 0;
193
194 if (fcntl(fd, F_SETFD, newflags) < 0)
195 {
196 fprintf(stderr, "%s: fcntl F_SETFD: %s\n",
197 progname, strerror(errno));
198 return -1;
199 }
200
201 return 0;
202}
203
204/*
205 * When strace is setuid executable, we have to swap uids
206 * before and after filesystem and process management operations.
207 */
208static void
209swap_uid(void)
210{
211#ifndef SVR4
212 int euid = geteuid(), uid = getuid();
213
214 if (euid != uid && setreuid(euid, uid) < 0)
215 {
216 fprintf(stderr, "%s: setreuid: %s\n",
217 progname, strerror(errno));
218 exit(1);
219 }
220#endif
221}
222
223static FILE *
224strace_fopen(const char *path, const char *mode)
225{
226 FILE *fp;
227
228 swap_uid();
229 if ((fp = fopen(path, mode)) == NULL)
230 fprintf(stderr, "%s: can't fopen '%s': %s\n",
231 progname, path, strerror(errno));
232 swap_uid();
233 if (fp && set_cloexec_flag(fileno(fp)) < 0)
234 {
235 fclose(fp);
236 fp = NULL;
237 }
238 return fp;
239}
240
241static int popen_pid = -1;
242
243#ifndef _PATH_BSHELL
244# define _PATH_BSHELL "/bin/sh"
245#endif
246
247/*
248 * We cannot use standard popen(3) here because we have to distinguish
249 * popen child process from other processes we trace, and standard popen(3)
250 * does not export its child's pid.
251 */
252static FILE *
253strace_popen(const char *command)
254{
255 int fds[2];
256
257 swap_uid();
258 if (pipe(fds) < 0)
259 {
260 fprintf(stderr, "%s: pipe: %s\n",
261 progname, strerror(errno));
262 swap_uid();
263 return NULL;
264 }
265
266 if (set_cloexec_flag(fds[1]) < 0)
267 {
268 close(fds[0]);
269 close(fds[1]);
270 swap_uid();
271 return NULL;
272 }
273
274 if ((popen_pid = fork()) == -1)
275 {
276 fprintf(stderr, "%s: fork: %s\n",
277 progname, strerror(errno));
278 close(fds[0]);
279 close(fds[1]);
280 swap_uid();
281 return NULL;
282 }
283
284 if (popen_pid)
285 {
286 /* parent */
287 close(fds[0]);
288 swap_uid();
289 return fdopen(fds[1], "w");
290 } else
291 {
292 /* child */
293 close(fds[1]);
294 if (fds[0] && (dup2(fds[0], 0) || close(fds[0])))
295 {
296 fprintf(stderr, "%s: dup2: %s\n",
297 progname, strerror(errno));
298 _exit(1);
299 }
300 execl(_PATH_BSHELL, "sh", "-c", command, NULL);
301 fprintf(stderr, "%s: execl: %s: %s\n",
302 progname, _PATH_BSHELL, strerror(errno));
303 _exit(1);
304 }
305}
306
307static int
308newoutf(struct tcb *tcp)
309{
310 if (outfname && followfork > 1) {
311 char name[MAXPATHLEN];
312 FILE *fp;
313
314 sprintf(name, "%s.%u", outfname, tcp->pid);
315 if ((fp = strace_fopen(name, "w")) == NULL)
316 return -1;
317 tcp->outf = fp;
318 }
319 return 0;
320}
321
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000322int
323main(argc, argv)
324int argc;
325char *argv[];
326{
327 extern int optind;
328 extern char *optarg;
329 struct tcb *tcp;
330 int c, pid = 0;
331 struct sigaction sa;
332
333 static char buf[BUFSIZ];
334
Roland McGrathee9d4352002-12-18 04:16:10 +0000335 /* Allocate the initial tcbtab. */
336 tcbtabsize = argc; /* Surely enough for all -p args. */
337 tcbtab = (struct tcb **) malloc (tcbtabsize * sizeof tcbtab[0]);
338 tcbtab[0] = (struct tcb *) calloc (tcbtabsize, sizeof *tcbtab[0]);
339 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
340 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
341
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000342 progname = argv[0];
343 outf = stderr;
344 interactive = 1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000345 set_sortby(DEFAULT_SORTBY);
346 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000347 qualify("trace=all");
348 qualify("abbrev=all");
349 qualify("verbose=all");
350 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000351 while ((c = getopt(argc, argv,
Roland McGrathde6e5332003-01-24 04:31:23 +0000352 "+cdfFhiqrtTvVxza:e:o:O:p:s:S:u:E:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000353 switch (c) {
354 case 'c':
355 cflag++;
356 dtime++;
357 break;
358 case 'd':
359 debug++;
360 break;
361 case 'f':
362 followfork++;
363 break;
364 case 'F':
365 followvfork++;
366 break;
367 case 'h':
368 usage(stdout, 0);
369 break;
370 case 'i':
371 iflag++;
372 break;
373 case 'q':
374 qflag++;
375 break;
376 case 'r':
377 rflag++;
378 tflag++;
379 break;
380 case 't':
381 tflag++;
382 break;
383 case 'T':
384 dtime++;
385 break;
386 case 'x':
387 xflag++;
388 break;
389 case 'v':
390 qualify("abbrev=none");
391 break;
392 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +0000393 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000394 exit(0);
395 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000396 case 'z':
397 not_failing_only = 1;
398 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000399 case 'a':
400 acolumn = atoi(optarg);
401 break;
402 case 'e':
403 qualify(optarg);
404 break;
405 case 'o':
406 outfname = strdup(optarg);
407 break;
408 case 'O':
409 set_overhead(atoi(optarg));
410 break;
411 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +0000412 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000413 fprintf(stderr, "%s: Invalid process id: %s\n",
414 progname, optarg);
415 break;
416 }
417 if (pid == getpid()) {
Wichert Akkerman54a47671999-10-17 00:57:34 +0000418 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000419 break;
420 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000421 if ((tcp = alloc_tcb(pid, 0)) == NULL) {
Roland McGrathde6e5332003-01-24 04:31:23 +0000422 fprintf(stderr, "%s: out of memory\n",
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000423 progname);
424 exit(1);
425 }
426 tcp->flags |= TCB_ATTACHED;
427 pflag_seen++;
428 break;
429 case 's':
430 max_strlen = atoi(optarg);
Roland McGrathdccec722005-05-09 07:45:47 +0000431 if (max_strlen < 0) {
432 fprintf(stderr,
433 "%s: invalid -s argument: %s\n",
434 progname, optarg);
435 exit(1);
436 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000437 break;
438 case 'S':
439 set_sortby(optarg);
440 break;
441 case 'u':
442 username = strdup(optarg);
443 break;
Roland McGrathde6e5332003-01-24 04:31:23 +0000444 case 'E':
445 if (putenv(optarg) < 0) {
446 fprintf(stderr, "%s: out of memory\n",
447 progname);
448 exit(1);
449 }
450 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000451 default:
452 usage(stderr, 1);
453 break;
454 }
455 }
456
Roland McGrathd0c4c0c2006-04-25 07:39:40 +0000457 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +0000458 usage(stderr, 1);
459
Roland McGrathcb9def62006-04-25 07:48:03 +0000460 if (followfork > 1 && cflag) {
461 fprintf(stderr,
462 "%s: -c and -ff are mutually exclusive options\n",
463 progname);
464 exit(1);
465 }
466
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000467 /* See if they want to run as another user. */
468 if (username != NULL) {
469 struct passwd *pent;
470
471 if (getuid() != 0 || geteuid() != 0) {
472 fprintf(stderr,
473 "%s: you must be root to use the -u option\n",
474 progname);
475 exit(1);
476 }
477 if ((pent = getpwnam(username)) == NULL) {
478 fprintf(stderr, "%s: cannot find user `%s'\n",
479 progname, optarg);
480 exit(1);
481 }
482 run_uid = pent->pw_uid;
483 run_gid = pent->pw_gid;
484 }
485 else {
486 run_uid = getuid();
487 run_gid = getgid();
488 }
489
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000490 /* Check if they want to redirect the output. */
491 if (outfname) {
Roland McGrath37b9a662003-11-07 02:26:54 +0000492 /* See if they want to pipe the output. */
493 if (outfname[0] == '|' || outfname[0] == '!') {
494 /*
495 * We can't do the <outfname>.PID funny business
496 * when using popen, so prohibit it.
497 */
498 if (followfork > 1) {
499 fprintf(stderr, "\
500%s: piping the output and -ff are mutually exclusive options\n",
501 progname);
502 exit(1);
503 }
504
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000505 if ((outf = strace_popen(outfname + 1)) == NULL)
Roland McGrath37b9a662003-11-07 02:26:54 +0000506 exit(1);
Roland McGrath37b9a662003-11-07 02:26:54 +0000507 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000508 else if (followfork <= 1 &&
509 (outf = strace_fopen(outfname, "w")) == NULL)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000510 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000511 }
512
Roland McGrath37b9a662003-11-07 02:26:54 +0000513 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000514 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +0000515 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000516 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000517 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +0000518 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000519
Roland McGrathee9d4352002-12-18 04:16:10 +0000520 for (c = 0; c < tcbtabsize; c++) {
521 tcp = tcbtab[c];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000522 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
523 continue;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000524#ifdef LINUX
525 if (tcp->flags & TCB_CLONE_THREAD)
526 continue;
527#endif
528 /* Reinitialize the output since it may have changed. */
529 tcp->outf = outf;
530 if (newoutf(tcp) < 0)
531 exit(1);
532
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000533#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000534 if (proc_open(tcp, 1) < 0) {
535 fprintf(stderr, "trouble opening proc file\n");
536 droptcb(tcp);
537 continue;
538 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000539#else /* !USE_PROCFS */
Roland McGrath70b08532004-04-09 00:25:21 +0000540# ifdef LINUX
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000541 if (followfork) {
Roland McGrath70b08532004-04-09 00:25:21 +0000542 char procdir[MAXPATHLEN];
543 DIR *dir;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000544
Roland McGrath70b08532004-04-09 00:25:21 +0000545 sprintf(procdir, "/proc/%d/task", tcp->pid);
546 dir = opendir(procdir);
547 if (dir != NULL) {
548 unsigned int ntid = 0, nerr = 0;
549 struct dirent *de;
550 int tid;
551 while ((de = readdir(dir)) != NULL) {
552 if (de->d_fileno == 0 ||
553 de->d_name[0] == '.')
554 continue;
555 tid = atoi(de->d_name);
556 if (tid <= 0)
557 continue;
558 ++ntid;
559 if (ptrace(PTRACE_ATTACH, tid,
560 (char *) 1, 0) < 0)
561 ++nerr;
562 else if (tid != tcbtab[c]->pid) {
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000563 if (nprocs == tcbtabsize &&
564 expand_tcbtab())
565 tcp = NULL;
566 else
567 tcp = alloctcb(tid);
Dmitry V. Levin76860f62006-10-11 22:55:25 +0000568 if (tcp == NULL)
Roland McGrath70b08532004-04-09 00:25:21 +0000569 exit(1);
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000570 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_CLONE_DETACHED|TCB_FOLLOWFORK;
Roland McGrath70b08532004-04-09 00:25:21 +0000571 tcbtab[c]->nchildren++;
572 tcbtab[c]->nclone_threads++;
573 tcbtab[c]->nclone_detached++;
574 tcp->parent = tcbtab[c];
575 }
576 }
577 closedir(dir);
578 if (nerr == ntid) {
579 perror("attach: ptrace(PTRACE_ATTACH, ...)");
580 droptcb(tcp);
581 continue;
582 }
583 if (!qflag) {
584 ntid -= nerr;
585 if (ntid > 1)
586 fprintf(stderr, "\
587Process %u attached with %u threads - interrupt to quit\n",
588 tcp->pid, ntid);
589 else
590 fprintf(stderr, "\
591Process %u attached - interrupt to quit\n",
592 tcp->pid);
593 }
594 continue;
595 }
596 }
597# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000598 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
599 perror("attach: ptrace(PTRACE_ATTACH, ...)");
600 droptcb(tcp);
601 continue;
602 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000603#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000604 if (!qflag)
605 fprintf(stderr,
606 "Process %u attached - interrupt to quit\n",
Roland McGrathc3266d52004-02-20 02:23:52 +0000607 tcp->pid);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000608 }
609
Roland McGrathce0d1542003-11-11 21:24:23 +0000610 if (!pflag_seen) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000611 struct stat statbuf;
612 char *filename;
613 char pathname[MAXPATHLEN];
614
615 filename = argv[optind];
Roland McGrathbdb09df2004-03-02 06:50:04 +0000616 if (strchr(filename, '/')) {
617 if (strlen(filename) > sizeof pathname - 1) {
618 errno = ENAMETOOLONG;
619 perror("strace: exec");
620 exit(1);
621 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000622 strcpy(pathname, filename);
Roland McGrathbdb09df2004-03-02 06:50:04 +0000623 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000624#ifdef USE_DEBUGGING_EXEC
625 /*
626 * Debuggers customarily check the current directory
627 * first regardless of the path but doing that gives
628 * security geeks a panic attack.
629 */
630 else if (stat(filename, &statbuf) == 0)
631 strcpy(pathname, filename);
632#endif /* USE_DEBUGGING_EXEC */
633 else {
634 char *path;
635 int m, n, len;
636
637 for (path = getenv("PATH"); path && *path; path += m) {
638 if (strchr(path, ':')) {
639 n = strchr(path, ':') - path;
640 m = n + 1;
641 }
642 else
643 m = n = strlen(path);
644 if (n == 0) {
Dmitry V. Levincbd470f2006-10-14 14:23:57 +0000645 if (!getcwd(pathname, MAXPATHLEN))
646 continue;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000647 len = strlen(pathname);
648 }
Roland McGrathbdb09df2004-03-02 06:50:04 +0000649 else if (n > sizeof pathname - 1)
650 continue;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000651 else {
652 strncpy(pathname, path, n);
653 len = n;
654 }
655 if (len && pathname[len - 1] != '/')
656 pathname[len++] = '/';
657 strcpy(pathname + len, filename);
Roland McGrathed645162003-06-03 07:18:19 +0000658 if (stat(pathname, &statbuf) == 0 &&
659 /* Accept only regular files
660 with some execute bits set.
661 XXX not perfect, might still fail */
662 S_ISREG(statbuf.st_mode) &&
663 (statbuf.st_mode & 0111))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000664 break;
665 }
666 }
667 if (stat(pathname, &statbuf) < 0) {
668 fprintf(stderr, "%s: %s: command not found\n",
669 progname, filename);
670 exit(1);
671 }
672 switch (pid = fork()) {
673 case -1:
674 perror("strace: fork");
675 cleanup();
676 exit(1);
677 break;
678 case 0: {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000679#ifdef USE_PROCFS
680 if (outf != stderr) close (fileno (outf));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000681#ifdef MIPS
682 /* Kludge for SGI, see proc_open for details. */
683 sa.sa_handler = foobar;
684 sa.sa_flags = 0;
685 sigemptyset(&sa.sa_mask);
686 sigaction(SIGINT, &sa, NULL);
687#endif /* MIPS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000688#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000689 pause();
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000690#else /* FREEBSD */
691 kill(getpid(), SIGSTOP); /* stop HERE */
Roland McGrath553a6092002-12-16 20:40:39 +0000692#endif /* FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000693#else /* !USE_PROCFS */
Roland McGrath553a6092002-12-16 20:40:39 +0000694 if (outf!=stderr)
Wichert Akkerman7987cdf2000-07-05 16:05:39 +0000695 close(fileno (outf));
Wichert Akkermanbd4125c2000-06-27 17:28:06 +0000696
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000697 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
698 perror("strace: ptrace(PTRACE_TRACEME, ...)");
699 return -1;
700 }
701 if (debug)
702 kill(getpid(), SIGSTOP);
703
704 if (username != NULL || geteuid() == 0) {
705 uid_t run_euid = run_uid;
706 gid_t run_egid = run_gid;
707
708 if (statbuf.st_mode & S_ISUID)
709 run_euid = statbuf.st_uid;
710 if (statbuf.st_mode & S_ISGID)
711 run_egid = statbuf.st_gid;
712
713 /*
714 * It is important to set groups before we
715 * lose privileges on setuid.
716 */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +0000717 if (username != NULL) {
718 if (initgroups(username, run_gid) < 0) {
719 perror("initgroups");
720 exit(1);
721 }
722 if (setregid(run_gid, run_egid) < 0) {
723 perror("setregid");
724 exit(1);
725 }
726 if (setreuid(run_uid, run_euid) < 0) {
727 perror("setreuid");
728 exit(1);
729 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000730 }
731 }
732 else
733 setreuid(run_uid, run_uid);
Roland McGrath15dca8e2005-02-06 01:16:32 +0000734
735 /*
736 * Induce an immediate stop so that the parent
737 * will resume us with PTRACE_SYSCALL and display
738 * this execve call normally.
739 */
740 kill(getpid(), SIGSTOP);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000741#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000742
743 execv(pathname, &argv[optind]);
744 perror("strace: exec");
745 _exit(1);
746 break;
747 }
748 default:
749 if ((tcp = alloctcb(pid)) == NULL) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000750 cleanup();
751 exit(1);
752 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000753#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000754 if (proc_open(tcp, 0) < 0) {
755 fprintf(stderr, "trouble opening proc file\n");
756 cleanup();
757 exit(1);
758 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000759#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000760 break;
761 }
762 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000763
764 sigemptyset(&empty_set);
765 sigemptyset(&blocked_set);
766 sa.sa_handler = SIG_IGN;
767 sigemptyset(&sa.sa_mask);
768 sa.sa_flags = 0;
769 sigaction(SIGTTOU, &sa, NULL);
770 sigaction(SIGTTIN, &sa, NULL);
771 if (interactive) {
772 sigaddset(&blocked_set, SIGHUP);
773 sigaddset(&blocked_set, SIGINT);
774 sigaddset(&blocked_set, SIGQUIT);
775 sigaddset(&blocked_set, SIGPIPE);
776 sigaddset(&blocked_set, SIGTERM);
777 sa.sa_handler = interrupt;
778#ifdef SUNOS4
779 /* POSIX signals on sunos4.1 are a little broken. */
780 sa.sa_flags = SA_INTERRUPT;
781#endif /* SUNOS4 */
782 }
783 sigaction(SIGHUP, &sa, NULL);
784 sigaction(SIGINT, &sa, NULL);
785 sigaction(SIGQUIT, &sa, NULL);
786 sigaction(SIGPIPE, &sa, NULL);
787 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000788#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000789 sa.sa_handler = reaper;
790 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000791#else
792 /* Make sure SIGCHLD has the default action so that waitpid
793 definitely works without losing track of children. The user
794 should not have given us a bogus state to inherit, but he might
795 have. Arguably we should detect SIG_IGN here and pass it on
796 to children, but probably noone really needs that. */
797 sa.sa_handler = SIG_DFL;
798 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000799#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000800
801 if (trace() < 0)
802 exit(1);
803 cleanup();
804 exit(0);
805}
806
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000807int
808expand_tcbtab()
809{
810 /* Allocate some more TCBs and expand the table.
811 We don't want to relocate the TCBs because our
812 callers have pointers and it would be a pain.
813 So tcbtab is a table of pointers. Since we never
814 free the TCBs, we allocate a single chunk of many. */
815 struct tcb **newtab = (struct tcb **)
816 realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
817 struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
818 sizeof *newtcbs);
819 int i;
820 if (newtab == NULL || newtcbs == NULL) {
821 if (newtab != NULL)
822 free(newtab);
Dmitry V. Levin76860f62006-10-11 22:55:25 +0000823 fprintf(stderr, "%s: expand_tcbtab: out of memory\n",
824 progname);
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000825 return 1;
826 }
827 for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
828 newtab[i] = &newtcbs[i - tcbtabsize];
829 tcbtabsize *= 2;
830 tcbtab = newtab;
831
832 return 0;
833}
834
835
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000836struct tcb *
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000837alloc_tcb(int pid, int command_options_parsed)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000838{
839 int i;
840 struct tcb *tcp;
841
Roland McGrathee9d4352002-12-18 04:16:10 +0000842 for (i = 0; i < tcbtabsize; i++) {
843 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000844 if ((tcp->flags & TCB_INUSE) == 0) {
845 tcp->pid = pid;
846 tcp->parent = NULL;
847 tcp->nchildren = 0;
Roland McGrath09623452003-05-23 02:27:13 +0000848 tcp->nzombies = 0;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000849#ifdef TCB_CLONE_THREAD
850 tcp->nclone_threads = tcp->nclone_detached = 0;
851 tcp->nclone_waiting = 0;
852#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000853 tcp->flags = TCB_INUSE | TCB_STARTUP;
854 tcp->outf = outf; /* Initialise to current out file */
855 tcp->stime.tv_sec = 0;
856 tcp->stime.tv_usec = 0;
857 tcp->pfd = -1;
858 nprocs++;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000859 if (command_options_parsed)
860 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000861 return tcp;
862 }
863 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000864 fprintf(stderr, "%s: alloc_tcb: tcb table full\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000865 return NULL;
866}
867
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000868#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000869int
870proc_open(tcp, attaching)
871struct tcb *tcp;
872int attaching;
873{
874 char proc[32];
875 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000876#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +0000877 int i;
878 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000879 sigset_t signals;
880 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000881#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000882#ifndef HAVE_POLLABLE_PROCFS
883 static int last_pfd;
884#endif
885
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000886#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000887 /* Open the process pseudo-files in /proc. */
888 sprintf(proc, "/proc/%d/ctl", tcp->pid);
889 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000890 perror("strace: open(\"/proc/...\", ...)");
891 return -1;
892 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000893 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000894 return -1;
895 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000896 sprintf(proc, "/proc/%d/status", tcp->pid);
897 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
898 perror("strace: open(\"/proc/...\", ...)");
899 return -1;
900 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000901 if (set_cloexec_flag(tcp->pfd_stat) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000902 return -1;
903 }
904 sprintf(proc, "/proc/%d/as", tcp->pid);
905 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
906 perror("strace: open(\"/proc/...\", ...)");
907 return -1;
908 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000909 if (set_cloexec_flag(tcp->pfd_as) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000910 return -1;
911 }
912#else
913 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000914#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000915 sprintf(proc, "/proc/%d", tcp->pid);
916 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000917#else /* FREEBSD */
918 sprintf(proc, "/proc/%d/mem", tcp->pid);
919 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
920#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000921 perror("strace: open(\"/proc/...\", ...)");
922 return -1;
923 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000924 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000925 return -1;
926 }
927#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000928#ifdef FREEBSD
929 sprintf(proc, "/proc/%d/regs", tcp->pid);
930 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
931 perror("strace: open(\"/proc/.../regs\", ...)");
932 return -1;
933 }
934 if (cflag) {
935 sprintf(proc, "/proc/%d/status", tcp->pid);
936 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
937 perror("strace: open(\"/proc/.../status\", ...)");
938 return -1;
939 }
940 } else
941 tcp->pfd_status = -1;
942#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000943 rebuild_pollv();
944 if (!attaching) {
945 /*
946 * Wait for the child to pause. Because of a race
947 * condition we have to poll for the event.
948 */
949 for (;;) {
950 if (IOCTL_STATUS (tcp) < 0) {
951 perror("strace: PIOCSTATUS");
952 return -1;
953 }
954 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000955 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000956 }
957 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000958#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000959 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000960 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000961 perror("strace: PIOCSTOP");
962 return -1;
963 }
Roland McGrath553a6092002-12-16 20:40:39 +0000964#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000965#ifdef PIOCSET
966 /* Set Run-on-Last-Close. */
967 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000968 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000969 perror("PIOCSET PR_RLC");
970 return -1;
971 }
972 /* Set or Reset Inherit-on-Fork. */
973 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000974 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000975 perror("PIOC{SET,RESET} PR_FORK");
976 return -1;
977 }
978#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +0000979#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000980 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
981 perror("PIOCSRLC");
982 return -1;
983 }
984 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
985 perror("PIOC{S,R}FORK");
986 return -1;
987 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000988#else /* FREEBSD */
989 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
990 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
991 perror("PIOCGFL");
992 return -1;
993 }
994 arg &= ~PF_LINGER;
995 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
996 perror("PIOCSFL");
997 return -1;
998 }
999#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001000#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001001#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +00001002 /* Enable all syscall entries we care about. */
1003 premptyset(&syscalls);
1004 for (i = 1; i < MAX_QUALS; ++i) {
1005 if (i > (sizeof syscalls) * CHAR_BIT) break;
1006 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
1007 }
1008 praddset (&syscalls, SYS_execve);
1009 if (followfork) {
1010 praddset (&syscalls, SYS_fork);
1011#ifdef SYS_forkall
1012 praddset (&syscalls, SYS_forkall);
1013#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001014#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +00001015 praddset (&syscalls, SYS_fork1);
1016#endif
1017#ifdef SYS_rfork1
1018 praddset (&syscalls, SYS_rfork1);
1019#endif
1020#ifdef SYS_rforkall
1021 praddset (&syscalls, SYS_rforkall);
1022#endif
1023 }
1024 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001025 perror("PIOCSENTRY");
1026 return -1;
1027 }
John Hughes19e49982001-10-19 08:59:12 +00001028 /* Enable the syscall exits. */
1029 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001030 perror("PIOSEXIT");
1031 return -1;
1032 }
John Hughes19e49982001-10-19 08:59:12 +00001033 /* Enable signals we care about. */
1034 premptyset(&signals);
1035 for (i = 1; i < MAX_QUALS; ++i) {
1036 if (i > (sizeof signals) * CHAR_BIT) break;
1037 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
1038 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001039 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001040 perror("PIOCSTRACE");
1041 return -1;
1042 }
John Hughes19e49982001-10-19 08:59:12 +00001043 /* Enable faults we care about */
1044 premptyset(&faults);
1045 for (i = 1; i < MAX_QUALS; ++i) {
1046 if (i > (sizeof faults) * CHAR_BIT) break;
1047 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
1048 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001049 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001050 perror("PIOCSFAULT");
1051 return -1;
1052 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001053#else /* FREEBSD */
1054 /* set events flags. */
1055 arg = S_SIG | S_SCE | S_SCX ;
1056 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
1057 perror("PIOCBIS");
1058 return -1;
1059 }
1060#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001061 if (!attaching) {
1062#ifdef MIPS
1063 /*
1064 * The SGI PRSABORT doesn't work for pause() so
1065 * we send it a caught signal to wake it up.
1066 */
1067 kill(tcp->pid, SIGINT);
1068#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +00001069#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001070 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001071 arg = PRSABORT;
1072 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001073 perror("PIOCRUN");
1074 return -1;
1075 }
Roland McGrath553a6092002-12-16 20:40:39 +00001076#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001077#endif /* !MIPS*/
1078#ifdef FREEBSD
1079 /* wake up the child if it received the SIGSTOP */
1080 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001081#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001082 for (;;) {
1083 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001084 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001085 perror("PIOCWSTOP");
1086 return -1;
1087 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001088 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001089 tcp->flags &= ~TCB_INSYSCALL;
1090 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001091 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001092 break;
1093 }
1094 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001095#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001096 arg = 0;
1097 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001098#else /* FREEBSD */
1099 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001100#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001101 perror("PIOCRUN");
1102 return -1;
1103 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001104#ifdef FREEBSD
1105 /* handle the case where we "opened" the child before
1106 it did the kill -STOP */
1107 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1108 tcp->status.PR_WHAT == SIGSTOP)
1109 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001110#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001111 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001112#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001113 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001114#else /* FREEBSD */
1115 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001116 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001117 /* We are attaching to an already running process.
1118 * Try to figure out the state of the process in syscalls,
1119 * to handle the first event well.
1120 * This is done by having a look at the "wchan" property of the
1121 * process, which tells where it is stopped (if it is). */
1122 FILE * status;
1123 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001124
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001125 sprintf(proc, "/proc/%d/status", tcp->pid);
1126 status = fopen(proc, "r");
1127 if (status &&
1128 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1129 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1130 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1131 strcmp(wchan, "stopevent")) {
1132 /* The process is asleep in the middle of a syscall.
1133 Fake the syscall entry event */
1134 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1135 tcp->status.PR_WHY = PR_SYSENTRY;
1136 trace_syscall(tcp);
1137 }
1138 if (status)
1139 fclose(status);
1140 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001141 }
1142#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001143#ifndef HAVE_POLLABLE_PROCFS
1144 if (proc_poll_pipe[0] != -1)
1145 proc_poller(tcp->pfd);
1146 else if (nprocs > 1) {
1147 proc_poll_open();
1148 proc_poller(last_pfd);
1149 proc_poller(tcp->pfd);
1150 }
1151 last_pfd = tcp->pfd;
1152#endif /* !HAVE_POLLABLE_PROCFS */
1153 return 0;
1154}
1155
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001156#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001157
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001158struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001159pid2tcb(pid)
1160int pid;
1161{
1162 int i;
1163 struct tcb *tcp;
1164
Roland McGrathee9d4352002-12-18 04:16:10 +00001165 for (i = 0; i < tcbtabsize; i++) {
1166 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001167 if (pid && tcp->pid != pid)
1168 continue;
1169 if (tcp->flags & TCB_INUSE)
1170 return tcp;
1171 }
1172 return NULL;
1173}
1174
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001175#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001176
1177static struct tcb *
1178pfd2tcb(pfd)
1179int pfd;
1180{
1181 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001182
Roland McGrathca16be82003-01-10 19:55:28 +00001183 for (i = 0; i < tcbtabsize; i++) {
1184 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001185 if (tcp->pfd != pfd)
1186 continue;
1187 if (tcp->flags & TCB_INUSE)
1188 return tcp;
1189 }
1190 return NULL;
1191}
1192
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001193#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001194
1195void
1196droptcb(tcp)
1197struct tcb *tcp;
1198{
1199 if (tcp->pid == 0)
1200 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001201#ifdef TCB_CLONE_THREAD
1202 if (tcp->nclone_threads > 0) {
1203 /* There are other threads left in this process, but this
1204 is the one whose PID represents the whole process.
1205 We need to keep this record around as a zombie until
1206 all the threads die. */
1207 tcp->flags |= TCB_EXITING;
1208 return;
1209 }
1210#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001211 nprocs--;
1212 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001213
Roland McGrathe29341c2003-01-10 20:14:20 +00001214 if (tcp->parent != NULL) {
1215 tcp->parent->nchildren--;
1216#ifdef TCB_CLONE_THREAD
1217 if (tcp->flags & TCB_CLONE_DETACHED)
1218 tcp->parent->nclone_detached--;
1219 if (tcp->flags & TCB_CLONE_THREAD)
1220 tcp->parent->nclone_threads--;
1221#endif
Roland McGrath09623452003-05-23 02:27:13 +00001222#ifdef TCB_CLONE_DETACHED
1223 if (!(tcp->flags & TCB_CLONE_DETACHED))
1224#endif
1225 tcp->parent->nzombies++;
Roland McGrathe29341c2003-01-10 20:14:20 +00001226 tcp->parent = NULL;
1227 }
1228
1229 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001230 if (tcp->pfd != -1) {
1231 close(tcp->pfd);
1232 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001233#ifdef FREEBSD
1234 if (tcp->pfd_reg != -1) {
1235 close(tcp->pfd_reg);
1236 tcp->pfd_reg = -1;
1237 }
1238 if (tcp->pfd_status != -1) {
1239 close(tcp->pfd_status);
1240 tcp->pfd_status = -1;
1241 }
Roland McGrath553a6092002-12-16 20:40:39 +00001242#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001243#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001244 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001245#endif
1246 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001247
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001248 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001249 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001250
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001251 tcp->outf = 0;
1252}
1253
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001254#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001255
1256static int
1257resume(tcp)
1258struct tcb *tcp;
1259{
1260 if (tcp == NULL)
1261 return -1;
1262
1263 if (!(tcp->flags & TCB_SUSPENDED)) {
1264 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1265 return -1;
1266 }
1267 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001268#ifdef TCB_CLONE_THREAD
1269 if (tcp->flags & TCB_CLONE_THREAD)
1270 tcp->parent->nclone_waiting--;
1271#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001272
1273 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
1274 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
1275 return -1;
1276 }
1277
1278 if (!qflag)
1279 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1280 return 0;
1281}
1282
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001283#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001284
1285/* detach traced process; continue with sig */
1286
1287static int
1288detach(tcp, sig)
1289struct tcb *tcp;
1290int sig;
1291{
1292 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001293#ifdef LINUX
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001294 int status, resumed;
Roland McGratha08a97e2005-08-03 11:23:46 +00001295 struct tcb *zombie = NULL;
1296
1297 /* If the group leader is lingering only because of this other
1298 thread now dying, then detach the leader as well. */
1299 if ((tcp->flags & TCB_CLONE_THREAD) &&
1300 tcp->parent->nclone_threads == 1 &&
1301 (tcp->parent->flags & TCB_EXITING))
1302 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001303#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001304
1305 if (tcp->flags & TCB_BPTSET)
1306 sig = SIGKILL;
1307
1308#ifdef LINUX
1309 /*
1310 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001311 * before detaching. Arghh. We go through hoops
1312 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001313 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001314#if defined(SPARC)
1315#undef PTRACE_DETACH
1316#define PTRACE_DETACH PTRACE_SUNDETACH
1317#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001318 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1319 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001320 }
1321 else if (errno != ESRCH) {
1322 /* Shouldn't happen. */
1323 perror("detach: ptrace(PTRACE_DETACH, ...)");
1324 }
1325 else if (kill(tcp->pid, 0) < 0) {
1326 if (errno != ESRCH)
1327 perror("detach: checking sanity");
1328 }
1329 else if (kill(tcp->pid, SIGSTOP) < 0) {
1330 if (errno != ESRCH)
1331 perror("detach: stopping child");
1332 }
1333 else {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001334 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001335#ifdef __WALL
1336 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1337 if (errno == ECHILD) /* Already gone. */
1338 break;
1339 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001340 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001341 break;
1342 }
1343#endif /* __WALL */
1344 /* No __WALL here. */
1345 if (waitpid(tcp->pid, &status, 0) < 0) {
1346 if (errno != ECHILD) {
1347 perror("detach: waiting");
1348 break;
1349 }
1350#ifdef __WCLONE
1351 /* If no processes, try clones. */
1352 if (wait4(tcp->pid, &status, __WCLONE,
1353 NULL) < 0) {
1354 if (errno != ECHILD)
1355 perror("detach: waiting");
1356 break;
1357 }
1358#endif /* __WCLONE */
1359 }
1360#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001361 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001362#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001363 if (!WIFSTOPPED(status)) {
1364 /* Au revoir, mon ami. */
1365 break;
1366 }
1367 if (WSTOPSIG(status) == SIGSTOP) {
1368 if ((error = ptrace(PTRACE_DETACH,
Roland McGrath7bf10472002-12-16 20:42:50 +00001369 tcp->pid, (char *) 1, sig)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001370 if (errno != ESRCH)
1371 perror("detach: ptrace(PTRACE_DETACH, ...)");
1372 /* I died trying. */
1373 }
1374 break;
1375 }
1376 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
Roland McGrath7bf10472002-12-16 20:42:50 +00001377 WSTOPSIG(status) == SIGTRAP ?
1378 0 : WSTOPSIG(status))) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001379 if (errno != ESRCH)
1380 perror("detach: ptrace(PTRACE_CONT, ...)");
1381 break;
1382 }
1383 }
1384 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001385#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001386
1387#if defined(SUNOS4)
1388 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1389 if (sig && kill(tcp->pid, sig) < 0)
1390 perror("detach: kill");
1391 sig = 0;
1392 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1393 perror("detach: ptrace(PTRACE_DETACH, ...)");
1394#endif /* SUNOS4 */
1395
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001396#ifndef USE_PROCFS
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001397 resumed = 0;
1398
1399 /* XXX This won't always be quite right (but it never was).
1400 A waiter with argument 0 or < -1 is waiting for any pid in
1401 a particular pgrp, which this child might or might not be
1402 in. The waiter will only wake up if it's argument is -1
1403 or if it's waiting for tcp->pid's pgrp. It makes a
1404 difference to wake up a waiter when there might be more
1405 traced children, because it could get a false ECHILD
1406 error. OTOH, if this was the last child in the pgrp, then
1407 it ought to wake up and get ECHILD. We would have to
1408 search the system for all pid's in the pgrp to be sure.
1409
1410 && (t->waitpid == -1 ||
1411 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1412 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1413 */
1414
1415 if (tcp->parent &&
1416 (tcp->parent->flags & TCB_SUSPENDED) &&
1417 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1418 error = resume(tcp->parent);
1419 ++resumed;
1420 }
1421#ifdef TCB_CLONE_THREAD
1422 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1423 /* Some other threads of our parent are waiting too. */
1424 unsigned int i;
1425
1426 /* Resume all the threads that were waiting for this PID. */
1427 for (i = 0; i < tcbtabsize; i++) {
1428 struct tcb *t = tcbtab[i];
1429 if (t->parent == tcp->parent && t != tcp
1430 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1431 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1432 && t->waitpid == tcp->pid) {
1433 error |= resume (t);
1434 ++resumed;
1435 }
1436 }
1437 if (resumed == 0)
1438 /* Noone was waiting for this PID in particular,
1439 so now we might need to resume some wildcarders. */
1440 for (i = 0; i < tcbtabsize; i++) {
1441 struct tcb *t = tcbtab[i];
1442 if (t->parent == tcp->parent && t != tcp
1443 && ((t->flags
1444 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1445 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1446 && t->waitpid <= 0
1447 ) {
1448 error |= resume (t);
1449 break;
1450 }
1451 }
1452 }
1453#endif
1454
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001455#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001456
1457 if (!qflag)
1458 fprintf(stderr, "Process %u detached\n", tcp->pid);
1459
1460 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001461
1462#ifdef LINUX
1463 if (zombie != NULL)
1464 error = detach(zombie) || error;
1465#endif
1466
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001467 return error;
1468}
1469
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001470#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001471
1472static void
1473reaper(sig)
1474int sig;
1475{
1476 int pid;
1477 int status;
1478
1479 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1480#if 0
1481 struct tcb *tcp;
1482
1483 tcp = pid2tcb(pid);
1484 if (tcp)
1485 droptcb(tcp);
1486#endif
1487 }
1488}
1489
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001490#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001491
1492static void
1493cleanup()
1494{
1495 int i;
1496 struct tcb *tcp;
1497
Roland McGrathee9d4352002-12-18 04:16:10 +00001498 for (i = 0; i < tcbtabsize; i++) {
1499 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001500 if (!(tcp->flags & TCB_INUSE))
1501 continue;
1502 if (debug)
1503 fprintf(stderr,
1504 "cleanup: looking at pid %u\n", tcp->pid);
1505 if (tcp_last &&
1506 (!outfname || followfork < 2 || tcp_last == tcp)) {
1507 tprintf(" <unfinished ...>\n");
1508 tcp_last = NULL;
1509 }
1510 if (tcp->flags & TCB_ATTACHED)
1511 detach(tcp, 0);
1512 else {
1513 kill(tcp->pid, SIGCONT);
1514 kill(tcp->pid, SIGTERM);
1515 }
1516 }
1517 if (cflag)
1518 call_summary(outf);
1519}
1520
1521static void
1522interrupt(sig)
1523int sig;
1524{
1525 interrupted = 1;
1526}
1527
1528#ifndef HAVE_STRERROR
1529
Roland McGrath6d2b3492002-12-30 00:51:30 +00001530#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001531extern int sys_nerr;
1532extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001533#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001534
1535const char *
1536strerror(errno)
1537int errno;
1538{
1539 static char buf[64];
1540
1541 if (errno < 1 || errno >= sys_nerr) {
1542 sprintf(buf, "Unknown error %d", errno);
1543 return buf;
1544 }
1545 return sys_errlist[errno];
1546}
1547
1548#endif /* HAVE_STERRROR */
1549
1550#ifndef HAVE_STRSIGNAL
1551
Roland McGrath8f474e02003-01-14 07:53:33 +00001552#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001553extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001554#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001555#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1556extern char *_sys_siglist[];
1557#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001558
1559const char *
1560strsignal(sig)
1561int sig;
1562{
1563 static char buf[64];
1564
1565 if (sig < 1 || sig >= NSIG) {
1566 sprintf(buf, "Unknown signal %d", sig);
1567 return buf;
1568 }
1569#ifdef HAVE__SYS_SIGLIST
1570 return _sys_siglist[sig];
1571#else
1572 return sys_siglist[sig];
1573#endif
1574}
1575
1576#endif /* HAVE_STRSIGNAL */
1577
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001578#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001579
1580static void
1581rebuild_pollv()
1582{
1583 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001584
Roland McGrathee9d4352002-12-18 04:16:10 +00001585 if (pollv != NULL)
1586 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001587 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001588 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001589 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00001590 exit(1);
1591 }
1592
Roland McGrathca16be82003-01-10 19:55:28 +00001593 for (i = j = 0; i < tcbtabsize; i++) {
1594 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001595 if (!(tcp->flags & TCB_INUSE))
1596 continue;
1597 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001598 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001599 j++;
1600 }
1601 if (j != nprocs) {
1602 fprintf(stderr, "strace: proc miscount\n");
1603 exit(1);
1604 }
1605}
1606
1607#ifndef HAVE_POLLABLE_PROCFS
1608
1609static void
1610proc_poll_open()
1611{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001612 int i;
1613
1614 if (pipe(proc_poll_pipe) < 0) {
1615 perror("pipe");
1616 exit(1);
1617 }
1618 for (i = 0; i < 2; i++) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001619 if (set_cloexec_flag(proc_poll_pipe[i]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001620 exit(1);
1621 }
1622 }
1623}
1624
1625static int
1626proc_poll(pollv, nfds, timeout)
1627struct pollfd *pollv;
1628int nfds;
1629int timeout;
1630{
1631 int i;
1632 int n;
1633 struct proc_pollfd pollinfo;
1634
1635 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1636 return n;
1637 if (n != sizeof(struct proc_pollfd)) {
1638 fprintf(stderr, "panic: short read: %d\n", n);
1639 exit(1);
1640 }
1641 for (i = 0; i < nprocs; i++) {
1642 if (pollv[i].fd == pollinfo.fd)
1643 pollv[i].revents = pollinfo.revents;
1644 else
1645 pollv[i].revents = 0;
1646 }
1647 poller_pid = pollinfo.pid;
1648 return 1;
1649}
1650
1651static void
1652wakeup_handler(sig)
1653int sig;
1654{
1655}
1656
1657static void
1658proc_poller(pfd)
1659int pfd;
1660{
1661 struct proc_pollfd pollinfo;
1662 struct sigaction sa;
1663 sigset_t blocked_set, empty_set;
1664 int i;
1665 int n;
1666 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001667#ifdef FREEBSD
1668 struct procfs_status pfs;
1669#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001670
1671 switch (fork()) {
1672 case -1:
1673 perror("fork");
1674 _exit(0);
1675 case 0:
1676 break;
1677 default:
1678 return;
1679 }
1680
1681 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1682 sa.sa_flags = 0;
1683 sigemptyset(&sa.sa_mask);
1684 sigaction(SIGHUP, &sa, NULL);
1685 sigaction(SIGINT, &sa, NULL);
1686 sigaction(SIGQUIT, &sa, NULL);
1687 sigaction(SIGPIPE, &sa, NULL);
1688 sigaction(SIGTERM, &sa, NULL);
1689 sa.sa_handler = wakeup_handler;
1690 sigaction(SIGUSR1, &sa, NULL);
1691 sigemptyset(&blocked_set);
1692 sigaddset(&blocked_set, SIGUSR1);
1693 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1694 sigemptyset(&empty_set);
1695
1696 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1697 perror("getrlimit(RLIMIT_NOFILE, ...)");
1698 _exit(0);
1699 }
1700 n = rl.rlim_cur;
1701 for (i = 0; i < n; i++) {
1702 if (i != pfd && i != proc_poll_pipe[1])
1703 close(i);
1704 }
1705
1706 pollinfo.fd = pfd;
1707 pollinfo.pid = getpid();
1708 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001709#ifndef FREEBSD
1710 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1711#else /* FREEBSD */
1712 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1713#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001714 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001715 switch (errno) {
1716 case EINTR:
1717 continue;
1718 case EBADF:
1719 pollinfo.revents = POLLERR;
1720 break;
1721 case ENOENT:
1722 pollinfo.revents = POLLHUP;
1723 break;
1724 default:
1725 perror("proc_poller: PIOCWSTOP");
1726 }
1727 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1728 _exit(0);
1729 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001730 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001731 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1732 sigsuspend(&empty_set);
1733 }
1734}
1735
1736#endif /* !HAVE_POLLABLE_PROCFS */
1737
1738static int
1739choose_pfd()
1740{
1741 int i, j;
1742 struct tcb *tcp;
1743
1744 static int last;
1745
1746 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001747 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001748 /*
1749 * The previous process is ready to run again. We'll
1750 * let it do so if it is currently in a syscall. This
1751 * heuristic improves the readability of the trace.
1752 */
1753 tcp = pfd2tcb(pollv[last].fd);
1754 if (tcp && (tcp->flags & TCB_INSYSCALL))
1755 return pollv[last].fd;
1756 }
1757
1758 for (i = 0; i < nprocs; i++) {
1759 /* Let competing children run round robin. */
1760 j = (i + last + 1) % nprocs;
1761 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1762 tcp = pfd2tcb(pollv[j].fd);
1763 if (!tcp) {
1764 fprintf(stderr, "strace: lost proc\n");
1765 exit(1);
1766 }
1767 droptcb(tcp);
1768 return -1;
1769 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001770 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001771 last = j;
1772 return pollv[j].fd;
1773 }
1774 }
1775 fprintf(stderr, "strace: nothing ready\n");
1776 exit(1);
1777}
1778
1779static int
1780trace()
1781{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001782#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001783 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001784#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001785 struct tcb *tcp;
1786 int pfd;
1787 int what;
1788 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001789 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001790
1791 for (;;) {
1792 if (interactive)
1793 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1794
1795 if (nprocs == 0)
1796 break;
1797
1798 switch (nprocs) {
1799 case 1:
1800#ifndef HAVE_POLLABLE_PROCFS
1801 if (proc_poll_pipe[0] == -1) {
1802#endif
1803 tcp = pid2tcb(0);
1804 if (!tcp)
1805 continue;
1806 pfd = tcp->pfd;
1807 if (pfd == -1)
1808 continue;
1809 break;
1810#ifndef HAVE_POLLABLE_PROCFS
1811 }
1812 /* fall through ... */
1813#endif /* !HAVE_POLLABLE_PROCFS */
1814 default:
1815#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001816#ifdef POLL_HACK
1817 /* On some systems (e.g. UnixWare) we get too much ugly
1818 "unfinished..." stuff when multiple proceses are in
1819 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001820
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001821 if (in_syscall) {
1822 struct pollfd pv;
1823 tcp = in_syscall;
1824 in_syscall = NULL;
1825 pv.fd = tcp->pfd;
1826 pv.events = POLLWANT;
1827 if ((what = poll (&pv, 1, 1)) < 0) {
1828 if (interrupted)
1829 return 0;
1830 continue;
1831 }
1832 else if (what == 1 && pv.revents & POLLWANT) {
1833 goto FOUND;
1834 }
1835 }
1836#endif
1837
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001838 if (poll(pollv, nprocs, INFTIM) < 0) {
1839 if (interrupted)
1840 return 0;
1841 continue;
1842 }
1843#else /* !HAVE_POLLABLE_PROCFS */
1844 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1845 if (interrupted)
1846 return 0;
1847 continue;
1848 }
1849#endif /* !HAVE_POLLABLE_PROCFS */
1850 pfd = choose_pfd();
1851 if (pfd == -1)
1852 continue;
1853 break;
1854 }
1855
1856 /* Look up `pfd' in our table. */
1857 if ((tcp = pfd2tcb(pfd)) == NULL) {
1858 fprintf(stderr, "unknown pfd: %u\n", pfd);
1859 exit(1);
1860 }
John Hughesb6643082002-05-23 11:02:22 +00001861#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001862 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001863#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001864 /* Get the status of the process. */
1865 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001866#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001867 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001868#else /* FREEBSD */
1869 /* Thanks to some scheduling mystery, the first poller
1870 sometimes waits for the already processed end of fork
1871 event. Doing a non blocking poll here solves the problem. */
1872 if (proc_poll_pipe[0] != -1)
1873 ioctl_result = IOCTL_STATUS (tcp);
1874 else
1875 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00001876#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001877 ioctl_errno = errno;
1878#ifndef HAVE_POLLABLE_PROCFS
1879 if (proc_poll_pipe[0] != -1) {
1880 if (ioctl_result < 0)
1881 kill(poller_pid, SIGKILL);
1882 else
1883 kill(poller_pid, SIGUSR1);
1884 }
1885#endif /* !HAVE_POLLABLE_PROCFS */
1886 }
1887 if (interrupted)
1888 return 0;
1889
1890 if (interactive)
1891 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1892
1893 if (ioctl_result < 0) {
1894 /* Find out what happened if it failed. */
1895 switch (ioctl_errno) {
1896 case EINTR:
1897 case EBADF:
1898 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001899#ifdef FREEBSD
1900 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00001901#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001902 case ENOENT:
1903 droptcb(tcp);
1904 continue;
1905 default:
1906 perror("PIOCWSTOP");
1907 exit(1);
1908 }
1909 }
1910
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001911#ifdef FREEBSD
1912 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1913 /* discard first event for a syscall we never entered */
1914 IOCTL (tcp->pfd, PIOCRUN, 0);
1915 continue;
1916 }
Roland McGrath553a6092002-12-16 20:40:39 +00001917#endif
1918
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001919 /* clear the just started flag */
1920 tcp->flags &= ~TCB_STARTUP;
1921
1922 /* set current output file */
1923 outf = tcp->outf;
1924
1925 if (cflag) {
1926 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001927#ifdef FREEBSD
1928 char buf[1024];
1929 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001930
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001931 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1932 buf[len] = '\0';
1933 sscanf(buf,
1934 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1935 &stime.tv_sec, &stime.tv_usec);
1936 } else
1937 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001938#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001939 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1940 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001941#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001942 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1943 tcp->stime = stime;
1944 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001945 what = tcp->status.PR_WHAT;
1946 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001947#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001948 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001949 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1950 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001951 if (trace_syscall(tcp) < 0) {
1952 fprintf(stderr, "syscall trouble\n");
1953 exit(1);
1954 }
1955 }
1956 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001957#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001958 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001959#ifdef POLL_HACK
1960 in_syscall = tcp;
1961#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001962 case PR_SYSEXIT:
1963 if (trace_syscall(tcp) < 0) {
1964 fprintf(stderr, "syscall trouble\n");
1965 exit(1);
1966 }
1967 break;
1968 case PR_SIGNALLED:
1969 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1970 printleader(tcp);
1971 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001972 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001973 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00001974#ifdef PR_INFO
1975 if (tcp->status.PR_INFO.si_signo == what) {
1976 printleader(tcp);
1977 tprintf(" siginfo=");
1978 printsiginfo(&tcp->status.PR_INFO, 1);
1979 printtrailer(tcp);
1980 }
1981#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001982 }
1983 break;
1984 case PR_FAULTED:
1985 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1986 printleader(tcp);
1987 tprintf("=== FAULT %d ===", what);
1988 printtrailer(tcp);
1989 }
1990 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001991#ifdef FREEBSD
1992 case 0: /* handle case we polled for nothing */
1993 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00001994#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001995 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001996 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001997 exit(1);
1998 break;
1999 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002000 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002001#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002002 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00002003#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002004 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00002005#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002006 perror("PIOCRUN");
2007 exit(1);
2008 }
2009 }
2010 return 0;
2011}
2012
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002013#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002014
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002015#ifdef TCB_GROUP_EXITING
2016/* Handle an exit detach or death signal that is taking all the
2017 related clone threads with it. This is called in three circumstances:
2018 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
2019 SIG == 0 Continuing TCP will perform an exit_group syscall.
2020 SIG == other Continuing TCP with SIG will kill the process.
2021*/
2022static int
2023handle_group_exit(struct tcb *tcp, int sig)
2024{
2025 /* We need to locate our records of all the clone threads
2026 related to TCP, either its children or siblings. */
2027 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
2028 ? tcp->parent
2029 : tcp->nclone_detached > 0
2030 ? tcp : NULL);
2031
2032 if (sig < 0) {
Roland McGrath05690952004-10-20 01:00:27 +00002033 if (leader != NULL && leader != tcp &&
2034 !(leader->flags & TCB_GROUP_EXITING))
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002035 fprintf(stderr,
2036 "PANIC: handle_group_exit: %d leader %d\n",
2037 tcp->pid, leader ? leader->pid : -1);
Roland McGratha08a97e2005-08-03 11:23:46 +00002038 detach(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002039 }
2040 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00002041 /* Mark that we are taking the process down. */
2042 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002043 if (tcp->flags & TCB_ATTACHED) {
Roland McGrath00dc13f2004-10-20 02:04:15 +00002044 if (leader != NULL && leader != tcp) {
2045 if (leader->flags & TCB_ATTACHED) {
2046 /* We need to detach the leader so
2047 that the process death will be
2048 reported to its real parent.
2049 But we kill it first to prevent
2050 it doing anything before we kill
2051 the whole process in a moment.
2052 We can use PTRACE_KILL on a
2053 thread that's not already
2054 stopped. Then the value we pass
2055 in PTRACE_DETACH just sets the
2056 death signal reported to the
2057 real parent. */
2058 ptrace(PTRACE_KILL, leader->pid, 0, 0);
2059 if (debug)
2060 fprintf(stderr,
2061 " [%d exit %d kills %d]\n",
2062 tcp->pid, sig, leader->pid);
2063 detach(leader, sig);
2064 }
2065 else
2066 leader->flags |= TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002067 }
2068 detach(tcp, sig);
2069 }
2070 else if (ptrace(PTRACE_CONT, tcp->pid, (char *) 1, sig) < 0) {
2071 perror("strace: ptrace(PTRACE_CONT, ...)");
2072 cleanup();
2073 return -1;
2074 }
2075 else {
Roland McGrath05690952004-10-20 01:00:27 +00002076 if (leader != NULL)
2077 leader->flags |= TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002078 if (leader != NULL && leader != tcp)
2079 droptcb(tcp);
2080 /* The leader will report to us as parent now,
2081 and then we'll get to the SIG==-1 case. */
2082 return 0;
2083 }
2084 }
2085
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002086 return 0;
2087}
2088#endif
2089
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002090static int
2091trace()
2092{
2093 int pid;
2094 int wait_errno;
2095 int status;
2096 struct tcb *tcp;
2097#ifdef LINUX
2098 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002099#ifdef __WALL
2100 static int wait4_options = __WALL;
2101#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002102#endif /* LINUX */
2103
2104 while (nprocs != 0) {
2105 if (interactive)
2106 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2107#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002108#ifdef __WALL
2109 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002110 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002111 /* this kernel does not support __WALL */
2112 wait4_options &= ~__WALL;
2113 errno = 0;
2114 pid = wait4(-1, &status, wait4_options,
2115 cflag ? &ru : NULL);
2116 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002117 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002118 /* most likely a "cloned" process */
2119 pid = wait4(-1, &status, __WCLONE,
2120 cflag ? &ru : NULL);
2121 if (pid == -1) {
2122 fprintf(stderr, "strace: clone wait4 "
2123 "failed: %s\n", strerror(errno));
2124 }
2125 }
2126#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002127 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002128#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002129#endif /* LINUX */
2130#ifdef SUNOS4
2131 pid = wait(&status);
2132#endif /* SUNOS4 */
2133 wait_errno = errno;
2134 if (interactive)
2135 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2136
2137 if (interrupted)
2138 return 0;
2139
2140 if (pid == -1) {
2141 switch (wait_errno) {
2142 case EINTR:
2143 continue;
2144 case ECHILD:
2145 /*
2146 * We would like to verify this case
2147 * but sometimes a race in Solbourne's
2148 * version of SunOS sometimes reports
2149 * ECHILD before sending us SIGCHILD.
2150 */
2151#if 0
2152 if (nprocs == 0)
2153 return 0;
2154 fprintf(stderr, "strace: proc miscount\n");
2155 exit(1);
2156#endif
2157 return 0;
2158 default:
2159 errno = wait_errno;
2160 perror("strace: wait");
2161 return -1;
2162 }
2163 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002164 if (pid == popen_pid) {
2165 if (WIFEXITED(status) || WIFSIGNALED(status))
2166 popen_pid = -1;
2167 continue;
2168 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002169 if (debug)
2170 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2171
2172 /* Look up `pid' in our table. */
2173 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002174#ifdef LINUX
2175 if (followfork || followvfork) {
2176 /* This is needed to go with the CLONE_PTRACE
2177 changes in process.c/util.c: we might see
2178 the child's initial trap before we see the
2179 parent return from the clone syscall.
2180 Leave the child suspended until the parent
2181 returns from its system call. Only then
2182 will we have the association of parent and
2183 child so that we know how to do clearbpt
2184 in the child. */
Dmitry V. Levin76860f62006-10-11 22:55:25 +00002185 if (nprocs == tcbtabsize &&
2186 expand_tcbtab())
2187 tcp = NULL;
2188 else
2189 tcp = alloctcb(pid);
2190 if (tcp == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002191 kill(pid, SIGKILL); /* XXX */
2192 return 0;
2193 }
2194 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002195 if (!qflag)
2196 fprintf(stderr, "\
2197Process %d attached (waiting for parent)\n",
2198 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002199 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002200 else
2201 /* This can happen if a clone call used
2202 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002203#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002204 {
2205 fprintf(stderr, "unknown pid: %u\n", pid);
2206 if (WIFSTOPPED(status))
2207 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2208 exit(1);
2209 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002210 }
2211 /* set current output file */
2212 outf = tcp->outf;
2213 if (cflag) {
2214#ifdef LINUX
2215 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2216 tcp->stime = ru.ru_stime;
2217#endif /* !LINUX */
2218 }
2219
2220 if (tcp->flags & TCB_SUSPENDED) {
2221 /*
2222 * Apparently, doing any ptrace() call on a stopped
2223 * process, provokes the kernel to report the process
2224 * status again on a subsequent wait(), even if the
2225 * process has not been actually restarted.
2226 * Since we have inspected the arguments of suspended
2227 * processes we end up here testing for this case.
2228 */
2229 continue;
2230 }
2231 if (WIFSIGNALED(status)) {
2232 if (!cflag
2233 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2234 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002235 tprintf("+++ killed by %s %s+++",
2236 signame(WTERMSIG(status)),
2237#ifdef WCOREDUMP
2238 WCOREDUMP(status) ? "(core dumped) " :
2239#endif
2240 "");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002241 printtrailer(tcp);
2242 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002243#ifdef TCB_GROUP_EXITING
2244 handle_group_exit(tcp, -1);
2245#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002246 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002247#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002248 continue;
2249 }
2250 if (WIFEXITED(status)) {
2251 if (debug)
2252 fprintf(stderr, "pid %u exited\n", pid);
Roland McGrath05690952004-10-20 01:00:27 +00002253 if ((tcp->flags & TCB_ATTACHED)
2254#ifdef TCB_GROUP_EXITING
2255 && !(tcp->parent && (tcp->parent->flags &
2256 TCB_GROUP_EXITING))
2257#endif
2258 )
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002259 fprintf(stderr,
2260 "PANIC: attached pid %u exited\n",
2261 pid);
Roland McGrath0a396902003-06-10 03:05:53 +00002262 if (tcp == tcp_last) {
2263 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT))
2264 == TCB_INSYSCALL)
2265 tprintf(" <unfinished ... exit status %d>\n",
2266 WEXITSTATUS(status));
2267 tcp_last = NULL;
2268 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002269#ifdef TCB_GROUP_EXITING
2270 handle_group_exit(tcp, -1);
2271#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002272 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002273#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002274 continue;
2275 }
2276 if (!WIFSTOPPED(status)) {
2277 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2278 droptcb(tcp);
2279 continue;
2280 }
2281 if (debug)
2282 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002283 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002284
2285 if (tcp->flags & TCB_STARTUP) {
2286 /*
2287 * This flag is there to keep us in sync.
2288 * Next time this process stops it should
2289 * really be entering a system call.
2290 */
2291 tcp->flags &= ~TCB_STARTUP;
2292 if (tcp->flags & TCB_ATTACHED) {
2293 /*
2294 * Interestingly, the process may stop
2295 * with STOPSIG equal to some other signal
2296 * than SIGSTOP if we happend to attach
2297 * just before the process takes a signal.
2298 */
2299 if (!WIFSTOPPED(status)) {
2300 fprintf(stderr,
2301 "pid %u not stopped\n", pid);
2302 detach(tcp, WSTOPSIG(status));
2303 continue;
2304 }
2305 }
2306 else {
2307#ifdef SUNOS4
2308 /* A child of us stopped at exec */
2309 if (WSTOPSIG(status) == SIGTRAP && followvfork)
2310 fixvfork(tcp);
2311#endif /* SUNOS4 */
2312 }
2313 if (tcp->flags & TCB_BPTSET) {
2314 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2315 droptcb(tcp);
2316 cleanup();
2317 return -1;
2318 }
2319 }
2320 goto tracing;
2321 }
2322
2323 if (WSTOPSIG(status) != SIGTRAP) {
2324 if (WSTOPSIG(status) == SIGSTOP &&
2325 (tcp->flags & TCB_SIGTRAPPED)) {
2326 /*
2327 * Trapped attempt to block SIGTRAP
2328 * Hope we are back in control now.
2329 */
2330 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
2331 if (ptrace(PTRACE_SYSCALL,
2332 pid, (char *) 1, 0) < 0) {
2333 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2334 cleanup();
2335 return -1;
2336 }
2337 continue;
2338 }
2339 if (!cflag
2340 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002341 unsigned long addr = 0, pc = 0;
Dmitry V. Levin96339422006-10-11 23:11:43 +00002342#if defined(PT_CR_IPSR) && defined(PT_CR_IIP) && defined(PT_GETSIGINFO)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002343# define PSR_RI 41
2344 struct siginfo si;
2345 unsigned long psr;
2346
2347 upeek(pid, PT_CR_IPSR, &psr);
2348 upeek(pid, PT_CR_IIP, &pc);
2349
2350 pc += (psr >> PSR_RI) & 0x3;
2351 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2352 addr = (unsigned long) si.si_addr;
Roland McGrath3a055d72005-03-06 22:24:29 +00002353#elif defined PTRACE_GETSIGINFO
2354 if (WSTOPSIG(status) == SIGSEGV ||
2355 WSTOPSIG(status) == SIGBUS) {
2356 siginfo_t si;
2357 if (ptrace(PTRACE_GETSIGINFO, pid,
2358 0, &si) == 0)
2359 addr = (unsigned long)
2360 si.si_addr;
2361 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002362#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002363 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002364 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002365 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002366 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002367 printtrailer(tcp);
2368 }
Roland McGrath05690952004-10-20 01:00:27 +00002369 if (((tcp->flags & TCB_ATTACHED) ||
2370 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002371 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002372#ifdef TCB_GROUP_EXITING
2373 handle_group_exit(tcp, WSTOPSIG(status));
2374#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002375 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002376#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002377 continue;
2378 }
2379 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
2380 WSTOPSIG(status)) < 0) {
2381 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2382 cleanup();
2383 return -1;
2384 }
2385 tcp->flags &= ~TCB_SUSPENDED;
2386 continue;
2387 }
2388 if (trace_syscall(tcp) < 0) {
2389 if (tcp->flags & TCB_ATTACHED)
2390 detach(tcp, 0);
2391 else {
2392 ptrace(PTRACE_KILL,
2393 tcp->pid, (char *) 1, SIGTERM);
2394 droptcb(tcp);
2395 }
2396 continue;
2397 }
2398 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002399#ifdef TCB_GROUP_EXITING
2400 if (tcp->flags & TCB_GROUP_EXITING) {
2401 if (handle_group_exit(tcp, 0) < 0)
2402 return -1;
2403 continue;
2404 }
2405#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002406 if (tcp->flags & TCB_ATTACHED)
2407 detach(tcp, 0);
2408 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
2409 perror("strace: ptrace(PTRACE_CONT, ...)");
2410 cleanup();
2411 return -1;
2412 }
2413 continue;
2414 }
2415 if (tcp->flags & TCB_SUSPENDED) {
2416 if (!qflag)
2417 fprintf(stderr, "Process %u suspended\n", pid);
2418 continue;
2419 }
2420 tracing:
2421 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
2422 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2423 cleanup();
2424 return -1;
2425 }
2426 }
2427 return 0;
2428}
2429
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002430#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002431
2432static int curcol;
2433
2434#ifdef __STDC__
2435#include <stdarg.h>
2436#define VA_START(a, b) va_start(a, b)
2437#else
2438#include <varargs.h>
2439#define VA_START(a, b) va_start(a)
2440#endif
2441
2442void
2443#ifdef __STDC__
2444tprintf(const char *fmt, ...)
2445#else
2446tprintf(fmt, va_alist)
2447char *fmt;
2448va_dcl
2449#endif
2450{
2451 va_list args;
2452
2453 VA_START(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002454 if (outf) {
2455 int n = vfprintf(outf, fmt, args);
2456 if (n < 0 && outf != stderr)
2457 perror(outfname == NULL
2458 ? "<writing to pipe>" : outfname);
2459 else
2460 curcol += n;
2461 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002462 va_end(args);
2463 return;
2464}
2465
2466void
2467printleader(tcp)
2468struct tcb *tcp;
2469{
2470 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
2471 tcp_last->flags |= TCB_REPRINT;
2472 tprintf(" <unfinished ...>\n");
2473 }
2474 curcol = 0;
2475 if ((followfork == 1 || pflag_seen > 1) && outfname)
2476 tprintf("%-5d ", tcp->pid);
2477 else if (nprocs > 1 && !outfname)
2478 tprintf("[pid %5u] ", tcp->pid);
2479 if (tflag) {
2480 char str[sizeof("HH:MM:SS")];
2481 struct timeval tv, dtv;
2482 static struct timeval otv;
2483
2484 gettimeofday(&tv, NULL);
2485 if (rflag) {
2486 if (otv.tv_sec == 0)
2487 otv = tv;
2488 tv_sub(&dtv, &tv, &otv);
2489 tprintf("%6ld.%06ld ",
2490 (long) dtv.tv_sec, (long) dtv.tv_usec);
2491 otv = tv;
2492 }
2493 else if (tflag > 2) {
2494 tprintf("%ld.%06ld ",
2495 (long) tv.tv_sec, (long) tv.tv_usec);
2496 }
2497 else {
2498 time_t local = tv.tv_sec;
2499 strftime(str, sizeof(str), "%T", localtime(&local));
2500 if (tflag > 1)
2501 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2502 else
2503 tprintf("%s ", str);
2504 }
2505 }
2506 if (iflag)
2507 printcall(tcp);
2508}
2509
2510void
2511tabto(col)
2512int col;
2513{
2514 if (curcol < col)
2515 tprintf("%*s", col - curcol, "");
2516}
2517
2518void
2519printtrailer(tcp)
2520struct tcb *tcp;
2521{
2522 tprintf("\n");
2523 tcp_last = NULL;
2524}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002525
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002526#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002527
2528int mp_ioctl (int fd, int cmd, void *arg, int size) {
2529
2530 struct iovec iov[2];
2531 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002532
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002533 iov[0].iov_base = &cmd;
2534 iov[0].iov_len = sizeof cmd;
2535 if (arg) {
2536 ++n;
2537 iov[1].iov_base = arg;
2538 iov[1].iov_len = size;
2539 }
Roland McGrath553a6092002-12-16 20:40:39 +00002540
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002541 return writev (fd, iov, n);
2542}
2543
2544#endif