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