Commit | Line | Data |
---|---|---|
a0b1f42c | 1 | #!/usr/bin/env python3 |
9d16b343 MJ |
2 | # |
3 | # Copyright (C) 2016 Julien Desfossez <jdesfossez@efficios.com> | |
4 | # | |
5 | # SPDX-License-Identifier: GPL-2.0-only | |
6 | # | |
a0b1f42c | 7 | |
4c4634e3 FD |
8 | import argparse |
9 | import pprint | |
a0b1f42c JD |
10 | import sys |
11 | import time | |
2af9cd67 | 12 | import json |
4c4634e3 FD |
13 | |
14 | from collections import defaultdict | |
a0b1f42c JD |
15 | |
16 | NSEC_PER_SEC = 1000000000 | |
17 | ||
18 | try: | |
19 | from babeltrace import TraceCollection | |
20 | except ImportError: | |
21 | # quick fix for debian-based distros | |
22 | sys.path.append("/usr/local/lib/python%d.%d/site-packages" % | |
23 | (sys.version_info.major, sys.version_info.minor)) | |
24 | from babeltrace import TraceCollection | |
25 | ||
26 | ||
27 | class TraceParser: | |
28 | def __init__(self, trace, pid): | |
29 | self.trace = trace | |
30 | self.pid = pid | |
4c4634e3 FD |
31 | |
32 | # This dictionnary holds the results of each testcases of a test. | |
33 | # Its layout is the following: | |
34 | # self.expect={ | |
35 | # 'event_name_1': {'check_1': 0, 'check_2: 1}, | |
36 | # 'event_name_2': {'check_1': 1} | |
37 | # } | |
38 | # Each test classes checks the payload of different events. Each of | |
39 | # those checks are stored in a event_name specific dictionnary in this | |
40 | # data structure. | |
41 | self.expect = defaultdict(lambda : defaultdict(int)) | |
42 | ||
43 | # This dictionnary holds the value recorded in the trace that are | |
44 | # tested. Its content is use to print the values that caused a test to | |
45 | # fail. | |
46 | self.recorded_values = {} | |
a0b1f42c JD |
47 | |
48 | def ns_to_hour_nsec(self, ns): | |
49 | d = time.localtime(ns/NSEC_PER_SEC) | |
50 | return "%02d:%02d:%02d.%09d" % (d.tm_hour, d.tm_min, d.tm_sec, | |
51 | ns % NSEC_PER_SEC) | |
52 | ||
53 | def parse(self): | |
54 | # iterate over all the events | |
55 | for event in self.trace.events: | |
56 | if self.pid is not None and event["pid"] != self.pid: | |
57 | continue | |
58 | ||
59 | method_name = "handle_%s" % event.name.replace(":", "_").replace( | |
60 | "+", "_") | |
61 | # call the function to handle each event individually | |
62 | if hasattr(TraceParser, method_name): | |
63 | func = getattr(TraceParser, method_name) | |
64 | func(self, event) | |
65 | ||
66 | ret = 0 | |
4c4634e3 FD |
67 | # For each event of the test case, check all entries for failed |
68 | for event_name, event_results in self.expect.items(): | |
69 | for val in event_results.keys(): | |
70 | if self.expect[event_name][val] == 0: | |
71 | print("%s not validated" % val) | |
72 | print("Values of the local variables of this test:") | |
73 | # using pprint for pretty printing the dictionnary | |
74 | pprint.pprint(self.recorded_values[event_name]) | |
75 | ret = 1 | |
a0b1f42c JD |
76 | |
77 | return ret | |
78 | ||
79 | # epoll_ctl | |
80 | def handle_compat_syscall_entry_epoll_ctl(self, event): | |
81 | self.epoll_ctl_entry(event) | |
82 | ||
83 | def handle_compat_syscall_exit_epoll_ctl(self, event): | |
84 | self.epoll_ctl_exit(event) | |
85 | ||
86 | def handle_syscall_entry_epoll_ctl(self, event): | |
87 | self.epoll_ctl_entry(event) | |
88 | ||
89 | def handle_syscall_exit_epoll_ctl(self, event): | |
90 | self.epoll_ctl_exit(event) | |
91 | ||
92 | def epoll_ctl_entry(self, event): | |
93 | pass | |
94 | ||
95 | def epoll_ctl_exit(self, event): | |
96 | pass | |
97 | ||
98 | # epoll_wait + epoll_pwait | |
99 | def handle_compat_syscall_entry_epoll_wait(self, event): | |
100 | self.epoll_wait_entry(event) | |
101 | ||
102 | def handle_compat_syscall_exit_epoll_wait(self, event): | |
103 | self.epoll_wait_exit(event) | |
104 | ||
105 | def handle_syscall_entry_epoll_wait(self, event): | |
106 | self.epoll_wait_entry(event) | |
107 | ||
108 | def handle_syscall_exit_epoll_wait(self, event): | |
109 | self.epoll_wait_exit(event) | |
110 | ||
111 | def handle_compat_syscall_entry_epoll_pwait(self, event): | |
2af9cd67 | 112 | self.epoll_pwait_entry(event) |
a0b1f42c JD |
113 | |
114 | def handle_compat_syscall_exit_epoll_pwait(self, event): | |
2af9cd67 | 115 | self.epoll_pwait_exit(event) |
a0b1f42c JD |
116 | |
117 | def handle_syscall_entry_epoll_pwait(self, event): | |
2af9cd67 | 118 | self.epoll_pwait_entry(event) |
a0b1f42c JD |
119 | |
120 | def handle_syscall_exit_epoll_pwait(self, event): | |
2af9cd67 | 121 | self.epoll_pwait_exit(event) |
a0b1f42c JD |
122 | |
123 | def epoll_wait_entry(self, event): | |
124 | pass | |
125 | ||
126 | def epoll_wait_exit(self, event): | |
127 | pass | |
128 | ||
2af9cd67 JG |
129 | def epoll_pwait_entry(self, event): |
130 | self.epoll_wait_entry(event) | |
131 | ||
132 | def epoll_pwait_exit(self, event): | |
133 | self.epoll_wait_exit(event) | |
134 | ||
a0b1f42c JD |
135 | ## poll + ppoll |
136 | def handle_compat_syscall_entry_poll(self, event): | |
137 | self.poll_entry(event) | |
138 | ||
139 | def handle_compat_syscall_exit_poll(self, event): | |
140 | self.poll_exit(event) | |
141 | ||
142 | def handle_syscall_entry_poll(self, event): | |
143 | self.poll_entry(event) | |
144 | ||
145 | def handle_syscall_exit_poll(self, event): | |
146 | self.poll_exit(event) | |
147 | ||
148 | def handle_compat_syscall_entry_ppoll(self, event): | |
149 | self.poll_entry(event) | |
150 | ||
151 | def handle_compat_syscall_exit_ppoll(self, event): | |
152 | self.poll_exit(event) | |
153 | ||
154 | def handle_syscall_entry_ppoll(self, event): | |
155 | self.poll_entry(event) | |
156 | ||
157 | def handle_syscall_exit_ppoll(self, event): | |
158 | self.poll_exit(event) | |
159 | ||
160 | def poll_entry(self, event): | |
161 | pass | |
162 | ||
163 | def poll_exit(self, event): | |
164 | pass | |
165 | ||
166 | # epoll_create | |
167 | def handle_compat_syscall_entry_epoll_create1(self, event): | |
168 | self.epoll_create_entry(event) | |
169 | ||
170 | def handle_compat_syscall_exit_epoll_create1(self, event): | |
171 | self.epoll_create_exit(event) | |
172 | ||
173 | def handle_compat_syscall_entry_epoll_create(self, event): | |
174 | self.epoll_create_entry(event) | |
175 | ||
176 | def handle_compat_syscall_exit_epoll_create(self, event): | |
177 | self.epoll_create_exit(event) | |
178 | ||
179 | def handle_syscall_entry_epoll_create1(self, event): | |
180 | self.epoll_create_entry(event) | |
181 | ||
182 | def handle_syscall_exit_epoll_create1(self, event): | |
183 | self.epoll_create_exit(event) | |
184 | ||
185 | def handle_syscall_entry_epoll_create(self, event): | |
186 | self.epoll_create_entry(event) | |
187 | ||
188 | def handle_syscall_exit_epoll_create(self, event): | |
189 | self.epoll_create_exit(event) | |
190 | ||
191 | def epoll_create_entry(self, event): | |
192 | pass | |
193 | ||
194 | def epoll_create_exit(self, event): | |
195 | pass | |
196 | ||
197 | # select + pselect6 | |
198 | def handle_syscall_entry_pselect6(self, event): | |
199 | self.select_entry(event) | |
200 | ||
201 | def handle_syscall_exit_pselect6(self, event): | |
202 | self.select_exit(event) | |
203 | ||
204 | def handle_compat_syscall_entry_pselect6(self, event): | |
205 | self.select_entry(event) | |
206 | ||
207 | def handle_compat_syscall_exit_pselect6(self, event): | |
208 | self.select_exit(event) | |
209 | ||
210 | def handle_syscall_entry_select(self, event): | |
211 | self.select_entry(event) | |
212 | ||
213 | def handle_syscall_exit_select(self, event): | |
214 | self.select_exit(event) | |
215 | ||
216 | def handle_compat_syscall_entry_select(self, event): | |
217 | self.select_entry(event) | |
218 | ||
219 | def handle_compat_syscall_exit_select(self, event): | |
220 | self.select_exit(event) | |
221 | ||
222 | def select_entry(self, event): | |
223 | pass | |
224 | ||
225 | def select_exit(self, event): | |
226 | pass | |
227 | ||
228 | ||
229 | class Test1(TraceParser): | |
2af9cd67 JG |
230 | def __init__(self, trace, validation_args): |
231 | super().__init__(trace, validation_args['pid']) | |
232 | ||
233 | # Values expected in the trace | |
234 | self.epoll_wait_fd = validation_args['epoll_wait_fd'] | |
235 | self.epoll_pwait_fd = validation_args['epoll_pwait_fd'] | |
236 | ||
4c4634e3 FD |
237 | self.expect["select_entry"]["select_in_fd0"] = 0 |
238 | self.expect["select_entry"]["select_in_fd1023"] = 0 | |
239 | self.expect["select_exit"]["select_out_fd0"] = 0 | |
240 | self.expect["select_exit"]["select_out_fd1023"] = 0 | |
241 | self.expect["poll_entry"]["poll_in_nfds1"] = 0 | |
242 | self.expect["poll_exit"]["poll_out_nfds1"] = 0 | |
243 | self.expect["epoll_ctl_entry"]["epoll_ctl_in_add"] = 0 | |
244 | self.expect["epoll_ctl_exit"]["epoll_ctl_out_ok"] = 0 | |
245 | self.expect["epoll_wait_entry"]["epoll_wait_in_ok"] = 0 | |
246 | self.expect["epoll_wait_exit"]["epoll_wait_out_fd0"] = 0 | |
2af9cd67 JG |
247 | self.expect["epoll_pwait_entry"]["epoll_pwait_in_ok"] = 0 |
248 | self.expect["epoll_pwait_exit"]["epoll_pwait_out_fd0"] = 0 | |
a0b1f42c JD |
249 | |
250 | def select_entry(self, event): | |
a0b1f42c JD |
251 | n = event["n"] |
252 | overflow = event["overflow"] | |
4c4634e3 | 253 | readfd_0 = event["readfds"][0] |
a0b1f42c JD |
254 | |
255 | # check that the FD 0 is actually set in the readfds | |
4c4634e3 FD |
256 | if n == 1 and readfd_0 == 1: |
257 | self.expect["select_entry"]["select_in_fd0"] = 1 | |
a0b1f42c | 258 | if n == 1023: |
4c4634e3 FD |
259 | readfd_127 = event["readfds"][127] |
260 | writefd_127 = event["writefds"][127] | |
261 | exceptfd_127 = event["exceptfds"][127] | |
262 | ||
a0b1f42c | 263 | # check that the FD 1023 is actually set in the readfds |
4c4634e3 FD |
264 | if readfd_127 == 0x40 and writefd_127 == 0 and \ |
265 | exceptfd_127 == 0 and overflow == 0: | |
266 | self.expect["select_entry"]["select_in_fd1023"] = 1 | |
267 | ||
268 | # Save values of local variables to print in case of test failure | |
269 | self.recorded_values["select_entry"] = locals() | |
a0b1f42c JD |
270 | |
271 | def select_exit(self, event): | |
a0b1f42c | 272 | ret = event["ret"] |
a0b1f42c | 273 | tvp = event["tvp"] |
4c4634e3 | 274 | overflow = event["overflow"] |
a0b1f42c | 275 | _readfds_length = event["_readfds_length"] |
a0b1f42c JD |
276 | |
277 | if ret == 1: | |
278 | # check that the FD 0 is actually set in the readfds | |
4c4634e3 FD |
279 | readfd_0 = event["readfds"][0] |
280 | ||
281 | if readfd_0 == 1: | |
282 | self.expect["select_exit"]["select_out_fd0"] = 1 | |
a0b1f42c | 283 | # check that the FD 1023 is actually set in the readfds |
4c4634e3 FD |
284 | if _readfds_length == 128: |
285 | readfd_127 = event["readfds"][127] | |
286 | writefd_127 = event["writefds"][127] | |
287 | exceptfd_127 = event["exceptfds"][127] | |
288 | if readfd_127 == 0x40 and writefd_127 == 0 and \ | |
289 | exceptfd_127 == 0 and tvp == 0: | |
290 | self.expect["select_exit"]["select_out_fd1023"] = 1 | |
291 | ||
292 | # Save values of local variables to print in case of test failure | |
293 | self.recorded_values["select_exit"] = locals() | |
a0b1f42c JD |
294 | |
295 | def poll_entry(self, event): | |
a0b1f42c JD |
296 | nfds = event["nfds"] |
297 | fds_length = event["fds_length"] | |
298 | overflow = event["overflow"] | |
a0b1f42c JD |
299 | |
300 | # check that only one FD is set, that it has the POLLIN flag and that | |
301 | # the raw value matches the events bit field. | |
4c4634e3 FD |
302 | if nfds == 1 and fds_length == 1: |
303 | fd_0 = event["fds"][0] | |
304 | if fd_0["raw_events"] == 0x3 and fd_0["events"]["POLLIN"] == 1 and \ | |
305 | fd_0["events"]["padding"] == 0: | |
306 | self.expect["poll_entry"]["poll_in_nfds1"] = 1 | |
307 | ||
308 | # Save values of local variables to print in case of test failure | |
309 | self.recorded_values["poll_entry"] = locals() | |
a0b1f42c JD |
310 | |
311 | def poll_exit(self, event): | |
a0b1f42c | 312 | ret = event["ret"] |
a0b1f42c | 313 | fds_length = event["fds_length"] |
a0b1f42c JD |
314 | |
315 | # check that only one FD is set, that it has the POLLIN flag and that | |
316 | # the raw value matches the events bit field. | |
4c4634e3 FD |
317 | if ret == 1 and fds_length == 1: |
318 | fd_0 = event["fds"][0] | |
319 | if fd_0["raw_events"] == 0x1 and fd_0["events"]["POLLIN"] == 1 and \ | |
320 | fd_0["events"]["padding"] == 0: | |
321 | self.expect["poll_exit"]["poll_out_nfds1"] = 1 | |
322 | ||
323 | # Save values of local variables to print in case of test failure | |
324 | self.recorded_values["poll_exit"] = locals() | |
a0b1f42c JD |
325 | |
326 | def epoll_ctl_entry(self, event): | |
a0b1f42c JD |
327 | epfd = event["epfd"] |
328 | op_enum = event["op_enum"] | |
329 | fd = event["fd"] | |
330 | _event = event["event"] | |
331 | ||
332 | # check that we have FD 0 waiting for EPOLLIN|EPOLLPRI and that | |
333 | # data.fd = 0 | |
b1986eff | 334 | if (epfd == self.epoll_wait_fd or epfd == self.epoll_pwait_fd) and 'EPOLL_CTL_ADD' == op_enum and fd == 0 and \ |
a0b1f42c JD |
335 | _event["data_union"]["fd"] == 0 and \ |
336 | _event["events"]["EPOLLIN"] == 1 and \ | |
337 | _event["events"]["EPOLLPRI"] == 1: | |
4c4634e3 FD |
338 | self.expect["epoll_ctl_entry"]["epoll_ctl_in_add"] = 1 |
339 | ||
340 | # Save values of local variables to print in case of test failure | |
341 | self.recorded_values["epoll_ctl_entry"] = locals() | |
a0b1f42c JD |
342 | |
343 | def epoll_ctl_exit(self, event): | |
a0b1f42c JD |
344 | ret = event["ret"] |
345 | ||
346 | if ret == 0: | |
4c4634e3 FD |
347 | self.expect["epoll_ctl_exit"]["epoll_ctl_out_ok"] = 1 |
348 | ||
349 | # Save values of local variables to print in case of test failure | |
350 | self.recorded_values["epoll_ctl_exit"] = locals() | |
a0b1f42c JD |
351 | |
352 | def epoll_wait_entry(self, event): | |
a0b1f42c JD |
353 | epfd = event["epfd"] |
354 | maxevents = event["maxevents"] | |
355 | timeout = event["timeout"] | |
356 | ||
2af9cd67 | 357 | if epfd == self.epoll_wait_fd and maxevents == 1 and timeout == -1: |
4c4634e3 FD |
358 | self.expect["epoll_wait_entry"]["epoll_wait_in_ok"] = 1 |
359 | ||
360 | # Save values of local variables to print in case of test failure | |
361 | self.recorded_values["epoll_wait_entry"] = locals() | |
a0b1f42c JD |
362 | |
363 | def epoll_wait_exit(self, event): | |
a0b1f42c JD |
364 | ret = event["ret"] |
365 | fds_length = event["fds_length"] | |
366 | overflow = event["overflow"] | |
a0b1f42c JD |
367 | |
368 | # check that FD 0 returned with EPOLLIN and the right data.fd | |
4c4634e3 FD |
369 | if ret == 1 and fds_length == 1: |
370 | fd_0 = event["fds"][0] | |
371 | if overflow == 0 and fd_0["data_union"]["fd"] == 0 and \ | |
372 | fd_0["events"]["EPOLLIN"] == 1: | |
373 | self.expect["epoll_wait_exit"]["epoll_wait_out_fd0"] = 1 | |
374 | ||
375 | # Save values of local variables to print in case of test failure | |
376 | self.recorded_values["epoll_wait_exit"] = locals() | |
a0b1f42c | 377 | |
2af9cd67 JG |
378 | def epoll_pwait_entry(self, event): |
379 | epfd = event["epfd"] | |
380 | maxevents = event["maxevents"] | |
381 | timeout = event["timeout"] | |
382 | ||
383 | if epfd == self.epoll_pwait_fd and maxevents == 1 and timeout == -1: | |
384 | self.expect["epoll_pwait_entry"]["epoll_pwait_in_ok"] = 1 | |
385 | ||
386 | # Save values of local variables to print in case of test failure | |
387 | self.recorded_values["epoll_pwait_entry"] = locals() | |
388 | ||
389 | def epoll_pwait_exit(self, event): | |
390 | ret = event["ret"] | |
391 | fds_length = event["fds_length"] | |
392 | overflow = event["overflow"] | |
393 | ||
394 | # check that FD 0 returned with EPOLLIN and the right data.fd | |
395 | if ret == 1 and fds_length == 1: | |
396 | fd_0 = event["fds"][0] | |
397 | if overflow == 0 and fd_0["data_union"]["fd"] == 0 and \ | |
398 | fd_0["events"]["EPOLLIN"] == 1: | |
399 | self.expect["epoll_pwait_exit"]["epoll_pwait_out_fd0"] = 1 | |
400 | ||
401 | # Save values of local variables to print in case of test failure | |
402 | self.recorded_values["epoll_pwait_exit"] = locals() | |
a0b1f42c JD |
403 | |
404 | class Test2(TraceParser): | |
2af9cd67 JG |
405 | def __init__(self, trace, validation_args): |
406 | super().__init__(trace, validation_args['pid']) | |
4c4634e3 FD |
407 | self.expect["select_entry"]["select_timeout_in_fd0"] = 0 |
408 | self.expect["select_entry"]["select_timeout_in_fd1023"] = 0 | |
409 | self.expect["select_exit"]["select_timeout_out"] = 0 | |
410 | self.expect["poll_entry"]["poll_timeout_in"] = 0 | |
411 | self.expect["poll_exit"]["poll_timeout_out"] = 0 | |
412 | self.expect["epoll_ctl_entry"]["epoll_ctl_timeout_in_add"] = 0 | |
413 | self.expect["epoll_ctl_exit"]["epoll_ctl_timeout_out_ok"] = 0 | |
414 | self.expect["epoll_wait_entry"]["epoll_wait_timeout_in"] = 0 | |
415 | self.expect["epoll_wait_exit"]["epoll_wait_timeout_out"] = 0 | |
a0b1f42c JD |
416 | |
417 | def select_entry(self, event): | |
a0b1f42c | 418 | n = event["n"] |
a0b1f42c | 419 | tvp = event["tvp"] |
a0b1f42c JD |
420 | |
421 | if n == 1 and tvp != 0: | |
4c4634e3 | 422 | self.expect["select_entry"]["select_timeout_in_fd0"] = 1 |
a0b1f42c | 423 | if n == 1023: |
4c4634e3 FD |
424 | readfd_127 = event["readfds"][127] |
425 | writefd_127 = event["writefds"][127] | |
426 | exceptfd_127 = event["exceptfds"][127] | |
427 | ||
428 | if readfd_127 == 0x40 and writefd_127 == 0 and \ | |
429 | exceptfd_127 == 0 and tvp != 0: | |
430 | self.expect["select_entry"]["select_timeout_in_fd1023"] = 1 | |
431 | ||
432 | # Save values of local variables to print in case of test failure | |
433 | self.recorded_values["select_entry"] = locals() | |
a0b1f42c JD |
434 | |
435 | def select_exit(self, event): | |
a0b1f42c | 436 | ret = event["ret"] |
a0b1f42c | 437 | tvp = event["tvp"] |
a0b1f42c JD |
438 | |
439 | if ret == 0 and tvp != 0: | |
4c4634e3 FD |
440 | self.expect["select_exit"]["select_timeout_out"] = 1 |
441 | ||
442 | # Save values of local variables to print in case of test failure | |
443 | self.recorded_values["select_exit"] = locals() | |
a0b1f42c JD |
444 | |
445 | def poll_entry(self, event): | |
a0b1f42c JD |
446 | nfds = event["nfds"] |
447 | fds_length = event["fds_length"] | |
a0b1f42c JD |
448 | |
449 | # check that we wait on FD 0 for POLLIN and that the raw_events | |
450 | # field matches the value of POLLIN | |
4c4634e3 FD |
451 | if nfds == 1 and fds_length == 1: |
452 | fd_0 = event["fds"][0] | |
453 | if fd_0["raw_events"] == 0x3 and \ | |
454 | fd_0["events"]["POLLIN"] == 1 and \ | |
455 | fd_0["events"]["padding"] == 0: | |
456 | self.expect["poll_entry"]["poll_timeout_in"] = 1 | |
457 | ||
458 | # Save values of local variables to print in case of test failure | |
459 | self.recorded_values["poll_entry"] = locals() | |
a0b1f42c JD |
460 | |
461 | def poll_exit(self, event): | |
a0b1f42c JD |
462 | ret = event["ret"] |
463 | nfds = event["nfds"] | |
464 | fds_length = event["fds_length"] | |
a0b1f42c JD |
465 | |
466 | if ret == 0 and nfds == 1 and fds_length == 0: | |
4c4634e3 FD |
467 | self.expect["poll_exit"]["poll_timeout_out"] = 1 |
468 | ||
469 | # Save values of local variables to print in case of test failure | |
470 | self.recorded_values["poll_exit"] = locals() | |
a0b1f42c JD |
471 | |
472 | def epoll_ctl_entry(self, event): | |
a0b1f42c | 473 | op_enum = event["op_enum"] |
a0b1f42c JD |
474 | _event = event["event"] |
475 | ||
476 | # make sure we see a EPOLLIN|EPOLLPRI | |
477 | if op_enum == "EPOLL_CTL_ADD" and \ | |
478 | _event["events"]["EPOLLIN"] == 1 and \ | |
479 | _event["events"]["EPOLLPRI"] == 1: | |
4c4634e3 FD |
480 | self.expect["epoll_ctl_entry"]["epoll_ctl_timeout_in_add"] = 1 |
481 | ||
482 | # Save values of local variables to print in case of test failure | |
483 | self.recorded_values["epoll_ctl_entry"] = locals() | |
a0b1f42c JD |
484 | |
485 | def epoll_ctl_exit(self, event): | |
a0b1f42c JD |
486 | ret = event["ret"] |
487 | ||
488 | if ret == 0: | |
4c4634e3 FD |
489 | self.expect["epoll_ctl_exit"]["epoll_ctl_timeout_out_ok"] = 1 |
490 | ||
491 | # Save values of local variables to print in case of test failure | |
492 | self.recorded_values["epoll_ctl_exit"] = locals() | |
a0b1f42c JD |
493 | |
494 | def epoll_wait_entry(self, event): | |
a0b1f42c JD |
495 | maxevents = event["maxevents"] |
496 | timeout = event["timeout"] | |
497 | ||
498 | if maxevents == 1 and timeout == 1: | |
4c4634e3 FD |
499 | self.expect["epoll_wait_entry"]["epoll_wait_timeout_in"] = 1 |
500 | ||
501 | # Save values of local variables to print in case of test failure | |
502 | self.recorded_values["epoll_wait_entry"] = locals() | |
a0b1f42c JD |
503 | |
504 | def epoll_wait_exit(self, event): | |
a0b1f42c JD |
505 | ret = event["ret"] |
506 | fds_length = event["fds_length"] | |
507 | overflow = event["overflow"] | |
a0b1f42c JD |
508 | |
509 | if ret == 0 and fds_length == 0 and overflow == 0: | |
4c4634e3 FD |
510 | self.expect["epoll_wait_exit"]["epoll_wait_timeout_out"] = 1 |
511 | ||
512 | # Save values of local variables to print in case of test failure | |
513 | self.recorded_values["epoll_wait_exit"] = locals() | |
a0b1f42c JD |
514 | |
515 | ||
516 | class Test3(TraceParser): | |
2af9cd67 JG |
517 | def __init__(self, trace, validation_args): |
518 | super().__init__(trace, validation_args['pid']) | |
4c4634e3 FD |
519 | self.expect["select_entry"]["select_invalid_fd_in"] = 0 |
520 | self.expect["select_exit"]["select_invalid_fd_out"] = 0 | |
a0b1f42c JD |
521 | |
522 | def select_entry(self, event): | |
a0b1f42c JD |
523 | n = event["n"] |
524 | overflow = event["overflow"] | |
a0b1f42c | 525 | |
8b3b99e2 | 526 | if n > 0 and overflow == 0: |
4c4634e3 FD |
527 | self.expect["select_entry"]["select_invalid_fd_in"] = 1 |
528 | ||
529 | # Save values of local variables to print in case of test failure | |
530 | self.recorded_values["select_entry"] = locals() | |
a0b1f42c JD |
531 | |
532 | def select_exit(self, event): | |
a0b1f42c JD |
533 | ret = event["ret"] |
534 | overflow = event["overflow"] | |
a0b1f42c | 535 | _readfds_length = event["_readfds_length"] |
a0b1f42c | 536 | |
8b3b99e2 | 537 | # make sure the event has a ret field equal to -EBADF |
a0b1f42c | 538 | if ret == -9 and overflow == 0 and _readfds_length == 0: |
4c4634e3 FD |
539 | self.expect["select_exit"]["select_invalid_fd_out"] = 1 |
540 | ||
541 | # Save values of local variables to print in case of test failure | |
542 | self.recorded_values["select_exit"] = locals() | |
a0b1f42c JD |
543 | |
544 | ||
545 | class Test4(TraceParser): | |
2af9cd67 JG |
546 | def __init__(self, trace, validation_args): |
547 | super().__init__(trace, validation_args['pid']) | |
4c4634e3 FD |
548 | self.expect["poll_entry"]["big_poll_in"] = 0 |
549 | self.expect["poll_exit"]["big_poll_out"] = 0 | |
a0b1f42c JD |
550 | |
551 | def poll_entry(self, event): | |
a0b1f42c JD |
552 | nfds = event["nfds"] |
553 | fds_length = event["fds_length"] | |
554 | overflow = event["overflow"] | |
a0b1f42c JD |
555 | |
556 | # test of big list of FDs and the behaviour of the overflow | |
4c4634e3 FD |
557 | if nfds == 2047 and fds_length == 512 and overflow == 1: |
558 | fd_0 = event["fds"][0] | |
559 | fd_511 = event["fds"][511] | |
560 | if fd_0["raw_events"] == 0x3 and fd_0["events"]["POLLIN"] == 1 and \ | |
561 | fd_0["events"]["padding"] == 0 and \ | |
562 | fd_511["events"]["POLLIN"] == 1 and \ | |
563 | fd_511["events"]["POLLPRI"] == 1: | |
564 | self.expect["poll_entry"]["big_poll_in"] = 1 | |
565 | ||
566 | # Save values of local variables to print in case of test failure | |
567 | self.recorded_values["poll_entry"] = locals() | |
a0b1f42c JD |
568 | |
569 | def poll_exit(self, event): | |
a0b1f42c JD |
570 | ret = event["ret"] |
571 | nfds = event["nfds"] | |
572 | fds_length = event["fds_length"] | |
573 | overflow = event["overflow"] | |
a0b1f42c JD |
574 | |
575 | # test of big list of FDs and the behaviour of the overflow | |
4c4634e3 FD |
576 | if ret == 2047 and nfds == 2047 and fds_length == 512 and overflow == 1: |
577 | fd_0 = event["fds"][0] | |
578 | fd_511 = event["fds"][511] | |
579 | if fd_0["events"]["POLLIN"] == 1 and fd_511["events"]["POLLIN"] == 1: | |
580 | self.expect["poll_exit"]["big_poll_out"] = 1 | |
a0b1f42c | 581 | |
4c4634e3 FD |
582 | # Save values of local variables to print in case of test failure |
583 | self.recorded_values["poll_exit"] = locals() | |
a0b1f42c JD |
584 | |
585 | class Test5(TraceParser): | |
2af9cd67 JG |
586 | def __init__(self, trace, validation_args): |
587 | super().__init__(trace, validation_args['pid']) | |
4c4634e3 FD |
588 | self.expect["poll_entry"]["poll_overflow_in"] = 0 |
589 | self.expect["poll_exit"]["poll_overflow_out"] = 0 | |
a0b1f42c JD |
590 | |
591 | def poll_entry(self, event): | |
a0b1f42c JD |
592 | nfds = event["nfds"] |
593 | fds_length = event["fds_length"] | |
594 | overflow = event["overflow"] | |
a0b1f42c JD |
595 | |
596 | # test that event in valid even though the target buffer is too small | |
597 | # and the program segfaults | |
4c4634e3 FD |
598 | if nfds == 100 and fds_length == 100 and overflow == 0: |
599 | fd_0 = event["fds"][0] | |
600 | if fd_0["events"]["POLLIN"] == 1: | |
601 | self.expect["poll_entry"]["poll_overflow_in"] = 1 | |
602 | ||
603 | # Save values of local variables to print in case of test failure | |
604 | self.recorded_values["poll_entry"] = locals() | |
a0b1f42c JD |
605 | |
606 | def poll_exit(self, event): | |
a0b1f42c | 607 | nfds = event["nfds"] |
a0b1f42c | 608 | overflow = event["overflow"] |
a0b1f42c JD |
609 | |
610 | # test that event in valid even though the target buffer is too small | |
611 | # and the program segfaults | |
612 | if nfds == 100 and overflow == 0: | |
4c4634e3 FD |
613 | self.expect["poll_exit"]["poll_overflow_out"] = 1 |
614 | ||
615 | # Save values of local variables to print in case of test failure | |
616 | self.recorded_values["poll_exit"] = locals() | |
a0b1f42c JD |
617 | |
618 | ||
619 | class Test6(TraceParser): | |
2af9cd67 JG |
620 | def __init__(self, trace, validation_args): |
621 | super().__init__(trace, validation_args['pid']) | |
4c4634e3 FD |
622 | self.expect["select_entry"]["pselect_invalid_in"] = 0 |
623 | self.expect["select_exit"]["pselect_invalid_out"] = 0 | |
a0b1f42c JD |
624 | |
625 | def select_entry(self, event): | |
a0b1f42c JD |
626 | n = event["n"] |
627 | overflow = event["overflow"] | |
a0b1f42c | 628 | _readfds_length = event["_readfds_length"] |
a0b1f42c JD |
629 | |
630 | # test that event in valid even though the target buffer pointer is | |
631 | # invalid and the program segfaults | |
632 | if n == 1 and overflow == 0 and _readfds_length == 0: | |
4c4634e3 FD |
633 | self.expect["select_entry"]["pselect_invalid_in"] = 1 |
634 | ||
635 | # Save values of local variables to print in case of test failure | |
636 | self.recorded_values["select_entry"] = locals() | |
a0b1f42c JD |
637 | |
638 | def select_exit(self, event): | |
a0b1f42c JD |
639 | ret = event["ret"] |
640 | overflow = event["overflow"] | |
a0b1f42c | 641 | _readfds_length = event["_readfds_length"] |
a0b1f42c JD |
642 | |
643 | # test that event in valid even though the target buffer pointer is | |
644 | # invalid and the program segfaults | |
645 | if ret == -14 and overflow == 0 and _readfds_length == 0: | |
4c4634e3 FD |
646 | self.expect["select_exit"]["pselect_invalid_out"] = 1 |
647 | ||
648 | # Save values of local variables to print in case of test failure | |
649 | self.recorded_values["select_exit"] = locals() | |
a0b1f42c JD |
650 | |
651 | ||
652 | class Test7(TraceParser): | |
2af9cd67 JG |
653 | def __init__(self, trace, validation_args): |
654 | super().__init__(trace, validation_args['pid']) | |
4c4634e3 FD |
655 | self.expect["poll_entry"]["poll_max_in"] = 0 |
656 | self.expect["poll_exit"]["poll_max_out"] = 0 | |
a0b1f42c JD |
657 | |
658 | def poll_entry(self, event): | |
a0b1f42c | 659 | nfds = event["nfds"] |
a0b1f42c | 660 | overflow = event["overflow"] |
a0b1f42c JD |
661 | |
662 | # check the proper working of INT_MAX maxevent value | |
663 | if nfds == 4294967295 and overflow == 1: | |
4c4634e3 FD |
664 | self.expect["poll_entry"]["poll_max_in"] = 1 |
665 | ||
666 | # Save values of local variables to print in case of test failure | |
667 | self.recorded_values["poll_entry"] = locals() | |
668 | ||
a0b1f42c JD |
669 | |
670 | def poll_exit(self, event): | |
a0b1f42c JD |
671 | ret = event["ret"] |
672 | nfds = event["nfds"] | |
a0b1f42c | 673 | overflow = event["overflow"] |
a0b1f42c JD |
674 | |
675 | # check the proper working of UINT_MAX maxevent value | |
676 | if ret == -22 and nfds == 4294967295 and overflow == 0: | |
4c4634e3 FD |
677 | self.expect["poll_exit"]["poll_max_out"] = 1 |
678 | ||
679 | # Save values of local variables to print in case of test failure | |
680 | self.recorded_values["poll_exit"] = locals() | |
a0b1f42c JD |
681 | |
682 | ||
683 | class Test8(TraceParser): | |
2af9cd67 JG |
684 | def __init__(self, trace, validation_args): |
685 | super().__init__(trace, validation_args['pid']) | |
686 | ||
687 | # Values expected in the trace | |
688 | self.epoll_fd = validation_args['epollfd'] | |
689 | ||
4c4634e3 FD |
690 | self.expect["epoll_wait_entry"]["epoll_wait_invalid_in"] = 0 |
691 | self.expect["epoll_wait_exit"]["epoll_wait_invalid_out"] = 0 | |
a0b1f42c JD |
692 | |
693 | def epoll_wait_entry(self, event): | |
a0b1f42c JD |
694 | epfd = event["epfd"] |
695 | maxevents = event["maxevents"] | |
696 | timeout = event["timeout"] | |
697 | ||
698 | # test that event in valid even though the target buffer pointer is | |
699 | # invalid and the program segfaults | |
2af9cd67 | 700 | if epfd == self.epoll_fd and maxevents == 1 and timeout == -1: |
4c4634e3 FD |
701 | self.expect["epoll_wait_entry"]["epoll_wait_invalid_in"] = 1 |
702 | ||
703 | # Save values of local variables to print in case of test failure | |
704 | self.recorded_values["epoll_wait_entry"] = locals() | |
a0b1f42c JD |
705 | |
706 | def epoll_wait_exit(self, event): | |
a0b1f42c JD |
707 | ret = event["ret"] |
708 | fds_length = event["fds_length"] | |
709 | overflow = event["overflow"] | |
a0b1f42c JD |
710 | |
711 | # test that event in valid even though the target buffer pointer is | |
712 | # invalid and the program segfaults | |
713 | if ret == -14 and fds_length == 0 and overflow == 0: | |
4c4634e3 FD |
714 | self.expect["epoll_wait_exit"]["epoll_wait_invalid_out"] = 1 |
715 | ||
716 | # Save values of local variables to print in case of test failure | |
717 | self.recorded_values["epoll_wait_exit"] = locals() | |
a0b1f42c JD |
718 | |
719 | ||
720 | class Test9(TraceParser): | |
2af9cd67 JG |
721 | def __init__(self, trace, validation_args): |
722 | super().__init__(trace, validation_args['pid']) | |
723 | ||
724 | # Values expected in the trace | |
725 | self.epoll_fd = validation_args['epollfd'] | |
726 | ||
4c4634e3 FD |
727 | self.expect["epoll_wait_entry"]["epoll_wait_max_in"] = 0 |
728 | self.expect["epoll_wait_exit"]["epoll_wait_max_out"] = 0 | |
a0b1f42c JD |
729 | |
730 | def epoll_wait_entry(self, event): | |
a0b1f42c JD |
731 | epfd = event["epfd"] |
732 | maxevents = event["maxevents"] | |
733 | timeout = event["timeout"] | |
734 | ||
735 | # check the proper working of INT_MAX maxevent value | |
2af9cd67 | 736 | if epfd == self.epoll_fd and maxevents == 2147483647 and timeout == -1: |
4c4634e3 FD |
737 | self.expect["epoll_wait_entry"]["epoll_wait_max_in"] = 1 |
738 | ||
739 | # Save values of local variables to print in case of test failure | |
740 | self.recorded_values["epoll_wait_entry"] = locals() | |
a0b1f42c JD |
741 | |
742 | def epoll_wait_exit(self, event): | |
a0b1f42c JD |
743 | ret = event["ret"] |
744 | fds_length = event["fds_length"] | |
745 | overflow = event["overflow"] | |
a0b1f42c JD |
746 | |
747 | # check the proper working of INT_MAX maxevent value | |
748 | if ret == -22 and fds_length == 0 and overflow == 0: | |
4c4634e3 FD |
749 | self.expect["epoll_wait_exit"]["epoll_wait_max_out"] = 1 |
750 | ||
751 | # Save values of local variables to print in case of test failure | |
752 | self.recorded_values["epoll_wait_exit"] = locals() | |
a0b1f42c JD |
753 | |
754 | ||
755 | if __name__ == "__main__": | |
756 | parser = argparse.ArgumentParser(description='Trace parser') | |
757 | parser.add_argument('path', metavar="<path/to/trace>", help='Trace path') | |
758 | parser.add_argument('-t', '--test', type=int, help='Test to validate') | |
2af9cd67 | 759 | parser.add_argument('-o', '--validation-file', type=str, help='Validation file path') |
a0b1f42c JD |
760 | args = parser.parse_args() |
761 | ||
762 | if not args.test: | |
2af9cd67 | 763 | print("Need to pass a test to validate (--test/-t)") |
a0b1f42c JD |
764 | sys.exit(1) |
765 | ||
2af9cd67 JG |
766 | if not args.validation_file: |
767 | print("Need to pass the test validation file (--validation-file/-o)") | |
a0b1f42c JD |
768 | sys.exit(1) |
769 | ||
770 | traces = TraceCollection() | |
771 | handle = traces.add_traces_recursive(args.path, "ctf") | |
772 | if handle is None: | |
773 | sys.exit(1) | |
774 | ||
2af9cd67 JG |
775 | with open(args.validation_file) as f: |
776 | try: | |
777 | test_validation_args = json.load(f) | |
778 | except Exception as e: | |
779 | print('Failed to parse validation file: ' + str(e)) | |
780 | sys.exit(1) | |
781 | ||
a0b1f42c JD |
782 | t = None |
783 | ||
784 | if args.test == 1: | |
2af9cd67 | 785 | t = Test1(traces, test_validation_args) |
a0b1f42c | 786 | elif args.test == 2: |
2af9cd67 | 787 | t = Test2(traces, test_validation_args) |
a0b1f42c | 788 | elif args.test == 3: |
2af9cd67 | 789 | t = Test3(traces, test_validation_args) |
a0b1f42c | 790 | elif args.test == 4: |
2af9cd67 | 791 | t = Test4(traces, test_validation_args) |
a0b1f42c | 792 | elif args.test == 5: |
2af9cd67 | 793 | t = Test5(traces, test_validation_args) |
a0b1f42c | 794 | elif args.test == 6: |
2af9cd67 | 795 | t = Test6(traces, test_validation_args) |
a0b1f42c | 796 | elif args.test == 7: |
2af9cd67 | 797 | t = Test7(traces, test_validation_args) |
a0b1f42c | 798 | elif args.test == 8: |
2af9cd67 | 799 | t = Test8(traces, test_validation_args) |
a0b1f42c | 800 | elif args.test == 9: |
2af9cd67 | 801 | t = Test9(traces, test_validation_args) |
a0b1f42c JD |
802 | elif args.test == 10: |
803 | # stress test, nothing reliable to check | |
804 | ret = 0 | |
805 | elif args.test == 11: | |
806 | # stress test, nothing reliable to check | |
807 | ret = 0 | |
808 | else: | |
809 | print("Invalid test case") | |
810 | sys.exit(1) | |
811 | ||
812 | if t is not None: | |
813 | ret = t.parse() | |
814 | ||
815 | for h in handle.values(): | |
816 | traces.remove_trace(h) | |
817 | ||
818 | sys.exit(ret) |