Skip to content

@zym0017d /json-support.patch
Last active

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
add support for JSON output - single diff file
diff --git a/defs.h b/defs.h
index 1a3b483..3f4c36c 100644
--- a/defs.h
+++ b/defs.h
@@ -559,6 +559,7 @@ extern cflag_t cflag;
extern bool debug_flag;
extern bool Tflag;
extern bool iflag;
+extern bool jflag;
extern bool count_wallclock;
extern unsigned int qflag;
extern bool not_failing_only;
@@ -766,7 +767,9 @@ extern struct tcb *printing_tcp;
extern void printleader(struct tcb *);
extern void line_ended(void);
extern void tabto(void);
+extern void _tprintf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
extern void tprintf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+extern void tvprintf(const char *fmt, va_list args);
extern void tprints(const char *str);
#if SUPPORTED_PERSONALITIES > 1
@@ -829,3 +832,29 @@ extern unsigned num_quals;
/* Only ensures that sysent[scno] isn't out of range */
#define SCNO_IN_RANGE(scno) \
((unsigned long)(scno) < nsyscalls)
+
+
+/*
+ * JSON format support
+ */
+#define JSON_SYSCALL_BEGIN "{\"type\": \"syscall\", \"name\": "
+#define JSON_PAIR_FORMAT(key, value) "\"" key "\": " value
+#define JSON_SIGPLUS_FORMAT(name, args) "{\"type\": \"+++\", \"name\": \"" name "\", \"info\": " args " }\n"
+
+#define JSONSTR(json_str, normal_str) (jflag?(json_str):(normal_str))
+const char* jsonstr(const char* with_jflag, const char* without_jflag);
+
+extern int json_printflags_array_enable;
+void json_set_printflags_array(int is_enable, const char* output);
+
+
+const char* json_escape_string(const char *str);
+const char* json_translate_format(const char *fmt);
+
+void jprints(const char *str);
+void jprintf_struct(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+void jprintf(const char *json_fmt, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+/*
+ * End OF JSON format support
+ */
\ No newline at end of file
diff --git a/desc.c b/desc.c
index 5b8869b..7fd92c5 100644
--- a/desc.c
+++ b/desc.c
@@ -71,16 +71,17 @@ printflock64(struct tcb *tcp, long addr, int getlk)
struct flock64 fl;
if (umove(tcp, addr, &fl) < 0) {
- tprints("{...}");
+ jprintf("'...'", "{...}");
return;
}
- tprints("{type=");
+ jprintf_struct("{type=");
printxval(lockfcmds, fl.l_type, "F_???");
- tprints(", whence=");
+ jrpintf(", 'whence': ", ", whence=");
printxval(whence_codes, fl.l_whence, "SEEK_???");
- tprintf(", start=%lld, len=%lld", (long long) fl.l_start, (long long) fl.l_len);
+ jprintf_struct(", start=%lld, len=%lld",
+ (long long) fl.l_start, (long long) fl.l_len);
if (getlk)
- tprintf(", pid=%lu}", (unsigned long) fl.l_pid);
+ jprintf_struct(", pid=%lu}", (unsigned long) fl.l_pid);
else
tprints("}");
}
@@ -127,20 +128,20 @@ printflock(struct tcb *tcp, long addr, int getlk)
r = umove(tcp, addr, &fl);
}
if (r < 0) {
- tprints("{...}");
+ jprintf("'...'", "{...}");
return;
}
- tprints("{type=");
+ jprintf_struct("{type=");
printxval(lockfcmds, fl.l_type, "F_???");
- tprints(", whence=");
+ jprintf_struct(", whence=");
printxval(whence_codes, fl.l_whence, "SEEK_???");
#if SIZEOF_OFF_T > SIZEOF_LONG
- tprintf(", start=%lld, len=%lld", fl.l_start, fl.l_len);
+ jprintf_struct(", start=%lld, len=%lld", fl.l_start, fl.l_len);
#else
- tprintf(", start=%ld, len=%ld", fl.l_start, fl.l_len);
+ jprintf_struct(", start=%ld, len=%ld", fl.l_start, fl.l_len);
#endif
if (getlk)
- tprintf(", pid=%lu}", (unsigned long) fl.l_pid);
+ jprintf_struct(", pid=%lu}", (unsigned long) fl.l_pid);
else
tprints("}");
}
@@ -347,7 +348,7 @@ decode_select(struct tcb *tcp, long *args, enum bitness_t bitness)
for (i = 0; i < 3; i++) {
arg = args[i+1];
if (arg == 0) {
- tprints(", NULL");
+ jprints(", NULL");
continue;
}
if (!verbose(tcp) || !fds) {
@@ -355,7 +356,7 @@ decode_select(struct tcb *tcp, long *args, enum bitness_t bitness)
continue;
}
if (umoven(tcp, arg, fdsize, (char *) fds) < 0) {
- tprints(", [?]");
+ jprints(", [?]");
continue;
}
tprints(", [");
@@ -365,7 +366,7 @@ decode_select(struct tcb *tcp, long *args, enum bitness_t bitness)
break;
tprints(sep);
printfd(tcp, j);
- sep = " ";
+ sep = jsonstr(",", " ");
}
tprints("]");
}
@@ -447,7 +448,7 @@ sys_oldselect(struct tcb *tcp)
long args[5];
if (umoven(tcp, tcp->u_arg[0], sizeof args, (char *) args) < 0) {
- tprints("[...]");
+ jprintf("['...']", "[...]");
return 0;
}
return decode_select(tcp, args, BITNESS_CURRENT);
@@ -485,12 +486,13 @@ sys_epoll_create1(struct tcb *tcp)
static void
print_epoll_event(struct epoll_event *ev)
{
- tprints("{");
+ tprints(jsonstr("[", "{"));
printflags(epollevents, ev->events, "EPOLL???");
/* We cannot know what format the program uses, so print u32 and u64
which will cover every value. */
- tprintf(", {u32=%" PRIu32 ", u64=%" PRIu64 "}}",
+ jprintf_struct(", {u32=%" PRIu32 ", u64=%" PRIu64 "}",
ev->data.u32, ev->data.u64);
+ tprints(jsonstr("]", "}"));
}
#endif
@@ -505,7 +507,7 @@ sys_epoll_ctl(struct tcb *tcp)
printfd(tcp, tcp->u_arg[2]);
tprints(", ");
if (tcp->u_arg[3] == 0)
- tprints("NULL");
+ jprints("NULL");
else {
#ifdef HAVE_SYS_EPOLL_H
struct epoll_event ev;
@@ -539,7 +541,7 @@ epoll_wait_common(struct tcb *tcp)
struct epoll_event ev, *start, *cur, *end;
int failed = 0;
- tprints("{");
+ tprints(jsonstr("[", "{"));
start = (struct epoll_event *) tcp->u_arg[1];
end = start + tcp->u_rval;
for (cur = start; cur < end; ++cur) {
@@ -548,16 +550,16 @@ epoll_wait_common(struct tcb *tcp)
if (umove(tcp, (long) cur, &ev) == 0)
print_epoll_event(&ev);
else {
- tprints("?");
+ jprints("?");
failed = 1;
break;
}
}
- tprints("}");
+ tprints(jsonstr("]", "}"));
if (failed)
tprintf(" %#lx", (long) start);
#else
- tprints("{...}");
+ jprintf("['...']", "{...}");
#endif
}
tprintf(", %d, %d", (int) tcp->u_arg[2], (int) tcp->u_arg[3]);
@@ -615,10 +617,10 @@ sys_pselect6(struct tcb *tcp)
if (r < 0)
tprintf(", %#lx", tcp->u_arg[5]);
else {
- tprints(", {");
+ tprints(jsonstr(", [", ", {"));
/* NB: kernel requires data.len == NSIG / 8 */
print_sigset_addr_len(tcp, data.ptr, data.len);
- tprintf(", %lu}", data.len);
+ jprintf(", $]", ", %lu}", data.len);
}
}
return rc;
diff --git a/file.c b/file.c
index a92a7dc..8096a9a 100644
--- a/file.c
+++ b/file.c
@@ -236,7 +236,7 @@ void
print_dirfd(struct tcb *tcp, int fd)
{
if (fd == AT_FDCWD)
- tprints("AT_FDCWD, ");
+ jprintf("'AT_FDCWD', ", "AT_FDCWD, ");
else {
printfd(tcp, fd);
tprints(", ");
@@ -250,7 +250,7 @@ print_dirfd(struct tcb *tcp, int fd)
const char *
sprint_open_modes(mode_t flags)
{
- static char outstr[(1 + ARRAY_SIZE(open_mode_flags)) * sizeof("O_LARGEFILE")];
+ static char outstr[(1 + ARRAY_SIZE(open_mode_flags)) * sizeof("[\"O_LARGEFILE\"]")];
char *p;
char sep;
const char *str;
@@ -261,26 +261,48 @@ sprint_open_modes(mode_t flags)
str = xlookup(open_access_modes, flags & 3);
if (str) {
*p++ = sep;
+ if (jflag && sep == ' ') *p++ = '[';
+ if (jflag) *p++ = '\"';
p = stpcpy(p, str);
+ if (jflag) {
+ *p++ = '\"';
+ *p = '\0';
+ }
flags &= ~3;
- if (!flags)
+ if (!flags) {
+ if (jflag) {
+ *p++ = ']';
+ *p = '\0';
+ }
return outstr;
- sep = '|';
+ }
+ sep = JSONSTR(',', '|');
}
for (x = open_mode_flags; x->str; x++) {
if ((flags & x->val) == x->val) {
*p++ = sep;
+ if (jflag && sep == ' ') *p++ = '[';
+ if (jflag) *p++ = '\"';
p = stpcpy(p, x->str);
+ if (jflag) {
+ *p++ = '\"';
+ *p = '\0';
+ }
flags &= ~x->val;
- if (!flags)
+ if (!flags) {
+ if (jflag) {
+ *p++ = ']';
+ *p = '\0';
+ }
return outstr;
- sep = '|';
+ }
+ sep = JSONSTR(',', '|');
}
}
/* flags is still nonzero */
*p++ = sep;
- sprintf(p, "%#x", flags);
+ sprintf(p, jsonstr("%u]", "%#x"), flags);
return outstr;
}
@@ -535,23 +557,30 @@ sprintmode(int mode)
{
static char buf[sizeof("S_IFSOCK|S_ISUID|S_ISGID|S_ISVTX|%o")
+ sizeof(int)*3
- + /*paranoia:*/ 8];
+ + /*paranoia:*/ 8 + 16];
const char *s;
if ((mode & S_IFMT) == 0)
s = "";
else if ((s = xlookup(modetypes, mode & S_IFMT)) == NULL) {
- sprintf(buf, "%#o", mode);
+ sprintf(buf, jsonstr("%u", "%#o"), mode);
return buf;
}
- s = buf + sprintf(buf, "%s%s%s%s", s,
- (mode & S_ISUID) ? "|S_ISUID" : "",
- (mode & S_ISGID) ? "|S_ISGID" : "",
- (mode & S_ISVTX) ? "|S_ISVTX" : "");
+ s = buf + sprintf(buf, jsonstr("[\"%s\"%s%s%s", "%s%s%s%s"), s,
+ (mode & S_ISUID) ? jsonstr(",\"S_ISUID\"", "|S_ISUID") : "",
+ (mode & S_ISGID) ? jsonstr(",\"S_ISGID\"", "|S_ISGID") : "",
+ (mode & S_ISVTX) ? jsonstr(",\"S_ISVTX\"", "|S_ISVTX") : "");
mode &= ~(S_IFMT|S_ISUID|S_ISGID|S_ISVTX);
if (mode)
- sprintf((char*)s, "|%#o", mode);
- s = (*buf == '|') ? buf + 1 : buf;
+ s += sprintf((char*)s, jsonstr(",%u", "|%#o"), mode);
+ if (jflag)
+ sprintf((char*)s, "%s", "]");
+ s = (*buf == '|' ) ? buf + 1 : buf;
+ if (jflag && buf[2] == '\"') {
+ buf[1] = ' ';
+ buf[2] = ' ';
+ buf[3] = ' ';
+ }
return *s ? s : "0";
}
@@ -559,7 +588,7 @@ static char *
sprinttime(time_t t)
{
struct tm *tmp;
- static char buf[sizeof("yyyy/mm/dd-hh:mm:ss")];
+ static char buf[sizeof("yyyy/mm/dd-hh:mm:ss") + 8];
if (t == 0) {
strcpy(buf, "0");
@@ -567,7 +596,8 @@ sprinttime(time_t t)
}
tmp = localtime(&t);
if (tmp)
- snprintf(buf, sizeof buf, "%02d/%02d/%02d-%02d:%02d:%02d",
+ snprintf(buf, sizeof buf,
+ jsonstr("[%2d,%2d,%2d,%2d,%2d,%2d]", "%02d/%02d/%02d-%02d:%02d:%02d"),
tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
else
@@ -765,65 +795,67 @@ static void
realprintstat(struct tcb *tcp, struct stat *statbuf)
{
if (!abbrev(tcp)) {
- tprintf("{st_dev=makedev(%lu, %lu), st_ino=%lu, st_mode=%s, ",
+ jprintf("{'st_dev': [$, $], 'st_ino': $, 'st_mode': %s, ",
+ "{st_dev=makedev(%lu, %lu), st_ino=%lu, st_mode=%s, ",
(unsigned long) major(statbuf->st_dev),
(unsigned long) minor(statbuf->st_dev),
(unsigned long) statbuf->st_ino,
sprintmode(statbuf->st_mode));
- tprintf("st_nlink=%lu, st_uid=%lu, st_gid=%lu, ",
+ jprintf_struct("st_nlink=%lu, st_uid=%lu, st_gid=%lu, ",
(unsigned long) statbuf->st_nlink,
(unsigned long) statbuf->st_uid,
(unsigned long) statbuf->st_gid);
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
- tprintf("st_blksize=%lu, ", (unsigned long) statbuf->st_blksize);
+ jprintf_struct("st_blksize=%lu, ", (unsigned long) statbuf->st_blksize);
#endif
#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
- tprintf("st_blocks=%lu, ", (unsigned long) statbuf->st_blocks);
+ jprintf_struct("st_blocks=%lu, ", (unsigned long) statbuf->st_blocks);
#endif
}
else
- tprintf("{st_mode=%s, ", sprintmode(statbuf->st_mode));
+ jprintf("{'st_mode': %s, ",
+ "{st_mode=%s, ", sprintmode(statbuf->st_mode));
switch (statbuf->st_mode & S_IFMT) {
case S_IFCHR: case S_IFBLK:
#ifdef HAVE_STRUCT_STAT_ST_RDEV
- tprintf("st_rdev=makedev(%lu, %lu), ",
+ jprintf("'st_rdev': [$, $], ", "st_rdev=makedev(%lu, %lu), ",
(unsigned long) major(statbuf->st_rdev),
(unsigned long) minor(statbuf->st_rdev));
#else /* !HAVE_STRUCT_STAT_ST_RDEV */
- tprintf("st_size=makedev(%lu, %lu), ",
+ jprintf("'st_size': [$, $], ", "st_size=makedev(%lu, %lu), ",
(unsigned long) major(statbuf->st_size),
(unsigned long) minor(statbuf->st_size));
#endif /* !HAVE_STRUCT_STAT_ST_RDEV */
break;
default:
- tprintf("st_size=%lu, ", (unsigned long) statbuf->st_size);
+ jprintf_struct("st_size=%lu, ", (unsigned long) statbuf->st_size);
break;
}
if (!abbrev(tcp)) {
- tprintf("st_atime=%s, ", sprinttime(statbuf->st_atime));
- tprintf("st_mtime=%s, ", sprinttime(statbuf->st_mtime));
- tprintf("st_ctime=%s", sprinttime(statbuf->st_ctime));
+ jprintf_struct("st_atime=%s, ", sprinttime(statbuf->st_atime));
+ jprintf_struct("st_mtime=%s, ", sprinttime(statbuf->st_mtime));
+ jprintf_struct("st_ctime=%s", sprinttime(statbuf->st_ctime));
#if HAVE_STRUCT_STAT_ST_FLAGS
- tprints(", st_flags=");
+ jprintf_struct(", st_flags=");
printflags(fileflags, statbuf->st_flags, "UF_???");
#endif
#if HAVE_STRUCT_STAT_ST_ACLCNT
- tprintf(", st_aclcnt=%d", statbuf->st_aclcnt);
+ jprintf_struct(", st_aclcnt=%d", statbuf->st_aclcnt);
#endif
#if HAVE_STRUCT_STAT_ST_LEVEL
- tprintf(", st_level=%ld", statbuf->st_level);
+ jprintf_struct(", st_level=%ld", statbuf->st_level);
#endif
#if HAVE_STRUCT_STAT_ST_FSTYPE
- tprintf(", st_fstype=%.*s",
+ jprintf_struct(", st_fstype=%.*s",
(int) sizeof statbuf->st_fstype, statbuf->st_fstype);
#endif
#if HAVE_STRUCT_STAT_ST_GEN
- tprintf(", st_gen=%u", statbuf->st_gen);
+ jprintf_struct(", st_gen=%u", statbuf->st_gen);
#endif
tprints("}");
}
else
- tprints("...}");
+ jprints(jsonstr("...: null}", "...}"));
}
#ifndef X32
@@ -833,7 +865,7 @@ printstat(struct tcb *tcp, long addr)
struct stat statbuf;
if (!addr) {
- tprints("NULL");
+ jprints("NULL");
return;
}
if (syserror(tcp) || !verbose(tcp)) {
@@ -862,7 +894,7 @@ printstat(struct tcb *tcp, long addr)
#endif
if (umove(tcp, addr, &statbuf) < 0) {
- tprints("{...}");
+ jprints(jsonstr("[...]", "{...}"));
return;
}
@@ -929,7 +961,7 @@ printstat64(struct tcb *tcp, long addr)
#endif
if (!addr) {
- tprints("NULL");
+ jprints("NULL");
return;
}
if (syserror(tcp) || !verbose(tcp)) {
@@ -964,71 +996,74 @@ printstat64(struct tcb *tcp, long addr)
#endif
if (umove(tcp, addr, &statbuf) < 0) {
- tprints("{...}");
+ jprintf("['...']", "{...}");
return;
}
if (!abbrev(tcp)) {
- tprintf("{st_dev=makedev(%lu, %lu), st_ino=%llu, st_mode=%s, ",
+ jprintf("{'st_dev': [$, $]', 'st_ino': $, 'st_mode': $, ",
+ "{st_dev=makedev(%lu, %lu), st_ino=%llu, st_mode=%s, ",
(unsigned long) major(statbuf.st_dev),
(unsigned long) minor(statbuf.st_dev),
(unsigned long long) statbuf.st_ino,
sprintmode(statbuf.st_mode));
- tprintf("st_nlink=%lu, st_uid=%lu, st_gid=%lu, ",
+ jprintf_struct("st_nlink=%lu, st_uid=%lu, st_gid=%lu, ",
(unsigned long) statbuf.st_nlink,
(unsigned long) statbuf.st_uid,
(unsigned long) statbuf.st_gid);
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
- tprintf("st_blksize=%lu, ",
+ jprintf_struct("st_blksize=%lu, ",
(unsigned long) statbuf.st_blksize);
#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
- tprintf("st_blocks=%lu, ", (unsigned long) statbuf.st_blocks);
+ jprintf_struct("st_blocks=%lu, ", (unsigned long) statbuf.st_blocks);
#endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
}
else
- tprintf("{st_mode=%s, ", sprintmode(statbuf.st_mode));
+ jprintf_struct("{st_mode=%s, ", sprintmode(statbuf.st_mode));
switch (statbuf.st_mode & S_IFMT) {
case S_IFCHR: case S_IFBLK:
#ifdef HAVE_STRUCT_STAT_ST_RDEV
- tprintf("st_rdev=makedev(%lu, %lu), ",
+ jprintf("'st_rdev': [$, $], ",
+ "st_rdev=makedev(%lu, %lu), ",
(unsigned long) major(statbuf.st_rdev),
(unsigned long) minor(statbuf.st_rdev));
#else /* !HAVE_STRUCT_STAT_ST_RDEV */
- tprintf("st_size=makedev(%lu, %lu), ",
+ jprintf("'st_size': [$, $], ",
+ "st_size=makedev(%lu, %lu), ",
(unsigned long) major(statbuf.st_size),
(unsigned long) minor(statbuf.st_size));
#endif /* !HAVE_STRUCT_STAT_ST_RDEV */
break;
default:
- tprintf("st_size=%llu, ", (unsigned long long) statbuf.st_size);
+ jprintf_struct("st_size=%llu, ", (unsigned long long) statbuf.st_size);
break;
}
if (!abbrev(tcp)) {
- tprintf("st_atime=%s, ", sprinttime(statbuf.st_atime));
- tprintf("st_mtime=%s, ", sprinttime(statbuf.st_mtime));
- tprintf("st_ctime=%s", sprinttime(statbuf.st_ctime));
+ jprintf_struct("st_atime=%s, ", sprinttime(statbuf.st_atime));
+ jprintf_struct("st_mtime=%s, ", sprinttime(statbuf.st_mtime));
+ jprintf_struct("st_ctime=%s", sprinttime(statbuf.st_ctime));
#if HAVE_STRUCT_STAT_ST_FLAGS
- tprints(", st_flags=");
+ jprintf_struct(", st_flags=");
printflags(fileflags, statbuf.st_flags, "UF_???");
#endif
#if HAVE_STRUCT_STAT_ST_ACLCNT
- tprintf(", st_aclcnt=%d", statbuf.st_aclcnt);
+ jprintf_struct(", st_aclcnt=%d", statbuf.st_aclcnt);
#endif
#if HAVE_STRUCT_STAT_ST_LEVEL
- tprintf(", st_level=%ld", statbuf.st_level);
+ jprintf_struct(", st_level=%ld", statbuf.st_level);
#endif
#if HAVE_STRUCT_STAT_ST_FSTYPE
- tprintf(", st_fstype=%.*s",
+ jprintf_struct(", st_fstype=%.*s",
(int) sizeof statbuf.st_fstype, statbuf.st_fstype);
#endif
#if HAVE_STRUCT_STAT_ST_GEN
- tprintf(", st_gen=%u", statbuf.st_gen);
+ jprintf_struct(", st_gen=%u", statbuf.st_gen);
#endif
tprints("}");
}
else
- tprints("...}");
+ tprints(jsonstr("\"...\"}", "...}"));
}
#endif /* HAVE_STAT64 */
diff --git a/io.c b/io.c
index fea1218..40fe78e 100644
--- a/io.c
+++ b/io.c
@@ -112,15 +112,15 @@ tprint_iov_upto(struct tcb *tcp, unsigned long len, unsigned long addr, int deco
if (cur > addr)
tprints(", ");
if (cur >= abbrev_end) {
- tprints("...");
+ jprints("...");
break;
}
if (umoven(tcp, cur, sizeof_iov, (char *) &iov) < 0) {
- tprints("?");
+ jprints("?");
failed = 1;
break;
}
- tprints("{");
+ tprints(jsonstr("[", "{"));
if (decode_iov) {
unsigned long len = iov_iov_len;
if (len > data_size)
@@ -129,11 +129,13 @@ tprint_iov_upto(struct tcb *tcp, unsigned long len, unsigned long addr, int deco
printstr(tcp, (long) iov_iov_base, len);
} else
tprintf("%#lx", (long) iov_iov_base);
- tprintf(", %lu}", (unsigned long)iov_iov_len);
+ jprintf(", $]", ", %lu}", (unsigned long)iov_iov_len);
}
tprints("]");
- if (failed)
- tprintf(" %#lx", addr);
+ if (failed) {
+ jprints(jsonstr(", ", ""));
+ tprintf("%#lx", addr);
+ }
#undef sizeof_iov
#undef iov_iov_base
#undef iov_iov_len
@@ -256,7 +258,7 @@ print_off_t(struct tcb *tcp, long addr)
unsigned long offset;
if (!addr) {
- tprints("NULL");
+ jprints("NULL");
return;
}
@@ -296,7 +298,7 @@ print_loff_t(struct tcb *tcp, long addr)
loff_t offset;
if (!addr)
- tprints("NULL");
+ jprints("NULL");
else if (umove(tcp, addr, &offset) < 0)
tprintf("%#lx", addr);
else
@@ -387,9 +389,11 @@ sys_ioctl(struct tcb *tcp)
tprints(", ");
iop = ioctl_lookup(tcp->u_arg[1]);
if (iop) {
- tprints(iop->symbol);
- while ((iop = ioctl_next_match(iop)))
- tprintf(" or %s", iop->symbol);
+ jprintf("[$", "%s", iop->symbol);
+ while ((iop = ioctl_next_match(iop))) {
+ jprintf(", $", " or %s", iop->symbol);
+ }
+ jprintf("]", NULL);
} else
tprintf("%#lx", tcp->u_arg[1]);
ioctl_decode(tcp, tcp->u_arg[1], tcp->u_arg[2]);
diff --git a/json.c b/json.c
new file mode 100644
index 0000000..299039d
--- /dev/null
+++ b/json.c
@@ -0,0 +1,329 @@
+#include "defs.h"
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+
+
+/*
+ * return the length of the specifer starting from fmt
+ * -1 when couldn't find any specifier
+ * e.g.
+ * "abcd" -> -1
+ * "%" -> -1
+ * "%d" -> 2
+ * "%+lld" -> 5
+ */
+static int check_specifier(const char *fmt)
+{
+ if (*fmt++ != '%') return -1;
+ size_t len = strcspn(fmt, "diuoxXfFeEgGaAcspn%");
+ if (*(fmt + len) == '\0') return -1;
+ return len + 2;
+}
+
+
+/*
+ * Extract the % specifier in a format string
+ * buf should be long enough to contain the whole specifier string
+ *
+ * Return the next start position or
+ * NULL(couldn't find any format specifier in the string, will not write to buf)
+*/
+static const char* get_next_specifier(const char *fmt, char *buf)
+{
+ if (fmt == NULL) return NULL;
+ while (*fmt != '%' && *fmt != '\0') ++fmt;
+ if (*fmt == '\0') return NULL;
+
+ const char *end = fmt + 1;
+ end += strcspn(end, "diuoxXfFeEgGaAcspn%");
+
+ if (*end++ == '\0')
+ return NULL;
+
+ while (fmt != end) *buf++ = *fmt++;
+ *buf = '\0';
+ return fmt;
+}
+
+
+/*
+ * copy a printf format specifer to dst
+ *
+ * spec: point to the first '%' character of a format specifier
+ * spec_len: length of the specifier
+ * ignore: ignored chars when copying
+ * new_spec: replace the end of dst with new_spec
+ *
+ * return the next to-write position of dst
+ */
+static char* copy_specifier(char *dst, const char *spec, int spec_len,
+ const char* ignore, char new_spec)
+{
+ int i;
+ for (i = 0; i < spec_len - 1; i++) {
+ if (strchr(ignore, spec[i]) == NULL) {
+ *dst++ = spec[i];
+ }
+ }
+ *dst++ = new_spec;
+ return dst;
+}
+
+
+static char* replace_specifier(char *dst, const char *specifier, int spec_len, int no_quotes)
+{
+ char spec = *(specifier + spec_len - 1);
+
+ if (spec == 'x' || spec == 'X' || spec == 'o') {
+ dst = copy_specifier(dst, specifier, spec_len, "#0123456789", 'u');
+ } else if (spec == 'p' || spec == 's') {
+ if (!no_quotes) *dst++ = '\"';
+ dst = copy_specifier(dst, specifier, spec_len, "", spec == 'p' ? 'p' : 's');
+ if (!no_quotes) *dst++ = '\"';
+ } else {
+ while (spec_len--)
+ *dst++ = *specifier++;
+ *dst = '\0';
+ }
+ return dst;
+}
+
+
+static void jvprintf(const char *json_fmt, const char *fmt, va_list args)
+{
+ static char json_fmt_buf[100];
+ char* new_fmt = json_fmt_buf;
+#define JSON_SPECIFIER_MAX_COUNT (50)
+ static char specifier[JSON_SPECIFIER_MAX_COUNT][50];
+ static int specifier_length[JSON_SPECIFIER_MAX_COUNT];
+
+ int sp_counts = 0;
+ while((fmt = get_next_specifier(fmt, specifier[sp_counts])) != NULL) {
+ specifier_length[sp_counts] = strlen(specifier[sp_counts]);
+ ++sp_counts;
+ assert(sp_counts != JSON_SPECIFIER_MAX_COUNT);
+ }
+
+ int sp_i = 0;
+ while (*json_fmt != '\0') {
+ if (*json_fmt == '$') {
+ assert(sp_i < sp_counts);
+ new_fmt = replace_specifier(new_fmt, specifier[sp_i], specifier_length[sp_i], 0);
+ ++json_fmt;
+ ++sp_i;
+ } else {
+ if (*json_fmt == '%' && *(json_fmt + 1) != '%') {
+ sp_i++;
+ } else if (*json_fmt == '\'') {
+ *new_fmt++ = '\"';
+ ++json_fmt;
+ continue;
+ }
+ *new_fmt++ = *json_fmt++;
+ }
+ }
+ *new_fmt++ = '\0';
+ tvprintf(json_fmt_buf, args);
+}
+
+
+/*
+ * JSON format interface implementation
+ */
+inline const char* jsonstr(const char* with_jflag, const char* without_jflag)
+{
+ return jflag ? with_jflag : without_jflag;
+}
+
+/*
+ * control the behavir of printflags()
+ * is_enable == 1 will print the '[' and ']' before,after the flags
+ * is_enable == 0 will NOT print '[' and ']'
+ *
+ * will also print the string output, you can set it to NULL to ignore
+ *
+ * work only when jflag != 0
+ */
+int json_printflags_array_enable = 1;
+void json_set_printflags_array(int is_enable, const char* output)
+{
+ if (!jflag) return;
+ if (is_enable)
+ json_printflags_array_enable = 1;
+ else
+ json_printflags_array_enable = 0;
+ tprints(output);
+ return;
+}
+
+
+const char* json_escape_string(const char *str)
+{
+ static char buffer[1024];
+ if (!jflag || str == NULL)
+ return str;
+ int i = 0;
+ while(i < 1000) {
+ switch(*str) {
+ case '\0':
+ buffer[i] = '\0';
+ return buffer;
+ case '\"':
+ buffer[i++] = '\\';
+ buffer[i++] = '\"';
+ ++str;
+ break;
+ case '\\':
+ buffer[i++] = '\\';
+ buffer[i++] = '\\';
+ ++str;
+ break;
+ default:
+ buffer[i++] = *str++;
+ break;
+ }
+ }
+ // FIXME: str is too long
+ assert(0);
+ return NULL;
+}
+
+/*
+ * return json parsed format string, replace some specifier in fmt when -j is enabled
+ * replace rules:
+ * %x -> %u (with length but ignore char in "#0123456789")
+ * %X -> %u (with length but ignore char in "#0123456789")
+ * %o -> %u (with length but ignore char in "#0123456789")
+ * %p -> \"%p\"
+ * %s -> \"%s\"
+ */
+const char* json_translate_format(const char *fmt)
+{
+ static char newfmt[200];
+ char *pnf = newfmt;
+ size_t len;
+ while (*fmt != '\0') {
+ if ((len = check_specifier(fmt)) == -1) {
+ *pnf++ = *fmt++;
+ } else {
+ int no_quotes = 0;
+ if (fmt[len-1] == 's' && fmt[-1] == '\"' && fmt[len] == '\"')
+ no_quotes = 1;
+ pnf = replace_specifier(pnf, fmt, len, no_quotes);
+ fmt += len;
+ }
+ }
+ *pnf++ = '\0';
+ return newfmt;
+}
+
+
+void jprints(const char *str)
+{
+ if (jflag) {
+ static char buf[100];
+ char* pb = buf;
+ while (*str != '\0') {
+ switch (*str) {
+ case '?':
+ pb = stpcpy(pb, "false");
+ ++str;
+ break;
+ case 'N':
+ if (strncmp(str, "NULL", 4) == 0) {
+ pb = stpcpy(pb, "null");
+ str += 4;
+ break;
+ }
+ case '.':
+ if (strncmp(str, "...", 3) == 0) {
+ pb = stpcpy(pb, "\"...\"");
+ str += 3;
+ break;
+ }
+ default:
+ *pb++ = *str++;
+ }
+ }
+ *pb++ = '\0';
+ str = buf;
+ }
+ tprints(str);
+}
+
+
+void jprintf_struct(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ if (jflag) {
+ static char newfmt[100];
+ char* pnf = newfmt;
+ while(*fmt != '\0') {
+ if (isalnum(*fmt)) {
+ char* equal = strchr(fmt, '=');
+ if (equal) {
+ pnf += sprintf(pnf, "\"%.*s\": ", (int)(equal-fmt), fmt);
+ fmt = equal + 1;
+ continue;
+ }
+ } else if (*fmt == '%') {
+ size_t len = check_specifier(fmt);
+ if (len != -1) {
+ int no_quotes = 0;
+ if (fmt[len-1] == 's' && fmt[-1] == '\"' && fmt[len] == '\"')
+ no_quotes = 1;
+ pnf = replace_specifier(pnf, fmt, len, no_quotes);
+ fmt += len;
+ continue;
+ }
+ }
+
+ *pnf++ = *fmt++;
+ }
+ *pnf++ = '\0';
+ fmt = newfmt;
+ }
+ tvprintf(fmt, args);
+ va_end(args);
+}
+
+
+/*
+ * print like tprintf but provide some special format extend when -j is enabled
+ *
+ * 1, when -j is NOT enabled, just the same to tprintf(), ignore the first argument
+ *
+ * 2, when -j is enabled, use the first argument as the format string
+ * you can use $ in json_fmt, and all $ in json_fmt will be replaced by the
+ * corresponding specifer in fmt
+ *
+ * Note: the replace rules for specifier is the same to jprinta()
+ * e.g.
+ * jprintf("[$, $]", "{%d = %u}", 123, 345) equal to
+ * tprintf("[%d, %u]", 123, 345)
+ *
+ * jprintf("{'abcd': [$, $]}", "abcd: {%s= %#llx}", "xyz", 123) equal to
+ * tprintf("{\"abcd\": [\"%s\", %llu]}", "xyz", 123)
+ *
+ * you can also use any original % specifer in json_fmt.
+ * e.g.
+ * jprintf("%#llx and $", "%#llx and %#llx", 123, 456) equal to
+ * tprintf("%#llx and %llu", 123, 456)
+ *
+ */
+void jprintf(const char *json_fmt, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+
+ if(jflag && json_fmt != NULL) {
+ jvprintf(json_fmt, fmt, args);
+ } else if (!jflag && fmt != NULL){
+ tvprintf(fmt, args);
+ }
+
+ va_end(args);
+}
\ No newline at end of file
diff --git a/ldt.c b/ldt.c
index 0376d2b..0858b1d 100644
--- a/ldt.c
+++ b/ldt.c
@@ -15,28 +15,29 @@ print_user_desc(struct tcb *tcp, long addr)
}
if (!verbose(tcp)) {
- tprintf("{entry_number:%d, ...}", desc.entry_number);
+ jprintf("{'entry_number': $}", "{entry_number:%d, ...}", desc.entry_number);
return;
}
- tprintf("{entry_number:%d, "
- "base_addr:%#08x, "
- "limit:%d, "
- "seg_32bit:%d, "
- "contents:%d, "
- "read_exec_only:%d, "
- "limit_in_pages:%d, "
- "seg_not_present:%d, "
- "useable:%d}",
- desc.entry_number,
- desc.base_addr,
- desc.limit,
- desc.seg_32bit,
- desc.contents,
- desc.read_exec_only,
- desc.limit_in_pages,
- desc.seg_not_present,
- desc.useable);
+ jprintf_struct("{entry_number:%d, "
+ "base_addr:%#08x, "
+ "limit:%d, "
+ "seg_32bit:%d, "
+ "contents:%d, "
+ "read_exec_only:%d, "
+ "limit_in_pages:%d, "
+ "seg_not_present:%d, "
+ "useable:%d}",
+ desc.entry_number,
+ desc.base_addr,
+ desc.limit,
+ desc.seg_32bit,
+ desc.contents,
+ desc.read_exec_only,
+ desc.limit_in_pages,
+ desc.seg_not_present,
+ desc.useable
+ );
}
int
diff --git a/mem.c b/mem.c
index 6ecd363..a53a6b6 100644
--- a/mem.c
+++ b/mem.c
@@ -62,7 +62,7 @@ print_mmap(struct tcb *tcp, long *u_arg, unsigned long long offset)
if (entering(tcp)) {
/* addr */
if (!u_arg[0])
- tprints("NULL, ");
+ jprints("NULL, ");
else
tprintf("%#lx, ", u_arg[0]);
/* len */
diff --git a/mtd.c b/mtd.c
index 8ba658b..170b0ad 100644
--- a/mtd.c
+++ b/mtd.c
@@ -272,13 +272,13 @@ int ubi_ioctl(struct tcb *tcp, long code, long arg)
if (!verbose(tcp) || umove(tcp, arg, &mkvol) < 0)
return 0;
- tprintf(", {vol_id=%" PRIi32 ", alignment=%" PRIi32
+ jprintf_struct(", {vol_id=%" PRIi32 ", alignment=%" PRIi32
", bytes=%" PRIi64 ", vol_type=", mkvol.vol_id,
mkvol.alignment, (int64_t)mkvol.bytes);
printxval(ubi_volume_types, mkvol.vol_type, "UBI_???_VOLUME");
ret = string_quote(mkvol.name, vol_name, -1,
CLAMP(mkvol.name_len, 0, UBI_MAX_VOLUME_NAME));
- tprintf(", name_len=%" PRIi16 ", name=%s%s",
+ jprintf_struct(", name_len=%" PRIi16 ", name=%s%s",
mkvol.name_len, vol_name, ret ? "..." : "");
tprints("}");
return 1;
@@ -287,7 +287,7 @@ int ubi_ioctl(struct tcb *tcp, long code, long arg)
if (!verbose(tcp) || umove(tcp, arg, &rsvol) < 0)
return 0;
- tprintf(", {vol_id=%" PRIi32 ", bytes=%" PRIi64 "}",
+ jprintf_struct(", {vol_id=%" PRIi32 ", bytes=%" PRIi64 "}",
rsvol.vol_id, (int64_t)rsvol.bytes);
return 1;
@@ -297,13 +297,13 @@ int ubi_ioctl(struct tcb *tcp, long code, long arg)
if (!verbose(tcp) || umove(tcp, arg, &rnvol) < 0)
return 0;
- tprintf(", {count=%" PRIi32 ", ents=[", rnvol.count);
+ jprintf_struct(", {count=%" PRIi32 ", ents=[", rnvol.count);
for (c = 0; c < CLAMP(rnvol.count, 0, UBI_MAX_RNVOL); ++c) {
if (c)
tprints(", ");
ret = string_quote(rnvol.ents[c].name, vol_name, -1,
CLAMP(rnvol.ents[c].name_len, 0, UBI_MAX_VOLUME_NAME));
- tprintf("{vol_id=%" PRIi32 ", name_len=%" PRIi16
+ jprintf_struct("{vol_id=%" PRIi32 ", name_len=%" PRIi16
", name=%s%s}", rnvol.ents[c].vol_id,
rnvol.ents[c].name_len, vol_name, ret ? "..." : "");
}
diff --git a/net.c b/net.c
index 08341ad..9eccf2a 100644
--- a/net.c
+++ b/net.c
@@ -181,7 +181,7 @@ printsock(struct tcb *tcp, long addr, int addrlen)
char string_addr[100];
if (addr == 0) {
- tprints("NULL");
+ jprints("NULL");
return;
}
if (!verbose(tcp)) {
@@ -194,35 +194,38 @@ printsock(struct tcb *tcp, long addr, int addrlen)
memset(&addrbuf, 0, sizeof(addrbuf));
if (umoven(tcp, addr, addrlen, addrbuf.pad) < 0) {
- tprints("{...}");
+ tprints(jsonstr("false", "{...}"));
return;
}
addrbuf.pad[sizeof(addrbuf.pad) - 1] = '\0';
- tprints("{sa_family=");
+ jprintf_struct("{sa_family=");
printxval(addrfams, addrbuf.sa.sa_family, "AF_???");
tprints(", ");
switch (addrbuf.sa.sa_family) {
case AF_UNIX:
if (addrlen == 2) {
- tprints("NULL");
+ jprints("NULL");
} else if (addrbuf.sau.sun_path[0]) {
- tprints("sun_path=");
+ jprintf_struct("sun_path=");
printpathn(tcp, addr + 2, strlen(addrbuf.sau.sun_path));
} else {
- tprints("sun_path=@");
+ jprintf_struct("sun_path=");
+ tprints(jsonstr("", "@"));
printpathn(tcp, addr + 3, strlen(addrbuf.sau.sun_path + 1));
}
break;
case AF_INET:
- tprintf("sin_port=htons(%u), sin_addr=inet_addr(\"%s\")",
+ jprintf("'sin_port': $, 'sin_addr': $",
+ "sin_port=htons(%u), sin_addr=inet_addr(\"%s\")",
ntohs(addrbuf.sin.sin_port), inet_ntoa(addrbuf.sin.sin_addr));
break;
#ifdef HAVE_INET_NTOP
case AF_INET6:
inet_ntop(AF_INET6, &addrbuf.sa6.sin6_addr, string_addr, sizeof(string_addr));
- tprintf("sin6_port=htons(%u), inet_pton(AF_INET6, \"%s\", &sin6_addr), sin6_flowinfo=%u",
+ jprintf("'sin6_port': $, 'inet_pton': $, 'sin6_flowinfo': $",
+ "sin6_port=htons(%u), inet_pton(AF_INET6, \"%s\", &sin6_addr), sin6_flowinfo=%u",
ntohs(addrbuf.sa6.sin6_port), string_addr,
addrbuf.sa6.sin6_flowinfo);
#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
@@ -236,13 +239,14 @@ printsock(struct tcb *tcp, long addr, int addrlen)
if (if_indextoname(addrbuf.sa6.sin6_scope_id, scopebuf) == NULL)
numericscope++;
else
- tprintf(", sin6_scope_id=if_nametoindex(\"%s\")", scopebuf);
+ jprintf(", 'sin6_scope_id': $",
+ ", sin6_scope_id=if_nametoindex(\"%s\")", scopebuf);
} else
numericscope++;
if (numericscope)
#endif
- tprintf(", sin6_scope_id=%u", addrbuf.sa6.sin6_scope_id);
+ jprintf_struct(", sin6_scope_id=%u", addrbuf.sa6.sin6_scope_id);
}
#endif
break;
@@ -251,7 +255,8 @@ printsock(struct tcb *tcp, long addr, int addrlen)
case AF_IPX:
{
int i;
- tprintf("sipx_port=htons(%u), ",
+ jprintf("'sipx_port': $, ",
+ "sipx_port=htons(%u), ",
ntohs(addrbuf.sipx.sipx_port));
/* Yes, I know, this does not look too
* strace-ish, but otherwise the IPX
@@ -270,29 +275,34 @@ printsock(struct tcb *tcp, long addr, int addrlen)
case AF_PACKET:
{
int i;
- tprintf("proto=%#04x, if%d, pkttype=",
+ jprintf("'proto': [$, $], 'pkttype': ",
+ "proto=%#04x, if%d, pkttype=",
ntohs(addrbuf.ll.sll_protocol),
addrbuf.ll.sll_ifindex);
printxval(af_packet_types, addrbuf.ll.sll_pkttype, "?");
- tprintf(", addr(%d)={%d, ",
+ jprintf(", 'addr': [$, $, [",
+ ", addr(%d)={%d, ",
addrbuf.ll.sll_halen,
addrbuf.ll.sll_hatype);
- for (i = 0; i < addrbuf.ll.sll_halen; i++)
+ for (i = 0; i < addrbuf.ll.sll_halen; i++) {
+ if (i > 0 && jflag) tprints(", ");
tprintf("%02x", addrbuf.ll.sll_addr[i]);
+ }
+ tprints(jsonstr("]", ""));
}
break;
#endif /* AF_PACKET */
#ifdef AF_NETLINK
case AF_NETLINK:
- tprintf("pid=%d, groups=%08x", addrbuf.nl.nl_pid, addrbuf.nl.nl_groups);
+ jprintf_struct("pid=%d, groups=%08x", addrbuf.nl.nl_pid, addrbuf.nl.nl_groups);
break;
#endif /* AF_NETLINK */
/* AF_AX25 AF_APPLETALK AF_NETROM AF_BRIDGE AF_AAL5
AF_X25 AF_ROSE etc. still need to be done */
default:
- tprints("sa_data=");
+ jprintf_struct("sa_data=");
printstr(tcp, (long) &((struct sockaddr *) addr)->sa_data,
sizeof addrbuf.sa.sa_data);
break;
@@ -309,14 +319,14 @@ printcmsghdr(struct tcb *tcp, unsigned long addr, unsigned long len)
struct cmsghdr *cmsg = len < sizeof(struct cmsghdr) ?
NULL : malloc(len);
if (cmsg == NULL || umoven(tcp, addr, len, (char *) cmsg) < 0) {
- tprintf(", msg_control=%#lx", addr);
+ jprintf_struct(", msg_control=%#lx", addr);
free(cmsg);
return;
}
- tprintf(", {cmsg_len=%u, cmsg_level=", (unsigned) cmsg->cmsg_len);
+ jprintf_struct(", {cmsg_len=%u, cmsg_level=", (unsigned) cmsg->cmsg_len);
printxval(socketlayers, cmsg->cmsg_level, "SOL_???");
- tprints(", cmsg_type=");
+ jprintf_struct(", cmsg_type=");
if (cmsg->cmsg_level == SOL_SOCKET) {
unsigned long cmsg_len;
@@ -329,14 +339,14 @@ printcmsghdr(struct tcb *tcp, unsigned long addr, unsigned long len)
int *fds = (int *) CMSG_DATA(cmsg);
int first = 1;
- tprints(", {");
+ tprints(jsonstr(", [", ", {"));
while ((char *) fds < ((char *) cmsg + cmsg_len)) {
if (!first)
tprints(", ");
printfd(tcp, *fds++);
first = 0;
}
- tprints("}}");
+ tprints(jsonstr("]}", "}}"));
free(cmsg);
return;
}
@@ -344,35 +354,35 @@ printcmsghdr(struct tcb *tcp, unsigned long addr, unsigned long len)
&& CMSG_LEN(sizeof(struct ucred)) <= cmsg_len) {
struct ucred *uc = (struct ucred *) CMSG_DATA(cmsg);
- tprintf("{pid=%ld, uid=%ld, gid=%ld}}",
+ jprintf_struct("{pid=%ld, uid=%ld, gid=%ld}}",
(long)uc->pid, (long)uc->uid, (long)uc->gid);
free(cmsg);
return;
}
}
free(cmsg);
- tprints(", ...}");
+ jprintf(", '...': false", ", ...}");
}
static void
do_msghdr(struct tcb *tcp, struct msghdr *msg, unsigned long data_size)
{
- tprintf("{msg_name(%d)=", msg->msg_namelen);
+ jprintf_struct("{msg_name(%d)=", msg->msg_namelen);
printsock(tcp, (long)msg->msg_name, msg->msg_namelen);
- tprintf(", msg_iov(%lu)=", (unsigned long)msg->msg_iovlen);
+ jprintf_struct(", msg_iov(%lu)=", (unsigned long)msg->msg_iovlen);
tprint_iov_upto(tcp, (unsigned long)msg->msg_iovlen,
(unsigned long)msg->msg_iov, 1, data_size);
#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
- tprintf(", msg_controllen=%lu", (unsigned long)msg->msg_controllen);
+ jprintf_struct(", msg_controllen=%lu", (unsigned long)msg->msg_controllen);
if (msg->msg_controllen)
printcmsghdr(tcp, (unsigned long) msg->msg_control,
msg->msg_controllen);
- tprints(", msg_flags=");
+ jprintf_struct(", msg_flags=");
printflags(msg_flags, msg->msg_flags, "MSG_???");
#else /* !HAVE_STRUCT_MSGHDR_MSG_CONTROL */
- tprintf("msg_accrights=%#lx, msg_accrightslen=%u",
+ jprintf_struct("msg_accrights=%#lx, msg_accrightslen=%u",
(unsigned long) msg->msg_accrights, msg->msg_accrightslen);
#endif /* !HAVE_STRUCT_MSGHDR_MSG_CONTROL */
tprints("}");
@@ -495,14 +505,16 @@ tprint_sock_type(struct tcb *tcp, int flags)
{
const char *str = xlookup(socktypes, flags & SOCK_TYPE_MASK);
+ tprints(jsonstr("[", ""));
if (str) {
- tprints(str);
+ tprintf("%s", str);
flags &= ~SOCK_TYPE_MASK;
if (!flags)
return;
- tprints("|");
+ tprints(jsonstr(",", "|"));
}
printflags(sock_type_flags, flags, "SOCK_???");
+ tprints(jsonstr("]", ""));
}
int
@@ -578,8 +590,10 @@ do_accept(struct tcb *tcp, int flags_arg)
tprints(", ");
return 0;
}
- if (!tcp->u_arg[2])
- tprintf("%#lx, NULL", tcp->u_arg[1]);
+ if (!tcp->u_arg[2]) {
+ tprintf("%#lx, ", tcp->u_arg[1]);
+ jprints("NULL");
+ }
else {
int len;
if (tcp->u_arg[1] == 0 || syserror(tcp)
@@ -723,17 +737,17 @@ sys_recvfrom(struct tcb *tcp)
/* from address, len */
if (!tcp->u_arg[4] || !tcp->u_arg[5]) {
if (tcp->u_arg[4] == 0)
- tprints(", NULL");
+ jprints(", NULL");
else
tprintf(", %#lx", tcp->u_arg[4]);
if (tcp->u_arg[5] == 0)
- tprints(", NULL");
+ jprints(", NULL");
else
tprintf(", %#lx", tcp->u_arg[5]);
return 0;
}
if (umove(tcp, tcp->u_arg[5], &fromlen) < 0) {
- tprints(", {...}, [?]");
+ jprintf(", '...', [false]", ", {...}, [?]");
return 0;
}
tprints(", ");
@@ -790,7 +804,7 @@ sys_recvmmsg(struct tcb *tcp)
if (verbose(tcp)) {
decode_mmsg(tcp, 0);
/* timeout on entrance */
- tprintf(", %s", tcp->auxstr ? tcp->auxstr : "{...}");
+ tprintf(", %s", tcp->auxstr ? tcp->auxstr : jsonstr("...", "{...}"));
free((void *) tcp->auxstr);
tcp->auxstr = NULL;
}
@@ -892,7 +906,7 @@ sys_socketpair(struct tcb *tcp)
return 0;
}
if (umoven(tcp, tcp->u_arg[3], sizeof fds, (char *) fds) < 0)
- tprints(", [...]");
+ jprints(", [...]");
else
tprintf(", [%u, %u]", fds[0], fds[1]);
}
@@ -968,7 +982,7 @@ sys_getsockopt(struct tcb *tcp)
tcp->u_arg[3],
&linger) < 0)
break;
- tprintf("{onoff=%d, linger=%d}, "
+ jprintf_struct("{onoff=%d, linger=%d}, "
"[%d]",
linger.l_onoff,
linger.l_linger,
@@ -985,7 +999,7 @@ sys_getsockopt(struct tcb *tcp)
tcp->u_arg[3],
&uc) < 0)
break;
- tprintf("{pid=%ld, uid=%ld, gid=%ld}, "
+ jprintf_struct("{pid=%ld, uid=%ld, gid=%ld}, "
"[%d]",
(long)uc.pid,
(long)uc.uid,
@@ -1007,7 +1021,7 @@ sys_getsockopt(struct tcb *tcp)
tcp->u_arg[3],
&stats) < 0)
break;
- tprintf("{packets=%u, drops=%u}, "
+ jprintf_struct("{packets=%u, drops=%u}, "
"[%d]",
stats.tp_packets,
stats.tp_drops,
@@ -1037,7 +1051,7 @@ static void printicmpfilter(struct tcb *tcp, long addr)
struct icmp_filter filter;
if (!addr) {
- tprints("NULL");
+ jprints("NULL");
return;
}
if (syserror(tcp) || !verbose(tcp)) {
@@ -1045,13 +1059,13 @@ static void printicmpfilter(struct tcb *tcp, long addr)
return;
}
if (umove(tcp, addr, &filter) < 0) {
- tprints("{...}");
+ jprintf("['...']", "{...}");
return;
}
- tprints("~(");
+ tprints(jsonstr("[", "~("));
printflags(icmpfilterflags, ~filter.data, "ICMP_???");
- tprints(")");
+ tprints(jsonstr("]", ")"));
}
#endif /* ICMP_FILTER */
@@ -1070,7 +1084,7 @@ printsockopt(struct tcb *tcp, int level, int name, long addr, int len)
struct linger linger;
if (umove(tcp, addr, &linger) < 0)
break;
- tprintf(", {onoff=%d, linger=%d}",
+ jprintf_struct(", {onoff=%d, linger=%d}",
linger.l_onoff,
linger.l_linger);
return 0;
@@ -1110,7 +1124,7 @@ printsockopt(struct tcb *tcp, int level, int name, long addr, int len)
struct tpacket_req req;
if (umove(tcp, addr, &req) < 0)
break;
- tprintf(", {block_size=%u, block_nr=%u, frame_size=%u, frame_nr=%u}",
+ jprintf_struct(", {block_size=%u, block_nr=%u, frame_size=%u, frame_nr=%u}",
req.tp_block_size,
req.tp_block_nr,
req.tp_frame_size,
diff --git a/process.c b/process.c
index 2cd0f01..9476c87 100644
--- a/process.c
+++ b/process.c
@@ -124,7 +124,7 @@ unalignctl_string(unsigned int ctl)
default:
break;
}
- sprintf(buf, "%x", ctl);
+ sprintf(buf, jsonstr("%u", "%x"), ctl);
return buf;
}
@@ -189,7 +189,7 @@ sys_prctl(struct tcb *tcp)
if (umove(tcp, tcp->u_arg[1], &i) < 0)
tprintf(", %#lx", tcp->u_arg[1]);
else
- tprintf(", {%u}", i);
+ jprintf(", [$]", ", {%u}", i);
break;
#endif
#ifdef PR_GET_DUMPABLE
@@ -258,9 +258,9 @@ sys_exit(struct tcb *tcp)
return -1;
}
/* special case: we stop tracing this process, finish line now */
- tprintf("%ld) ", tcp->u_arg[0]);
+ jprintf("$], ", "%ld) ", tcp->u_arg[0]);
tabto();
- tprints("= ?\n");
+ jprintf(JSON_PAIR_FORMAT("ret", "'?' }\n"), "= ?\n");
line_ended();
return 0;
}
@@ -337,41 +337,47 @@ int
sys_clone(struct tcb *tcp)
{
if (exiting(tcp)) {
- const char *sep = "|";
+ const char *sep = jsonstr(",", "|");
unsigned long flags = tcp->u_arg[ARG_FLAGS];
- tprintf("child_stack=%#lx, ", tcp->u_arg[ARG_STACK]);
+ tprints(jsonstr("{", ""));
+ jprintf_struct("child_stack=%#lx, ", tcp->u_arg[ARG_STACK]);
#ifdef ARG_STACKSIZE
if (ARG_STACKSIZE != -1)
- tprintf("stack_size=%#lx, ",
- tcp->u_arg[ARG_STACKSIZE]);
+ jprintf_struct("stack_size=%#lx, ", tcp->u_arg[ARG_STACKSIZE]);
#endif
- tprints("flags=");
+ jprintf_struct("flags=");
+ json_set_printflags_array(0, "[");
if (!printflags(clone_flags, flags &~ CSIGNAL, NULL))
sep = "";
if ((flags & CSIGNAL) != 0)
- tprintf("%s%s", sep, signame(flags & CSIGNAL));
+ jprintf("%s $", "%s%s", sep, signame(flags & CSIGNAL));
+ json_set_printflags_array(1, "]");
if ((flags & (CLONE_PARENT_SETTID|CLONE_CHILD_SETTID
- |CLONE_CHILD_CLEARTID|CLONE_SETTLS)) == 0)
+ |CLONE_CHILD_CLEARTID|CLONE_SETTLS)) == 0) {
+ tprints(jsonstr("}", ""));
return 0;
+ }
if (flags & CLONE_PARENT_SETTID)
- tprintf(", parent_tidptr=%#lx", tcp->u_arg[ARG_PTID]);
+ jprintf_struct(", parent_tidptr=%#lx", tcp->u_arg[ARG_PTID]);
if (flags & CLONE_SETTLS) {
#if defined I386 || defined X86_64 || defined X32
# ifndef I386
if (current_personality == 1)
# endif
{
- tprints(", tls=");
+ jprintf_struct(", tls=");
print_user_desc(tcp, tcp->u_arg[ARG_TLS]);
}
# ifndef I386
else
# endif
#endif /* I386 || X86_64 || X32 */
- tprintf(", tls=%#lx", tcp->u_arg[ARG_TLS]);
+ jprintf_struct(", tls=%#lx", tcp->u_arg[ARG_TLS]);
+ }
+ if (flags & (CLONE_CHILD_SETTID|CLONE_CHILD_CLEARTID)) {
+ jprintf_struct(", child_tidptr=%#lx", tcp->u_arg[ARG_CTID]);
+ tprints(jsonstr("}", ""));
}
- if (flags & (CLONE_CHILD_SETTID|CLONE_CHILD_CLEARTID))
- tprintf(", child_tidptr=%#lx", tcp->u_arg[ARG_CTID]);
}
/* TODO on syscall entry:
* We can clear CLONE_PTRACE here since it is an ancient hack
@@ -503,7 +509,7 @@ sys_setgroups(struct tcb *tcp)
}
start = tcp->u_arg[1];
if (start == 0) {
- tprints("NULL");
+ jprints("NULL");
return 0;
}
size = len * sizeof(gid);
@@ -524,11 +530,11 @@ sys_setgroups(struct tcb *tcp)
if (cur > start)
tprints(", ");
if (cur >= abbrev_end) {
- tprints("...");
+ jprints("...");
break;
}
if (umoven(tcp, cur, sizeof(gid), (char *) &gid) < 0) {
- tprints("?");
+ jprints("?");
failed = 1;
break;
}
@@ -536,7 +542,7 @@ sys_setgroups(struct tcb *tcp)
}
tprints("]");
if (failed)
- tprintf(" %#lx", tcp->u_arg[1]);
+ jprintf(", $", " %#lx", tcp->u_arg[1]);
}
return 0;
}
@@ -561,7 +567,7 @@ sys_getgroups(struct tcb *tcp)
}
start = tcp->u_arg[1];
if (start == 0) {
- tprints("NULL");
+ jprints("NULL");
return 0;
}
if (tcp->u_arg[0] == 0) {
@@ -587,11 +593,11 @@ sys_getgroups(struct tcb *tcp)
if (cur > start)
tprints(", ");
if (cur >= abbrev_end) {
- tprints("...");
+ jprints("...");
break;
}
if (umoven(tcp, cur, sizeof(gid), (char *) &gid) < 0) {
- tprints("?");
+ jprints("?");
failed = 1;
break;
}
@@ -599,7 +605,7 @@ sys_getgroups(struct tcb *tcp)
}
tprints("]");
if (failed)
- tprintf(" %#lx", tcp->u_arg[1]);
+ jprintf(", $", " %#lx", tcp->u_arg[1]);
}
return 0;
}
@@ -620,7 +626,7 @@ sys_setgroups32(struct tcb *tcp)
}
start = tcp->u_arg[1];
if (start == 0) {
- tprints("NULL");
+ jprints("NULL");
return 0;
}
size = len * sizeof(gid);
@@ -641,11 +647,11 @@ sys_setgroups32(struct tcb *tcp)
if (cur > start)
tprints(", ");
if (cur >= abbrev_end) {
- tprints("...");
+ jprints("...");
break;
}
if (umoven(tcp, cur, sizeof(gid), (char *) &gid) < 0) {
- tprints("?");
+ jprints("?");
failed = 1;
break;
}
@@ -653,7 +659,7 @@ sys_setgroups32(struct tcb *tcp)
}
tprints("]");
if (failed)
- tprintf(" %#lx", tcp->u_arg[1]);
+ jprintf(", $", " %#lx", tcp->u_arg[1]);
}
return 0;
}
@@ -678,7 +684,7 @@ sys_getgroups32(struct tcb *tcp)
}
start = tcp->u_arg[1];
if (start == 0) {
- tprints("NULL");
+ jprints("NULL");
return 0;
}
size = len * sizeof(gid);
@@ -700,11 +706,11 @@ sys_getgroups32(struct tcb *tcp)
if (cur > start)
tprints(", ");
if (cur >= abbrev_end) {
- tprints("...");
+ jprints("...");
break;
}
if (umoven(tcp, cur, sizeof(gid), (char *) &gid) < 0) {
- tprints("?");
+ jprints("?");
failed = 1;
break;
}
@@ -712,7 +718,7 @@ sys_getgroups32(struct tcb *tcp)
}
tprints("]");
if (failed)
- tprintf(" %#lx", tcp->u_arg[1]);
+ jprintf(", $", " %#lx", tcp->u_arg[1]);
}
return 0;
}
@@ -744,7 +750,7 @@ printargv(struct tcb *tcp, long addr)
addr += wordsize;
}
if (cp.p64)
- tprintf("%s...", sep);
+ jprintf("$ '...'", "%s...", sep);
}
static void
@@ -756,7 +762,7 @@ printargc(const char *fmt, struct tcb *tcp, long addr)
for (count = 0; umove(tcp, addr, &cp) >= 0 && cp != NULL; count++) {
addr += sizeof(char *);
}
- tprintf(fmt, count, count == 1 ? "" : "s");
+ jprintf(", $", fmt, count, count == 1 ? "" : "s");
}
#if defined(SPARC) || defined(SPARC64)
@@ -841,19 +847,20 @@ printstatus(int status)
* are no wait status constructors it will have to do.
*/
if (WIFSTOPPED(status)) {
- tprintf("[{WIFSTOPPED(s) && WSTOPSIG(s) == %s}",
- signame(WSTOPSIG(status)));
+ jprintf("[{'WIFSTOPPED(s) && WSTOPSIG(s)': $}",
+ "[{WIFSTOPPED(s) && WSTOPSIG(s) == %s}", signame(WSTOPSIG(status)));
status &= ~W_STOPCODE(WSTOPSIG(status));
}
else if (WIFSIGNALED(status)) {
- tprintf("[{WIFSIGNALED(s) && WTERMSIG(s) == %s%s}",
- signame(WTERMSIG(status)),
- WCOREDUMP(status) ? " && WCOREDUMP(s)" : "");
+ jprintf("[{'WIFSIGNALED(s) && WTERMSIG(s)': [$, $]}",
+ "[{WIFSIGNALED(s) && WTERMSIG(s) == %s%s}",
+ signame(WTERMSIG(status)),
+ WCOREDUMP(status) ? " && WCOREDUMP(s)" : "");
status &= ~(W_EXITCODE(0, WTERMSIG(status)) | WCOREFLAG);
}
else if (WIFEXITED(status)) {
- tprintf("[{WIFEXITED(s) && WEXITSTATUS(s) == %d}",
- WEXITSTATUS(status));
+ jprintf("[{'WIFEXITED(s) && WEXITSTATUS(s)': $}",
+ "[{WIFEXITED(s) && WEXITSTATUS(s) == %d}", WEXITSTATUS(status));
exited = 1;
status &= ~W_EXITCODE(WEXITSTATUS(status), 0);
}
@@ -865,7 +872,7 @@ printstatus(int status)
if (status == 0)
tprints("]");
else
- tprintf(" | %#x]", status);
+ jprintf(", $]", " | %#x]", status);
return exited;
}
@@ -887,11 +894,11 @@ printwaitn(struct tcb *tcp, int n, int bitness)
} else {
/* status */
if (!tcp->u_arg[1])
- tprints("NULL");
+ jprints("NULL");
else if (syserror(tcp) || tcp->u_rval == 0)
tprintf("%#lx", tcp->u_arg[1]);
else if (umove(tcp, tcp->u_arg[1], &status) < 0)
- tprints("[?]");
+ jprints("[?]");
else
printstatus(status);
/* options */
@@ -901,7 +908,7 @@ printwaitn(struct tcb *tcp, int n, int bitness)
tprints(", ");
/* usage */
if (!tcp->u_arg[3])
- tprints("NULL");
+ jprints("NULL");
else if (tcp->u_rval > 0) {
#ifdef ALPHA
if (bitness)
@@ -956,7 +963,7 @@ sys_waitid(struct tcb *tcp)
/* usage */
tprints(", ");
if (!tcp->u_arg[4])
- tprints("NULL");
+ jprints("NULL");
else if (tcp->u_error)
tprintf("%#lx", tcp->u_arg[4]);
else
@@ -975,21 +982,21 @@ sys_uname(struct tcb *tcp)
if (syserror(tcp) || !verbose(tcp))
tprintf("%#lx", tcp->u_arg[0]);
else if (umove(tcp, tcp->u_arg[0], &uname) < 0)
- tprints("{...}");
+ jprintf("['...']", "{...}");
else if (!abbrev(tcp)) {
- tprintf("{sysname=\"%s\", nodename=\"%s\", ",
- uname.sysname, uname.nodename);
- tprintf("release=\"%s\", version=\"%s\", ",
- uname.release, uname.version);
- tprintf("machine=\"%s\"", uname.machine);
+ jprintf_struct("{sysname=\"%s\", nodename=\"%s\", ", uname.sysname, uname.nodename);
+ jprintf_struct("release=\"%s\", version=\"%s\", ", uname.release, uname.version);
+ jprintf_struct("machine=\"%s\"", uname.machine);
#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME
- tprintf(", domainname=\"%s\"", uname.domainname);
+ jprintf_struct(", domainname=\"%s\"", uname.domainname);
#endif
tprints("}");
}
- else
- tprintf("{sys=\"%s\", node=\"%s\", ...}",
- uname.sysname, uname.nodename);
+ else {
+ jprintf_struct("{sys=\"%s\", node=\"%s\"", uname.sysname, uname.nodename);
+ tprints(jsonstr("", ", ..."));
+ tprints("}");
+ }
}
return 0;
}
@@ -2121,7 +2128,7 @@ sys_ptrace(struct tcb *tcp)
tprintf("%#lx, ", addr);
else if (x->val > addr && x != struct_user_offsets) {
x--;
- tprintf("%s + %ld, ", x->str, addr - x->val);
+ jprintf("[$, $], ", "%s + %ld, ", x->str, addr - x->val);
}
else
tprintf("%s, ", x->str);
@@ -2308,15 +2315,16 @@ sys_futex(struct tcb *tcp)
else if (cmd == FUTEX_CMP_REQUEUE || cmd == FUTEX_CMP_REQUEUE_PI)
tprintf(", %ld, %p, %ld", tcp->u_arg[3], (void *) tcp->u_arg[4], tcp->u_arg[5]);
else if (cmd == FUTEX_WAKE_OP) {
- tprintf(", %ld, %p, {", tcp->u_arg[3], (void *) tcp->u_arg[4]);
+ jprintf(", $, $, [", ", %ld, %p, {",
+ tcp->u_arg[3], (void *) tcp->u_arg[4]);
if ((tcp->u_arg[5] >> 28) & 8)
- tprints("FUTEX_OP_OPARG_SHIFT|");
+ jprintf("'FUTEX_OP_OPARG_SHIFT', ", "FUTEX_OP_OPARG_SHIFT|");
printxval(futexwakeops, (tcp->u_arg[5] >> 28) & 0x7, "FUTEX_OP_???");
tprintf(", %ld, ", (tcp->u_arg[5] >> 12) & 0xfff);
if ((tcp->u_arg[5] >> 24) & 8)
- tprints("FUTEX_OP_OPARG_SHIFT|");
+ jprintf("'FUTEX_OP_OPARG_SHIFT', ", "FUTEX_OP_OPARG_SHIFT|");
printxval(futexwakecmps, (tcp->u_arg[5] >> 24) & 0x7, "FUTEX_OP_CMP_???");
- tprintf(", %ld}", tcp->u_arg[5] & 0xfff);
+ jprintf(", $]", ", %ld}", tcp->u_arg[5] & 0xfff);
} else if (cmd == FUTEX_WAIT_REQUEUE_PI) {
tprints(", ");
printtv(tcp, tcp->u_arg[3]);
@@ -2341,7 +2349,7 @@ print_affinitylist(struct tcb *tcp, long list, unsigned int len)
if (umove(tcp, list, &w) < 0)
break;
if (first)
- tprints("{");
+ tprints(jsonstr("[", "{"));
else
tprints(", ");
first = 0;
@@ -2351,10 +2359,10 @@ print_affinitylist(struct tcb *tcp, long list, unsigned int len)
if (first)
tprintf("%#lx", list);
else
- tprintf(", %s}", (len >= sizeof(w) && len > min_len ?
+ jprintf(", $]", ", %s}", (len >= sizeof(w) && len > min_len ?
"???" : "..."));
} else {
- tprints(first ? "{}" : "}");
+ tprints(first ? jsonstr("[]","{}") : jsonstr("]","}"));
}
}
@@ -2435,7 +2443,7 @@ sys_sched_setscheduler(struct tcb *tcp)
if (umove(tcp, tcp->u_arg[2], &p) < 0)
tprintf(", %#lx", tcp->u_arg[2]);
else
- tprintf(", { %d }", p.sched_priority);
+ jprintf(", [ $ ]", ", { %d }", p.sched_priority);
}
return 0;
}
@@ -2450,7 +2458,7 @@ sys_sched_getparam(struct tcb *tcp)
if (umove(tcp, tcp->u_arg[1], &p) < 0)
tprintf("%#lx", tcp->u_arg[1]);
else
- tprintf("{ %d }", p.sched_priority);
+ jprintf("[ $ ]", "{ %d }", p.sched_priority);
}
return 0;
}
@@ -2463,7 +2471,7 @@ sys_sched_setparam(struct tcb *tcp)
if (umove(tcp, tcp->u_arg[1], &p) < 0)
tprintf("%d, %#lx", (int) tcp->u_arg[0], tcp->u_arg[1]);
else
- tprintf("%d, { %d }", (int) tcp->u_arg[0], p.sched_priority);
+ jprintf("$, [ $ ]", "%d, { %d }", (int) tcp->u_arg[0], p.sched_priority);
}
return 0;
}
@@ -2527,13 +2535,13 @@ sys_getcpu(struct tcb *tcp)
if (exiting(tcp)) {
unsigned u;
if (tcp->u_arg[0] == 0)
- tprints("NULL, ");
+ jprints("NULL, ");
else if (umove(tcp, tcp->u_arg[0], &u) < 0)
tprintf("%#lx, ", tcp->u_arg[0]);
else
tprintf("[%u], ", u);
if (tcp->u_arg[1] == 0)
- tprints("NULL, ");
+ jprints("NULL, ");
else if (umove(tcp, tcp->u_arg[1], &u) < 0)
tprintf("%#lx, ", tcp->u_arg[1]);
else
diff --git a/resource.c b/resource.c
index 12e218f..534b2ed 100644
--- a/resource.c
+++ b/resource.c
@@ -61,8 +61,8 @@ print_rlimit64(struct tcb *tcp, unsigned long addr)
if (umove(tcp, addr, &rlim) < 0)
tprintf("%#lx", addr);
else {
- tprintf("{rlim_cur=%s,", sprint_rlim64(rlim.rlim_cur));
- tprintf(" rlim_max=%s}", sprint_rlim64(rlim.rlim_max));
+ jprintf_struct("{rlim_cur=%s,", sprint_rlim64(rlim.rlim_cur));
+ jprintf_struct(" rlim_max=%s}", sprint_rlim64(rlim.rlim_max));
}
}
@@ -106,8 +106,8 @@ print_rlimit32(struct tcb *tcp, unsigned long addr)
if (umove(tcp, addr, &rlim) < 0)
tprintf("%#lx", addr);
else {
- tprintf("{rlim_cur=%s,", sprint_rlim32(rlim.rlim_cur));
- tprintf(" rlim_max=%s}", sprint_rlim32(rlim.rlim_max));
+ jprintf_struct("{rlim_cur=%s,", sprint_rlim32(rlim.rlim_cur));
+ jprintf_struct(" rlim_max=%s}", sprint_rlim32(rlim.rlim_max));
}
}
@@ -115,7 +115,7 @@ static void
decode_rlimit(struct tcb *tcp, unsigned long addr)
{
if (!addr)
- tprints("NULL");
+ jprints("NULL");
else if (!verbose(tcp) || (exiting(tcp) && syserror(tcp)))
tprintf("%#lx", addr);
else {
@@ -247,32 +247,31 @@ printrusage(struct tcb *tcp, long addr)
struct rusage ru;
if (!addr)
- tprints("NULL");
+ jprints("NULL");
else if (syserror(tcp) || !verbose(tcp))
tprintf("%#lx", addr);
else if (umove(tcp, addr, &ru) < 0)
- tprints("{...}");
+ jprints("{...}");
else if (!abbrev(tcp)) {
- tprintf("{ru_utime={%lu, %lu}, ru_stime={%lu, %lu}, ",
- (long) ru.ru_utime.tv_sec, (long) ru.ru_utime.tv_usec,
- (long) ru.ru_stime.tv_sec, (long) ru.ru_stime.tv_usec);
- tprintf("ru_maxrss=%lu, ru_ixrss=%lu, ",
- ru.ru_maxrss, ru.ru_ixrss);
- tprintf("ru_idrss=%lu, ru_isrss=%lu, ",
- ru.ru_idrss, ru.ru_isrss);
- tprintf("ru_minflt=%lu, ru_majflt=%lu, ru_nswap=%lu, ",
- ru.ru_minflt, ru.ru_majflt, ru.ru_nswap);
- tprintf("ru_inblock=%lu, ru_oublock=%lu, ",
- ru.ru_inblock, ru.ru_oublock);
- tprintf("ru_msgsnd=%lu, ru_msgrcv=%lu, ",
- ru.ru_msgsnd, ru.ru_msgrcv);
- tprintf("ru_nsignals=%lu, ru_nvcsw=%lu, ru_nivcsw=%lu}",
- ru.ru_nsignals, ru.ru_nvcsw, ru.ru_nivcsw);
+ jprintf("{'ru_utime': [$, $], 'ru_stime': [$, $], ",
+ "{ru_utime={%lu, %lu}, ru_stime={%lu, %lu}, ",
+ (long) ru.ru_utime.tv_sec, (long) ru.ru_utime.tv_usec,
+ (long) ru.ru_stime.tv_sec, (long) ru.ru_stime.tv_usec);
+ jprintf_struct("%s=%lu, %s=%lu, ", "ru_maxrss", ru.ru_maxrss, "ru_ixrss", ru.ru_ixrss);
+ jprintf_struct("%s=%lu, %s=%lu, ", "ru_idrss", ru.ru_idrss, "ru_isrss", ru.ru_isrss);
+ jprintf_struct("%s=%lu, %s=%lu, %s=%lu, ", "ru_minflt", ru.ru_minflt, "ru_majflt", ru.ru_majflt, "ru_nswap", ru.ru_nswap);
+ jprintf_struct("%s=%lu, %s=%lu, ", "ru_inblock", ru.ru_inblock, "ru_oublock", ru.ru_oublock);
+ jprintf_struct("%s=%lu, %s=%lu, ", "ru_msgsnd", ru.ru_msgsnd, "ru_msgrcv", ru.ru_msgrcv);
+ jprintf_struct("%s=%lu, %s=%lu, %s=%lu}",
+ "ru_nsignals", ru.ru_nsignals,
+ "ru_nvcsw", ru.ru_nvcsw,
+ "ru_nivcsw", ru.ru_nivcsw);
}
else {
- tprintf("{ru_utime={%lu, %lu}, ru_stime={%lu, %lu}, ...}",
- (long) ru.ru_utime.tv_sec, (long) ru.ru_utime.tv_usec,
- (long) ru.ru_stime.tv_sec, (long) ru.ru_stime.tv_usec);
+ jprintf("{$: [$, $], $: [$, $]}",
+ "{%s={%lu, %lu}, %s={%lu, %lu}, ...}",
+ "ru_utime", (long) ru.ru_utime.tv_sec, (long) ru.ru_utime.tv_usec,
+ "ru_stime", (long) ru.ru_stime.tv_sec, (long) ru.ru_stime.tv_usec);
}
}
diff --git a/signal.c b/signal.c
index f013e0a..dd01f14 100644
--- a/signal.c
+++ b/signal.c
@@ -192,6 +192,7 @@ sprintsigmask_n(const char *prefix, const void *sig_mask, unsigned int bytes)
char sep;
s = stpcpy(outstr, prefix);
+ if (jflag) *s++ = '\"';
mask = sig_mask;
/* length of signal mask in 4-byte words */
@@ -227,6 +228,7 @@ sprintsigmask_n(const char *prefix, const void *sig_mask, unsigned int bytes)
if (sep == '[')
*s++ = sep;
*s++ = ']';
+ if (jflag) *s++ = '\"';
*s = '\0';
return outstr;
}
@@ -243,7 +245,7 @@ sprintsigmask_n(const char *prefix, const void *sig_mask, unsigned int bytes)
void
printsignal(int nr)
{
- tprints(signame(nr));
+ tprintf("%s", signame(nr));
}
void
@@ -252,7 +254,7 @@ print_sigset_addr_len(struct tcb *tcp, long addr, long len)
char mask[NSIG / 8];
if (!addr) {
- tprints("NULL");
+ jprints("NULL");
return;
}
/* Here len is usually equals NSIG / 8 or current_wordsize.
@@ -349,20 +351,19 @@ print_sigset_addr_len(struct tcb *tcp, long addr, long len)
static void
printsigsource(const siginfo_t *sip)
{
- tprintf(", si_pid=%lu, si_uid=%lu",
- (unsigned long) sip->si_pid,
- (unsigned long) sip->si_uid);
+ jprintf_struct(", si_pid=%lu, si_uid=%lu",
+ (unsigned long) sip->si_pid,
+ (unsigned long) sip->si_uid);
}
static void
printsigval(const siginfo_t *sip, int verbose)
{
if (!verbose)
- tprints(", ...");
+ jprints(", ...");
else
- tprintf(", si_value={int=%u, ptr=%#lx}",
- sip->si_int,
- (unsigned long) sip->si_ptr);
+ jprintf_struct(", si_value={int=%u, ptr=%#lx}",
+ sip->si_int, (unsigned long) sip->si_ptr);
}
void
@@ -374,7 +375,7 @@ printsiginfo(siginfo_t *sip, int verbose)
tprints("{}");
return;
}
- tprints("{si_signo=");
+ jprintf_struct("{si_signo=");
printsignal(sip->si_signo);
code = xlookup(siginfo_codes, sip->si_code);
if (!code) {
@@ -414,18 +415,18 @@ printsiginfo(siginfo_t *sip, int verbose)
}
}
if (code)
- tprintf(", si_code=%s", code);
+ jprintf(", $: $", ", %s=%s", "si_code", code);
else
- tprintf(", si_code=%#x", sip->si_code);
+ jprintf(", $: $", ", %s=%#x", "si_code", sip->si_code);
#ifdef SI_NOINFO
if (sip->si_code != SI_NOINFO)
#endif
{
if (sip->si_errno) {
if (sip->si_errno < 0 || sip->si_errno >= nerrnos)
- tprintf(", si_errno=%d", sip->si_errno);
+ jprintf(", $: $", ", %s=%d", "si_errno", sip->si_errno);
else
- tprintf(", si_errno=%s",
+ jprintf(", $: $", ", %s=%s", "si_errno",
errnoent[sip->si_errno]);
}
#ifdef SI_FROMUSER
@@ -443,8 +444,8 @@ printsiginfo(siginfo_t *sip, int verbose)
#endif
#ifdef SI_TIMER
case SI_TIMER:
- tprintf(", si_timerid=%#x, si_overrun=%d",
- sip->si_timerid, sip->si_overrun);
+ jprintf(", $: $, $: $", ", %s=%#x, %s=%d",
+ "si_timerid", sip->si_timerid, "si_overrun", sip->si_overrun);
printsigval(sip, verbose);
break;
#endif
@@ -461,7 +462,7 @@ printsiginfo(siginfo_t *sip, int verbose)
switch (sip->si_signo) {
case SIGCHLD:
printsigsource(sip);
- tprints(", si_status=");
+ jprintf(", $:", ", %s=", "si_status");
if (sip->si_code == CLD_EXITED)
tprintf("%d", sip->si_status);
else
@@ -469,28 +470,30 @@ printsiginfo(siginfo_t *sip, int verbose)
if (!verbose)
tprints(", ...");
else
- tprintf(", si_utime=%llu, si_stime=%llu",
- (unsigned long long) sip->si_utime,
- (unsigned long long) sip->si_stime);
+ jprintf(", $: $, $: $",
+ ", %s=%llu, %s=%llu",
+ "si_utime", (unsigned long long) sip->si_utime,
+ "si_stime", (unsigned long long) sip->si_stime);
break;
case SIGILL: case SIGFPE:
case SIGSEGV: case SIGBUS:
- tprintf(", si_addr=%#lx",
+ jprintf(", $: $", ", %s=%#lx", "si_addr",
(unsigned long) sip->si_addr);
break;
case SIGPOLL:
switch (sip->si_code) {
case POLL_IN: case POLL_OUT: case POLL_MSG:
- tprintf(", si_band=%ld",
+ jprintf(", $: $", ", %s=%ld", "si_band",
(long) sip->si_band);
break;
}
break;
#ifdef HAVE_SIGINFO_T_SI_SYSCALL
case SIGSYS:
- tprintf(", si_call_addr=%#lx, si_syscall=%d, si_arch=%u",
- (unsigned long) sip->si_call_addr,
- sip->si_syscall, sip->si_arch);
+ jprintf(", $: $, $: $, $: $",
+ ", %s=%#lx, %s=%d, %s=%u",
+ "si_call_addr", (unsigned long) sip->si_call_addr,
+ "si_syscall", sip->si_syscall, "si_arch", sip->si_arch);
break;
#endif
default:
@@ -509,7 +512,7 @@ printsiginfo_at(struct tcb *tcp, long addr)
{
siginfo_t si;
if (!addr) {
- tprints("NULL");
+ jprints("NULL");
return;
}
if (syserror(tcp)) {
@@ -517,7 +520,7 @@ printsiginfo_at(struct tcb *tcp, long addr)
return;
}
if (umove(tcp, addr, &si) < 0) {
- tprints("{???}");
+ tprints(jsonstr("[false]", "{???}"));
return;
}
printsiginfo(&si, verbose(tcp));
@@ -1149,7 +1152,7 @@ decode_new_sigaction(struct tcb *tcp, long addr)
int r;
if (!addr) {
- tprints("NULL");
+ jprints("NULL");
return;
}
if (!verbose(tcp) || (exiting(tcp) && syserror(tcp))) {
@@ -1181,7 +1184,7 @@ decode_new_sigaction(struct tcb *tcp, long addr)
r = umove(tcp, addr, &sa);
}
if (r < 0) {
- tprints("{...}");
+ jprintf("['...']", "{...}");
return;
}
/* Architectures using function pointers, like
@@ -1193,13 +1196,13 @@ decode_new_sigaction(struct tcb *tcp, long addr)
* compiler from generating code to manipulate
* __sa_handler we cast the function pointers to long. */
if ((long)sa.__sa_handler == (long)SIG_ERR)
- tprints("{SIG_ERR, ");
+ jprintf("['SIG_ERR', ", "{SIG_ERR, ");
else if ((long)sa.__sa_handler == (long)SIG_DFL)
- tprints("{SIG_DFL, ");
+ jprintf("['SIG_DFL', ", "{SIG_DFL, ");
else if ((long)sa.__sa_handler == (long)SIG_IGN)
- tprints("{SIG_IGN, ");
+ jprintf("['SIG_IGN', ", "{SIG_IGN, ");
else
- tprintf("{%#lx, ", (long) sa.__sa_handler);
+ jprintf("[$, ", "{%#lx, ", (long) sa.__sa_handler);
/*
* Sigset size is in tcp->u_arg[4] (SPARC)
* or in tcp->u_arg[3] (all other),
@@ -1215,7 +1218,7 @@ decode_new_sigaction(struct tcb *tcp, long addr)
if (sa.sa_flags & SA_RESTORER)
tprintf(", %p", sa.sa_restorer);
#endif
- tprints("}");
+ jprintf("]", "}");
}
int
diff --git a/strace.c b/strace.c
index 4154cde..6eeeb68 100644
--- a/strace.c
+++ b/strace.c
@@ -82,6 +82,7 @@ bool need_fork_exec_workarounds = 0;
bool debug_flag = 0;
bool Tflag = 0;
bool iflag = 0;
+bool jflag = 0;
bool count_wallclock = 0;
unsigned int qflag = 0;
/* Which WSTOPSIG(status) value marks syscall traps? */
@@ -535,11 +536,8 @@ strace_popen(const char *command)
}
void
-tprintf(const char *fmt, ...)
+tvprintf(const char *fmt, va_list args)
{
- va_list args;
-
- va_start(args, fmt);
if (current_tcp) {
int n = strace_vfprintf(current_tcp->outf, fmt, args);
if (n < 0) {
@@ -548,6 +546,26 @@ tprintf(const char *fmt, ...)
} else
current_tcp->curcol += n;
}
+}
+
+void
+_tprintf(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ tvprintf(fmt, args);
+ va_end(args);
+}
+
+void
+tprintf(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ if (jflag) {
+ fmt = json_translate_format(fmt);
+ }
+ tvprintf(fmt, args);
va_end(args);
}
@@ -648,7 +666,7 @@ printleader(struct tcb *tcp)
void
tabto(void)
{
- if (current_tcp->curcol < acolumn)
+ if (current_tcp->curcol < acolumn && !jflag)
tprints(acolumn_spaces + current_tcp->curcol);
}
@@ -708,7 +726,6 @@ alloctcb(int pid)
if (stack_trace_enabled)
unwind_tcb_init(tcp);
#endif
-
nprocs++;
if (debug_flag)
fprintf(stderr, "new tcb for pid %d, active tcbs:%d\n", tcp->pid, nprocs);
@@ -1672,7 +1689,7 @@ init(int argc, char *argv[])
#endif
qualify("signal=all");
while ((c = getopt(argc, argv,
- "+b:cCdfFhiqrtTvVwxyz"
+ "+b:cCdfFhijqrtTvVwxyz"
#ifdef USE_LIBUNWIND
"k"
#endif
@@ -1715,6 +1732,9 @@ init(int argc, char *argv[])
case 'i':
iflag = 1;
break;
+ case 'j':
+ jflag = 1;
+ break;
case 'q':
qflag++;
break;
@@ -2053,6 +2073,7 @@ trace(void)
int stopped;
struct tcb *tcp;
unsigned event;
+ // static int only_once = 1;
if (interrupted)
return;
@@ -2216,12 +2237,13 @@ trace(void)
tcp->pid = pid;
if (cflag != CFLAG_ONLY_STATS) {
printleader(tcp);
- tprintf("+++ superseded by execve in pid %lu +++\n", old_pid);
+ jprintf(JSON_SIGPLUS_FORMAT("superseded", "$"),
+ "+++ superseded by execve in pid %lu +++\n", old_pid);
line_ended();
tcp->flags |= TCB_REPRINT;
}
}
- dont_switch_tcbs:
+dont_switch_tcbs:
if (event == PTRACE_EVENT_EXEC) {
if (detach_on_execve && !skip_one_b_execve)
@@ -2245,12 +2267,13 @@ trace(void)
) {
printleader(tcp);
#ifdef WCOREDUMP
- tprintf("+++ killed by %s %s+++\n",
+ jprintf(JSON_SIGPLUS_FORMAT("killed", "[$, $]"),
+ "+++ killed by %s %s+++\n",
signame(WTERMSIG(status)),
WCOREDUMP(status) ? "(core dumped) " : "");
#else
- tprintf("+++ killed by %s +++\n",
- signame(WTERMSIG(status)));
+ jprintf(JSON_SIGPLUS_FORMAT("killed", "[$]")
+ "+++ killed by %s +++\n", signame(WTERMSIG(status)));
#endif
line_ended();
}
@@ -2263,7 +2286,8 @@ trace(void)
if (cflag != CFLAG_ONLY_STATS &&
qflag < 2) {
printleader(tcp);
- tprintf("+++ exited with %d +++\n", WEXITSTATUS(status));
+ jprintf(JSON_SIGPLUS_FORMAT("exited", "$"),
+ "+++ exited with %d +++\n", WEXITSTATUS(status));
line_ended();
}
droptcb(tcp);
@@ -2362,8 +2386,7 @@ trace(void)
printsiginfo(&si, verbose(tcp));
tprints(" ---\n");
} else
- tprintf("--- stopped by %s ---\n",
- signame(sig));
+ tprintf("--- stopped by %s ---\n", signame(sig));
line_ended();
}
@@ -2393,6 +2416,13 @@ trace(void)
if (interrupted)
return;
+ /*
+ * make the JSON output in a big array
+ if (only_once) {
+ tprints(jsonstr("[", ""));
+ only_once = 0;
+ }
+ */
/* This should be syscall entry or exit.
* (Or it still can be that pesky post-execve SIGTRAP!)
* Handle it.
diff --git a/syscall.c b/syscall.c
index b0ad47e..65dde6d 100644
--- a/syscall.c
+++ b/syscall.c
@@ -632,7 +632,7 @@ printargs(struct tcb *tcp)
int i;
int n = tcp->s_ent->nargs;
for (i = 0; i < n; i++)
- tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
+ jprintf("%s$", "%s%#lx", i ? ", " : "", tcp->u_arg[i]);
}
return 0;
}
@@ -644,7 +644,7 @@ printargs_lu(struct tcb *tcp)
int i;
int n = tcp->s_ent->nargs;
for (i = 0; i < n; i++)
- tprintf("%s%lu", i ? ", " : "", tcp->u_arg[i]);
+ _tprintf("%s%lu", i ? ", " : "", tcp->u_arg[i]);
}
return 0;
}
@@ -656,7 +656,7 @@ printargs_ld(struct tcb *tcp)
int i;
int n = tcp->s_ent->nargs;
for (i = 0; i < n; i++)
- tprintf("%s%ld", i ? ", " : "", tcp->u_arg[i]);
+ _tprintf("%s%ld", i ? ", " : "", tcp->u_arg[i]);
}
return 0;
}
@@ -1983,13 +1983,14 @@ trace_syscall_entering(struct tcb *tcp)
}
if (res != 1) {
+ tprints(jsonstr(JSON_SYSCALL_BEGIN, ""));
printleader(tcp);
if (scno_good != 1)
- tprints("????" /* anti-trigraph gap */ "(");
+ tprints(jsonstr("\"?\", " JSON_PAIR_FORMAT("args", "["), "????" /* anti-trigraph gap */ "("));
else if (tcp->qual_flg & UNDEFINED_SCNO)
- tprintf("%s(", undefined_scno_name(tcp));
+ jprintf("$, " JSON_PAIR_FORMAT("args", "["), "%s(", undefined_scno_name(tcp));
else
- tprintf("%s(", tcp->s_ent->sys_name);
+ jprintf("$, " JSON_PAIR_FORMAT("args", "["), "%s(", tcp->s_ent->sys_name);
/*
* " <unavailable>" will be added later by the code which
* detects ptrace errors.
@@ -2047,15 +2048,17 @@ trace_syscall_entering(struct tcb *tcp)
}
#endif
+ tprints(jsonstr(JSON_SYSCALL_BEGIN, ""));
printleader(tcp);
if (tcp->qual_flg & UNDEFINED_SCNO)
- tprintf("%s(", undefined_scno_name(tcp));
+ jprintf("$, " JSON_PAIR_FORMAT("args", "["), "%s(", undefined_scno_name(tcp));
else
- tprintf("%s(", tcp->s_ent->sys_name);
+ jprintf("$, " JSON_PAIR_FORMAT("args", "["), "%s(", tcp->s_ent->sys_name);
if ((tcp->qual_flg & QUAL_RAW) && tcp->s_ent->sys_func != sys_exit)
res = printargs(tcp);
- else
+ else {
res = tcp->s_ent->sys_func(tcp);
+ }
fflush(tcp->outf);
ret:
@@ -2560,17 +2563,20 @@ trace_syscall_exiting(struct tcb *tcp)
tcp->flags &= ~TCB_REPRINT;
printleader(tcp);
if (tcp->qual_flg & UNDEFINED_SCNO)
- tprintf("<... %s resumed> ", undefined_scno_name(tcp));
+ jprintf("<... $ resumed, please use -ff to output valid JSON result> ",
+ "<... %s resumed> ", undefined_scno_name(tcp));
else
- tprintf("<... %s resumed> ", tcp->s_ent->sys_name);
+ jprintf("<... $ resumed, please use -ff to output valid JSON result> ",
+ "<... %s resumed> ", tcp->s_ent->sys_name);
}
printing_tcp = tcp;
if (res != 1) {
/* There was error in one of prior ptrace ops */
- tprints(") ");
+ tprints(jsonstr("], ", ") "));
tabto();
- tprints("= ? <unavailable>\n");
+ jprintf(JSON_PAIR_FORMAT("ret", "\"?\", ") JSON_PAIR_FORMAT("desc", "$"),
+ "= ? <%s>\n", "unavailable");
line_ended();
tcp->flags &= ~TCB_INSYSCALL;
return res;
@@ -2593,14 +2599,15 @@ trace_syscall_exiting(struct tcb *tcp)
sys_res = tcp->s_ent->sys_func(tcp);
}
- tprints(") ");
+ tprints(jsonstr("], ", ") "));
tabto();
u_error = tcp->u_error;
if (tcp->qual_flg & QUAL_RAW) {
if (u_error)
- tprintf("= -1 (errno %ld)", u_error);
+ jprintf(JSON_PAIR_FORMAT("ret", "$, ") JSON_PAIR_FORMAT("errno", "$, "),
+ "= %d (errno %ld)", -1, u_error);
else
- tprintf("= %#lx", tcp->u_rval);
+ jprintf(JSON_PAIR_FORMAT("ret", "$"), "= %#lx", tcp->u_rval);
}
else if (!(sys_res & RVAL_NONE) && u_error) {
switch (u_error) {
@@ -2625,13 +2632,15 @@ trace_syscall_exiting(struct tcb *tcp)
* The system call will be restarted with the same arguments
* if SA_RESTART is set; otherwise, it will fail with EINTR.
*/
- tprints("= ? ERESTARTSYS (To be restarted if SA_RESTART is set)");
+ jprintf(JSON_PAIR_FORMAT("ret", "'?', ") JSON_PAIR_FORMAT("desc", "$"),
+ "= ? %s", "ERESTARTSYS (To be restarted if SA_RESTART is set)");
break;
case ERESTARTNOINTR:
/* Rare. For example, fork() returns this if interrupted.
* SA_RESTART is ignored (assumed set): the restart is unconditional.
*/
- tprints("= ? ERESTARTNOINTR (To be restarted)");
+ jprintf(JSON_PAIR_FORMAT("ret", "'?', ") JSON_PAIR_FORMAT("desc", "$"),
+ "= ? %s", "ERESTARTNOINTR (To be restarted)");
break;
case ERESTARTNOHAND:
/* pause(), rt_sigsuspend() etc use this code.
@@ -2641,7 +2650,8 @@ trace_syscall_exiting(struct tcb *tcp)
* after SIG_IGN or SIG_DFL signal it will restart
* (thus the name "restart only if has no handler").
*/
- tprints("= ? ERESTARTNOHAND (To be restarted if no handler)");
+ jprintf(JSON_PAIR_FORMAT("ret", "'?', ") JSON_PAIR_FORMAT("desc", "$"),
+ "= ? %s", "ERESTARTNOHAND (To be restarted if no handler)");
break;
case ERESTART_RESTARTBLOCK:
/* Syscalls like nanosleep(), poll() which can't be
@@ -2655,62 +2665,70 @@ trace_syscall_exiting(struct tcb *tcp)
* which in turn saves another such restart block,
* old data is lost and restart becomes impossible)
*/
- tprints("= ? ERESTART_RESTARTBLOCK (Interrupted by signal)");
+ jprintf(JSON_PAIR_FORMAT("ret", "'?', ") JSON_PAIR_FORMAT("desc", "$"),
+ "= ? %s", "ERESTART_RESTARTBLOCK (Interrupted by signal)");
break;
default:
if (u_error < 0)
- tprintf("= -1 E??? (errno %ld)", u_error);
+ jprintf(JSON_PAIR_FORMAT("ret", "-1, ")
+ JSON_PAIR_FORMAT("error", "$, ")
+ JSON_PAIR_FORMAT("errno", "$"),
+ "= -1 %s (errno %ld)", "E???", u_error);
else if (u_error < nerrnos)
- tprintf("= -1 %s (%s)", errnoent[u_error],
- strerror(u_error));
+ jprintf(JSON_PAIR_FORMAT("ret", "-1, ")
+ JSON_PAIR_FORMAT("error" ,"$, ")
+ JSON_PAIR_FORMAT("strerror", "$"),
+ "= -1 %s (%s)", errnoent[u_error], strerror(u_error));
else
- tprintf("= -1 ERRNO_%ld (%s)", u_error,
- strerror(u_error));
+ jprintf(JSON_PAIR_FORMAT("ret", "-1, ")
+ JSON_PAIR_FORMAT("errno", "$, ")
+ JSON_PAIR_FORMAT("strerror", "$"),
+ "= -1 ERRNO_%ld (%s)", u_error, strerror(u_error));
break;
}
if ((sys_res & RVAL_STR) && tcp->auxstr)
- tprintf(" (%s)", tcp->auxstr);
+ jprintf(", " JSON_PAIR_FORMAT("auxstr", "$"), " (%s)", tcp->auxstr);
}
else {
if (sys_res & RVAL_NONE)
- tprints("= ?");
+ jprintf(JSON_PAIR_FORMAT("ret", "'?'"), "= ?");
else {
switch (sys_res & RVAL_MASK) {
case RVAL_HEX:
- tprintf("= %#lx", tcp->u_rval);
+ jprintf(JSON_PAIR_FORMAT("ret", "$"), "= %#lx", tcp->u_rval);
break;
case RVAL_OCTAL:
- tprintf("= %#lo", tcp->u_rval);
+ jprintf(JSON_PAIR_FORMAT("ret", "$"), "= %#lo", tcp->u_rval);
break;
case RVAL_UDECIMAL:
- tprintf("= %lu", tcp->u_rval);
+ jprintf(JSON_PAIR_FORMAT("ret", "$"), "= %lu", tcp->u_rval);
break;
case RVAL_DECIMAL:
- tprintf("= %ld", tcp->u_rval);
+ jprintf(JSON_PAIR_FORMAT("ret", "$"), "= %ld", tcp->u_rval);
break;
case RVAL_FD:
if (show_fd_path) {
- tprints("= ");
+ tprints(jsonstr(JSON_PAIR_FORMAT("ret", "") , "= "));
printfd(tcp, tcp->u_rval);
}
else
- tprintf("= %ld", tcp->u_rval);
+ jprintf(JSON_PAIR_FORMAT("ret", "$"), "= %ld", tcp->u_rval);
break;
#if defined(LINUX_MIPSN32) || defined(X32)
/*
case RVAL_LHEX:
- tprintf("= %#llx", tcp->u_lrval);
+ jprintf(JSON_PAIR_FORMAT("ret", "$"), "= %#llx", tcp->u_lrval);
break;
case RVAL_LOCTAL:
- tprintf("= %#llo", tcp->u_lrval);
+ jprintf(JSON_PAIR_FORMAT("ret", "$"), "= %#llo", tcp->u_lrval);
break;
*/
case RVAL_LUDECIMAL:
- tprintf("= %llu", tcp->u_lrval);
+ jprintf(JSON_PAIR_FORMAT("ret", "$"), "= %llu", tcp->u_lrval);
break;
/*
case RVAL_LDECIMAL:
- tprintf("= %lld", tcp->u_lrval);
+ jprintf(JSON_PAIR_FORMAT("ret", "$"), "= %lld", tcp->u_lrval);
break;
*/
#endif
@@ -2721,14 +2739,14 @@ trace_syscall_exiting(struct tcb *tcp)
}
}
if ((sys_res & RVAL_STR) && tcp->auxstr)
- tprintf(" (%s)", tcp->auxstr);
+ jprintf(", " JSON_PAIR_FORMAT("auxstr", "$"), " (%s)", tcp->auxstr);
}
if (Tflag) {
tv_sub(&tv, &tv, &tcp->etime);
tprintf(" <%ld.%06ld>",
(long) tv.tv_sec, (long) tv.tv_usec);
}
- tprints("\n");
+ tprints(jsonstr("}\n", "\n"));
dumpio(tcp);
line_ended();
diff --git a/term.c b/term.c
index d1c9b65..a5ed28a 100644
--- a/term.c
+++ b/term.c
@@ -71,27 +71,32 @@ int term_ioctl(struct tcb *tcp, long code, long arg)
if (!verbose(tcp) || umove(tcp, arg, &tios) < 0)
return 0;
if (abbrev(tcp)) {
- tprints(", {");
+ tprints(jsonstr(", [", ", {"));
printxval(baud_options, tios.c_cflag & CBAUD, "B???");
- tprintf(" %sopost %sisig %sicanon %secho ...}",
+ jprintf(", '%sopost', '%sisig', '%sicanon', '%secho', '...']",
+ " %sopost %sisig %sicanon %secho ...}",
(tios.c_oflag & OPOST) ? "" : "-",
(tios.c_lflag & ISIG) ? "" : "-",
(tios.c_lflag & ICANON) ? "" : "-",
(tios.c_lflag & ECHO) ? "" : "-");
return 1;
}
- tprintf(", {c_iflags=%#lx, c_oflags=%#lx, ",
- (long) tios.c_iflag, (long) tios.c_oflag);
- tprintf("c_cflags=%#lx, c_lflags=%#lx, ",
- (long) tios.c_cflag, (long) tios.c_lflag);
- tprintf("c_line=%u, ", tios.c_line);
+ jprintf(", {$: $, $: $, ", ", {%s=%#lx, %s=%#lx, ",
+ "c_iflags", (long) tios.c_iflag,
+ "c_oflags", (long) tios.c_oflag);
+ jprintf("$: $, $ :$, ", "%s=%#lx, %s=%#lx, ",
+ "c_cflags", (long) tios.c_cflag,
+ "c_lflags", (long) tios.c_lflag);
+ jprintf("$: $, ", "%s=%u, ", "c_line", tios.c_line);
if (!(tios.c_lflag & ICANON))
- tprintf("c_cc[VMIN]=%d, c_cc[VTIME]=%d, ",
- tios.c_cc[VMIN], tios.c_cc[VTIME]);
- tprintf("c_cc=\"");
- for (i = 0; i < NCCS; i++)
- tprintf("\\x%02x", tios.c_cc[i]);
- tprintf("\"}");
+ jprintf("$: $, $: $, ", "%s=%d, %s=%d, ",
+ "c_cc[VMIN]", tios.c_cc[VMIN],
+ "c_cc[VTIME]", tios.c_cc[VTIME]);
+ jprintf("{'c_cc': '", "c_cc=\"");
+ for (i = 0; i < NCCS; i++) {
+ jprintf("\\\\x%02x", "\\x%02x", tios.c_cc[i]);
+ }
+ jprintf("'} }", "\"}");
return 1;
#endif /* TCGETS */
@@ -105,33 +110,32 @@ int term_ioctl(struct tcb *tcp, long code, long arg)
if (!verbose(tcp) || umove(tcp, arg, &tio) < 0)
return 0;
if (abbrev(tcp)) {
- tprints(", {");
+ tprints(jsonstr(", [", ", {"));
printxval(baud_options, tio.c_cflag & CBAUD, "B???");
- tprintf(" %sopost %sisig %sicanon %secho ...}",
+ jprintf(", \"$opost\", \"$isig\", \"$icanon\", \"$echo\", \"...\"]",
+ " %sopost %sisig %sicanon %secho ...}",
(tio.c_oflag & OPOST) ? "" : "-",
(tio.c_lflag & ISIG) ? "" : "-",
(tio.c_lflag & ICANON) ? "" : "-",
(tio.c_lflag & ECHO) ? "" : "-");
return 1;
}
- tprintf(", {c_iflags=%#lx, c_oflags=%#lx, ",
- (long) tio.c_iflag, (long) tio.c_oflag);
- tprintf("c_cflags=%#lx, c_lflags=%#lx, ",
- (long) tio.c_cflag, (long) tio.c_lflag);
- tprintf("c_line=%u, ", tio.c_line);
+ jprintf_struct(", {c_iflags=%#lx, c_oflags=%#lx, ", (long) tio.c_iflag, (long) tio.c_oflag);
+ jprintf_struct("c_cflags=%#lx, c_lflags=%#lx, ", (long) tio.c_cflag, (long) tio.c_lflag);
+ jprintf_struct("c_line=%u, ", tio.c_line);
#ifdef _VMIN
if (!(tio.c_lflag & ICANON))
- tprintf("c_cc[_VMIN]=%d, c_cc[_VTIME]=%d, ",
- tio.c_cc[_VMIN], tio.c_cc[_VTIME]);
+ jprintf_struct("c_cc[_VMIN]=%d, c_cc[_VTIME]=%d, ", tio.c_cc[_VMIN], tio.c_cc[_VTIME]);
#else /* !_VMIN */
if (!(tio.c_lflag & ICANON))
- tprintf("c_cc[VMIN]=%d, c_cc[VTIME]=%d, ",
- tio.c_cc[VMIN], tio.c_cc[VTIME]);
+ jprintf_struct("c_cc[VMIN]=%d, c_cc[VTIME]=%d, ", tio.c_cc[VMIN], tio.c_cc[VTIME]);
#endif /* !_VMIN */
- tprintf("c_cc=\"");
- for (i = 0; i < NCC; i++)
- tprintf("\\x%02x", tio.c_cc[i]);
- tprintf("\"}");
+ jprintf("{'c_cc': [", "c_cc=\"");
+ for (i = 0; i < NCC; i++) {
+ tprints(jsonstr(i != 0 ? ", " : "", ""));
+ jprintf("$", "\\x%02x", tio.c_cc[i]);
+ }
+ tprints(jsonstr("]} }", "\"}"));
return 1;
#endif /* TCGETA */
@@ -144,8 +148,12 @@ int term_ioctl(struct tcb *tcp, long code, long arg)
case TIOCSWINSZ:
if (!verbose(tcp) || umove(tcp, arg, &ws) < 0)
return 0;
- tprintf(", {ws_row=%d, ws_col=%d, ws_xpixel=%d, ws_ypixel=%d}",
- ws.ws_row, ws.ws_col, ws.ws_xpixel, ws.ws_ypixel);
+ jprintf(", {$: $, $: $, $: $, $: $}",
+ ", {%s=%d, %s=%d, %s=%d, %s=%d}",
+ "ws_row", ws.ws_row,
+ "ws_col", ws.ws_col,
+ "ws_xpixel", ws.ws_xpixel,
+ "ws_ypixel", ws.ws_ypixel);
return 1;
#endif /* TIOCGWINSZ */
diff --git a/test/.gitignore b/test/.gitignore
index c73b64a..b7b4417 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -1,3 +1,4 @@
+json_test
vfork
fork
sig
diff --git a/test/Makefile b/test/Makefile
index cc7d47a..bdd86f2 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -3,7 +3,7 @@ CFLAGS += -Wall
PROGS = \
vfork fork sig skodic clone leaderkill childthread \
sigkill_rain wait_must_be_interruptible threaded_execve \
- mtd ubi select sigreturn
+ mtd ubi select sigreturn json_test
all: $(PROGS)
diff --git a/test/json_io.c b/test/json_io.c
new file mode 100644
index 0000000..ea95c2a
--- /dev/null
+++ b/test/json_io.c
@@ -0,0 +1,98 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <sys/sendfile.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <linux/fs.h>
+
+void test(void)
+{
+ #define BUFSIZE (1000)
+ static char buf[BUFSIZE] = "xm\216\315r\177\0\0 \304\311\315r\177\0\0\0\0\0\0\1\0\0\0\242\10\0\0\1\0\0\0";
+ static char str[] = "helloworld, this_is_a_test_string,\n\n\n. !@$%^$!@, \\{{{\"\"\"]]]}}}%%---%%";
+ int strsz = strlen(str) + 1;
+
+ int fd1 = open("/tmp/strace_GSOC_json_test.txt", O_CLOEXEC|O_CREAT|O_RDWR|O_TRUNC, S_IWUSR|S_IRUSR|S_IROTH|S_IRGRP);
+
+ write(923, buf, 25);
+ write(fd1, buf, 0);
+ write(fd1, str, strsz);
+ write(fd1, str, 10);
+
+ read(923, buf, BUFSIZE);
+ lseek(fd1, 0, SEEK_SET);
+ read(fd1, buf, 0);
+ read(fd1, buf, BUFSIZE);
+ lseek(fd1, -10, SEEK_END);
+ read(fd1, buf, 20);
+
+ static char vecstr[5][50] = {
+ "abcdefgabcdefgabcdefg",
+ "6fgjgbcduifgabcdefgbcdefg",
+ "i890abfghgabcduioefg",
+ "vgyjghuvbbcddfsucdefgdefg",
+ "sfd0-9gcdefgabcdefgbcdefg"};
+
+ struct iovec vecbuf[5];
+ int i;
+ for (i=0; i<5; i++) {
+ vecbuf[i].iov_base = vecstr[i];
+ vecbuf[i].iov_len = strlen(vecstr[i]) + 1;
+ }
+ readv(1989, vecbuf, 5);
+ writev(923, vecbuf, 5);
+ readv(fd1, vecbuf, 5);
+ writev(fd1, vecbuf, 5);
+
+ pread(fd1, buf, BUFSIZE, 0);
+ pwrite(fd1, buf, BUFSIZE, 0);
+ preadv(fd1, vecbuf, 5, 0);
+ pwritev(fd1, vecbuf, 5, 0);
+ preadv(923, vecbuf, 5, 0);
+ pwritev(923, vecbuf, 5, 0);
+
+ int fd2 = 923;
+ off_t off = 99999346451407343;
+ sendfile(fd1, fd2, NULL, BUFSIZE);
+ sendfile(fd1, -1, &off, BUFSIZE);
+ fd2 = open("/tmp/strace_tmp_file2", O_RDWR | O_CREAT | O_TRUNC, S_IWUSR|S_IRUSR|S_IROTH|S_IRGRP);
+ write(fd2, buf, BUFSIZE);
+ lseek(fd2, 0, SEEK_SET);
+ sendfile(fd1, fd2, &off, BUFSIZE);
+ off = 0;
+ sendfile(fd1, fd2, &off, 100);
+
+ tee(fd1, fd2, 2345, SPLICE_F_MORE | SPLICE_F_MOVE | SPLICE_F_GIFT);
+ tee(fd1, fd2, 2345, SPLICE_F_NONBLOCK | SPLICE_F_MOVE);
+ tee(STDIN_FILENO, STDOUT_FILENO, 99999, SPLICE_F_NONBLOCK);
+
+ off_t o1 = 12;
+ int pfd[2];
+ pipe2(pfd, O_NONBLOCK | O_CLOEXEC);
+ splice(fd1, NULL, fd2, NULL, 100, SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
+ splice(fd1, &o1, pfd[1], NULL, 100, SPLICE_F_MOVE);
+ splice(fd1, &o1, pfd[1], NULL, 100, 8349583);
+ splice(fd1, &o1, pfd[1], NULL, 100, 0);
+
+ vmsplice(923, vecbuf, 5, 23487);
+ vmsplice(pfd[0], vecbuf, 5, SPLICE_F_NONBLOCK|SPLICE_F_MOVE);
+ vmsplice(pfd[1], vecbuf, 5, SPLICE_F_NONBLOCK|SPLICE_F_MOVE);
+}
+
+
+int main(int argc, char *argv[])
+{
+ int cnt = 1;
+ if (argc >= 2)
+ cnt = atoi(argv[1]);
+ while (cnt-- > 0) {
+ test();
+ }
+ return 0;
+}
diff --git a/test/json_parse.py b/test/json_parse.py
new file mode 100755
index 0000000..7c7be10
--- /dev/null
+++ b/test/json_parse.py
@@ -0,0 +1,150 @@
+#!/usr/bin/python
+import json
+from sys import argv
+from sys import stdout
+from sys import stderr
+
+
+def arg_printfd(fd):
+ if type(fd) == list:
+ # when -y option is enabled
+ stdout.write(fd[0] + "<" + fd[1] + ">")
+ else:
+ stdout.write(fd)
+
+def arg_iov(iovs):
+ stdout.write("[")
+ first = True
+ for i in iovs:
+ if not first:
+ stdout.write(", ")
+ stdout.write("{")
+ stdout.write(i[0] + ", " + i[1])
+ stdout.write("}")
+ first = False
+ stdout.write("]")
+
+def arg_iop(iop):
+ first = True
+ for i in iop:
+ if not first:
+ stdout.write(" or ")
+ first = False
+ stdout.write(i)
+
+def arg_simple(arg):
+ stdout.write(arg if arg is not None else "NULL")
+
+def arg_print_off_t(arg):
+ if not arg:
+ stdout.write("NULL")
+ elif arg.startswith("0x"):
+ stdout.write(arg)
+ else:
+ stdout.write("[" + arg + "]")
+
+def arg_printflags(arg):
+ pass
+
+
+def choose(*args):
+ first_type = args[0]
+ fun_list = args[1]
+ fun_def = args[2]
+
+ def real_fun(arg):
+ if type(arg) == first_type:
+ fun_list(arg)
+ else:
+ fun_def(arg)
+
+ return real_fun
+
+
+arg_fun_table = {
+ "read" : [arg_printfd, arg_simple, arg_simple],
+ "write" : [arg_printfd, arg_simple, arg_simple],
+ "readv" : [arg_printfd, choose(list, arg_iov, arg_simple), arg_simple],
+ "writev" : [arg_printfd, choose(list, arg_iov, arg_simple), arg_simple],
+ "pread" : [arg_printfd, arg_simple, arg_simple, arg_simple],
+ "pwrite" : [arg_printfd, arg_simple, arg_simple, arg_simple],
+ "preadv" : [arg_printfd, choose(list, arg_iov, arg_simple), arg_simple, arg_simple],
+ "pwritev" : [arg_printfd, choose(list, arg_iov, arg_simple), arg_simple, arg_simple],
+ "sendfile" : [arg_printfd, arg_printfd, arg_print_off_t, arg_simple],
+ "sendfile64" : [arg_printfd, arg_printfd, arg_print_off_t, arg_simple],
+ "tee" : [arg_printfd, arg_printfd, arg_simple, arg_simple],
+ "splice" : [arg_printfd, arg_simple, arg_printfd, arg_simple, arg_simple, arg_simple],
+ "vmsplice" : [arg_printfd, arg_iov, arg_simple, arg_simple],
+ "ioctl" : [arg_printfd, choose(list, arg_iop, arg_simple), arg_simple, arg_simple],
+}
+
+
+def arg_default(obj):
+ outstr = ", ".join(obj)
+ stdout.write(outstr)
+
+
+def syscall(entry):
+ stdout.write(entry["name"])
+ stdout.write("(")
+ if entry["name"] in arg_fun_table:
+ i = 0
+ for arg in entry["args"]:
+ if i > 0:
+ # special case for ioctl()
+ if i == 2 and entry["name"] == "ioctl":
+ # the 3rd argument of ioctl() itself contain a ', '
+ pass
+ else:
+ stdout.write(", ")
+ arg_fun_table[entry["name"]][i](arg)
+ i += 1
+ else:
+ arg_default(entry["args"])
+ stdout.write(")")
+
+ stdout.write(" = " + entry["ret"])
+ if ("desc" in entry):
+ stdout.write(" " + entry["desc"])
+ if ("desc_long" in entry):
+ stdout.write(" (" + entry["desc_long"] + ")")
+ if ("auxstr" in entry):
+ stdout.write(" (" + entry["auxstr"] + ")")
+ stdout.write("\n")
+
+
+# this is for the +++ signal, should rename..
+def plusplusplus(entry):
+ print "+++ " + entry["desc"] + " with " + entry["sigcode"] + " +++"
+
+
+def main(infile, options):
+ with open(infile) as f:
+ for i, line in enumerate(f):
+ try:
+ entry = json.loads(line)
+ except ValueError as e:
+ stderr.write("<Error> JSON format invalid!\n")
+ stderr.write(" File:" + infile + ", line:" + str(i+1) + "\n")
+ stderr.write(" " + line + "\n")
+ raise ValueError
+ try:
+ if (entry["type"] == "syscall"):
+ syscall(entry)
+ elif (entry["type"] == "+++"):
+ plusplusplus(entry)
+ else:
+ raise ValueError
+ except Exception:
+ stderr.write("<Error> Failed to parse output!\n")
+ stderr.write(" File:" + infile + ", line:" + str(i+1) + "\n")
+ stderr.write(" " + line + "\n")
+
+
+if __name__ == "__main__":
+ options = {}
+ for o in argv[1:-1]:
+ if o == "-y":
+ options["y"] = True
+ # in fact, the options here is not used explicitly
+ main(argv[-1], options)
diff --git a/test/json_test.c b/test/json_test.c
new file mode 100644
index 0000000..e739283
--- /dev/null
+++ b/test/json_test.c
@@ -0,0 +1,134 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <sys/sendfile.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <linux/fs.h>
+#include <sched.h>
+#include <grp.h>
+#include <sys/prctl.h>
+
+static void test_io(void)
+{
+ #define BUFSIZE (1000)
+ static char buf[BUFSIZE] = "tempbuffer\216\315r\177\0\0 \304\311\315r\177\242";
+ static char str[] = "helloworld, this_is_a_test_string,\n\n\n. !@$%^$!@, \\{{{\"\"\"]]}}%%";
+ int strsz = strlen(str) + 1;
+
+ int fd1 = open("/tmp/strace_GSOC_json_test.txt", O_CLOEXEC|O_CREAT|O_RDWR|O_TRUNC, S_IWUSR|S_IRUSR|S_IROTH|S_IRGRP);
+
+ write(923, buf, 25);
+ write(fd1, buf, 0);
+ write(fd1, str, strsz);
+ write(fd1, str, 10);
+
+ read(923, buf, BUFSIZE);
+ lseek(fd1, 0, SEEK_SET);
+ read(fd1, buf, 0);
+ read(fd1, buf, BUFSIZE);
+ lseek(fd1, -10, SEEK_END);
+ read(fd1, buf, 20);
+
+ static char vecstr[5][50] = {
+ "abcdefgabcdefgabcdefg",
+ "6fgjgbcduifgabcdefgbcdefg",
+ "i890abfghgabcduioefg",
+ "vgyjghuvbbcddfsucdefgdefg",
+ "sfd0-9gcdefgabcdefgbcdefg"};
+
+ struct iovec vecbuf[5];
+ int i;
+ for (i=0; i<5; i++) {
+ vecbuf[i].iov_base = vecstr[i];
+ vecbuf[i].iov_len = strlen(vecstr[i]) + 1;
+ }
+ readv(1989, vecbuf, 5);
+ writev(923, vecbuf, 5);
+ readv(fd1, vecbuf, 5);
+ writev(fd1, vecbuf, 5);
+
+ pread(fd1, buf, BUFSIZE, 0);
+ pwrite(fd1, buf, BUFSIZE, 0);
+ preadv(fd1, vecbuf, 5, 0);
+ pwritev(fd1, vecbuf, 5, 0);
+ preadv(923, vecbuf, 5, 0);
+ pwritev(923, vecbuf, 5, 0);
+
+ int fd2 = 923;
+ off_t off = 99999346451407343;
+ sendfile(fd1, fd2, NULL, BUFSIZE);
+ sendfile(fd1, -1, &off, BUFSIZE);
+ fd2 = open("/tmp/strace_tmp_file2", O_RDWR | O_CREAT | O_TRUNC, S_IWUSR|S_IRUSR|S_IROTH|S_IRGRP);
+ write(fd2, buf, BUFSIZE);
+ lseek(fd2, 0, SEEK_SET);
+ sendfile(fd1, fd2, &off, BUFSIZE);
+ off = 0;
+ sendfile(fd1, fd2, &off, 100);
+
+ tee(fd1, fd2, 2345, SPLICE_F_MORE | SPLICE_F_MOVE | SPLICE_F_GIFT);
+ tee(fd1, fd2, 2345, SPLICE_F_NONBLOCK | SPLICE_F_MOVE);
+ tee(STDIN_FILENO, STDOUT_FILENO, 99999, SPLICE_F_NONBLOCK);
+
+ off_t o1 = 12;
+ int pfd[2];
+ pipe2(pfd, O_NONBLOCK | O_CLOEXEC);
+ splice(fd1, NULL, fd2, NULL, 100, SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
+ splice(fd1, &o1, pfd[1], NULL, 100, SPLICE_F_MOVE);
+ splice(fd1, &o1, pfd[1], NULL, 100, 8349583);
+ splice(fd1, &o1, pfd[1], NULL, 100, 0);
+
+ vmsplice(923, vecbuf, 5, 23487);
+ vmsplice(pfd[0], vecbuf, 5, SPLICE_F_NONBLOCK|SPLICE_F_MOVE);
+ vmsplice(pfd[1], vecbuf, 5, SPLICE_F_NONBLOCK|SPLICE_F_MOVE);
+}
+
+static void test_process(void)
+{
+ sethostname("abcde12345zzzzz", 15);
+ sethostname("dsfgdsfgfsdg", -1);
+ setdomainname("12345bbbbbccccczzzzz", 20);
+ setdomainname("jkjytujbtyukyukbuyhdfgbdfbgdjfgdfghdfghdfkjg", -1);
+
+ uid_t uid[3] = {1989, -1, 222229292};
+ setresuid(uid[0], uid[1], uid[2]);
+ getresuid(uid, uid+1, uid+2);
+
+ gid_t gid[4] = {1989, 233, -11, 0};
+ getgroups(4, gid);
+ setgroups(4, gid);
+
+ setns(1989, CLONE_NEWIPC);
+ setns(222, 0);
+ setns(111, 0xffffffff);
+ setns(-1, 33);
+
+ int i;
+ unsigned long args[4] = {1, 2, 33, 44444};
+ for (i = 0; i < 20; i++) {
+ prctl(i, args[0], args[1], args[2], args[3]);
+ }
+}
+
+static void test_desc(void)
+{
+
+}
+
+int main(int argc, char *argv[])
+{
+ int cnt = 1;
+ if (argc >= 2)
+ cnt = atoi(argv[1]);
+ while (cnt-- > 0) {
+ test_io();
+ test_process();
+ test_desc();
+ }
+ return 0;
+}
diff --git a/test/json_test.sh b/test/json_test.sh
new file mode 100755
index 0000000..0738220
--- /dev/null
+++ b/test/json_test.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+set -u
+
+Unmodified_Strace="strace -y"
+Normal_Strace="../strace -y"
+JSON_Strace="../strace -j -y"
+
+TEMPDIR=${TEMPDIR:-"./temp_results"}
+SYSCALLS=${SYSCALLS:-""}
+FLAGS=${FLAGS:-""}
+TARGETS=${TARGETS:-""}
+
+JSON_PARSER="./json_parse.py"
+
+function simple_diff()
+{
+ diff $1 $2
+}
+function adv_diff()
+{
+ wdiff -3 $1 $2 | colordiff
+}
+
+DODIFF="simple_diff"
+if type colordiff &> /dev/null; then
+ if type wdiff &> /dev/null; then
+ DODIFF="adv_diff"
+ fi
+fi
+
+$DODIFF "lala"
+
+mkdir -p $TEMPDIR
+
+function start_test() {
+ for i in $TARGETS; do
+ echo "--- --- --- ---"
+ echo "generating trace results for $i"
+ $Unmodified_Strace -o "$TEMPDIR/$i-raw-unmodified" $SYSCALLS $FLAGS ./$i
+ $Normal_Strace -o "$TEMPDIR/$i-raw-normal" $SYSCALLS $FLAGS ./$i
+ $JSON_Strace -o "$TEMPDIR/$i-json-GSOC" $SYSCALLS $FLAGS ./$i
+ $JSON_PARSER "$TEMPDIR/$i-json-GSOC" > "$TEMPDIR/$i-raw-GSOC"
+
+ echo "> comparing $i-raw-unmodified $i-raw-normal results:"
+ $DODIFF "$TEMPDIR/$i-raw-unmodified" "$TEMPDIR/$i-raw-normal"
+
+ echo -e "\n> comparing $i-raw-unmodified $i-raw-GSOC results(ignore all white space):"
+ $DODIFF "$TEMPDIR/$i-raw-unmodified" "$TEMPDIR/$i-raw-GSOC"
+
+ echo -e "\n> comparing $i-raw-normal $i-raw-GSOC results(ignore all white space):"
+ $DODIFF "$TEMPDIR/$i-raw-normal" "$TEMPDIR/$i-raw-GSOC"
+ echo -e "--- --- --- ---\n"
+ done
+}
+
+# test for io-related syscall
+IO_SYSCALL="-e read,write,readv,writev,pread,pwrite,preadv,pwritev,sendfile,sendfile64,tee,splice,vmsplice,ioctl"
+SYSCALLS=$IO_SYSCALL
+TARGETS="json_io mtd ubi select"
+start_test
+
+# test for fork-related syscall
+FLAGS="-ff"
+TARGETS="vfork fork clone childthread threaded_execve"
+
+# test for other syscall
+FLAGS=""
+TARGETS="sig skodic clone leaderkill childthread sigkill_rain wait_must_be_interruptible sigreturn"
diff --git a/time.c b/time.c
index 1ad90d9..07d4782 100644
--- a/time.c
+++ b/time.c
@@ -72,10 +72,10 @@ sprinttv(char *buf, struct tcb *tcp, long addr, enum bitness_t bitness, int spec
int rc;
if (addr == 0)
- return stpcpy(buf, "NULL");
+ return stpcpy(buf, jsonstr("null", "NULL"));
if (!verbose(tcp))
- return buf + sprintf(buf, "%#lx", addr);
+ return buf + sprintf(buf, jsonstr("\"%#lx\"","%#lx"), addr);
if (bitness == BITNESS_32
#if SUPPORTED_PERSONALITIES > 1
@@ -89,11 +89,11 @@ sprinttv(char *buf, struct tcb *tcp, long addr, enum bitness_t bitness, int spec
if (rc >= 0) {
if (special && tv.tv_sec == 0) {
if (tv.tv_usec == UTIME_NOW)
- return stpcpy(buf, "UTIME_NOW");
+ return stpcpy(buf, jsonstr("\"UTIME_NOW\"", "UTIME_NOW"));
if (tv.tv_usec == UTIME_OMIT)
- return stpcpy(buf, "UTIME_OMIT");
+ return stpcpy(buf, jsonstr("\"UTIME_OMIT\"", "UTIME_OMIT"));
}
- return buf + sprintf(buf, "{%u, %u}",
+ return buf + sprintf(buf, jsonstr("[%u, %u]", "{%u, %u}"),
tv.tv_sec, tv.tv_usec);
}
} else {
@@ -103,17 +103,17 @@ sprinttv(char *buf, struct tcb *tcp, long addr, enum bitness_t bitness, int spec
if (rc >= 0) {
if (special && tv.tv_sec == 0) {
if (tv.tv_usec == UTIME_NOW)
- return stpcpy(buf, "UTIME_NOW");
+ return stpcpy(buf, jsonstr("\"UTIME_NOW\"", "UTIME_NOW"));
if (tv.tv_usec == UTIME_OMIT)
- return stpcpy(buf, "UTIME_OMIT");
+ return stpcpy(buf, jsonstr("\"UTIME_OMIT\"", "UTIME_OMIT"));
}
- return buf + sprintf(buf, "{%lu, %lu}",
+ return buf + sprintf(buf, jsonstr("[%lu, %lu]", "{%lu, %lu}"),
(unsigned long) tv.tv_sec,
(unsigned long) tv.tv_usec);
}
}
- return stpcpy(buf, "{...}");
+ return stpcpy(buf, jsonstr("{}", "{...}"));
}
void
@@ -128,9 +128,9 @@ void
sprint_timespec(char *buf, struct tcb *tcp, long addr)
{
if (addr == 0)
- strcpy(buf, "NULL");
+ strcpy(buf, jsonstr("null","NULL"));
else if (!verbose(tcp))
- sprintf(buf, "%#lx", addr);
+ sprintf(buf, jsonstr("\"%#lx\"", "%#lx"), addr);
else {
int rc;
@@ -140,7 +140,7 @@ sprint_timespec(char *buf, struct tcb *tcp, long addr)
rc = umove(tcp, addr, &tv);
if (rc >= 0)
- sprintf(buf, "{%u, %u}",
+ sprintf(buf, jsonstr("[%u, %u]", "{%u, %u}"),
tv.tv_sec, tv.tv_usec);
} else
#endif
@@ -149,12 +149,12 @@ sprint_timespec(char *buf, struct tcb *tcp, long addr)
rc = umove(tcp, addr, &ts);
if (rc >= 0)
- sprintf(buf, "{%lu, %lu}",
+ sprintf(buf, jsonstr("[%lu, %lu]", "{%lu, %lu}"),
(unsigned long) ts.tv_sec,
(unsigned long) ts.tv_nsec);
}
if (rc < 0)
- strcpy(buf, "{...}");
+ strcpy(buf, jsonstr("[\"...\"]","{...}"));
}
}
diff --git a/util.c b/util.c
index 33482d5..06e0302 100644
--- a/util.c
+++ b/util.c
@@ -215,9 +215,9 @@ printxval(const struct xlat *xlat, int val, const char *dflt)
const char *str = xlookup(xlat, val);
if (str)
- tprints(str);
+ tprintf("%s", str);
else
- tprintf("%#x /* %s */", val, dflt);
+ jprintf("[$, $]", "%#x /* %s */", val, dflt);
}
/*
@@ -285,12 +285,12 @@ addflags(const struct xlat *xlat, int flags)
{
for (; xlat->str; xlat++) {
if (xlat->val && (flags & xlat->val) == xlat->val) {
- tprintf("|%s", xlat->str);
+ jprintf(", $", "|%s", xlat->str);
flags &= ~xlat->val;
}
}
if (flags) {
- tprintf("|%#x", flags);
+ jprintf(", $", "|%#x", flags);
}
}
@@ -335,36 +335,36 @@ printflags(const struct xlat *xlat, int flags, const char *dflt)
const char *sep;
if (flags == 0 && xlat->val == 0) {
- tprints(xlat->str);
+ tprintf("%s", xlat->str);
return 1;
}
- sep = "";
+ sep = json_printflags_array_enable ? jsonstr("[", "") : "";
for (n = 0; xlat->str; xlat++) {
if (xlat->val && (flags & xlat->val) == xlat->val) {
- tprintf("%s%s", sep, xlat->str);
+ jprintf("%s'%s'", "%s%s", sep, xlat->str);
flags &= ~xlat->val;
- sep = "|";
+ sep = jsonstr(",", "|");
n++;
}
}
if (n) {
if (flags) {
- tprintf("%s%#x", sep, flags);
+ jprintf("%s $", "%s%#x", sep, flags);
n++;
}
+ sep = json_printflags_array_enable ? jsonstr("]", "") : "";
+ tprints(sep);
} else {
if (flags) {
- tprintf("%#x", flags);
if (dflt)
- tprintf(" /* %s */", dflt);
+ jprintf("$", " /* %s */", dflt);
} else {
if (dflt)
tprints("0");
}
}
-
return n;
}
@@ -374,7 +374,7 @@ printnum(struct tcb *tcp, long addr, const char *fmt)
long num;
if (!addr) {
- tprints("NULL");
+ jprints("NULL");
return;
}
if (umove(tcp, addr, &num) < 0) {
@@ -392,7 +392,7 @@ printnum_int(struct tcb *tcp, long addr, const char *fmt)
int num;
if (!addr) {
- tprints("NULL");
+ jprints("NULL");
return;
}
if (umove(tcp, addr, &num) < 0) {
@@ -410,7 +410,7 @@ printfd(struct tcb *tcp, int fd)
char path[PATH_MAX + 1];
if (show_fd_path && getfdpath(tcp, fd, path, sizeof(path)) >= 0)
- tprintf("%d<%s>", fd, path);
+ jprintf("[$, $]", "%d<%s>", fd, path);
else
tprintf("%d", fd);
}
@@ -418,7 +418,7 @@ printfd(struct tcb *tcp, int fd)
void
printuid(const char *text, unsigned long uid)
{
- tprintf((uid == -1) ? "%s%ld" : "%s%lu", text, uid);
+ _tprintf((uid == -1) ? "%s%ld" : "%s%lu", text, uid);
}
/*
@@ -470,7 +470,8 @@ string_quote(const char *instr, char *outstr, long len, int size)
}
}
- *s++ = '\"';
+ if(!jflag)
+ *s++ = '\"';
if (usehex) {
/* Hex-quote the whole string. */
@@ -543,7 +544,8 @@ string_quote(const char *instr, char *outstr, long len, int size)
}
}
- *s++ = '\"';
+ if(!jflag)
+ *s++ = '\"';
*s = '\0';
/* Return zero if we printed entire ASCIZ string (didn't truncate it) */
@@ -557,7 +559,8 @@ string_quote(const char *instr, char *outstr, long len, int size)
return 1;
asciz_ended:
- *s++ = '\"';
+ if(!jflag)
+ *s++ = '\"';
*s = '\0';
/* Return zero: we printed entire ASCIZ string (didn't truncate it) */
return 0;
@@ -574,7 +577,7 @@ printpathn(struct tcb *tcp, long addr, int n)
int nul_seen;
if (!addr) {
- tprints("NULL");
+ jprints("NULL");
return;
}
@@ -593,9 +596,9 @@ printpathn(struct tcb *tcp, long addr, int n)
n++;
outstr = alloca(4 * n); /* 4*(n-1) + 3 for quotes and NUL */
string_quote(path, outstr, -1, n);
- tprints(outstr);
+ tprintf("%s", json_escape_string(outstr));
if (!nul_seen)
- tprints("...");
+ tprints(jsonstr("", "..."));
}
}
@@ -620,7 +623,7 @@ printstr(struct tcb *tcp, long addr, long len)
int ellipsis;
if (!addr) {
- tprints("NULL");
+ jprintf("null", "NULL");
return;
}
/* Allocate static buffers if they are not allocated yet. */
@@ -664,9 +667,9 @@ printstr(struct tcb *tcp, long addr, long len)
ellipsis = (string_quote(str, outstr, len, size) &&
(len < 0 || len > max_strlen));
- tprints(outstr);
+ tprintf("%s", json_escape_string(outstr));
if (ellipsis)
- tprints("...");
+ tprints(jsonstr("", "..."));
}
#if HAVE_SYS_UIO_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.