1import random
2
3import gdbremote_testcase
4from lldbsuite.test.decorators import *
5from lldbsuite.test.lldbtest import *
6from lldbsuite.test import lldbutil
7
8class TestGdbRemoteFork(gdbremote_testcase.GdbRemoteTestCaseBase):
9
10    fork_regex = ("[$]T05thread:p([0-9a-f]+)[.]([0-9a-f]+);.*"
11                  "{}:p([0-9a-f]+)[.]([0-9a-f]+).*")
12    fork_regex_nonstop = ("%Stop:T05thread:p([0-9a-f]+)[.]([0-9a-f]+);.*"
13                          "{}:p([0-9a-f]+)[.]([0-9a-f]+).*")
14    fork_capture = {1: "parent_pid", 2: "parent_tid",
15                    3: "child_pid", 4: "child_tid"}
16
17    def start_fork_test(self, args, variant="fork", nonstop=False):
18        self.build()
19        self.prep_debug_monitor_and_inferior(inferior_args=args)
20        self.add_qSupported_packets(["multiprocess+",
21                                     "{}-events+".format(variant)])
22        ret = self.expect_gdbremote_sequence()
23        self.assertIn("{}-events+".format(variant), ret["qSupported_response"])
24        self.reset_test_sequence()
25
26        # continue and expect fork
27        if nonstop:
28            self.test_sequence.add_log_lines([
29                "read packet: $QNonStop:1#00",
30                "send packet: $OK#00",
31                "read packet: $c#00",
32                "send packet: $OK#00",
33                {"direction": "send",
34                 "regex": self.fork_regex_nonstop.format(variant),
35                 "capture": self.fork_capture},
36                "read packet: $vStopped#00",
37                "send packet: $OK#00",
38            ], True)
39        else:
40            self.test_sequence.add_log_lines([
41                "read packet: $c#00",
42                {"direction": "send", "regex": self.fork_regex.format(variant),
43                 "capture": self.fork_capture},
44            ], True)
45        ret = self.expect_gdbremote_sequence()
46        self.reset_test_sequence()
47
48        return tuple(ret[x] for x in ("parent_pid", "parent_tid",
49                                      "child_pid", "child_tid"))
50
51    @add_test_categories(["fork"])
52    def test_fork_multithreaded(self):
53        _, _, child_pid, _ = self.start_fork_test(["thread:new"]*2 + ["fork"])
54
55        # detach the forked child
56        self.test_sequence.add_log_lines([
57            "read packet: $D;{}#00".format(child_pid),
58            "send packet: $OK#00",
59            "read packet: $k#00",
60        ], True)
61        self.expect_gdbremote_sequence()
62
63    def fork_and_detach_test(self, variant, nonstop=False):
64        parent_pid, parent_tid, child_pid, child_tid = (
65            self.start_fork_test([variant], variant, nonstop=nonstop))
66
67        # detach the forked child
68        self.test_sequence.add_log_lines([
69            "read packet: $D;{}#00".format(child_pid),
70            "send packet: $OK#00",
71            # verify that the current process is correct
72            "read packet: $qC#00",
73            "send packet: $QCp{}.{}#00".format(parent_pid, parent_tid),
74            # verify that the correct processes are detached/available
75            "read packet: $Hgp{}.{}#00".format(child_pid, child_tid),
76            "send packet: $Eff#00",
77            "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid),
78            "send packet: $OK#00",
79        ], True)
80        self.expect_gdbremote_sequence()
81        self.reset_test_sequence()
82        return parent_pid, parent_tid
83
84    @add_test_categories(["fork"])
85    def test_fork(self):
86        parent_pid, _ = self.fork_and_detach_test("fork")
87
88        # resume the parent
89        self.test_sequence.add_log_lines([
90            "read packet: $c#00",
91            "send packet: $W00;process:{}#00".format(parent_pid),
92        ], True)
93        self.expect_gdbremote_sequence()
94
95    @add_test_categories(["fork"])
96    def test_fork_nonstop(self):
97        parent_pid, _ = self.fork_and_detach_test("fork", nonstop=True)
98
99        # resume the parent
100        self.test_sequence.add_log_lines([
101            "read packet: $c#00",
102            "send packet: $OK#00",
103            "send packet: %Stop:W00;process:{}#00".format(parent_pid),
104            "read packet: $vStopped#00",
105            "send packet: $OK#00",
106        ], True)
107        self.expect_gdbremote_sequence()
108
109    @add_test_categories(["fork"])
110    def test_vfork(self):
111        parent_pid, parent_tid = self.fork_and_detach_test("vfork")
112
113        # resume the parent
114        self.test_sequence.add_log_lines([
115            "read packet: $c#00",
116            {"direction": "send",
117             "regex": r"[$]T05thread:p{}[.]{}.*vforkdone.*".format(parent_pid,
118                                                                   parent_tid),
119             },
120            "read packet: $c#00",
121            "send packet: $W00;process:{}#00".format(parent_pid),
122        ], True)
123        self.expect_gdbremote_sequence()
124
125    @add_test_categories(["fork"])
126    def test_vfork_nonstop(self):
127        parent_pid, parent_tid = self.fork_and_detach_test("vfork",
128                                                           nonstop=True)
129
130        # resume the parent
131        self.test_sequence.add_log_lines([
132            "read packet: $c#00",
133            "send packet: $OK#00",
134            {"direction": "send",
135             "regex": r"%Stop:T05thread:p{}[.]{}.*vforkdone.*".format(
136                 parent_pid, parent_tid),
137             },
138            "read packet: $vStopped#00",
139            "send packet: $OK#00",
140            "read packet: $c#00",
141            "send packet: $OK#00",
142            "send packet: %Stop:W00;process:{}#00".format(parent_pid),
143            "read packet: $vStopped#00",
144            "send packet: $OK#00",
145        ], True)
146        self.expect_gdbremote_sequence()
147
148    def fork_and_follow_test(self, variant, nonstop=False):
149        parent_pid, parent_tid, child_pid, child_tid = (
150            self.start_fork_test([variant], variant, nonstop=nonstop))
151
152        # switch to the forked child
153        self.test_sequence.add_log_lines([
154            "read packet: $Hgp{}.{}#00".format(child_pid, child_tid),
155            "send packet: $OK#00",
156            "read packet: $Hcp{}.{}#00".format(child_pid, child_tid),
157            "send packet: $OK#00",
158            # detach the parent
159            "read packet: $D;{}#00".format(parent_pid),
160            "send packet: $OK#00",
161            # verify that the correct processes are detached/available
162            "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid),
163            "send packet: $Eff#00",
164            "read packet: $Hgp{}.{}#00".format(child_pid, child_tid),
165            "send packet: $OK#00",
166            # then resume the child
167            "read packet: $c#00",
168        ], True)
169
170        if nonstop:
171            self.test_sequence.add_log_lines([
172                "send packet: $OK#00",
173                "send packet: %Stop:W00;process:{}#00".format(child_pid),
174                "read packet: $vStopped#00",
175                "send packet: $OK#00",
176            ], True)
177        else:
178            self.test_sequence.add_log_lines([
179                "send packet: $W00;process:{}#00".format(child_pid),
180            ], True)
181        self.expect_gdbremote_sequence()
182
183    @add_test_categories(["fork"])
184    def test_fork_follow(self):
185        self.fork_and_follow_test("fork")
186
187    @add_test_categories(["fork"])
188    def test_fork_follow_nonstop(self):
189        self.fork_and_follow_test("fork", nonstop=True)
190
191    @add_test_categories(["fork"])
192    def test_vfork_follow(self):
193        self.fork_and_follow_test("vfork")
194
195    @add_test_categories(["fork"])
196    def test_vfork_follow_nonstop(self):
197        self.fork_and_follow_test("vfork", nonstop=True)
198
199    @add_test_categories(["fork"])
200    def test_select_wrong_pid(self):
201        self.build()
202        self.prep_debug_monitor_and_inferior()
203        self.add_qSupported_packets(["multiprocess+"])
204        ret = self.expect_gdbremote_sequence()
205        self.assertIn("multiprocess+", ret["qSupported_response"])
206        self.reset_test_sequence()
207
208        # get process pid
209        self.test_sequence.add_log_lines([
210            "read packet: $qC#00",
211            {"direction": "send", "regex": "[$]QCp([0-9a-f]+).([0-9a-f]+)#.*",
212             "capture": {1: "pid", 2: "tid"}},
213        ], True)
214        ret = self.expect_gdbremote_sequence()
215        pid, tid = (int(ret[x], 16) for x in ("pid", "tid"))
216        self.reset_test_sequence()
217
218        self.test_sequence.add_log_lines([
219            # try switching to correct pid
220            "read packet: $Hgp{:x}.{:x}#00".format(pid, tid),
221            "send packet: $OK#00",
222            "read packet: $Hcp{:x}.{:x}#00".format(pid, tid),
223            "send packet: $OK#00",
224            # try switching to invalid tid
225            "read packet: $Hgp{:x}.{:x}#00".format(pid, tid+1),
226            "send packet: $E15#00",
227            "read packet: $Hcp{:x}.{:x}#00".format(pid, tid+1),
228            "send packet: $E15#00",
229            # try switching to invalid pid
230            "read packet: $Hgp{:x}.{:x}#00".format(pid+1, tid),
231            "send packet: $Eff#00",
232            "read packet: $Hcp{:x}.{:x}#00".format(pid+1, tid),
233            "send packet: $Eff#00",
234        ], True)
235        self.expect_gdbremote_sequence()
236
237    @add_test_categories(["fork"])
238    def test_detach_current(self):
239        self.build()
240        self.prep_debug_monitor_and_inferior()
241        self.add_qSupported_packets(["multiprocess+"])
242        ret = self.expect_gdbremote_sequence()
243        self.assertIn("multiprocess+", ret["qSupported_response"])
244        self.reset_test_sequence()
245
246        # get process pid
247        self.test_sequence.add_log_lines([
248            "read packet: $qC#00",
249            {"direction": "send", "regex": "[$]QCp([0-9a-f]+).[0-9a-f]+#.*",
250             "capture": {1: "pid"}},
251        ], True)
252        ret = self.expect_gdbremote_sequence()
253        pid = ret["pid"]
254        self.reset_test_sequence()
255
256        # detach the process
257        self.test_sequence.add_log_lines([
258            "read packet: $D;{}#00".format(pid),
259            "send packet: $OK#00",
260            "read packet: $qC#00",
261            "send packet: $E44#00",
262        ], True)
263        self.expect_gdbremote_sequence()
264
265    def detach_all_test(self, nonstop=False):
266        parent_pid, parent_tid, child_pid, child_tid = (
267            self.start_fork_test(["fork"], nonstop=nonstop))
268
269        self.test_sequence.add_log_lines([
270            # double-check our PIDs
271            "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid),
272            "send packet: $OK#00",
273            "read packet: $Hgp{}.{}#00".format(child_pid, child_tid),
274            "send packet: $OK#00",
275            # detach all processes
276            "read packet: $D#00",
277            "send packet: $OK#00",
278            # verify that both PIDs are invalid now
279            "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid),
280            "send packet: $Eff#00",
281            "read packet: $Hgp{}.{}#00".format(child_pid, child_tid),
282            "send packet: $Eff#00",
283        ], True)
284        self.expect_gdbremote_sequence()
285
286    @add_test_categories(["fork"])
287    def test_detach_all(self):
288        self.detach_all_test()
289
290    @add_test_categories(["fork"])
291    def test_detach_all_nonstop(self):
292        self.detach_all_test(nonstop=True)
293
294    @add_test_categories(["fork"])
295    def test_kill_all(self):
296        parent_pid, _, child_pid, _ = self.start_fork_test(["fork"])
297
298        exit_regex = "[$]X09;process:([0-9a-f]+)#.*"
299        self.test_sequence.add_log_lines([
300            # kill all processes
301            "read packet: $k#00",
302            {"direction": "send", "regex": exit_regex,
303             "capture": {1: "pid1"}},
304            {"direction": "send", "regex": exit_regex,
305             "capture": {1: "pid2"}},
306        ], True)
307        ret = self.expect_gdbremote_sequence()
308        self.assertEqual(set([ret["pid1"], ret["pid2"]]),
309                         set([parent_pid, child_pid]))
310
311    @add_test_categories(["fork"])
312    def test_kill_all_nonstop(self):
313        parent_pid, _, child_pid, _ = self.start_fork_test(["fork"],
314                                                           nonstop=True)
315
316        exit_regex = "X09;process:([0-9a-f]+)"
317        # Depending on a potential race, the second kill may make it into
318        # the async queue before we issue vStopped or after.  In the former
319        # case, we should expect the exit status in reply to vStopped.
320        # In the latter, we should expect an OK response (queue empty),
321        # followed by another async notification.
322        vstop_regex = "[$](OK|{})#.*".format(exit_regex)
323        self.test_sequence.add_log_lines([
324            # kill all processes
325            "read packet: $k#00",
326            "send packet: $OK#00",
327            {"direction": "send", "regex": "%Stop:{}#.*".format(exit_regex),
328             "capture": {1: "pid1"}},
329            "read packet: $vStopped#00",
330            {"direction": "send", "regex": vstop_regex,
331             "capture": {1: "vstop_reply", 2: "pid2"}},
332        ], True)
333        ret = self.expect_gdbremote_sequence()
334        pid1 = ret["pid1"]
335        if ret["vstop_reply"] == "OK":
336            self.reset_test_sequence()
337            self.test_sequence.add_log_lines([
338                {"direction": "send", "regex": "%Stop:{}#.*".format(exit_regex),
339                 "capture": {1: "pid2"}},
340            ], True)
341            ret = self.expect_gdbremote_sequence()
342        pid2 = ret["pid2"]
343        self.reset_test_sequence()
344        self.test_sequence.add_log_lines([
345            "read packet: $vStopped#00",
346            "send packet: $OK#00",
347        ], True)
348        self.expect_gdbremote_sequence()
349        self.assertEqual(set([ret["pid1"], ret["pid2"]]),
350                         set([parent_pid, child_pid]))
351
352    def vkill_test(self, kill_parent=False, kill_child=False, nonstop=False):
353        assert kill_parent or kill_child
354        parent_pid, parent_tid, child_pid, child_tid = (
355            self.start_fork_test(["fork"], nonstop=nonstop))
356
357        if kill_parent:
358            self.test_sequence.add_log_lines([
359                # kill the process
360                "read packet: $vKill;{}#00".format(parent_pid),
361                "send packet: $OK#00",
362            ], True)
363        if kill_child:
364            self.test_sequence.add_log_lines([
365                # kill the process
366                "read packet: $vKill;{}#00".format(child_pid),
367                "send packet: $OK#00",
368            ], True)
369        self.test_sequence.add_log_lines([
370            # check child PID/TID
371            "read packet: $Hgp{}.{}#00".format(child_pid, child_tid),
372            "send packet: ${}#00".format("Eff" if kill_child else "OK"),
373            # check parent PID/TID
374            "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid),
375            "send packet: ${}#00".format("Eff" if kill_parent else "OK"),
376        ], True)
377        self.expect_gdbremote_sequence()
378
379    @add_test_categories(["fork"])
380    def test_vkill_child(self):
381        self.vkill_test(kill_child=True)
382
383    @add_test_categories(["fork"])
384    def test_vkill_parent(self):
385        self.vkill_test(kill_parent=True)
386
387    @add_test_categories(["fork"])
388    def test_vkill_both(self):
389        self.vkill_test(kill_parent=True, kill_child=True)
390
391    @add_test_categories(["fork"])
392    def test_vkill_both_nonstop(self):
393        self.vkill_test(kill_parent=True, kill_child=True, nonstop=True)
394
395    def resume_one_test(self, run_order, use_vCont=False, nonstop=False):
396        parent_pid, parent_tid, child_pid, child_tid = (
397            self.start_fork_test(["fork", "trap"], nonstop=nonstop))
398
399        parent_expect = [
400            "T05thread:p{}.{};.*".format(parent_pid, parent_tid),
401            "W00;process:{}#.*".format(parent_pid),
402        ]
403        child_expect = [
404            "T05thread:p{}.{};.*".format(child_pid, child_tid),
405            "W00;process:{}#.*".format(child_pid),
406        ]
407
408        for x in run_order:
409            if x == "parent":
410                pidtid = (parent_pid, parent_tid)
411                expect = parent_expect.pop(0)
412            elif x == "child":
413                pidtid = (child_pid, child_tid)
414                expect = child_expect.pop(0)
415            else:
416                assert False, "unexpected x={}".format(x)
417
418            if use_vCont:
419                self.test_sequence.add_log_lines([
420                    # continue the selected process
421                    "read packet: $vCont;c:p{}.{}#00".format(*pidtid),
422                ], True)
423            else:
424                self.test_sequence.add_log_lines([
425                    # continue the selected process
426                    "read packet: $Hcp{}.{}#00".format(*pidtid),
427                    "send packet: $OK#00",
428                    "read packet: $c#00",
429                ], True)
430            if nonstop:
431                self.test_sequence.add_log_lines([
432                    "send packet: $OK#00",
433                    {"direction": "send", "regex": "%Stop:" + expect},
434                    "read packet: $vStopped#00",
435                    "send packet: $OK#00",
436                ], True)
437            else:
438                self.test_sequence.add_log_lines([
439                    {"direction": "send", "regex": "[$]" + expect},
440                ], True)
441            # if at least one process remained, check both PIDs
442            if parent_expect or child_expect:
443                self.test_sequence.add_log_lines([
444                    "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid),
445                    "send packet: ${}#00".format("OK" if parent_expect else "Eff"),
446                    "read packet: $Hgp{}.{}#00".format(child_pid, child_tid),
447                    "send packet: ${}#00".format("OK" if child_expect else "Eff"),
448                ], True)
449        self.expect_gdbremote_sequence()
450
451    @expectedFailureAll(archs=["arm"])  # TODO
452    @expectedFailureAll(archs=["aarch64"],
453                        bugnumber="https://github.com/llvm/llvm-project/issues/56268")
454    @add_test_categories(["fork"])
455    def test_c_parent(self):
456        self.resume_one_test(run_order=["parent", "parent"])
457
458    @expectedFailureAll(archs=["arm"])  # TODO
459    @expectedFailureAll(archs=["aarch64"],
460                        bugnumber="https://github.com/llvm/llvm-project/issues/56268")
461    @add_test_categories(["fork"])
462    def test_c_child(self):
463        self.resume_one_test(run_order=["child", "child"])
464
465    @expectedFailureAll(archs=["arm"])  # TODO
466    @expectedFailureAll(archs=["aarch64"],
467                        bugnumber="https://github.com/llvm/llvm-project/issues/56268")
468    @add_test_categories(["fork"])
469    def test_c_parent_then_child(self):
470        self.resume_one_test(run_order=["parent", "parent", "child", "child"])
471
472    @expectedFailureAll(archs=["arm"])  # TODO
473    @expectedFailureAll(archs=["aarch64"],
474                        bugnumber="https://github.com/llvm/llvm-project/issues/56268")
475    @add_test_categories(["fork"])
476    def test_c_child_then_parent(self):
477        self.resume_one_test(run_order=["child", "child", "parent", "parent"])
478
479    @expectedFailureAll(archs=["arm"])  # TODO
480    @expectedFailureAll(archs=["aarch64"],
481                        bugnumber="https://github.com/llvm/llvm-project/issues/56268")
482    @add_test_categories(["fork"])
483    def test_c_interspersed(self):
484        self.resume_one_test(run_order=["parent", "child", "parent", "child"])
485
486    @expectedFailureAll(archs=["arm"])  # TODO
487    @expectedFailureAll(archs=["aarch64"],
488                        bugnumber="https://github.com/llvm/llvm-project/issues/56268")
489    @add_test_categories(["fork"])
490    def test_c_interspersed_nonstop(self):
491        self.resume_one_test(run_order=["parent", "child", "parent", "child"],
492                             nonstop=True)
493
494    @expectedFailureAll(archs=["arm"])  # TODO
495    @expectedFailureAll(archs=["aarch64"],
496                        bugnumber="https://github.com/llvm/llvm-project/issues/56268")
497    @add_test_categories(["fork"])
498    def test_vCont_parent(self):
499        self.resume_one_test(run_order=["parent", "parent"], use_vCont=True)
500
501    @expectedFailureAll(archs=["arm"])  # TODO
502    @expectedFailureAll(archs=["aarch64"],
503                        bugnumber="https://github.com/llvm/llvm-project/issues/56268")
504    @add_test_categories(["fork"])
505    def test_vCont_child(self):
506        self.resume_one_test(run_order=["child", "child"], use_vCont=True)
507
508    @expectedFailureAll(archs=["arm"])  # TODO
509    @expectedFailureAll(archs=["aarch64"],
510                        bugnumber="https://github.com/llvm/llvm-project/issues/56268")
511    @add_test_categories(["fork"])
512    def test_vCont_parent_then_child(self):
513        self.resume_one_test(run_order=["parent", "parent", "child", "child"],
514                             use_vCont=True)
515
516    @expectedFailureAll(archs=["arm"])  # TODO
517    @expectedFailureAll(archs=["aarch64"],
518                        bugnumber="https://github.com/llvm/llvm-project/issues/56268")
519    @add_test_categories(["fork"])
520    def test_vCont_child_then_parent(self):
521        self.resume_one_test(run_order=["child", "child", "parent", "parent"],
522                             use_vCont=True)
523
524    @expectedFailureAll(archs=["arm"])  # TODO
525    @expectedFailureAll(archs=["aarch64"],
526                        bugnumber="https://github.com/llvm/llvm-project/issues/56268")
527    @add_test_categories(["fork"])
528    def test_vCont_interspersed(self):
529        self.resume_one_test(run_order=["parent", "child", "parent", "child"],
530                             use_vCont=True)
531
532    @expectedFailureAll(archs=["arm"])  # TODO
533    @expectedFailureAll(archs=["aarch64"],
534                        bugnumber="https://github.com/llvm/llvm-project/issues/56268")
535    @add_test_categories(["fork"])
536    def test_vCont_interspersed_nonstop(self):
537        self.resume_one_test(run_order=["parent", "child", "parent", "child"],
538                             use_vCont=True, nonstop=True)
539
540    @add_test_categories(["fork"])
541    def test_vCont_two_processes(self):
542        parent_pid, parent_tid, child_pid, child_tid = (
543            self.start_fork_test(["fork", "trap"]))
544
545        self.test_sequence.add_log_lines([
546            # try to resume both processes
547            "read packet: $vCont;c:p{}.{};c:p{}.{}#00".format(
548                parent_pid, parent_tid, child_pid, child_tid),
549            "send packet: $E03#00",
550        ], True)
551        self.expect_gdbremote_sequence()
552
553    @add_test_categories(["fork"])
554    def test_vCont_all_processes_explicit(self):
555        self.start_fork_test(["fork", "trap"])
556
557        self.test_sequence.add_log_lines([
558            # try to resume all processes implicitly
559            "read packet: $vCont;c:p-1.-1#00",
560            "send packet: $E03#00",
561        ], True)
562        self.expect_gdbremote_sequence()
563
564    @add_test_categories(["fork"])
565    def test_vCont_all_processes_implicit(self):
566        self.start_fork_test(["fork", "trap"])
567
568        self.test_sequence.add_log_lines([
569            # try to resume all processes implicitly
570            "read packet: $vCont;c#00",
571            "send packet: $E03#00",
572        ], True)
573        self.expect_gdbremote_sequence()
574
575    @expectedFailureAll(archs=["arm"])  # TODO
576    @add_test_categories(["fork"])
577    def test_threadinfo(self):
578        parent_pid, parent_tid, child_pid, child_tid = (
579            self.start_fork_test(["fork", "thread:new", "trap"]))
580        pidtids = [
581            (parent_pid, parent_tid),
582            (child_pid, child_tid),
583        ]
584
585        self.add_threadinfo_collection_packets()
586        ret = self.expect_gdbremote_sequence()
587        prev_pidtids = set(self.parse_threadinfo_packets(ret))
588        self.assertEqual(prev_pidtids,
589                         frozenset((int(pid, 16), int(tid, 16))
590                                   for pid, tid in pidtids))
591        self.reset_test_sequence()
592
593        for pidtid in pidtids:
594            self.test_sequence.add_log_lines(
595                ["read packet: $Hcp{}.{}#00".format(*pidtid),
596                 "send packet: $OK#00",
597                 "read packet: $c#00",
598                 {"direction": "send",
599                  "regex": "^[$]T05thread:p{}.{}.*".format(*pidtid),
600                  },
601                 ], True)
602            self.add_threadinfo_collection_packets()
603            ret = self.expect_gdbremote_sequence()
604            self.reset_test_sequence()
605            new_pidtids = set(self.parse_threadinfo_packets(ret))
606            added_pidtid = new_pidtids - prev_pidtids
607            prev_pidtids = new_pidtids
608
609            # verify that we've got exactly one new thread, and that
610            # the PID matches
611            self.assertEqual(len(added_pidtid), 1)
612            self.assertEqual(added_pidtid.pop()[0], int(pidtid[0], 16))
613
614        for pidtid in new_pidtids:
615            self.test_sequence.add_log_lines(
616                ["read packet: $Hgp{:x}.{:x}#00".format(*pidtid),
617                 "send packet: $OK#00",
618                 ], True)
619        self.expect_gdbremote_sequence()
620
621    @expectedFailureAll(archs=["arm"])  # TODO
622    @add_test_categories(["fork"])
623    def test_memory_read_write(self):
624        self.build()
625        INITIAL_DATA = "Initial message"
626        self.prep_debug_monitor_and_inferior(
627            inferior_args=["set-message:{}".format(INITIAL_DATA),
628                           "get-data-address-hex:g_message",
629                           "fork",
630                           "print-message:",
631                           "trap",
632                           ])
633        self.add_qSupported_packets(["multiprocess+",
634                                     "fork-events+"])
635        ret = self.expect_gdbremote_sequence()
636        self.assertIn("fork-events+", ret["qSupported_response"])
637        self.reset_test_sequence()
638
639        # continue and expect fork
640        self.test_sequence.add_log_lines([
641            "read packet: $c#00",
642            {"type": "output_match",
643             "regex": self.maybe_strict_output_regex(r"data address: 0x([0-9a-fA-F]+)\r\n"),
644             "capture": {1: "addr"}},
645            {"direction": "send", "regex": self.fork_regex.format("fork"),
646             "capture": self.fork_capture},
647        ], True)
648        ret = self.expect_gdbremote_sequence()
649        pidtids = {
650            "parent": (ret["parent_pid"], ret["parent_tid"]),
651            "child": (ret["child_pid"], ret["child_tid"]),
652        }
653        addr = ret["addr"]
654        self.reset_test_sequence()
655
656        for name, pidtid in pidtids.items():
657            self.test_sequence.add_log_lines(
658                ["read packet: $Hgp{}.{}#00".format(*pidtid),
659                 "send packet: $OK#00",
660                 # read the current memory contents
661                 "read packet: $m{},{:x}#00".format(addr,
662                                                    len(INITIAL_DATA) + 1),
663                 {"direction": "send",
664                  "regex": r"^[$](.+)#.*$",
665                  "capture": {1: "data"}},
666                 # write a new value
667                 "read packet: $M{},{:x}:{}#00".format(addr,
668                                                       len(name) + 1,
669                                                       seven.hexlify(
670                                                           name + "\0")),
671                 "send packet: $OK#00",
672                 # resume the process and wait for the trap
673                 "read packet: $Hcp{}.{}#00".format(*pidtid),
674                 "send packet: $OK#00",
675                 "read packet: $c#00",
676                 {"type": "output_match",
677                  "regex": self.maybe_strict_output_regex(r"message: (.*)\r\n"),
678                  "capture": {1: "printed_message"}},
679                 {"direction": "send",
680                  "regex": "^[$]T05thread:p{}.{}.*".format(*pidtid),
681                  },
682                 ], True)
683            ret = self.expect_gdbremote_sequence()
684            data = seven.unhexlify(ret["data"])
685            self.assertEqual(data, INITIAL_DATA + "\0")
686            self.assertEqual(ret["printed_message"], name);
687            self.reset_test_sequence()
688
689        # we do the second round separately to make sure that initial data
690        # is correctly preserved while writing into the first process
691
692        for name, pidtid in pidtids.items():
693            self.test_sequence.add_log_lines(
694                ["read packet: $Hgp{}.{}#00".format(*pidtid),
695                 "send packet: $OK#00",
696                 # read the current memory contents
697                 "read packet: $m{},{:x}#00".format(addr,
698                                                    len(name) + 1),
699                 {"direction": "send",
700                  "regex": r"^[$](.+)#.*$",
701                  "capture": {1: "data"}},
702                 ], True)
703            ret = self.expect_gdbremote_sequence()
704            self.assertIsNotNone(ret.get("data"))
705            data = seven.unhexlify(ret.get("data"))
706            self.assertEqual(data, name + "\0")
707            self.reset_test_sequence()
708
709    @expectedFailureAll(archs=["arm"])  # TODO
710    @add_test_categories(["fork"])
711    def test_register_read_write(self):
712        parent_pid, parent_tid, child_pid, child_tid = (
713            self.start_fork_test(["fork", "thread:new", "trap"]))
714        pidtids = [
715            (parent_pid, parent_tid),
716            (child_pid, child_tid),
717        ]
718
719        for pidtid in pidtids:
720            self.test_sequence.add_log_lines(
721                ["read packet: $Hcp{}.{}#00".format(*pidtid),
722                 "send packet: $OK#00",
723                 "read packet: $c#00",
724                 {"direction": "send",
725                  "regex": "^[$]T05thread:p{}.{}.*".format(*pidtid),
726                  },
727                 ], True)
728
729        self.add_threadinfo_collection_packets()
730        ret = self.expect_gdbremote_sequence()
731        self.reset_test_sequence()
732
733        pidtids = set(self.parse_threadinfo_packets(ret))
734        self.assertEqual(len(pidtids), 4)
735        # first, save register values from all the threads
736        thread_regs = {}
737        for pidtid in pidtids:
738            for regno in range(256):
739                self.test_sequence.add_log_lines(
740                    ["read packet: $Hgp{:x}.{:x}#00".format(*pidtid),
741                     "send packet: $OK#00",
742                     "read packet: $p{:x}#00".format(regno),
743                     {"direction": "send",
744                      "regex": r"^[$](.+)#.*$",
745                      "capture": {1: "data"}},
746                     ], True)
747                ret = self.expect_gdbremote_sequence()
748                data = ret.get("data")
749                self.assertIsNotNone(data)
750                # ignore registers shorter than 32 bits (this also catches
751                # "Exx" errors)
752                if len(data) >= 8:
753                    break
754            else:
755                self.skipTest("no usable register found")
756            thread_regs[pidtid] = (regno, data)
757
758        vals = set(x[1] for x in thread_regs.values())
759        # NB: cheap hack to make the loop below easier
760        new_val = next(iter(vals))
761
762        # then, start altering them and verify that we don't unexpectedly
763        # change the value from another thread
764        for pidtid in pidtids:
765            old_val = thread_regs[pidtid]
766            regno = old_val[0]
767            old_val_length = len(old_val[1])
768            # generate a unique new_val
769            while new_val in vals:
770                new_val = ('{{:0{}x}}'.format(old_val_length)
771                           .format(random.getrandbits(old_val_length*4)))
772            vals.add(new_val)
773
774            self.test_sequence.add_log_lines(
775                ["read packet: $Hgp{:x}.{:x}#00".format(*pidtid),
776                 "send packet: $OK#00",
777                 "read packet: $p{:x}#00".format(regno),
778                 {"direction": "send",
779                  "regex": r"^[$](.+)#.*$",
780                  "capture": {1: "data"}},
781                 "read packet: $P{:x}={}#00".format(regno, new_val),
782                 "send packet: $OK#00",
783                 ], True)
784            ret = self.expect_gdbremote_sequence()
785            data = ret.get("data")
786            self.assertIsNotNone(data)
787            self.assertEqual(data, old_val[1])
788            thread_regs[pidtid] = (regno, new_val)
789
790        # finally, verify that new values took effect
791        for pidtid in pidtids:
792            old_val = thread_regs[pidtid]
793            self.test_sequence.add_log_lines(
794                ["read packet: $Hgp{:x}.{:x}#00".format(*pidtid),
795                 "send packet: $OK#00",
796                 "read packet: $p{:x}#00".format(old_val[0]),
797                 {"direction": "send",
798                  "regex": r"^[$](.+)#.*$",
799                  "capture": {1: "data"}},
800                 ], True)
801            ret = self.expect_gdbremote_sequence()
802            data = ret.get("data")
803            self.assertIsNotNone(data)
804            self.assertEqual(data, old_val[1])
805
806    @expectedFailureAll(archs=["arm"])  # TODO
807    @add_test_categories(["fork"])
808    def test_qC(self):
809        parent_pid, parent_tid, child_pid, child_tid = (
810            self.start_fork_test(["fork", "thread:new", "trap"]))
811        pidtids = [
812            (parent_pid, parent_tid),
813            (child_pid, child_tid),
814        ]
815
816        for pidtid in pidtids:
817            self.test_sequence.add_log_lines(
818                ["read packet: $Hcp{}.{}#00".format(*pidtid),
819                 "send packet: $OK#00",
820                 "read packet: $c#00",
821                 {"direction": "send",
822                  "regex": "^[$]T05thread:p{}.{}.*".format(*pidtid),
823                  },
824                 ], True)
825
826        self.add_threadinfo_collection_packets()
827        ret = self.expect_gdbremote_sequence()
828        self.reset_test_sequence()
829
830        pidtids = set(self.parse_threadinfo_packets(ret))
831        self.assertEqual(len(pidtids), 4)
832        for pidtid in pidtids:
833            self.test_sequence.add_log_lines(
834                ["read packet: $Hgp{:x}.{:x}#00".format(*pidtid),
835                 "send packet: $OK#00",
836                 "read packet: $qC#00",
837                 "send packet: $QCp{:x}.{:x}#00".format(*pidtid),
838                 ], True)
839        self.expect_gdbremote_sequence()
840
841    @expectedFailureAll(archs=["arm"])  # TODO
842    @add_test_categories(["fork"])
843    def test_T(self):
844        parent_pid, parent_tid, child_pid, child_tid = (
845            self.start_fork_test(["fork", "thread:new", "trap"]))
846        pidtids = [
847            (parent_pid, parent_tid),
848            (child_pid, child_tid),
849        ]
850
851        for pidtid in pidtids:
852            self.test_sequence.add_log_lines(
853                ["read packet: $Hcp{}.{}#00".format(*pidtid),
854                 "send packet: $OK#00",
855                 "read packet: $c#00",
856                 {"direction": "send",
857                  "regex": "^[$]T05thread:p{}.{}.*".format(*pidtid),
858                  },
859                 ], True)
860
861        self.add_threadinfo_collection_packets()
862        ret = self.expect_gdbremote_sequence()
863        self.reset_test_sequence()
864
865        pidtids = set(self.parse_threadinfo_packets(ret))
866        self.assertEqual(len(pidtids), 4)
867        max_pid = max(pid for pid, tid in pidtids)
868        max_tid = max(tid for pid, tid in pidtids)
869        bad_pidtids = (
870            (max_pid, max_tid + 1, "E02"),
871            (max_pid + 1, max_tid, "E01"),
872            (max_pid + 1, max_tid + 1, "E01"),
873        )
874
875        for pidtid in pidtids:
876            self.test_sequence.add_log_lines(
877                [
878                 # test explicit PID+TID
879                 "read packet: $Tp{:x}.{:x}#00".format(*pidtid),
880                 "send packet: $OK#00",
881                 # test implicit PID via Hg
882                 "read packet: $Hgp{:x}.{:x}#00".format(*pidtid),
883                 "send packet: $OK#00",
884                 "read packet: $T{:x}#00".format(max_tid + 1),
885                 "send packet: $E02#00",
886                 "read packet: $T{:x}#00".format(pidtid[1]),
887                 "send packet: $OK#00",
888                 ], True)
889        for pid, tid, expected in bad_pidtids:
890            self.test_sequence.add_log_lines(
891                ["read packet: $Tp{:x}.{:x}#00".format(pid, tid),
892                 "send packet: ${}#00".format(expected),
893                 ], True)
894        self.expect_gdbremote_sequence()
895