]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - usr.bin/truss/setup.c
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.git] / usr.bin / truss / setup.c
1 /*-
2  * Copyright 1997 Sean Eric Fagan
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. All advertising materials mentioning features or use of this software
13  *    must display the following acknowledgement:
14  *      This product includes software developed by Sean Eric Fagan
15  * 4. Neither the name of the author may be used to endorse or promote
16  *    products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 /*
36  * Various setup functions for truss.  Not the cleanest-written code,
37  * I'm afraid.
38  */
39
40 #include <sys/ptrace.h>
41 #include <sys/sysctl.h>
42 #include <sys/wait.h>
43
44 #include <assert.h>
45 #include <err.h>
46 #include <errno.h>
47 #include <signal.h>
48 #include <stdint.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <time.h>
53 #include <unistd.h>
54
55 #include "truss.h"
56 #include "syscall.h"
57 #include "extern.h"
58
59 SET_DECLARE(procabi, struct procabi);
60
61 static sig_atomic_t detaching;
62
63 static void     new_proc(struct trussinfo *, pid_t);
64
65 /*
66  * setup_and_wait() is called to start a process.  All it really does
67  * is fork(), enable tracing in the child, and then exec the given
68  * command.  At that point, the child process stops, and the parent
69  * can wake up and deal with it.
70  */
71 void
72 setup_and_wait(struct trussinfo *info, char *command[])
73 {
74         pid_t pid;
75
76         pid = vfork();
77         if (pid == -1)
78                 err(1, "fork failed");
79         if (pid == 0) { /* Child */
80                 ptrace(PT_TRACE_ME, 0, 0, 0);
81                 execvp(command[0], command);
82                 err(1, "execvp %s", command[0]);
83         }
84
85         /* Only in the parent here */
86         if (waitpid(pid, NULL, 0) < 0)
87                 err(1, "unexpect stop in waitpid");
88
89         new_proc(info, pid);
90 }
91
92 /*
93  * start_tracing is called to attach to an existing process.
94  */
95 void
96 start_tracing(struct trussinfo *info, pid_t pid)
97 {
98         int ret, retry;
99
100         retry = 10;
101         do {
102                 ret = ptrace(PT_ATTACH, pid, NULL, 0);
103                 usleep(200);
104         } while (ret && retry-- > 0);
105         if (ret)
106                 err(1, "can not attach to target process");
107
108         if (waitpid(pid, NULL, 0) < 0)
109                 err(1, "Unexpect stop in waitpid");
110
111         new_proc(info, pid);
112 }
113
114 /*
115  * Restore a process back to it's pre-truss state.
116  * Called for SIGINT, SIGTERM, SIGQUIT.  This only
117  * applies if truss was told to monitor an already-existing
118  * process.
119  */
120 void
121 restore_proc(int signo __unused)
122 {
123
124         detaching = 1;
125 }
126
127 static void
128 detach_proc(pid_t pid)
129 {
130
131         /* stop the child so that we can detach */
132         kill(pid, SIGSTOP);
133         if (waitpid(pid, NULL, 0) < 0)
134                 err(1, "Unexpected stop in waitpid");
135
136         if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0)
137                 err(1, "Can not detach the process");
138
139         kill(pid, SIGCONT);
140 }
141
142 /*
143  * Determine the ABI.  This is called after every exec, and when
144  * a process is first monitored.
145  */
146 static struct procabi *
147 find_abi(pid_t pid)
148 {
149         struct procabi **pabi;
150         size_t len;
151         int error;
152         int mib[4];
153         char progt[32];
154
155         len = sizeof(progt);
156         mib[0] = CTL_KERN;
157         mib[1] = KERN_PROC;
158         mib[2] = KERN_PROC_SV_NAME;
159         mib[3] = pid;
160         error = sysctl(mib, 4, progt, &len, NULL, 0);
161         if (error != 0)
162                 err(2, "can not get sysvec name");
163
164         SET_FOREACH(pabi, procabi) {
165                 if (strcmp((*pabi)->type, progt) == 0)
166                         return (*pabi);
167         }
168         warnx("ABI %s for pid %ld is not supported", progt, (long)pid);
169         return (NULL);
170 }
171
172 static void
173 new_proc(struct trussinfo *info, pid_t pid)
174 {
175         struct procinfo *np;
176
177         /*
178          * If this happens it means there is a bug in truss.  Unfortunately
179          * this will kill any processes are attached to.
180          */
181         LIST_FOREACH(np, &info->proclist, entries) {
182                 if (np->pid == pid)
183                         errx(1, "Duplicate process for pid %ld", (long)pid);
184         }
185
186         if (info->flags & FOLLOWFORKS)
187                 if (ptrace(PT_FOLLOW_FORK, pid, NULL, 1) == -1)
188                         err(1, "Unable to follow forks for pid %ld", (long)pid);
189         np = calloc(1, sizeof(struct procinfo));
190         np->pid = pid;
191         np->abi = find_abi(pid);
192         SLIST_INIT(&np->threadlist);
193         LIST_INSERT_HEAD(&info->proclist, np, entries);
194 }
195
196 static void
197 free_proc(struct procinfo *p)
198 {
199         struct threadinfo *t, *t2;
200
201         SLIST_FOREACH_SAFE(t, &p->threadlist, entries, t2) {
202                 free(t);
203         }
204         LIST_REMOVE(p, entries);
205         free(p);
206 }
207
208 static void
209 detach_all_procs(struct trussinfo *info)
210 {
211         struct procinfo *p, *p2;
212
213         LIST_FOREACH_SAFE(p, &info->proclist, entries, p2) {
214                 detach_proc(p->pid);
215                 free_proc(p);
216         }
217 }
218
219 static struct procinfo *
220 find_proc(struct trussinfo *info, pid_t pid)
221 {
222         struct procinfo *np;
223
224         LIST_FOREACH(np, &info->proclist, entries) {
225                 if (np->pid == pid)
226                         return (np);
227         }
228
229         return (NULL);
230 }
231
232 /*
233  * Change curthread member based on (pid, lwpid).
234  * If it is a new thread, create a threadinfo structure.
235  */
236 static void
237 find_thread(struct trussinfo *info, pid_t pid, lwpid_t lwpid)
238 {
239         struct procinfo *np;
240         struct threadinfo *nt;
241
242         np = find_proc(info, pid);
243         assert(np != NULL);
244
245         SLIST_FOREACH(nt, &np->threadlist, entries) {
246                 if (nt->tid == lwpid) {
247                         info->curthread = nt;
248                         return;
249                 }
250         }
251
252         nt = calloc(1, sizeof(struct threadinfo));
253         if (nt == NULL)
254                 err(1, "calloc() failed");
255         nt->proc = np;
256         nt->tid = lwpid;
257         SLIST_INSERT_HEAD(&np->threadlist, nt, entries);
258         info->curthread = nt;
259 }
260
261 /*
262  * When a process exits, it no longer has any threads left.  However,
263  * the main loop expects a valid curthread.  In cases when a thread
264  * triggers the termination (e.g. calling exit or triggering a fault)
265  * we would ideally use that thread.  However, if a process is killed
266  * by a signal sent from another process then there is no "correct"
267  * thread.  We just punt and use the first thread.
268  */
269 static void
270 find_exit_thread(struct trussinfo *info, pid_t pid)
271 {
272         struct procinfo *np;
273         struct threadinfo *nt;
274
275         np = find_proc(info, pid);
276         assert(np != NULL);
277
278         if (SLIST_EMPTY(&np->threadlist)) {
279                 /*
280                  * If an existing process exits right after we attach
281                  * to it but before it posts any events, there won't
282                  * be any threads.  Create a dummy thread and set its
283                  * "before" time to the global start time.
284                  */
285                 nt = calloc(1, sizeof(struct threadinfo));
286                 if (nt == NULL)
287                         err(1, "calloc() failed");
288                 nt->proc = np;
289                 nt->tid = 0;
290                 SLIST_INSERT_HEAD(&np->threadlist, nt, entries);
291                 nt->before = info->start_time;
292         }
293         info->curthread = SLIST_FIRST(&np->threadlist);
294 }
295
296 static void
297 alloc_syscall(struct threadinfo *t, struct ptrace_lwpinfo *pl)
298 {
299         u_int i;
300
301         assert(t->in_syscall == 0);
302         assert(t->cs.number == 0);
303         assert(t->cs.name == NULL);
304         assert(t->cs.nargs == 0);
305         for (i = 0; i < nitems(t->cs.s_args); i++)
306                 assert(t->cs.s_args[i] == NULL);
307         memset(t->cs.args, 0, sizeof(t->cs.args));
308         t->cs.number = pl->pl_syscall_code;
309         t->in_syscall = 1;
310 }
311
312 static void
313 free_syscall(struct threadinfo *t)
314 {
315         u_int i;
316
317         for (i = 0; i < t->cs.nargs; i++)
318                 free(t->cs.s_args[i]);
319         memset(&t->cs, 0, sizeof(t->cs));
320         t->in_syscall = 0;
321 }
322
323 static void
324 enter_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl)
325 {
326         struct threadinfo *t;
327         struct syscall *sc;
328         u_int i, narg;
329
330         t = info->curthread;
331         alloc_syscall(t, pl);
332         narg = MIN(pl->pl_syscall_narg, nitems(t->cs.args));
333         if (narg != 0 && t->proc->abi->fetch_args(info, narg) != 0) {
334                 free_syscall(t);
335                 return;
336         }
337
338         if (t->cs.number >= 0 && t->cs.number < t->proc->abi->nsyscalls)
339                 t->cs.name = t->proc->abi->syscallnames[t->cs.number];
340         if (t->cs.name == NULL)
341                 fprintf(info->outfile, "-- UNKNOWN %s SYSCALL %d --\n",
342                     t->proc->abi->type, t->cs.number);
343
344         sc = get_syscall(t->cs.name, narg);
345         t->cs.nargs = sc->nargs;
346         assert(sc->nargs <= nitems(t->cs.s_args));
347
348         t->cs.sc = sc;
349
350         /*
351          * At this point, we set up the system call arguments.
352          * We ignore any OUT ones, however -- those are arguments that
353          * are set by the system call, and so are probably meaningless
354          * now. This doesn't currently support arguments that are
355          * passed in *and* out, however.
356          */
357         if (t->cs.name != NULL) {
358 #if DEBUG
359                 fprintf(stderr, "syscall %s(", t->cs.name);
360 #endif
361                 for (i = 0; i < t->cs.nargs; i++) {
362 #if DEBUG
363                         fprintf(stderr, "0x%lx%s", sc ?
364                             t->cs.args[sc->args[i].offset] : t->cs.args[i],
365                             i < (t->cs.nargs - 1) ? "," : "");
366 #endif
367                         if (!(sc->args[i].type & OUT)) {
368                                 t->cs.s_args[i] = print_arg(&sc->args[i],
369                                     t->cs.args, 0, info);
370                         }
371                 }
372 #if DEBUG
373                 fprintf(stderr, ")\n");
374 #endif
375         }
376
377         clock_gettime(CLOCK_REALTIME, &t->before);
378 }
379
380 static void
381 exit_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl)
382 {
383         struct threadinfo *t;
384         struct procinfo *p;
385         struct syscall *sc;
386         long retval[2];
387         u_int i;
388         int errorp;
389
390         t = info->curthread;
391         if (!t->in_syscall)
392                 return;
393
394         clock_gettime(CLOCK_REALTIME, &t->after);
395         p = t->proc;
396         if (p->abi->fetch_retval(info, retval, &errorp) < 0) {
397                 free_syscall(t);
398                 return;
399         }
400
401         sc = t->cs.sc;
402         /*
403          * Here, we only look for arguments that have OUT masked in --
404          * otherwise, they were handled in enter_syscall().
405          */
406         for (i = 0; i < sc->nargs; i++) {
407                 char *temp;
408
409                 if (sc->args[i].type & OUT) {
410                         /*
411                          * If an error occurred, then don't bother
412                          * getting the data; it may not be valid.
413                          */
414                         if (errorp) {
415                                 asprintf(&temp, "0x%lx",
416                                     t->cs.args[sc->args[i].offset]);
417                         } else {
418                                 temp = print_arg(&sc->args[i],
419                                     t->cs.args, retval, info);
420                         }
421                         t->cs.s_args[i] = temp;
422                 }
423         }
424
425         print_syscall_ret(info, t->cs.name, t->cs.nargs, t->cs.s_args,
426             errorp, retval, sc);
427         free_syscall(t);
428
429         /*
430          * If the process executed a new image, check the ABI.  If the
431          * new ABI isn't supported, stop tracing this process.
432          */
433         if (pl->pl_flags & PL_FLAG_EXEC) {
434                 p->abi = find_abi(p->pid);
435                 if (p->abi == NULL) {
436                         if (ptrace(PT_DETACH, p->pid, (caddr_t)1, 0) < 0)
437                                 err(1, "Can not detach the process");
438                         free_proc(p);
439                 }
440         }
441 }
442
443 static void
444 report_exit(struct trussinfo *info, siginfo_t *si)
445 {
446         struct timespec timediff;
447
448         if (info->flags & FOLLOWFORKS)
449                 fprintf(info->outfile, "%5d: ", si->si_pid);
450         clock_gettime(CLOCK_REALTIME, &info->curthread->after);
451         if (info->flags & ABSOLUTETIMESTAMPS) {
452                 timespecsubt(&info->curthread->after, &info->start_time,
453                     &timediff);
454                 fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec,
455                     timediff.tv_nsec);
456         }
457         if (info->flags & RELATIVETIMESTAMPS) {
458                 timespecsubt(&info->curthread->after, &info->curthread->before,
459                     &timediff);
460                 fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec,
461                     timediff.tv_nsec);
462         }
463         if (si->si_code == CLD_EXITED)
464                 fprintf(info->outfile, "process exit, rval = %u\n",
465                     si->si_status);
466         else
467                 fprintf(info->outfile, "process killed, signal = %u%s\n",
468                     si->si_status, si->si_code == CLD_DUMPED ?
469                     " (core dumped)" : "");
470 }
471
472 static void
473 report_new_child(struct trussinfo *info, pid_t pid)
474 {
475         struct timespec timediff;
476
477         clock_gettime(CLOCK_REALTIME, &info->curthread->after);
478         assert(info->flags & FOLLOWFORKS);
479         fprintf(info->outfile, "%5d: ", pid);
480         if (info->flags & ABSOLUTETIMESTAMPS) {
481                 timespecsubt(&info->curthread->after, &info->start_time,
482                     &timediff);
483                 fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec,
484                     timediff.tv_nsec);
485         }
486         if (info->flags & RELATIVETIMESTAMPS) {
487                 timediff.tv_sec = 0;
488                 timediff.tv_nsec = 0;
489                 fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec,
490                     timediff.tv_nsec);
491         }
492         fprintf(info->outfile, "<new process>\n");
493 }
494
495 static void
496 report_signal(struct trussinfo *info, siginfo_t *si)
497 {
498         struct timespec timediff;
499         char *signame;
500
501         if (info->flags & FOLLOWFORKS)
502                 fprintf(info->outfile, "%5d: ", si->si_pid);
503         if (info->flags & ABSOLUTETIMESTAMPS) {
504                 timespecsubt(&info->curthread->after, &info->start_time,
505                     &timediff);
506                 fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec,
507                     timediff.tv_nsec);
508         }
509         if (info->flags & RELATIVETIMESTAMPS) {
510                 timespecsubt(&info->curthread->after, &info->curthread->before,
511                     &timediff);
512                 fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec,
513                     timediff.tv_nsec);
514         }
515         signame = strsig(si->si_status);
516         fprintf(info->outfile, "SIGNAL %u (%s)\n", si->si_status,
517             signame == NULL ? "?" : signame);
518 }
519
520 /*
521  * Wait for events until all the processes have exited or truss has been
522  * asked to stop.
523  */
524 void
525 eventloop(struct trussinfo *info)
526 {
527         struct ptrace_lwpinfo pl;
528         siginfo_t si;
529         int pending_signal;
530
531         while (!LIST_EMPTY(&info->proclist)) {
532                 if (detaching) {
533                         detach_all_procs(info);
534                         return;
535                 }
536
537                 if (waitid(P_ALL, 0, &si, WTRAPPED | WEXITED) == -1) {
538                         if (errno == EINTR)
539                                 continue;
540                         err(1, "Unexpected error from waitid");
541                 }
542
543                 assert(si.si_signo == SIGCHLD);
544
545                 switch (si.si_code) {
546                 case CLD_EXITED:
547                 case CLD_KILLED:
548                 case CLD_DUMPED:
549                         find_exit_thread(info, si.si_pid);
550                         if ((info->flags & COUNTONLY) == 0)
551                                 report_exit(info, &si);
552                         free_proc(info->curthread->proc);
553                         info->curthread = NULL;
554                         break;
555                 case CLD_TRAPPED:
556                         if (ptrace(PT_LWPINFO, si.si_pid, (caddr_t)&pl,
557                             sizeof(pl)) == -1)
558                                 err(1, "ptrace(PT_LWPINFO)");
559
560                         if (pl.pl_flags & PL_FLAG_CHILD) {
561                                 new_proc(info, si.si_pid);
562                                 assert(LIST_FIRST(&info->proclist)->abi !=
563                                     NULL);
564                         }
565                         find_thread(info, si.si_pid, pl.pl_lwpid);
566
567                         if (si.si_status == SIGTRAP &&
568                             (pl.pl_flags & (PL_FLAG_SCE|PL_FLAG_SCX)) != 0) {
569                                 if (pl.pl_flags & PL_FLAG_SCE)
570                                         enter_syscall(info, &pl);
571                                 else if (pl.pl_flags & PL_FLAG_SCX)
572                                         exit_syscall(info, &pl);
573                                 pending_signal = 0;
574                         } else if (pl.pl_flags & PL_FLAG_CHILD) {
575                                 if ((info->flags & COUNTONLY) == 0)
576                                         report_new_child(info, si.si_pid);
577                                 pending_signal = 0;
578                         } else {
579                                 if ((info->flags & NOSIGS) == 0)
580                                         report_signal(info, &si);
581                                 pending_signal = si.si_status;
582                         }
583                         ptrace(PT_SYSCALL, si.si_pid, (caddr_t)1,
584                             pending_signal);
585                         break;
586                 case CLD_STOPPED:
587                         errx(1, "waitid reported CLD_STOPPED");
588                 case CLD_CONTINUED:
589                         break;
590                 }
591         }
592 }