summaryrefslogtreecommitdiff
path: root/internal/generate
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-21 08:16:08 +0300
committerPaul Buetow <paul@buetow.org>2026-05-21 08:16:08 +0300
commitbe8735fe701f7398c19c17c394f4827614eab875 (patch)
treeaba59890563edb6e03f2eb82fee5d89b49fa2c81 /internal/generate
parent3a5706f21d30258577a5934efb93c400dad723db (diff)
p7 add attach-time trace dimension gating
Diffstat (limited to 'internal/generate')
-rw-r--r--internal/generate/bpfhandler.go4
-rw-r--r--internal/generate/classify.go55
-rw-r--r--internal/generate/tracepointsgo.go107
-rw-r--r--internal/generate/tracepointsgo_test.go22
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",`)
+}