mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
truss(1): capsicumize
The new ptrace(2) features allow to change truss(1) to systematically operate on the process descriptors instead of pids. Allocate the global kqueue that tracks all noted children by pdopenpid()-ing them and adding to the kqueue with EVFILT_PROCDESC/NOTE_PDSIGCHLD. The activated knote triggers the pdwait() call to return the child tracing info. This replaces the waitid(P_ALL) call in the non-capsicumized truss(1) eventloop. Reviewed by: markj Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D58094
This commit is contained in:
1 parent
1fb9c5ffe2
commit
151a8512bd
6 files changed
+470
-183
No files matched your search
+18
-9
@@ -31,12 +31,21 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
extern void add_syscall_filter(const char *);
|
||||
extern void list_syscall_groups(void);
|
||||
extern bool syscall_filter_match(const char *, u_int);
|
||||
extern int print_line_prefix(struct trussinfo *);
|
||||
extern void setup_and_wait(struct trussinfo *, char **);
|
||||
extern void start_tracing(struct trussinfo *, pid_t);
|
||||
extern void restore_proc(int);
|
||||
extern void decode_siginfo(FILE *, siginfo_t *);
|
||||
extern void eventloop(struct trussinfo *);
|
||||
#ifndef __TRUSS_EXTERN_H__
|
||||
#define __TRUSS_EXTERN_H__
|
||||
|
||||
void add_syscall_filter(const char *);
|
||||
void list_syscall_groups(void);
|
||||
bool syscall_filter_match(const char *, u_int);
|
||||
int print_line_prefix(struct trussinfo *);
|
||||
void setup_and_wait(struct trussinfo *, char **);
|
||||
void start_tracing(struct trussinfo *, pid_t);
|
||||
void restore_proc(int);
|
||||
void decode_siginfo(FILE *, siginfo_t *);
|
||||
void eventloop(struct trussinfo *);
|
||||
|
||||
int truss_kill(struct trussinfo *info, struct procinfo *p, int sig);
|
||||
int truss_ptrace(struct trussinfo *info, int req, struct procinfo *p,
|
||||
void *addr, int data);
|
||||
|
||||
#endif
|
||||
+22
-10
@@ -31,13 +31,14 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
/*
|
||||
* The main module for truss. Surprisingly simple, but, then, the other
|
||||
* files handle the bulk of the work. And, of course, the kernel has to
|
||||
* do a lot of the work :).
|
||||
*/
|
||||
|
||||
#include <sys/capsicum.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
#include <err.h>
|
||||
@@ -57,8 +58,8 @@ static __dead2 void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "%s\n%s\n%s\n",
|
||||
"usage: truss [-cfaedDHS] [-o file] [-s strsize] [-t expr] -p pid",
|
||||
" truss [-cfaedDHS] [-o file] [-s strsize] [-t expr] "
|
||||
"usage: truss [-cfaedyDHS] [-o file] [-s strsize] [-t expr] -p pid",
|
||||
" truss [-cfaedyDHS] [-o file] [-s strsize] [-t expr] "
|
||||
"command [args]",
|
||||
" truss -t");
|
||||
exit(1);
|
||||
@@ -69,6 +70,7 @@ main(int ac, char **av)
|
||||
{
|
||||
struct sigaction sa;
|
||||
struct trussinfo *trussinfo;
|
||||
struct procinfo *np;
|
||||
char *fname;
|
||||
char **command;
|
||||
const char *errstr;
|
||||
@@ -87,13 +89,15 @@ main(int ac, char **av)
|
||||
trussinfo->strsize = 32;
|
||||
trussinfo->curthread = NULL;
|
||||
LIST_INIT(&trussinfo->proclist);
|
||||
trussinfo->cap_mode = true;
|
||||
|
||||
/*
|
||||
* The leading ':' asks getopt() to report a missing option
|
||||
* argument as ':' rather than '?' so that a bare -t, which lists
|
||||
* the system call groups, can be told from a malformed option.
|
||||
* Diagnosing the other two cases then falls to us.
|
||||
*/
|
||||
while ((c = getopt(ac, av, ":p:o:facedDs:t:SH")) != -1) {
|
||||
while ((c = getopt(ac, av, ":p:o:facedyDs:t:SH")) != -1) {
|
||||
switch (c) {
|
||||
case 'p': /* specified pid */
|
||||
pid = atoi(optarg);
|
||||
@@ -132,6 +136,9 @@ main(int ac, char **av)
|
||||
case 't': /* Select the system calls to trace */
|
||||
add_syscall_filter(optarg);
|
||||
break;
|
||||
case 'y':
|
||||
trussinfo->cap_mode = false;
|
||||
break;
|
||||
case 'S': /* Don't trace signals */
|
||||
trussinfo->flags |= NOSIGS;
|
||||
break;
|
||||
@@ -166,6 +173,12 @@ main(int ac, char **av)
|
||||
err(1, "cannot open %s", fname);
|
||||
}
|
||||
|
||||
if (trussinfo->cap_mode) {
|
||||
trussinfo->pdkq = kqueue();
|
||||
if (trussinfo->pdkq == -1)
|
||||
err(1, "kqueue");
|
||||
}
|
||||
|
||||
/*
|
||||
* If truss starts the process itself, it will ignore some signals --
|
||||
* they should be passed off to the process, which may or may not
|
||||
@@ -193,7 +206,8 @@ main(int ac, char **av)
|
||||
* At this point, if we started the process, it is stopped waiting to
|
||||
* be woken up, either in exit() or in execve().
|
||||
*/
|
||||
if (LIST_FIRST(&trussinfo->proclist)->abi == NULL) {
|
||||
np = LIST_FIRST(&trussinfo->proclist);
|
||||
if (np->abi == NULL) {
|
||||
/*
|
||||
* If we are not able to handle this ABI, detach from the
|
||||
* process and exit. If we just created a new process to
|
||||
@@ -201,13 +215,11 @@ main(int ac, char **av)
|
||||
* it run untraced.
|
||||
*/
|
||||
if (pid == 0)
|
||||
kill(LIST_FIRST(&trussinfo->proclist)->pid, SIGKILL);
|
||||
ptrace(PT_DETACH, LIST_FIRST(&trussinfo->proclist)->pid, NULL,
|
||||
0);
|
||||
truss_kill(trussinfo, np, SIGKILL);
|
||||
truss_ptrace(trussinfo, PT_DETACH, np, NULL, 0);
|
||||
return (1);
|
||||
}
|
||||
ptrace(PT_SYSCALL, LIST_FIRST(&trussinfo->proclist)->pid, (caddr_t)1,
|
||||
0);
|
||||
truss_ptrace(trussinfo, PT_SYSCALL, np, (caddr_t)1, 0);
|
||||
|
||||
/*
|
||||
* At this point, it's a simple loop, waiting for the process to
|
||||
|
||||
+304
-97
@@ -31,18 +31,22 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
/*
|
||||
* Various setup functions for truss. Not the cleanest-written code,
|
||||
* I'm afraid.
|
||||
*/
|
||||
|
||||
#include <sys/capsicum.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/procdesc.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <capsicum_helpers.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
@@ -59,6 +63,8 @@
|
||||
#include "syscall.h"
|
||||
#include "extern.h"
|
||||
|
||||
#define WFLAGS (WTRAPPED | WEXITED | WCONTINUED | WUNTRACED)
|
||||
|
||||
struct procabi_table {
|
||||
const char *name;
|
||||
struct procabi *abi;
|
||||
@@ -68,8 +74,9 @@ static sig_atomic_t detaching;
|
||||
|
||||
static void enter_syscall(struct trussinfo *, struct threadinfo *,
|
||||
struct ptrace_lwpinfo *);
|
||||
static void new_proc(struct trussinfo *, pid_t, lwpid_t);
|
||||
|
||||
static bool new_proc(struct trussinfo *, pid_t, lwpid_t, int, bool, bool);
|
||||
static void new_proc_register_kev(struct trussinfo *info, int pfd);
|
||||
static struct procinfo *find_proc(struct trussinfo *info, pid_t pid);
|
||||
|
||||
static struct procabi freebsd = {
|
||||
.type = "FreeBSD",
|
||||
@@ -138,6 +145,49 @@ static struct procabi_table abis[] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
int
|
||||
truss_ptrace(struct trussinfo *info, int req, struct procinfo *p, void *addr,
|
||||
int data)
|
||||
{
|
||||
if (info->cap_mode)
|
||||
return (pdptrace(req, p->pfd, -1, addr, data));
|
||||
return (ptrace(req, p->pid, addr, data));
|
||||
}
|
||||
|
||||
static int
|
||||
truss_ptrace_lwp(struct trussinfo *info, int req, struct procinfo *p,
|
||||
lwpid_t lwpid, void *addr, int data)
|
||||
{
|
||||
if (info->cap_mode)
|
||||
return (pdptrace(req, p->pfd, lwpid, addr, data));
|
||||
return (ptrace(req, lwpid, addr, data));
|
||||
}
|
||||
|
||||
static int
|
||||
t_wait(struct trussinfo *info, int pid, int *status, int wflags)
|
||||
{
|
||||
if (info->cap_mode)
|
||||
return (pdwait(pid, status, wflags, NULL, NULL));
|
||||
return (waitpid(pid, status, wflags));
|
||||
}
|
||||
|
||||
static int
|
||||
truss_wait(struct trussinfo *info, struct procinfo *p, int *status,
|
||||
int wflags)
|
||||
{
|
||||
if (info->cap_mode)
|
||||
return (pdwait(p->pfd, status, wflags, NULL, NULL));
|
||||
return (waitpid(p->pid, status, wflags));
|
||||
}
|
||||
|
||||
int
|
||||
truss_kill(struct trussinfo *info, struct procinfo *p, int sig)
|
||||
{
|
||||
if (info->cap_mode)
|
||||
return (pdkill(p->pfd, sig));
|
||||
return (kill(p->pid, sig));
|
||||
}
|
||||
|
||||
/*
|
||||
* setup_and_wait() is called to start a process. All it really does
|
||||
* is fork(), enable tracing in the child, and then exec the given
|
||||
@@ -148,21 +198,34 @@ void
|
||||
setup_and_wait(struct trussinfo *info, char *command[])
|
||||
{
|
||||
pid_t pid;
|
||||
int fd, res;
|
||||
|
||||
pid = vfork();
|
||||
if (info->cap_mode) {
|
||||
pid = pdfork(&fd, PD_DAEMON | PD_CLOEXEC | PD_PTRACE_CAP);
|
||||
if (pid == -1)
|
||||
err(1, "fork failed");
|
||||
} else {
|
||||
pid = vfork();
|
||||
fd = -1;
|
||||
}
|
||||
if (pid == 0) { /* Child */
|
||||
ptrace(PT_TRACE_ME, 0, 0, 0);
|
||||
execvp(command[0], command);
|
||||
err(1, "execvp %s", command[0]);
|
||||
}
|
||||
|
||||
if (info->cap_mode) {
|
||||
if (caph_enter() == -1)
|
||||
err(1, "cap_enter");
|
||||
new_proc_register_kev(info, fd);
|
||||
}
|
||||
|
||||
/* Only in the parent here */
|
||||
if (waitpid(pid, NULL, 0) < 0)
|
||||
res = t_wait(info, info->cap_mode ? fd : pid, NULL, WFLAGS);
|
||||
if (res < 0)
|
||||
err(1, "unexpected stop in waitpid");
|
||||
|
||||
new_proc(info, pid, 0);
|
||||
new_proc(info, pid, 0, fd, false, false);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -171,20 +234,33 @@ setup_and_wait(struct trussinfo *info, char *command[])
|
||||
void
|
||||
start_tracing(struct trussinfo *info, pid_t pid)
|
||||
{
|
||||
int ret, retry;
|
||||
int fd, ret, retry;
|
||||
|
||||
if (info->cap_mode) {
|
||||
fd = pdopenpid(pid, PD_DAEMON | PD_CLOEXEC | PD_PTRACE_CAP);
|
||||
if (fd == -1)
|
||||
err(1, "Cannot open the target process");
|
||||
if (caph_enter() == -1)
|
||||
err(1, "cap_enter");
|
||||
new_proc_register_kev(info, fd);
|
||||
} else {
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
retry = 10;
|
||||
do {
|
||||
ret = ptrace(PT_ATTACH, pid, NULL, 0);
|
||||
ret = info->cap_mode ? pdptrace(PT_ATTACH, fd, -1,
|
||||
NULL, 0) : ptrace(PT_ATTACH, pid, NULL, 0);
|
||||
usleep(200);
|
||||
} while (ret && retry-- > 0);
|
||||
if (ret)
|
||||
err(1, "Cannot attach to target process");
|
||||
|
||||
if (waitpid(pid, NULL, 0) < 0)
|
||||
ret = t_wait(info, info->cap_mode ? fd : pid, NULL, WFLAGS);
|
||||
if (ret < 0)
|
||||
err(1, "Unexpected stop in waitpid");
|
||||
|
||||
new_proc(info, pid, 0);
|
||||
new_proc(info, pid, 0, fd, false, false);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -201,31 +277,32 @@ restore_proc(int signo __unused)
|
||||
}
|
||||
|
||||
static void
|
||||
detach_proc(pid_t pid)
|
||||
detach_proc(struct trussinfo *info, struct procinfo *p)
|
||||
{
|
||||
int sig, status;
|
||||
int error, sig, status;
|
||||
|
||||
/*
|
||||
* Stop the child so that we can detach. Filter out possible
|
||||
* lingering SIGTRAP events buffered in the threads.
|
||||
*/
|
||||
kill(pid, SIGSTOP);
|
||||
truss_kill(info, p, SIGSTOP);
|
||||
for (;;) {
|
||||
if (waitpid(pid, &status, 0) < 0)
|
||||
error = truss_wait(info, p, &status, WFLAGS);
|
||||
if (error < 0)
|
||||
err(1, "Unexpected error in waitpid");
|
||||
sig = WIFSTOPPED(status) ? WSTOPSIG(status) : 0;
|
||||
if (sig == SIGSTOP)
|
||||
break;
|
||||
if (sig == SIGTRAP)
|
||||
sig = 0;
|
||||
if (ptrace(PT_CONTINUE, pid, (caddr_t)1, sig) < 0)
|
||||
if (truss_ptrace(info, PT_CONTINUE, p, (caddr_t)1, sig) < 0)
|
||||
err(1, "Can not continue for detach");
|
||||
}
|
||||
|
||||
if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0)
|
||||
if (truss_ptrace(info, PT_DETACH, p, (caddr_t)1, 0) < 0)
|
||||
err(1, "Can not detach the process");
|
||||
|
||||
kill(pid, SIGCONT);
|
||||
truss_kill(info, p, SIGCONT);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -233,28 +310,22 @@ detach_proc(pid_t pid)
|
||||
* a process is first monitored.
|
||||
*/
|
||||
static struct procabi *
|
||||
find_abi(pid_t pid)
|
||||
find_abi(struct trussinfo *info, struct procinfo *p)
|
||||
{
|
||||
size_t len;
|
||||
unsigned int i;
|
||||
int error;
|
||||
int mib[4];
|
||||
unsigned i;
|
||||
char progt[32];
|
||||
|
||||
len = sizeof(progt);
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_SV_NAME;
|
||||
mib[3] = pid;
|
||||
error = sysctl(mib, 4, progt, &len, NULL, 0);
|
||||
if (error != 0)
|
||||
err(2, "can not get sysvec name");
|
||||
if (truss_ptrace(info, PT_GET_ABI_NAME, p, progt,
|
||||
sizeof(progt)) == -1) {
|
||||
warn("cannot get ABI for proc %ld", (long)p->pid);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
for (i = 0; i < nitems(abis); i++) {
|
||||
if (strcmp(abis[i].name, progt) == 0)
|
||||
return (abis[i].abi);
|
||||
}
|
||||
warnx("ABI %s for pid %ld is not supported", progt, (long)pid);
|
||||
warnx("ABI %s for pid %ld is not supported", progt, (long)p->pid);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
@@ -297,17 +368,18 @@ add_threads(struct trussinfo *info, struct procinfo *p)
|
||||
lwpid_t *lwps;
|
||||
int i, nlwps;
|
||||
|
||||
nlwps = ptrace(PT_GETNUMLWPS, p->pid, NULL, 0);
|
||||
nlwps = truss_ptrace(info, PT_GETNUMLWPS, p, NULL, 0);
|
||||
if (nlwps == -1)
|
||||
err(1, "Unable to fetch number of LWPs");
|
||||
assert(nlwps > 0);
|
||||
lwps = calloc(nlwps, sizeof(*lwps));
|
||||
nlwps = ptrace(PT_GETLWPLIST, p->pid, (caddr_t)lwps, nlwps);
|
||||
nlwps = truss_ptrace(info, PT_GETLWPLIST, p, lwps, nlwps);
|
||||
if (nlwps == -1)
|
||||
err(1, "Unable to fetch LWP list");
|
||||
for (i = 0; i < nlwps; i++) {
|
||||
t = new_thread(p, lwps[i]);
|
||||
if (ptrace(PT_LWPINFO, lwps[i], (caddr_t)&pl, sizeof(pl)) == -1)
|
||||
if (truss_ptrace_lwp(info, PT_LWPINFO, p, lwps[i], &pl,
|
||||
sizeof(pl)) == -1)
|
||||
err(1, "ptrace(PT_LWPINFO)");
|
||||
if (pl.pl_flags & PL_FLAG_SCE) {
|
||||
info->curthread = t;
|
||||
@@ -318,27 +390,56 @@ add_threads(struct trussinfo *info, struct procinfo *p)
|
||||
}
|
||||
|
||||
static void
|
||||
new_proc(struct trussinfo *info, pid_t pid, lwpid_t lwpid)
|
||||
new_proc_register_kev(struct trussinfo *info, int pfd)
|
||||
{
|
||||
struct kevent ev[1];
|
||||
int error;
|
||||
|
||||
if (!info->cap_mode)
|
||||
return;
|
||||
EV_SET(&ev[0], pfd, EVFILT_PROCDESC, EV_ADD, NOTE_EXIT |
|
||||
NOTE_PDSIGCHLD | NOTE_FORK, 0, 0);
|
||||
error = kevent(info->pdkq, ev, nitems(ev), NULL, 0, NULL);
|
||||
if (error == -1)
|
||||
err(1, "Unable to register pfd %d for notifications", pfd);
|
||||
}
|
||||
|
||||
static bool
|
||||
new_proc(struct trussinfo *info, pid_t pid, lwpid_t lwpid, int pfd,
|
||||
bool allow_known, bool wait_for)
|
||||
{
|
||||
struct procinfo *np;
|
||||
|
||||
if (find_proc(info, pid) != NULL) {
|
||||
if (allow_known)
|
||||
return (false);
|
||||
|
||||
/*
|
||||
* If this happens it means there is a bug in truss. Unfortunately
|
||||
* this will kill any processes truss is attached to.
|
||||
* If this happens it means there is a bug in truss.
|
||||
* Unfortunately this will kill any processes truss is
|
||||
* attached to.
|
||||
*/
|
||||
LIST_FOREACH(np, &info->proclist, entries) {
|
||||
if (np->pid == pid)
|
||||
errx(1, "Duplicate process for pid %ld", (long)pid);
|
||||
}
|
||||
if (pfd == -1 && info->cap_mode) {
|
||||
pfd = pdopenpid(pid, PD_DAEMON | PD_CLOEXEC | PD_PTRACE_CAP);
|
||||
if (pfd == -1)
|
||||
err(1, "pdopenpid %d", pid);
|
||||
if (wait_for && t_wait(info, pfd, NULL, WFLAGS) < 0)
|
||||
err(1, "waitpid on attach to %d", pid);
|
||||
new_proc_register_kev(info, pfd);
|
||||
}
|
||||
|
||||
if (info->flags & FOLLOWFORKS)
|
||||
if (ptrace(PT_FOLLOW_FORK, pid, NULL, 1) == -1)
|
||||
err(1, "Unable to follow forks for pid %ld", (long)pid);
|
||||
if (ptrace(PT_LWP_EVENTS, pid, NULL, 1) == -1)
|
||||
err(1, "Unable to enable LWP events for pid %ld", (long)pid);
|
||||
np = calloc(1, sizeof(struct procinfo));
|
||||
np->pid = pid;
|
||||
np->abi = find_abi(pid);
|
||||
np->pfd = pfd;
|
||||
np->abi = find_abi(info, np);
|
||||
np->herald_printed = false;
|
||||
if ((info->flags & FOLLOWFORKS) != 0 && truss_ptrace(info,
|
||||
PT_FOLLOW_FORK, np, NULL, 1) == -1)
|
||||
err(1, "Unable to follow forks for pid %ld", (long)pid);
|
||||
if (truss_ptrace(info, PT_LWP_EVENTS, np, NULL, 1) == -1)
|
||||
err(1, "Unable to enable LWP events for pid %ld", (long)pid);
|
||||
LIST_INIT(&np->threadlist);
|
||||
LIST_INIT(&np->fdlist);
|
||||
LIST_INSERT_HEAD(&info->proclist, np, entries);
|
||||
@@ -347,13 +448,21 @@ new_proc(struct trussinfo *info, pid_t pid, lwpid_t lwpid)
|
||||
new_thread(np, lwpid);
|
||||
else
|
||||
add_threads(info, np);
|
||||
return (true);
|
||||
}
|
||||
|
||||
static void
|
||||
free_proc(struct procinfo *p)
|
||||
free_proc(struct trussinfo *info, struct procinfo *p)
|
||||
{
|
||||
struct threadinfo *t, *t2;
|
||||
struct fd_domain *f, *f2;
|
||||
struct kevent ev[1];
|
||||
|
||||
if (info->cap_mode) {
|
||||
EV_SET(&ev[0], p->pfd, EVFILT_PROCDESC, EV_DELETE, 0, 0, 0);
|
||||
(void)kevent(info->pdkq, ev, nitems(ev), NULL, 0, 0);
|
||||
close(p->pfd);
|
||||
}
|
||||
|
||||
LIST_FOREACH_SAFE(t, &p->threadlist, entries, t2) {
|
||||
free(t);
|
||||
@@ -373,8 +482,8 @@ detach_all_procs(struct trussinfo *info)
|
||||
struct procinfo *p, *p2;
|
||||
|
||||
LIST_FOREACH_SAFE(p, &info->proclist, entries, p2) {
|
||||
detach_proc(p->pid);
|
||||
free_proc(p);
|
||||
detach_proc(info, p);
|
||||
free_proc(info, p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,8 +574,8 @@ enter_syscall(struct trussinfo *info, struct threadinfo *t,
|
||||
|
||||
alloc_syscall(t, pl);
|
||||
narg = MIN(pl->pl_syscall_narg, nitems(t->cs.args));
|
||||
if (narg != 0 && ptrace(PT_GET_SC_ARGS, t->tid, (caddr_t)t->cs.args,
|
||||
sizeof(t->cs.args)) != 0) {
|
||||
if (narg != 0 && truss_ptrace_lwp(info, PT_GET_SC_ARGS, t->proc,
|
||||
t->tid, (caddr_t)t->cs.args, sizeof(t->cs.args)) != 0) {
|
||||
free_syscall(t);
|
||||
return;
|
||||
}
|
||||
@@ -555,7 +664,8 @@ exit_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl)
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &t->after);
|
||||
p = t->proc;
|
||||
if (ptrace(PT_GET_SC_RET, t->tid, (caddr_t)&psr, sizeof(psr)) != 0) {
|
||||
if (truss_ptrace_lwp(info, PT_GET_SC_RET, p, t->tid, &psr,
|
||||
sizeof(psr)) != 0) {
|
||||
free_syscall(t);
|
||||
return;
|
||||
}
|
||||
@@ -624,11 +734,11 @@ exit_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl)
|
||||
*/
|
||||
if (pl->pl_flags & PL_FLAG_EXEC) {
|
||||
assert(LIST_NEXT(LIST_FIRST(&p->threadlist), entries) == NULL);
|
||||
p->abi = find_abi(p->pid);
|
||||
p->abi = find_abi(info, p);
|
||||
if (p->abi == NULL) {
|
||||
if (ptrace(PT_DETACH, p->pid, (caddr_t)1, 0) < 0)
|
||||
if (truss_ptrace(info, PT_DETACH, p, (caddr_t)1, 0) < 0)
|
||||
err(1, "Can not detach the process");
|
||||
free_proc(p);
|
||||
free_proc(info, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -711,6 +821,9 @@ report_new_child(struct trussinfo *info)
|
||||
struct threadinfo *t;
|
||||
|
||||
t = info->curthread;
|
||||
if (t->proc->herald_printed)
|
||||
return;
|
||||
t->proc->herald_printed = true;
|
||||
clock_gettime(CLOCK_REALTIME, &t->after);
|
||||
t->before = t->after;
|
||||
print_line_prefix(info);
|
||||
@@ -790,6 +903,96 @@ report_signal(struct trussinfo *info, siginfo_t *si, struct ptrace_lwpinfo *pl)
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
eventloop_handle_trapped(struct trussinfo *info, pid_t si_pid, int si_status,
|
||||
siginfo_t *si)
|
||||
{
|
||||
struct procinfo *np;
|
||||
struct ptrace_lwpinfo pl;
|
||||
int pending_signal;
|
||||
|
||||
np = find_proc(info, si_pid);
|
||||
if (np == NULL) {
|
||||
new_proc(info, si_pid, 0, -1, true, false);
|
||||
np = find_proc(info, si_pid);
|
||||
}
|
||||
if (truss_ptrace(info, PT_LWPINFO, np, &pl, sizeof(pl)) == -1)
|
||||
err(1, "ptrace(PT_LWPINFO)");
|
||||
|
||||
if ((pl.pl_flags & PL_FLAG_CHILD) != 0) {
|
||||
assert(LIST_FIRST(&info->proclist)->abi != NULL);
|
||||
} else if ((pl.pl_flags & PL_FLAG_BORN) != 0) {
|
||||
new_thread(np, pl.pl_lwpid);
|
||||
}
|
||||
find_thread(info, si_pid, pl.pl_lwpid);
|
||||
|
||||
pending_signal = 0;
|
||||
if (si_status == SIGTRAP && (pl.pl_flags & (PL_FLAG_BORN |
|
||||
PL_FLAG_EXITED | PL_FLAG_SCE | PL_FLAG_SCX)) != 0) {
|
||||
if ((pl.pl_flags & PL_FLAG_BORN) != 0) {
|
||||
if ((info->flags & COUNTONLY) == 0)
|
||||
report_thread_birth(info);
|
||||
} else if ((pl.pl_flags & PL_FLAG_EXITED) != 0) {
|
||||
if ((info->flags & COUNTONLY) == 0)
|
||||
report_thread_death(info);
|
||||
free_thread(info->curthread);
|
||||
info->curthread = NULL;
|
||||
} else if ((pl.pl_flags & PL_FLAG_SCE) != 0) {
|
||||
enter_syscall(info, info->curthread, &pl);
|
||||
} else if ((pl.pl_flags & PL_FLAG_SCX) != 0) {
|
||||
exit_syscall(info, &pl);
|
||||
}
|
||||
} else if ((pl.pl_flags & PL_FLAG_CHILD) != 0) {
|
||||
if ((info->flags & COUNTONLY) == 0)
|
||||
report_new_child(info);
|
||||
} else if (si != NULL) {
|
||||
if ((info->flags & NOSIGS) == 0)
|
||||
report_signal(info, si, &pl);
|
||||
pending_signal = si->si_status;
|
||||
}
|
||||
if (truss_ptrace(info, PT_SYSCALL, np, (caddr_t)1,
|
||||
pending_signal) == -1)
|
||||
err(1, "ptrace(PT_SYSCALL)");
|
||||
}
|
||||
|
||||
static void
|
||||
eventloop_handle_note_fork(struct trussinfo *info)
|
||||
{
|
||||
struct ptrace_child *ptcs;
|
||||
int cnt, i;
|
||||
|
||||
again:
|
||||
cnt = ptrace(PT_GET_CHILDREN, getpid(), NULL, 0);
|
||||
if (cnt == -1)
|
||||
err(1, "Unexpected error from ptrace(PT_GET_CHILDREN) size");
|
||||
if (cnt == 0)
|
||||
return;
|
||||
ptcs = calloc(cnt, sizeof(*ptcs));
|
||||
if (ptcs == NULL)
|
||||
err(1, "No memory");
|
||||
cnt = ptrace(PT_GET_CHILDREN, getpid(), (caddr_t)ptcs,
|
||||
cnt * sizeof(*ptcs));
|
||||
if (cnt == -1) {
|
||||
if (errno == ENOMEM) {
|
||||
free(ptcs);
|
||||
goto again;
|
||||
}
|
||||
err(1, "Unexpected error from ptrace(PT_GET_CHILDREN) data");
|
||||
}
|
||||
for (i = 0; i < cnt; i++) {
|
||||
if ((ptcs[i].flags & (PTCHLD_TRACED | PTCHLD_TRACED_BY_ME |
|
||||
PTCHLD_EXITED)) != (PTCHLD_TRACED | PTCHLD_TRACED_BY_ME))
|
||||
continue;
|
||||
if (new_proc(info, ptcs[i].pid, 0, -1, true, true)) {
|
||||
if ((info->flags & COUNTONLY) == 0)
|
||||
report_new_child(info);
|
||||
eventloop_handle_trapped(info, ptcs[i].pid, SIGTRAP,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
free(ptcs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for events until all the processes have exited or truss has been
|
||||
* asked to stop.
|
||||
@@ -797,9 +1000,10 @@ report_signal(struct trussinfo *info, siginfo_t *si, struct ptrace_lwpinfo *pl)
|
||||
void
|
||||
eventloop(struct trussinfo *info)
|
||||
{
|
||||
struct ptrace_lwpinfo pl;
|
||||
siginfo_t si;
|
||||
int pending_signal;
|
||||
struct kevent ev[1];
|
||||
int cnt, error;
|
||||
bool has_si;
|
||||
|
||||
while (!LIST_EMPTY(&info->proclist)) {
|
||||
if (detaching) {
|
||||
@@ -807,11 +1011,52 @@ eventloop(struct trussinfo *info)
|
||||
return;
|
||||
}
|
||||
|
||||
has_si = false;
|
||||
if (info->cap_mode) {
|
||||
cnt = kevent(info->pdkq, NULL, 0, ev, nitems(ev),
|
||||
NULL);
|
||||
if (cnt == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
err(1, "Unexpected error from kevent");
|
||||
}
|
||||
if (cnt == 0) {
|
||||
/* XXXKIB ? */
|
||||
continue;
|
||||
}
|
||||
if ((ev[0].fflags & (NOTE_EXIT | NOTE_PDSIGCHLD)) !=
|
||||
0) {
|
||||
error = pdwait(ev[0].ident, NULL,
|
||||
WFLAGS | WNOHANG, NULL, &si);
|
||||
if (error == -1) {
|
||||
if (errno == EINTR ||
|
||||
errno == EWOULDBLOCK)
|
||||
continue;
|
||||
err(1, "Unexpected error from pdwait");
|
||||
}
|
||||
has_si = true;
|
||||
|
||||
/*
|
||||
* To get rid of zombie, we need to
|
||||
* waitpid() on it in addition to the
|
||||
* pdwait() above, because we are the
|
||||
* debugger, and the child was
|
||||
* reparented to us.
|
||||
*/
|
||||
waitpid(si.si_pid, NULL, WEXITED | WNOHANG);
|
||||
}
|
||||
if ((ev[0].fflags & NOTE_FORK) != 0)
|
||||
eventloop_handle_note_fork(info);
|
||||
} else {
|
||||
if (waitid(P_ALL, 0, &si, WTRAPPED | WEXITED) == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
err(1, "Unexpected error from waitid");
|
||||
}
|
||||
has_si = true;
|
||||
}
|
||||
if (!has_si)
|
||||
continue;
|
||||
|
||||
assert(si.si_signo == SIGCHLD);
|
||||
|
||||
@@ -825,50 +1070,12 @@ eventloop(struct trussinfo *info)
|
||||
thread_exit_syscall(info);
|
||||
report_exit(info, &si);
|
||||
}
|
||||
free_proc(info->curthread->proc);
|
||||
free_proc(info, info->curthread->proc);
|
||||
info->curthread = NULL;
|
||||
break;
|
||||
case CLD_TRAPPED:
|
||||
if (ptrace(PT_LWPINFO, si.si_pid, (caddr_t)&pl,
|
||||
sizeof(pl)) == -1)
|
||||
err(1, "ptrace(PT_LWPINFO)");
|
||||
|
||||
if (pl.pl_flags & PL_FLAG_CHILD) {
|
||||
new_proc(info, si.si_pid, pl.pl_lwpid);
|
||||
assert(LIST_FIRST(&info->proclist)->abi !=
|
||||
NULL);
|
||||
} else if (pl.pl_flags & PL_FLAG_BORN)
|
||||
new_thread(find_proc(info, si.si_pid),
|
||||
pl.pl_lwpid);
|
||||
find_thread(info, si.si_pid, pl.pl_lwpid);
|
||||
|
||||
if (si.si_status == SIGTRAP &&
|
||||
(pl.pl_flags & (PL_FLAG_BORN|PL_FLAG_EXITED|
|
||||
PL_FLAG_SCE|PL_FLAG_SCX)) != 0) {
|
||||
if (pl.pl_flags & PL_FLAG_BORN) {
|
||||
if ((info->flags & COUNTONLY) == 0)
|
||||
report_thread_birth(info);
|
||||
} else if (pl.pl_flags & PL_FLAG_EXITED) {
|
||||
if ((info->flags & COUNTONLY) == 0)
|
||||
report_thread_death(info);
|
||||
free_thread(info->curthread);
|
||||
info->curthread = NULL;
|
||||
} else if (pl.pl_flags & PL_FLAG_SCE)
|
||||
enter_syscall(info, info->curthread, &pl);
|
||||
else if (pl.pl_flags & PL_FLAG_SCX)
|
||||
exit_syscall(info, &pl);
|
||||
pending_signal = 0;
|
||||
} else if (pl.pl_flags & PL_FLAG_CHILD) {
|
||||
if ((info->flags & COUNTONLY) == 0)
|
||||
report_new_child(info);
|
||||
pending_signal = 0;
|
||||
} else {
|
||||
if ((info->flags & NOSIGS) == 0)
|
||||
report_signal(info, &si, &pl);
|
||||
pending_signal = si.si_status;
|
||||
}
|
||||
ptrace(PT_SYSCALL, si.si_pid, (caddr_t)1,
|
||||
pending_signal);
|
||||
eventloop_handle_trapped(info, si.si_pid,
|
||||
si.si_status, &si);
|
||||
break;
|
||||
case CLD_STOPPED:
|
||||
errx(1, "waitid reported CLD_STOPPED");
|
||||
|
||||
+92
-65
@@ -950,7 +950,8 @@ get_syscall(struct threadinfo *t, u_int number, u_int nargs)
|
||||
* Copy a fixed amount of bytes from the process.
|
||||
*/
|
||||
static int
|
||||
get_struct(pid_t pid, psaddr_t offset, void *buf, size_t len)
|
||||
get_struct(struct trussinfo *info, struct procinfo *p, psaddr_t offset,
|
||||
void *buf, size_t len)
|
||||
{
|
||||
struct ptrace_io_desc iorequest;
|
||||
|
||||
@@ -958,7 +959,7 @@ get_struct(pid_t pid, psaddr_t offset, void *buf, size_t len)
|
||||
iorequest.piod_offs = (void *)(uintptr_t)offset;
|
||||
iorequest.piod_addr = buf;
|
||||
iorequest.piod_len = len;
|
||||
if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
|
||||
if (truss_ptrace(info, PT_IO, p, (caddr_t)&iorequest, 0) < 0)
|
||||
return (-1);
|
||||
return (0);
|
||||
}
|
||||
@@ -971,7 +972,7 @@ get_struct(pid_t pid, psaddr_t offset, void *buf, size_t len)
|
||||
* only get that much.
|
||||
*/
|
||||
static char *
|
||||
get_string(pid_t pid, psaddr_t addr, int max)
|
||||
get_string(struct trussinfo *info, struct procinfo *p, psaddr_t addr, int max)
|
||||
{
|
||||
struct ptrace_io_desc iorequest;
|
||||
char *buf, *nbuf;
|
||||
@@ -995,7 +996,7 @@ get_string(pid_t pid, psaddr_t addr, int max)
|
||||
iorequest.piod_offs = (void *)((uintptr_t)addr + offset);
|
||||
iorequest.piod_addr = buf + offset;
|
||||
iorequest.piod_len = size;
|
||||
if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
|
||||
if (truss_ptrace(info, PT_IO, p, (caddr_t)&iorequest, 0) < 0) {
|
||||
free(buf);
|
||||
return (NULL);
|
||||
}
|
||||
@@ -1098,7 +1099,9 @@ print_sockaddr(FILE *fp, struct trussinfo *trussinfo, uintptr_t arg,
|
||||
struct sockaddr_un *sun;
|
||||
struct sockaddr *sa;
|
||||
u_char *q;
|
||||
pid_t pid = trussinfo->curthread->proc->pid;
|
||||
struct procinfo *p;
|
||||
|
||||
p = trussinfo->curthread->proc;
|
||||
|
||||
if (arg == 0) {
|
||||
fputs("NULL", fp);
|
||||
@@ -1111,7 +1114,7 @@ print_sockaddr(FILE *fp, struct trussinfo *trussinfo, uintptr_t arg,
|
||||
}
|
||||
|
||||
sa = calloc(1, len);
|
||||
if (get_struct(pid, arg, sa, len) == -1) {
|
||||
if (get_struct(trussinfo, p, arg, sa, len) == -1) {
|
||||
free(sa);
|
||||
print_pointer(fp, arg);
|
||||
return;
|
||||
@@ -1161,11 +1164,11 @@ print_sockaddr(FILE *fp, struct trussinfo *trussinfo, uintptr_t arg,
|
||||
static void
|
||||
print_iovec(FILE *fp, struct trussinfo *trussinfo, uintptr_t arg, int iovcnt)
|
||||
{
|
||||
struct procinfo *p;
|
||||
struct iovec iov[IOV_LIMIT];
|
||||
size_t max_string = trussinfo->strsize;
|
||||
char tmp2[max_string + 1], *tmp3;
|
||||
size_t len;
|
||||
pid_t pid = trussinfo->curthread->proc->pid;
|
||||
int i;
|
||||
bool buf_truncated, iov_truncated;
|
||||
|
||||
@@ -1179,7 +1182,9 @@ print_iovec(FILE *fp, struct trussinfo *trussinfo, uintptr_t arg, int iovcnt)
|
||||
} else {
|
||||
iov_truncated = false;
|
||||
}
|
||||
if (get_struct(pid, arg, &iov, iovcnt * sizeof(struct iovec)) == -1) {
|
||||
p = trussinfo->curthread->proc;
|
||||
if (get_struct(trussinfo, p, arg, &iov, iovcnt *
|
||||
sizeof(struct iovec)) == -1) {
|
||||
print_pointer(fp, arg);
|
||||
return;
|
||||
}
|
||||
@@ -1194,7 +1199,8 @@ print_iovec(FILE *fp, struct trussinfo *trussinfo, uintptr_t arg, int iovcnt)
|
||||
buf_truncated = false;
|
||||
}
|
||||
fprintf(fp, "%s{", (i > 0) ? "," : "");
|
||||
if (len && get_struct(pid, (uintptr_t)iov[i].iov_base, &tmp2, len) != -1) {
|
||||
if (len && get_struct(trussinfo, p, (uintptr_t)iov[i].iov_base,
|
||||
&tmp2, len) != -1) {
|
||||
tmp3 = malloc(len * 4 + 1);
|
||||
while (len) {
|
||||
if (strvisx(tmp3, tmp2, len,
|
||||
@@ -1466,7 +1472,8 @@ print_sctp_cmsg(FILE *fp, bool receive, struct cmsghdr *cmsghdr)
|
||||
}
|
||||
|
||||
static void
|
||||
print_cmsgs(FILE *fp, pid_t pid, bool receive, struct msghdr *msghdr)
|
||||
print_cmsgs(FILE *fp, struct trussinfo *info, struct procinfo *p,
|
||||
bool receive, struct msghdr *msghdr)
|
||||
{
|
||||
struct cmsghdr *cmsghdr;
|
||||
char *cmsgbuf;
|
||||
@@ -1481,7 +1488,8 @@ print_cmsgs(FILE *fp, pid_t pid, bool receive, struct msghdr *msghdr)
|
||||
return;
|
||||
}
|
||||
cmsgbuf = calloc(1, len);
|
||||
if (get_struct(pid, (uintptr_t)msghdr->msg_control, cmsgbuf, len) == -1) {
|
||||
if (get_struct(info, p, (uintptr_t)msghdr->msg_control, cmsgbuf,
|
||||
len) == -1) {
|
||||
print_pointer(fp, (uintptr_t)msghdr->msg_control);
|
||||
free(cmsgbuf);
|
||||
return;
|
||||
@@ -1599,7 +1607,7 @@ print_netlink(FILE *fp, struct trussinfo *trussinfo, void *msg, size_t len,
|
||||
int protocol)
|
||||
{
|
||||
char *buf;
|
||||
pid_t pid = trussinfo->curthread->proc->pid;
|
||||
struct procinfo *p;
|
||||
bool success = false;
|
||||
|
||||
if (msg == NULL || len == 0)
|
||||
@@ -1613,7 +1621,8 @@ print_netlink(FILE *fp, struct trussinfo *trussinfo, void *msg, size_t len,
|
||||
if (buf == NULL)
|
||||
return (false);
|
||||
|
||||
if (get_struct(pid, (uintptr_t)msg, buf, read_len) == -1) {
|
||||
p = trussinfo->curthread->proc;
|
||||
if (get_struct(trussinfo, p, (uintptr_t)msg, buf, read_len) == -1) {
|
||||
free(buf);
|
||||
return (false);
|
||||
}
|
||||
@@ -1637,12 +1646,12 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
struct trussinfo *trussinfo, struct syscall_decode *decode)
|
||||
{
|
||||
FILE *fp;
|
||||
struct procinfo *p;
|
||||
char *tmp;
|
||||
size_t tmplen;
|
||||
pid_t pid;
|
||||
|
||||
fp = open_memstream(&tmp, &tmplen);
|
||||
pid = trussinfo->curthread->proc->pid;
|
||||
p = trussinfo->curthread->proc;
|
||||
switch (sc->type & ARG_MASK) {
|
||||
case Hex:
|
||||
fprintf(fp, "0x%x", (int)args[sc->offset]);
|
||||
@@ -1659,7 +1668,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case PUInt: {
|
||||
unsigned int val;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &val,
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &val,
|
||||
sizeof(val)) == 0)
|
||||
fprintf(fp, "{ %u }", val);
|
||||
else
|
||||
@@ -1686,7 +1695,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
/* NULL-terminated string. */
|
||||
char *tmp2;
|
||||
|
||||
tmp2 = get_string(pid, args[sc->offset], 0);
|
||||
tmp2 = get_string(trussinfo, p, args[sc->offset], 0);
|
||||
fprintf(fp, "\"%s\"", tmp2);
|
||||
free(tmp2);
|
||||
break;
|
||||
@@ -1729,8 +1738,8 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
len = max_string;
|
||||
truncated = 1;
|
||||
}
|
||||
if (len && get_struct(pid, args[sc->offset], &tmp2, len)
|
||||
!= -1) {
|
||||
if (len && get_struct(trussinfo, p, args[sc->offset], &tmp2,
|
||||
len) != -1) {
|
||||
tmp3 = malloc(len * 4 + 1);
|
||||
while (len) {
|
||||
if (strvisx(tmp3, tmp2, len,
|
||||
@@ -1786,7 +1795,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
}
|
||||
|
||||
len = PAGE_SIZE - (addr & PAGE_MASK);
|
||||
if (get_struct(pid, addr, u.buf, len) == -1) {
|
||||
if (get_struct(trussinfo, p, addr, u.buf, len) == -1) {
|
||||
print_pointer(fp, args[sc->offset]);
|
||||
break;
|
||||
}
|
||||
@@ -1809,7 +1818,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
/* Stop once we read the first NULL pointer. */
|
||||
if (straddr == 0)
|
||||
break;
|
||||
string = get_string(pid, straddr, 0);
|
||||
string = get_string(trussinfo, p, straddr, 0);
|
||||
fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
|
||||
free(string);
|
||||
first = 0;
|
||||
@@ -1818,7 +1827,8 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
if (i == len / pointer_size) {
|
||||
addr += len;
|
||||
len = PAGE_SIZE;
|
||||
if (get_struct(pid, addr, u.buf, len) == -1) {
|
||||
if (get_struct(trussinfo, p, addr, u.buf,
|
||||
len) == -1) {
|
||||
fprintf(fp, ", <inval>");
|
||||
break;
|
||||
}
|
||||
@@ -1854,7 +1864,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case PQuadHex: {
|
||||
uint64_t val;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &val,
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &val,
|
||||
sizeof(val)) == 0)
|
||||
fprintf(fp, "{ 0x%jx }", (uintmax_t)val);
|
||||
else
|
||||
@@ -1869,7 +1879,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
|
||||
if (retval[0] == -1)
|
||||
break;
|
||||
tmp2 = get_string(pid, args[sc->offset], retval[0]);
|
||||
tmp2 = get_string(trussinfo, p, args[sc->offset], retval[0]);
|
||||
fprintf(fp, "\"%s\"", tmp2);
|
||||
free(tmp2);
|
||||
break;
|
||||
@@ -1894,7 +1904,8 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case Timespec: {
|
||||
struct timespec ts;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &ts, sizeof(ts)) != -1)
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &ts, sizeof(ts))
|
||||
!= -1)
|
||||
fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
|
||||
ts.tv_nsec);
|
||||
else
|
||||
@@ -1906,7 +1917,8 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
const char *sep;
|
||||
unsigned int i;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &ts, sizeof(ts)) != -1) {
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &ts, sizeof(ts))
|
||||
!= -1) {
|
||||
fputs("{ ", fp);
|
||||
sep = "";
|
||||
for (i = 0; i < nitems(ts); i++) {
|
||||
@@ -1934,7 +1946,8 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case Timeval: {
|
||||
struct timeval tv;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &tv, sizeof(tv)) != -1)
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &tv, sizeof(tv))
|
||||
!= -1)
|
||||
fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
|
||||
tv.tv_usec);
|
||||
else
|
||||
@@ -1944,7 +1957,8 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case Timeval2: {
|
||||
struct timeval tv[2];
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &tv, sizeof(tv)) != -1)
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &tv, sizeof(tv))
|
||||
!= -1)
|
||||
fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
|
||||
(intmax_t)tv[0].tv_sec, tv[0].tv_usec,
|
||||
(intmax_t)tv[1].tv_sec, tv[1].tv_usec);
|
||||
@@ -1955,7 +1969,8 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case Itimerval: {
|
||||
struct itimerval itv;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &itv, sizeof(itv)) != -1)
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &itv, sizeof(itv))
|
||||
!= -1)
|
||||
fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
|
||||
(intmax_t)itv.it_interval.tv_sec,
|
||||
itv.it_interval.tv_usec,
|
||||
@@ -1969,7 +1984,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
{
|
||||
struct linux_socketcall_args largs;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], (void *)&largs,
|
||||
if (get_struct(trussinfo, p, args[sc->offset], (void *)&largs,
|
||||
sizeof(largs)) != -1)
|
||||
fprintf(fp, "{ %s, 0x%lx }",
|
||||
lookup(linux_socketcall_ops, largs.what, 10),
|
||||
@@ -1992,7 +2007,8 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
if ((pfd = malloc(bytes)) == NULL)
|
||||
err(1, "Cannot malloc %zu bytes for pollfd array",
|
||||
bytes);
|
||||
if (get_struct(pid, args[sc->offset], pfd, bytes) != -1) {
|
||||
if (get_struct(trussinfo, p, args[sc->offset], pfd, bytes)
|
||||
!= -1) {
|
||||
fputs("{", fp);
|
||||
for (i = 0; i < numfds; i++) {
|
||||
fprintf(fp, " %d/%s", pfd[i].fd,
|
||||
@@ -2019,7 +2035,8 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
if ((fds = malloc(bytes)) == NULL)
|
||||
err(1, "Cannot malloc %zu bytes for fd_set array",
|
||||
bytes);
|
||||
if (get_struct(pid, args[sc->offset], fds, bytes) != -1) {
|
||||
if (get_struct(trussinfo, p, args[sc->offset], fds, bytes)
|
||||
!= -1) {
|
||||
fputs("{", fp);
|
||||
for (i = 0; i < numfds; i++) {
|
||||
if (FD_ISSET(i, fds))
|
||||
@@ -2038,7 +2055,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
sigset_t ss;
|
||||
int i, first;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], (void *)&ss,
|
||||
if (get_struct(trussinfo, p, args[sc->offset], (void *)&ss,
|
||||
sizeof(ss)) == -1) {
|
||||
print_pointer(fp, args[sc->offset]);
|
||||
break;
|
||||
@@ -2124,8 +2141,8 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
* the next argument contains a socklen_t by value.
|
||||
*/
|
||||
if (sc->type & OUT) {
|
||||
if (get_struct(pid, args[sc->offset + 1], &len,
|
||||
sizeof(len)) == -1) {
|
||||
if (get_struct(trussinfo, p, args[sc->offset + 1],
|
||||
&len, sizeof(len)) == -1) {
|
||||
print_pointer(fp, args[sc->offset]);
|
||||
break;
|
||||
}
|
||||
@@ -2138,7 +2155,8 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case Sigaction: {
|
||||
struct sigaction sa;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &sa, sizeof(sa)) != -1) {
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &sa, sizeof(sa))
|
||||
!= -1) {
|
||||
fputs("{ ", fp);
|
||||
if (sa.sa_handler == SIG_DFL)
|
||||
fputs("SIG_DFL", fp);
|
||||
@@ -2155,7 +2173,8 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case Sigevent: {
|
||||
struct sigevent se;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &se, sizeof(se)) != -1)
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &se, sizeof(se))
|
||||
!= -1)
|
||||
print_sigevent(fp, &se);
|
||||
else
|
||||
print_pointer(fp, args[sc->offset]);
|
||||
@@ -2187,7 +2206,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
bytes);
|
||||
} else
|
||||
ke = NULL;
|
||||
if (numevents >= 0 && get_struct(pid, args[sc->offset],
|
||||
if (numevents >= 0 && get_struct(trussinfo, p, args[sc->offset],
|
||||
ke, bytes) != -1) {
|
||||
fputc('{', fp);
|
||||
for (i = 0; i < numevents; i++) {
|
||||
@@ -2222,7 +2241,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
} else
|
||||
ke11 = NULL;
|
||||
memset(&ke, 0, sizeof(ke));
|
||||
if (numevents >= 0 && get_struct(pid, args[sc->offset],
|
||||
if (numevents >= 0 && get_struct(trussinfo, p, args[sc->offset],
|
||||
ke11, bytes) != -1) {
|
||||
fputc('{', fp);
|
||||
for (i = 0; i < numevents; i++) {
|
||||
@@ -2245,7 +2264,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case Stat: {
|
||||
struct stat st;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &st, sizeof(st))
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &st, sizeof(st))
|
||||
!= -1) {
|
||||
char mode[12];
|
||||
|
||||
@@ -2262,7 +2281,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case Stat11: {
|
||||
struct freebsd11_stat st;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &st, sizeof(st))
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &st, sizeof(st))
|
||||
!= -1) {
|
||||
char mode[12];
|
||||
|
||||
@@ -2280,7 +2299,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
unsigned int i;
|
||||
struct statfs buf;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &buf,
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &buf,
|
||||
sizeof(buf)) != -1) {
|
||||
char fsid[17];
|
||||
|
||||
@@ -2303,7 +2322,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case Rusage: {
|
||||
struct rusage ru;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &ru, sizeof(ru))
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &ru, sizeof(ru))
|
||||
!= -1) {
|
||||
fprintf(fp,
|
||||
"{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
|
||||
@@ -2317,7 +2336,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case Rlimit: {
|
||||
struct rlimit rl;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &rl, sizeof(rl))
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &rl, sizeof(rl))
|
||||
!= -1) {
|
||||
fprintf(fp, "{ cur=%ju,max=%ju }",
|
||||
rl.rlim_cur, rl.rlim_max);
|
||||
@@ -2328,7 +2347,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case ExitStatus: {
|
||||
int status;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &status,
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &status,
|
||||
sizeof(status)) != -1) {
|
||||
fputs("{ ", fp);
|
||||
if (WIFCONTINUED(status))
|
||||
@@ -2386,7 +2405,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
|
||||
memset(name, 0, sizeof(name));
|
||||
len = args[sc->offset + 1];
|
||||
if (get_struct(pid, args[sc->offset], oid,
|
||||
if (get_struct(trussinfo, p, args[sc->offset], oid,
|
||||
len * sizeof(oid[0])) != -1) {
|
||||
fprintf(fp, "\"");
|
||||
if (oid[0] == CTL_SYSCTL) {
|
||||
@@ -2404,7 +2423,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
break;
|
||||
case CTL_SYSCTL_NAME2OID:
|
||||
fprintf(fp, "name2oid %s",
|
||||
get_string(pid,
|
||||
get_string(trussinfo, p,
|
||||
args[sc->offset + 4],
|
||||
args[sc->offset + 5]));
|
||||
break;
|
||||
@@ -2454,7 +2473,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
|
||||
len = args[sc->offset + 1];
|
||||
utrace_addr = calloc(1, len);
|
||||
if (get_struct(pid, args[sc->offset],
|
||||
if (get_struct(trussinfo, p, args[sc->offset],
|
||||
(void *)utrace_addr, len) != -1)
|
||||
print_utrace(fp, utrace_addr, len);
|
||||
else
|
||||
@@ -2473,7 +2492,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
ndescriptors = nitems(descriptors);
|
||||
truncated = true;
|
||||
}
|
||||
if (get_struct(pid, args[sc->offset],
|
||||
if (get_struct(trussinfo, p, args[sc->offset],
|
||||
descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
|
||||
fprintf(fp, "{");
|
||||
for (i = 0; i < ndescriptors; i++)
|
||||
@@ -2491,7 +2510,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
uint32_t rights;
|
||||
|
||||
if (sc->type & OUT) {
|
||||
if (get_struct(pid, args[sc->offset], &rights,
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &rights,
|
||||
sizeof(rights)) == -1) {
|
||||
print_pointer(fp, args[sc->offset]);
|
||||
break;
|
||||
@@ -2587,7 +2606,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case CapRights: {
|
||||
cap_rights_t rights;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &rights,
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &rights,
|
||||
sizeof(rights)) != -1) {
|
||||
fputs("{ ", fp);
|
||||
sysdecode_cap_rights(fp, &rights);
|
||||
@@ -2629,8 +2648,8 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case Sendfilehdtr: {
|
||||
struct sf_hdtr hdtr;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &hdtr, sizeof(hdtr)) !=
|
||||
-1) {
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &hdtr,
|
||||
sizeof(hdtr)) != -1) {
|
||||
fprintf(fp, "{");
|
||||
print_iovec(fp, trussinfo, (uintptr_t)hdtr.headers,
|
||||
hdtr.hdr_cnt);
|
||||
@@ -2659,7 +2678,8 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case Schedparam: {
|
||||
struct sched_param sp;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &sp, sizeof(sp)) != -1)
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &sp,
|
||||
sizeof(sp)) != -1)
|
||||
fprintf(fp, "{ %d }", sp.sched_priority);
|
||||
else
|
||||
print_pointer(fp, args[sc->offset]);
|
||||
@@ -2668,7 +2688,8 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case PSig: {
|
||||
int sig;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &sig, sizeof(sig)) == 0)
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &sig,
|
||||
sizeof(sig)) == 0)
|
||||
fprintf(fp, "{ %s }", strsig2(sig));
|
||||
else
|
||||
print_pointer(fp, args[sc->offset]);
|
||||
@@ -2677,7 +2698,8 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case Siginfo: {
|
||||
siginfo_t si;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &si, sizeof(si)) != -1) {
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &si,
|
||||
sizeof(si)) != -1) {
|
||||
fprintf(fp, "{ signo=%s", strsig2(si.si_signo));
|
||||
decode_siginfo(fp, &si);
|
||||
fprintf(fp, " }");
|
||||
@@ -2697,7 +2719,8 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case Aiocb: {
|
||||
struct aiocb cb;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &cb, sizeof(cb)) != -1)
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &cb,
|
||||
sizeof(cb)) != -1)
|
||||
print_aiocb(fp, &cb);
|
||||
else
|
||||
print_pointer(fp, args[sc->offset]);
|
||||
@@ -2719,14 +2742,16 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
truncated = true;
|
||||
}
|
||||
|
||||
if (get_struct(pid, args[sc->offset], cbs, sizeof(uintptr_t) * nent) != -1) {
|
||||
if (get_struct(trussinfo, p, args[sc->offset], cbs,
|
||||
sizeof(uintptr_t) * nent) != -1) {
|
||||
unsigned int i;
|
||||
fputs("[", fp);
|
||||
for (i = 0; i < nent; ++i) {
|
||||
struct aiocb cb;
|
||||
if (i > 0)
|
||||
fputc(',', fp);
|
||||
if (get_struct(pid, cbs[i], &cb, sizeof(cb)) != -1)
|
||||
if (get_struct(trussinfo, p, cbs[i], &cb,
|
||||
sizeof(cb)) != -1)
|
||||
print_aiocb(fp, &cb);
|
||||
else
|
||||
print_pointer(fp, cbs[i]);
|
||||
@@ -2746,8 +2771,10 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
uintptr_t cbp;
|
||||
struct aiocb cb;
|
||||
|
||||
if (get_struct(pid, args[sc->offset], &cbp, sizeof(cbp)) != -1) {
|
||||
if (get_struct(pid, cbp, &cb, sizeof(cb)) != -1)
|
||||
if (get_struct(trussinfo, p, args[sc->offset], &cbp,
|
||||
sizeof(cbp)) != -1) {
|
||||
if (get_struct(trussinfo, p, cbp, &cb, sizeof(cb))
|
||||
!= -1)
|
||||
print_aiocb(fp, &cb);
|
||||
else
|
||||
print_pointer(fp, cbp);
|
||||
@@ -2758,7 +2785,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
case Sctpsndrcvinfo: {
|
||||
struct sctp_sndrcvinfo info;
|
||||
|
||||
if (get_struct(pid, args[sc->offset],
|
||||
if (get_struct(trussinfo, p, args[sc->offset],
|
||||
&info, sizeof(struct sctp_sndrcvinfo)) == -1) {
|
||||
print_pointer(fp, args[sc->offset]);
|
||||
break;
|
||||
@@ -2770,7 +2797,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
struct msghdr msghdr;
|
||||
struct iovec iov;
|
||||
|
||||
if (get_struct(pid, args[sc->offset],
|
||||
if (get_struct(trussinfo, p, args[sc->offset],
|
||||
&msghdr, sizeof(struct msghdr)) == -1) {
|
||||
print_pointer(fp, args[sc->offset]);
|
||||
break;
|
||||
@@ -2781,7 +2808,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
/* Attempt Netlink decode; fallback to standard iovec if it fails. */
|
||||
int protocol = get_netlink_protocol(trussinfo, (int)args[0]);
|
||||
if ((protocol == -1) ||
|
||||
(get_struct(pid, (uintptr_t)msghdr.msg_iov,
|
||||
(get_struct(trussinfo, p, (uintptr_t)msghdr.msg_iov,
|
||||
&iov, sizeof(iov)) == -1) ||
|
||||
(!print_netlink(fp, trussinfo, (void *)iov.iov_base,
|
||||
(size_t)iov.iov_len, protocol))) {
|
||||
@@ -2789,7 +2816,7 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
|
||||
msghdr.msg_iovlen);
|
||||
}
|
||||
fprintf(fp, ",%d,", msghdr.msg_iovlen);
|
||||
print_cmsgs(fp, pid, sc->type & OUT, &msghdr);
|
||||
print_cmsgs(fp, trussinfo, p, sc->type & OUT, &msghdr);
|
||||
fprintf(fp, ",%u,", msghdr.msg_controllen);
|
||||
print_mask_arg(sysdecode_msg_flags, fp, msghdr.msg_flags);
|
||||
fputs("}", fp);
|
||||
|
||||
+25
-2
@@ -7,7 +7,7 @@
|
||||
.Nd trace system calls
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl facedDHS
|
||||
.Op Fl facedyDHS
|
||||
.Op Fl o Ar file
|
||||
.Op Fl s Ar strsize
|
||||
.Op Fl t Ar expr
|
||||
@@ -28,6 +28,15 @@ Output is to the specified output file, or standard error by default.
|
||||
It does this by stopping and restarting the process being monitored via
|
||||
.Xr ptrace 2 .
|
||||
.Pp
|
||||
By default,
|
||||
.Nm
|
||||
enters the capability mode
|
||||
.Pq see Xr capsicum 4
|
||||
after opening the output file and creating and
|
||||
attaching to the target process.
|
||||
An error to enter the mode is not fatal, but a warning is
|
||||
issued to the standard error.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width indent
|
||||
.It Fl f
|
||||
@@ -66,6 +75,17 @@ Do not display information about signals received by the process.
|
||||
(Normally,
|
||||
.Nm
|
||||
displays signal as well as system call events.)
|
||||
.It Fl y
|
||||
Use the
|
||||
.Sq classic
|
||||
combination of
|
||||
.Xr ptrace 2
|
||||
and
|
||||
.Xr waitpid 2
|
||||
system calls to control the traced processes, instead of the
|
||||
process descriptors and kqueue PROCDESC filter
|
||||
.Pq see Xr pdfork 2 and Xr kqueue 2.
|
||||
Do not try to enter capability mode.
|
||||
.It Fl o Ar file
|
||||
Print the output to the specified
|
||||
.Ar file
|
||||
@@ -286,10 +306,13 @@ calls made while starting a program:
|
||||
.Xr dtrace 1 ,
|
||||
.Xr kdump 1 ,
|
||||
.Xr ktrace 1 ,
|
||||
.Xr pdfork 2 ,
|
||||
.Xr pdtrace 2 ,
|
||||
.Xr ptrace 2 ,
|
||||
.Xr utrace 2 ,
|
||||
.Xr fnmatch 3 ,
|
||||
.Xr sysdecode 3
|
||||
.Xr sysdecode 3 ,
|
||||
.Xr capsicum 4
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __TRUSS_TRUSS_H__
|
||||
#define __TRUSS_TRUSS_H__
|
||||
|
||||
#include <sys/queue.h>
|
||||
|
||||
#define FOLLOWFORKS 0x00000001
|
||||
@@ -106,7 +109,9 @@ struct fd_domain
|
||||
struct procinfo {
|
||||
LIST_ENTRY(procinfo) entries;
|
||||
pid_t pid;
|
||||
int pfd;
|
||||
struct procabi *abi;
|
||||
bool herald_printed;
|
||||
|
||||
LIST_HEAD(, threadinfo) threadlist;
|
||||
LIST_HEAD(, fd_domain) fdlist;
|
||||
@@ -117,6 +122,8 @@ struct trussinfo
|
||||
int flags;
|
||||
int strsize;
|
||||
FILE *outfile;
|
||||
int pdkq;
|
||||
bool cap_mode;
|
||||
|
||||
struct timespec start_time;
|
||||
|
||||
@@ -124,3 +131,5 @@ struct trussinfo
|
||||
|
||||
LIST_HEAD(, procinfo) proclist;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user