summaryrefslogtreecommitdiff
path: root/internal/generate/bpfhandler.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-02-21 11:51:01 +0200
committerPaul Buetow <paul@buetow.org>2026-02-21 11:51:01 +0200
commit6c912a9d72ae2a43923c638538d320e6bf585952 (patch)
tree727f66d158210e01abf8c18a83ef4db6066e0c1a /internal/generate/bpfhandler.go
parent32136b8cb18944157ff1f361bc0755f6b627fd47 (diff)
Migrate make targets to mage
Amp-Thread-ID: https://ampcode.com/threads/T-019c7f4e-cc5f-76f1-aaf0-dd7cbaabbb18 Co-authored-by: Amp <amp@ampcode.com>
Diffstat (limited to 'internal/generate/bpfhandler.go')
-rw-r--r--internal/generate/bpfhandler.go152
1 files changed, 152 insertions, 0 deletions
diff --git a/internal/generate/bpfhandler.go b/internal/generate/bpfhandler.go
new file mode 100644
index 0000000..1ce6d3e
--- /dev/null
+++ b/internal/generate/bpfhandler.go
@@ -0,0 +1,152 @@
+package generate
+
+import (
+ "fmt"
+ "strings"
+)
+
+func generateBPFHandler(tp GeneratedTracepoint) string {
+ f := tp.Format
+ isEnter := strings.Split(f.Name, "_")[1] == "enter"
+
+ ctxStruct := "trace_event_raw_sys_exit"
+ if isEnter {
+ ctxStruct = "trace_event_raw_sys_enter"
+ }
+
+ eventStruct := eventStructName(tp.Classification.Kind)
+ comment := eventStruct
+ if tp.Classification.Kind == KindRet {
+ comment = fmt.Sprintf("%s (%s)", eventStruct, ClassifyRet(f.Name))
+ }
+
+ eventTypeConst := eventTypeConstant(tp.Classification.Kind, isEnter)
+ extra := generateExtra(tp, isEnter)
+
+ return renderHandler(f.Name, ctxStruct, eventStruct, comment, eventTypeConst, extra)
+}
+
+func renderHandler(name, ctxStruct, eventStruct, comment, eventTypeConst, extra string) string {
+ var b strings.Builder
+ fmt.Fprintf(&b, "/// %s is a struct %s\n", name, comment)
+ fmt.Fprintf(&b, "SEC(\"tracepoint/syscalls/%s\")\n", name)
+ fmt.Fprintf(&b, "int handle_%s(struct %s *ctx) {\n", strings.ToLower(name), ctxStruct)
+ b.WriteString(" __u32 pid, tid;\n")
+ b.WriteString(" if (filter(&pid, &tid))\n")
+ b.WriteString(" return 0;\n")
+ b.WriteString("\n")
+ fmt.Fprintf(&b, " struct %s *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct %s), 0);\n", eventStruct, eventStruct)
+ b.WriteString(" if (!ev)\n")
+ b.WriteString(" return 0;\n")
+ b.WriteString("\n")
+ fmt.Fprintf(&b, " ev->event_type = %s;\n", eventTypeConst)
+ fmt.Fprintf(&b, " ev->trace_id = %s;\n", strings.ToUpper(name))
+ b.WriteString(" ev->pid = pid;\n")
+ b.WriteString(" ev->tid = tid;\n")
+ b.WriteString(" ev->time = bpf_ktime_get_boot_ns();\n")
+ if extra != "" {
+ b.WriteString(extra)
+ }
+ b.WriteString("\n")
+ b.WriteString(" bpf_ringbuf_submit(ev, 0);\n")
+ b.WriteString(" return 0;\n")
+ b.WriteString("}\n")
+ return b.String()
+}
+
+func generateExtra(tp GeneratedTracepoint, isEnter bool) string {
+ f := tp.Format
+
+ switch tp.Classification.Kind {
+ case KindFd:
+ return " ev->fd = (__s32)ctx->args[0];\n"
+
+ case KindDup3:
+ 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 KindOpen:
+ filenameIdx := f.FieldNumber("filename")
+ flagsIdx := f.FieldNumber("flags")
+ var b strings.Builder
+ b.WriteString(" __builtin_memset(&(ev->filename), 0, sizeof(ev->filename) + sizeof(ev->comm));\n")
+ fmt.Fprintf(&b, " bpf_probe_read_user_str(ev->filename, sizeof(ev->filename), (void *)ctx->args[%d]);\n", filenameIdx)
+ b.WriteString(" bpf_get_current_comm(&ev->comm, sizeof(ev->comm));\n")
+ if flagsIdx > -1 {
+ fmt.Fprintf(&b, " ev->flags = ctx->args[%d];\n", flagsIdx)
+ } else {
+ b.WriteString(" ev->flags = -1; // Probably OK\n")
+ }
+ return b.String()
+
+ case KindPathname:
+ fieldName := tp.Classification.PathnameField
+ fieldIdx := f.FieldNumber(fieldName)
+ var b strings.Builder
+ b.WriteString(" __builtin_memset(&(ev->pathname), 0, sizeof(ev->pathname));\n")
+ fmt.Fprintf(&b, " bpf_probe_read_user_str(ev->pathname, sizeof(ev->pathname), (void*)ctx->args[%d]);\n", fieldIdx)
+ return b.String()
+
+ case KindName:
+ oldIdx := f.FieldNumber("oldname")
+ newIdx := f.FieldNumber("newname")
+ var b strings.Builder
+ b.WriteString(" __builtin_memset(&(ev->oldname), 0, sizeof(ev->oldname) + sizeof(ev->newname));\n")
+ fmt.Fprintf(&b, " bpf_probe_read_user_str(ev->oldname, sizeof(ev->oldname), (void*)ctx->args[%d]);\n", oldIdx)
+ fmt.Fprintf(&b, " bpf_probe_read_user_str(ev->newname, sizeof(ev->newname), (void*)ctx->args[%d]);\n", newIdx)
+ return b.String()
+
+ case KindFcntl:
+ fdIdx := f.FieldNumber("fd")
+ cmdIdx := f.FieldNumber("cmd")
+ argIdx := f.FieldNumber("arg")
+ return fmt.Sprintf(
+ " ev->fd = ctx->args[%d];\n ev->cmd = ctx->args[%d];\n ev->arg = ctx->args[%d];\n",
+ fdIdx, cmdIdx, argIdx,
+ )
+
+ case KindRet:
+ classification := ClassifyRet(f.Name)
+ return fmt.Sprintf(" ev->ret = ctx->ret;\n ev->ret_type = %s;\n", classification)
+
+ case KindNull:
+ return ""
+ }
+
+ return ""
+}
+
+func eventStructName(kind TracepointKind) string {
+ switch kind {
+ case KindFd:
+ return "fd_event"
+ case KindOpen:
+ return "open_event"
+ case KindPathname:
+ return "path_event"
+ case KindName:
+ return "name_event"
+ case KindRet:
+ return "ret_event"
+ case KindFcntl:
+ return "fcntl_event"
+ case KindNull:
+ return "null_event"
+ case KindDup3:
+ return "dup3_event"
+ case KindOpenByHandleAt:
+ return "open_by_handle_at_event"
+ default:
+ return "unknown_event"
+ }
+}
+
+func eventTypeConstant(kind TracepointKind, isEnter bool) string {
+ prefix := "EXIT_"
+ if isEnter {
+ prefix = "ENTER_"
+ }
+ return prefix + strings.ToUpper(eventStructName(kind))
+}