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