diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-18 14:14:33 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-18 14:14:33 +0300 |
| commit | 519cd996b5a7fede23b8b23f3c101d10b26111de (patch) | |
| tree | 93f14954325e936d459003f334b667d2afec93b6 /internal/generate | |
| parent | d68e12c92f2aec9b59a849480e0788ab5d798b2a (diff) | |
k6: emit tracepoints for all syscall families
Diffstat (limited to 'internal/generate')
| -rw-r--r-- | internal/generate/classify.go | 38 | ||||
| -rw-r--r-- | internal/generate/classify_test.go | 105 | ||||
| -rw-r--r-- | internal/generate/codegen.go | 12 | ||||
| -rw-r--r-- | internal/generate/codegen_test.go | 54 | ||||
| -rw-r--r-- | internal/generate/family.go | 166 | ||||
| -rw-r--r-- | internal/generate/family_test.go | 51 | ||||
| -rw-r--r-- | internal/generate/format.go | 2 |
7 files changed, 321 insertions, 107 deletions
diff --git a/internal/generate/classify.go b/internal/generate/classify.go index f3b9a44..b96ee0d 100644 --- a/internal/generate/classify.go +++ b/internal/generate/classify.go @@ -40,10 +40,6 @@ func ClassifyFormat(f *Format) ClassificationResult { return ClassificationResult{Kind: KindNone} } - if shouldIgnore(f.Name) { - return ClassificationResult{Kind: KindNone} - } - if r, ok := classifyNameOnly(f.Name); ok { return r } @@ -63,40 +59,6 @@ func ClassifyFormat(f *Format) ClassificationResult { return ClassificationResult{Kind: KindNone} } -func shouldIgnore(name string) bool { - prefixIgnores := []string{ - "sys_enter_mknod", - "sys_enter_execve", - "sys_enter_accept", - "sys_enter_listen", - "sys_enter_epoll", - } - for _, p := range prefixIgnores { - if strings.HasPrefix(name, p) { - return true - } - } - - if strings.HasPrefix(name, "sys_enter_") { - containsIgnores := []string{"recv", "send", "sock", "inotify"} - for _, sub := range containsIgnores { - if strings.Contains(name, sub) { - return true - } - } - } - - exactIgnores := map[string]bool{ - "sys_enter_bind": true, - "sys_enter_setns": true, - "sys_enter_shutdown": true, - "sys_enter_connect": true, - "sys_enter_fanotify_init": true, - "sys_enter_getpeername": true, - } - return exactIgnores[name] -} - // classifyNameOnly handles tracepoints classified by name alone, // independent of any field. func classifyNameOnly(name string) (ClassificationResult, bool) { diff --git a/internal/generate/classify_test.go b/internal/generate/classify_test.go index 301d4bc..f02f7de 100644 --- a/internal/generate/classify_test.go +++ b/internal/generate/classify_test.go @@ -223,77 +223,38 @@ func TestClassifyRetExitSymlink(t *testing.T) { } } -// --- Ignore tests --- - -func TestIgnoreMknod(t *testing.T) { +func TestClassifyPathnameMknod(t *testing.T) { r := classifyFromData(t, FormatMknod) - if r.Kind != KindNone { - t.Errorf("mknod: got kind %d, want KindNone (ignored)", r.Kind) + if r.Kind != KindPathname { + t.Errorf("mknod: got kind %d, want KindPathname", r.Kind) } } -func TestIgnoreExecve(t *testing.T) { +func TestClassifyPathnameExecve(t *testing.T) { r := classifyFromData(t, FormatExecve) - if r.Kind != KindNone { - t.Errorf("execve: got kind %d, want KindNone (ignored)", r.Kind) + if r.Kind != KindPathname { + t.Errorf("execve: got kind %d, want KindPathname", r.Kind) } } -func TestIgnoreAccept(t *testing.T) { +func TestClassifyFdAccept(t *testing.T) { r := classifyFromData(t, FormatAccept) - if r.Kind != KindNone { - t.Errorf("accept: got kind %d, want KindNone (ignored)", r.Kind) + if r.Kind != KindFd { + t.Errorf("accept: got kind %d, want KindFd", r.Kind) } } -func TestIgnoreSocket(t *testing.T) { +func TestClassifySocketRequiresGenerationFallback(t *testing.T) { r := classifyFromData(t, FormatSocket) if r.Kind != KindNone { - t.Errorf("socket: got kind %d, want KindNone (ignored)", r.Kind) + t.Errorf("socket: got kind %d, want KindNone before generation fallback", r.Kind) } } -func TestIgnoreKill(t *testing.T) { +func TestClassifyKillRequiresGenerationFallback(t *testing.T) { r := classifyFromData(t, FormatKill) if r.Kind != KindNone { - t.Errorf("kill: got kind %d, want KindNone (no matching type)", r.Kind) - } -} - -func TestShouldIgnorePatterns(t *testing.T) { - ignoreNames := []string{ - "sys_enter_mknod", "sys_enter_mknodat", - "sys_enter_execve", "sys_enter_execveat", - "sys_enter_accept", "sys_enter_accept4", - "sys_enter_listen", - "sys_enter_epoll_ctl", "sys_enter_epoll_pwait", - "sys_enter_recvfrom", "sys_enter_recvmsg", "sys_enter_recvmmsg", - "sys_enter_sendto", "sys_enter_sendmsg", "sys_enter_sendmmsg", - "sys_enter_socket", "sys_enter_socketpair", "sys_enter_getsockname", - "sys_enter_inotify_init", "sys_enter_inotify_add_watch", - "sys_enter_bind", "sys_enter_setns", "sys_enter_shutdown", - "sys_enter_connect", "sys_enter_fanotify_init", "sys_enter_getpeername", - } - for _, name := range ignoreNames { - if !shouldIgnore(name) { - t.Errorf("shouldIgnore(%q) = false, want true", name) - } - } -} - -func TestShouldNotIgnore(t *testing.T) { - noIgnore := []string{ - "sys_enter_read", "sys_enter_write", "sys_enter_openat", - "sys_enter_close", "sys_enter_rename", "sys_enter_unlink", - "sys_enter_copy_file_range", - "sys_enter_msync", - "sys_enter_pidfd_getfd", - "sys_exit_read", "sys_exit_openat", - } - for _, name := range noIgnore { - if shouldIgnore(name) { - t.Errorf("shouldIgnore(%q) = true, want false", name) - } + t.Errorf("kill: got kind %d, want KindNone before generation fallback", r.Kind) } } @@ -324,6 +285,11 @@ func TestClassifySyscallPairAccepted(t *testing.T) { {"io_uring_register", FormatIoUringRegister, FormatExitIoUringRegister, KindFd}, {"pread64", FormatPread64, FormatExitPread64, KindFd}, {"symlink", FormatSymlink, FormatExitSymlink, KindName}, + {"mknod", FormatMknod, FormatExitMknod, KindPathname}, + {"execve", FormatExecve, FormatExitExecve, KindPathname}, + {"accept", FormatAccept, FormatExitAccept, KindFd}, + {"socket", FormatSocket, FormatExitSocket, KindNull}, + {"kill", FormatKill, FormatExitKill, KindNull}, } for _, tt := range tests { @@ -337,25 +303,36 @@ func TestClassifySyscallPairAccepted(t *testing.T) { } } -func TestClassifySyscallPairIgnored(t *testing.T) { +func TestClassifySyscallPairEmitsAllFamilies(t *testing.T) { tests := []struct { - name string - enter string - exit string + name string + enter string + exit string + family SyscallFamily }{ - {"mknod", FormatMknod, FormatExitMknod}, - {"execve", FormatExecve, FormatExitExecve}, - {"accept", FormatAccept, FormatExitAccept}, - {"socket", FormatSocket, FormatExitSocket}, - {"kill", FormatKill, FormatExitKill}, + {"mknod", FormatMknod, FormatExitMknod, FamilyFS}, + {"execve", FormatExecve, FormatExitExecve, FamilyProcess}, + {"accept", FormatAccept, FormatExitAccept, FamilyNetwork}, + {"socket", FormatSocket, FormatExitSocket, FamilyNetwork}, + {"kill", FormatKill, FormatExitKill, FamilySignals}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { input := tt.enter + "\n" + tt.exit - output := GenerateTracepointsC(mustParseAll(t, input)) - if !strings.Contains(output, "Ignoring") { - t.Errorf("syscall %s was accepted, expected ignored", tt.name) + formats := mustParseAll(t, input) + if formats[0].Family != tt.family { + t.Fatalf("%s family = %s, want %s", tt.name, formats[0].Family, tt.family) + } + output := GenerateTracepointsC(formats) + if strings.Contains(output, "Ignoring") { + t.Errorf("syscall %s was ignored, expected accepted", tt.name) + } + if !strings.Contains(output, `SEC("tracepoint/syscalls/sys_enter_`+tt.name+`")`) { + t.Errorf("syscall %s missing enter handler", tt.name) + } + if !strings.Contains(output, `SEC("tracepoint/syscalls/sys_exit_`+tt.name+`")`) { + t.Errorf("syscall %s missing exit handler", tt.name) } }) } diff --git a/internal/generate/codegen.go b/internal/generate/codegen.go index e3ec0ef..3848b93 100644 --- a/internal/generate/codegen.go +++ b/internal/generate/codegen.go @@ -94,7 +94,7 @@ func classifySyscall(sc Syscall) ([]GeneratedTracepoint, string) { allCanGenerate := true if sc.Enter != nil { - enterClass = ClassifyFormat(sc.Enter) + enterClass = classifyEnterForGeneration(sc.Enter) if enterClass.Kind == KindNone { allCanGenerate = false } @@ -113,7 +113,7 @@ func classifySyscall(sc Syscall) ([]GeneratedTracepoint, string) { if !allCanGenerate { names := syscallFormatNames(sc) - return nil, fmt.Sprintf("Ignoring %s as possibly not file I/O related", strings.Join(names, " ")) + return nil, fmt.Sprintf("Skipping %s as incomplete or unclassifiable", strings.Join(names, " ")) } if isEnterRejected(enterClass.Kind) { @@ -131,6 +131,14 @@ func classifySyscall(sc Syscall) ([]GeneratedTracepoint, string) { return result, "" } +func classifyEnterForGeneration(f *Format) ClassificationResult { + classification := ClassifyFormat(f) + if classification.Kind != KindNone || len(f.ExternalFields) == 0 { + return classification + } + return ClassificationResult{Kind: KindNull} +} + // isEnterRejected reports whether kind must not appear on a syscall-enter // tracepoint. The answer comes from the kindRegistry so no switch statement // needs updating when a new TracepointKind is added. diff --git a/internal/generate/codegen_test.go b/internal/generate/codegen_test.go index 7a7d469..a448162 100644 --- a/internal/generate/codegen_test.go +++ b/internal/generate/codegen_test.go @@ -195,10 +195,50 @@ func TestGenerateNameToHandleAtHandler(t *testing.T) { requireContains(t, output, "bpf_probe_read_user_str(ev->pathname, sizeof(ev->pathname), (void*)ctx->args[1]);") } -func TestGenerateIgnoredComment(t *testing.T) { +func TestGenerateFallbackNullHandler(t *testing.T) { output := generateFromPair(t, FormatKill, FormatExitKill) - requireContains(t, output, "/// Ignoring sys_enter_kill sys_exit_kill as possibly not file I/O related") + requireContains(t, output, `SEC("tracepoint/syscalls/sys_enter_kill")`) + requireContains(t, output, "struct null_event *ev") + requireContains(t, output, "ev->event_type = ENTER_NULL_EVENT;") + requireContains(t, output, `SEC("tracepoint/syscalls/sys_exit_kill")`) + requireContains(t, output, "ev->event_type = EXIT_RET_EVENT;") +} + +func TestGenerateHandlersForEverySyscallFamily(t *testing.T) { + tests := []struct { + syscall string + family SyscallFamily + }{ + {"accept", FamilyNetwork}, + {"pipe2", FamilyIPC}, + {"munmap", FamilyMemory}, + {"execve", FamilyProcess}, + {"kill", FamilySignals}, + {"nanosleep", FamilyTime}, + {"sched_yield", FamilySched}, + {"mknod", FamilyFS}, + {"epoll_wait", FamilyPolling}, + {"io_setup", FamilyAIO}, + {"bpf", FamilySecurity}, + {"sysinfo", FamilyMisc}, + } + + for _, tt := range tests { + t.Run(tt.syscall, func(t *testing.T) { + input := syntheticPair(tt.syscall) + formats := mustParseAll(t, input) + if formats[0].Family != tt.family { + t.Fatalf("%s family = %s, want %s", tt.syscall, formats[0].Family, tt.family) + } + output := GenerateTracepointsC(formats) + if strings.Contains(output, "Skipping") { + t.Fatalf("%s was skipped: %s", tt.syscall, output) + } + requireContains(t, output, `SEC("tracepoint/syscalls/sys_enter_`+tt.syscall+`")`) + requireContains(t, output, `SEC("tracepoint/syscalls/sys_exit_`+tt.syscall+`")`) + }) + } } func TestGenerateDefineConstants(t *testing.T) { @@ -333,12 +373,20 @@ func TestGroupBySyscallInvalid(t *testing.T) { func TestClassifySyscallNoExit(t *testing.T) { formats := mustParseAll(t, FormatRead) output := GenerateTracepointsC(formats) - requireContains(t, output, "Ignoring") + requireContains(t, output, "Skipping") if strings.Contains(output, "SEC(") { t.Error("syscall with only enter and no exit should be ignored") } } +func syntheticPair(syscall string) string { + enter := strings.Replace(FormatKill, "sys_enter_kill", "sys_enter_"+syscall, 1) + enter = strings.Replace(enter, "ID: 183", "ID: 1001", 1) + exit := strings.Replace(FormatExitKill, "sys_exit_kill", "sys_exit_"+syscall, 1) + exit = strings.Replace(exit, "ID: 182", "ID: 1000", 1) + return enter + "\n" + exit +} + func requireContains(t *testing.T, haystack, needle string) { t.Helper() if !strings.Contains(haystack, needle) { diff --git a/internal/generate/family.go b/internal/generate/family.go new file mode 100644 index 0000000..f39b13f --- /dev/null +++ b/internal/generate/family.go @@ -0,0 +1,166 @@ +package generate + +import "strings" + +// SyscallFamily is the broad syscall grouping attached to every parsed format. +type SyscallFamily string + +const ( + FamilyNetwork SyscallFamily = "Network" + FamilyIPC SyscallFamily = "IPC" + FamilyMemory SyscallFamily = "Memory" + FamilyProcess SyscallFamily = "Process" + FamilySignals SyscallFamily = "Signals" + FamilyTime SyscallFamily = "Time" + FamilySched SyscallFamily = "Sched" + FamilyFS SyscallFamily = "FS" + FamilyPolling SyscallFamily = "Polling" + FamilyAIO SyscallFamily = "AIO" + FamilySecurity SyscallFamily = "Security" + FamilyMisc SyscallFamily = "Misc" +) + +var syscallFamilies = map[string]SyscallFamily{ + "accept": FamilyNetwork, "accept4": FamilyNetwork, "bind": FamilyNetwork, + "connect": FamilyNetwork, "getpeername": FamilyNetwork, "getsockname": FamilyNetwork, + "getsockopt": FamilyNetwork, "listen": FamilyNetwork, "recvfrom": FamilyNetwork, + "recvmmsg": FamilyNetwork, "recvmsg": FamilyNetwork, "sendfile64": FamilyNetwork, + "sendmmsg": FamilyNetwork, "sendmsg": FamilyNetwork, "sendto": FamilyNetwork, + "setsockopt": FamilyNetwork, "shutdown": FamilyNetwork, "socket": FamilyNetwork, + "socketpair": FamilyNetwork, "splice": FamilyNetwork, "tee": FamilyNetwork, + + "eventfd": FamilyIPC, "eventfd2": FamilyIPC, "inotify_add_watch": FamilyIPC, + "inotify_init": FamilyIPC, "inotify_init1": FamilyIPC, "inotify_rm_watch": FamilyIPC, + "memfd_create": FamilyIPC, "memfd_secret": FamilyIPC, "mq_getsetattr": FamilyIPC, + "mq_notify": FamilyIPC, "mq_open": FamilyIPC, "mq_timedreceive": FamilyIPC, + "mq_timedsend": FamilyIPC, "mq_unlink": FamilyIPC, "msgctl": FamilyIPC, + "msgget": FamilyIPC, "msgrcv": FamilyIPC, "msgsnd": FamilyIPC, + "pidfd_getfd": FamilyIPC, "pidfd_open": FamilyIPC, "pidfd_send_signal": FamilyIPC, + "pipe": FamilyIPC, "pipe2": FamilyIPC, "semctl": FamilyIPC, "semget": FamilyIPC, + "semop": FamilyIPC, "semtimedop": FamilyIPC, "shmat": FamilyIPC, + "shmctl": FamilyIPC, "shmdt": FamilyIPC, "shmget": FamilyIPC, + "signalfd": FamilyIPC, "signalfd4": FamilyIPC, "timerfd_create": FamilyIPC, + "timerfd_gettime": FamilyIPC, "timerfd_settime": FamilyIPC, "userfaultfd": FamilyIPC, + + "brk": FamilyMemory, "madvise": FamilyMemory, "map_shadow_stack": FamilyMemory, + "mbind": FamilyMemory, "membarrier": FamilyMemory, "migrate_pages": FamilyMemory, + "mincore": FamilyMemory, "mlock": FamilyMemory, "mlock2": FamilyMemory, + "mlockall": FamilyMemory, "mmap": FamilyMemory, "mmap2": FamilyMemory, + "mprotect": FamilyMemory, "mremap": FamilyMemory, "mseal": FamilyMemory, + "munlock": FamilyMemory, "munlockall": FamilyMemory, "munmap": FamilyMemory, + "move_pages": FamilyMemory, "pkey_alloc": FamilyMemory, "pkey_free": FamilyMemory, + "pkey_mprotect": FamilyMemory, "process_madvise": FamilyMemory, + "process_mrelease": FamilyMemory, "process_vm_readv": FamilyMemory, + "process_vm_writev": FamilyMemory, "remap_file_pages": FamilyMemory, + "set_mempolicy": FamilyMemory, "set_mempolicy_home_node": FamilyMemory, + + "arch_prctl": FamilyProcess, "clone": FamilyProcess, "clone3": FamilyProcess, + "execve": FamilyProcess, "execveat": FamilyProcess, "exit": FamilyProcess, + "exit_group": FamilyProcess, "fork": FamilyProcess, "getegid": FamilyProcess, + "geteuid": FamilyProcess, "getgid": FamilyProcess, "getgroups": FamilyProcess, + "getpgid": FamilyProcess, "getpgrp": FamilyProcess, "getpid": FamilyProcess, + "getppid": FamilyProcess, "getpriority": FamilyProcess, "getresgid": FamilyProcess, + "getresuid": FamilyProcess, "getrlimit": FamilyProcess, "getrusage": FamilyProcess, + "getsid": FamilyProcess, "gettid": FamilyProcess, "getuid": FamilyProcess, + "kcmp": FamilyProcess, "personality": FamilyProcess, "pivot_root": FamilyProcess, + "prctl": FamilyProcess, "prlimit64": FamilyProcess, "reboot": FamilyProcess, + "restart_syscall": FamilyProcess, "set_tid_address": FamilyProcess, + "setfsuid": FamilyProcess, "setfsgid": FamilyProcess, "setgid": FamilyProcess, + "setgroups": FamilyProcess, "setns": FamilyProcess, "setpgid": FamilyProcess, + "setpriority": FamilyProcess, "setregid": FamilyProcess, "setresgid": FamilyProcess, + "setresuid": FamilyProcess, "setreuid": FamilyProcess, "setrlimit": FamilyProcess, + "setsid": FamilyProcess, "setuid": FamilyProcess, "umask": FamilyProcess, + "unshare": FamilyProcess, "vfork": FamilyProcess, "vhangup": FamilyProcess, + "wait4": FamilyProcess, "waitid": FamilyProcess, + + "kill": FamilySignals, "pause": FamilySignals, "rt_sigaction": FamilySignals, + "rt_sigpending": FamilySignals, "rt_sigprocmask": FamilySignals, + "rt_sigqueueinfo": FamilySignals, "rt_sigreturn": FamilySignals, + "rt_sigsuspend": FamilySignals, "rt_sigtimedwait": FamilySignals, + "rt_tgsigqueueinfo": FamilySignals, "sigaltstack": FamilySignals, + "tgkill": FamilySignals, "tkill": FamilySignals, + + "clock_adjtime": FamilyTime, "clock_getres": FamilyTime, "clock_gettime": FamilyTime, + "clock_nanosleep": FamilyTime, "clock_settime": FamilyTime, "getitimer": FamilyTime, + "gettimeofday": FamilyTime, "nanosleep": FamilyTime, "setitimer": FamilyTime, + "settimeofday": FamilyTime, "time": FamilyTime, "timer_create": FamilyTime, + "timer_delete": FamilyTime, "timer_getoverrun": FamilyTime, + "timer_gettime": FamilyTime, "timer_settime": FamilyTime, "times": FamilyTime, + + "sched_get_priority_max": FamilySched, "sched_get_priority_min": FamilySched, + "sched_getaffinity": FamilySched, "sched_getattr": FamilySched, + "sched_getparam": FamilySched, "sched_getscheduler": FamilySched, + "sched_rr_get_interval": FamilySched, "sched_setaffinity": FamilySched, + "sched_setattr": FamilySched, "sched_setparam": FamilySched, + "sched_setscheduler": FamilySched, "sched_yield": FamilySched, + + "epoll_create": FamilyPolling, "epoll_create1": FamilyPolling, + "epoll_ctl": FamilyPolling, "epoll_pwait": FamilyPolling, + "epoll_pwait2": FamilyPolling, "epoll_wait": FamilyPolling, + "poll": FamilyPolling, "ppoll": FamilyPolling, "pselect6": FamilyPolling, + "select": FamilyPolling, + + "io_cancel": FamilyAIO, "io_destroy": FamilyAIO, "io_getevents": FamilyAIO, + "io_pgetevents": FamilyAIO, "io_setup": FamilyAIO, "io_submit": FamilyAIO, + "io_uring_enter": FamilyAIO, "io_uring_register": FamilyAIO, + "io_uring_setup": FamilyAIO, + + "add_key": FamilySecurity, "bpf": FamilySecurity, "capget": FamilySecurity, + "capset": FamilySecurity, "delete_module": FamilySecurity, "finit_module": FamilySecurity, + "get_mempolicy": FamilySecurity, "getrandom": FamilySecurity, "init_module": FamilySecurity, + "kexec_file_load": FamilySecurity, "keyctl": FamilySecurity, + "landlock_add_rule": FamilySecurity, "landlock_create_ruleset": FamilySecurity, + "landlock_restrict_self": FamilySecurity, "lookup_dcookie": FamilySecurity, + "perf_event_open": FamilySecurity, "ptrace": FamilySecurity, + "request_key": FamilySecurity, "seccomp": FamilySecurity, +} + +// ClassifySyscallFamily returns the high-level syscall family for a tracepoint. +func ClassifySyscallFamily(tracepointName string) SyscallFamily { + syscall := syscallName(tracepointName) + if family, ok := syscallFamilies[syscall]; ok { + return family + } + if isFSSyscall(syscall) { + return FamilyFS + } + return FamilyMisc +} + +func syscallName(tracepointName string) string { + name := strings.TrimPrefix(tracepointName, "sys_enter_") + return strings.TrimPrefix(name, "sys_exit_") +} + +func isFSSyscall(syscall string) bool { + for _, marker := range fsNameMarkers { + if strings.Contains(syscall, marker) { + return true + } + } + _, ok := fsSyscalls[syscall] + return ok +} + +var fsNameMarkers = []string{"xattr", "stat", "chmod", "chown"} + +var fsSyscalls = map[string]struct{}{ + "access": {}, "cachestat": {}, "chdir": {}, "chroot": {}, "close": {}, + "close_range": {}, "copy_file_range": {}, "creat": {}, "dup": {}, "dup2": {}, + "dup3": {}, "faccessat": {}, "faccessat2": {}, "fadvise64": {}, "fallocate": {}, + "fcntl": {}, "fdatasync": {}, "fchdir": {}, "flock": {}, "fsconfig": {}, + "fsmount": {}, "fsopen": {}, "fspick": {}, "fsync": {}, "ftruncate": {}, + "futimesat": {}, "getcwd": {}, "getdents": {}, "getdents64": {}, "ioctl": {}, + "link": {}, "linkat": {}, "lseek": {}, "mkdir": {}, "mkdirat": {}, + "mknod": {}, "mknodat": {}, "mount": {}, "mount_setattr": {}, "move_mount": {}, + "msync": {}, + "name_to_handle_at": {}, "newfstat": {}, "newfstatat": {}, "newlstat": {}, + "newstat": {}, "open": {}, "open_by_handle_at": {}, "open_tree": {}, + "open_tree_attr": {}, "openat": {}, "openat2": {}, "quotactl": {}, + "quotactl_fd": {}, "read": {}, "readahead": {}, "readlink": {}, "readlinkat": {}, + "readv": {}, "rename": {}, "renameat": {}, "renameat2": {}, "rmdir": {}, + "statfs": {}, "sync": {}, "sync_file_range": {}, "syncfs": {}, "symlink": {}, + "symlinkat": {}, "truncate": {}, "umount2": {}, "unlink": {}, "unlinkat": {}, + "utimensat": {}, "write": {}, "writev": {}, "pread64": {}, "preadv": {}, + "preadv2": {}, "pwrite64": {}, "pwritev": {}, "pwritev2": {}, +} diff --git a/internal/generate/family_test.go b/internal/generate/family_test.go new file mode 100644 index 0000000..93431b4 --- /dev/null +++ b/internal/generate/family_test.go @@ -0,0 +1,51 @@ +package generate + +import "testing" + +func TestClassifySyscallFamily(t *testing.T) { + tests := []struct { + name string + want SyscallFamily + }{ + {"sys_enter_accept", FamilyNetwork}, + {"sys_exit_accept", FamilyNetwork}, + {"sys_enter_pipe2", FamilyIPC}, + {"sys_enter_munmap", FamilyMemory}, + {"sys_enter_execve", FamilyProcess}, + {"sys_enter_rt_sigaction", FamilySignals}, + {"sys_enter_clock_gettime", FamilyTime}, + {"sys_enter_sched_yield", FamilySched}, + {"sys_enter_openat", FamilyFS}, + {"sys_enter_epoll_wait", FamilyPolling}, + {"sys_enter_io_uring_enter", FamilyAIO}, + {"sys_enter_bpf", FamilySecurity}, + {"sys_enter_unlisted_future_syscall", FamilyMisc}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := ClassifySyscallFamily(tt.name); got != tt.want { + t.Errorf("ClassifySyscallFamily(%q) = %s, want %s", tt.name, got, tt.want) + } + }) + } +} + +func TestParseFormatsTagsEveryFormatWithFamily(t *testing.T) { + formats := mustParseAll(t, FormatRead+"\n"+FormatExitSocket+"\n"+FormatExitKill) + + tests := []struct { + index int + want SyscallFamily + }{ + {0, FamilyFS}, + {1, FamilyNetwork}, + {2, FamilySignals}, + } + + for _, tt := range tests { + if got := formats[tt.index].Family; got != tt.want { + t.Errorf("formats[%d].Family = %s, want %s", tt.index, got, tt.want) + } + } +} diff --git a/internal/generate/format.go b/internal/generate/format.go index ef51ba8..597d496 100644 --- a/internal/generate/format.go +++ b/internal/generate/format.go @@ -19,6 +19,7 @@ type Field struct { type Format struct { Name string ID int + Family SyscallFamily InternalFields []Field ExternalFields []Field } @@ -64,6 +65,7 @@ func applyFormatLine(line string, _ []Format, current *Format, isExternal bool, case strings.HasPrefix(trimmed, "name:"): f := Format{} f.Name = strings.TrimSpace(strings.TrimPrefix(trimmed, "name:")) + f.Family = ClassifySyscallFamily(f.Name) *formats = append(*formats, f) current = &(*formats)[len(*formats)-1] isExternal = false |
