#define _XOPEN_SOURCE 500
#define _GNU_SOURCE
#include <asm/types.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <sys/un.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <poll.h>
#include <semaphore.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <sf_tools.h>
#include "ids.h"
#include "params.h"
#include "shared.h"
#include "tools.h"
#include "decode_text.h"
struct theme
{
char *name;
unsigned int colors;
unsigned int color_default;
unsigned int color_func_i_c, color_func_i_r, color_func_i_m;
unsigned int color_func_n_c, color_func_n_r, color_func_n_m;
unsigned int color_ts_s, color_ts_e, color_ts_bad;
unsigned int color_ret_ok, color_ret_error, color_flags, color_file;
unsigned int pad;
};
static const struct theme themes[] =
{
{ .name = "def",
.colors = 256, .color_default = 3,
.color_func_i_c = 196, .color_func_i_r = 202, .color_func_i_m = 207,
.color_func_n_c = 46, .color_func_n_r = 70, .color_func_n_m = 90,
.color_ts_s = 246, .color_ts_e = 255, .color_ts_bad = 196,
.color_ret_ok = 48, .color_ret_error = 197, .color_flags = 46,
.color_file = 226
},
{ .name = NULL }
};
static const char *theme_name = "def";
static const char *theme_s1 = "", *theme_s2 = "", *theme_e = "";
static const struct theme *theme = NULL;
static const struct option options[] =
{
{"pid", required_argument, NULL, 'p'},
{"output", required_argument, NULL, 'o'},
{"only-high-level", no_argument, NULL, 'H'},
{"theme", required_argument, NULL, 't'},
{"time-format", required_argument, NULL, 'T'},
{"hide-pids", no_argument, NULL, 'P'},
{NULL, 0, NULL, 0}
};
static void usage(void)
{
fprintf(stderr,
"Usage: nd-trace [options]\n"
" --pid -p pid to trace (can be added multiple times)\n"
" --output -o where to store the output\n"
" --only-high-level -H log only high level, if possible\n"
" --theme -t do not show output with colors ['def']\n"
" --time-format -T none, ts [def], human\n"
" --hide-pids -P do not show pids\n"
" If output is not a tty, no theme is used\n"
" Use 'none' for no theme\n"
"\n");
exit(1);
}
static FILE *outf;
static unsigned int do_exit;
static pid_t pids[256];
static unsigned int no_pids;
static char only_high_level;
static char *time_format = "ts";
static char hide_pids = 0;
static uint64_t last_ts;
/*
* Set the theme
*/
static void nd_trace_color_set_theme(void)
{
unsigned theme_colors;
if (strcmp(theme_name, "none") == 0)
return;
if (!isatty(fileno(outf)))
return;
const char *term = getenv("TERM");
//fprintf(outf, "TERM=[%s]\n", term); fflush(outf);
if (term == NULL)
return;
if (strcmp(term, "xterm-256color") == 0) {
theme_colors = 256;
} else if (strcmp(term, "xterm") == 0) {
theme_colors = 16;
} else {
return;
}
//fprintf(outf, "Searching for theme [%s] and %u colors...\n",
// theme_name, theme_colors); fflush(outf);
for (int i = 0; themes[i].name != NULL; i++) {
if (strcmp(themes[i].name, theme_name) != 0)
continue;
if (themes[i].colors != theme_colors)
continue;
theme = &themes[i];
break;
}
if (!theme) {
fprintf(outf, " Theme [%s/%u] not found, using no theme.\n",
theme_name, theme_colors);
return;
}
if (theme->colors == 16) {
theme_s1 = "\x1b["; theme_s2 = "m";
theme_e = "\x1b[0m";
} else if (theme->colors == 256) {
theme_s1 = "\x1b[38;5;"; theme_s2 = "m";
theme_e = "\x1b[0m";
}
fprintf(outf, "Theme set to [%s] based on term [%s]; colors=%u\n",
theme->name, term, theme->colors);
}
/*
* Color output
*/
static void nd_trace_color(char *out, const size_t out_size,
const char *str, const char *category, const char type,
const char *flags, const uint64_t u64)
{
char scolor[4] = { 0 };
int r;
//fprintf(outf, "%s: str=[%s] category=[%s] u64=%lu\n",
// __func__, str, category, u64); fflush(outf);
if (!theme)
goto no_theme;
unsigned color = theme->color_default;
if (strcmp(category, "func") == 0) {
if (strstr("i", flags)) {
if ((type == 'c') || (type == 'R'))
color = theme->color_func_i_c;
else if (type == 'r')
color = theme->color_func_i_r;
else if (type == 'm')
color = theme->color_func_i_m;
} else {
if ((type == 'c') || (type == 'R'))
color = theme->color_func_n_c;
else if (type == 'r')
color = theme->color_func_n_r;
else if (type == 'm')
color = theme->color_func_n_m;
}
} else if (strcmp(category, "ts") == 0) { // 'u64' contains milliseconds
if (u64 >= 2000)
color = theme->color_ts_bad;
else if (u64 >= 1000)
color = theme->color_ts_e;
else
color = theme->color_ts_s + u64 / 100;
} else if (strcmp(category, "error") == 0) {
if (u64 == 0)
color = theme->color_ret_ok;
else
color = theme->color_ret_error;
} else if (strcmp(category, "flags") == 0) {
color = theme->color_flags;
} else if (strcmp(category, "file") == 0) {
color = theme->color_file;
}
snprintf(scolor, sizeof(scolor), "%u", color);
no_theme:
r = snprintf(out, out_size, "%s%s%s%s%s",
theme_s1, scolor, theme_s2, str, theme_e);
// we will not color things if we do not have enough space
if ((unsigned) r > out_size)
snprintf(out, out_size, "%s", str);
}
static uint8_t decode8(unsigned char *d, unsigned int *i)
{
uint8_t u;
u = d[*i];
*i = *i + 1;
return u;
}
static uint16_t decode16(unsigned char *d, unsigned int *i)
{
uint16_t u;
memcpy(&u, d + *i, 2);
*i = *i + 2;
return be16toh(u);
}
static uint32_t decode32(unsigned char *d, unsigned int *i)
{
uint32_t u;
memcpy(&u, d + *i, 4);
*i = *i + 4;
return be32toh(u);
}
static uint64_t decode64(unsigned char *d, unsigned int *i)
{
uint64_t u;
memcpy(&u, d + *i, 8);
*i = *i + 8;
return be64toh(u);
}
static uint8_t decode_bool(const char *prefix, char *out0, size_t out_size,
unsigned char *d, unsigned int *i)
{
char out[out_size];
uint8_t v = d[*i]; *i = *i + 1;
snprintf(out, out_size, "%s%s", prefix, v == 0 ? "nok" : "ok");
nd_trace_color(out0, out_size, out, "error", '-', "", 0);
return v;
}
// TODO: more to add from /usr/include/asm-generic/errno.h
// TODO: move this in common
static void decode_errno(char *out0, unsigned out_max, const int e)
{
char out[out_max];
switch (e) {
case EPERM: snprintf(out, out_max, "EPERM"); break;
case ENOENT: snprintf(out, out_max, "ENOENT"); break;
case ESRCH: snprintf(out, out_max, "ESRCH"); break;
case EINTR: snprintf(out, out_max, "EINTR"); break;
case EIO: snprintf(out, out_max, "EIO"); break;
case ENXIO: snprintf(out, out_max, "ENXIO"); break;
case E2BIG: snprintf(out, out_max, "E2BIG"); break;
case ENOEXEC: snprintf(out, out_max, "NOEXEC"); break;
case EBADF: snprintf(out, out_max, "BADF"); break;
case ECHILD: snprintf(out, out_max, "ECHILD"); break;
case EAGAIN: snprintf(out, out_max, "EAGAIN"); break;
case ENOMEM: snprintf(out, out_max, "ENOMEM"); break;
case EACCES: snprintf(out, out_max, "EACCES"); break;
case EFAULT: snprintf(out, out_max, "EFAULT"); break;
case ENOTBLK: snprintf(out, out_max, "ENOTBLK"); break;
case EBUSY: snprintf(out, out_max, "EBUSY"); break;
case EEXIST: snprintf(out, out_max, "EEXIST"); break;
case EXDEV: snprintf(out, out_max, "EXDEV"); break;
case ENODEV: snprintf(out, out_max, "ENODEV"); break;
case ENOTDIR: snprintf(out, out_max, "ENOTDIR"); break;
case EISDIR: snprintf(out, out_max, "EISDIR"); break;
case EINVAL: snprintf(out, out_max, "EINVAL"); break;
case ENFILE: snprintf(out, out_max, "ENFILE"); break;
case ENOTTY: snprintf(out, out_max, "ENOTTY"); break;
case ETXTBSY: snprintf(out, out_max, "ETXTBSY"); break;
case EFBIG: snprintf(out, out_max, "EFBIG"); break;
case ENOSPC: snprintf(out, out_max, "ENOSPC"); break;
case ESPIPE: snprintf(out, out_max, "ESPIPE"); break;
case EROFS: snprintf(out, out_max, "EROFS"); break;
case EMLINK: snprintf(out, out_max, "EMLINK"); break;
case EPIPE: snprintf(out, out_max, "EPIPE"); break;
case EDOM: snprintf(out, out_max, "EDOM"); break;
case ERANGE: snprintf(out, out_max, "ERANGE"); break;
case EDEADLK: snprintf(out, out_max, "EDEADLK"); break;
case ENAMETOOLONG: snprintf(out, out_max, "ENAMETOOLONG"); break;
case ENOLCK: snprintf(out, out_max, "ENOLCK"); break;
case EINPROGRESS: snprintf(out, out_max, "EINPROGRESS"); break;
default: snprintf(out, out_max, "%d", e); break;
}
nd_trace_color(out0, out_max, out, "error", '-', "", 0);
}
static int decode_ret_int(char *out, unsigned out_max,
unsigned char *d, unsigned int *i)
{
int ret = decode32(d, i);
if (ret != -1) {
snprintf(out, out_max, " = %d", ret);
return ret;
}
int xerrno = decode32(d, i);
char err[64];
decode_errno(err, sizeof(err), xerrno);
snprintf(out, out_max, " = %d (%s)", ret, err);
return ret;
}
static ssize_t decode_ret_int64(char *out, unsigned out_max,
unsigned char *d, unsigned int *i)
{
ssize_t ret = decode64(d, i);
if (ret != -1) {
snprintf(out, out_max, " = %zd", ret);
return ret;
}
int xerrno = decode32(d, i);
char err[64];
decode_errno(err, sizeof(err), xerrno);
snprintf(out, out_max, " = %zd (%s)", ret, err);
return ret;
}
static void *decode_ret_pointer(char *out, unsigned out_max,
unsigned char *d, unsigned int *i)
{
void *ret = (void *) decode64(d, i);
if (ret) {
snprintf(out, out_max, " = %p", ret);
return ret;
}
char out2[32];
nd_trace_color(out2, sizeof(out2), "NULL", "error", '-', "", 0);
snprintf(out, out_max, " = %s", out2);
return ret;
}
static void *decode_ret_pointer_errno(char *out, unsigned out_max,
unsigned char *d, unsigned int *i)
{
void *ret = (void *) decode64(d, i);
if (ret) {
snprintf(out, out_max, " = %p", ret);
return ret;
}
int xerrno = decode32(d, i);
char err[64];
decode_errno(err, sizeof(err), xerrno);
char out2[64];
nd_trace_color(out2, sizeof(out2), err, "error", '-', "", 0);
snprintf(out, out_max, " = %p (%s)", ret, out2);
return ret;
}
static void decode_dirfd(char *out0, unsigned out_size,
unsigned char *d, unsigned int *i, const char *postfix)
{
int v = decode32(d, i);
char out[out_size];
switch (v) {
case AT_FDCWD: snprintf(out, out_size, "AT_FDCWD%s", postfix); break;
default: sprintf(out, "%d%s", v, postfix); return;
}
nd_trace_color(out0, out_size, out, "flags", '-', "", 0);
}
static socklen_t decode_sockaddr(char *out, unsigned char *d, unsigned int *i)
{
struct sockaddr_storage ss;
socklen_t sl;
sl = decode16(d, i);
if (sl > sizeof(ss)) {
char dump[65];
sf_tools_bin2hex(dump, d + *i, 32);
sprintf(out, "[sl is too big: %u: %s]", sl, dump);
return sl;
}
memcpy(&ss, d + *i, sl); *i = *i + sl;
nd_decode_sockaddr(out, &ss, sl);
return sl;
}
// TODO: move to 'common'
static int decode_sock_level(char *out0, unsigned out_size,
unsigned char *d, unsigned int *i)
{
char out[out_size];
int level = decode32(d, i);
switch (level) {
case SOL_SOCKET: snprintf(out, out_size, "SOL_SOCKET"); break;
case SOL_IP: snprintf(out, out_size, "SOL_IP"); break;
case SOL_RAW: snprintf(out, out_size, "SOL_RAW"); break;
case SOL_PACKET: snprintf(out, out_size, "SOL_PACKET"); break;
case SOL_NETLINK: snprintf(out, out_size, "SOL_NETLINK"); break;
case SOL_IPV6: snprintf(out, out_size, "SOL_IPV6"); break;
case SOL_ICMPV6: snprintf(out, out_size, "SOL_ICMPV6"); break;
case IPPROTO_UDP: snprintf(out, out_size, "IPPROTO_UDP"); break;
case IPPROTO_TCP: snprintf(out, out_size, "IPPROTO_TCP"); break;
default: snprintf(out, out_size, "todo(%d)", level); break;
}
nd_trace_color(out0, out_size, out, "flags", '-', "", 0);
return level;
}
static void decode_sock_optname_socket(char *out0, unsigned out_size,
const int optname)
{
char out[out_size];
switch (optname) {
case SO_DEBUG: snprintf(out, out_size, "SO_DEBUG"); break;
case SO_REUSEADDR: snprintf(out, out_size, "SO_REUSEADDR"); break;
case SO_TYPE: snprintf(out, out_size, "SO_TYPE"); break;
case SO_ERROR: snprintf(out, out_size, "SO_ERROR"); break;
case SO_DONTROUTE: snprintf(out, out_size, "SO_DONTROUTE"); break;
case SO_BROADCAST: snprintf(out, out_size, "SO_BROADCAST"); break;
case SO_SNDBUF: snprintf(out, out_size, "SO_SNDBUF"); break;
case SO_RCVBUF: snprintf(out, out_size, "SO_RCVBUF"); break;
case SO_SNDBUFFORCE: snprintf(out, out_size, "SO_SNDBUFFORCE"); break;
case SO_RCVBUFFORCE: snprintf(out, out_size, "SO_RCVBUFFORCE"); break;
case SO_KEEPALIVE: snprintf(out, out_size, "SO_KEEPALIVE"); break;
case SO_OOBINLINE: snprintf(out, out_size, "SO_OOBINLINE"); break;
case SO_NO_CHECK: snprintf(out, out_size, "SO_NO_CHECK"); break;
case SO_PRIORITY: snprintf(out, out_size, "SO_PRIORITY"); break;
case SO_LINGER: snprintf(out, out_size, "SO_LINGER"); break;
case SO_BSDCOMPAT: snprintf(out, out_size, "SO_BSDCOMPAT"); break;
case SO_REUSEPORT: snprintf(out, out_size, "SO_REUSEPORT"); break; // 15
case SO_PASSCRED: snprintf(out, out_size, "SO_PASSCRED"); break; // 16
case SO_PEERCRED: snprintf(out, out_size, "SO_PEECRED"); break; // 17
case SO_RCVLOWAT: snprintf(out, out_size, "SO_RCVLOWAT"); break;
case SO_SNDLOWAT: snprintf(out, out_size, "SO_SNDLOWAT"); break;
case SO_RCVTIMEO_OLD: snprintf(out, out_size, "SO_RCVTIMEO_OLD"); break;
case SO_SNDTIMEO_OLD: snprintf(out, out_size, "SO_SNDTIMEO_OLD"); break;
case SO_BINDTODEVICE: snprintf(out, out_size, "SO_BINDTODEVICE"); break;
case SO_ATTACH_FILTER: snprintf(out, out_size, "SO_ATTACH_FILTER"); break;
case SO_DETACH_FILTER: snprintf(out, out_size, "SO_DETACH_FILTER"); break;
case SO_ACCEPTCONN: snprintf(out, out_size, "SO_ACCEPTCONN"); break;
case SO_PEERSEC: snprintf(out, out_size, "SO_PEERSEC"); break;
case SO_PASSSEC: snprintf(out, out_size, "SO_PASSSEC"); break;
case SO_MARK: snprintf(out, out_size, "SO_MARK"); break;
case SO_PROTOCOL: snprintf(out, out_size, "SO_PROTOCOL"); break;
case SO_DOMAIN: snprintf(out, out_size, "SO_DOMAIN"); break;
case SO_RXQ_OVFL: snprintf(out, out_size, "SO_RXQ_OVFL"); break;
case SO_WIFI_STATUS: snprintf(out, out_size, "SO_WIFI_STATUS"); break;
case SO_PEEK_OFF: snprintf(out, out_size, "SO_PEEK_OFF"); break;
case SO_NOFCS: snprintf(out, out_size, "SO_NOFCS"); break;
case SO_LOCK_FILTER: snprintf(out, out_size, "SO_LOCK_FILTER"); break;
case SO_SELECT_ERR_QUEUE: snprintf(out, out_size, "SO_SELECT_ERR_QUEUE"); break;
case SO_BUSY_POLL: snprintf(out, out_size, "SO_BUSY_POLL"); break;
case SO_MAX_PACING_RATE: snprintf(out, out_size, "SO_PACING_RATE"); break;
case SO_BPF_EXTENSIONS: snprintf(out, out_size, "SO_BPF_EXTENSIONS"); break;
case SO_INCOMING_CPU: snprintf(out, out_size, "SO_INCOMING_CPU"); break;
case SO_ATTACH_BPF: snprintf(out, out_size, "SO_ATTACH_BPF"); break;
case SO_ATTACH_REUSEPORT_CBPF: snprintf(out, out_size, "SO_ATTACH_REUSEPORT_CBPF"); break;
case SO_ATTACH_REUSEPORT_EBPF: snprintf(out, out_size, "SO_ATTACH_REUSEPORT_EBPF"); break;
case SO_CNX_ADVICE: snprintf(out, out_size, "SO_CNX_ADVICE"); break;
case SCM_TIMESTAMPING_OPT_STATS: snprintf(out, out_size, "SCM_TIMESTAMPING_OPT_STATS"); break;
case SO_MEMINFO: snprintf(out, out_size, "SO_MEMINFO"); break;
case SO_INCOMING_NAPI_ID: snprintf(out, out_size, "SO_INCOMING_NAPI_ID"); break;
case SO_COOKIE: snprintf(out, out_size, "SO_COOKIE"); break;
case SCM_TIMESTAMPING_PKTINFO: snprintf(out, out_size, "SCM_TIMESTAMPING_PKTINFO"); break;
case SO_PEERGROUPS: snprintf(out, out_size, "SO_PEERGROUPS"); break;
case SO_ZEROCOPY: snprintf(out, out_size, "SO_ZEROCOPY"); break;
case SO_TXTIME: snprintf(out, out_size, "SO_TXTIME"); break;
case SO_BINDTOIFINDEX: snprintf(out, out_size, "SO_BINDTOIFINDEX"); break;
case SO_TIMESTAMP_OLD: snprintf(out, out_size, "SO_TIMESTAMP_OLD"); break;
case SO_TIMESTAMPNS_OLD: snprintf(out, out_size, "SO_TIMESTAMPNS_OLD"); break;
case SO_TIMESTAMPING_OLD: snprintf(out, out_size, "SO_TIMESTAMPING_OLD"); break;
case SO_TIMESTAMP_NEW: snprintf(out, out_size, "SO_TIMESTAMP_NEW"); break;
case SO_TIMESTAMPNS_NEW: snprintf(out, out_size, "SO_TIMESTAMPNS_NEW"); break;
case SO_TIMESTAMPING_NEW: snprintf(out, out_size, "SO_TIMESTAMPING_NEW"); break;
case SO_RCVTIMEO_NEW: snprintf(out, out_size, "SO_RCVTIMEO_NEW"); break;
case SO_SNDTIMEO_NEW: snprintf(out, out_size, "SO_SNDTIMEO_NEW"); break;
case SO_DETACH_REUSEPORT_BPF: snprintf(out, out_size, "SO_DETACH_REUSEPORT_BPF"); break;
case SO_PREFER_BUSY_POLL: snprintf(out, out_size, "SO_PREFER_BUSY_POLL"); break;
case SO_BUSY_POLL_BUDGET: snprintf(out, out_size, "SO_BUSY_POLL_BUDGET"); break;
case SO_NETNS_COOKIE: snprintf(out, out_size, "SO_NETNS_COOKIE"); break;
case SO_BUF_LOCK: snprintf(out, out_size, "SO_BUF_LOCK"); break;
case SO_RESERVE_MEM: snprintf(out, out_size, "SO_RESERVE_MEM"); break;
case SO_TXREHASH: snprintf(out, out_size, "SO_TXREHASH"); break;
case SO_RCVMARK: snprintf(out, out_size, "SO_RCVMARK"); break; // 75
default: snprintf(out, out_size, "todo(%d)", optname); break;
}
nd_trace_color(out0, out_size, out, "flags", '-', "", 0);
}
#ifndef IP_RECVERR_RFC4884
#define IP_RECVERR_RFC4884 26
#endif
static void decode_sock_optname_ip(char *out0, unsigned out_size,
const int optname)
{
char out[out_size];
switch (optname) {
case IP_OPTIONS: snprintf(out, out_size, "IP_OPTIONS"); break;
case IP_HDRINCL: snprintf(out, out_size, "IP_HDRINCL"); break;
case IP_TOS: snprintf(out, out_size, "IP_TOS"); break;
case IP_TTL: snprintf(out, out_size, "IP_TTL"); break;
case IP_RECVOPTS: snprintf(out, out_size, "IP_RECVOPTS"); break;
case IP_RETOPTS: snprintf(out, out_size, "IP_RETOPTS"); break;
case IP_MULTICAST_IF: snprintf(out, out_size, "IP_MULTICAST_IF"); break;
case IP_MULTICAST_TTL: snprintf(out, out_size, "IP_MULTICAST_TTL"); break;
case IP_MULTICAST_LOOP: snprintf(out, out_size, "IP_MULTICAST_LOOP"); break;
case IP_ADD_MEMBERSHIP: snprintf(out, out_size, "IP_ADD_MEMBERSHIP"); break;
case IP_DROP_MEMBERSHIP: snprintf(out, out_size, "IP_DROP_MEMBERSHIP"); break;
case IP_UNBLOCK_SOURCE: snprintf(out, out_size, "IP_UNBLOCK_SOURCE"); break;
case IP_BLOCK_SOURCE: snprintf(out, out_size, "IP_BLOCK_SOURCE"); break;
case IP_ADD_SOURCE_MEMBERSHIP: snprintf(out, out_size, "IP_ADD_SOURCE_MEMBERSHIP"); break;
case IP_DROP_SOURCE_MEMBERSHIP: snprintf(out, out_size, "IP_DROP_SOURCE_MEMBERSHIP"); break;
case IP_MSFILTER: snprintf(out, out_size, "IP_MSFILTER"); break;
case MCAST_JOIN_GROUP: snprintf(out, out_size, "MCAST_JOIN_GROUP"); break;
case MCAST_BLOCK_SOURCE: snprintf(out, out_size, "MCAST_BLOCK_SOURCE"); break;
case MCAST_UNBLOCK_SOURCE: snprintf(out, out_size, "MCAST_UNBLOCK_SOURCE"); break;
case MCAST_LEAVE_GROUP: snprintf(out, out_size, "MCAST_LEAVE_GROUP"); break;
case MCAST_JOIN_SOURCE_GROUP: snprintf(out, out_size, "MCAST_JOIN_SOURCE_GROUP"); break;
case MCAST_LEAVE_SOURCE_GROUP: snprintf(out, out_size, "MCAST_LEAVE_SOURCE_GROUP"); break;
case MCAST_MSFILTER: snprintf(out, out_size, "MCAST_MSFILTER"); break;
case IP_MULTICAST_ALL: snprintf(out, out_size, "IP_MULTICAST_ALL"); break;
case IP_UNICAST_IF: snprintf(out, out_size, "IP_UNICAST_IF"); break;
case IP_ROUTER_ALERT: snprintf(out, out_size, "IP_ROUTER_ALERT"); break;
case IP_PKTINFO: snprintf(out, out_size, "IP_PKTINFO"); break;
case IP_PKTOPTIONS: snprintf(out, out_size, "IP_PKTOPTIONS"); break;
case IP_MTU_DISCOVER: snprintf(out, out_size, "IP_MTU_DISCOVER"); break;
// TODO: these are for optname IP_MTU_DISCOVER
//case IP_PMTUDISC_DONT: snprintf(out, out_size, "IP_PMTUDISC_DONT"); break;
//case IP_PMTUDISC_WANT: snprintf(out, out_size, "IP_PMTUDISC_WANT"); break;
//case IP_PMTUDISC_DO: snprintf(out, out_size, "IP_PMTUDISC_DO"); break;
//case IP_PMTUDISC_PROBE: snprintf(out, out_size, "IP_PMTUDISC_PROBE"); break;
//case IP_PMTUDISC_INTERFACE: snprintf(out, out_size, "IP_PMTUDISC_INTERFACE"); break;
//case IP_PMTUDISC_OMIT: snprintf(out, out_size, "IP_PMTUDISC_OMIT"); break;
case IP_RECVERR: snprintf(out, out_size, "IP_RECVERR"); break;
case IP_RECVTTL: snprintf(out, out_size, "IP_RECVTTL"); break;
case IP_RECVTOS: snprintf(out, out_size, "IP_RECVTOS"); break;
case IP_MTU: snprintf(out, out_size, "IP_MTU"); break;
case IP_FREEBIND: snprintf(out, out_size, "IP_FREEBIND"); break;
case IP_IPSEC_POLICY: snprintf(out, out_size, "IP_IPSEC_POLICY"); break;
case IP_XFRM_POLICY: snprintf(out, out_size, "IP_XFRM_POLICY"); break;
case IP_PASSSEC: snprintf(out, out_size, "IP_PASSSEC"); break;
case IP_TRANSPARENT: snprintf(out, out_size, "IP_TRANSPARENT"); break;
case IP_ORIGDSTADDR: snprintf(out, out_size, "IP_ORIGDSTADDR"); break;
case IP_MINTTL: snprintf(out, out_size, "IP_MINTTL"); break;
case IP_NODEFRAG: snprintf(out, out_size, "IP_NODEFRAG"); break;
case IP_CHECKSUM: snprintf(out, out_size, "IP_CHECKSUM"); break;
case IP_BIND_ADDRESS_NO_PORT: snprintf(out, out_size, "IP_BIND_ADDRESS_NO_PORT"); break;
case IP_RECVFRAGSIZE: snprintf(out, out_size, "IP_RECVFRAGSIZE"); break;
case IP_RECVERR_RFC4884: snprintf(out, out_size, "IP_RECVERR_RFC4884"); break;
// TODO case IP_MAX_MEMBERSHIPS: snprintf(out, out_size, "IP_MAX_MEMBERSHIPS"); break;
default: snprintf(out, out_size, "todo(%d)", optname); break;
}
nd_trace_color(out0, out_size, out, "flags", '-', "", 0);
}
#ifndef IPV6_MULTICAST_ALL
#define IPV6_MULTICAST_ALL 29
#endif
#ifndef IPV6_ROUTER_ALERT_ISOLATE
#define IPV6_ROUTER_ALERT_ISOLATE 30
#endif
#ifndef IPV6_RECVERR_RFC4884
#define IPV6_RECVERR_RFC4884 31
#endif
static void decode_sock_optname_ipv6(char *out0, unsigned out_size,
const int optname)
{
char out[out_size];
switch (optname) {
case IPV6_ADDRFORM: snprintf(out, out_size, "IPV6_ADDRFORM"); break;
case IPV6_2292PKTINFO: snprintf(out, out_size, "IPV6_2292PKTINFO"); break;
case IPV6_2292HOPOPTS: snprintf(out, out_size, "IPV6_2292HOPOPTS"); break;
case IPV6_2292DSTOPTS: snprintf(out, out_size, "IPV6_2292DSTOPTS"); break;
case IPV6_2292RTHDR: snprintf(out, out_size, "IPV6_2292RTHDR"); break;
case IPV6_2292PKTOPTIONS: snprintf(out, out_size, "IPV6_2292PKTOPTIONS"); break;
case IPV6_CHECKSUM: snprintf(out, out_size, "IPV6_CHECKSUM"); break;
case IPV6_2292HOPLIMIT: snprintf(out, out_size, "IPV6_2292HOPLIMIT"); break;
case IPV6_NEXTHOP: snprintf(out, out_size, "IPV6_NEXTHOP"); break;
case IPV6_AUTHHDR: snprintf(out, out_size, "IPV6_AUTHHDR"); break;
case IPV6_UNICAST_HOPS: snprintf(out, out_size, "IPV6_UNICAST_HOPS"); break;
case IPV6_MULTICAST_IF: snprintf(out, out_size, "IPV6_MULTICAST_IF"); break;
case IPV6_MULTICAST_HOPS: snprintf(out, out_size, "IPV6_MULTICAST_HOPS"); break;
case IPV6_MULTICAST_LOOP: snprintf(out, out_size, "IPV6_MULTICAST_LOOP"); break;
case IPV6_JOIN_GROUP: snprintf(out, out_size, "IPV6_JOIN_GROUP"); break;
case IPV6_LEAVE_GROUP: snprintf(out, out_size, "IPV6_LEAVE_GROUP"); break;
case IPV6_ROUTER_ALERT: snprintf(out, out_size, "IPV6_ROUTER_ALERT"); break;
case IPV6_MTU_DISCOVER: snprintf(out, out_size, "IPV6_MTU_DISCOVER"); break;
case IPV6_MTU: snprintf(out, out_size, "IPV6_MTU"); break;
case IPV6_RECVERR: snprintf(out, out_size, "IPV6_RECVERR"); break;
case IPV6_V6ONLY: snprintf(out, out_size, "IPV6_V6ONLY"); break;
case IPV6_JOIN_ANYCAST: snprintf(out, out_size, "IPV6_JOIN_ANYCAST"); break;
case IPV6_LEAVE_ANYCAST: snprintf(out, out_size, "IPV6_LEAVE_ANYCAST"); break;
case IPV6_MULTICAST_ALL: snprintf(out, out_size, "IPV6_MULTICAST_ALL"); break;
case IPV6_ROUTER_ALERT_ISOLATE: snprintf(out, out_size, "IPV6_ROUTER_ALERT_ISOLATE"); break;
case IPV6_RECVERR_RFC4884: snprintf(out, out_size, "IPV6_RECVERR_RFC4884"); break;
case IPV6_IPSEC_POLICY: snprintf(out, out_size, "IPV6_IPSEC_POLICY"); break;
case IPV6_XFRM_POLICY: snprintf(out, out_size, "IPV6_XFRM_POLICY"); break;
case IPV6_HDRINCL: snprintf(out, out_size, "IPV6_HDRINCL"); break;
case IPV6_RECVPKTINFO: snprintf(out, out_size, "IPV6_RECVPKTINFO"); break;
case IPV6_PKTINFO: snprintf(out, out_size, "IPV6_PKTINFO"); break;
case IPV6_RECVHOPLIMIT: snprintf(out, out_size, "IPV6_RECVHOPLIMIT"); break;
case IPV6_HOPLIMIT: snprintf(out, out_size, "IPV6_HOPLIMIT"); break;
case IPV6_RECVHOPOPTS: snprintf(out, out_size, "IPV6_RECVHOPOPTS"); break;
case IPV6_HOPOPTS: snprintf(out, out_size, "IPV6_HOPOPTS"); break;
case IPV6_RTHDRDSTOPTS: snprintf(out, out_size, "IPV6_RTHDRDSTOPTS"); break;
case IPV6_RECVRTHDR: snprintf(out, out_size, "IPV6_RECVRTHDR"); break;
case IPV6_RTHDR: snprintf(out, out_size, "IPV6_RTHDR"); break;
case IPV6_RECVDSTOPTS: snprintf(out, out_size, "IPV6_RECVDSTOPTS"); break;
case IPV6_DSTOPTS: snprintf(out, out_size, "IPV6_DSTOPTS"); break;
case IPV6_RECVPATHMTU: snprintf(out, out_size, "IPV6_RECVPATHMTU"); break;
case IPV6_PATHMTU: snprintf(out, out_size, "IPV6_PATHMTU"); break;
case IPV6_DONTFRAG: snprintf(out, out_size, "IPV6_DONTFRAG"); break;
case IPV6_RECVTCLASS: snprintf(out, out_size, "IPV6_RECVTCLASS"); break;
case IPV6_TCLASS: snprintf(out, out_size, "IPV6_TCLASS"); break;
case IPV6_AUTOFLOWLABEL: snprintf(out, out_size, "IPV6_AUTOFLOWLABEL"); break;
case IPV6_ADDR_PREFERENCES: snprintf(out, out_size, "IPV6_ADDR_PREFERENCES"); break;
case IPV6_MINHOPCOUNT: snprintf(out, out_size, "IPV6_MINHOPCOUNT"); break;
case IPV6_ORIGDSTADDR: snprintf(out, out_size, "IPV6_ORIGDSTADDR"); break;
case IPV6_TRANSPARENT: snprintf(out, out_size, "IPV6_TRANSPARENT"); break;
case IPV6_UNICAST_IF: snprintf(out, out_size, "IPV6_UNICAST_IF"); break;
case IPV6_RECVFRAGSIZE: snprintf(out, out_size, "IPV6_RECVFRAGSIZE"); break;
case IPV6_FREEBIND: snprintf(out, out_size, "IPV6_FREEBIND"); break;
//case : snprintf(out, out_size, ""); break;
default: snprintf(out, out_size, "todo(%d)", optname); break;
}
nd_trace_color(out0, out_size, out, "flags", '-', "", 0);
}
#ifndef TCP_ZEROCOPY_RECEIVE
#define TCP_ZEROCOPY_RECEIVE 35
#endif
#ifndef TCP_INQ
#define TCP_INQ 36
#endif
#ifndef TCP_TX_DELAY
#define TCP_TX_DELAY 37
#endif
#ifndef UDP_GRO
#define UDP_GRO 104
#endif
static void decode_sock_optname_tcp(char *out0, unsigned out_size,
const int optname)
{
char out[out_size];
switch (optname) {
case TCP_NODELAY: snprintf(out, out_size, "TCP_NODELAY"); break;
case TCP_MAXSEG: snprintf(out, out_size, "TCP_MAXSEG"); break;
case TCP_CORK: snprintf(out, out_size, "TCP_CORK"); break;
case TCP_KEEPIDLE: snprintf(out, out_size, "TCP_KEEPIDLE"); break;
case TCP_KEEPINTVL: snprintf(out, out_size, "TCP_KEEPINTVL"); break;
case TCP_KEEPCNT: snprintf(out, out_size, "TCP_KEEPCNT"); break;
case TCP_SYNCNT: snprintf(out, out_size, "TCP_SYNCNT"); break;
case TCP_LINGER2: snprintf(out, out_size, "TCP_LINGER2"); break;
case TCP_DEFER_ACCEPT: snprintf(out, out_size, "TCP_DEFER_ACCEPT"); break;
case TCP_WINDOW_CLAMP: snprintf(out, out_size, "TCP_WINDOW_CLAMP"); break;
case TCP_INFO: snprintf(out, out_size, "TCP_INFO"); break;
case TCP_QUICKACK: snprintf(out, out_size, "TCP_QUICKACK"); break;
case TCP_CONGESTION: snprintf(out, out_size, "TCP_CONGESTION"); break;
case TCP_MD5SIG: snprintf(out, out_size, "TCP_MD5SIG"); break;
case TCP_COOKIE_TRANSACTIONS: snprintf(out, out_size, "TCP_COOKIE_TRANSACTIONS"); break;
case TCP_THIN_LINEAR_TIMEOUTS: snprintf(out, out_size, "TCP_THIN_LINEAR_TIMEOUTS"); break;
case TCP_THIN_DUPACK: snprintf(out, out_size, "TCP_THIN_DUPACK"); break;
case TCP_USER_TIMEOUT: snprintf(out, out_size, "TCP_USER_TIMEOUT"); break;
case TCP_REPAIR: snprintf(out, out_size, "TCP_REPAIR"); break;
case TCP_REPAIR_QUEUE: snprintf(out, out_size, "TCP_REPAIR_QUEUE"); break;
case TCP_QUEUE_SEQ: snprintf(out, out_size, "TCP_QUEUE_SEQ"); break;
case TCP_REPAIR_OPTIONS: snprintf(out, out_size, "TCP_REPAIR_OPTIONS"); break;
case TCP_FASTOPEN: snprintf(out, out_size, "TCP_FASTOPEN"); break;
case TCP_TIMESTAMP: snprintf(out, out_size, "TCP_TIMESTAMP"); break;
case TCP_NOTSENT_LOWAT: snprintf(out, out_size, "TCP_NOTSENT_LOWAT"); break;
case TCP_CC_INFO: snprintf(out, out_size, "TCP_CC_INFO"); break;
case TCP_SAVE_SYN: snprintf(out, out_size, "TCP_SAVE_SYN"); break;
case TCP_SAVED_SYN: snprintf(out, out_size, "TCP_SAVED_SYN"); break;
case TCP_REPAIR_WINDOW: snprintf(out, out_size, "TCP_REPAIR_WINDOW"); break;
case TCP_FASTOPEN_CONNECT: snprintf(out, out_size, "TCP_FASTOPEN_CONNECT"); break;
case TCP_ULP: snprintf(out, out_size, "TCP_ULP"); break;
case TCP_MD5SIG_EXT: snprintf(out, out_size, "TCP_MD5SIG_EXT"); break;
case TCP_FASTOPEN_KEY: snprintf(out, out_size, "TCP_FASTOPEN_KEY"); break;
case TCP_FASTOPEN_NO_COOKIE: snprintf(out, out_size, "TCP_FASTOPEN_NO_COOKIE"); break;
case TCP_ZEROCOPY_RECEIVE: snprintf(out, out_size, "TCP_ZEROCOPY_RECEIVE"); break;
case TCP_INQ: snprintf(out, out_size, "TCP_INQ"); break;
case TCP_TX_DELAY: snprintf(out, out_size, "TCP_TX_DELAY"); break;
//case : snprintf(out, out_size, ""); break;
default: snprintf(out, out_size, "todo(%d)", optname); break;
}
nd_trace_color(out0, out_size, out, "flags", '-', "", 0);
}
#ifndef UDP_SEGMENT
#define UDP_SEGMENT 103
#endif
static void decode_sock_optname_udp(char *out0, unsigned out_size,
const int optname)
{
char out[out_size];
switch (optname) {
case UDP_CORK: snprintf(out, out_size, "UDP_CORK"); break;
case UDP_ENCAP: snprintf(out, out_size, "UDP_ENCAP"); break;
case UDP_NO_CHECK6_TX: snprintf(out, out_size, "UDP_NO_CHECK6_TX"); break;
case UDP_NO_CHECK6_RX: snprintf(out, out_size, "UDP_NO_CHECK6_RX"); break;
case UDP_SEGMENT: snprintf(out, out_size, "UDP_SEGMENT"); break;
case UDP_GRO: snprintf(out, out_size, "UDP_GRO"); break;
//case : snprintf(out, out_size, ""); break;
default: snprintf(out, out_size, "todo(%d)", optname); break;
}
nd_trace_color(out0, out_size, out, "flags", '-', "", 0);
}
static void decode_sock_optname_nl(char *out0, unsigned out_size,
const int optname)
{
char out[out_size];
switch (optname) {
case NETLINK_ADD_MEMBERSHIP: snprintf(out, out_size, "ADD_MEMBERSHIP"); break;
case NETLINK_DROP_MEMBERSHIP: snprintf(out, out_size, "DROP_MEMBERSHIP"); break;
case NETLINK_PKTINFO: snprintf(out, out_size, "PKTINFO"); break;
case NETLINK_BROADCAST_ERROR: snprintf(out, out_size, "BROADCAST_ERROR"); break;
case NETLINK_NO_ENOBUFS: snprintf(out, out_size, "NO_ENOBUFS"); break;
case NETLINK_RX_RING: snprintf(out, out_size, "RX_RING"); break;
case NETLINK_TX_RING: snprintf(out, out_size, "TX_RING"); break;
case NETLINK_LISTEN_ALL_NSID: snprintf(out, out_size, "LISTEN_ALL_NSID"); break;
case NETLINK_LIST_MEMBERSHIPS: snprintf(out, out_size, "LIST_MEMBERSHIPS"); break;
case NETLINK_CAP_ACK: snprintf(out, out_size, "CAP_ACK"); break;
case NETLINK_EXT_ACK: snprintf(out, out_size, "EXT_ACK"); break;
case NETLINK_GET_STRICT_CHK: snprintf(out, out_size, "GET_STRICT_CHK"); break;
default: snprintf(out, out_size, "todo(%d)", optname); break;
}
nd_trace_color(out0, out_size, out, "flags", '-', "", 0);
}
static void decode_sock_optname(char *out, unsigned out_size,
const int level,
unsigned char *d, unsigned int *i)
{
int v = decode32(d, i);
if (level == SOL_SOCKET)
decode_sock_optname_socket(out, out_size, v);
else if (level == SOL_IP)
decode_sock_optname_ip(out, out_size, v);
else if (level == SOL_IPV6)
decode_sock_optname_ipv6(out, out_size, v);
else if (level == SOL_TCP)
decode_sock_optname_tcp(out, out_size, v);
else if (level == SOL_UDP)
decode_sock_optname_udp(out, out_size, v);
else if (level == SOL_NETLINK)
decode_sock_optname_nl(out, out_size, v);
else
snprintf(out, out_size, "%d", v);
}
static void decode_syslog_prio(char *out0, unsigned out_size,
unsigned char *d, unsigned int *i)
{
int v = decode32(d, i);
int facility = v >> 3;
char sfac[16];
if (facility)
snprintf(sfac, sizeof(sfac), "/fac=%d", facility);
else
sfac[0] = '\0';
char out[out_size];
switch (v & 7) {
case LOG_EMERG: snprintf(out, out_size, "LOG_EMERG%s", sfac); break;
case LOG_ALERT: snprintf(out, out_size, "LOG_ALERT%s", sfac); break;
case LOG_CRIT: snprintf(out, out_size, "LOG_CRIT%s", sfac); break;
case LOG_ERR: snprintf(out, out_size, "LOG_ERR%s", sfac); break;
case LOG_WARNING: snprintf(out, out_size, "LOG_WARNING%s", sfac); break;
case LOG_NOTICE: snprintf(out, out_size, "LOG_NOTICE%s", sfac); break;
case LOG_INFO: snprintf(out, out_size, "LOG_INFO%s", sfac); break;
case LOG_DEBUG: snprintf(out, out_size, "LOG_DEBUG%s", sfac); break;
default: snprintf(out, out_size, "todo(%d/%s)", v & 7, sfac);
}
nd_trace_color(out0, out_size, out, "flags", '-', "", 0);
}
static void decode_stat(char *out, unsigned out_size,
unsigned char *d, unsigned int *i)
{
struct stat s;
int ret = decode_ret_int(out, out_size, d, i);
if (ret != 0)
return;
s.st_dev = decode64(d, i);
s.st_ino = decode64(d, i);
s.st_mode = decode32(d, i);
s.st_nlink = decode64(d, i);
s.st_uid = decode32(d, i);
s.st_gid = decode32(d, i);
s.st_rdev = decode64(d, i);
s.st_size = decode64(d, i);
s.st_blksize = decode64(d, i);
s.st_blocks = decode64(d, i);
s.st_atim.tv_sec = decode64(d, i);
s.st_atim.tv_nsec = decode32(d, i);
s.st_mtim.tv_sec = decode64(d, i);
s.st_mtim.tv_nsec = decode32(d, i);
s.st_ctim.tv_sec = decode64(d, i);
s.st_ctim.tv_nsec = decode32(d, i);
snprintf(out, out_size,
" => {dev=%u:%u ino=%lu mode=0x%u nlink=%lu uid=%u gid=%u rdev=%lu"
" size=%lu blksize=%lu blocks=%lu atime=%ld.%010ld"
" mtime=%ld.%010ld ctime=%ld.%010ld}",
major(s.st_dev), minor(s.st_dev),
s.st_ino, s.st_mode, s.st_nlink, s.st_uid, s.st_gid, s.st_rdev,
s.st_size, s.st_blksize, s.st_blocks, s.st_atim.tv_sec, s.st_atim.tv_nsec,
s.st_mtim.tv_sec, s.st_mtim.tv_nsec, s.st_ctim.tv_sec, s.st_ctim.tv_nsec);
}
static void decode_statx_dirfd(char *out0, const size_t out_size,
unsigned char *d, unsigned int *i)
{
int v = decode32(d, i);
char out[out_size];
switch (v) {
case AT_FDCWD: snprintf(out, out_size, "AT_FDCWD"); break;
default: snprintf(out, out_size, "%d", v); break;
}
nd_trace_color(out0, out_size, out, "flags", '-', "", 0);
}
static void decode_statx_timestamp(char *out, const size_t out_size,
const char *prefix, unsigned char *d, unsigned int *i)
{
struct statx_timestamp ts;
ts.tv_sec = decode64(d, i);
ts.tv_nsec = decode32(d, i);
snprintf(out, out_size, "%s%llu.%06u", prefix, ts.tv_sec, ts.tv_nsec);
}
static void decode_statx_attr(char *out, const size_t out_size,
const uint64_t attr, const uint64_t attr_mask)
{
char sattr[128], color_sattr[128];
nd_decode_statx_attr(sattr, sizeof(sattr), attr);
nd_trace_color(color_sattr, sizeof(color_sattr), sattr, "flags", '-', "", 0);
//char sattr_mask[128];
//nd_decode_statx_attr(sattr_mask, sizeof(sattr_mask), attr_mask);
//snprintf(out, out_size, " attr=%s/%s", sattr, sattr_mask);
snprintf(out, out_size, " attr=%s", color_sattr);
}
// TODO: proper decoding of file type
static void decode_statx(char *out, unsigned out_size,
unsigned char *d, unsigned int *i)
{
struct statx s;
char blksize[16] = { 0 };
char nlink[16] = { 0 };
char uid[16] = { 0 };
char gid[16] = { 0 };
char mode[16] = { 0 };
char ino[32] = { 0 };
char size[32] = { 0 };
char blocks[32] = { 0 };
char atime[32] = { 0 };
char btime[32] = { 0 };
char ctime[32] = { 0 };
char mtime[32] = { 0 };
char rdev[32] = { 0 };
char dev[32] = { 0 };
char mnt[32] = { 0 };
int ret = decode_ret_int(out, out_size, d, i);
if (ret != 0)
return;
s.stx_mask = decode32(d, i);
s.stx_blksize = decode32(d, i);
snprintf(blksize, sizeof(blksize), "blksize=%u", s.stx_blksize);
s.stx_attributes = decode64(d, i);
if (s.stx_mask & STATX_NLINK) {
s.stx_nlink = decode32(d, i);
snprintf(nlink, sizeof(nlink), " nlink=%u", s.stx_nlink);
}
if (s.stx_mask & STATX_UID) {
s.stx_uid = decode32(d, i);
snprintf(uid, sizeof(uid), " uid=%u", s.stx_uid);
}
if (s.stx_mask & STATX_GID) {
s.stx_gid = decode32(d, i);
snprintf(gid, sizeof(gid), " gid=%u", s.stx_gid);
}
if (s.stx_mask & (STATX_TYPE | STATX_MODE)) {
s.stx_mode = decode16(d, i);
snprintf(mode, sizeof(mode), " mode=%hu", s.stx_mode);
}
if (s.stx_mask & STATX_INO) {
s.stx_ino = decode64(d, i);
snprintf(ino, sizeof(ino), " ino=%llu", s.stx_ino);
}
if (s.stx_mask & STATX_SIZE) {
s.stx_size = decode64(d, i);
snprintf(size, sizeof(size), " size=%llu", s.stx_size);
}
if (s.stx_mask & STATX_BLOCKS) {
s.stx_blocks = decode64(d, i);
snprintf(blocks, sizeof(blocks), " blocks=%llu", s.stx_blocks);
}
s.stx_attributes_mask = decode64(d, i);
if (s.stx_mask & STATX_ATIME)
decode_statx_timestamp(atime, sizeof(atime), " atime=", d, i);
if (s.stx_mask & STATX_BTIME)
decode_statx_timestamp(btime, sizeof(btime), " btime=", d, i);
if (s.stx_mask & STATX_CTIME)
decode_statx_timestamp(ctime, sizeof(ctime), " ctime=", d, i);
if (s.stx_mask & STATX_MTIME)
decode_statx_timestamp(mtime, sizeof(mtime), " mtime=", d, i);
s.stx_rdev_major = decode32(d, i);
s.stx_rdev_minor = decode32(d, i);
snprintf(rdev, sizeof(rdev), " rdev=%u:%u", s.stx_rdev_major, s.stx_rdev_minor);
s.stx_dev_major = decode32(d, i);
s.stx_dev_minor = decode32(d, i);
snprintf(dev, sizeof(dev), " dev=%u:%u", s.stx_dev_major, s.stx_dev_minor);
if (s.stx_mask & STATX_MNT_ID) {
s.stx_mnt_id = decode64(d, i);
snprintf(mnt, sizeof(mnt), " mnt_id=%llu", s.stx_mnt_id);
}
char attr[128];
decode_statx_attr(attr, sizeof(attr), s.stx_attributes, s.stx_attributes_mask);
snprintf(out, out_size,
" => {%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s}",
blksize, attr, nlink, uid, gid, mode, ino, size, blocks,
atime, btime, ctime, mtime, rdev, dev);
}
static void decode_string_array(char *out, size_t out_size,
unsigned char *d, unsigned int *i)
{
size_t rest = out_size;
char *add = "";
if (out_size < 1)
return;
if (out_size < 3) {
strcpy(out, "");
return;
}
strcpy(out, "{");
while (1) {
unsigned short len = decode16(d, i);
if (len == 0)
break;
char e[len * 4 + 1];
sf_tools_bin2hex_ascii(e, d + *i, len); *i = *i + len;
unsigned int e_len = strlen(e);
if (2 + e_len + 2 > rest) // 2 for 2x"'" and 2 for ', ' or '}'
break;
strcat(out, add);
strcat(out, "'");
strcat(out, e);
strcat(out, "'");
add = ", ";
rest -= e_len + 2;
}
strcat(out, "}");
}
static int decode_sqlite3_ret(char *out0, unsigned out_size,
unsigned char *d, unsigned int *i)
{
unsigned int ret = decode32(d, i);
char out[out_size];
switch (ret) {
case 0: snprintf(out, out_size, "ok"); break;
case 1: snprintf(out, out_size, "ERROR"); break;
case 2: snprintf(out, out_size, "INTERNAL"); break;
case 3: snprintf(out, out_size, "PERM"); break;
case 4: snprintf(out, out_size, "ABORT"); break;
case 5: snprintf(out, out_size, "BUSY"); break;
case 6: snprintf(out, out_size, "LOCKED"); break;
case 7: snprintf(out, out_size, "NOMEM"); break;
case 8: snprintf(out, out_size, "READONLY"); break;
case 9: snprintf(out, out_size, "INTERRUPT"); break;
case 10: snprintf(out, out_size, "IOERR"); break;
case 11: snprintf(out, out_size, "CORRUPT"); break;
case 12: snprintf(out, out_size, "NOTFOUND"); break;
case 13: snprintf(out, out_size, "FULL"); break;
case 14: snprintf(out, out_size, "CANTOPEN"); break;
case 15: snprintf(out, out_size, "PROTOCOL"); break;
case 16: snprintf(out, out_size, "EMPTY"); break;
case 17: snprintf(out, out_size, "SCHEMA"); break;
case 18: snprintf(out, out_size, "TOOBIG"); break;
case 19: snprintf(out, out_size, "CONSTRAINT"); break;
case 20: snprintf(out, out_size, "MISMATCH"); break;
case 21: snprintf(out, out_size, "MISUSE"); break;
case 22: snprintf(out, out_size, "NOLFS"); break;
case 23: snprintf(out, out_size, "AUTH"); break;
case 24: snprintf(out, out_size, "FORMAT"); break;
case 25: snprintf(out, out_size, "RANGE"); break;
case 26: snprintf(out, out_size, "NOTADB"); break;
case 27: snprintf(out, out_size, "NOTICE"); break;
case 28: snprintf(out, out_size, "WARNING"); break;
case 100: snprintf(out, out_size, "ROW"); break;
case 101: snprintf(out, out_size, "DONE"); break;
default: snprintf(out, out_size, "todo(%u)", ret);
}
nd_trace_color(out0, out_size, out, "flags", '-', "", 0);
return ret;
}
static int decode_sqlite3_open_flags(char *out, unsigned out_size,
unsigned char *d, unsigned int *i)
{
unsigned int ret = decode32(d, i);
char *a = ""; if (ret & 0x00000001) a = "|READONLY";
char *b = ""; if (ret & 0x00000002) b = "|READWRITE";
char *c = ""; if (ret & 0x00000004) c = "|CREATE";
char *e = ""; if (ret & 0x00000008) e = "|DELETEONCLOSE";
char *f = ""; if (ret & 0x00000010) f = "|EXCLUSIVE";
char *g = ""; if (ret & 0x00000020) g = "|AUTOPROXY";
char *h = ""; if (ret & 0x00000040) h = "|URI";
char *j = ""; if (ret & 0x00000080) j = "|MEMORY";
char *k = ""; if (ret & 0x00000100) k = "|MAIN_DB";
char *l = ""; if (ret & 0x00000200) l = "|TEMP_DB";
char *m = ""; if (ret & 0x00000400) m = "|TRANSIENT_DB";
char *n = ""; if (ret & 0x00000800) n = "|MAIN_JOURNAL";
char *o = ""; if (ret & 0x00001000) o = "|TEMP_JOURNAL";
char *p = ""; if (ret & 0x00002000) p = "|SUBJOURNAL";
char *q = ""; if (ret & 0x00004000) q = "|SUPER_JOURNAL";
char *r = ""; if (ret & 0x00008000) r = "|NOMUTEX";
char *s = ""; if (ret & 0x00010000) s = "|FULLMUTEX";
char *t = ""; if (ret & 0x00020000) t = "|SHAREDCACHE";
char *u = ""; if (ret & 0x00040000) u = "|PRIVATECACHE";
char *v = ""; if (ret & 0x00080000) v = "|WAL";
char *w = ""; if (ret & 0x00100000) w = "|NOFOLLOW";
snprintf(out, out_size, "0x%x=%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
ret, a, b, c, e, f, g, h, j, k, l, m, n, o, p, q, r, s, t, u, v, w);
return ret;
}
static int decode_mysql_real_connect_flags(char *out, unsigned out_size,
unsigned char *d, unsigned int *i)
{
int ret = decode32(d, i);
char *f1 = ""; if (ret & 2) f1 = "|FOUND_ROWS";
char *f2 = ""; if (ret & 32) f2 = "|COMPRESS";
char *f3 = ""; if (ret & 64) f3 = "|SSL_DONT_VERIFY_SERVER_CERT";
char *f4 = ""; if (ret & 256) f4 = "|IGNORE_SPACE";
char *f5 = ""; if (ret & 1024) f5 = "|INTERACTIVE";
char *f6 = ""; if (ret & 2048) f6 = "|SSL";
snprintf(out, out_size, "0x%x=%s%s%s%s%s%s", ret, f1, f2, f3, f4, f5, f6);
return ret;
}
static int decode_dlopen_flags(char *out, size_t out_size,
unsigned char *d, unsigned int *i)
{
int ret = decode32(d, i);
char *lazy = ""; if (ret & RTLD_LAZY) lazy = "|LAZY";
char *now = ""; if (ret & RTLD_NOW) lazy = "|NOW";
char *global = ""; if (ret & RTLD_GLOBAL) global = "|GLOBAL";
char *local = ""; if (ret & RTLD_LOCAL) local = "|LOCAL";
char *nodel = ""; if (ret & RTLD_NODELETE) nodel = "|NODELETE";
char *noload = ""; if (ret & RTLD_NOLOAD) nodel = "|NOLOAD";
char *deep = ""; if (ret & RTLD_DEEPBIND) deep = "|DEEPBIND";
snprintf(out, out_size, "0x%x=%s%s%s%s%s%s%s",
ret, lazy, now, global, local, nodel, noload, deep);
return ret;
}
static int decode_mysqli_mode(char *out, size_t out_size,
unsigned char *d, unsigned int *i)
{
int mode = decode32(d, i);
if (mode == 1)
snprintf(out, out_size, "MYSQLI_ASSOC");
else if (mode == 2)
snprintf(out, out_size, "MYSQLI_NUM");
else if (mode == 3)
snprintf(out, out_size, "MYSQLI_BOTH");
return mode;
}
static void decode_query_params(char *out, size_t out_size,
unsigned char filter_bind_way, unsigned char *d, unsigned int *i)
{
unsigned short j;
size_t len, rest = out_size - 1 - 1; // -1 for \0 and -1 for '}'
//fprintf(outf, "%s: filter_bind_way=%hhu\n",
// __func__, filter_bind_way);
if (rest >= 2) {
strcpy(out, " {");
rest -= 2;
}
char *add = "", do_break = 0;
j = 1;
while (1) {
char value[64];
uint8_t type = decode8(d, i);
//fprintf(outf, " type=%hhu\n", type);
if (type == ND_TYPE_LAST)
break;
uint8_t bind_info = decode8(d, i); // (o->bind_way << 2) | o->bind_type
uint8_t bind_type = bind_info & 3;
uint8_t bind_way = (bind_info >> 2) & 3;
char head[128];
const char *way = "";
if (bind_way == ND_PARAMS_BIND_WAY_IN)
way = "IN:";
else if (bind_way == ND_PARAMS_BIND_WAY_OUT)
way = "OUT:";
else if (bind_way == ND_PARAMS_BIND_WAY_BOTH)
way = "IN/OUT:";
//fprintf(outf, " type=%hhu bind_type=%hhu bind_way=%hhu\n",
// type, bind_type, bind_way);
if (bind_type == ND_PARAMS_BIND_TYPE_NAME) {
uint8_t name_len = decode8(d, i);
char name[name_len * 4 + 1];
sf_tools_bin2hex_ascii(name, d + *i, name_len); *i = *i + name_len;
snprintf(head, sizeof(head), "%s'%s'", way, name);
} else if (bind_type == ND_PARAMS_BIND_TYPE_POS) {
snprintf(head, sizeof(head), "%s%hu", way, decode16(d, i));
} else {
snprintf(head, sizeof(head), "%s%hu", way, j);
}
if (type == ND_TYPE_NULL) { // NULL
snprintf(value, sizeof(value),
"%s:NULL", head);
} else if (type == ND_TYPE_INT) {
snprintf(value, sizeof(value),
"%s:int:%d", head, decode32(d, i));
} else if (type == ND_TYPE_LONG) {
snprintf(value, sizeof(value),
"%s:long:%ld", head, decode64(d, i));
} else if (type == ND_TYPE_DOUBLE) {
double dd;
uint64_t u = decode64(d, i);
memcpy(&dd, &u, 8);
snprintf(value, sizeof(value),
"%s:double:%f", head, dd);
} else if ((type == ND_TYPE_STRING) || (type == ND_TYPE_UNK)) {
uint16_t len = decode16(d, i);
char s[len * 4 + 1];
sf_tools_bin2hex_ascii(s, d + *i, len); *i = *i + len;
snprintf(value, sizeof(value),
"%s:str:'%s'", head, s);
} else {
snprintf(value, sizeof(value),
"%s:unk, ...", head);
do_break = 1; // we cannot continue
}
len = 2 + strlen(value);
if (len > rest)
break;
if (filter_bind_way & bind_way) {
strcat(out, add);
strcat(out, value);
add = ", ";
rest -= len;
}
if (do_break)
break;
j++;
}
strcat(out, "}");
}
static int decode_h_errno(char *out, const size_t out_size, unsigned char *d, unsigned int *i)
{
int ret = decode32(d, i);
switch (ret) {
case HOST_NOT_FOUND: snprintf(out, out_size, "HOST_NOT_FOUND"); break;
case NO_DATA: snprintf(out, out_size, "NO_DATA"); break;
case NO_RECOVERY: snprintf(out, out_size, "NO_RECOVERY"); break;
case TRY_AGAIN: snprintf(out, out_size, "TRY_AGAIN"); break;
default: snprintf(out, out_size, "todo(%d)", ret);
}
return ret;
}
static void decode_hostent(char *out, const size_t out_size, unsigned char *d, unsigned int *i)
{
uint8_t len = decode8(d, i);
char name[len * 4 + 1];
sf_tools_bin2hex_ascii(name, d + *i, len); *i = *i + len;
char aliases[512] = {0}; char *add = "";
for (int j = 0; ; j++) {
uint8_t alen = decode8(d, i);
if (alen == 0)
break;
char alias[alen * 4 + 1];
sf_tools_bin2hex_ascii(alias, d + *i, alen); *i = *i + alen;
strcat(aliases, add); add = ",";
strcat(aliases, alias);
}
uint8_t addrtype = decode8(d, i);
uint8_t h_length = decode8(d, i);
uint8_t count = decode8(d, i);
char addrs[512] = {0}; add = "";
for (int j = 0; j < count; j++) {
char addr[40];
const char *r = inet_ntop(addrtype, d + *i, addr, sizeof(addr));
if (!r)
sf_tools_bin2hex(addr, d + *i, h_length);
*i = *i + h_length;
strcat(addrs, add); add = ", ";
strcat(addrs, addr);
}
snprintf(out, out_size, " => name=[%s] aliases={%s} addrs={%s}",
name, aliases, addrs);
}
static int decode_whence(char *out0, const size_t out_size, unsigned char *d, unsigned int *i)
{
int ret = decode32(d, i);
char out[out_size];
switch (ret) {
case SEEK_SET: snprintf(out, out_size, "SEEK_SET"); break;
case SEEK_CUR: snprintf(out, out_size, "SEEK_CUR"); break;
case SEEK_END: snprintf(out, out_size, "SEEK_END"); break;
case SEEK_DATA: snprintf(out, out_size, "SEEK_DATA"); break;
case SEEK_HOLE: snprintf(out, out_size, "SEEK_HOLE"); break;
default: snprintf(out, out_size, "todo(%d)", ret);
}
nd_trace_color(out0, out_size, out, "flags", '-', "", 0);
return ret;
}
// TODO: we need to check if out is large enough
static void decode_types(char *out, const size_t out_size,
unsigned char *buf, unsigned int *i)
{
unsigned int off = 0;
uint16_t u16;
int64_t d64;
uint64_t u64;
char *add = "";
unsigned char depth = 0;
char tmp[4096];
do {
unsigned char type = buf[*i]; *i = *i + 1;
switch (type) {
case ND_TYPE_ARRAY_START:
strcat(out + off, add); off += strlen(add);
out[off++] = '{';
depth++;
add = "";
break;
case ND_TYPE_ARRAY_END:
out[off++] = '}';
depth--;
add = ", ";
break;
case ND_TYPE_STRING:
memcpy(&u16, buf + *i, 2); *i = *i + 2;
u16 = be16toh(u16);
sf_tools_bin2hex_ascii(tmp, buf + *i, u16); *i = *i + u16;
off += sprintf(out + off, "%s'%s'", add, tmp);
add = ", ";
break;
case ND_TYPE_TRUE:
off += sprintf(out + off, "%strue", add);
add = ", ";
break;
case ND_TYPE_FALSE:
off += sprintf(out + off, "%sfalse", add);
add = ", ";
break;
case ND_TYPE_NULL:
off += sprintf(out + off, "%snull", add);
add = ", ";
break;
case ND_TYPE_UNK:
off += sprintf(out + off, "%s?", add);
add = ", ";
break;
case ND_TYPE_LONG:
memcpy(&d64, buf + *i, 8); *i = *i + 8;
d64 = be64toh(d64);
off += sprintf(out + off, "%s%ld", add, d64);
add = ", ";
break;
case ND_TYPE_DOUBLE:
memcpy(&d64, buf + *i, 8); *i = *i + 8;
d64 = be64toh(d64);
double d;
memcpy(&d, &d64, 8);
off += sprintf(out + off, "%s%f", add, d);
add = ", ";
break;
case ND_TYPE_POINTER:
memcpy(&u64, buf + *i, 8); *i = *i + 8;
u64 = be64toh(u64);
off += sprintf(out + off, "%s0x%lx", add, u64);
add = ", ";
break;
}
} while (depth > 0);
}
static uint8_t decode_string8(unsigned char *out, unsigned char *d, unsigned int *i)
{
uint8_t len = decode8(d, i);
memcpy(out, d + *i, len); *i = *i + len;
return len;
}
// TODO: use this!
static void decode_ascii_string8(char *out, unsigned char *d, unsigned int *i)
{
uint8_t len = decode8(d, i);
sf_tools_bin2hex_ascii(out, d + *i, len); *i = *i + len;
}
static void decode_filename(char *out, unsigned char *d, unsigned int *i)
{
char tmp[512];
decode_ascii_string8(tmp, d, i);
nd_trace_color(out, 512, tmp, "file", '-', "", 0);
}
// TODO: decode type
// TODO: add color for the file name
static void decode_dirent(char *out, const size_t out_size,
unsigned char *d, unsigned int *i)
{
uint8_t we_have_data = decode8(d, i);
if (we_have_data == 0) {
int xerrno = decode32(d, i);
char err[64];
decode_errno(err, sizeof(err), xerrno);
if (xerrno == 0)
snprintf(out, out_size, " - no more objects");
else
snprintf(out, out_size, " = %d (%s)", xerrno, err);
return;
}
struct dirent e;
e.d_ino = decode64(d, i);
e.d_off = decode64(d, i);
e.d_type = decode8(d, i);
char name[512];
decode_filename(name, d, i);
snprintf(out, out_size, " => %s {ino=%lu off=%lu type=%hhu}",
name, e.d_ino, e.d_off, e.d_type);
}
// 2400000018000106443322118877665502200012fa00ff01000000000800010008000500
static void decode_msg_nl_rt(char *out, const size_t out_size,
unsigned char *buf, const unsigned int buf_size)
{
struct rtmsg *r = (struct rtmsg *) buf;
unsigned int rest;
size_t off = 0;
char dom[32], protocol[32], scope[32], type[32], flags[128];
nd_decode_socket_domain(dom, sizeof(dom), r->rtm_family);
nd_decode_route_protocol(protocol, sizeof(protocol), r->rtm_protocol);
nd_decode_route_scope(scope, sizeof(scope), r->rtm_scope);
nd_decode_route_type(type, sizeof(type), r->rtm_type);
nd_decode_route_flags(flags, sizeof(flags), r->rtm_flags);
nd_str_append(out, out_size, &off,
"family=%s dst_len=%hhu src_len=%hhu tos=0x%hhx"
" table=%hhu protocol=%s scope=%s type=%s flags=%s",
dom, r->rtm_dst_len, r->rtm_src_len, r->rtm_tos,
r->rtm_table, protocol, scope, type, flags);
struct rtattr *rta = (struct rtattr *) (buf + NLMSG_ALIGN(sizeof(struct rtmsg)));
rest = buf_size - NLMSG_ALIGN(sizeof(struct rtmsg));
while (1) {
if (!RTA_OK(rta, rest))
break;
char dump[512];
nd_decode_rta(dump, sizeof(dump), rta->rta_type, r->rtm_family,
RTA_DATA(rta), RTA_PAYLOAD(rta));
nd_str_append(out, out_size, &off, "%s", dump);
rta = RTA_NEXT(rta, rest);
}
if (rest != 0) {
char dump[rest * 4 + 1];
sf_tools_bin2hex(dump, rta, rest);
nd_str_append(out, out_size, &off, " junk=%s", dump);
}
}
static void decode_msg_nl(char *out, const size_t out_size,
unsigned char *buf, const unsigned int buf_size)
{
struct nlmsghdr *n = (struct nlmsghdr *) buf;
char stype[32], sflags[128];
uint8_t req_type;
nd_decode_nlmsg_type(stype, sizeof(stype), n->nlmsg_type, &req_type);
nd_decode_nlmsg_flags(sflags, sizeof(sflags), n->nlmsg_flags, req_type);
char decoded[buf_size * 10 + 1];
unsigned char *buf2 = buf + NLMSG_LENGTH(0);
const unsigned int buf2_size = buf_size - NLMSG_LENGTH(0);
if (n->nlmsg_type == RTM_NEWROUTE)
decode_msg_nl_rt(decoded, sizeof(decoded), buf2, buf2_size);
else
sf_tools_bin2hex(decoded, buf2, buf2_size);
snprintf(out, out_size, "nl={len=%u, type=%s flags=%s seq=%u pid=%u [%s]}",
n->nlmsg_len, stype, sflags, n->nlmsg_seq, n->nlmsg_pid, decoded);
}
static void decode_msg(char *out, const size_t out_size, const uint16_t family,
unsigned char *buf, const unsigned int buf_size)
{
if (family == AF_NETLINK) {
decode_msg_nl(out, out_size, buf, buf_size);
} else {
char dump[buf_size * 4 + 1];
sf_tools_bin2hex(dump, buf, buf_size);
snprintf(out, out_size, "?%hu?={%s}", family, dump);
}
}
static void decode_msghdr(char *out, const size_t out_size,
unsigned char *d, unsigned int *i)
{
char *add = "";
size_t len = 0;
uint16_t family = 0;
nd_str_append(out, out_size, &len, "{");
unsigned char name[256];
uint8_t name_len = decode_string8(name, d, i);
if (name_len) {
struct sockaddr *s = (struct sockaddr *) name;
family = s->sa_family;
char sname[name_len * 4 + 1];
sf_tools_bin2hex_ascii(sname, name, name_len);
nd_str_append(out, out_size, &len, "name=[%s] ", sname);
}
unsigned char control[256];
uint8_t control_len = decode_string8(control, d, i);
if (control_len) {
char scontrol[control_len * 4 + 1];
sf_tools_bin2hex_ascii(scontrol, control, control_len);
nd_str_append(out, out_size, &len, "control=[%s] ", control);
}
int msg_flags = decode32(d, i);
size_t iovlen = decode64(d, i);
nd_str_append(out, out_size, &len, "flags=0x%x iovlen=%zu",
msg_flags, iovlen);
uint16_t real_iovlen = decode16(d, i);
if (iovlen > 0) {
nd_str_append(out, out_size, &len, ": ");
for (uint16_t j = 0; j < real_iovlen; j++) {
size_t msg_iov_len = decode64(d, i);
uint16_t max = decode16(d, i);
char decoded[4096] = { 0 };
if (max > 0) {
decode_msg(decoded, sizeof(decoded), family, d + *i, max);
*i = *i + max;
}
nd_str_append(out, out_size, &len,
"%s" "{iov %hu: len=%zu: %s}",
add, j, msg_iov_len, decoded);
add = ", ";
}
}
nd_str_append(out, out_size, &len, "}");
}
static void decode_func(const uint32_t parent, unsigned char *d)
{
unsigned char nothing_to_log = 0;
unsigned int i = 0;
unsigned short func_len, trace_depth;
char type, line[64000], line2[64000], rest[4000];
uint64_t t;
line[0] = '\0';
line2[0] = '\0';
rest[0] = '\0';
t = decode64(d, &i);
uint8_t tf_len = decode8(d, &i);
char tf[tf_len + 1];
memcpy(tf, d + i, tf_len); i += tf_len;
tf[tf_len] = '\0';
trace_depth = decode16(d, &i);
func_len = decode16(d, &i);
char func[func_len * 4 + 1];
sf_tools_bin2hex_ascii(func, d + i, func_len); i += func_len;
type = d[i++];
uint32_t pid = decode32(d, &i);
uint32_t tid = decode32(d, &i);
//fprintf(outf, "%s: t=%lu func_len=%hu func=[%s] tf=[%s] type=%c pid=%u tid=%u\n",
// __func__, t, func_len, func, tf, type, pid, tid);
if (only_high_level && !strstr(tf, "i"))
return;
switch (func[0]) {
case '-': // project specific
if (strcmp(func, "-stop") == 0) {
int ret = decode32(d, &i);
sprintf(rest, "exit code = %d", ret);
char color[64];
nd_trace_color(color, sizeof(color), rest, "error", '-', "", ret);
sprintf(line, ": %s", color);
if (pid == parent)
do_exit++;
} else if (strcmp(func, "-segv") == 0) {
uint8_t regs = decode8(d, &i);
strcat(line, ": regs:");
for (uint8_t j = 0; j < regs; j++) {
char l[64], name[32];
nd_decode_register(name, sizeof(name), j);
snprintf(l, sizeof(l), " %s=0x%016lx",
name, decode64(d, &i));
strcat(line, l);
}
int r = decode32(d, &i);
strcat(line, "; bt:");
for (int j = 0; j < r; j++) {
unsigned char len = decode8(d, &i);
char l[len * 4 + 1];
sf_tools_bin2hex_ascii(l, d + i, len); i += len;
strcat(line, " ");
strcat(line, l);
}
if (pid == parent)
do_exit++;
} else if (strcmp(func, "-msgs_lost") == 0) {
sprintf(rest, "ninedogs: messages lost: %u", decode32(d, &i));
nd_trace_color(line, sizeof(line), rest, "error", '-', "", 1);
} break;
case 'a':
if (strcmp(func, "accept") == 0) {
int fd = decode32(d, &i);
int addrlen = decode32(d, &i);
if (type == 'c') {
sprintf(line, "(%d, sockaddr, %u)%s",
fd, addrlen, rest);
} else {
char sa[256];
nd_decode_sockaddr(sa, d + i, addrlen); i += addrlen;
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(%d, %s, %u)%s",
fd, sa, addrlen, rest);
}
} else if (strcmp(func, "accept4") == 0) {
int fd = decode32(d, &i);
int addrlen = decode32(d, &i);
int flags = decode32(d, &i);
if (type == 'c') {
sprintf(line, "(%d, sockaddr, %u, 0x%x)",
fd, addrlen, flags);
} else {
char sa[256];
nd_decode_sockaddr(sa, d + i, addrlen); i += addrlen;
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(%d, %s, %u, 0x%x)%s",
fd, sa, addrlen, flags, rest);
}
} break;
case 'b':
if (strcmp(func, "bind") == 0) {
int sock = decode32(d, &i);
char dump[128];
socklen_t sl = decode_sockaddr(dump, d, &i);
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(%d, %s, %d)%s", sock, dump, sl, rest);
} break;
case 'c':
if (strcmp(func, "close") == 0) {
int fd = decode32(d, &i);
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(%d)%s", fd, rest);
} else if (strcmp(func, "closedir") == 0) {
uint64_t dir = decode64(d, &i);
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(0x%lx)%s", dir, rest);
} else if (strcmp(func, "connect") == 0) {
int sock = decode32(d, &i);
if (type == 'c') {
char dump[128];
socklen_t sl = decode_sockaddr(dump, d, &i);
sprintf(line, "(%d, %s, %d)", sock, dump, sl);
} else if (type == 'r') {
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(%d)%s", sock, rest);
}
} else if (strcmp(func, "curl_easy_cleanup") == 0) {
uint64_t handle = decode64(d, &i);
sprintf(line, "(0x%lx)", handle);
} else if (strcmp(func, "curl_init") == 0) { // php
uint64_t handle = decode64(d, &i);
uint16_t len = decode16(d, &i);
if (len == 0) {
sprintf(line, "() = 0x%lx", handle);
} else {
char url[len * 4 + 1];
sf_tools_bin2hex_ascii(url, d + i, len); i += len;
sprintf(line, "('%s') = 0x%lx", url, handle);
}
} else if (strcmp(func, "curl_setopt") == 0) { // php
uint64_t handle = decode64(d, &i);
uint8_t oplen = decode8(d, &i);
char op[oplen * 4 + 1];
sf_tools_bin2hex_ascii(op, d + i, oplen); i += oplen;
char types[4096], types2[4096];
decode_types(types, sizeof(types), d, &i);
nd_trace_color(types2, sizeof(types2), types, "flags", type, tf, 0);
if (type == 'r') {
uint8_t ret = decode8(d, &i); // TODO: decode error
snprintf(rest, sizeof(rest), " = %s", ret == 1 ? "ok" : "nok");
}
sprintf(line, "(0x%lx, %s, %s)%s", handle, op, types2, rest);
} else if (strcmp(func, "curl_exec") == 0) { // php
uint64_t handle = decode64(d, &i);
if (type == 'r') {
uint8_t ret = decode8(d, &i);
if (ret == 2) {
uint16_t sret_len = decode16(d, &i);
char sret[sret_len * 4 + 1];
sf_tools_bin2hex_ascii(sret, d + i, sret_len); i += sret_len;
snprintf(rest, sizeof(rest), " = '%s'", sret);
} else if (ret == 0) {
snprintf(rest, sizeof(rest), " = nok");
} else {
snprintf(rest, sizeof(rest), " = ok");
}
}
sprintf(line, "(0x%lx)%s", handle, rest);
} else if (strcmp(func, "curl_easy_init") == 0) {
uint64_t handle = decode64(d, &i);
sprintf(line, "() = 0x%lx", handle);
} else if (strcmp(func, "curl_easy_perform") == 0) {
if (type == 'm') {
uint8_t len = decode8(d, &i);
char info[len * 4 + 1], info2[len * 4 + 1];
sf_tools_bin2hex_ascii(info, d + i, len); i += len;
nd_trace_color(info2, sizeof(info2), info, "flags", type, tf, 0);
uint64_t handle = decode64(d, &i);
uint16_t post_len = decode16(d, &i);
char post[post_len * 4 + 1];
sf_tools_bin2hex_ascii(post, d + i, post_len); i += post_len;
sprintf(line, "(0x%lx): meta: %s: %s", handle, info2, post);
} else {
uint64_t handle = decode64(d, &i);
if (type == 'r') {
int ret = decode32(d, &i);
nd_decode_curl_code(rest, sizeof(rest), ret);
char sret[sizeof(rest)];
nd_trace_color(sret, sizeof(sret), rest,
"error", type, tf, ret == 0 ? 0 : 1);
sprintf(line, "(0x%lx) = %s", handle, sret);
} else {
sprintf(line, "(0x%lx)", handle);
}
}
} else if (strcmp(func, "curl_easy_setopt") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint64_t handle = decode64(d, &i);
uint8_t type = decode8(d, &i);
uint8_t option_len = decode8(d, &i);
char option[option_len * 4 + 1], option2[option_len * 4 + 32];
sf_tools_bin2hex_ascii(option, d + i, option_len); i += option_len;
nd_trace_color(option2, sizeof(option2), option, "flags", type, tf, 0);
if ((type == 0) || (type == 2)) { // long or off_t
snprintf(rest, sizeof(rest), "%ld", decode64(d, &i));
} else if ((type == 3) || (type == 4)) { // object or string
long len = decode64(d, &i);
if (len >= 0) {
uint16_t s_len = decode16(d, &i);
char s[s_len * 4 + 1];
sf_tools_bin2hex_ascii(s, d + i, len); i += s_len;
snprintf(rest, sizeof(rest), "'%s'", s);
} else {
snprintf(rest, sizeof(rest),
"[cannot dump because size was not set yet]");
}
} else if (type == 5) { // slist
decode_string_array(rest, sizeof(rest), d, &i);
} else {
snprintf(rest, sizeof(rest), "%p", (void *) decode64(d, &i));
}
int ret = decode32(d, &i);
char sret[32], sret2[64];
nd_decode_curl_code(sret, sizeof(sret), ret);
nd_trace_color(sret2, sizeof(sret2), sret,
"error", type, tf, ret == 0 ? 0 : 1);
sprintf(line, "(0x%lx, %s, %s) = %s",
handle, option2, rest, sret2);
} break;
case 'd':
if (strcmp(func, "dlopen") == 0) {
char filename[512];
decode_filename(filename, d, &i);
char flags[128];
decode_dlopen_flags(flags, sizeof(flags), d, &i);
if (type == 'r')
decode_ret_pointer_errno(rest, sizeof(rest), d, &i);
sprintf(line, "('%s', '%s')%s", filename, flags, rest);
} else if (strcmp(func, "dlclose") == 0) {
void *h = (void *) decode64(d, &i);
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(%p)%s", h, rest);
} break;
case 'e':
if (strcmp(func, "execve") == 0) {
char argv[4096], envp[4096];
char pathname[512];
decode_filename(pathname, d, &i);
decode_string_array(argv, sizeof(argv), d, &i);
decode_string_array(envp, sizeof(envp), d, &i);
if (type == 'r')
decode_ret_pointer_errno(rest, sizeof(rest), d, &i);
sprintf(line, "('%s', %s, %s)%s",
pathname, argv, envp, rest);
// special action here. We need to switch to the new pid
// TODO: close previous one?
if (no_pids < 256) {
pids[no_pids] = pid;
no_pids++;
}
} break;
case 'f':
if (strcmp(func, "fork") == 0) {
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "()%s", rest);
} else if ((strcmp(func, "fstatat") == 0)
|| (strcmp(func, "fstat64") == 0)) {
char dirfd[32], sstat[512];
decode_dirfd(dirfd, sizeof(dirfd), d, &i, "");
char pathname[512];
decode_filename(pathname, d, &i);
decode_stat(sstat, sizeof(sstat), d, &i);
int flags = decode32(d, &i);
if (type == 'r')
decode_ret_pointer_errno(rest, sizeof(rest), d, &i);
sprintf(line, "(%s, '%s', {%s}, 0x%x)%s",
dirfd, pathname, sstat, flags, rest);
} else if ((strcmp(func, "fsync") == 0)
|| (strcmp(func, "fdatasync") == 0)) {
int fd = decode32(d, &i);
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(%d)%s", fd, rest);
} else if (strcmp(func, "ftruncate") == 0) {
int fd = decode32(d, &i);
uint64_t len = decode64(d, &i);
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(fd=%d, len=%lu)%s", fd, len, rest);
} break;
case 'g':
if (strcmp(func, "getaddrinfo") == 0) {
uint16_t len;
char node[256];
char service[256];
len = decode16(d, &i);
if (len == 0xFFFF) {
sprintf(node, "NULL");
} else {
memcpy(node, d + i, len); i += len;
node[len] = '\0';
}
len = decode16(d, &i);
if (len == 0xFFFF) {
sprintf(service, "NULL");
} else {
memcpy(service, d + i, len); i += len;
service[0] = '\0';
}
if (type == 'r') {
int ret = decode32(d, &i);
sprintf(rest, " = %d%s%s%s",
ret, ret > 0 ? " (" : "",
ret > 0 ? gai_strerror(ret) : "",
ret > 0 ? ")" : "");
}
sprintf(line, "('%s', '%s')%s",
node, service, rest);
} else if (strcmp(func, "gethostbyname") == 0) {
uint16_t len = decode16(d, &i);
char host[len * 4 + 1];
sf_tools_bin2hex_ascii(host, d + i, len); i += len;
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "('%s')%s", host, rest);
} else if (strcmp(func, "gethostbyname_r") == 0) {
uint16_t len = decode16(d, &i);
char host[len * 4 + 1];
sf_tools_bin2hex_ascii(host, d + i, len); i += len;
if (type == 'r') {
int ret = decode32(d, &i);
if (ret == -1)
decode_h_errno(rest, sizeof(rest), d, &i);
else
decode_hostent(rest, sizeof(rest), d, &i);
}
sprintf(line, "('%s')%s", host, rest);
} else if (strcmp(func, "getrandom") == 0) {
size_t buflen = decode64(d, &i);
unsigned int flags = decode32(d, &i);
if (type == 'c') {
sprintf(line, "(buf, %zu, 0x%x)", buflen, flags);
} else {
ssize_t ret = decode_ret_int64(rest, sizeof(rest), d, &i);
if (ret != -1) {
unsigned short max = decode16(d, &i);
char dump[max * 2 + 1];
sf_tools_bin2hex(dump, d + i, max); i += max;
sprintf(line, "('%s'%s, %zu, 0x%x)%s",
dump, max < buflen ? "..." : "",
buflen, flags, rest);
} else {
sprintf(line, "(buf, %zu, 0x%x)%s",
buflen, flags, rest);
}
}
} else if (strcmp(func, "getsockopt") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
int sock = decode32(d, &i);
char level[32], optname[32];
int ilevel = decode_sock_level(level, sizeof(level), d, &i);
decode_sock_optname(optname, sizeof(optname), ilevel, d, &i);
socklen_t optlen = decode32(d, &i);
char optval[optlen * 2 + 1];
sf_tools_bin2hex(optval, d + i, optlen); i+= optlen;
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(%d, %s, %s, 0x%s, %u)%s",
sock, level, optname, optval, optlen, rest);
} break;
case 'i':
if ((strcmp(func, "imagecreate") == 0)
|| (strcmp(func, "imagecreatetruecolor") == 0)) {
uint64_t w = decode64(d, &i);
uint64_t h = decode64(d, &i);
decode_ret_pointer(rest, sizeof(rest), d, &i);
sprintf(line, "(w=%lu, h=%lu)%s", w, h, rest);
} else if (strcmp(func, "imagedestroy") == 0) {
uint64_t im = decode64(d, &i);
uint64_t elap_us = decode64(d, &i);
decode_bool("", rest, sizeof(rest), d, &i);
char elap[64], elap2[64];
snprintf(elap, sizeof(elap), "[image generation time: %luus]", elap_us);
nd_trace_color(elap2, sizeof(elap2), elap, "ts", type, tf, elap_us / 1000);
sprintf(line, "(0x%lx) = %s %s", im, rest, elap2);
}
break;
case 'j':
if (strcmp(func, "java/db/connect") == 0) {
char db_type = decode8(d, &i);
uint16_t cs_len = decode16(d, &i);
char cs[cs_len * 4 + 1];
sf_tools_bin2hex_ascii(cs, d + i, cs_len); i += cs_len;
if (type == 'r') {
uint64_t dbh = decode64(d, &i);
if (dbh != 0) {
snprintf(rest, sizeof(rest), " = 0x%lx", dbh);
} else {
uint16_t ex_len = decode16(d, &i);
char ex[ex_len * 4 + 1];
sf_tools_bin2hex_ascii(ex, d + i, ex_len); i += ex_len;
snprintf(rest, sizeof(rest), " = nok [%s]", ex);
}
}
sprintf(line, "/%c('%s')%s", db_type, cs, rest);
} else if (strcmp(func, "java/db/close") == 0) {
char db_type = decode8(d, &i);
uint64_t dbh = decode64(d, &i);
sprintf(line, "/%c(0x%lx) = ok", db_type, dbh);
} else if ((strcmp(func, "java/db/prepared/execute") == 0)
|| (strcmp(func, "java/db/stmt/execute") == 0)) {
char db_type = decode8(d, &i);
uint64_t stmt = decode64(d, &i);
if (type == 'r') {
uint64_t res = decode64(d, &i);
if (res != 0) {
snprintf(rest, sizeof(rest), " = ok");
} else {
uint16_t ex_len = decode16(d, &i);
char ex[ex_len * 4 + 1];
sf_tools_bin2hex_ascii(ex, d + i, ex_len); i += ex_len;
snprintf(rest, sizeof(rest), " = nok [%s]", ex);
}
}
sprintf(line, "/%c(0x%lx)%s", db_type, stmt, rest);
} else if (strcmp(func, "java/db/prepare") == 0) {
char db_type = decode8(d, &i);
uint64_t dbh = decode64(d, &i);
uint16_t q_len = decode16(d, &i);
char q[q_len * 4 + 1];
sf_tools_bin2hex_ascii(q, d + i, q_len); i += q_len;
if (type == 'r') {
uint64_t stmt = decode64(d, &i);
if (stmt != 0) {
snprintf(rest, sizeof(rest), " = 0x%lx", stmt);
} else {
uint16_t ex_len = decode16(d, &i);
char ex[ex_len * 4 + 1];
sf_tools_bin2hex_ascii(ex, d + i, ex_len); i += ex_len;
snprintf(rest, sizeof(rest), " = nok [%s]", ex);
}
}
sprintf(line, "/%c(0x%lx, '%s')%s", db_type, dbh, q, rest);
} else if (strcmp(func, "java/db/stmt/create") == 0) {
char db_type = decode8(d, &i);
uint64_t dbh = decode64(d, &i);
uint64_t stmt = decode64(d, &i);
if (stmt != 0) {
snprintf(rest, sizeof(rest), " = 0x%lx", stmt);
} else {
uint16_t ex_len = decode16(d, &i);
char ex[ex_len * 4 + 1];
sf_tools_bin2hex_ascii(ex, d + i, ex_len); i += ex_len;
snprintf(rest, sizeof(rest), " = nok [%s]", ex);
}
sprintf(line, "/%c(0x%lx)%s", db_type, dbh, rest);
} else if (strcmp(func, "java/db/stmt/close") == 0) {
char db_type = decode8(d, &i);
uint64_t stmt = decode64(d, &i);
sprintf(line, "/%c(0x%lx) = ok", db_type, stmt);
} else if (strcmp(func, "java/db/stmt/execute/sql") == 0) {
char db_type = decode8(d, &i);
uint64_t stmt = decode64(d, &i);
uint16_t q_len = decode16(d, &i);
char q[q_len * 4 + 1];
sf_tools_bin2hex_ascii(q, d + i, q_len); i += q_len;
if (type == 'r') {
uint64_t res = decode64(d, &i);
if (res != 0) {
snprintf(rest, sizeof(rest), " = 0x%lx", res);
} else {
uint16_t ex_len = decode16(d, &i);
char ex[ex_len * 4 + 1];
sf_tools_bin2hex_ascii(ex, d + i, ex_len); i += ex_len;
snprintf(rest, sizeof(rest), " = nok [%s]", ex);
}
}
sprintf(line, "/%c(0x%lx, '%s')%s", db_type, stmt, q, rest);
} else if (strcmp(func, "java/db/result/get") == 0) {
char db_type = decode8(d, &i);
uint64_t stmt = decode64(d, &i);
if (type == 'r') {
uint64_t res = decode64(d, &i);
if (res != 0) {
snprintf(rest, sizeof(rest), " = 0x%lx", res);
} else {
uint16_t ex_len = decode16(d, &i);
char ex[ex_len * 4 + 1];
sf_tools_bin2hex_ascii(ex, d + i, ex_len); i += ex_len;
snprintf(rest, sizeof(rest), " = nok [%s]", ex);
}
}
sprintf(line, "/%c(0x%lx)%s", db_type, stmt, rest);
} else if (strcmp(func, "java/db/stmt/setInt") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
char db_type = decode8(d, &i);
uint64_t stmt = decode64(d, &i);
uint8_t index = decode8(d, &i);
int32_t value = decode32(d, &i);
uint64_t res = decode64(d, &i);
if (res != 0) {
snprintf(rest, sizeof(rest), " = ok");
} else {
uint16_t ex_len = decode16(d, &i);
char ex[ex_len * 4 + 1];
sf_tools_bin2hex_ascii(ex, d + i, ex_len); i += ex_len;
snprintf(rest, sizeof(rest), " = nok [%s]", ex);
}
sprintf(line, "/%c(0x%lx, %hhu, %d)%s",
db_type, stmt, index, value, rest);
} else if (strcmp(func, "java/db/stmt/setString") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
char db_type = decode8(d, &i);
uint64_t stmt = decode64(d, &i);
uint8_t index = decode8(d, &i);
uint16_t vlen = decode16(d, &i);
char value[vlen * 4 + 1];
sf_tools_bin2hex_ascii(value, d + i, vlen); i += vlen;
uint64_t res = decode64(d, &i);
if (res != 0) {
snprintf(rest, sizeof(rest), " = ok");
} else {
uint16_t ex_len = decode16(d, &i);
char ex[ex_len * 4 + 1];
sf_tools_bin2hex_ascii(ex, d + i, ex_len); i += ex_len;
snprintf(rest, sizeof(rest), " = nok [%s]", ex);
}
sprintf(line, "/%c(0x%lx, %hhu, '%s')%s",
db_type, stmt, index, value, rest);
} break;
case 'l':
if (strcmp(func, "link") == 0) {
char oldpath[512], newpath[512];
decode_filename(oldpath, d, &i);
decode_filename(newpath, d, &i);
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "('%s', '%s')%s", oldpath, newpath, rest);
} else if (strcmp(func, "listen") == 0) {
int sock = decode32(d, &i);
int backlog = decode32(d, &i);
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(%d, %d)%s", sock, backlog, rest);
} else if (strcmp(func, "lseek") == 0) {
int fd = decode32(d, &i);
int64_t off = decode64(d, &i);
char whence[32];
decode_whence(whence, sizeof(whence), d, &i);
if (type == 'r')
decode_ret_int64(rest, sizeof(rest), d, &i);
sprintf(line, "(%d, %zd, %s)%s", fd, off, whence, rest);
} break;
case 'm':
if (strcmp(func, "memfd_create") == 0) {
char name[512];
decode_filename(name, d, &i);
uint32_t flags = decode32(d, &i);
char sflags[64];
nd_decode_memfd_flags(sflags, sizeof(sflags), flags);
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "('%s', %s)%s", name, sflags, rest);
} else if (strcmp(func, "mysqli_autocommit") == 0) {
uint64_t link = decode64(d, &i);
uint8_t value = decode8(d, &i);
if (type == 'r')
decode_bool(" = ", rest, sizeof(rest), d, &i);
sprintf(line, "(link=0x%lx, %s)%s",
link, value == 0 ? "false" : "true", rest);
} else if (strcmp(func, "mysqli_close") == 0) {
uint64_t link = decode64(d, &i);
if (type == 'r')
decode_bool(" = ", rest, sizeof(rest), d, &i);
sprintf(line, "(link=0x%lx)%s", link, rest);
} else if (strcmp(func, "mysqli_connect") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint32_t cs_len = decode32(d, &i);
char cs[cs_len * 4 + 1];
sf_tools_bin2hex_ascii(cs, d + i, cs_len); i += cs_len;
if (type == 'r')
decode_bool(" = ", rest, sizeof(rest), d, &i);
sprintf(line, "('%s')%s", cs, rest);
} else if (strcmp(func, "mysqli_fetch_all") == 0) {
uint64_t res = decode64(d, &i);
char mode[64];
decode_mysqli_mode(mode, sizeof(mode), d ,&i);
if (type == 'r')
snprintf(rest, sizeof(rest), " [%lu row(s)]", decode64(d, &i));
sprintf(line, "(0x%lx, %s)%s", res, mode, rest);
} else if (strcmp(func, "mysqli_fetch_array") == 0) {
uint64_t res = decode64(d, &i);
char mode[64];
decode_mysqli_mode(mode, sizeof(mode), d ,&i);
if (type == 'r') {
uint8_t ret = decode8(d, &i);
if (ret == 0)
snprintf(rest, sizeof(rest), " = no row");
else if (ret == 1)
snprintf(rest, sizeof(rest), " = nok");
else if (ret == 2)
snprintf(rest, sizeof(rest), " = ok");
}
sprintf(line, "(0x%lx, %s)%s", res, mode, rest);
} else if (strcmp(func, "mysqli_free_result") == 0) {
uint64_t res = decode64(d, &i);
sprintf(line, "(0x%lx)", res);
} else if (strcmp(func, "mysqli_prepare") == 0) {
uint64_t link = decode64(d, &i);
uint16_t q_len = decode16(d, &i);
char q[q_len * 4 + 1];
sf_tools_bin2hex_ascii(q, d + i, q_len); i += q_len;
if (type == 'r') {
uint64_t stmt = decode64(d, &i);
snprintf(rest, sizeof(rest), " = 0x%lx", stmt);
}
sprintf(line, "(link=0x%lx, '%s')%s", link, q, rest);
} else if (strcmp(func, "mysqli_query") == 0) {
uint64_t link = decode64(d, &i);
uint16_t q_len = decode16(d, &i);
char q[q_len * 4 + 1];
sf_tools_bin2hex_ascii(q, d + i, q_len); i += q_len;
if (type == 'r') {
uint64_t res = decode64(d, &i);
uint64_t rows = decode64(d, &i);
uint64_t aff = decode64(d, &i);
if (res == 0)
snprintf(rest, sizeof(rest), " = nok");
else if (res == 1)
snprintf(rest, sizeof(rest), " = ok [%lu rows, %ld aff]",
rows, aff);
else
snprintf(rest, sizeof(rest),
" = 0x%lx [%lu rows, %ld aff]",
res, rows, aff);
}
sprintf(line, "(link=0x%lx, '%s')%s", link, q, rest);
} else if (strcmp(func, "mysqli_real_connect") == 0) {
uint64_t link = decode64(d, &i);
uint32_t cs_len = decode32(d, &i);
char cs[cs_len * 4 + 1];
sf_tools_bin2hex_ascii(cs, d + i, cs_len); i += cs_len;
char flags[512];
decode_mysql_real_connect_flags(flags, sizeof(flags), d, &i);
if (type == 'r')
decode_bool(" = ", rest, sizeof(rest), d, &i);
sprintf(line, "(link=0x%lx, '%s', flags=%s)%s", link, cs, flags, rest);
} else if (strcmp(func, "mysqli_stmt_bind_param") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint64_t stmt = decode64(d, &i);
unsigned short types_len = decode16(d, &i);
char types[types_len * 4 + 1];
sf_tools_bin2hex_ascii(types, d + i, types_len); i += types_len;
if (type == 'r')
decode_bool(" = ", rest, sizeof(rest), d, &i);
sprintf(line, "(stmt=0x%lx, types='%s', ...)%s",
stmt, types, rest);
} else if (strcmp(func, "mysqli_stmt_bind_result") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint64_t stmt = decode64(d, &i);
if (type == 'r')
decode_bool(" = ", rest, sizeof(rest), d, &i);
sprintf(line, "(stmt=0x%lx, ...)%s", stmt, rest);
} else if (strcmp(func, "mysqli_stmt_close") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint64_t stmt = decode64(d, &i);
if (type == 'r') {
uint8_t ret = decode8(d, &i);
snprintf(rest, sizeof(rest), " = %s", ret == 1 ? "ok" : "nok");
}
sprintf(line, "(stmt=0x%lx)%s", stmt, rest);
} else if ((strcmp(func, "mysqli_stmt_execute") == 0)
|| (strcmp(func, "mysqli_execute") == 0)) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint64_t stmt = decode64(d, &i);
if (type == 'm') {
nothing_to_log = 1;
unsigned char bind_way = decode8(d, &i);
decode_query_params(rest, sizeof(rest), bind_way, d, &i);
if (bind_way == ND_PARAMS_BIND_WAY_IN) {
uint16_t q_len = decode16(d, &i);
char q[q_len * 4 + 1];
sf_tools_bin2hex_ascii(q, d + i, q_len); i += q_len;
sprintf(line, "(stmt=0x%lx): meta: sql: %s", stmt, q);
if (strcmp(rest, " {}") != 0)
sprintf(line2, "(stmt=0x%lx): meta: binds:%s", stmt, rest);
} else {
if (strcmp(rest, " {}") != 0)
sprintf(line, "(stmt=0x%lx): meta: binds:%s", stmt, rest);
}
} else {
if (type == 'c') {
decode_query_params(rest, sizeof(rest),
ND_PARAMS_BIND_WAY_IN, d, &i);
sprintf(line, "(stmt=0x%lx%s%s)",
stmt, rest[0] ? "," : "", rest);
} else if (type == 'r') {
uint8_t ret = decode8(d, &i);
if (ret == 1) {
uint64_t rows = decode64(d, &i);
uint64_t aff = decode64(d, &i);
snprintf(rest, sizeof(rest),
" = ok [%lu rows, %ld aff]", rows, aff);
} else {
snprintf(rest, sizeof(rest), " = nok");
}
sprintf(line, "(stmt=0x%lx)%s", stmt, rest);
}
}
} else if (strcmp(func, "mysqli_stmt_fetch") == 0) {
uint64_t stmt = decode64(d, &i);
if (type == 'm') {
nothing_to_log = 1;
uint8_t bind_way = decode8(d, &i);
decode_query_params(rest, sizeof(rest), bind_way, d, &i);
if (strcmp(rest, " {}") != 0)
sprintf(line, "(stmt=0x%lx): meta: binds:%s", stmt, rest);
} else {
if (type == 'r') {
uint8_t ret = decode8(d, &i);
if (ret == 0)
snprintf(rest, sizeof(rest), " = nok");
else if (ret == 1)
snprintf(rest, sizeof(rest), " = ok");
else
snprintf(rest, sizeof(rest), " = ok [no more rows available]");
}
sprintf(line, "(stmt=0x%lx)%s", stmt, rest);
}
} else if (strcmp(func, "mysqli_stmt_init") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint64_t dbh = decode64(d, &i);
if (type == 'r') {
uint64_t stmt = decode64(d, &i);
snprintf(rest, sizeof(rest), " = 0x%lx", stmt);
}
sprintf(line, "(dbh=0x%lx)%s", dbh, rest);
} else if (strcmp(func, "mysqli_stmt_prepare") == 0) {
uint64_t stmt = decode64(d, &i);
uint16_t q_len = decode16(d, &i);
char q[q_len * 4 + 1];
sf_tools_bin2hex_ascii(q, d + i, q_len); i += q_len;
if (type == 'r')
decode_bool(" = ", rest, sizeof(rest), d, &i);
sprintf(line, "(stmt=0x%lx, '%s')%s", stmt, q, rest);
} else if (strcmp(func, "mount") == 0) {
char source[512], target[512];
decode_filename(source, d, &i);
decode_filename(target, d, &i);
uint8_t len = decode16(d, &i);
char fstype[len * 4 + 1];
sf_tools_bin2hex_ascii(fstype, d + i, len); i += len;
long flags = decode64(d, &i);
char sflags[128];
nd_decode_mount_flags(sflags, sizeof(sflags), flags);
len = decode16(d, &i);
char data[len * 4 + 1];
sf_tools_bin2hex_ascii(data, d + i, len); i += len;
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "('%s', '%s', '%s', %s, '%s')%s",
source, target, fstype, sflags, data, rest);
} break;
case 'n':
if (strcmp(func, "nanosleep") == 0) {
struct timespec req;
req.tv_sec = decode64(d, &i);
req.tv_nsec = decode64(d, &i);
if (type == 'c') {
sprintf(line, "(%lu.%09ld)",
req.tv_sec, req.tv_nsec);
} else {
struct timespec rem;
rem.tv_sec = decode64(d, &i);
rem.tv_nsec = decode64(d, &i);
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(%lu.%09ld, %lu.%09ld)%s",
req.tv_sec, req.tv_nsec, rem.tv_sec, rem.tv_nsec, rest);
}
} else if (strcmp(func, "nice") == 0) {
int inc = decode32(d, &i);
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(inc=%d)%s", inc, rest);
} break;
case 'o':
if (strcmp(func, "oci_bind_by_name") == 0) {
uint64_t stmt = decode64(d, &i);
sprintf(line, "(stmt=0x%lx)", stmt);
} else if (strcmp(func, "oci_close") == 0) {
uint64_t h = decode64(d, &i);
sprintf(line, "(0x%lx)", h);
} else if (strcmp(func, "oci_execute") == 0) {
uint64_t stmt = decode64(d, &i);
uint64_t mode = decode64(d, &i);
if (type == 'r') {
uint8_t ret = decode8(d, &i);
if (ret == 1)
snprintf(rest, sizeof(rest), " = ok");
else
snprintf(rest, sizeof(rest), " = nok");
}
char s_mode[128];
nd_decode_oci_execute_mode(s_mode, sizeof(s_mode), mode);
sprintf(line, "(stmt=0x%lx, %s)%s", stmt, s_mode, rest);
} else if (strcmp(func, "oci_parse") == 0) {
uint64_t dbh = decode64(d, &i);
uint16_t q_len = decode16(d, &i);
char q[q_len * 4 + 1];
sf_tools_bin2hex_ascii(q, d + i, q_len); i += q_len;
if (type == 'r') {
uint64_t stmt = decode64(d, &i);
snprintf(rest, sizeof(rest), " = 0x%lx", stmt);
}
sprintf(line, "(dbh=0x%lx, '%s')%s", dbh, q, rest);
} else if (strcmp(func, "oci_pconnect") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint32_t cs_len = decode32(d, &i);
char cs[cs_len * 4 + 1];
sf_tools_bin2hex_ascii(cs, d + i, cs_len); i += cs_len;
if (type == 'r') {
uint64_t h = decode64(d, &i);
snprintf(rest, sizeof(rest), " = 0x%lx", h);
}
sprintf(line, "('%s')%s", cs, rest);
} else if ((strcmp(func, "open") == 0)
|| (strcmp(func, "open64") == 0)
|| (strcmp(func, "openat") == 0)) {
char dirfd[32];
if (strcmp(func, "openat") == 0)
decode_dirfd(dirfd, sizeof(dirfd), d, &i, " ,");
else
dirfd[0] = '\0';
char pathname[512];
decode_filename(pathname, d, &i);
int flags = decode32(d, &i);
mode_t mode = decode32(d, &i);
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(%s'%s', 0x%x, 0x%x)%s",
dirfd, pathname, flags, mode, rest);
} else if (strcmp(func, "opendir") == 0) {
char name[512];
decode_filename(name, d, &i);
if (type == 'r')
decode_ret_pointer(rest, sizeof(rest), d, &i);
sprintf(line, "('%s')%s", name, rest);
} break;
case 'O':
if (strcmp(func, "OCIAttrSet") == 0) {
uint64_t h = decode64(d, &i);
uint32_t htype = decode32(d, &i);
unsigned int attr_size = decode32(d, &i);
char attr[attr_size * 4 + 1];
sf_tools_bin2hex_ascii(attr, d + i, attr_size); i += attr_size;
unsigned int attr_type = decode32(d, &i);
uint64_t err = decode64(d, &i);
char s_htype[32];
nd_decode_oci_handle_alloc_type(s_htype, sizeof(s_htype), htype);
char s_attr_type[32];
nd_decode_oci_attr_type(s_attr_type, sizeof(s_attr_type), attr_type);
int32_t ret = decode32(d, &i);
sprintf(line, "(h=0x%lx, htype=%s, attr='%s'"
", attr_type=%s, err=0x%lx) = %d",
h, s_htype, attr, s_attr_type, err, ret);
} else if (strcmp(func, "OCIBindByName") == 0) {
uint64_t stmt = decode64(d, &i);
uint64_t bind = decode64(d, &i);
uint64_t oci_error = decode64(d, &i);
unsigned int ph_len = decode32(d, &i);
char ph[ph_len * 4 + 1];
sf_tools_bin2hex_ascii(ph, d + i, ph_len); i += ph_len;
int value_size = decode32(d, &i);
uint16_t dty = decode16(d, &i);
uint64_t ind = decode64(d, &i);
uint64_t alen = decode64(d, &i);
uint64_t rcode = decode64(d, &i);
uint32_t maxarr_len = decode32(d, &i);
uint64_t curelep = decode64(d, &i);
uint32_t mode = decode32(d, &i);
int32_t ret = decode32(d, &i);
char s_dty[32], /*s_ind[32],*/ s_mode[128], s_ret[32];
nd_decode_oci_dty(s_dty, sizeof(s_dty), dty);
//nd_decode_oci_ind(s_ind, sizeof(s_ind), ind);
nd_decode_oci_bind_mode(s_mode, sizeof(s_mode), mode);
nd_decode_oci_ret(s_ret, sizeof(s_ret), ret);
sprintf(line, "(0x%lx, 0x%lx, 0x%lx, '%s', value, value_size=%d"
", dty=%s, ind=0x%lx, alen=0x%lx, rcode=0x%lx, %u, curelep=0x%lx, mode=%s) = %s",
stmt, bind, oci_error, ph, value_size,
s_dty, ind, alen, rcode, maxarr_len, curelep, s_mode, s_ret);
} else if (strcmp(func, "OCIDefineByPos") == 0) {
uint64_t stmt = decode64(d, &i);
uint64_t def = decode64(d, &i);
uint64_t oci_error = decode64(d, &i);
uint32_t pos = decode32(d, &i);
int value_size = decode32(d, &i);
uint16_t dty = decode16(d, &i);
uint64_t ind = decode64(d, &i);
uint64_t rlen = decode64(d, &i);
uint64_t rcode = decode64(d, &i);
uint32_t mode = decode32(d, &i);
int32_t ret = decode32(d, &i);
char s_dty[32], /*s_ind[32],*/ s_mode[128], s_ret[32];
nd_decode_oci_dty(s_dty, sizeof(s_dty), dty);
//nd_decode_oci_ind(s_ind, sizeof(s_ind), ind);
nd_decode_oci_bind_mode(s_mode, sizeof(s_mode), mode);
nd_decode_oci_ret(s_ret, sizeof(s_ret), ret);
sprintf(line, "(0x%lx, 0x%lx, 0x%lx, pos=%u, value, value_size=%d"
", %s, ind=0x%lx, rlen=0x%lx, rcode=0x%lx, mode=%s) = %s",
stmt, def, oci_error, pos, value_size,
s_dty, ind, rlen, rcode, s_mode, s_ret);
} else if (strcmp(func, "OCIHandleAlloc") == 0) {
uint64_t parent = decode64(d, &i);
uint64_t dbh = decode64(d, &i);
uint32_t type = decode32(d, &i);
size_t extra_mem = decode64(d, &i);
uint64_t user_mem = decode64(d, &i);
char s_type[32];
nd_decode_oci_handle_alloc_type(s_type, sizeof(s_type), type);
sprintf(line, "(0x%lx, 0x%lx, %s, %zu, 0x%lx)",
parent, dbh, s_type, extra_mem, user_mem);
} else if (strcmp(func, "OCIHandleFree") == 0) {
uint64_t hnd = decode64(d, &i);
uint32_t type = decode32(d, &i);
char s_type[32];
nd_decode_oci_handle_alloc_type(s_type, sizeof(s_type), type);
sprintf(line, "(0x%lx, %s)", hnd, s_type);
} else if (strcmp(func, "OCIServerAttach") == 0) {
uint64_t oci_server = decode64(d, &i);
uint64_t oci_error = decode64(d, &i);
int32_t db_link_len = decode32(d, &i), a;
a = db_link_len < 0 ? 0 : db_link_len;
char db_link[a * 4 + 1];
sf_tools_bin2hex_ascii(db_link, d + i, a); i += a;
uint32_t mode = decode32(d, &i);
if (type == 'r')
snprintf(rest, sizeof(rest), " = %d", decode32(d, &i));
char s_mode[128];
nd_decode_oci_mode(s_mode, sizeof(s_mode), mode);
sprintf(line, "(0x%lx, 0x%lx, '%s', %d, mode=%s)%s",
oci_server, oci_error, db_link, db_link_len, s_mode, rest);
} else if (strcmp(func, "OCIServerDetach") == 0) {
uint64_t oci_server = decode64(d, &i);
uint64_t oci_error = decode64(d, &i);
uint32_t mode = decode32(d, &i);
if (type == 'r')
snprintf(rest, sizeof(rest), " = %d", decode32(d, &i));
char s_mode[128];
nd_decode_oci_mode(s_mode, sizeof(s_mode), mode);
sprintf(line, "(0x%lx, 0x%lx, mode=%s)%s",
oci_server, oci_error, s_mode, rest);
} else if (strcmp(func, "OCIStmtExecute") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
if (type == 'm') {
nothing_to_log = 1;
uint64_t stmt = decode64(d, &i);
unsigned char bind_way = decode8(d, &i);
decode_query_params(rest, sizeof(rest), bind_way, d, &i);
if (bind_way == ND_PARAMS_BIND_WAY_IN) {
uint16_t q_len = decode16(d, &i);
char q[q_len * 4 + 1];
sf_tools_bin2hex_ascii(q, d + i, q_len); i += q_len;
sprintf(line, "(stmt=0x%lx): meta: sql: %s", stmt, q);
if (strcmp(rest, " {}") != 0)
sprintf(line2, "(stmt=0x%lx): meta: binds:%s", stmt, rest);
} else {
if (strcmp(rest, " {}") != 0)
sprintf(line, "(stmt=0x%lx): meta: binds:%s", stmt, rest);
}
} else {
uint64_t svc = decode64(d, &i);
uint64_t stmt = decode64(d, &i);
uint64_t err = decode64(d, &i);
uint32_t iters = decode32(d, &i);
uint32_t rowoff = decode32(d, &i);
uint64_t snap_in = decode64(d, &i);
uint64_t snap_out = decode64(d, &i);
uint32_t mode = decode32(d, &i);
if (type == 'r') {
int ret = decode32(d, &i);
char s_ret[32];
nd_decode_oci_ret(s_ret, sizeof(s_ret), ret);
snprintf(rest, sizeof(rest), " = %s", s_ret);
}
char s_mode[128];
nd_decode_oci_execute_mode(s_mode, sizeof(s_mode), mode);
sprintf(line, "(0x%lx, 0x%lx, 0x%lx iters=%u rowoff=%u, 0x%lx, 0x%lx, %s)%s",
svc, stmt, err, iters, rowoff, snap_in, snap_out, s_mode, rest);
}
} else if (strcmp(func, "OCIStmtPrepare") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint64_t stmt = decode64(d, &i);
uint64_t oci_error = decode64(d, &i);
uint16_t q_len = decode16(d, &i);
char q[q_len * 4 + 1];
sf_tools_bin2hex_ascii(q, d + i, q_len); i += q_len;
uint32_t lang = decode32(d, &i);
uint32_t mode = decode32(d, &i);
int32_t ret = decode32(d, &i);
char s_lang[32], s_mode[128];
nd_decode_oci_lang(s_lang, sizeof(s_lang), lang);
nd_decode_oci_mode(s_mode, sizeof(s_mode), mode);
sprintf(line, "(0x%lx, 0x%lx, '%s', %s, mode=%s) = %d",
stmt, oci_error, q, s_lang, s_mode, ret);
} else if (strcmp(func, "OCITransCommit") == 0) {
uint64_t svc = decode64(d, &i);
uint64_t oci_error = decode64(d, &i);
uint32_t flags = decode32(d, &i);
if (type == 'r') {
int ret = decode32(d, &i);
char s_ret[32];
nd_decode_oci_ret(s_ret, sizeof(s_ret), ret);
snprintf(rest, sizeof(rest), " = %s", s_ret);
}
char s_flags[128];
nd_decode_oci_trans_commit_flags(s_flags, sizeof(s_flags), flags);
sprintf(line, "(0x%lx, 0x%lx, %s)%s",
svc, oci_error, s_flags, rest);
} else if (strcmp(func, "OCITransRollback") == 0) {
uint64_t svc = decode64(d, &i);
uint64_t oci_error = decode64(d, &i);
uint32_t flags = decode32(d, &i);
if (type == 'r') {
int ret = decode32(d, &i);
char s_ret[32];
nd_decode_oci_ret(s_ret, sizeof(s_ret), ret);
snprintf(rest, sizeof(rest), " = %s", s_ret);
}
char s_flags[128];
nd_decode_oci_trans_rollback_flags(s_flags, sizeof(s_flags), flags);
sprintf(line, "(0x%lx, 0x%lx, %s)%s",
svc, oci_error, s_flags, rest);
} else if (strcmp(func, "OCITransStart") == 0) {
uint64_t svc = decode64(d, &i);
uint64_t oci_error = decode64(d, &i);
uint32_t timeout = decode32(d, &i);
uint32_t flags = decode32(d, &i);
int ret = decode32(d, &i);
char s_flags[128], s_ret[32];
nd_decode_oci_trans_start_flags(s_flags, sizeof(s_flags), flags);
nd_decode_oci_ret(s_ret, sizeof(s_ret), ret);
sprintf(line, "(0x%lx, 0x%lx, %us, %s) = %s",
svc, oci_error, timeout, s_flags, s_ret);
} break;
case 'p':
if (strcmp(func, "poll") == 0) {
uint16_t nf = decode32(d, &i);
char list[nf * 16 + 1], *add = "";
list[0] = '\0';
for (unsigned j = 0; j < nf; j++) {
int fd = decode32(d, &i);
short ev = decode16(d, &i);
char tmp[16 + 1];
snprintf(tmp, sizeof(tmp),
"%s%d%s%s%s", add, fd,
ev ? "/" : "",
ev & POLLIN ? "i" : "",
ev & POLLOUT ? "o" : "");
strcat(list, tmp);
add = ",";
}
int timeout = decode32(d, &i);
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "([%s], %u, %d)%s",
list, nf, timeout, rest);
} else if ((strcmp(func, "pread") == 0)
|| (strcmp(func, "pread64") == 0)) {
int fd = decode32(d, &i);
size_t count = decode64(d, &i);
off_t offset = decode64(d, &i);
if (type == 'c') {
sprintf(line, "(%d, buf, %zu, off=%zu)", fd, count, offset);
} else {
ssize_t ret = decode_ret_int64(rest, sizeof(rest), d, &i);
if (ret > 0) {
unsigned short max = decode16(d, &i);
char data[max * 4 + 1];
sf_tools_bin2hex_ascii(data, d + i, max); i += max;
sprintf(line, "(%d, '%s'%s, %zu, off=%zu)%s",
fd, data,
max < ret ? "..." : "", count, offset, rest);
} else {
sprintf(line, "(%d, buf, %zu, off=%zu)%s",
fd, count, offset, rest);
}
}
} else if ((strcmp(func, "pwrite") == 0)
|| (strcmp(func, "pwrite64") == 0)) {
int fd = decode32(d, &i);
size_t count = decode64(d, &i);
off_t offset = decode64(d, &i);
if (type == 'c') {
unsigned short max = decode16(d, &i);
char data[max * 4 + 1];
sf_tools_bin2hex_ascii(data, d + i, max); i += max;
sprintf(line, "(%d, '%s'%s, %zu, off=%zu)",
fd, data,
max < count ? "..." : "", count, offset);
} else {
decode_ret_int64(rest, sizeof(rest), d, &i);
sprintf(line, "(%d, buf, %zu, off=%zu)%s",
fd, count, offset, rest);
}
} else if (strcmp(func, "pg_close") == 0) {
uint64_t h = decode64(d, &i);
if (h == 0)
sprintf(line, "()");
else
sprintf(line, "(0x%lx)", h);
} else if ((strcmp(func, "pg_connect") == 0)
|| (strcmp(func, "pg_pconnect") == 0)) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint32_t cs_len = decode32(d, &i);
char cs[cs_len * 4 + 1];
sf_tools_bin2hex_ascii(cs, d + i, cs_len); i += cs_len;
if (type == 'r') {
uint64_t h = decode64(d, &i);
snprintf(rest, sizeof(rest), " = 0x%lx", h);
}
sprintf(line, "('%s')%s", cs, rest);
} else if (strcmp(func, "pg_free_result") == 0) {
void *res = (void *) decode64(d, &i);
uint8_t ret = decode8(d, &i);
sprintf(line, "(%p) = %s", res, ret == 1 ? "ok" : "nok");
} else if ((strcmp(func, "pg_query") == 0)
|| (strcmp(func, "pg_query_params") == 0)
|| (strcmp(func, "pg_send_query") == 0)
|| (strcmp(func, "pg_send_query_params") == 0)) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint64_t dbh = decode64(d, &i);
uint16_t q_len = decode16(d, &i);
char q[q_len * 4 + 1];
sf_tools_bin2hex_ascii(q, d + i, q_len); i += q_len;
if (type == 'c') {
decode_query_params(rest, sizeof(rest),
ND_PARAMS_BIND_WAY_IN, d, &i);
} else if (type == 'r') {
uint64_t res = decode64(d, &i);
uint64_t rows = decode64(d, &i);
uint64_t aff = decode64(d, &i);
if (res == 1) // pg_send_query[_params]
snprintf(rest, sizeof(rest),
" = ok [%lu rows, %lu aff]",
rows, aff);
else if (res == 0) // pg_send_query[_params] TODO when this happens? pg_query returns false
snprintf(rest, sizeof(rest), " = nok"); // TODO: error code
else
snprintf(rest, sizeof(rest),
" = 0x%lx [%lu rows, %lu aff]",
res, rows, aff);
}
sprintf(line, "(h=0x%lx, '%s')%s", dbh, q, rest);
} else if (strcmp(func, "pg_get_result") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint64_t dbh = decode64(d, &i);
if (type == 'r') {
uint64_t res = decode64(d, &i);
uint64_t rows = decode64(d, &i);
uint64_t aff = decode64(d, &i);
snprintf(rest, sizeof(rest), " = 0x%lx [%lu rows, %lu aff]",
res, rows, aff);
}
sprintf(line, "(h=0x%lx)%s", dbh, rest);
} else if (strcmp(func, "pipe") == 0) {
int fd0 = decode32(d, &i);
int fd1 = decode32(d, &i);
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "()%s => {%d, %d}", rest, fd0, fd1);
} else if (strcmp(func, "pipe2") == 0) {
int fd0 = decode32(d, &i);
int fd1 = decode32(d, &i);
int flags = decode32(d, &i);
char sflags[128];
nd_decode_pipe_flags(sflags, sizeof(sflags), flags);
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(flags=%s)%s => {%d, %d}", sflags, rest, fd0, fd1);
} else if (strcmp(func, "pthread_join") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint64_t thread = decode64(d, &i);
int ret = decode_ret_int(rest, sizeof(rest), d, &i);
uint64_t retval = 0;
if (ret != -1)
retval = decode64(d, &i);
sprintf(line, "(thread=0x%lx, retval=0x%lx)%s",
thread, retval, rest);
} else if (strcmp(func, "pthread_attr_setstacksize") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint64_t attr = decode64(d, &i);
size_t stack_size = decode64(d, &i);
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(attr=0x%lx, %zu)%s",
attr, stack_size, rest);
} else if (strcmp(func, "pthread_create") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint64_t thread = decode64(d, &i);
uint64_t attr = decode64(d, &i);
uint64_t arg = decode64(d, &i);
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(thread=0x%lx, attr=0x%lx, arg=0x%lx)%s",
thread, attr, arg, rest);
} else if (strcmp(func, "pthread_setname_np") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint64_t thread = decode64(d, &i);
uint16_t len = decode16(d, &i);
char name[len * 4 + 1];
sf_tools_bin2hex_ascii(name, d + i, len); i += len;
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(thread=0x%lx, '%s')%s",
thread, name, rest);
} break;
case 'r':
if (strcmp(func, "read") == 0) {
int fd = decode32(d, &i);
size_t count = decode64(d, &i);
sprintf(rest, ", %zu)", count);
if (type == 'c') {
sprintf(line, "(%d, buf%s", fd, rest);
} else if (type == 'r') {
ssize_t ret = decode_ret_int64(rest, sizeof(rest), d, &i);
if (ret != -1) {
unsigned short max = decode16(d, &i);
char data[max * 4 + 1];
sf_tools_bin2hex_ascii(data, d + i, max); i += max;
sprintf(line, "(%d, '%s'%s)%s",
fd, data,
max < ret ? "..." : "", rest);
} else {
sprintf(line, "(%d)%s", fd, rest);
}
}
} else if (strcmp(func, "readdir") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint64_t dir = decode64(d, &i);
if (type == 'r')
decode_dirent(rest, sizeof(rest), d, &i);
sprintf(line, "(0x%lx)%s", dir, rest);
} else if (strcmp(func, "readahead") == 0) {
int fd = decode32(d, &i);
off_t off = decode64(d, &i);
size_t count = decode64(d, &i);
if (type == 'r')
decode_ret_int64(rest, sizeof(rest), d, &i);
sprintf(line, "(fd=%d, off=%zu, count=%zu)%s",
fd, off, count, rest);
} else if (strcmp(func, "recv") == 0) {
int sock = decode32(d, &i);
size_t len = decode64(d, &i);
int flags = decode32(d, &i);
sprintf(rest, ", %zu, 0x%x)", len, flags);
if (type == 'c') {
sprintf(line, "(%d, buf%s", sock, rest);
} else if (type == 'r') {
ssize_t ret = decode_ret_int64(rest, sizeof(rest), d, &i);
if (ret != -1) {
unsigned short max = decode16(d, &i);
char data[max * 4 + 1];
sf_tools_bin2hex_ascii(data, d + i, max); i += max;
sprintf(line, "(%d, '%s'%s)%s",
sock, data,
max < ret ? "..." : "", rest);
} else {
sprintf(line, "(%d)%s", sock, rest);
}
}
} else if (strcmp(func, "recvfrom") == 0) {
int sock = decode32(d, &i);
uint64_t len = decode64(d, &i);
int addrlen = decode32(d, &i);
int flags = decode32(d, &i);
if (type == 'c')
sprintf(line, "(%d, buf, %zu, 0x%x, addr, %u)",
sock, len, flags, addrlen);
while (type == 'r') {
ssize_t ret = decode_ret_int64(rest, sizeof(rest), d, &i);
if (ret <= 0)
break;
uint16_t max = decode16(d, &i);
char buf[max * 4 + 1];
sf_tools_bin2hex_ascii(buf, d + i, max); i += max;
if (addrlen == 0)
break;
char addr[addrlen * 2 + 1];
sf_tools_bin2hex(addr, d + i, addrlen); i += addrlen; // TODO: we need to decode this!
sprintf(line, "(%d, '%s'%s, %zd, 0x%x, '%s')%s",
sock, buf, len > max ? "..." : "",
len, flags, addr, rest);
break;
}
} else if (strcmp(func, "recvmsg") == 0) {
char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
int sock = decode32(d, &i);
int flags = decode32(d, &i);
char sflags[128];
nd_decode_msghdr_flags(sflags, sizeof(sflags), flags);
if (type == 'c') {
sprintf(line, "(%d, msg, flags=%s)", sock, sflags);
} else if (type == 'r') {
char sret[128];
ssize_t r = decode_ret_int64(sret, sizeof(sret), d, &i);
if (r != -1)
decode_msghdr(rest, sizeof(rest), d, &i);
else
strcpy(rest, "msg");
sprintf(line, "(%d, %s, flags=%s)%s",
sock, rest, sflags, sret);
}
} else if (strcmp(func, "rename") == 0) {
char oldpath[512], newpath[512];
decode_filename(oldpath, d, &i);
decode_filename(newpath, d, &i);
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "('%s', '%s')%s", oldpath, newpath, rest);
} else if (strcmp(func, "rmdir") == 0) {
char path[512];
decode_filename(path, d, &i);
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "('%s')%s", path, rest);
} break;
case 's':
if (strcmp(func, "send") == 0) {
int sock = decode32(d, &i);
size_t len = decode64(d, &i);
int flags = decode32(d, &i);
if (type == 'c') {
unsigned short max = decode16(d, &i);
char data[max * 4 + 1];
sf_tools_bin2hex_ascii(data, d + i, max); i += max;
sprintf(line, "(%d, '%s'%s, %zu, 0x%x)",
sock, data,
max < len ? "..." : "", len, flags);
} else if (type == 'r') {
decode_ret_int64(rest, sizeof(rest), d, &i);
sprintf(line, "(%d, buf, %zu, 0x%x)%s",
sock, len, flags, rest);
}
} else if (strcmp(func, "sendfile") == 0) {
int out_fd = decode32(d, &i);
int in_fd = decode32(d, &i);
off_t off = decode64(d, &i);
size_t count = decode64(d, &i);
if (type == 'r')
decode_ret_int64(rest, sizeof(rest), d, &i);
sprintf(line, "(out_fd=%d, in_fd=%d, off=%zu, count=%zu)%s",
out_fd, in_fd, off, count, rest);
} else if (strcmp(func, "sendmsg") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
int sock = decode32(d, &i);
if (type == 'c')
decode_msghdr(rest, sizeof(rest), d, &i);
int flags = decode32(d, &i);
char sflags[128];
nd_decode_msghdr_flags(sflags, sizeof(sflags), flags);
if (type == 'c') {
sprintf(line, "(%d, %s, flags=%s)", sock, rest, sflags);
// TODO: I need a way to split on multiple lines
// TODO: really needed?
} else if (type == 'r') {
decode_ret_int64(rest, sizeof(rest), d, &i);
sprintf(line, "(%d, msg, flags=%s)%s",
sock, sflags, rest);
}
} else if (strcmp(func, "setns") == 0) {
int fd = decode32(d, &i);
int nstype = decode32(d, &i);
char snstype[32];
nd_decode_clone_flags(snstype, sizeof(snstype), nstype);
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(fd=%d, nstype=%s)%s",
fd, snstype, rest);
} else if (strcmp(func, "setsockopt") == 0) {
int sock = decode32(d, &i);
char level[32], optname[32];
int ilevel = decode_sock_level(level, sizeof(level), d, &i);
decode_sock_optname(optname, sizeof(optname), ilevel, d, &i);
socklen_t optlen = decode32(d, &i);
char optval[optlen * 2 + 1];
sf_tools_bin2hex(optval, d + i, optlen); i+= optlen;
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(%d, %s, %s, 0x%s, %u)%s",
sock, level, optname, optval, optlen, rest);
} else if (strcmp(func, "socket") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
int xdomain = decode32(d, &i);
int xtype = decode32(d, &i);
int xprotocol = decode32(d, &i);
decode_ret_int(rest, sizeof(rest), d, &i);
char dom[32], type[32], proto[32];
nd_decode_socket_domain(dom, sizeof(dom), xdomain);
nd_decode_socket_type(type, sizeof(type), xtype);
nd_decode_socket_protocol(proto, sizeof(proto),
xdomain, xtype, xprotocol);
sprintf(line, "(%s, %s, %s)%s", dom, type, proto, rest);
} else if (strcmp(func, "sqlite3_bind_double") == 0) {
uint64_t stmt = decode64(d, &i);
int index = decode32(d, &i);
double value = decode64(d, &i);
decode_sqlite3_ret(rest, sizeof(rest), d, &i);
sprintf(line, "(0x%lx, index=%d, value=%f) = %s",
stmt, index, value, rest);
} else if (strcmp(func, "sqlite3_bind_int") == 0) {
uint64_t stmt = decode64(d, &i);
int index = decode32(d, &i);
int value = decode32(d, &i);
decode_sqlite3_ret(rest, sizeof(rest), d, &i);
sprintf(line, "(0x%lx, index=%d, value=%d) = %s",
stmt, index, value, rest);
} else if (strcmp(func, "sqlite3_bind_int64") == 0) {
uint64_t stmt = decode64(d, &i);
int index = decode32(d, &i);
int64_t value = decode64(d, &i);
decode_sqlite3_ret(rest, sizeof(rest), d, &i);
sprintf(line, "(0x%lx, index=%d, value=%ld) = %s",
stmt, index, value, rest);
} else if (strcmp(func, "sqlite3_bind_text") == 0) {
uint64_t stmt = decode64(d, &i);
int index = decode32(d, &i);
int16_t len = decode16(d, &i);
char value[len * 4 + 1];
sf_tools_bin2hex_ascii(value, d + i, len); i += len;
decode_sqlite3_ret(rest, sizeof(rest), d, &i);
sprintf(line, "(stmt=0x%lx, index=%d, '%s') = %s",
stmt, index, value, rest);
} else if (strcmp(func, "sqlite3_finalize") == 0) {
uint64_t stmt = decode64(d, &i);
decode_sqlite3_ret(rest, sizeof(rest), d, &i);
sprintf(line, "(0x%lx)%s%s", stmt, rest[0] ? " = " : "", rest);
} else if (strcmp(func, "sqlite3_open_v2") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
char filename[512];
decode_filename(filename, d, &i);
char flags[128];
decode_sqlite3_open_flags(flags, sizeof(flags), d, &i);
uint16_t vfs_len = decode16(d, &i);
char vfs[vfs_len * 4 + 1];
sf_tools_bin2hex_ascii(vfs, d + i, vfs_len); i += vfs_len;
if (type == 'c') {
sprintf(line, "('%s', %s, vfs='%s')",
filename, flags, vfs);
} else {
char err[64];
int ret = decode_sqlite3_ret(err, sizeof(err), d, &i);
uint64_t pdb = 0;
if (ret == 0)
pdb = decode64(d, &i);
sprintf(line, "('%s', 0x%lx, %s, vfs='%s') = %s",
filename, pdb, flags, vfs, err);
}
} else if (strcmp(func, "sqlite3_prepare_v2") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint64_t h = decode64(d, &i);
uint32_t sql_len = decode32(d, &i);
char sql[sql_len * 4 + 1];
sf_tools_bin2hex_ascii(sql, d + i, sql_len); i += sql_len;
int nByte = decode32(d, &i);
if (type == 'c') {
sprintf(line, "(0x%lx, '%s', %d, stmt, tail)",
h, sql, nByte);
} else {
uint64_t stmt = decode64(d, &i);
char err[64];
decode_sqlite3_ret(err, sizeof(err), d, &i);
sprintf(line, "(0x%lx, '%s', %d, 0x%lx, tail) = %s",
h, sql, nByte, stmt, err);
}
} else if (strcmp(func, "sqlite3_step") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
uint64_t stmt = decode64(d, &i);
if (type == 'c') {
sprintf(line, "(0x%lx)", stmt);
} else {
char err[64];
decode_sqlite3_ret(err, sizeof(err), d, &i);
sprintf(line, "(0x%lx) = %s", stmt, err);
}
} else if (strcmp(func, "stat") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
char pathname[512];
decode_filename(pathname, d, &i);
if (type == 'r')
decode_stat(rest, sizeof(rest), d, &i);
sprintf(line, "('%s')%s", pathname, rest);
} else if (strcmp(func, "statx") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
char sdirfd[64];
decode_statx_dirfd(sdirfd, sizeof(sdirfd), d, &i);
char pathname[512];
decode_filename(pathname, d, &i);
int flags = decode32(d, &i);
char sflags[128];
nd_decode_statx_flags(sflags, sizeof(sflags), flags);
unsigned int mask = decode32(d, &i);
char smask[128];
nd_decode_statx_mask(smask, sizeof(smask), mask);
if (type == 'r')
decode_statx(rest, sizeof(rest), d, &i);
sprintf(line, "(%s, '%s', flags=%s, mask=%s)%s",
sdirfd, pathname, sflags, smask, rest);
} else if (strcmp(func, "symlink") == 0) {
char target[512], linkpath[512];
decode_filename(target, d, &i);
decode_filename(linkpath, d, &i);
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "('%s', '%s')%s", target, linkpath, rest);
} else if (strcmp(func, "symlinkat") == 0) {
char target[512];
decode_filename(target, d, &i);
int newdirfd = decode32(d, &i);
char snewdirfd[32], color_snewdirfd[64];
nd_decode_symlink_newdirfd(snewdirfd, sizeof(snewdirfd), newdirfd);
nd_trace_color(color_snewdirfd, sizeof(color_snewdirfd),
snewdirfd, "flags", '-', "", 0);
char linkpath[512];
decode_filename(linkpath, d, &i);
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "('%s', %s, '%s')%s",
target, color_snewdirfd, linkpath, rest);
} else if (strcmp(func, "sync") == 0) {
strcpy(line, "()");
} else if (strcmp(func, "syncfs") == 0) {
int fd = decode32(d, &i);
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(%d)%s", fd, rest);
} else if (strcmp(func, "syslog") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP[%s][%c]: %s\n", func, type, dump);
char sprio[32];
decode_syslog_prio(sprio, sizeof(sprio), d, &i);
int len = decode16(d, &i);
char data[len * 4 + 1];
sf_tools_bin2hex_ascii(data, d + i, len); i += len;
sprintf(line, "(%s, '%s')", sprio, data);
} break;
case 't':
if (strcmp(func, "timerfd_create") == 0) {
int clockid = decode32(d, &i);
int flags = decode32(d, &i);
char sclock[32], sflags[64];
nd_decode_clockid(sclock, sizeof(sclock), clockid);
nd_decode_timerfd_flags(sflags, sizeof(sflags), flags);
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(%s, %s)%s", sclock, sflags, rest);
} break;
case 'u':
if (strcmp(func, "umask") == 0) {
mode_t mode = decode32(d, &i);
mode_t ret = decode32(d, &i);
sprintf(line, "(%03o) = %03o", mode, ret);
} else if (strcmp(func, "unlink") == 0) {
char pathname[512];
decode_filename(pathname, d, &i);
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "('%s')%s", pathname, rest);
} else if (strcmp(func, "umount") == 0) {
char target[512];
decode_filename(target, d, &i);
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "('%s')%s", target, rest);
} else if (strcmp(func, "umount2") == 0) {
char target[512];
decode_filename(target, d, &i);
int flags = decode32(d, &i);
char sflags[128];
nd_decode_umount_flags(sflags, sizeof(sflags), flags);
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "('%s', %s)%s", target, sflags, rest);
} else if (strcmp(func, "unshare") == 0) {
int flags = decode32(d, &i);
char sflags[128];
nd_decode_clone_flags(sflags, sizeof(sflags), flags);
if (type == 'r')
decode_ret_int(rest, sizeof(rest), d, &i);
sprintf(line, "(%s)%s", sflags, rest);
} break;
case 'w':
if (strcmp(func, "write") == 0) {
//char dump[4096]; sf_tools_bin2hex_ascii(dump, d + i, 128); fprintf(outf, "DUMP: %s\n", dump);
int fd = decode32(d, &i);
size_t count = decode64(d, &i);
if (type == 'c') {
unsigned short max = decode16(d, &i);
char data[max * 4 + 1];
sf_tools_bin2hex_ascii(data, d + i, max); i += max;
sprintf(line, "(%d, '%s'%s, %zu)",
fd, data,
max < count ? "..." : "", count);
} else if (type == 'r') {
decode_ret_int64(rest, sizeof(rest), d, &i);
sprintf(line, "(%d, buf, %zu)%s",
fd, count, rest);
}
} break;
}
if (line[0] == '\0') {
if (nothing_to_log == 0)
fprintf(outf, "I do not know how to decode func [%s] type [%c]!\n",
func, type);
return;
}
char space[4096];
unsigned short max = sizeof(space) - 1;
if (max > trace_depth)
max = trace_depth;
memset(space, ' ', max);
space[max] = '\0';
char cfunc[128];
if (theme)
nd_trace_color(cfunc, sizeof(cfunc), func, "func", type, tf, 0);
char sts[32], sts2[64];
if (strcmp(time_format, "none") == 0) {
sts2[0] = '\0';
} else {
if (strcmp(time_format, "human") == 0) {
snprintf(sts, sizeof(sts), "%lu.%03lu ", t / 1000, t % 1000);
} else {
snprintf(sts, sizeof(sts), "%lu.%03lu ", t / 1000, t % 1000);
}
nd_trace_color(sts2, sizeof(sts2), sts, "ts", '-', "",
last_ts == 0 ? 0 : t - last_ts);
}
if (hide_pids) {
fprintf(outf, "%s%s %s%s\n",
sts2, space, theme ? cfunc : func, line);
if (line2[0] != '\0')
fprintf(outf, "%s%s %s%s\n",
sts2, space, theme ? cfunc : func, line2);
} else if (pid == tid) {
fprintf(outf, "%s%10u %s %s%s\n",
sts2, pid, space, theme ? cfunc : func, line);
if (line2[0] != '\0')
fprintf(outf, "%s%10u %s %s%s\n",
sts2, pid, space, theme ? cfunc : func, line2);
} else {
fprintf(outf, "%s%10u %10u %s %s%s\n",
sts2, pid, tid, space, theme ? cfunc : func, line);
if (line2[0] != '\0')
fprintf(outf, "%s%10u %10u %s %s%s\n",
sts2, pid, tid, space, theme ? cfunc : func, line2);
}
last_ts = t;
}
static void decode(const pid_t parent, unsigned char *d, size_t len)
{
unsigned int i = 0;
char type;
type = d[i++];
if (type == 'F') {
decode_func(parent, d + i);
} else {
fprintf(outf, "I do not know how to decode type [%c]!\n", type);
char dump[len * 4 + 1];
sf_tools_bin2hex_ascii(dump, d, len);
fprintf(outf, "Decode %s\n", dump);
}
}
int main(int argc, char *argv[])
{
int c, r;
int options_index = 0;
char *out_file = NULL;
int sm[256];
char version[256];
struct shared *shared[256];
pid_t child;
// Disabling ninedogs.so for the tracer
int fd = open("/dev/ninedogs", O_WRONLY);
if (fd != -1) {
ssize_t junk = write(fd, "disable", 7);
(void) junk;
close(fd);
}
for (unsigned i = 0; i < 256; i++) {
sm[i] = -2;
version[i] = 0;
}
setlinebuf(stderr);
while ((c = getopt_long(argc, argv, "p:o:Ht:T:P", options, &options_index)) != -1) {
switch (c) {
case 'o': out_file = optarg; break;
case 'p': if (no_pids < 256) pids[no_pids++] = strtoull(optarg, NULL, 10); break;
case 'H': only_high_level = 1; break;
case 't': theme_name = optarg; break;
case 'T': time_format = optarg; break;
case 'P': hide_pids = 1; break;
default: usage();
}
}
argc -= optind;
argv += optind;
//fprintf(stderr, "argc=%u [%s]\n", argc, argv[0]);
if (argc > 0) {
child = fork();
if (child == -1) {
fprintf(stderr, "Cannot execute: %m\n");
exit(1);
} else if (child == 0) {
char *env[] = { "LD_PRELOAD=ninedogs.so",
"NINEDOGS_DELAY=1", "NINEDOGS_VERBOSE=0", NULL };
r = execvpe(argv[0], argv, env);
if (r == -1)
fprintf(stderr, "Error executing: %m\n");
exit(1);
}
fprintf(stderr, "Adding pid %u to list\n", child);
if (no_pids < 256)
pids[no_pids++] = child;
}
if (no_pids == 0) {
fprintf(stderr, "Error: no pids specified with -p!\n");
return 1;
}
if (!out_file) {
outf = stderr;
} else {
fprintf(stderr, "Saving output to [%s]\n", out_file);
umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
outf = fopen(out_file, "w");
if (!outf) {
fprintf(stderr, "Error: cannot open [%s]: %m\n", out_file);
return 1;
}
}
setlinebuf(outf);
//pid_t my_pid = getpid();
nd_trace_color_set_theme();
again:
for (unsigned i = 0; i < no_pids; i++) {
unsigned char *p;
unsigned int ava, head, tail, used;
unsigned char buf[64000];
struct stat s;
if (sm[i] < 0) {
char name[32];
snprintf(name, sizeof(name), "/ninedogs-%d", pids[i]);
sm[i] = shm_open(name, O_RDWR, 0);
if (sm[i] == -1) {
//fprintf(stderr, "%u: Cannot do shm_open: %m\n", pids[i]);
continue;
}
//fprintf(stderr, "%u: shm_open returned %d\n", pids[i], sm[i]);
shared[i] = mmap(NULL, sizeof(struct shared),
PROT_READ | PROT_WRITE, MAP_SHARED, sm[i], 0);
if (shared[i] == MAP_FAILED) {
fprintf(stderr, "%u: Cannot mmap: %m\n", pids[i]);
close(sm[i]);
sm[i] = -1;
continue;
}
fprintf(stderr, "%u: attached\n", pids[i]);
// we use '|' because we may have a concurrent tracer attached
shared[i]->clients++;
shared[i]->client_flags |= only_high_level == 1 ? ND_SHARED_ONLY_HIGH_LEVEL : 0;
}
if (do_exit == no_pids) {
shared[i]->clients--;
fprintf(stderr, "Bye!\n");
break;
}
fstat(sm[i], &s);
if (s.st_size == 0) {
//fprintf(outf, "%u: Shared memory size is zero!\n", pids[i]);
continue;
}
//fprintf(outf, "%u: Shared memory size: %ld\n", pids[i], s.st_size);
r = sem_wait(&shared[i]->sem1);
if (r == -1) {
fprintf(stderr, "%u: Cannot wait for sem1: %m\n", pids[i]);
return 1;
}
// Only here we can read 'head' and 'tail'
head = shared[i]->head;
tail = shared[i]->tail;
r = sem_post(&shared[i]->sem1);
if (r == -1) {
fprintf(stderr, "%u: Cannot post sem1: %m\n", pids[i]);
return 1;
}
if (version[i] == 0) {
version[i] = shared[i]->version;
fprintf(outf, "%u: version is %hhu\n", pids[i], version[i]);
}
// tail-1 points to last value available
if (tail == head)
continue;
else if (head < tail) // 01h3t5 => ava = 2
ava = tail - head;
else // 01t345h78 => ava = 2 + (9 - 6) = 5
ava = tail + (shared[i]->buf_size - head);
//fprintf(outf, "RING[%u]: head=%u tail=%u ava=%u [after lock]\n",
// i, head, tail, ava);
//char dump[ava * 4 + 1];
//sf_tools_bin2hex_ascii(dump, shared[i]->buf + shared[i]->head, ava);
//fprintf(outf, "DUMP0[%hu]: %s\n", ava, dump);
used = 0;
while (ava >= 2) {
unsigned short plen;
// TODO: we may have a byte at the end and the other at the beginning!
if (shared[i]->buf_size - head == 1) { // ...h size=4 h=3 => max=1 or ..h. max=2
// Split length!
plen = shared[i]->buf[head] << 8;
plen |= shared[i]->buf[0];
} else {
memcpy(&plen, shared[i]->buf + head, sizeof(plen));
plen = be16toh(plen);
}
if (plen > ava) {
fprintf(outf, "%u: Too short packet: plen=%hu > ava[%u]!\n",
pids[i], plen, ava);
break;
}
if (head + plen <= shared[i]->buf_size) { // dddt...hddd size=11, head=7, plen=4 => 10 <= 11
p = shared[i]->buf + head;
} else { // split data! dddt...hddd size=11, head=7, plen=8 => max=4
unsigned int max = shared[i]->buf_size - head;
if (max > plen) max = plen;
//fprintf(outf, " DEBUG: split data. max=%u\n", max);
//fprintf(outf, " DEBUG: copy to buf from %p+%u, %u bytes\n", shared[i]->buf, shared[i]->head, max);
memcpy(buf, shared[i]->buf + head, max);
//fprintf(outf, " DEBUG: copy to buf+%u from %p, %u bytes\n", max, shared[i]->buf, plen - max);
memcpy(buf + max, shared[i]->buf, plen - max);
p = buf;
}
if (0) {
char dump[plen * 4 + 1];
sf_tools_bin2hex_ascii(dump, p, plen);
fprintf(outf, "%u: DUMP[%hu] head=%u: %s\n",
pids[i], plen, head, dump);
}
decode(pids[i], p + 2, plen - 2);
ava -= plen;
head = (head + plen) % shared[i]->buf_size;
used += plen;
//fprintf(outf, " DEBUG: ava[%u] after substracting plen[%hu]; no_pids=%u\n",
// ava, plen, no_pids);
}
r = sem_wait(&shared[i]->sem1);
if (r == -1) {
fprintf(stderr, "%u: Cannot wait for sem1: %m\n", pids[i]);
return 1;
}
// Only here we can change 'head'
shared[i]->head = head;
shared[i]->junk++;
//fprintf(outf, " DEBUG: shared[%u]->head moved to %u\n", i, shared[i]->head);
r = sem_post(&shared[i]->sem1);
if (r == -1) {
fprintf(stderr, "%u: Cannot post sem1: %m\n", pids[i]);
return 1;
}
}
if (!do_exit) {
usleep(100 * 1000);
goto again;
}
// TODO: print some stats
return 0;
}