tools: remove redundant Python event data structure definitions (#2204)

Simplify code following #2198 (https://github.com/iovisor/bcc/pull/2198).

Some tools are not touched: mountsnoop.py, trace.py, lib/*.py, old/*.py.
diff --git a/tools/bashreadline.py b/tools/bashreadline.py
index da9c1b7..af4f18e 100755
--- a/tools/bashreadline.py
+++ b/tools/bashreadline.py
@@ -14,7 +14,6 @@
 from __future__ import print_function
 from bcc import BPF
 from time import strftime
-import ctypes as ct
 
 # load BPF program
 bpf_text = """
@@ -40,13 +39,6 @@
     return 0;
 };
 """
-STR_DATA = 80
-
-class Data(ct.Structure):
-    _fields_ = [
-        ("pid", ct.c_ulonglong),
-        ("str", ct.c_char * STR_DATA)
-    ]
 
 b = BPF(text=bpf_text)
 b.attach_uretprobe(name="/bin/bash", sym="readline", fn_name="printret")
@@ -55,7 +47,7 @@
 print("%-9s %-6s %s" % ("TIME", "PID", "COMMAND"))
 
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
     print("%-9s %-6d %s" % (strftime("%H:%M:%S"), event.pid,
                             event.str.decode('utf-8', 'replace')))
 
diff --git a/tools/biosnoop.py b/tools/biosnoop.py
index 259a81b..97f4785 100755
--- a/tools/biosnoop.py
+++ b/tools/biosnoop.py
@@ -15,7 +15,6 @@
 
 from __future__ import print_function
 from bcc import BPF
-import ctypes as ct
 import re
 
 # load BPF program
@@ -128,21 +127,6 @@
 b.attach_kprobe(event="blk_account_io_completion",
     fn_name="trace_req_completion")
 
-TASK_COMM_LEN = 16  # linux/sched.h
-DISK_NAME_LEN = 32  # linux/genhd.h
-
-class Data(ct.Structure):
-    _fields_ = [
-        ("pid", ct.c_ulonglong),
-        ("rwflag", ct.c_ulonglong),
-        ("delta", ct.c_ulonglong),
-        ("sector", ct.c_ulonglong),
-        ("len", ct.c_ulonglong),
-        ("ts", ct.c_ulonglong),
-        ("disk_name", ct.c_char * DISK_NAME_LEN),
-        ("name", ct.c_char * TASK_COMM_LEN)
-    ]
-
 # header
 print("%-14s %-14s %-6s %-7s %-2s %-9s %-7s %7s" % ("TIME(s)", "COMM", "PID",
     "DISK", "T", "SECTOR", "BYTES", "LAT(ms)"))
@@ -154,7 +138,7 @@
 
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
 
     val = -1
     global start_ts
diff --git a/tools/btrfsslower.py b/tools/btrfsslower.py
index 0a59820..bacbc06 100755
--- a/tools/btrfsslower.py
+++ b/tools/btrfsslower.py
@@ -28,7 +28,6 @@
 from bcc import BPF
 import argparse
 from time import strftime
-import ctypes as ct
 
 # symbols
 kallsyms = "/proc/kallsyms"
@@ -287,24 +286,9 @@
     if args.ebpf:
         exit()
 
-# kernel->user event data: struct data_t
-DNAME_INLINE_LEN = 32   # linux/dcache.h
-TASK_COMM_LEN = 16      # linux/sched.h
-class Data(ct.Structure):
-    _fields_ = [
-        ("ts_us", ct.c_ulonglong),
-        ("type", ct.c_ulonglong),
-        ("size", ct.c_ulonglong),
-        ("offset", ct.c_ulonglong),
-        ("delta_us", ct.c_ulonglong),
-        ("pid", ct.c_ulonglong),
-        ("task", ct.c_char * TASK_COMM_LEN),
-        ("file", ct.c_char * DNAME_INLINE_LEN)
-    ]
-
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
 
     type = 'R'
     if event.type == 1:
diff --git a/tools/capable.py b/tools/capable.py
index 65ffa77..a4a332c 100755
--- a/tools/capable.py
+++ b/tools/capable.py
@@ -18,7 +18,6 @@
 import errno
 import argparse
 from time import strftime
-import ctypes as ct
 
 # arguments
 examples = """examples:
@@ -165,19 +164,6 @@
 # initialize BPF
 b = BPF(text=bpf_text)
 
-TASK_COMM_LEN = 16    # linux/sched.h
-
-class Data(ct.Structure):
-    _fields_ = [
-        ("tgid", ct.c_uint32),
-        ("pid", ct.c_uint32),
-        ("uid", ct.c_uint32),
-        ("cap", ct.c_int),
-        ("audit", ct.c_int),
-        ("comm", ct.c_char * TASK_COMM_LEN),
-    ] + ([("kernel_stack_id", ct.c_int)] if args.kernel_stack else []) \
-      + ([("user_stack_id", ct.c_int)] if args.user_stack else [])
-
 # header
 print("%-9s %-6s %-6s %-6s %-16s %-4s %-20s %s" % (
     "TIME", "UID", "PID", "TID", "COMM", "CAP", "NAME", "AUDIT"))
@@ -198,7 +184,7 @@
 
 # process event
 def print_event(bpf, cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
 
     if event.cap in capabilities:
         name = capabilities[event.cap]
diff --git a/tools/cpuunclaimed.py b/tools/cpuunclaimed.py
index 75ee932..dc0f325 100755
--- a/tools/cpuunclaimed.py
+++ b/tools/cpuunclaimed.py
@@ -59,11 +59,9 @@
 from __future__ import print_function
 from bcc import BPF, PerfType, PerfSWConfig
 from time import sleep, strftime
-from ctypes import c_int
 import argparse
 import multiprocessing
 from os import getpid, system, open, close, dup, unlink, O_WRONLY
-import ctypes as ct
 from tempfile import NamedTemporaryFile
 
 # arguments
@@ -248,12 +246,6 @@
 else:
     print(("Sampling run queues... Output every %s seconds. " +
           "Hit Ctrl-C to end.") % args.interval)
-class Data(ct.Structure):
-    _fields_ = [
-        ("ts", ct.c_ulonglong),
-        ("cpu", ct.c_ulonglong),
-        ("len", ct.c_ulonglong)
-    ]
 
 samples = {}
 group = {}
@@ -261,7 +253,7 @@
 
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
     samples[event.ts] = {}
     samples[event.ts]['cpu'] = event.cpu
     samples[event.ts]['len'] = event.len
diff --git a/tools/criticalstat.py b/tools/criticalstat.py
index da28594..250cfc4 100755
--- a/tools/criticalstat.py
+++ b/tools/criticalstat.py
@@ -15,7 +15,6 @@
 from __future__ import print_function
 from bcc import BPF
 import argparse
-import ctypes as ct
 import sys
 import subprocess
 import os.path
@@ -271,18 +270,6 @@
 
 b = BPF(text=bpf_text)
 
-TASK_COMM_LEN = 16    # linux/sched.h
-
-class Data(ct.Structure):
-    _fields_ = [
-        ("time", ct.c_ulonglong),
-        ("stack_id", ct.c_longlong),
-        ("cpu", ct.c_int),
-        ("id", ct.c_ulonglong),
-        ("addrs", ct.c_int * 4),
-        ("comm", ct.c_char * TASK_COMM_LEN),
-    ]
-
 def get_syms(kstack):
     syms = []
 
@@ -296,7 +283,7 @@
 def print_event(cpu, data, size):
     try:
         global b
-        event = ct.cast(data, ct.POINTER(Data)).contents
+        event = b["events"].event(data)
         stack_traces = b['stack_traces']
         stext = b.ksymname('_stext')
 
diff --git a/tools/dbslower.py b/tools/dbslower.py
index 24e6394..da2180f 100755
--- a/tools/dbslower.py
+++ b/tools/dbslower.py
@@ -27,7 +27,6 @@
 from bcc import BPF, USDT
 import argparse
 import re
-import ctypes as ct
 import subprocess
 
 examples = """examples:
@@ -203,18 +202,10 @@
     if args.ebpf:
         exit()
 
-class Data(ct.Structure):
-    _fields_ = [
-        ("pid", ct.c_ulonglong),
-        ("timestamp", ct.c_ulonglong),
-        ("delta", ct.c_ulonglong),
-        ("query", ct.c_char * 256)
-    ]
-
 start = BPF.monotonic_time()
 
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = bpf["events"].event(data)
     print("%-14.6f %-6d %8.3f %s" % (
         float(event.timestamp - start) / 1000000000,
         event.pid, float(event.delta) / 1000000, event.query))
diff --git a/tools/execsnoop.py b/tools/execsnoop.py
index 0c2c065..c402116 100755
--- a/tools/execsnoop.py
+++ b/tools/execsnoop.py
@@ -21,7 +21,6 @@
 from bcc.utils import ArgString, printb
 import bcc.utils as utils
 import argparse
-import ctypes as ct
 import re
 import time
 from collections import defaultdict
@@ -173,19 +172,6 @@
     print("%-8s" % ("TIME(s)"), end="")
 print("%-16s %-6s %-6s %3s %s" % ("PCOMM", "PID", "PPID", "RET", "ARGS"))
 
-TASK_COMM_LEN = 16      # linux/sched.h
-ARGSIZE = 128           # should match #define in C above
-
-class Data(ct.Structure):
-    _fields_ = [
-        ("pid", ct.c_uint),
-        ("ppid", ct.c_uint),
-        ("comm", ct.c_char * TASK_COMM_LEN),
-        ("type", ct.c_int),
-        ("argv", ct.c_char * ARGSIZE),
-        ("retval", ct.c_int),
-    ]
-
 class EventType(object):
     EVENT_ARG = 0
     EVENT_RET = 1
@@ -209,8 +195,7 @@
 
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
-
+    event = b["events"].event(data)
     skip = False
 
     if event.type == EventType.EVENT_ARG:
diff --git a/tools/ext4slower.py b/tools/ext4slower.py
index 16b56ec..0524f22 100755
--- a/tools/ext4slower.py
+++ b/tools/ext4slower.py
@@ -29,7 +29,6 @@
 from bcc import BPF
 import argparse
 from time import strftime
-import ctypes as ct
 
 # symbols
 kallsyms = "/proc/kallsyms"
@@ -285,24 +284,9 @@
     if args.ebpf:
         exit()
 
-# kernel->user event data: struct data_t
-DNAME_INLINE_LEN = 32   # linux/dcache.h
-TASK_COMM_LEN = 16      # linux/sched.h
-class Data(ct.Structure):
-    _fields_ = [
-        ("ts_us", ct.c_ulonglong),
-        ("type", ct.c_ulonglong),
-        ("size", ct.c_ulonglong),
-        ("offset", ct.c_ulonglong),
-        ("delta_us", ct.c_ulonglong),
-        ("pid", ct.c_ulonglong),
-        ("task", ct.c_char * TASK_COMM_LEN),
-        ("file", ct.c_char * DNAME_INLINE_LEN)
-    ]
-
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
 
     type = 'R'
     if event.type == 1:
diff --git a/tools/filelife.py b/tools/filelife.py
index f66f00b..2eb4244 100755
--- a/tools/filelife.py
+++ b/tools/filelife.py
@@ -21,7 +21,6 @@
 from bcc import BPF
 import argparse
 from time import strftime
-import ctypes as ct
 
 # arguments
 examples = """examples:
@@ -100,17 +99,6 @@
 }
 """
 
-TASK_COMM_LEN = 16            # linux/sched.h
-DNAME_INLINE_LEN = 255        # linux/dcache.h
-
-class Data(ct.Structure):
-    _fields_ = [
-        ("pid", ct.c_uint),
-        ("delta", ct.c_ulonglong),
-        ("comm", ct.c_char * TASK_COMM_LEN),
-        ("fname", ct.c_char * DNAME_INLINE_LEN)
-    ]
-
 if args.pid:
     bpf_text = bpf_text.replace('FILTER',
         'if (pid != %s) { return 0; }' % args.pid)
@@ -134,7 +122,7 @@
 
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
     print("%-8s %-6d %-16s %-7.2f %s" % (strftime("%H:%M:%S"), event.pid,
         event.comm.decode('utf-8', 'replace'), float(event.delta) / 1000,
         event.fname.decode('utf-8', 'replace')))
diff --git a/tools/fileslower.py b/tools/fileslower.py
index e2830e9..6fa0c26 100755
--- a/tools/fileslower.py
+++ b/tools/fileslower.py
@@ -31,7 +31,6 @@
 from __future__ import print_function
 from bcc import BPF
 import argparse
-import ctypes as ct
 import time
 
 # arguments
@@ -210,20 +209,6 @@
     b.attach_kprobe(event="vfs_write", fn_name="trace_write_entry")
     b.attach_kretprobe(event="vfs_write", fn_name="trace_write_return")
 
-TASK_COMM_LEN = 16  # linux/sched.h
-DNAME_INLINE_LEN = 32  # linux/dcache.h
-
-class Data(ct.Structure):
-    _fields_ = [
-        ("mode", ct.c_int),
-        ("pid", ct.c_uint),
-        ("sz", ct.c_uint),
-        ("delta_us", ct.c_ulonglong),
-        ("name_len", ct.c_uint),
-        ("name", ct.c_char * DNAME_INLINE_LEN),
-        ("comm", ct.c_char * TASK_COMM_LEN),
-    ]
-
 mode_s = {
     0: 'R',
     1: 'W',
@@ -237,7 +222,7 @@
 start_ts = time.time()
 
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
 
     ms = float(event.delta_us) / 1000
     name = event.name.decode('utf-8', 'replace')
diff --git a/tools/funcslower.py b/tools/funcslower.py
index 283c801..bda6a84 100755
--- a/tools/funcslower.py
+++ b/tools/funcslower.py
@@ -24,7 +24,6 @@
 from __future__ import print_function
 from bcc import BPF
 import argparse
-import ctypes as ct
 import time
 
 examples = """examples:
@@ -241,20 +240,6 @@
         b.attach_kprobe(event=function, fn_name="trace_%d" % i)
         b.attach_kretprobe(event=function, fn_name="trace_return")
 
-TASK_COMM_LEN = 16  # linux/sched.h
-
-class Data(ct.Structure):
-    _fields_ = [
-        ("id", ct.c_ulonglong),
-        ("tgid_pid", ct.c_ulonglong),
-        ("start_ns", ct.c_ulonglong),
-        ("duration_ns", ct.c_ulonglong),
-        ("retval", ct.c_ulonglong),
-        ("comm", ct.c_char * TASK_COMM_LEN)
-    ] + ([("args", ct.c_ulonglong * 6)] if args.arguments else []) + \
-            ([("user_stack_id", ct.c_int)] if args.user_stack else []) + \
-            ([("kernel_stack_id", ct.c_int),("kernel_ip", ct.c_ulonglong)] if args.kernel_stack else [])
-
 time_designator = "us" if args.min_us else "ms"
 time_value = args.min_us or args.min_ms or 1
 time_multiplier = 1000 if args.min_us else 1000000
@@ -319,7 +304,7 @@
             print("    %s" % b.sym(addr, event.tgid_pid))
 
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
     ts = float(event.duration_ns) / time_multiplier
     if not args.folded:
         print((time_str(event) + "%-14.14s %-6s %7.2f %16x %s %s") %
diff --git a/tools/gethostlatency.py b/tools/gethostlatency.py
index 8d07e23..965c0db 100755
--- a/tools/gethostlatency.py
+++ b/tools/gethostlatency.py
@@ -19,7 +19,6 @@
 from bcc import BPF
 from time import strftime
 import argparse
-import ctypes as ct
 
 examples = """examples:
     ./gethostlatency           # trace all TCP accept()s
@@ -113,21 +112,11 @@
 b.attach_uretprobe(name="c", sym="gethostbyname2", fn_name="do_return",
                    pid=args.pid)
 
-TASK_COMM_LEN = 16    # linux/sched.h
-
-class Data(ct.Structure):
-    _fields_ = [
-        ("pid", ct.c_ulonglong),
-        ("delta", ct.c_ulonglong),
-        ("comm", ct.c_char * TASK_COMM_LEN),
-        ("host", ct.c_char * 80)
-    ]
-
 # header
 print("%-9s %-6s %-16s %10s %s" % ("TIME", "PID", "COMM", "LATms", "HOST"))
 
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
     print("%-9s %-6d %-16s %10.2f %s" % (strftime("%H:%M:%S"), event.pid,
         event.comm.decode('utf-8', 'replace'), (float(event.delta) / 1000000),
         event.host.decode('utf-8', 'replace')))
diff --git a/tools/killsnoop.py b/tools/killsnoop.py
index 16221a2..2fb1dcb 100755
--- a/tools/killsnoop.py
+++ b/tools/killsnoop.py
@@ -17,7 +17,6 @@
 from bcc.utils import ArgString, printb
 import argparse
 from time import strftime
-import ctypes as ct
 
 # arguments
 examples = """examples:
@@ -116,25 +115,13 @@
 b.attach_kprobe(event=kill_fnname, fn_name="syscall__kill")
 b.attach_kretprobe(event=kill_fnname, fn_name="do_ret_sys_kill")
 
-
-TASK_COMM_LEN = 16    # linux/sched.h
-
-class Data(ct.Structure):
-    _fields_ = [
-        ("pid", ct.c_ulonglong),
-        ("tpid", ct.c_int),
-        ("sig", ct.c_int),
-        ("ret", ct.c_int),
-        ("comm", ct.c_char * TASK_COMM_LEN)
-    ]
-
 # header
 print("%-9s %-6s %-16s %-4s %-6s %s" % (
     "TIME", "PID", "COMM", "SIG", "TPID", "RESULT"))
 
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
 
     if (args.failed and (event.ret >= 0)):
         return
diff --git a/tools/mdflush.py b/tools/mdflush.py
index 485635d..f1c68ae 100755
--- a/tools/mdflush.py
+++ b/tools/mdflush.py
@@ -14,7 +14,6 @@
 from __future__ import print_function
 from bcc import BPF
 from time import strftime
-import ctypes as ct
 
 # load BPF program
 b = BPF(text="""
@@ -54,23 +53,13 @@
 }
 """)
 
-# event data
-TASK_COMM_LEN = 16  # linux/sched.h
-DISK_NAME_LEN = 32  # linux/genhd.h
-class Data(ct.Structure):
-    _fields_ = [
-        ("pid", ct.c_ulonglong),
-        ("comm", ct.c_char * TASK_COMM_LEN),
-        ("disk", ct.c_char * DISK_NAME_LEN)
-    ]
-
 # header
 print("Tracing md flush requests... Hit Ctrl-C to end.")
 print("%-8s %-6s %-16s %s" % ("TIME", "PID", "COMM", "DEVICE"))
 
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
     print("%-8s %-6d %-16s %s" % (strftime("%H:%M:%S"), event.pid,
         event.comm.decode('utf-8', 'replace'),
         event.disk.decode('utf-8', 'replace')))
diff --git a/tools/mysqld_qslower.py b/tools/mysqld_qslower.py
index ab23b5b..1518974 100755
--- a/tools/mysqld_qslower.py
+++ b/tools/mysqld_qslower.py
@@ -18,7 +18,6 @@
 from __future__ import print_function
 from bcc import BPF, USDT
 import sys
-import ctypes as ct
 
 # arguments
 def usage():
@@ -109,19 +108,11 @@
     min_ms_text))
 print("%-14s %-6s %8s %s" % ("TIME(s)", "PID", "MS", "QUERY"))
 
-class Data(ct.Structure):
-    _fields_ = [
-        ("pid", ct.c_ulonglong),
-        ("ts", ct.c_ulonglong),
-        ("delta", ct.c_ulonglong),
-        ("query", ct.c_char * QUERY_MAX)
-    ]
-
 # process event
 start = 0
 def print_event(cpu, data, size):
     global start
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
     if start == 0:
         start = event.ts
     print("%-14.6f %-6d %8.3f %s" % (float(event.ts - start) / 1000000000,
diff --git a/tools/nfsslower.py b/tools/nfsslower.py
index 32e91c7..36918ca 100755
--- a/tools/nfsslower.py
+++ b/tools/nfsslower.py
@@ -32,7 +32,6 @@
 from bcc import BPF
 import argparse
 from time import strftime
-import ctypes as ct
 
 examples = """
     ./nfsslower         # trace operations slower than 10ms
@@ -243,27 +242,9 @@
     if args.ebpf:
         exit()
 
-# kernel->user event data: struct data_t
-DNAME_INLINE_LEN = 32   # linux/dcache.h
-TASK_COMM_LEN = 16      # linux/sched.h
-
-
-class Data(ct.Structure):
-    _fields_ = [
-        ("ts_us", ct.c_ulonglong),
-        ("type", ct.c_ulonglong),
-        ("size", ct.c_ulonglong),
-        ("offset", ct.c_ulonglong),
-        ("delta_us", ct.c_ulonglong),
-        ("pid", ct.c_ulonglong),
-        ("task", ct.c_char * TASK_COMM_LEN),
-        ("file", ct.c_char * DNAME_INLINE_LEN)
-    ]
-
-
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
 
     type = 'R'
     if event.type == 1:
diff --git a/tools/oomkill.py b/tools/oomkill.py
index 16defe0..4f3b6ce 100755
--- a/tools/oomkill.py
+++ b/tools/oomkill.py
@@ -16,7 +16,6 @@
 
 from bcc import BPF
 from time import strftime
-import ctypes as ct
 
 # linux stats
 loadavg = "/proc/loadavg"
@@ -51,20 +50,9 @@
 }
 """
 
-# kernel->user event data: struct data_t
-TASK_COMM_LEN = 16  # linux/sched.h
-class Data(ct.Structure):
-    _fields_ = [
-        ("fpid", ct.c_ulonglong),
-        ("tpid", ct.c_ulonglong),
-        ("pages", ct.c_ulonglong),
-        ("fcomm", ct.c_char * TASK_COMM_LEN),
-        ("tcomm", ct.c_char * TASK_COMM_LEN)
-    ]
-
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
     with open(loadavg) as stats:
         avgline = stats.read().rstrip()
     print(("%s Triggered by PID %d (\"%s\"), OOM kill of PID %d (\"%s\")"
diff --git a/tools/opensnoop.py b/tools/opensnoop.py
index 55db352..4ffedfa 100755
--- a/tools/opensnoop.py
+++ b/tools/opensnoop.py
@@ -19,7 +19,6 @@
 from bcc import ArgString, BPF
 from bcc.utils import printb
 import argparse
-import ctypes as ct
 from datetime import datetime, timedelta
 import os
 
@@ -182,20 +181,6 @@
 b.attach_kprobe(event="do_sys_open", fn_name="trace_entry")
 b.attach_kretprobe(event="do_sys_open", fn_name="trace_return")
 
-TASK_COMM_LEN = 16    # linux/sched.h
-NAME_MAX = 255        # linux/limits.h
-
-class Data(ct.Structure):
-    _fields_ = [
-        ("id", ct.c_ulonglong),
-        ("ts", ct.c_ulonglong),
-        ("uid", ct.c_uint32),
-        ("ret", ct.c_int),
-        ("comm", ct.c_char * TASK_COMM_LEN),
-        ("fname", ct.c_char * NAME_MAX),
-        ("flags", ct.c_int),
-    ]
-
 initial_ts = 0
 
 # header
@@ -211,7 +196,7 @@
 
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
     global initial_ts
 
     # split return value into FD and errno columns
diff --git a/tools/profile.py b/tools/profile.py
index 89cd523..958b632 100755
--- a/tools/profile.py
+++ b/tools/profile.py
@@ -35,7 +35,6 @@
 import os
 import errno
 import multiprocessing
-import ctypes as ct
 
 #
 # Process Arguments
diff --git a/tools/runqslower.py b/tools/runqslower.py
index bd1138e..1d48be8 100755
--- a/tools/runqslower.py
+++ b/tools/runqslower.py
@@ -33,7 +33,6 @@
 from bcc import BPF
 import argparse
 from time import strftime
-import ctypes as ct
 
 # arguments
 examples = """examples:
@@ -226,19 +225,9 @@
     if args.ebpf:
         exit()
 
-# kernel->user event data: struct data_t
-DNAME_INLINE_LEN = 32   # linux/dcache.h
-TASK_COMM_LEN = 16      # linux/sched.h
-class Data(ct.Structure):
-    _fields_ = [
-        ("pid", ct.c_uint),
-        ("task", ct.c_char * TASK_COMM_LEN),
-        ("delta_us", ct.c_ulonglong),
-    ]
-
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
     print("%-8s %-16s %-6s %14s" % (strftime("%H:%M:%S"), event.task, event.pid, event.delta_us))
 
 # load BPF program
diff --git a/tools/shmsnoop.py b/tools/shmsnoop.py
index bb50535..11b4b6f 100755
--- a/tools/shmsnoop.py
+++ b/tools/shmsnoop.py
@@ -14,7 +14,6 @@
 from __future__ import print_function
 from bcc import ArgString, BPF
 import argparse
-import ctypes as ct
 from datetime import datetime, timedelta
 
 # arguments
@@ -207,22 +206,6 @@
 
 initial_ts = 0
 
-class Data(ct.Structure):
-    _fields_ = [
-        ("id",      ct.c_ulonglong),
-        ("ts",      ct.c_ulonglong),
-        ("sys",     ct.c_int),
-        ("key",     ct.c_ulong),
-        ("size",    ct.c_ulong),
-        ("shmflg",  ct.c_ulong),
-        ("shmid",   ct.c_ulong),
-        ("cmd",     ct.c_ulong),
-        ("buf",     ct.c_ulong),
-        ("shmaddr", ct.c_ulong),
-        ("ret",     ct.c_ulong),
-        ("comm",    ct.c_char * TASK_COMM_LEN),
-    ]
-
 # header
 if args.timestamp:
     print("%-14s" % ("TIME(s)"), end="")
@@ -281,7 +264,7 @@
 
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
     global initial_ts
 
     if not initial_ts:
diff --git a/tools/sofdsnoop.py b/tools/sofdsnoop.py
index 77f8f14..e0c1310 100755
--- a/tools/sofdsnoop.py
+++ b/tools/sofdsnoop.py
@@ -15,7 +15,6 @@
 from bcc import ArgString, BPF
 import os
 import argparse
-import ctypes as ct
 from datetime import datetime, timedelta
 
 # arguments
@@ -279,21 +278,8 @@
 b.attach_kprobe(event="scm_detach_fds", fn_name="trace_scm_detach_fds_entry")
 b.attach_kretprobe(event="scm_detach_fds", fn_name="trace_scm_detach_fds_return")
 
-TASK_COMM_LEN = 16    # linux/sched.h
-
 initial_ts = 0
 
-class Data(ct.Structure):
-    _fields_ = [
-        ("id",      ct.c_ulonglong),
-        ("ts",      ct.c_ulonglong),
-        ("action",  ct.c_int),
-        ("sock_fd", ct.c_int),
-        ("fd_cnt",  ct.c_int),
-        ("fd",      ct.c_int  * MAX_FD),
-        ("comm",    ct.c_char * TASK_COMM_LEN),
-    ]
-
 # header
 if args.timestamp:
     print("%-14s" % ("TIME(s)"), end="")
@@ -309,7 +295,7 @@
 
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
     tid = event.id & 0xffffffff;
 
     cnt = min(MAX_FD, event.fd_cnt);
diff --git a/tools/solisten.py b/tools/solisten.py
index bced0a2..f2a0a34 100755
--- a/tools/solisten.py
+++ b/tools/solisten.py
@@ -22,7 +22,6 @@
 from struct import pack
 import argparse
 from bcc import BPF
-import ctypes as ct
 from bcc.utils import printb
 
 # Arguments
@@ -123,27 +122,13 @@
 };
 """
 
-# event data
-TASK_COMM_LEN = 16      # linux/sched.h
-class ListenEvt(ct.Structure):
-    _fields_ = [
-        ("ts_us", ct.c_ulonglong),
-        ("pid_tgid", ct.c_ulonglong),
-        ("backlog", ct.c_ulonglong),
-        ("netns", ct.c_ulonglong),
-        ("proto", ct.c_ulonglong),
-        ("lport", ct.c_ulonglong),
-        ("laddr", ct.c_ulonglong * 2),
-        ("task", ct.c_char * TASK_COMM_LEN)
-    ]
-
     # TODO: properties to unpack protocol / ip / pid / tgid ...
 
 # Format output
 def event_printer(show_netns):
     def print_event(cpu, data, size):
         # Decode event
-        event = ct.cast(data, ct.POINTER(ListenEvt)).contents
+        event = b["listen_evt"].event(data)
 
         pid = event.pid_tgid & 0xffffffff
         proto_family = event.proto & 0xff
diff --git a/tools/sslsniff.py b/tools/sslsniff.py
index 265e87f..e48fbb4 100755
--- a/tools/sslsniff.py
+++ b/tools/sslsniff.py
@@ -14,7 +14,6 @@
 #
 
 from __future__ import print_function
-import ctypes as ct
 from bcc import BPF
 import argparse
 
@@ -171,17 +170,6 @@
 MAX_BUF_SIZE = 464  # Limited by the BPF stack
 
 
-# Max size of the whole struct: 512 bytes
-class Data(ct.Structure):
-    _fields_ = [
-            ("timestamp_ns", ct.c_ulonglong),
-            ("pid", ct.c_uint),
-            ("comm", ct.c_char * TASK_COMM_LEN),
-            ("v0", ct.c_char * MAX_BUF_SIZE),
-            ("len", ct.c_uint)
-    ]
-
-
 # header
 print("%-12s %-18s %-16s %-6s %-6s" % ("FUNC", "TIME(s)", "COMM", "PID",
                                        "LEN"))
@@ -191,16 +179,16 @@
 
 
 def print_event_write(cpu, data, size):
-    print_event(cpu, data, size, "WRITE/SEND")
+    print_event(cpu, data, size, "WRITE/SEND", "perf_SSL_write")
 
 
 def print_event_read(cpu, data, size):
-    print_event(cpu, data, size, "READ/RECV")
+    print_event(cpu, data, size, "READ/RECV", "perf_SSL_read")
 
 
-def print_event(cpu, data, size, rw):
+def print_event(cpu, data, size, rw, evt):
     global start
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b[evt].event(data)
 
     # Filter events by command
     if args.comm:
diff --git a/tools/statsnoop.py b/tools/statsnoop.py
index 516eda2..6cdff94 100755
--- a/tools/statsnoop.py
+++ b/tools/statsnoop.py
@@ -15,7 +15,6 @@
 from __future__ import print_function
 from bcc import BPF
 import argparse
-import ctypes as ct
 
 # arguments
 examples = """examples:
@@ -129,18 +128,6 @@
     b.attach_kprobe(event=syscall_fnname, fn_name="syscall__entry")
     b.attach_kretprobe(event=syscall_fnname, fn_name="trace_return")
 
-TASK_COMM_LEN = 16    # linux/sched.h
-NAME_MAX = 255        # linux/limits.h
-
-class Data(ct.Structure):
-    _fields_ = [
-        ("pid", ct.c_ulonglong),
-        ("ts_ns", ct.c_ulonglong),
-        ("ret", ct.c_int),
-        ("comm", ct.c_char * TASK_COMM_LEN),
-        ("fname", ct.c_char * NAME_MAX)
-    ]
-
 start_ts = 0
 prev_ts = 0
 delta = 0
@@ -152,7 +139,7 @@
 
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
     global start_ts
     global prev_ts
     global delta
diff --git a/tools/syncsnoop.py b/tools/syncsnoop.py
index 708fbc4..e5fa78e 100755
--- a/tools/syncsnoop.py
+++ b/tools/syncsnoop.py
@@ -15,7 +15,6 @@
 
 from __future__ import print_function
 from bcc import BPF
-import ctypes as ct
 
 # load BPF program
 b = BPF(text="""
@@ -34,17 +33,12 @@
 b.attach_kprobe(event=b.get_syscall_fnname("sync"),
                 fn_name="syscall__sync")
 
-class Data(ct.Structure):
-    _fields_ = [
-        ("ts", ct.c_ulonglong)
-    ]
-
 # header
 print("%-18s %s" % ("TIME(s)", "CALL"))
 
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
     print("%-18.9f sync()" % (float(event.ts) / 1000000))
 
 # loop with callback to print_event
diff --git a/tools/tcpaccept.py b/tools/tcpaccept.py
index b128086..5f7b48c 100755
--- a/tools/tcpaccept.py
+++ b/tools/tcpaccept.py
@@ -20,7 +20,6 @@
 from socket import inet_ntop, AF_INET, AF_INET6
 from struct import pack
 import argparse
-import ctypes as ct
 from bcc.utils import printb
 
 # arguments
@@ -211,34 +210,9 @@
     if args.ebpf:
         exit()
 
-# event data
-TASK_COMM_LEN = 16      # linux/sched.h
-
-class Data_ipv4(ct.Structure):
-    _fields_ = [
-        ("ts_us", ct.c_ulonglong),
-        ("pid", ct.c_uint),
-        ("saddr", ct.c_uint),
-        ("daddr", ct.c_uint),
-        ("ip", ct.c_ulonglong),
-        ("lport", ct.c_ushort),
-        ("task", ct.c_char * TASK_COMM_LEN)
-    ]
-
-class Data_ipv6(ct.Structure):
-    _fields_ = [
-        ("ts_us", ct.c_ulonglong),
-        ("pid", ct.c_uint),
-        ("saddr", (ct.c_ulonglong * 2)),
-        ("daddr", (ct.c_ulonglong * 2)),
-        ("ip", ct.c_ulonglong),
-        ("lport", ct.c_ushort),
-        ("task", ct.c_char * TASK_COMM_LEN)
-    ]
-
 # process event
 def print_ipv4_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data_ipv4)).contents
+    event = b["ipv4_events"].event(data)
     global start_ts
     if args.timestamp:
         if start_ts == 0:
@@ -251,7 +225,7 @@
         event.lport))
 
 def print_ipv6_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data_ipv6)).contents
+    event = b["ipv6_events"].event(data)
     global start_ts
     if args.timestamp:
         if start_ts == 0:
diff --git a/tools/tcpconnlat.py b/tools/tcpconnlat.py
index 9f25f0f..8f68621 100755
--- a/tools/tcpconnlat.py
+++ b/tools/tcpconnlat.py
@@ -19,7 +19,6 @@
 from socket import inet_ntop, AF_INET, AF_INET6
 from struct import pack
 import argparse
-import ctypes as ct
 
 # arg validation
 def positive_float(val):
@@ -199,38 +198,11 @@
 b.attach_kprobe(event="tcp_rcv_state_process",
     fn_name="trace_tcp_rcv_state_process")
 
-# event data
-TASK_COMM_LEN = 16      # linux/sched.h
-
-class Data_ipv4(ct.Structure):
-    _fields_ = [
-        ("ts_us", ct.c_ulonglong),
-        ("pid", ct.c_uint),
-        ("saddr", ct.c_uint),
-        ("daddr", ct.c_uint),
-        ("ip", ct.c_ulonglong),
-        ("dport", ct.c_ushort),
-        ("delta_us", ct.c_ulonglong),
-        ("task", ct.c_char * TASK_COMM_LEN)
-    ]
-
-class Data_ipv6(ct.Structure):
-    _fields_ = [
-        ("ts_us", ct.c_ulonglong),
-        ("pid", ct.c_uint),
-        ("saddr", (ct.c_ulonglong * 2)),
-        ("daddr", (ct.c_ulonglong * 2)),
-        ("ip", ct.c_ulonglong),
-        ("dport", ct.c_ushort),
-        ("delta_us", ct.c_ulonglong),
-        ("task", ct.c_char * TASK_COMM_LEN)
-    ]
-
 # process event
 start_ts = 0
 
 def print_ipv4_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data_ipv4)).contents
+    event = b["ipv4_events"].event(data)
     global start_ts
     if args.timestamp:
         if start_ts == 0:
@@ -243,7 +215,7 @@
         float(event.delta_us) / 1000))
 
 def print_ipv6_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data_ipv6)).contents
+    event = b["ipv6_events"].event(data)
     global start_ts
     if args.timestamp:
         if start_ts == 0:
diff --git a/tools/tcpdrop.py b/tools/tcpdrop.py
index ca89be6..bf8634d 100755
--- a/tools/tcpdrop.py
+++ b/tools/tcpdrop.py
@@ -23,7 +23,6 @@
 from time import strftime
 from socket import inet_ntop, AF_INET, AF_INET6
 from struct import pack
-import ctypes as ct
 from time import sleep
 from bcc import tcp
 
@@ -151,36 +150,9 @@
     if args.ebpf:
         exit()
 
-# event data
-class Data_ipv4(ct.Structure):
-    _fields_ = [
-        ("pid", ct.c_uint),
-        ("ip", ct.c_ulonglong),
-        ("saddr", ct.c_uint),
-        ("daddr", ct.c_uint),
-        ("sport", ct.c_ushort),
-        ("dport", ct.c_ushort),
-        ("state", ct.c_ubyte),
-        ("tcpflags", ct.c_ubyte),
-        ("stack_id", ct.c_ulong)
-    ]
-
-class Data_ipv6(ct.Structure):
-    _fields_ = [
-        ("pid", ct.c_uint),
-        ("ip", ct.c_ulonglong),
-        ("saddr", (ct.c_ulonglong * 2)),
-        ("daddr", (ct.c_ulonglong * 2)),
-        ("sport", ct.c_ushort),
-        ("dport", ct.c_ushort),
-        ("state", ct.c_ubyte),
-        ("tcpflags", ct.c_ubyte),
-        ("stack_id", ct.c_ulong)
-    ]
-
 # process event
 def print_ipv4_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data_ipv4)).contents
+    event = b["ipv4_events"].event(data)
     print("%-8s %-6d %-2d %-20s > %-20s %s (%s)" % (
         strftime("%H:%M:%S"), event.pid, event.ip,
         "%s:%d" % (inet_ntop(AF_INET, pack('I', event.saddr)), event.sport),
@@ -192,7 +164,7 @@
     print("")
 
 def print_ipv6_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data_ipv6)).contents
+    event = b["ipv6_events"].event(data)
     print("%-8s %-6d %-2d %-20s > %-20s %s (%s)" % (
         strftime("%H:%M:%S"), event.pid, event.ip,
         "%s:%d" % (inet_ntop(AF_INET6, event.saddr), event.sport),
diff --git a/tools/tcplife.py b/tools/tcplife.py
index 4639582..ed25155 100755
--- a/tools/tcplife.py
+++ b/tools/tcplife.py
@@ -27,7 +27,6 @@
 import argparse
 from socket import inet_ntop, ntohs, AF_INET, AF_INET6
 from struct import pack
-import ctypes as ct
 from time import strftime
 
 # arguments
@@ -391,35 +390,6 @@
     if args.ebpf:
         exit()
 
-# event data
-TASK_COMM_LEN = 16      # linux/sched.h
-
-class Data_ipv4(ct.Structure):
-    _fields_ = [
-        ("ts_us", ct.c_ulonglong),
-        ("pid", ct.c_uint),
-        ("saddr", ct.c_uint),
-        ("daddr", ct.c_uint),
-        ("ports", ct.c_ulonglong),
-        ("rx_b", ct.c_ulonglong),
-        ("tx_b", ct.c_ulonglong),
-        ("span_us", ct.c_ulonglong),
-        ("task", ct.c_char * TASK_COMM_LEN)
-    ]
-
-class Data_ipv6(ct.Structure):
-    _fields_ = [
-        ("ts_us", ct.c_ulonglong),
-        ("pid", ct.c_uint),
-        ("saddr", (ct.c_ulonglong * 2)),
-        ("daddr", (ct.c_ulonglong * 2)),
-        ("ports", ct.c_ulonglong),
-        ("rx_b", ct.c_ulonglong),
-        ("tx_b", ct.c_ulonglong),
-        ("span_us", ct.c_ulonglong),
-        ("task", ct.c_char * TASK_COMM_LEN)
-    ]
-
 #
 # Setup output formats
 #
@@ -439,7 +409,7 @@
 
 # process event
 def print_ipv4_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data_ipv4)).contents
+    event = b["ipv4_events"].event(data)
     global start_ts
     if args.time:
         if args.csv:
@@ -461,7 +431,7 @@
         event.tx_b / 1024, event.rx_b / 1024, float(event.span_us) / 1000))
 
 def print_ipv6_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data_ipv6)).contents
+    event = b["ipv6_events"].event(data)
     global start_ts
     if args.time:
         if args.csv:
diff --git a/tools/tcpretrans.py b/tools/tcpretrans.py
index 47ac8c1..4301b8e 100755
--- a/tools/tcpretrans.py
+++ b/tools/tcpretrans.py
@@ -21,7 +21,6 @@
 from time import strftime
 from socket import inet_ntop, AF_INET, AF_INET6
 from struct import pack
-import ctypes as ct
 from time import sleep
 
 # arguments
@@ -199,31 +198,6 @@
     if args.ebpf:
         exit()
 
-# event data
-class Data_ipv4(ct.Structure):
-    _fields_ = [
-        ("pid", ct.c_uint),
-        ("ip", ct.c_ulonglong),
-        ("saddr", ct.c_uint),
-        ("daddr", ct.c_uint),
-        ("lport", ct.c_ushort),
-        ("dport", ct.c_ushort),
-        ("state", ct.c_ulonglong),
-        ("type", ct.c_ulonglong)
-    ]
-
-class Data_ipv6(ct.Structure):
-    _fields_ = [
-        ("pid", ct.c_uint),
-        ("ip", ct.c_ulonglong),
-        ("saddr", (ct.c_ulonglong * 2)),
-        ("daddr", (ct.c_ulonglong * 2)),
-        ("lport", ct.c_ushort),
-        ("dport", ct.c_ushort),
-        ("state", ct.c_ulonglong),
-        ("type", ct.c_ulonglong)
-    ]
-
 # from bpf_text:
 type = {}
 type[1] = 'R'
@@ -246,7 +220,7 @@
 
 # process event
 def print_ipv4_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data_ipv4)).contents
+    event = b["ipv4_events"].event(data)
     print("%-8s %-6d %-2d %-20s %1s> %-20s %s" % (
         strftime("%H:%M:%S"), event.pid, event.ip,
         "%s:%d" % (inet_ntop(AF_INET, pack('I', event.saddr)), event.lport),
@@ -255,7 +229,7 @@
         tcpstate[event.state]))
 
 def print_ipv6_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data_ipv6)).contents
+    event = b["ipv6_events"].event(data)
     print("%-8s %-6d %-2d %-20s %1s> %-20s %s" % (
         strftime("%H:%M:%S"), event.pid, event.ip,
         "%s:%d" % (inet_ntop(AF_INET6, event.saddr), event.lport),
diff --git a/tools/tcpstates.py b/tools/tcpstates.py
index 4a21f02..9b25b09 100755
--- a/tools/tcpstates.py
+++ b/tools/tcpstates.py
@@ -20,7 +20,6 @@
 import argparse
 from socket import inet_ntop, AF_INET, AF_INET6
 from struct import pack
-import ctypes as ct
 from time import strftime, time
 from os import getuid
 
@@ -191,37 +190,6 @@
     if args.ebpf:
         exit()
 
-# event data
-TASK_COMM_LEN = 16      # linux/sched.h
-
-class Data_ipv4(ct.Structure):
-    _fields_ = [
-        ("ts_us", ct.c_ulonglong),
-        ("skaddr", ct.c_ulonglong),
-        ("saddr", ct.c_uint),
-        ("daddr", ct.c_uint),
-        ("span_us", ct.c_ulonglong),
-        ("pid", ct.c_uint),
-        ("ports", ct.c_uint),
-        ("oldstate", ct.c_uint),
-        ("newstate", ct.c_uint),
-        ("task", ct.c_char * TASK_COMM_LEN)
-    ]
-
-class Data_ipv6(ct.Structure):
-    _fields_ = [
-        ("ts_us", ct.c_ulonglong),
-        ("skaddr", ct.c_ulonglong),
-        ("saddr", (ct.c_ulonglong * 2)),
-        ("daddr", (ct.c_ulonglong * 2)),
-        ("span_us", ct.c_ulonglong),
-        ("pid", ct.c_uint),
-        ("ports", ct.c_uint),
-        ("oldstate", ct.c_uint),
-        ("newstate", ct.c_uint),
-        ("task", ct.c_char * TASK_COMM_LEN)
-    ]
-
 #
 # Setup output formats
 #
@@ -312,7 +280,7 @@
 
 # process event
 def print_ipv4_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data_ipv4)).contents
+    event = b["ipv4_events"].event(data)
     global start_ts
     if args.time:
         if args.csv:
@@ -337,7 +305,7 @@
         journal.send(**journal_fields(event, AF_INET))
 
 def print_ipv6_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data_ipv6)).contents
+    event = b["ipv6_events"].event(data)
     global start_ts
     if args.time:
         if args.csv:
diff --git a/tools/tcptop.py b/tools/tcptop.py
index e1eb241..b6e26e1 100755
--- a/tools/tcptop.py
+++ b/tools/tcptop.py
@@ -31,7 +31,6 @@
 from struct import pack
 from time import sleep, strftime
 from subprocess import call
-import ctypes as ct
 from collections import namedtuple, defaultdict
 
 # arguments
diff --git a/tools/tcptracer.py b/tools/tcptracer.py
index cc92c3f..e61fe9b 100755
--- a/tools/tcptracer.py
+++ b/tools/tcptracer.py
@@ -18,7 +18,6 @@
 from bcc import BPF
 
 import argparse as ap
-import ctypes
 from socket import inet_ntop, AF_INET, AF_INET6
 from struct import pack
 
@@ -493,45 +492,12 @@
 }
 """
 
-TASK_COMM_LEN = 16   # linux/sched.h
-
-
-class TCPIPV4Evt(ctypes.Structure):
-    _fields_ = [
-            ("ts_ns", ctypes.c_ulonglong),
-            ("type", ctypes.c_uint),
-            ("pid", ctypes.c_uint),
-            ("comm", ctypes.c_char * TASK_COMM_LEN),
-            ("ip", ctypes.c_ubyte),
-            ("saddr", ctypes.c_uint),
-            ("daddr", ctypes.c_uint),
-            ("sport", ctypes.c_ushort),
-            ("dport", ctypes.c_ushort),
-            ("netns", ctypes.c_uint)
-    ]
-
-
-class TCPIPV6Evt(ctypes.Structure):
-    _fields_ = [
-            ("ts_ns", ctypes.c_ulonglong),
-            ("type", ctypes.c_uint),
-            ("pid", ctypes.c_uint),
-            ("comm", ctypes.c_char * TASK_COMM_LEN),
-            ("ip", ctypes.c_ubyte),
-            ("saddr", (ctypes.c_ulong * 2)),
-            ("daddr", (ctypes.c_ulong * 2)),
-            ("sport", ctypes.c_ushort),
-            ("dport", ctypes.c_ushort),
-            ("netns", ctypes.c_uint)
-    ]
-
-
 verbose_types = {"C": "connect", "A": "accept",
                  "X": "close", "U": "unknown"}
 
 
 def print_ipv4_event(cpu, data, size):
-    event = ctypes.cast(data, ctypes.POINTER(TCPIPV4Evt)).contents
+    event = b["tcp_ipv4_event"].event(data)
     global start_ts
 
     if args.timestamp:
@@ -569,7 +535,7 @@
 
 
 def print_ipv6_event(cpu, data, size):
-    event = ctypes.cast(data, ctypes.POINTER(TCPIPV6Evt)).contents
+    event = b["tcp_ipv6_event"].event(data)
     global start_ts
     if args.timestamp:
         if start_ts == 0:
diff --git a/tools/ttysnoop.py b/tools/ttysnoop.py
index 07f272f..058dc7e 100755
--- a/tools/ttysnoop.py
+++ b/tools/ttysnoop.py
@@ -16,7 +16,6 @@
 
 from __future__ import print_function
 from bcc import BPF
-import ctypes as ct
 from subprocess import call
 import argparse
 from sys import argv
@@ -101,20 +100,12 @@
 # initialize BPF
 b = BPF(text=bpf_text)
 
-BUFSIZE = 256
-
-class Data(ct.Structure):
-    _fields_ = [
-        ("count", ct.c_int),
-        ("buf", ct.c_char * BUFSIZE)
-    ]
-
 if not args.noclear:
     call("clear")
 
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
     print("%s" % event.buf[0:event.count].decode('utf-8', 'replace'), end="")
     sys.stdout.flush()
 
diff --git a/tools/xfsslower.py b/tools/xfsslower.py
index b79527b..9fa1256 100755
--- a/tools/xfsslower.py
+++ b/tools/xfsslower.py
@@ -28,7 +28,6 @@
 from bcc import BPF
 import argparse
 from time import strftime
-import ctypes as ct
 
 # arguments
 examples = """examples:
@@ -240,24 +239,9 @@
     if args.ebpf:
         exit()
 
-# kernel->user event data: struct data_t
-DNAME_INLINE_LEN = 32   # linux/dcache.h
-TASK_COMM_LEN = 16      # linux/sched.h
-class Data(ct.Structure):
-    _fields_ = [
-        ("ts_us", ct.c_ulonglong),
-        ("type", ct.c_ulonglong),
-        ("size", ct.c_ulonglong),
-        ("offset", ct.c_ulonglong),
-        ("delta_us", ct.c_ulonglong),
-        ("pid", ct.c_ulonglong),
-        ("task", ct.c_char * TASK_COMM_LEN),
-        ("file", ct.c_char * DNAME_INLINE_LEN)
-    ]
-
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
 
     type = 'R'
     if event.type == 1:
diff --git a/tools/zfsslower.py b/tools/zfsslower.py
index 7bf160b..2f05b56 100755
--- a/tools/zfsslower.py
+++ b/tools/zfsslower.py
@@ -31,7 +31,6 @@
 from bcc import BPF
 import argparse
 from time import strftime
-import ctypes as ct
 
 # arguments
 examples = """examples:
@@ -236,24 +235,9 @@
     if args.ebpf:
         exit()
 
-# kernel->user event data: struct data_t
-DNAME_INLINE_LEN = 32   # linux/dcache.h
-TASK_COMM_LEN = 16      # linux/sched.h
-class Data(ct.Structure):
-    _fields_ = [
-        ("ts_us", ct.c_ulonglong),
-        ("type", ct.c_ulonglong),
-        ("size", ct.c_ulonglong),
-        ("offset", ct.c_ulonglong),
-        ("delta_us", ct.c_ulonglong),
-        ("pid", ct.c_ulonglong),
-        ("task", ct.c_char * TASK_COMM_LEN),
-        ("file", ct.c_char * DNAME_INLINE_LEN)
-    ]
-
 # process event
 def print_event(cpu, data, size):
-    event = ct.cast(data, ct.POINTER(Data)).contents
+    event = b["events"].event(data)
 
     type = 'R'
     if event.type == 1: