diff options
Diffstat (limited to 'internal/generate')
| -rw-r--r-- | internal/generate/bpfhandler.go | 4 | ||||
| -rw-r--r-- | internal/generate/classify.go | 55 | ||||
| -rw-r--r-- | internal/generate/tracepointsgo.go | 107 | ||||
| -rw-r--r-- | internal/generate/tracepointsgo_test.go | 22 |
4 files changed, 183 insertions, 5 deletions
diff --git a/internal/generate/bpfhandler.go b/internal/generate/bpfhandler.go index 9365c52..dce776a 100644 --- a/internal/generate/bpfhandler.go +++ b/internal/generate/bpfhandler.go @@ -23,9 +23,9 @@ func generateBPFHandler(tp GeneratedTracepoint) string { } eventStruct := eventStructName(tp.Classification.Kind) - comment := eventStruct + comment := fmt.Sprintf("%s (kind=%s)", eventStruct, tp.Classification.Kind.MetadataName()) if tp.Classification.Kind == KindRet { - comment = fmt.Sprintf("%s (%s)", eventStruct, ClassifyRet(f.Name)) + comment = fmt.Sprintf("%s (%s) (kind=%s)", eventStruct, ClassifyRet(f.Name), tp.Classification.Kind.MetadataName()) } eventTypeConst := eventTypeConstant(tp.Classification.Kind, isEnter) diff --git a/internal/generate/classify.go b/internal/generate/classify.go index af7d78d..9e9df9c 100644 --- a/internal/generate/classify.go +++ b/internal/generate/classify.go @@ -32,6 +32,61 @@ const ( KindPerfOpen ) +func (k TracepointKind) MetadataName() string { + switch k { + case KindFd: + return "fd" + case KindOpen: + return "open" + case KindMqOpen: + return "mq-open" + case KindExec: + return "exec" + case KindPathname: + return "pathname" + case KindName: + return "name" + case KindRet: + return "ret" + case KindFcntl: + return "fcntl" + case KindNull: + return "null" + case KindDup3: + return "dup3" + case KindOpenByHandleAt: + return "open-by-handle-at" + case KindSocket: + return "socket" + case KindSocketpair: + return "socketpair" + case KindAccept: + return "accept" + case KindPipe: + return "pipe" + case KindEventfd: + return "eventfd" + case KindEpollCtl: + return "epoll-ctl" + case KindTwoFd: + return "two-fd" + case KindPoll: + return "poll" + case KindMem: + return "mem" + case KindSleep: + return "sleep" + case KindKeyctl: + return "keyctl" + case KindPtrace: + return "ptrace" + case KindPerfOpen: + return "perf-open" + default: + return "none" + } +} + type RetClassification string const ( diff --git a/internal/generate/tracepointsgo.go b/internal/generate/tracepointsgo.go index 0542f64..9d92047 100644 --- a/internal/generate/tracepointsgo.go +++ b/internal/generate/tracepointsgo.go @@ -5,14 +5,35 @@ import ( "fmt" "io" "regexp" + "sort" "strings" ) var secRe = regexp.MustCompile(`^SEC.*sys_((?:enter|exit)_[a-z_0-9]+)`) +var kindLineRe = regexp.MustCompile(`^(sys_enter_[a-z0-9_]+)\s+is a struct\s+([a-z0-9_]+)\s*$`) // ExtractTracepoints reads generated C code and extracts tracepoint names from // SEC annotations, producing the generated_tracepoints.go content. func ExtractTracepoints(r io.Reader) (string, error) { + return ExtractTracepointsWithKinds(r, strings.NewReader("")) +} + +// ExtractTracepointsWithKinds reads generated C code and the +// generated_tracepoints_result.txt metadata to produce +// internal/tracepoints/generated_tracepoints.go. +func ExtractTracepointsWithKinds(cReader io.Reader, kindsReader io.Reader) (string, error) { + tracepoints, err := extractTracepoints(cReader) + if err != nil { + return "", err + } + syscallKinds, err := extractSyscallKinds(kindsReader) + if err != nil { + return "", err + } + return formatTracepointsGo(tracepoints, syscallKinds), nil +} + +func extractTracepoints(r io.Reader) ([]string, error) { scanner := bufio.NewScanner(r) var tracepoints []string @@ -24,13 +45,58 @@ func ExtractTracepoints(r io.Reader) (string, error) { } if err := scanner.Err(); err != nil { - return "", fmt.Errorf("scanning input: %w", err) + return nil, fmt.Errorf("scanning input: %w", err) } + return tracepoints, nil +} - return formatTracepointsGo(tracepoints), nil +func extractSyscallKinds(r io.Reader) (map[string]string, error) { + kinds := make(map[string]string) + if r == nil { + return kinds, nil + } + scanner := bufio.NewScanner(r) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if line == "" { + continue + } + m := kindLineRe.FindStringSubmatch(line) + if m == nil { + continue + } + syscall := strings.TrimPrefix(m[1], "sys_enter_") + kind := normalizeStructKind(m[2]) + if kind == "" { + continue + } + kinds[syscall] = kind + } + if err := scanner.Err(); err != nil { + return nil, fmt.Errorf("scan kind metadata: %w", err) + } + return kinds, nil +} + +func normalizeStructKind(structName string) string { + base := strings.TrimSuffix(structName, "_event") + switch base { + case "mq_open": + return "mq-open" + case "open_by_handle_at": + return "open-by-handle-at" + case "two_fd": + return "two-fd" + case "epoll_ctl": + return "epoll-ctl" + case "perf_open": + return "perf-open" + default: + return base + } } -func formatTracepointsGo(tracepoints []string) string { +func formatTracepointsGo(tracepoints []string, syscallKinds map[string]string) string { var b strings.Builder b.WriteString("// Code generated - don't change manually!\n") b.WriteString("package tracepoints\n\n") @@ -39,5 +105,40 @@ func formatTracepointsGo(tracepoints []string) string { fmt.Fprintf(&b, "\t%q,\n", tp) } b.WriteString("}\n") + b.WriteString("\n") + b.WriteString("var syscallFamilies = map[string]string{\n") + syscallFamilies := make(map[string]string) + for _, tp := range tracepoints { + syscall := strings.TrimPrefix(tp, "sys_enter_") + syscall = strings.TrimPrefix(syscall, "sys_exit_") + if syscall == "" { + continue + } + if _, ok := syscallFamilies[syscall]; ok { + continue + } + family := ClassifySyscallFamily("sys_enter_" + syscall) + syscallFamilies[syscall] = string(family) + } + familySyscalls := make([]string, 0, len(syscallFamilies)) + for syscall := range syscallFamilies { + familySyscalls = append(familySyscalls, syscall) + } + sort.Strings(familySyscalls) + for _, syscall := range familySyscalls { + fmt.Fprintf(&b, "\t%q: %q,\n", syscall, syscallFamilies[syscall]) + } + b.WriteString("}\n") + b.WriteString("\n") + b.WriteString("var syscallKinds = map[string]string{\n") + syscalls := make([]string, 0, len(syscallKinds)) + for syscall := range syscallKinds { + syscalls = append(syscalls, syscall) + } + sort.Strings(syscalls) + for _, syscall := range syscalls { + fmt.Fprintf(&b, "\t%q: %q,\n", syscall, syscallKinds[syscall]) + } + b.WriteString("}\n") return b.String() } diff --git a/internal/generate/tracepointsgo_test.go b/internal/generate/tracepointsgo_test.go index 978633b..ebad63d 100644 --- a/internal/generate/tracepointsgo_test.go +++ b/internal/generate/tracepointsgo_test.go @@ -51,6 +51,8 @@ func TestExtractTracepoints(t *testing.T) { requireContains(t, output, `"sys_enter_close",`) requireContains(t, output, `"sys_exit_close",`) requireContains(t, output, "var List = []string{") + requireContains(t, output, "var syscallFamilies = map[string]string{") + requireContains(t, output, "var syscallKinds = map[string]string{") // Should NOT contain ignore comments or defines if strings.Contains(output, "kill") { @@ -78,6 +80,8 @@ func TestExtractTracepointsEmpty(t *testing.T) { t.Fatal(err) } requireContains(t, output, "var List = []string{") + requireContains(t, output, "var syscallFamilies = map[string]string{") + requireContains(t, output, "var syscallKinds = map[string]string{") requireContains(t, output, "}") } @@ -115,7 +119,25 @@ func TestExtractTracepointsNoSECLines(t *testing.T) { t.Fatalf("unexpected error: %v", err) } requireContains(t, output, "var List = []string{") + requireContains(t, output, "var syscallFamilies = map[string]string{") + requireContains(t, output, "var syscallKinds = map[string]string{") if strings.Contains(output, `"sys_`) { t.Error("input with no SEC lines should produce empty list") } } + +func TestExtractTracepointsWithKinds(t *testing.T) { + kindData := `sys_enter_read is a struct fd_event +sys_enter_open_by_handle_at is a struct open_by_handle_at_event +sys_enter_mq_open is a struct mq_open_event +sys_enter_epoll_ctl is a struct epoll_ctl_event +` + output, err := ExtractTracepointsWithKinds(strings.NewReader(sampleGeneratedC), strings.NewReader(kindData)) + if err != nil { + t.Fatalf("ExtractTracepointsWithKinds failed: %v", err) + } + requireContains(t, output, `"read": "fd",`) + requireContains(t, output, `"open_by_handle_at": "open-by-handle-at",`) + requireContains(t, output, `"mq_open": "mq-open",`) + requireContains(t, output, `"epoll_ctl": "epoll-ctl",`) +} |
