- Add decoding of kse_release, kevent, sigprocmask, unmount, socket, getrusage,
rename, __getcwd, shutdown, getrlimit, setrlimit, _umtx_lock, _umtx_unlock, pathconf, truncate, ftruncate, kill - Decode more arguments of open, mprot, *stat, and fcntl. - Convert all constant-macro and bitfield decoding to lookup tables; much cleaner than previous code. - Print the timestamp of process exit and signal reception when -d or -D are in use - Try six times with 1/2 second delay to debug the child PR: bin/52190 (updated) Submitted by: Dan Nelson <dnelson@allantgroup.com> Approved by: alfred
This commit is contained in:
parent
c46cb391cb
commit
081e5c4890
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=158630
@ -180,7 +180,8 @@ i386_syscall_entry(struct trussinfo *trussinfo, int nargs) {
|
||||
if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1)
|
||||
return;
|
||||
|
||||
sc = get_syscall(fsc.name);
|
||||
if (fsc.name)
|
||||
sc = get_syscall(fsc.name);
|
||||
if (sc) {
|
||||
fsc.nargs = sc->nargs;
|
||||
} else {
|
||||
@ -316,7 +317,7 @@ i386_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
|
||||
char *temp;
|
||||
if (sc->args[i].type & OUT) {
|
||||
/*
|
||||
* If an error occurred, than don't bothe getting the data;
|
||||
* If an error occurred, then don't bother getting the data;
|
||||
* it may not be valid.
|
||||
*/
|
||||
if (errorp)
|
||||
@ -328,6 +329,19 @@ i386_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The pipe syscall returns its fds in two registers and has assembly glue
|
||||
* to provide the libc API, so it cannot be handled like regular syscalls.
|
||||
* The nargs check is so we don't have to do yet another strcmp on every
|
||||
* syscall.
|
||||
*/
|
||||
if (!errorp && fsc.nargs == 0 && fsc.name && strcmp(fsc.name, "pipe") == 0) {
|
||||
fsc.nargs = 1;
|
||||
fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*));
|
||||
asprintf(&fsc.s_args[0], "[%d,%d]", (int)retval, regs.r_edx);
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* It would probably be a good idea to merge the error handling,
|
||||
* but that complicates things considerably.
|
||||
|
@ -180,7 +180,8 @@ i386_syscall_entry(struct trussinfo *trussinfo, int nargs) {
|
||||
if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1)
|
||||
return;
|
||||
|
||||
sc = get_syscall(fsc.name);
|
||||
if (fsc.name)
|
||||
sc = get_syscall(fsc.name);
|
||||
if (sc) {
|
||||
fsc.nargs = sc->nargs;
|
||||
} else {
|
||||
@ -316,7 +317,7 @@ i386_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
|
||||
char *temp;
|
||||
if (sc->args[i].type & OUT) {
|
||||
/*
|
||||
* If an error occurred, than don't bothe getting the data;
|
||||
* If an error occurred, then don't bother getting the data;
|
||||
* it may not be valid.
|
||||
*/
|
||||
if (errorp)
|
||||
@ -328,6 +329,19 @@ i386_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The pipe syscall returns its fds in two registers and has assembly glue
|
||||
* to provide the libc API, so it cannot be handled like regular syscalls.
|
||||
* The nargs check is so we don't have to do yet another strcmp on every
|
||||
* syscall.
|
||||
*/
|
||||
if (!errorp && fsc.nargs == 0 && fsc.name && strcmp(fsc.name, "pipe") == 0) {
|
||||
fsc.nargs = 1;
|
||||
fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*));
|
||||
asprintf(&fsc.s_args[0], "[%d,%d]", (int)retval, regs.r_edx);
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* It would probably be a good idea to merge the error handling,
|
||||
* but that complicates things considerably.
|
||||
|
@ -279,6 +279,7 @@ main(int ac, char **av)
|
||||
|
||||
do {
|
||||
int val = 0;
|
||||
struct timespec timediff;
|
||||
|
||||
if (ioctl(Procfd, PIOCWAIT, &pfs) == -1)
|
||||
warn("PIOCWAIT top of loop");
|
||||
@ -328,6 +329,23 @@ main(int ac, char **av)
|
||||
funcs->exit_syscall(trussinfo, pfs.val);
|
||||
break;
|
||||
case S_SIG:
|
||||
if (trussinfo->flags & FOLLOWFORKS)
|
||||
fprintf(trussinfo->outfile, "%5d: ",
|
||||
trussinfo->pid);
|
||||
if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
|
||||
timespecsubt(&trussinfo->after,
|
||||
&trussinfo->start_time, &timediff);
|
||||
fprintf(trussinfo->outfile, "%ld.%09ld ",
|
||||
(long)timediff.tv_sec,
|
||||
timediff.tv_nsec);
|
||||
}
|
||||
if (trussinfo->flags & RELATIVETIMESTAMPS) {
|
||||
timespecsubt(&trussinfo->after,
|
||||
&trussinfo->before, &timediff);
|
||||
fprintf(trussinfo->outfile, "%ld.%09ld ",
|
||||
(long)timediff.tv_sec,
|
||||
timediff.tv_nsec);
|
||||
}
|
||||
signame = strsig(pfs.val);
|
||||
fprintf(trussinfo->outfile,
|
||||
"SIGNAL %lu (%s)\n", pfs.val,
|
||||
@ -336,6 +354,22 @@ main(int ac, char **av)
|
||||
sigexit = pfs.val;
|
||||
break;
|
||||
case S_EXIT:
|
||||
if (trussinfo->flags & FOLLOWFORKS)
|
||||
fprintf(trussinfo->outfile, "%5d: ",
|
||||
trussinfo->pid);
|
||||
if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
|
||||
timespecsubt(&trussinfo->after,
|
||||
&trussinfo->start_time, &timediff);
|
||||
fprintf(trussinfo->outfile, "%ld.%09ld ",
|
||||
(long)timediff.tv_sec,
|
||||
timediff.tv_nsec);
|
||||
}
|
||||
if (trussinfo->flags & RELATIVETIMESTAMPS) {
|
||||
timespecsubt(&trussinfo->after,
|
||||
&trussinfo->before, &timediff);
|
||||
fprintf(trussinfo->outfile, "%ld.%09ld ",
|
||||
(long)timediff.tv_sec, timediff.tv_nsec);
|
||||
}
|
||||
fprintf(trussinfo->outfile,
|
||||
"process exit, rval = %lu\n", pfs.val);
|
||||
break;
|
||||
|
@ -71,6 +71,7 @@ setup_and_wait(char *command[])
|
||||
int fd;
|
||||
int pid;
|
||||
int flags;
|
||||
int loop;
|
||||
|
||||
pid = fork();
|
||||
if (pid == -1) {
|
||||
@ -108,15 +109,30 @@ setup_and_wait(char *command[])
|
||||
}
|
||||
|
||||
sprintf(buf, "/proc/%d/mem", pid);
|
||||
if ((fd = open(buf, O_RDWR)) == -1)
|
||||
err(5, "cannot open %s", buf);
|
||||
if (ioctl(fd, PIOCWAIT, &pfs) == -1)
|
||||
err(6, "PIOCWAIT");
|
||||
if (pfs.why == S_EXIT) {
|
||||
warnx("process exited before exec'ing");
|
||||
ioctl(fd, PIOCCONT, 0);
|
||||
wait(0);
|
||||
exit(7);
|
||||
|
||||
/* Try 6 times to trace our child, waiting 1/2 second each time */
|
||||
for (loop=6 ;; loop--) {
|
||||
if (loop != 6)
|
||||
usleep(500000);
|
||||
if ((fd = open(buf, O_RDWR)) == -1) {
|
||||
if (loop > 0)
|
||||
continue;
|
||||
else
|
||||
err(5, "cannot open1 %s", buf);
|
||||
}
|
||||
if (ioctl(fd, PIOCWAIT, &pfs) == -1) {
|
||||
if (loop >= 0)
|
||||
continue;
|
||||
else
|
||||
err(6, "PIOCWAIT");
|
||||
}
|
||||
if (pfs.why == S_EXIT) {
|
||||
warnx("process exited before exec'ing");
|
||||
ioctl(fd, PIOCCONT, 0);
|
||||
wait(0);
|
||||
exit(7);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
return (pid);
|
||||
@ -136,6 +152,7 @@ start_tracing(int pid, int failisfatal, int eventflags, int flags)
|
||||
struct procfs_status tmp;
|
||||
|
||||
sprintf(buf, "/proc/%d/mem", pid);
|
||||
/* usleep(500000); */
|
||||
|
||||
fd = open(buf, O_RDWR);
|
||||
if (fd == -1) {
|
||||
@ -146,7 +163,7 @@ start_tracing(int pid, int failisfatal, int eventflags, int flags)
|
||||
*/
|
||||
if (!failisfatal && kill(pid, 0) == -1)
|
||||
return (-1);
|
||||
err(8, "cannot open %s", buf);
|
||||
err(8, "cannot open2 %s", buf);
|
||||
}
|
||||
|
||||
if (ioctl(fd, PIOCSTATUS, &tmp) == -1) {
|
||||
|
@ -5,11 +5,10 @@
|
||||
* Hex -- values that should be printed in hex (addresses)
|
||||
* Octal -- Same as above, but octal
|
||||
* Int -- normal integer values (file descriptors, for example)
|
||||
* String -- pointers to sensible data. Note that we treat read() and
|
||||
* write() arguments as such, even though they may *not* be
|
||||
* printable data.
|
||||
* Ptr -- pointer to some specific structure. Just print as hex for now.
|
||||
* Stat -- a pointer to a stat buffer. Currently unused.
|
||||
* Name -- pointer to a NULL-terminated string.
|
||||
* BinString -- pointer to an array of chars, printed via strvisx().
|
||||
* Ptr -- pointer to some unspecified structure. Just print as hex for now.
|
||||
* Stat -- a pointer to a stat buffer. Prints a couple fields.
|
||||
* Ioctl -- an ioctl command. Woefully limited.
|
||||
* Quad -- a double-word value. e.g., lseek(int, offset_t, int)
|
||||
* Signal -- a signal number. Prints the signal name (SIGxxx)
|
||||
@ -17,10 +16,16 @@
|
||||
* StringArray -- a pointer to an array of string pointers.
|
||||
* Timespec -- a pointer to a struct timespec. Prints both elements.
|
||||
* Timeval -- a pointer to a struct timeval. Prints both elements.
|
||||
* Timeval2 -- a pointer to two struct timevals. Prints both elements of both.
|
||||
* Itimerval -- a pointer to a struct itimerval. Prints all elements.
|
||||
* Pollfd -- a pointer to an array of struct pollfd. Prints .fd and .events.
|
||||
* Fd_set -- a pointer to an array of fd_set. Prints the fds that are set.
|
||||
* Sigaction -- a pointer to a struct sigaction. Prints all elements.
|
||||
* Umtx -- a pointer to a struct umtx. Prints the value of owner.
|
||||
* Sigset -- a pointer to a sigset_t. Prints the signals that are set.
|
||||
* Sigprocmask -- the first argument to sigprocmask(). Prints the name.
|
||||
* Kevent -- a pointer to an array of struct kevents. Prints all elements.
|
||||
* Pathconf -- the 2nd argument of patchconf().
|
||||
*
|
||||
* In addition, the pointer types (String, Ptr) may have OUT masked in --
|
||||
* this means that the data is set on *return* from the system call -- or
|
||||
@ -30,9 +35,12 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
enum Argtype { None = 1, Hex, Octal, Int, Name, String, Ptr, Stat, Ioctl, Quad,
|
||||
Signal, Sockaddr, StringArray, Timespec, Timeval, Itimerval, Pollfd,
|
||||
Fd_set, Sigaction, Fcntl, Mprot, Mmapflags, Whence, Readlinkres };
|
||||
enum Argtype { None = 1, Hex, Octal, Int, Name, Ptr, Stat, Ioctl, Quad,
|
||||
Signal, Sockaddr, StringArray, Timespec, Timeval, Itimerval, Pollfd,
|
||||
Fd_set, Sigaction, Fcntl, Mprot, Mmapflags, Whence, Readlinkres,
|
||||
Umtx, Sigset, Sigprocmask, Kevent, Sockdomain, Socktype, Open,
|
||||
Fcntlflag, Rusage, BinString, Shutdown, Resource, Rlimit, Timeval2,
|
||||
Pathconf };
|
||||
|
||||
#define ARG_MASK 0xff
|
||||
#define OUT 0x100
|
||||
|
@ -46,6 +46,13 @@ static const char rcsid[] =
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/ioccom.h>
|
||||
#include <machine/atomic.h>
|
||||
#include <errno.h>
|
||||
#include <sys/umtx.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
@ -58,18 +65,19 @@ static const char rcsid[] =
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <vis.h>
|
||||
|
||||
#include "truss.h"
|
||||
#include "extern.h"
|
||||
#include "syscall.h"
|
||||
|
||||
/*
|
||||
* This should probably be in its own file.
|
||||
* This should probably be in its own file, sorted alphabetically.
|
||||
*/
|
||||
|
||||
struct syscall syscalls[] = {
|
||||
{ "fcntl", 1, 3,
|
||||
{ { Int, 0 } , { Fcntl, 1 }, { Hex, 2 }}},
|
||||
{ { Int, 0 } , { Fcntl, 1 }, { Fcntlflag | OUT, 2 }}},
|
||||
{ "readlink", 1, 3,
|
||||
{ { Name, 0 } , { Readlinkres | OUT, 1 }, { Int, 2 }}},
|
||||
{ "lseek", 2, 3,
|
||||
@ -89,7 +97,7 @@ struct syscall syscalls[] = {
|
||||
{ "mprotect", 1, 3,
|
||||
{ { Ptr, 0 }, {Int, 1}, {Mprot, 2}}},
|
||||
{ "open", 1, 3,
|
||||
{ { Name | IN, 0} , { Hex, 1}, {Octal, 2}}},
|
||||
{ { Name | IN, 0} , { Open, 1}, {Octal, 2}}},
|
||||
{ "mkdir", 1, 2,
|
||||
{ { Name, 0} , {Octal, 1}}},
|
||||
{ "linux_open", 1, 3,
|
||||
@ -115,17 +123,17 @@ struct syscall syscalls[] = {
|
||||
{ "umount", 0, 2,
|
||||
{ { Name, 0 }, { Int, 2 }}},
|
||||
{ "fstat", 1, 2,
|
||||
{ { Int, 0}, {Ptr | OUT , 1 }}},
|
||||
{ { Int, 0}, { Stat | OUT , 1 }}},
|
||||
{ "stat", 1, 2,
|
||||
{ { Name | IN, 0 }, { Ptr | OUT, 1 }}},
|
||||
{ { Name | IN, 0 }, { Stat | OUT, 1 }}},
|
||||
{ "lstat", 1, 2,
|
||||
{ { Name | IN, 0 }, { Ptr | OUT, 1 }}},
|
||||
{ { Name | IN, 0 }, { Stat | OUT, 1 }}},
|
||||
{ "linux_newstat", 1, 2,
|
||||
{ { Name | IN, 0 }, { Ptr | OUT, 1 }}},
|
||||
{ "linux_newfstat", 1, 2,
|
||||
{ { Int, 0 }, { Ptr | OUT, 1 }}},
|
||||
{ "write", 1, 3,
|
||||
{ { Int, 0 }, { String | IN, 1 }, { Int, 2 }}},
|
||||
{ { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }}},
|
||||
{ "ioctl", 1, 3,
|
||||
{ { Int, 0 }, { Ioctl, 1 }, { Hex, 2 }}},
|
||||
{ "break", 1, 1, { { Hex, 0 }}},
|
||||
@ -134,19 +142,19 @@ struct syscall syscalls[] = {
|
||||
{ "sigaction", 1, 3,
|
||||
{ { Signal, 0 }, { Sigaction | IN, 1 }, { Sigaction | OUT, 2 }}},
|
||||
{ "accept", 1, 3,
|
||||
{ { Hex, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
|
||||
{ { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
|
||||
{ "bind", 1, 3,
|
||||
{ { Hex, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
|
||||
{ { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
|
||||
{ "connect", 1, 3,
|
||||
{ { Hex, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
|
||||
{ { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
|
||||
{ "getpeername", 1, 3,
|
||||
{ { Hex, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
|
||||
{ { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
|
||||
{ "getsockname", 1, 3,
|
||||
{ { Hex, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
|
||||
{ { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
|
||||
{ "recvfrom", 1, 6,
|
||||
{ { Hex, 0 }, { Ptr | IN, 1 }, { Int, 3 }, { Hex, 3 }, { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } },
|
||||
{ { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, { Hex, 3 }, { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } },
|
||||
{ "sendto", 1, 6,
|
||||
{ { Hex, 0 }, { Ptr | IN, 1 }, { Int, 3 }, { Hex, 3 }, { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } },
|
||||
{ { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, { Hex, 3 }, { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } },
|
||||
{ "execve", 1, 3,
|
||||
{ { Name | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } },
|
||||
{ "linux_execve", 1, 3,
|
||||
@ -161,24 +169,43 @@ struct syscall syscalls[] = {
|
||||
{ "select", 1, 5, { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 }, { Timeval, 4 }}},
|
||||
{ "poll", 1, 3, { { Pollfd, 0 }, { Int, 1 }, { Int, 2 }}},
|
||||
{ "gettimeofday", 1, 2, { { Timeval | OUT, 0 }, { Ptr, 1 }}},
|
||||
{ "clock_gettime", 1, 2, { { Int, 0 }, { Timeval | OUT, 1 }}},
|
||||
{ "recvfrom", 1, 6, { { Int, 0 }, { Ptr | OUT, 1 }, { Int, 2 }, { Int, 3 }, { Sockaddr | OUT, 4}, {Ptr | OUT, 5}}},
|
||||
{ "clock_gettime", 1, 2, { { Int, 0 }, { Timespec | OUT, 1 }}},
|
||||
{ "getitimer", 1, 2, { { Int, 0 }, { Itimerval | OUT, 2 }}},
|
||||
{ "setitimer", 1, 3, { { Int, 0 }, { Itimerval, 1} , { Itimerval | OUT, 2 }}},
|
||||
{ "kse_release", 0, 1, { { Timespec, 0 }}},
|
||||
{ "kevent", 0, 6, { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 }, { Int, 4 }, { Timespec, 5 }}},
|
||||
{ "_umtx_lock", 0, 1, { { Umtx, 0 }}},
|
||||
{ "_umtx_unlock", 0, 1, { { Umtx, 0 }}},
|
||||
{ "sigprocmask", 0, 3, { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 }}},
|
||||
{ "unmount", 1, 2, { { Name, 0 }, { Int, 1 }}},
|
||||
{ "socket", 1, 3, { { Sockdomain, 0}, { Socktype, 1}, {Int, 2 }}},
|
||||
{ "getrusage", 1, 2, { { Int, 0 }, { Rusage | OUT, 1 }}},
|
||||
{ "__getcwd", 1, 2, { { Name | OUT, 0}, { Int, 1 }}},
|
||||
{ "shutdown", 1, 2, { { Int, 0}, { Shutdown, 1}}},
|
||||
{ "getrlimit", 1, 2, { { Resource, 0}, {Rlimit | OUT, 1}}},
|
||||
{ "setrlimit", 1, 2, { { Resource, 0}, {Rlimit | IN, 1}}},
|
||||
{ "utimes", 1, 2,
|
||||
{ { Name | IN, 0 }, { Timeval | IN, 1 }}},
|
||||
{ { Name | IN, 0 }, { Timeval2 | IN, 1 }}},
|
||||
{ "lutimes", 1, 2,
|
||||
{ { Name | IN, 0 }, { Timeval | IN, 1 }}},
|
||||
{ { Name | IN, 0 }, { Timeval2 | IN, 1 }}},
|
||||
{ "futimes", 1, 2,
|
||||
{ { Int, 0 }, { Timeval | IN, 1 }}},
|
||||
{ "chflags", 1, 2,
|
||||
{ { Name | IN, 0 }, { Hex, 1 }}},
|
||||
{ "lchflags", 1, 2,
|
||||
{ { Name | IN, 0 }, { Hex, 1 }}},
|
||||
{ "pathconf", 1, 2,
|
||||
{ { Name | IN, 0 }, { Pathconf, 1 }}},
|
||||
{ "truncate", 1, 3,
|
||||
{ { Name | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 }}},
|
||||
{ "ftruncate", 1, 3,
|
||||
{ { Int | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 }}},
|
||||
{ "kill", 1, 2,
|
||||
{ { Int | IN, 0 }, { Signal | IN, 1}}},
|
||||
{ "munmap", 1, 2,
|
||||
{ { Ptr, 0 }, { Int, 1 }}},
|
||||
{ "read", 1, 3,
|
||||
{ { Int, 0}, { String | OUT, 1}, { Int, 2}}},
|
||||
{ { Int, 0}, { BinString | OUT, 1}, { Int, 2}}},
|
||||
{ "rename", 1, 2,
|
||||
{ { Name , 0} , { Name, 1}}},
|
||||
{ "symlink", 1, 2,
|
||||
@ -186,6 +213,175 @@ struct syscall syscalls[] = {
|
||||
{ 0, 0, 0, { { 0, 0 }}},
|
||||
};
|
||||
|
||||
/* Xlat idea taken from strace */
|
||||
struct xlat {
|
||||
int val;
|
||||
char *str;
|
||||
};
|
||||
|
||||
#define X(a) { a, #a },
|
||||
#define XEND { 0, NULL }
|
||||
|
||||
static struct xlat kevent_filters[] = {
|
||||
X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE)
|
||||
X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER)
|
||||
X(EVFILT_NETDEV) X(EVFILT_FS) X(EVFILT_READ) XEND
|
||||
};
|
||||
|
||||
static struct xlat kevent_flags[] = {
|
||||
X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT)
|
||||
X(EV_CLEAR) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
|
||||
};
|
||||
|
||||
struct xlat poll_flags[] = {
|
||||
X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
|
||||
X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
|
||||
X(POLLWRBAND) X(POLLINIGNEOF) XEND
|
||||
};
|
||||
|
||||
static struct xlat mmap_flags[] = {
|
||||
X(MAP_SHARED) X(MAP_PRIVATE) X(MAP_FIXED) X(MAP_RENAME)
|
||||
X(MAP_NORESERVE) X(MAP_RESERVED0080) X(MAP_RESERVED0100)
|
||||
X(MAP_HASSEMAPHORE) X(MAP_STACK) X(MAP_NOSYNC) X(MAP_ANON)
|
||||
X(MAP_NOCORE) XEND
|
||||
};
|
||||
|
||||
static struct xlat mprot_flags[] = {
|
||||
X(PROT_NONE) X(PROT_READ) X(PROT_WRITE) X(PROT_EXEC) XEND
|
||||
};
|
||||
|
||||
static struct xlat whence_arg[] = {
|
||||
X(SEEK_SET) X(SEEK_CUR) X(SEEK_END) XEND
|
||||
};
|
||||
|
||||
static struct xlat sigaction_flags[] = {
|
||||
X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
|
||||
X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
|
||||
};
|
||||
|
||||
static struct xlat fcntl_arg[] = {
|
||||
X(F_DUPFD) X(F_GETFD) X(F_SETFD) X(F_GETFL) X(F_SETFL)
|
||||
X(F_GETOWN) X(F_SETOWN) X(F_GETLK) X(F_SETLK) X(F_SETLKW) XEND
|
||||
};
|
||||
|
||||
static struct xlat fcntlfd_arg[] = {
|
||||
X(FD_CLOEXEC) XEND
|
||||
};
|
||||
|
||||
static struct xlat fcntlfl_arg[] = {
|
||||
X(O_APPEND) X(O_ASYNC) X(O_FSYNC) X(O_NONBLOCK) X(O_NOFOLLOW)
|
||||
X(O_DIRECT) XEND
|
||||
};
|
||||
|
||||
static struct xlat sockdomain_arg[] = {
|
||||
X(PF_UNSPEC) X(PF_LOCAL) X(PF_UNIX) X(PF_INET) X(PF_IMPLINK)
|
||||
X(PF_PUP) X(PF_CHAOS) X(PF_NETBIOS) X(PF_ISO) X(PF_OSI)
|
||||
X(PF_ECMA) X(PF_DATAKIT) X(PF_CCITT) X(PF_SNA) X(PF_DECnet)
|
||||
X(PF_DLI) X(PF_LAT) X(PF_HYLINK) X(PF_APPLETALK) X(PF_ROUTE)
|
||||
X(PF_LINK) X(PF_XTP) X(PF_COIP) X(PF_CNT) X(PF_SIP) X(PF_IPX)
|
||||
X(PF_RTIP) X(PF_PIP) X(PF_ISDN) X(PF_KEY) X(PF_INET6)
|
||||
X(PF_NATM) X(PF_ATM) X(PF_NETGRAPH) X(PF_SLOW) X(PF_SCLUSTER)
|
||||
X(PF_ARP) X(PF_BLUETOOTH) XEND
|
||||
};
|
||||
|
||||
static struct xlat socktype_arg[] = {
|
||||
X(SOCK_STREAM) X(SOCK_DGRAM) X(SOCK_RAW) X(SOCK_RDM)
|
||||
X(SOCK_SEQPACKET) XEND
|
||||
};
|
||||
|
||||
static struct xlat open_flags[] = {
|
||||
X(O_RDONLY) X(O_WRONLY) X(O_RDWR) X(O_ACCMODE) X(O_NONBLOCK)
|
||||
X(O_APPEND) X(O_SHLOCK) X(O_EXLOCK) X(O_ASYNC) X(O_FSYNC)
|
||||
X(O_NOFOLLOW) X(O_CREAT) X(O_TRUNC) X(O_EXCL) X(O_NOCTTY)
|
||||
X(O_DIRECT) XEND
|
||||
};
|
||||
|
||||
static struct xlat shutdown_arg[] = {
|
||||
X(SHUT_RD) X(SHUT_WR) X(SHUT_RDWR) XEND
|
||||
};
|
||||
|
||||
static struct xlat resource_arg[] = {
|
||||
X(RLIMIT_CPU) X(RLIMIT_FSIZE) X(RLIMIT_DATA) X(RLIMIT_STACK)
|
||||
X(RLIMIT_CORE) X(RLIMIT_RSS) X(RLIMIT_MEMLOCK) X(RLIMIT_NPROC)
|
||||
X(RLIMIT_NOFILE) X(RLIMIT_SBSIZE) X(RLIMIT_VMEM) XEND
|
||||
};
|
||||
|
||||
static struct xlat pathconf_arg[] = {
|
||||
X(_PC_LINK_MAX) X(_PC_MAX_CANON) X(_PC_MAX_INPUT)
|
||||
X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF)
|
||||
X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE)
|
||||
X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO)
|
||||
X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS)
|
||||
X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE)
|
||||
X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN)
|
||||
X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX)
|
||||
X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT)
|
||||
XEND
|
||||
};
|
||||
|
||||
#undef X
|
||||
#undef XEND
|
||||
|
||||
/* Searches an xlat array for a value, and returns it if found. Otherwise
|
||||
return a string representation. */
|
||||
char *lookup(struct xlat *xlat, int val, int base)
|
||||
{
|
||||
static char tmp[16];
|
||||
for (; xlat->str != NULL; xlat++)
|
||||
if (xlat->val == val)
|
||||
return xlat->str;
|
||||
switch (base) {
|
||||
case 8:
|
||||
sprintf(tmp, "0%o", val);
|
||||
break;
|
||||
case 16:
|
||||
sprintf(tmp, "0x%x", val);
|
||||
break;
|
||||
case 10:
|
||||
sprintf(tmp, "%u", val);
|
||||
break;
|
||||
default:
|
||||
errx(1,"Unknown lookup base");
|
||||
break;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
char *xlookup(struct xlat *xlat, int val)
|
||||
{
|
||||
return lookup(xlat, val, 16);
|
||||
}
|
||||
|
||||
/* Searches an xlat array containing bitfield values. Remaining bits
|
||||
set after removing the known ones are printed at the end:
|
||||
IN|0x400 */
|
||||
char *xlookup_bits(struct xlat *xlat, int val)
|
||||
{
|
||||
static char str[512];
|
||||
int len = 0;
|
||||
int rem = val;
|
||||
|
||||
for (; xlat->str != NULL; xlat++)
|
||||
{
|
||||
if ((xlat->val & rem) == xlat->val)
|
||||
{
|
||||
/* don't print the "all-bits-zero" string unless all
|
||||
bits are really zero */
|
||||
if (xlat->val == 0 && val != 0)
|
||||
continue;
|
||||
len += sprintf(str + len, "%s|", xlat->str);
|
||||
rem &= ~(xlat->val);
|
||||
}
|
||||
}
|
||||
/* if we have leftover bits or didn't match anything */
|
||||
if (rem || len == 0)
|
||||
len += sprintf(str + len, "0x%x", rem);
|
||||
if (len && str[len - 1] == '|')
|
||||
len--;
|
||||
str[len] = 0;
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* If/when the list gets big, it might be desirable to do it
|
||||
* as a hash table or binary search.
|
||||
@ -262,19 +458,6 @@ get_string(int procfd, void *offset, int max) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Remove a trailing '|' in a string, useful for fixup after decoding
|
||||
* a "flags" argument.
|
||||
*/
|
||||
|
||||
void
|
||||
remove_trailing_or(char *str)
|
||||
{
|
||||
|
||||
if (str != NULL && (str = rindex(str, '|')) != NULL && str[1] == '\0')
|
||||
*str = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* print_arg
|
||||
* Converts a syscall argument into a string. Said string is
|
||||
@ -288,7 +471,6 @@ remove_trailing_or(char *str)
|
||||
char *
|
||||
print_arg(int fd, struct syscall_args *sc, unsigned long *args, long retval, struct trussinfo *trussinfo) {
|
||||
char *tmp = NULL;
|
||||
int max = 0;
|
||||
|
||||
switch (sc->type & ARG_MASK) {
|
||||
case Hex:
|
||||
@ -300,24 +482,52 @@ print_arg(int fd, struct syscall_args *sc, unsigned long *args, long retval, str
|
||||
case Int:
|
||||
asprintf(&tmp, "%ld", args[sc->offset]);
|
||||
break;
|
||||
case String:
|
||||
max = trussinfo->strsize;
|
||||
if (max == 0)
|
||||
{
|
||||
asprintf(&tmp, "0x%lx", args[sc->offset]);
|
||||
break;
|
||||
}
|
||||
case Name:
|
||||
{
|
||||
/* NULL-terminated string. */
|
||||
char *tmp2;
|
||||
tmp2 = get_string(fd, (void*)args[sc->offset], max ? max + 1 : 0);
|
||||
if (max && memchr(tmp2, '\0', max + 1) == NULL)
|
||||
asprintf(&tmp, "\"%.*s...\"", max, tmp2);
|
||||
else
|
||||
asprintf(&tmp, "\"%s\"", tmp2);
|
||||
tmp2 = get_string(fd, (void*)args[sc->offset], 0);
|
||||
asprintf(&tmp, "\"%s\"", tmp2);
|
||||
free(tmp2);
|
||||
}
|
||||
break;
|
||||
case BinString:
|
||||
{
|
||||
/* Binary block of data that might have printable characters.
|
||||
XXX If type|OUT, assume that the length is the syscall's
|
||||
return value. Otherwise, assume that the length of the block
|
||||
is in the next syscall argument. */
|
||||
int max_string = trussinfo->strsize;
|
||||
char tmp2[max_string+1], *tmp3;
|
||||
int len;
|
||||
int truncated = 0;
|
||||
|
||||
if (sc->type & OUT)
|
||||
len = retval;
|
||||
else
|
||||
len = args[sc->offset + 1];
|
||||
|
||||
/* Don't print more than max_string characters, to avoid word
|
||||
wrap. If we have to truncate put some ... after the string.
|
||||
*/
|
||||
if (len > max_string) {
|
||||
len = max_string;
|
||||
truncated = 1;
|
||||
}
|
||||
if (len && get_struct(fd, (void*)args[sc->offset], &tmp2, len) != -1) {
|
||||
tmp3 = malloc(len * 4 + 1);
|
||||
while (len) {
|
||||
if (strvisx(tmp3, tmp2, len, VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
|
||||
break;
|
||||
len--;
|
||||
truncated = 1;
|
||||
};
|
||||
asprintf(&tmp, "\"%s\"%s", tmp3, truncated?"...":"");
|
||||
free(tmp3);
|
||||
} else
|
||||
asprintf(&tmp, "0x%lx", args[sc->offset]);
|
||||
}
|
||||
break;
|
||||
case StringArray:
|
||||
{
|
||||
int num, size, i;
|
||||
@ -384,7 +594,22 @@ print_arg(int fd, struct syscall_args *sc, unsigned long *args, long retval, str
|
||||
{
|
||||
const char *temp = ioctlname(args[sc->offset]);
|
||||
if (temp)
|
||||
tmp = strdup(temp);
|
||||
tmp = strdup(temp);
|
||||
else
|
||||
{
|
||||
unsigned long arg = args[sc->offset];
|
||||
asprintf(&tmp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu}", arg,
|
||||
arg&IOC_OUT?"R":"", arg&IOC_IN?"W":"",
|
||||
IOCGROUP(arg), isprint(IOCGROUP(arg))?(char)IOCGROUP(arg):'?',
|
||||
arg & 0xFF, IOCPARM_LEN(arg));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Umtx:
|
||||
{
|
||||
struct umtx umtx;
|
||||
if (get_struct(fd, (void *)args[sc->offset], &umtx, sizeof(umtx)) != -1)
|
||||
asprintf(&tmp, "{0x%lx}", (long)umtx.u_owner);
|
||||
else
|
||||
asprintf(&tmp, "0x%lx", args[sc->offset]);
|
||||
}
|
||||
@ -393,7 +618,7 @@ print_arg(int fd, struct syscall_args *sc, unsigned long *args, long retval, str
|
||||
{
|
||||
struct timespec ts;
|
||||
if (get_struct(fd, (void *)args[sc->offset], &ts, sizeof(ts)) != -1)
|
||||
asprintf(&tmp, "{%jd %jd}", (intmax_t)ts.tv_sec, (intmax_t)ts.tv_nsec);
|
||||
asprintf(&tmp, "{%ld.%09ld}", (long)ts.tv_sec, ts.tv_nsec);
|
||||
else
|
||||
asprintf(&tmp, "0x%lx", args[sc->offset]);
|
||||
}
|
||||
@ -402,7 +627,18 @@ print_arg(int fd, struct syscall_args *sc, unsigned long *args, long retval, str
|
||||
{
|
||||
struct timeval tv;
|
||||
if (get_struct(fd, (void *)args[sc->offset], &tv, sizeof(tv)) != -1)
|
||||
asprintf(&tmp, "{%jd %jd}", (intmax_t)tv.tv_sec, (intmax_t)tv.tv_usec);
|
||||
asprintf(&tmp, "{%ld.%06ld}", (long)tv.tv_sec, tv.tv_usec);
|
||||
else
|
||||
asprintf(&tmp, "0x%lx", args[sc->offset]);
|
||||
}
|
||||
break;
|
||||
case Timeval2:
|
||||
{
|
||||
struct timeval tv[2];
|
||||
if (get_struct(fd, (void *)args[sc->offset], &tv, sizeof(tv)) != -1)
|
||||
asprintf(&tmp, "{%ld.%06ld, %ld.%06ld}",
|
||||
(long)tv[0].tv_sec, tv[0].tv_usec,
|
||||
(long)tv[1].tv_sec, tv[1].tv_usec);
|
||||
else
|
||||
asprintf(&tmp, "0x%lx", args[sc->offset]);
|
||||
}
|
||||
@ -411,11 +647,11 @@ print_arg(int fd, struct syscall_args *sc, unsigned long *args, long retval, str
|
||||
{
|
||||
struct itimerval itv;
|
||||
if (get_struct(fd, (void *)args[sc->offset], &itv, sizeof(itv)) != -1)
|
||||
asprintf(&tmp, "{%jd %jd, %jd %jd}",
|
||||
(intmax_t)itv.it_interval.tv_sec,
|
||||
(intmax_t)itv.it_interval.tv_usec,
|
||||
(intmax_t)itv.it_value.tv_sec,
|
||||
(intmax_t)itv.it_value.tv_usec);
|
||||
asprintf(&tmp, "{%ld.%06ld, %ld.%06ld}",
|
||||
(long)itv.it_interval.tv_sec,
|
||||
itv.it_interval.tv_usec,
|
||||
(long)itv.it_value.tv_sec,
|
||||
itv.it_value.tv_usec);
|
||||
else
|
||||
asprintf(&tmp, "0x%lx", args[sc->offset]);
|
||||
}
|
||||
@ -443,24 +679,12 @@ print_arg(int fd, struct syscall_args *sc, unsigned long *args, long retval, str
|
||||
|
||||
tmp[used++] = '{';
|
||||
for (i = 0; i < numfds; i++) {
|
||||
#define POLLKNOWN_EVENTS \
|
||||
(POLLIN | POLLPRI | POLLOUT | POLLERR | POLLHUP | POLLNVAL | \
|
||||
POLLRDNORM |POLLRDBAND | POLLWRBAND | POLLINIGNEOF)
|
||||
|
||||
u = snprintf(tmp + used, per_fd,
|
||||
"%s%d 0x%hx%s%s%s%s%s%s%s%s%s ",
|
||||
"%s%d/%s",
|
||||
i > 0 ? " " : "",
|
||||
pfd[i].fd,
|
||||
pfd[i].events & ~POLLKNOWN_EVENTS,
|
||||
pfd[i].events & POLLIN ? "" : "|IN",
|
||||
pfd[i].events & POLLPRI ? "" : "|PRI",
|
||||
pfd[i].events & POLLOUT ? "" : "|OUT",
|
||||
pfd[i].events & POLLERR ? "" : "|ERR",
|
||||
pfd[i].events & POLLHUP ? "" : "|HUP",
|
||||
pfd[i].events & POLLNVAL ? "" : "|NVAL",
|
||||
pfd[i].events & POLLRDNORM ? "" : "|RDNORM",
|
||||
pfd[i].events & POLLRDBAND ? "" : "|RDBAND",
|
||||
pfd[i].events & POLLWRBAND ? "" : "|WRBAND");
|
||||
xlookup_bits(poll_flags, pfd[i].events) );
|
||||
if (u > 0)
|
||||
used += u < per_fd ? u : per_fd;
|
||||
}
|
||||
@ -518,63 +742,98 @@ print_arg(int fd, struct syscall_args *sc, unsigned long *args, long retval, str
|
||||
asprintf(&tmp, "%ld", sig);
|
||||
}
|
||||
break;
|
||||
case Fcntl:
|
||||
case Sigset:
|
||||
{
|
||||
long sig;
|
||||
sigset_t ss;
|
||||
int i, used;
|
||||
|
||||
sig = args[sc->offset];
|
||||
if (get_struct(fd, (void *)args[sc->offset], (void *)&ss,
|
||||
sizeof(ss)) == -1)
|
||||
{
|
||||
asprintf(&tmp, "0x%lx", args[sc->offset]);
|
||||
break;
|
||||
}
|
||||
tmp = malloc(sys_nsig * 8); /* 7 bytes avg per signal name */
|
||||
used = 0;
|
||||
for (i = 1; i < sys_nsig; i++)
|
||||
{
|
||||
if (sigismember(&ss, i))
|
||||
{
|
||||
used += sprintf(tmp + used, "%s|", strsig(i));
|
||||
}
|
||||
}
|
||||
if(used)
|
||||
tmp[used-1] = 0;
|
||||
else
|
||||
strcpy(tmp, "0x0");
|
||||
}
|
||||
break;
|
||||
case Sigprocmask:
|
||||
{
|
||||
switch (args[sc->offset]) {
|
||||
#define S(a) case a: tmp = strdup(#a); break;
|
||||
S(F_DUPFD);
|
||||
S(F_GETFD);
|
||||
S(F_SETFD);
|
||||
S(F_GETFL);
|
||||
S(F_SETFL);
|
||||
S(F_GETOWN);
|
||||
S(F_SETOWN);
|
||||
S(F_GETLK);
|
||||
S(F_SETLK);
|
||||
S(F_SETLKW);
|
||||
S(SIG_BLOCK);
|
||||
S(SIG_UNBLOCK);
|
||||
S(SIG_SETMASK);
|
||||
#undef S
|
||||
}
|
||||
if (tmp == NULL)
|
||||
asprintf(&tmp, "0x%lx", args[sc->offset]);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case Fcntlflag:
|
||||
{
|
||||
/* XXX output depends on the value of the previous argument */
|
||||
switch (args[sc->offset-1]) {
|
||||
case F_SETFD:
|
||||
tmp = strdup(xlookup_bits(fcntlfd_arg, args[sc->offset]));
|
||||
break;
|
||||
case F_SETFL:
|
||||
tmp = strdup(xlookup_bits(fcntlfl_arg, args[sc->offset]));
|
||||
break;
|
||||
case F_GETFD:
|
||||
case F_GETFL:
|
||||
case F_GETOWN:
|
||||
tmp = strdup("");
|
||||
break;
|
||||
default:
|
||||
asprintf(&tmp, "0x%lx", args[sc->offset]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Open:
|
||||
tmp = strdup(xlookup_bits(open_flags, args[sc->offset]));
|
||||
break;
|
||||
case Fcntl:
|
||||
tmp = strdup(xlookup(fcntl_arg, args[sc->offset]));
|
||||
break;
|
||||
case Mprot:
|
||||
{
|
||||
|
||||
#define S(a) ((args[sc->offset] & a) ? #a "|" : "")
|
||||
asprintf(&tmp, "(0x%lx)%s%s%s%s", args[sc->offset],
|
||||
S(PROT_NONE), S(PROT_READ), S(PROT_WRITE), S(PROT_EXEC));
|
||||
#undef S
|
||||
remove_trailing_or(tmp);
|
||||
|
||||
}
|
||||
tmp = strdup(xlookup_bits(mprot_flags, args[sc->offset]));
|
||||
break;
|
||||
|
||||
case Mmapflags:
|
||||
{
|
||||
#define S(a) ((args[sc->offset] & a) ? #a "|" : "")
|
||||
asprintf(&tmp, "(0x%lx)%s%s%s%s%s%s%s%s", args[sc->offset],
|
||||
S(MAP_ANON), S(MAP_FIXED), S(MAP_HASSEMAPHORE),
|
||||
S(MAP_NOCORE), S(MAP_NOSYNC), S(MAP_PRIVATE),
|
||||
S(MAP_SHARED), S(MAP_STACK));
|
||||
#undef S
|
||||
|
||||
remove_trailing_or(tmp);
|
||||
}
|
||||
tmp = strdup(xlookup_bits(mmap_flags, args[sc->offset]));
|
||||
break;
|
||||
|
||||
case Whence:
|
||||
{
|
||||
switch (args[sc->offset]) {
|
||||
#define S(a) case a: tmp = strdup(#a); break;
|
||||
S(SEEK_SET);
|
||||
S(SEEK_CUR);
|
||||
S(SEEK_END);
|
||||
#undef S
|
||||
default: asprintf(&tmp, "0x%lx", args[sc->offset]); break;
|
||||
}
|
||||
}
|
||||
tmp = strdup(xlookup(whence_arg, args[sc->offset]));
|
||||
break;
|
||||
case Sockdomain:
|
||||
tmp = strdup(xlookup(sockdomain_arg, args[sc->offset]));
|
||||
break;
|
||||
case Socktype:
|
||||
tmp = strdup(xlookup(socktype_arg, args[sc->offset]));
|
||||
break;
|
||||
case Shutdown:
|
||||
tmp = strdup(xlookup(shutdown_arg, args[sc->offset]));
|
||||
break;
|
||||
case Resource:
|
||||
tmp = strdup(xlookup(resource_arg, args[sc->offset]));
|
||||
break;
|
||||
case Pathconf:
|
||||
tmp = strdup(xlookup(pathconf_arg, args[sc->offset]));
|
||||
break;
|
||||
case Sockaddr:
|
||||
{
|
||||
@ -653,10 +912,6 @@ print_arg(int fd, struct syscall_args *sc, unsigned long *args, long retval, str
|
||||
struct sigaction sa;
|
||||
char *hand;
|
||||
const char *h;
|
||||
#define SA_KNOWN_FLAGS \
|
||||
(SA_ONSTACK | SA_RESTART | SA_RESETHAND | SA_NOCLDSTOP | SA_NODEFER | \
|
||||
SA_NOCLDWAIT | SA_SIGINFO)
|
||||
|
||||
|
||||
if (get_struct(fd, (void *)args[sc->offset], &sa, sizeof(sa)) != -1) {
|
||||
|
||||
@ -667,35 +922,108 @@ print_arg(int fd, struct syscall_args *sc, unsigned long *args, long retval, str
|
||||
h = "SIG_IGN";
|
||||
else
|
||||
h = hand;
|
||||
asprintf(&tmp, "{ %s 0x%x%s%s%s%s%s%s%s ss_t }",
|
||||
|
||||
asprintf(&tmp, "{ %s %s ss_t }",
|
||||
h,
|
||||
sa.sa_flags & ~SA_KNOWN_FLAGS,
|
||||
sa.sa_flags & SA_ONSTACK ? "" : "|ONSTACK",
|
||||
sa.sa_flags & SA_RESTART ? "" : "|RESTART",
|
||||
sa.sa_flags & SA_RESETHAND ? "" : "|RESETHAND",
|
||||
sa.sa_flags & SA_NOCLDSTOP ? "" : "|NOCLDSTOP",
|
||||
sa.sa_flags & SA_NODEFER ? "" : "|NODEFER",
|
||||
sa.sa_flags & SA_NOCLDWAIT ? "" : "|NOCLDWAIT",
|
||||
sa.sa_flags & SA_SIGINFO ? "" : "|SIGINFO");
|
||||
xlookup_bits(sigaction_flags, sa.sa_flags));
|
||||
free(hand);
|
||||
} else
|
||||
asprintf(&tmp, "0x%lx", args[sc->offset]);
|
||||
|
||||
}
|
||||
break;
|
||||
case Kevent:
|
||||
{
|
||||
/*
|
||||
* XXX XXX: the size of the array is determined by either the
|
||||
* next syscall argument, or by the syscall returnvalue,
|
||||
* depending on which argument number we are. This matches the
|
||||
* kevent syscall, but luckily that's the only syscall that uses
|
||||
* them.
|
||||
*/
|
||||
struct kevent *ke;
|
||||
int numevents = -1;
|
||||
int bytes = 0;
|
||||
int i, tmpsize, u, used;
|
||||
const int per_ke = 100;
|
||||
|
||||
if (sc->offset == 1)
|
||||
numevents = args[sc->offset+1];
|
||||
else if (sc->offset == 3 && retval != -1)
|
||||
numevents = retval;
|
||||
|
||||
if (numevents >= 0)
|
||||
bytes = sizeof(struct kevent) * numevents;
|
||||
if ((ke = malloc(bytes)) == NULL)
|
||||
err(1, "Cannot malloc %d bytes for kevent array", bytes);
|
||||
if (numevents >= 0 && get_struct(fd, (void *)args[sc->offset], ke, bytes) != -1) {
|
||||
used = 0;
|
||||
tmpsize = 1 + per_ke * numevents + 2;
|
||||
if ((tmp = malloc(tmpsize)) == NULL)
|
||||
err(1, "Cannot alloc %d bytes for kevent output", tmpsize);
|
||||
|
||||
tmp[used++] = '{';
|
||||
for (i = 0; i < numevents; i++) {
|
||||
u = snprintf(tmp + used, per_ke,
|
||||
"%s%p,%s,%s,%d,%p,%p",
|
||||
i > 0 ? " " : "",
|
||||
(void *)ke[i].ident,
|
||||
xlookup(kevent_filters, ke[i].filter),
|
||||
xlookup_bits(kevent_flags, ke[i].flags),
|
||||
ke[i].fflags,
|
||||
(void *)ke[i].data,
|
||||
(void *)ke[i].udata);
|
||||
if (u > 0)
|
||||
used += u < per_ke ? u : per_ke;
|
||||
}
|
||||
tmp[used++] = '}';
|
||||
tmp[used++] = '\0';
|
||||
} else
|
||||
asprintf(&tmp, "0x%lx", args[sc->offset]);
|
||||
free(ke);
|
||||
}
|
||||
break;
|
||||
case Stat:
|
||||
{
|
||||
struct stat st;
|
||||
if (get_struct(fd, (void *)args[sc->offset], &st, sizeof(st)) != -1) {
|
||||
char mode[12];
|
||||
strmode(st.st_mode, mode);
|
||||
asprintf(&tmp, "{mode=%s,inode=%jd,size=%jd,blksize=%ld}",
|
||||
mode,
|
||||
(intmax_t)st.st_ino,(intmax_t)st.st_size,(long)st.st_blksize);
|
||||
} else
|
||||
asprintf(&tmp, "0x%lx", args[sc->offset]);
|
||||
}
|
||||
break;
|
||||
case Rusage:
|
||||
{
|
||||
struct rusage ru;
|
||||
if (get_struct(fd, (void *)args[sc->offset], &ru, sizeof(ru)) != -1)
|
||||
asprintf(&tmp, "{u=%ld.%06ld,s=%ld.%06ld,in=%ld,out=%ld}",
|
||||
(long)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
|
||||
(long)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
|
||||
ru.ru_inblock, ru.ru_oublock);
|
||||
else
|
||||
asprintf(&tmp, "0x%lx", args[sc->offset]);
|
||||
}
|
||||
break;
|
||||
case Rlimit:
|
||||
{
|
||||
struct rlimit rl;
|
||||
if (get_struct(fd, (void *)args[sc->offset], &rl, sizeof(rl)) != -1)
|
||||
asprintf(&tmp, "{cur=%ju,max=%ju}",
|
||||
rl.rlim_cur, rl.rlim_max);
|
||||
else
|
||||
asprintf(&tmp, "0x%lx", args[sc->offset]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#define timespecsubt(tvp, uvp, vvp) \
|
||||
do { \
|
||||
(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
|
||||
(vvp)->tv_nsec = (tvp)->tv_nsec - (uvp)->tv_nsec; \
|
||||
if ((vvp)->tv_nsec < 0) { \
|
||||
(vvp)->tv_sec--; \
|
||||
(vvp)->tv_nsec += 1000000000; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* print_syscall
|
||||
|
@ -44,3 +44,13 @@ struct trussinfo
|
||||
struct timespec before;
|
||||
struct timespec after;
|
||||
};
|
||||
|
||||
#define timespecsubt(tvp, uvp, vvp) \
|
||||
do { \
|
||||
(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
|
||||
(vvp)->tv_nsec = (tvp)->tv_nsec - (uvp)->tv_nsec; \
|
||||
if ((vvp)->tv_nsec < 0) { \
|
||||
(vvp)->tv_sec--; \
|
||||
(vvp)->tv_nsec += 1000000000; \
|
||||
} \
|
||||
} while (0)
|
||||
|
Loading…
Reference in New Issue
Block a user