summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-18 14:30:26 +0300
committerPaul Buetow <paul@buetow.org>2026-05-18 14:30:26 +0300
commit7fb497c435596a36c0fb0bd0ecae2a84793bcc70 (patch)
treecc12d16c0e34b034b1fc383a86ec6ffec997381b /internal
parent519cd996b5a7fede23b8b23f3c101d10b26111de (diff)
j6: account bytes for ret-classified syscalls
Diffstat (limited to 'internal')
-rw-r--r--internal/eventloop_bytes_test.go18
-rw-r--r--internal/eventloop_exit.go11
-rw-r--r--internal/eventloop_runtime.go1
-rw-r--r--internal/generate/classify_test.go61
-rw-r--r--internal/generate/retclassify_test.go25
5 files changed, 113 insertions, 3 deletions
diff --git a/internal/eventloop_bytes_test.go b/internal/eventloop_bytes_test.go
index ed7f7af..a7c25ef 100644
--- a/internal/eventloop_bytes_test.go
+++ b/internal/eventloop_bytes_test.go
@@ -3,6 +3,7 @@ package internal
import (
"testing"
+ "ior/internal/event"
"ior/internal/types"
)
@@ -71,3 +72,20 @@ func TestBytesFromRet(t *testing.T) {
})
}
}
+
+func TestApplyRetBytesForNullEnterRetExitPair(t *testing.T) {
+ pair := &event.Pair{
+ EnterEv: &types.NullEvent{TraceId: types.SYS_ENTER_SPLICE},
+ ExitEv: &types.RetEvent{
+ TraceId: types.SYS_EXIT_SPLICE,
+ Ret: 4096,
+ RetType: types.TRANSFER_CLASSIFIED,
+ },
+ }
+
+ applyRetBytes(pair)
+
+ if pair.Bytes != 4096 {
+ t.Fatalf("pair.Bytes = %d, want 4096", pair.Bytes)
+ }
+}
diff --git a/internal/eventloop_exit.go b/internal/eventloop_exit.go
index 79c1b5b..a0cc675 100644
--- a/internal/eventloop_exit.go
+++ b/internal/eventloop_exit.go
@@ -109,9 +109,6 @@ func (e *eventLoop) handleFdExit(ep *event.Pair, fdEv *types.FdEvent) bool {
if ok := e.applyFdTransferOp(ep, fdEv); !ok {
return false
}
- if retEv, ok := ep.ExitEv.(*types.RetEvent); ok {
- ep.Bytes = bytesFromRet(retEv)
- }
return true
}
@@ -315,6 +312,14 @@ func (e *eventLoop) recyclePair(ep *event.Pair, warning string) {
ep.Recycle()
}
+func applyRetBytes(ep *event.Pair) {
+ retEv, ok := ep.ExitEv.(*types.RetEvent)
+ if !ok {
+ return
+ }
+ ep.Bytes = bytesFromRet(retEv)
+}
+
// dropMalformedRawEvent records a warning when a raw BPF event cannot be
// decoded, keeping the error visible without crashing the event loop.
func (e *eventLoop) dropMalformedRawEvent(evType types.EventType, raw []byte) {
diff --git a/internal/eventloop_runtime.go b/internal/eventloop_runtime.go
index 74571c8..c285507 100644
--- a/internal/eventloop_runtime.go
+++ b/internal/eventloop_runtime.go
@@ -314,6 +314,7 @@ func (e *eventLoop) tracepointExited(exitEv event.Event, ch chan<- *event.Pair)
if !e.handleTracepointExit(ep) {
return
}
+ applyRetBytes(ep)
tid := ep.EnterEv.GetTid()
ep.CalculateDurations(e.pairs.prevTime(tid))
e.pairs.setPrevTime(tid, ep.ExitEv.GetTime())
diff --git a/internal/generate/classify_test.go b/internal/generate/classify_test.go
index f02f7de..4dd216e 100644
--- a/internal/generate/classify_test.go
+++ b/internal/generate/classify_test.go
@@ -338,6 +338,67 @@ func TestClassifySyscallPairEmitsAllFamilies(t *testing.T) {
}
}
+func TestClassifyPhaseAByteSyscallPairsAccepted(t *testing.T) {
+ tests := []struct {
+ name string
+ enterKindText string
+ retText string
+ }{
+ {"recvfrom", "struct fd_event", "READ_CLASSIFIED"},
+ {"recvmsg", "struct fd_event", "READ_CLASSIFIED"},
+ {"sendto", "struct fd_event", "WRITE_CLASSIFIED"},
+ {"sendmsg", "struct fd_event", "WRITE_CLASSIFIED"},
+ {"sendfile64", "struct null_event", "TRANSFER_CLASSIFIED"},
+ {"splice", "struct null_event", "TRANSFER_CLASSIFIED"},
+ {"tee", "struct null_event", "TRANSFER_CLASSIFIED"},
+ {"process_vm_readv", "struct null_event", "READ_CLASSIFIED"},
+ {"process_vm_writev", "struct null_event", "WRITE_CLASSIFIED"},
+ }
+
+ for i, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ formats := phaseAFormats(tt.name, 9000+i*2)
+ output := GenerateTracepointsC(formats)
+ if strings.Contains(output, "Ignoring") || strings.Contains(output, "Skipping") {
+ t.Fatalf("syscall %s was not accepted:\n%s", tt.name, output)
+ }
+ if !strings.Contains(output, "/// sys_enter_"+tt.name+" is a "+tt.enterKindText) {
+ t.Fatalf("sys_enter_%s did not use %s:\n%s", tt.name, tt.enterKindText, output)
+ }
+ if !strings.Contains(output, "/// sys_exit_"+tt.name+" is a struct ret_event ("+tt.retText+")") {
+ t.Fatalf("sys_exit_%s did not use %s:\n%s", tt.name, tt.retText, output)
+ }
+ })
+ }
+}
+
+func phaseAFormats(name string, enterID int) []Format {
+ enterFields := []Field{
+ {Type: "long", Name: "__syscall_nr"},
+ }
+ if name == "sendto" || name == "recvfrom" || name == "sendmsg" || name == "recvmsg" {
+ enterFields = append(enterFields, Field{Type: "int", Name: "fd"})
+ }
+
+ return []Format{
+ {
+ Name: "sys_enter_" + name,
+ ID: enterID,
+ Family: ClassifySyscallFamily("sys_enter_" + name),
+ ExternalFields: enterFields,
+ },
+ {
+ Name: "sys_exit_" + name,
+ ID: enterID - 1,
+ Family: ClassifySyscallFamily("sys_exit_" + name),
+ ExternalFields: []Field{
+ {Type: "long", Name: "__syscall_nr"},
+ {Type: "long", Name: "ret"},
+ },
+ },
+ }
+}
+
func TestClassifyFormatNoExternalFields(t *testing.T) {
f := &Format{
Name: "sys_enter_test",
diff --git a/internal/generate/retclassify_test.go b/internal/generate/retclassify_test.go
index 3152005..9a75a15 100644
--- a/internal/generate/retclassify_test.go
+++ b/internal/generate/retclassify_test.go
@@ -57,3 +57,28 @@ func TestClassifyRetCaseInsensitive(t *testing.T) {
t.Errorf("ClassifyRet(sys_exit_READ) = %q, want READ_CLASSIFIED", got)
}
}
+
+func TestPhaseAByteClassifiedSyscallsUseExistingRetClassifications(t *testing.T) {
+ tests := []struct {
+ name string
+ want RetClassification
+ }{
+ {"recvfrom", ReadClassified},
+ {"recvmsg", ReadClassified},
+ {"sendto", WriteClassified},
+ {"sendmsg", WriteClassified},
+ {"sendfile64", TransferClassified},
+ {"splice", TransferClassified},
+ {"tee", TransferClassified},
+ {"process_vm_readv", ReadClassified},
+ {"process_vm_writev", WriteClassified},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := ClassifyRet("sys_exit_" + tt.name); got != tt.want {
+ t.Fatalf("ClassifyRet(sys_exit_%s) = %q, want %q", tt.name, got, tt.want)
+ }
+ })
+ }
+}