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