summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-19 10:12:32 +0300
committerPaul Buetow <paul@buetow.org>2026-05-19 10:12:32 +0300
commit127516b4bf63dc922df222825a9a6a1d7eacc214 (patch)
tree3839a2f6a7f4f1bc713690678fc003d4e2be8a8c /internal
parent32a19cf9fb1344c9b1a61054d7cf2c90edc3708a (diff)
u6: add socket/socketpair kind scaffolding and wiring
Diffstat (limited to 'internal')
-rw-r--r--internal/bench_components_test.go2
-rw-r--r--internal/c/generated_tracepoints.c25
-rw-r--r--internal/c/generated_tracepoints_result.txt4
-rw-r--r--internal/c/types.h28
-rw-r--r--internal/event/interface_assertions.go6
-rw-r--r--internal/eventloop_exit.go53
-rw-r--r--internal/eventloop_runtime.go18
-rw-r--r--internal/eventloop_socket_test.go79
-rw-r--r--internal/generate/bpfhandler.go12
-rw-r--r--internal/generate/classify.go6
-rw-r--r--internal/generate/classify_test.go17
-rw-r--r--internal/generate/codegen_test.go28
-rw-r--r--internal/generate/kindregistry.go2
-rw-r--r--internal/generate/testdata.go31
-rw-r--r--internal/types/fastdecode.go42
-rw-r--r--internal/types/fastdecode_test.go28
-rw-r--r--internal/types/generated_types.go146
-rw-r--r--internal/types/types_test.go58
18 files changed, 572 insertions, 13 deletions
diff --git a/internal/bench_components_test.go b/internal/bench_components_test.go
index c7b724e..64438b9 100644
--- a/internal/bench_components_test.go
+++ b/internal/bench_components_test.go
@@ -108,6 +108,8 @@ func BenchmarkRawHandlerLookup(b *testing.B) {
types.ENTER_PATH_EVENT,
types.ENTER_FCNTL_EVENT,
types.ENTER_DUP3_EVENT,
+ types.ENTER_SOCKET_EVENT,
+ types.ENTER_SOCKETPAIR_EVENT,
}
b.ResetTimer()
diff --git a/internal/c/generated_tracepoints.c b/internal/c/generated_tracepoints.c
index 980f91d..0974d77 100644
--- a/internal/c/generated_tracepoints.c
+++ b/internal/c/generated_tracepoints.c
@@ -736,22 +736,25 @@
#define SYS_ENTER_RT_SIGRETURN 57
#define SYS_EXIT_RT_SIGRETURN 56
-/// sys_enter_socket is a struct null_event
+/// sys_enter_socket is a struct socket_event
SEC("tracepoint/syscalls/sys_enter_socket")
int handle_sys_enter_socket(struct syscall_trace_enter *ctx) {
__u32 pid, tid;
if (filter(&pid, &tid))
return 0;
- struct null_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct null_event), 0);
+ struct socket_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct socket_event), 0);
if (!ev)
return 0;
- ev->event_type = ENTER_NULL_EVENT;
+ ev->event_type = ENTER_SOCKET_EVENT;
ev->trace_id = SYS_ENTER_SOCKET;
ev->pid = pid;
ev->tid = tid;
ev->time = bpf_ktime_get_boot_ns();
+ ev->family = (__s32)ctx->args[0];
+ ev->type = (__s32)ctx->args[1];
+ ev->protocol = (__s32)ctx->args[2];
bpf_ringbuf_submit(ev, 0);
return 0;
@@ -780,22 +783,32 @@ int handle_sys_exit_socket(struct syscall_trace_exit *ctx) {
return 0;
}
-/// sys_enter_socketpair is a struct null_event
+/// sys_enter_socketpair is a struct socketpair_event
SEC("tracepoint/syscalls/sys_enter_socketpair")
int handle_sys_enter_socketpair(struct syscall_trace_enter *ctx) {
__u32 pid, tid;
if (filter(&pid, &tid))
return 0;
- struct null_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct null_event), 0);
+ struct socketpair_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct socketpair_event), 0);
if (!ev)
return 0;
- ev->event_type = ENTER_NULL_EVENT;
+ ev->event_type = ENTER_SOCKETPAIR_EVENT;
ev->trace_id = SYS_ENTER_SOCKETPAIR;
ev->pid = pid;
ev->tid = tid;
ev->time = bpf_ktime_get_boot_ns();
+ int sv[2];
+ __builtin_memset(&sv, 0xff, sizeof(sv));
+ if (ctx->args[3] != 0) {
+ bpf_probe_read_user(&sv, sizeof(sv), (void *)ctx->args[3]);
+ }
+ ev->family = (__s32)ctx->args[0];
+ ev->type = (__s32)ctx->args[1];
+ ev->protocol = (__s32)ctx->args[2];
+ ev->sv0 = (__s32)sv[0];
+ ev->sv1 = (__s32)sv[1];
bpf_ringbuf_submit(ev, 0);
return 0;
diff --git a/internal/c/generated_tracepoints_result.txt b/internal/c/generated_tracepoints_result.txt
index ea4f2d1..2d6e54c 100644
--- a/internal/c/generated_tracepoints_result.txt
+++ b/internal/c/generated_tracepoints_result.txt
@@ -316,8 +316,8 @@ sys_enter_shutdown is a struct fd_event
sys_enter_sigaltstack is a struct null_event
sys_enter_signalfd is a struct null_event
sys_enter_signalfd4 is a struct null_event
-sys_enter_socket is a struct null_event
-sys_enter_socketpair is a struct null_event
+sys_enter_socket is a struct socket_event
+sys_enter_socketpair is a struct socketpair_event
sys_enter_splice is a struct null_event
sys_enter_statfs is a struct path_event
sys_enter_statmount is a struct null_event
diff --git a/internal/c/types.h b/internal/c/types.h
index 18ffe6a..ddb2dca 100644
--- a/internal/c/types.h
+++ b/internal/c/types.h
@@ -21,6 +21,10 @@
#define EXIT_DUP3_EVENT 16
#define ENTER_OPEN_BY_HANDLE_AT_EVENT 17
#define EXIT_OPEN_BY_HANDLE_AT_EVENT 18
+#define ENTER_SOCKET_EVENT 19
+#define EXIT_SOCKET_EVENT 20
+#define ENTER_SOCKETPAIR_EVENT 21
+#define EXIT_SOCKETPAIR_EVENT 22
#define UNCLASSIFIED 0
#define READ_CLASSIFIED 1
@@ -114,3 +118,27 @@ struct open_by_handle_at_event {
__u32 tid;
__s32 flags;
};
+
+struct socket_event {
+ __u32 event_type;
+ __u32 trace_id;
+ __u64 time;
+ __u32 pid;
+ __u32 tid;
+ __s32 family;
+ __s32 type;
+ __s32 protocol;
+};
+
+struct socketpair_event {
+ __u32 event_type;
+ __u32 trace_id;
+ __u64 time;
+ __u32 pid;
+ __u32 tid;
+ __s32 family;
+ __s32 type;
+ __s32 protocol;
+ __s32 sv0;
+ __s32 sv1;
+};
diff --git a/internal/event/interface_assertions.go b/internal/event/interface_assertions.go
index 77a43ea..3dce64d 100644
--- a/internal/event/interface_assertions.go
+++ b/internal/event/interface_assertions.go
@@ -41,4 +41,10 @@ var (
// *types.OpenByHandleAtEvent carries the mount-fd and flags for
// open_by_handle_at syscalls.
_ Event = (*types.OpenByHandleAtEvent)(nil)
+
+ // *types.SocketEvent carries socket domain/type/protocol metadata.
+ _ Event = (*types.SocketEvent)(nil)
+
+ // *types.SocketpairEvent carries socketpair domain/type/protocol metadata.
+ _ Event = (*types.SocketpairEvent)(nil)
)
diff --git a/internal/eventloop_exit.go b/internal/eventloop_exit.go
index a0cc675..e13d3c5 100644
--- a/internal/eventloop_exit.go
+++ b/internal/eventloop_exit.go
@@ -26,6 +26,10 @@ func (e *eventLoop) handleTracepointExit(ep *event.Pair) bool {
return e.handleDup3Exit(ep, ev)
case *types.OpenByHandleAtEvent:
return e.handleOpenByHandleAtExit(ep, ev)
+ case *types.SocketEvent:
+ return e.handleSocketExit(ep, ev)
+ case *types.SocketpairEvent:
+ return e.handleSocketpairExit(ep, ev)
case *types.NullEvent:
return e.handleNullExit(ep, ev)
case *types.FcntlEvent:
@@ -216,6 +220,55 @@ func (e *eventLoop) handleOpenByHandleAtExit(ep *event.Pair, openByHandleEv *typ
return true
}
+func (e *eventLoop) handleSocketExit(ep *event.Pair, socketEv *types.SocketEvent) bool {
+ retEvent, ok := ep.ExitEv.(*types.RetEvent)
+ if !ok {
+ e.recyclePair(ep, "Dropped malformed socket exit event")
+ return false
+ }
+
+ if fd := int32(retEvent.Ret); fd >= 0 {
+ fdFile := file.NewFd(fd, socketDescriptorName(socketEv.Family, socketEv.Type, socketEv.Protocol), -1)
+ e.fdState().set(fd, fdFile)
+ ep.File = fdFile
+ }
+ ep.Comm = e.comm(socketEv.GetTid())
+ return true
+}
+
+func (e *eventLoop) handleSocketpairExit(ep *event.Pair, socketpairEv *types.SocketpairEvent) bool {
+ retEvent, ok := ep.ExitEv.(*types.RetEvent)
+ if !ok {
+ e.recyclePair(ep, "Dropped malformed socketpair exit event")
+ return false
+ }
+
+ if retEvent.Ret == 0 {
+ if socketpairEv.Sv0 >= 0 {
+ fdFile := file.NewFd(socketpairEv.Sv0, socketDescriptorName(socketpairEv.Family, socketpairEv.Type, socketpairEv.Protocol), -1)
+ e.fdState().set(socketpairEv.Sv0, fdFile)
+ ep.File = fdFile
+ }
+ if socketpairEv.Sv1 >= 0 {
+ fdFile := file.NewFd(socketpairEv.Sv1, socketDescriptorName(socketpairEv.Family, socketpairEv.Type, socketpairEv.Protocol), -1)
+ e.fdState().set(socketpairEv.Sv1, fdFile)
+ if ep.File == nil {
+ ep.File = fdFile
+ }
+ }
+ }
+ ep.Comm = e.comm(socketpairEv.GetTid())
+ if !e.Filter().MatchPair(ep) {
+ ep.Recycle()
+ return false
+ }
+ return true
+}
+
+func socketDescriptorName(family, typ, protocol int32) string {
+ return fmt.Sprintf("socket:%d:%d:%d", family, typ, protocol)
+}
+
func (e *eventLoop) handleNullExit(ep *event.Pair, nullEv *types.NullEvent) bool {
if ep.Is(types.SYS_ENTER_IO_URING_SETUP) {
retEvent, ok := ep.ExitEv.(*types.RetEvent)
diff --git a/internal/eventloop_runtime.go b/internal/eventloop_runtime.go
index c285507..d9acb23 100644
--- a/internal/eventloop_runtime.go
+++ b/internal/eventloop_runtime.go
@@ -146,6 +146,7 @@ func (e *eventLoop) initRawHandlers() {
e.registerRetHandlers()
e.registerNamePathHandlers()
e.registerMiscHandlers()
+ e.registerSocketHandlers()
}
// registerOpenHandlers wires enter/exit handlers for open-family events.
@@ -262,6 +263,23 @@ func (e *eventLoop) registerMiscHandlers() {
}
}
+func (e *eventLoop) registerSocketHandlers() {
+ e.rawHandlers[types.ENTER_SOCKET_EVENT] = func(raw []byte, _ chan<- *event.Pair) {
+ socketEv, ok := decodeRawEvent(e, types.ENTER_SOCKET_EVENT, raw, types.NewSocketEventFast)
+ if !ok {
+ return
+ }
+ e.tracepointEntered(socketEv)
+ }
+ e.rawHandlers[types.ENTER_SOCKETPAIR_EVENT] = func(raw []byte, _ chan<- *event.Pair) {
+ socketpairEv, ok := decodeRawEvent(e, types.ENTER_SOCKETPAIR_EVENT, raw, types.NewSocketpairEventFast)
+ if !ok {
+ return
+ }
+ e.tracepointEntered(socketpairEv)
+ }
+}
+
func decodeRawEvent[T any](e *eventLoop, eventType types.EventType, raw []byte, decode func([]byte) *T) (*T, bool) {
decoded := decode(raw)
if decoded == nil {
diff --git a/internal/eventloop_socket_test.go b/internal/eventloop_socket_test.go
new file mode 100644
index 0000000..6b76813
--- /dev/null
+++ b/internal/eventloop_socket_test.go
@@ -0,0 +1,79 @@
+package internal
+
+import (
+ "testing"
+
+ "ior/internal/event"
+ "ior/internal/types"
+)
+
+func TestHandleSocketExitTracksReturnedFd(t *testing.T) {
+ el := mustNewEventLoop(t, eventLoopConfig{})
+
+ enter := &types.SocketEvent{
+ EventType: types.ENTER_SOCKET_EVENT,
+ TraceId: types.SYS_ENTER_SOCKET,
+ Time: 100,
+ Pid: 42,
+ Tid: 43,
+ Family: 1,
+ Type: 2,
+ Protocol: 0,
+ }
+ exit := &types.RetEvent{
+ EventType: types.EXIT_SOCKET_EVENT,
+ TraceId: types.SYS_EXIT_SOCKET,
+ Time: 200,
+ Ret: 55,
+ Pid: 42,
+ Tid: 43,
+ }
+ ep := &event.Pair{EnterEv: enter, ExitEv: exit}
+
+ if ok := el.handleSocketExit(ep, enter); !ok {
+ t.Fatal("handleSocketExit returned false")
+ }
+ verifyFileDescriptor(t, el, 55, "socket:1:2:0")
+}
+
+func TestHandleSocketpairExitTracksReturnedFds(t *testing.T) {
+ el := mustNewEventLoop(t, eventLoopConfig{})
+
+ enter := &types.SocketpairEvent{
+ EventType: types.ENTER_SOCKETPAIR_EVENT,
+ TraceId: types.SYS_ENTER_SOCKETPAIR,
+ Time: 100,
+ Pid: 77,
+ Tid: 78,
+ Family: 1,
+ Type: 1,
+ Protocol: 0,
+ Sv0: 61,
+ Sv1: 62,
+ }
+ exit := &types.RetEvent{
+ EventType: types.EXIT_SOCKETPAIR_EVENT,
+ TraceId: types.SYS_EXIT_SOCKETPAIR,
+ Time: 200,
+ Ret: 0,
+ Pid: 77,
+ Tid: 78,
+ }
+ ep := &event.Pair{EnterEv: enter, ExitEv: exit}
+
+ if ok := el.handleSocketpairExit(ep, enter); !ok {
+ t.Fatal("handleSocketpairExit returned false")
+ }
+ verifyFileDescriptor(t, el, 61, "socket:1:1:0")
+ verifyFileDescriptor(t, el, 62, "socket:1:1:0")
+}
+
+func TestInitRawHandlersRegistersSocketEvents(t *testing.T) {
+ el := mustNewEventLoop(t, eventLoopConfig{})
+ if _, ok := el.rawHandlers[types.ENTER_SOCKET_EVENT]; !ok {
+ t.Fatal("ENTER_SOCKET_EVENT handler is not registered")
+ }
+ if _, ok := el.rawHandlers[types.ENTER_SOCKETPAIR_EVENT]; !ok {
+ t.Fatal("ENTER_SOCKETPAIR_EVENT handler is not registered")
+ }
+}
diff --git a/internal/generate/bpfhandler.go b/internal/generate/bpfhandler.go
index 549e80b..6c9c314 100644
--- a/internal/generate/bpfhandler.go
+++ b/internal/generate/bpfhandler.go
@@ -73,6 +73,10 @@ func generateExtra(tp GeneratedTracepoint, isEnter bool) string {
return " ev->fd = (__s32)ctx->args[0];\n ev->flags = (__s32)ctx->args[2];\n"
case KindOpenByHandleAt:
return " ev->flags = (__s32)ctx->args[2];\n"
+ case KindSocket:
+ return generateExtraSocket()
+ case KindSocketpair:
+ return generateExtraSocketpair()
case KindOpen:
return generateExtraOpen(f)
case KindPathname:
@@ -149,6 +153,14 @@ func generateExtraFcntl(f *Format) string {
)
}
+func generateExtraSocket() string {
+ return " ev->family = (__s32)ctx->args[0];\n ev->type = (__s32)ctx->args[1];\n ev->protocol = (__s32)ctx->args[2];\n"
+}
+
+func generateExtraSocketpair() string {
+ return " int sv[2];\n __builtin_memset(&sv, 0xff, sizeof(sv));\n if (ctx->args[3] != 0) {\n bpf_probe_read_user(&sv, sizeof(sv), (void *)ctx->args[3]);\n }\n ev->family = (__s32)ctx->args[0];\n ev->type = (__s32)ctx->args[1];\n ev->protocol = (__s32)ctx->args[2];\n ev->sv0 = (__s32)sv[0];\n ev->sv1 = (__s32)sv[1];\n"
+}
+
// eventStructName returns the C struct name for a TracepointKind. The mapping
// is driven by kindRegistry so adding a new kind only requires a registry entry.
func eventStructName(kind TracepointKind) string {
diff --git a/internal/generate/classify.go b/internal/generate/classify.go
index 7768ea7..68cd722 100644
--- a/internal/generate/classify.go
+++ b/internal/generate/classify.go
@@ -15,6 +15,8 @@ const (
KindNull
KindDup3
KindOpenByHandleAt
+ KindSocket
+ KindSocketpair
)
type RetClassification string
@@ -79,6 +81,10 @@ func classifyNameOnly(name string) (ClassificationResult, bool) {
return ClassificationResult{Kind: KindNull}, true
case "sys_enter_getcwd":
return ClassificationResult{Kind: KindNull}, true
+ case "sys_enter_socket":
+ return ClassificationResult{Kind: KindSocket}, true
+ case "sys_enter_socketpair":
+ return ClassificationResult{Kind: KindSocketpair}, true
}
if strings.HasPrefix(name, "sys_enter_io_") {
return ClassificationResult{Kind: KindNull}, true
diff --git a/internal/generate/classify_test.go b/internal/generate/classify_test.go
index ea7d662..ce6eff1 100644
--- a/internal/generate/classify_test.go
+++ b/internal/generate/classify_test.go
@@ -244,10 +244,17 @@ func TestClassifyFdAccept(t *testing.T) {
}
}
-func TestClassifySocketRequiresGenerationFallback(t *testing.T) {
+func TestClassifySocket(t *testing.T) {
r := classifyFromData(t, FormatSocket)
- if r.Kind != KindNone {
- t.Errorf("socket: got kind %d, want KindNone before generation fallback", r.Kind)
+ if r.Kind != KindSocket {
+ t.Errorf("socket: got kind %d, want KindSocket", r.Kind)
+ }
+}
+
+func TestClassifySocketpair(t *testing.T) {
+ r := classifyFromData(t, FormatSocketpair)
+ if r.Kind != KindSocketpair {
+ t.Errorf("socketpair: got kind %d, want KindSocketpair", r.Kind)
}
}
@@ -288,7 +295,8 @@ func TestClassifySyscallPairAccepted(t *testing.T) {
{"mknod", FormatMknod, FormatExitMknod, KindPathname},
{"execve", FormatExecve, FormatExitExecve, KindPathname},
{"accept", FormatAccept, FormatExitAccept, KindFd},
- {"socket", FormatSocket, FormatExitSocket, KindNull},
+ {"socket", FormatSocket, FormatExitSocket, KindSocket},
+ {"socketpair", FormatSocketpair, FormatExitSocketpair, KindSocketpair},
{"kill", FormatKill, FormatExitKill, KindNull},
}
@@ -314,6 +322,7 @@ func TestClassifySyscallPairEmitsAllFamilies(t *testing.T) {
{"execve", FormatExecve, FormatExitExecve, FamilyProcess},
{"accept", FormatAccept, FormatExitAccept, FamilyNetwork},
{"socket", FormatSocket, FormatExitSocket, FamilyNetwork},
+ {"socketpair", FormatSocketpair, FormatExitSocketpair, FamilyNetwork},
{"kill", FormatKill, FormatExitKill, FamilySignals},
}
diff --git a/internal/generate/codegen_test.go b/internal/generate/codegen_test.go
index a448162..f87a6dc 100644
--- a/internal/generate/codegen_test.go
+++ b/internal/generate/codegen_test.go
@@ -185,6 +185,28 @@ func TestGenerateOpenByHandleAtHandler(t *testing.T) {
requireContains(t, output, "ev->flags = (__s32)ctx->args[2];")
}
+func TestGenerateSocketHandler(t *testing.T) {
+ output := generateFromPair(t, FormatSocket, FormatExitSocket)
+
+ requireContains(t, output, "struct socket_event *ev")
+ requireContains(t, output, "ev->event_type = ENTER_SOCKET_EVENT;")
+ requireContains(t, output, "ev->family = (__s32)ctx->args[0];")
+ requireContains(t, output, "ev->type = (__s32)ctx->args[1];")
+ requireContains(t, output, "ev->protocol = (__s32)ctx->args[2];")
+}
+
+func TestGenerateSocketpairHandler(t *testing.T) {
+ output := generateFromPair(t, FormatSocketpair, FormatExitSocketpair)
+
+ requireContains(t, output, "struct socketpair_event *ev")
+ requireContains(t, output, "ev->event_type = ENTER_SOCKETPAIR_EVENT;")
+ requireContains(t, output, "int sv[2];")
+ requireContains(t, output, "bpf_probe_read_user(&sv, sizeof(sv), (void *)ctx->args[3]);")
+ requireContains(t, output, "ev->family = (__s32)ctx->args[0];")
+ requireContains(t, output, "ev->sv0 = (__s32)sv[0];")
+ requireContains(t, output, "ev->sv1 = (__s32)sv[1];")
+}
+
func TestGenerateNameToHandleAtHandler(t *testing.T) {
output := generateFromPair(t, FormatNameToHandleAt, FormatExitNameToHandleAt)
@@ -292,6 +314,8 @@ func TestGenerateAllEventTypes(t *testing.T) {
{KindNull, "ENTER_NULL_EVENT", "EXIT_NULL_EVENT"},
{KindDup3, "ENTER_DUP3_EVENT", "EXIT_DUP3_EVENT"},
{KindOpenByHandleAt, "ENTER_OPEN_BY_HANDLE_AT_EVENT", "EXIT_OPEN_BY_HANDLE_AT_EVENT"},
+ {KindSocket, "ENTER_SOCKET_EVENT", "EXIT_SOCKET_EVENT"},
+ {KindSocketpair, "ENTER_SOCKETPAIR_EVENT", "EXIT_SOCKETPAIR_EVENT"},
}
for _, tt := range tests {
@@ -318,6 +342,8 @@ func TestEventStructNames(t *testing.T) {
{KindNull, "null_event"},
{KindDup3, "dup3_event"},
{KindOpenByHandleAt, "open_by_handle_at_event"},
+ {KindSocket, "socket_event"},
+ {KindSocketpair, "socketpair_event"},
}
for _, tt := range tests {
@@ -336,7 +362,7 @@ func TestEnterReject(t *testing.T) {
t.Error("KindNone should be enter-rejected")
}
- accepted := []TracepointKind{KindFd, KindOpen, KindPathname, KindName, KindFcntl, KindNull, KindDup3, KindOpenByHandleAt}
+ accepted := []TracepointKind{KindFd, KindOpen, KindPathname, KindName, KindFcntl, KindNull, KindDup3, KindOpenByHandleAt, KindSocket, KindSocketpair}
for _, k := range accepted {
if isEnterRejected(k) {
t.Errorf("kind %d should NOT be enter-rejected", k)
diff --git a/internal/generate/kindregistry.go b/internal/generate/kindregistry.go
index 86b77aa..f716489 100644
--- a/internal/generate/kindregistry.go
+++ b/internal/generate/kindregistry.go
@@ -25,6 +25,8 @@ var kindRegistry = map[TracepointKind]kindMeta{
KindNull: {structName: "null_event", enterAccepted: true},
KindDup3: {structName: "dup3_event", enterAccepted: true},
KindOpenByHandleAt: {structName: "open_by_handle_at_event", enterAccepted: true},
+ KindSocket: {structName: "socket_event", enterAccepted: true},
+ KindSocketpair: {structName: "socketpair_event", enterAccepted: true},
// KindNone is intentionally absent: it represents "unclassified" and is
// never enter-accepted. lookupKind returns the zero kindMeta (enterAccepted=false)
// for any unregistered kind, so KindNone is implicitly rejected.
diff --git a/internal/generate/testdata.go b/internal/generate/testdata.go
index a9bedc6..e363a68 100644
--- a/internal/generate/testdata.go
+++ b/internal/generate/testdata.go
@@ -823,6 +823,37 @@ format:
print fmt: "0x%lx", REC->ret
`
+const FormatSocketpair = `name: sys_enter_socketpair
+ID: 1816
+format:
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+
+ field:int __syscall_nr; offset:8; size:4; signed:1;
+ field:int family; offset:16; size:8; signed:0;
+ field:int type; offset:24; size:8; signed:0;
+ field:int protocol; offset:32; size:8; signed:0;
+ field:int * usockvec; offset:40; size:8; signed:0;
+
+print fmt: "family: 0x%08lx, type: 0x%08lx, protocol: 0x%08lx, usockvec: 0x%08lx", ((unsigned long)(REC->family)), ((unsigned long)(REC->type)), ((unsigned long)(REC->protocol)), ((unsigned long)(REC->usockvec))
+`
+
+const FormatExitSocketpair = `name: sys_exit_socketpair
+ID: 1815
+format:
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+
+ field:int __syscall_nr; offset:8; size:4; signed:1;
+ field:long ret; offset:16; size:8; signed:1;
+
+print fmt: "0x%lx", REC->ret
+`
+
const FormatPread64 = `name: sys_enter_pread64
ID: 840
format:
diff --git a/internal/types/fastdecode.go b/internal/types/fastdecode.go
index a0ce5f1..b464013 100644
--- a/internal/types/fastdecode.go
+++ b/internal/types/fastdecode.go
@@ -12,6 +12,8 @@ const (
fcntlEventSize = 40
dup3EventSize = 32
openByHandleAtEventSize = 28
+ socketEventSize = 36
+ socketpairEventSize = 44
)
func NewOpenEventFast(raw []byte) *OpenEvent {
@@ -172,3 +174,43 @@ func NewOpenByHandleAtEventFast(raw []byte) *OpenByHandleAtEvent {
o.Flags = int32(binary.LittleEndian.Uint32(raw[24:28]))
return o
}
+
+func NewSocketEventFast(raw []byte) *SocketEvent {
+ if len(raw) < socketEventSize {
+ return nil
+ }
+ if len(raw) != socketEventSize {
+ return NewSocketEvent(raw)
+ }
+ s := poolOfSocketEvents.Get().(*SocketEvent)
+ s.EventType = EventType(binary.LittleEndian.Uint32(raw[0:4]))
+ s.TraceId = TraceId(binary.LittleEndian.Uint32(raw[4:8]))
+ s.Time = binary.LittleEndian.Uint64(raw[8:16])
+ s.Pid = binary.LittleEndian.Uint32(raw[16:20])
+ s.Tid = binary.LittleEndian.Uint32(raw[20:24])
+ s.Family = int32(binary.LittleEndian.Uint32(raw[24:28]))
+ s.Type = int32(binary.LittleEndian.Uint32(raw[28:32]))
+ s.Protocol = int32(binary.LittleEndian.Uint32(raw[32:36]))
+ return s
+}
+
+func NewSocketpairEventFast(raw []byte) *SocketpairEvent {
+ if len(raw) < socketpairEventSize {
+ return nil
+ }
+ if len(raw) != socketpairEventSize {
+ return NewSocketpairEvent(raw)
+ }
+ s := poolOfSocketpairEvents.Get().(*SocketpairEvent)
+ s.EventType = EventType(binary.LittleEndian.Uint32(raw[0:4]))
+ s.TraceId = TraceId(binary.LittleEndian.Uint32(raw[4:8]))
+ s.Time = binary.LittleEndian.Uint64(raw[8:16])
+ s.Pid = binary.LittleEndian.Uint32(raw[16:20])
+ s.Tid = binary.LittleEndian.Uint32(raw[20:24])
+ s.Family = int32(binary.LittleEndian.Uint32(raw[24:28]))
+ s.Type = int32(binary.LittleEndian.Uint32(raw[28:32]))
+ s.Protocol = int32(binary.LittleEndian.Uint32(raw[32:36]))
+ s.Sv0 = int32(binary.LittleEndian.Uint32(raw[36:40]))
+ s.Sv1 = int32(binary.LittleEndian.Uint32(raw[40:44]))
+ return s
+}
diff --git a/internal/types/fastdecode_test.go b/internal/types/fastdecode_test.go
index f40faeb..5279130 100644
--- a/internal/types/fastdecode_test.go
+++ b/internal/types/fastdecode_test.go
@@ -124,6 +124,32 @@ func TestFastDecodersMatchGeneratedDecoders(t *testing.T) {
t.Fatalf("open_by_handle_at decode mismatch")
}
})
+
+ t.Run("SocketEvent", func(t *testing.T) {
+ ev := &SocketEvent{EventType: ENTER_SOCKET_EVENT, TraceId: SYS_ENTER_SOCKET, Time: 1, Pid: 2, Tid: 3, Family: 1, Type: 2, Protocol: 3}
+ raw, _ := ev.Bytes()
+
+ slow := NewSocketEvent(raw)
+ fast := NewSocketEventFast(raw)
+ defer slow.Recycle()
+ defer fast.Recycle()
+ if !slow.Equals(fast) {
+ t.Fatalf("socket decode mismatch")
+ }
+ })
+
+ t.Run("SocketpairEvent", func(t *testing.T) {
+ ev := &SocketpairEvent{EventType: ENTER_SOCKETPAIR_EVENT, TraceId: SYS_ENTER_SOCKETPAIR, Time: 1, Pid: 2, Tid: 3, Family: 1, Type: 2, Protocol: 0, Sv0: 10, Sv1: 11}
+ raw, _ := ev.Bytes()
+
+ slow := NewSocketpairEvent(raw)
+ fast := NewSocketpairEventFast(raw)
+ defer slow.Recycle()
+ defer fast.Recycle()
+ if !slow.Equals(fast) {
+ t.Fatalf("socketpair decode mismatch")
+ }
+ })
}
func TestFastDecodersReturnNilOnShortPayload(t *testing.T) {
@@ -140,6 +166,8 @@ func TestFastDecodersReturnNilOnShortPayload(t *testing.T) {
{name: "FcntlEvent", decode: func(raw []byte) bool { return NewFcntlEventFast(raw) == nil }},
{name: "Dup3Event", decode: func(raw []byte) bool { return NewDup3EventFast(raw) == nil }},
{name: "OpenByHandleAtEvent", decode: func(raw []byte) bool { return NewOpenByHandleAtEventFast(raw) == nil }},
+ {name: "SocketEvent", decode: func(raw []byte) bool { return NewSocketEventFast(raw) == nil }},
+ {name: "SocketpairEvent", decode: func(raw []byte) bool { return NewSocketpairEventFast(raw) == nil }},
}
for _, tc := range cases {
diff --git a/internal/types/generated_types.go b/internal/types/generated_types.go
index 7eeac21..fb4dd36 100644
--- a/internal/types/generated_types.go
+++ b/internal/types/generated_types.go
@@ -86,6 +86,10 @@ const ENTER_DUP3_EVENT = 15
const EXIT_DUP3_EVENT = 16
const ENTER_OPEN_BY_HANDLE_AT_EVENT = 17
const EXIT_OPEN_BY_HANDLE_AT_EVENT = 18
+const ENTER_SOCKET_EVENT = 19
+const EXIT_SOCKET_EVENT = 20
+const ENTER_SOCKETPAIR_EVENT = 21
+const EXIT_SOCKETPAIR_EVENT = 22
const UNCLASSIFIED = 0
const READ_CLASSIFIED = 1
const WRITE_CLASSIFIED = 2
@@ -1442,3 +1446,145 @@ func (o *OpenByHandleAtEvent) Bytes() ([]byte, error) {
func (o *OpenByHandleAtEvent) Recycle() {
poolOfOpenByHandleAtEvents.Put(o)
}
+
+type SocketEvent struct {
+ EventType EventType
+ TraceId TraceId
+ Time uint64
+ Pid uint32
+ Tid uint32
+ Family int32
+ Type int32
+ Protocol int32
+}
+
+func (s SocketEvent) String() string {
+ return fmt.Sprintf("EventType:%v TraceId:%v Time:%v Pid:%v Tid:%v Family:%v Type:%v Protocol:%v", s.EventType, s.TraceId, s.Time, s.Pid, s.Tid, s.Family, s.Type, s.Protocol)
+}
+
+func (s SocketEvent) Equals(other any) bool {
+ otherConcrete, ok := other.(*SocketEvent)
+ if !ok {
+ return false
+ }
+ return s.EventType == otherConcrete.EventType && s.TraceId == otherConcrete.TraceId && s.Time == otherConcrete.Time && s.Pid == otherConcrete.Pid && s.Tid == otherConcrete.Tid && s.Family == otherConcrete.Family && s.Type == otherConcrete.Type && s.Protocol == otherConcrete.Protocol
+}
+
+func (s *SocketEvent) GetEventType() EventType {
+ return s.EventType
+}
+
+func (s *SocketEvent) GetTraceId() TraceId {
+ return s.TraceId
+}
+
+func (s *SocketEvent) GetPid() uint32 {
+ return s.Pid
+}
+
+func (s *SocketEvent) GetTid() uint32 {
+ return s.Tid
+}
+
+func (s *SocketEvent) GetTime() uint64 {
+ return s.Time
+}
+
+var poolOfSocketEvents = sync.Pool{
+ New: func() any { return &SocketEvent{} },
+}
+
+func NewSocketEvent(raw []byte) *SocketEvent {
+ s := poolOfSocketEvents.Get().(*SocketEvent)
+ if err := binary.Read(bytes.NewReader(raw), binary.LittleEndian, s); err != nil {
+ *s = SocketEvent{}
+ poolOfSocketEvents.Put(s)
+ return nil
+ }
+ return s
+}
+
+func (s *SocketEvent) Bytes() ([]byte, error) {
+ buf := new(bytes.Buffer)
+ err := binary.Write(buf, binary.LittleEndian, s)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+func (s *SocketEvent) Recycle() {
+ poolOfSocketEvents.Put(s)
+}
+
+type SocketpairEvent struct {
+ EventType EventType
+ TraceId TraceId
+ Time uint64
+ Pid uint32
+ Tid uint32
+ Family int32
+ Type int32
+ Protocol int32
+ Sv0 int32
+ Sv1 int32
+}
+
+func (s SocketpairEvent) String() string {
+ return fmt.Sprintf("EventType:%v TraceId:%v Time:%v Pid:%v Tid:%v Family:%v Type:%v Protocol:%v Sv0:%v Sv1:%v", s.EventType, s.TraceId, s.Time, s.Pid, s.Tid, s.Family, s.Type, s.Protocol, s.Sv0, s.Sv1)
+}
+
+func (s SocketpairEvent) Equals(other any) bool {
+ otherConcrete, ok := other.(*SocketpairEvent)
+ if !ok {
+ return false
+ }
+ return s.EventType == otherConcrete.EventType && s.TraceId == otherConcrete.TraceId && s.Time == otherConcrete.Time && s.Pid == otherConcrete.Pid && s.Tid == otherConcrete.Tid && s.Family == otherConcrete.Family && s.Type == otherConcrete.Type && s.Protocol == otherConcrete.Protocol && s.Sv0 == otherConcrete.Sv0 && s.Sv1 == otherConcrete.Sv1
+}
+
+func (s *SocketpairEvent) GetEventType() EventType {
+ return s.EventType
+}
+
+func (s *SocketpairEvent) GetTraceId() TraceId {
+ return s.TraceId
+}
+
+func (s *SocketpairEvent) GetPid() uint32 {
+ return s.Pid
+}
+
+func (s *SocketpairEvent) GetTid() uint32 {
+ return s.Tid
+}
+
+func (s *SocketpairEvent) GetTime() uint64 {
+ return s.Time
+}
+
+var poolOfSocketpairEvents = sync.Pool{
+ New: func() any { return &SocketpairEvent{} },
+}
+
+func NewSocketpairEvent(raw []byte) *SocketpairEvent {
+ s := poolOfSocketpairEvents.Get().(*SocketpairEvent)
+ if err := binary.Read(bytes.NewReader(raw), binary.LittleEndian, s); err != nil {
+ *s = SocketpairEvent{}
+ poolOfSocketpairEvents.Put(s)
+ return nil
+ }
+ return s
+}
+
+func (s *SocketpairEvent) Bytes() ([]byte, error) {
+ buf := new(bytes.Buffer)
+ err := binary.Write(buf, binary.LittleEndian, s)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+func (s *SocketpairEvent) Recycle() {
+ poolOfSocketpairEvents.Put(s)
+}
diff --git a/internal/types/types_test.go b/internal/types/types_test.go
index 8ba7367..9e11baa 100644
--- a/internal/types/types_test.go
+++ b/internal/types/types_test.go
@@ -130,6 +130,64 @@ func TestNullEventSerialization(t *testing.T) {
t.Log("NullEvent could be serialized correctly")
}
+func TestSocketEventSerialization(t *testing.T) {
+ socketEv1 := SocketEvent{
+ EventType: ENTER_SOCKET_EVENT,
+ TraceId: SYS_ENTER_SOCKET,
+ Time: 1234,
+ Pid: 30,
+ Tid: 31,
+ Family: 1,
+ Type: 2,
+ Protocol: 0,
+ }
+ bytes, err := socketEv1.Bytes()
+ if err != nil {
+ t.Error(err)
+ }
+ socketEv2 := NewSocketEvent(bytes)
+
+ assertEquals(t, socketEv1.EventType, socketEv2.EventType)
+ assertEquals(t, socketEv1.TraceId, socketEv2.TraceId)
+ assertEquals(t, socketEv1.Time, socketEv2.Time)
+ assertEquals(t, socketEv1.Pid, socketEv2.Pid)
+ assertEquals(t, socketEv1.Tid, socketEv2.Tid)
+ assertEquals(t, socketEv1.Family, socketEv2.Family)
+ assertEquals(t, socketEv1.Type, socketEv2.Type)
+ assertEquals(t, socketEv1.Protocol, socketEv2.Protocol)
+}
+
+func TestSocketpairEventSerialization(t *testing.T) {
+ socketpairEv1 := SocketpairEvent{
+ EventType: ENTER_SOCKETPAIR_EVENT,
+ TraceId: SYS_ENTER_SOCKETPAIR,
+ Time: 2345,
+ Pid: 32,
+ Tid: 33,
+ Family: 1,
+ Type: 1,
+ Protocol: 0,
+ Sv0: 42,
+ Sv1: 43,
+ }
+ bytes, err := socketpairEv1.Bytes()
+ if err != nil {
+ t.Error(err)
+ }
+ socketpairEv2 := NewSocketpairEvent(bytes)
+
+ assertEquals(t, socketpairEv1.EventType, socketpairEv2.EventType)
+ assertEquals(t, socketpairEv1.TraceId, socketpairEv2.TraceId)
+ assertEquals(t, socketpairEv1.Time, socketpairEv2.Time)
+ assertEquals(t, socketpairEv1.Pid, socketpairEv2.Pid)
+ assertEquals(t, socketpairEv1.Tid, socketpairEv2.Tid)
+ assertEquals(t, socketpairEv1.Family, socketpairEv2.Family)
+ assertEquals(t, socketpairEv1.Type, socketpairEv2.Type)
+ assertEquals(t, socketpairEv1.Protocol, socketpairEv2.Protocol)
+ assertEquals(t, socketpairEv1.Sv0, socketpairEv2.Sv0)
+ assertEquals(t, socketpairEv1.Sv1, socketpairEv2.Sv1)
+}
+
func TestEqualsDifferentTypes(t *testing.T) {
openEv := OpenEvent{EventType: ENTER_OPEN_EVENT, TraceId: SYS_ENTER_OPENAT, Time: 1, Pid: 1, Tid: 1}
nullEv := NullEvent{EventType: ENTER_NULL_EVENT, TraceId: SYS_ENTER_SYNC, Time: 1, Pid: 1, Tid: 1}