summaryrefslogtreecommitdiff
path: root/internal/eventloop.go
blob: b26ae35da95e1be0ac255867cfc30ea870479e62 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package internal

import "C"

import (
	"fmt"

	"ioriotng/internal/flags"
	. "ioriotng/internal/generated/types"
)

type eventLoop struct {
	filter    *eventFilter
	enterEvs  map[uint32]*eventPair // Temp. store of sys_enter tracepoints per Tid.
	files     map[int32]file        // Track all open files by file descriptor.
	comms     map[uint32]string     // Program or thread name of the current Tid.
	prevPairs map[uint32]*eventPair // Previous event (to calculate time differences between two events)
}

func newEventLoop(flags flags.Flags) *eventLoop {
	return &eventLoop{
		filter:    newEventFilter(flags),
		enterEvs:  make(map[uint32]*eventPair),
		files:     make(map[int32]file),
		comms:     make(map[uint32]string),
		prevPairs: make(map[uint32]*eventPair),
	}
}

func (e *eventLoop) run(rawCh <-chan []byte) {
	fmt.Println(eventStreamHeader)
	for ev := range e.events(rawCh) {
		fmt.Println(ev.String())
		if ev.prevPair != nil {
			// Only recycle the previous event, as the current event is the previous event of the next event!
			ev.prevPair.recycle()
			continue
		}
	}
	fmt.Println("Good bye")
}

// Deserialise raw byte stream from BPF ringbuffer.
func (e *eventLoop) events(rawCh <-chan []byte) <-chan *eventPair {
	ch := make(chan *eventPair)

	go func() {
		defer close(ch)
		for raw := range rawCh {
			switch EventType(raw[0]) {
			case ENTER_OPEN_EVENT:
				if ev, ok := e.filter.openEvent(NewOpenEvent(raw)); ok {
					e.syscallEnter(ev)
				}
			case EXIT_OPEN_EVENT:
				e.syscallExit(NewFdEvent(raw), ch)
			case ENTER_FD_EVENT:
				e.syscallEnter(NewFdEvent(raw))
			case EXIT_FD_EVENT:
				e.syscallExit(NewFdEvent(raw), ch)
			case EXIT_NULL_EVENT:
				e.syscallExit(NewNullEvent(raw), ch)
			case EXIT_RET_EVENT:
				e.syscallExit(NewRetEvent(raw), ch)
			case ENTER_NAME_EVENT:
				e.syscallEnter(NewNameEvent(raw))
			case ENTER_PATH_EVENT:
				e.syscallEnter(NewPathEvent(raw))
			default:
				panic(fmt.Sprintf("unhandled event type %v: %v", EventType(raw[0]), raw))
			}
		}
	}()

	return ch
}

func (e *eventLoop) syscallEnter(enterEv event) {
	e.enterEvs[enterEv.GetTid()] = newEventPair(enterEv)
}

func (e *eventLoop) syscallExit(exitEv event, ch chan<- *eventPair) {
	ev, ok := e.enterEvs[exitEv.GetTid()]
	if !ok {
		exitEv.Recycle()
		return
	}
	delete(e.enterEvs, exitEv.GetTid())
	ev.exitEv = exitEv

	// Expect ID one lower, otherwise, enter and exit tracepoints
	// don't match up. E.g.:
	// enterEv:SYS_ENTER_OPEN => exitEv:SYS_EXIT_OPEN
	if ev.enterEv.GetTraceId()-1 != ev.exitEv.GetTraceId() {
		ev.tracepointMismatch = true
	}

	switch v := ev.enterEv.(type) {
	case *OpenEvent:
		openEv := ev.enterEv.(*OpenEvent)

		fd := int32(ev.exitEv.(*RetEvent).Ret)
		file := newFdFile(fd, string(openEv.Filename[:]))
		if fd >= 0 {
			e.files[fd] = file
		}
		ev.file = file

		comm := string(openEv.Comm[:])
		e.comms[openEv.Tid] = comm

	case *NameEvent:
		nameEvent := ev.enterEv.(*NameEvent)
		ev.file = oldnameNewnameFile{
			oldname: string(nameEvent.Oldname[:]),
			newname: string(nameEvent.Newname[:]),
		}
		ev.comm, _ = e.comms[ev.enterEv.GetTid()]

	case *PathEvent:
		nameEvent := ev.enterEv.(*PathEvent)
		ev.file = pathnameFile{string(nameEvent.Pathname[:])}
		ev.comm, _ = e.comms[ev.enterEv.GetTid()]

	case *FdEvent:
		fd := ev.enterEv.(*FdEvent).Fd
		if file_, ok := e.files[fd]; ok {
			ev.file = file_
			if ev.is(SYS_ENTER_CLOSE) {
				delete(e.files, fd)
			}
		} else {
			ev.file = newFdFileWithPid(fd, ev.enterEv.(*FdEvent).Pid)
		}
		ev.comm, _ = e.comms[ev.enterEv.GetTid()]

	case *NullEvent:
		ev.comm, _ = e.comms[ev.enterEv.GetTid()]

	default:
		panic(fmt.Sprintf("unknown type: %v", v))
	}

	ev.prevPair, _ = e.prevPairs[ev.enterEv.GetTid()]
	ev.calculateDurations()
	e.prevPairs[ev.enterEv.GetTid()] = ev
	ch <- ev
}