|
| 1 | +import random |
| 2 | + |
1 | 3 | import gdbremote_testcase |
2 | 4 | from lldbsuite.test.decorators import * |
3 | 5 | from lldbsuite.test.lldbtest import * |
@@ -700,3 +702,118 @@ def test_memory_read_write(self): |
700 | 702 | data = seven.unhexlify(ret.get("data")) |
701 | 703 | self.assertEqual(data, name + "\0") |
702 | 704 | self.reset_test_sequence() |
| 705 | + |
| 706 | + @add_test_categories(["fork"]) |
| 707 | + def test_register_read_write(self): |
| 708 | + self.build() |
| 709 | + self.prep_debug_monitor_and_inferior( |
| 710 | + inferior_args=["fork", |
| 711 | + "thread:new", |
| 712 | + "trap", |
| 713 | + ]) |
| 714 | + self.add_qSupported_packets(["multiprocess+", |
| 715 | + "fork-events+"]) |
| 716 | + ret = self.expect_gdbremote_sequence() |
| 717 | + self.assertIn("fork-events+", ret["qSupported_response"]) |
| 718 | + self.reset_test_sequence() |
| 719 | + |
| 720 | + # continue and expect fork |
| 721 | + self.test_sequence.add_log_lines([ |
| 722 | + "read packet: $c#00", |
| 723 | + {"direction": "send", "regex": self.fork_regex.format("fork"), |
| 724 | + "capture": self.fork_capture}, |
| 725 | + ], True) |
| 726 | + self.add_threadinfo_collection_packets() |
| 727 | + ret = self.expect_gdbremote_sequence() |
| 728 | + pidtids = [ |
| 729 | + (ret["parent_pid"], ret["parent_tid"]), |
| 730 | + (ret["child_pid"], ret["child_tid"]), |
| 731 | + ] |
| 732 | + self.reset_test_sequence() |
| 733 | + |
| 734 | + for pidtid in pidtids: |
| 735 | + self.test_sequence.add_log_lines( |
| 736 | + ["read packet: $Hcp{}.{}#00".format(*pidtid), |
| 737 | + "send packet: $OK#00", |
| 738 | + "read packet: $c#00", |
| 739 | + {"direction": "send", |
| 740 | + "regex": "^[$]T05thread:p{}.{}.*".format(*pidtid), |
| 741 | + }, |
| 742 | + ], True) |
| 743 | + |
| 744 | + self.add_threadinfo_collection_packets() |
| 745 | + ret = self.expect_gdbremote_sequence() |
| 746 | + self.reset_test_sequence() |
| 747 | + |
| 748 | + pidtids = set(self.parse_threadinfo_packets(ret)) |
| 749 | + self.assertEqual(len(pidtids), 4) |
| 750 | + # first, save register values from all the threads |
| 751 | + thread_regs = {} |
| 752 | + for pidtid in pidtids: |
| 753 | + for regno in range(256): |
| 754 | + self.test_sequence.add_log_lines( |
| 755 | + ["read packet: $Hgp{:x}.{:x}#00".format(*pidtid), |
| 756 | + "send packet: $OK#00", |
| 757 | + "read packet: $p{:x}#00".format(regno), |
| 758 | + {"direction": "send", |
| 759 | + "regex": r"^[$](.+)#.*$", |
| 760 | + "capture": {1: "data"}}, |
| 761 | + ], True) |
| 762 | + ret = self.expect_gdbremote_sequence() |
| 763 | + data = ret.get("data") |
| 764 | + self.assertIsNotNone(data) |
| 765 | + # ignore registers shorter than 32 bits (this also catches |
| 766 | + # "Exx" errors) |
| 767 | + if len(data) >= 8: |
| 768 | + break |
| 769 | + else: |
| 770 | + self.skipTest("no usable register found") |
| 771 | + thread_regs[pidtid] = (regno, data) |
| 772 | + |
| 773 | + vals = set(x[1] for x in thread_regs.values()) |
| 774 | + # NB: cheap hack to make the loop below easier |
| 775 | + new_val = next(iter(vals)) |
| 776 | + |
| 777 | + # then, start altering them and verify that we don't unexpectedly |
| 778 | + # change the value from another thread |
| 779 | + for pidtid in pidtids: |
| 780 | + old_val = thread_regs[pidtid] |
| 781 | + regno = old_val[0] |
| 782 | + old_val_length = len(old_val[1]) |
| 783 | + # generate a unique new_val |
| 784 | + while new_val in vals: |
| 785 | + new_val = ('{{:0{}x}}'.format(old_val_length) |
| 786 | + .format(random.getrandbits(old_val_length*4))) |
| 787 | + vals.add(new_val) |
| 788 | + |
| 789 | + self.test_sequence.add_log_lines( |
| 790 | + ["read packet: $Hgp{:x}.{:x}#00".format(*pidtid), |
| 791 | + "send packet: $OK#00", |
| 792 | + "read packet: $p{:x}#00".format(regno), |
| 793 | + {"direction": "send", |
| 794 | + "regex": r"^[$](.+)#.*$", |
| 795 | + "capture": {1: "data"}}, |
| 796 | + "read packet: $P{:x}={}#00".format(regno, new_val), |
| 797 | + "send packet: $OK#00", |
| 798 | + ], True) |
| 799 | + ret = self.expect_gdbremote_sequence() |
| 800 | + data = ret.get("data") |
| 801 | + self.assertIsNotNone(data) |
| 802 | + self.assertEqual(data, old_val[1]) |
| 803 | + thread_regs[pidtid] = (regno, new_val) |
| 804 | + |
| 805 | + # finally, verify that new values took effect |
| 806 | + for pidtid in pidtids: |
| 807 | + old_val = thread_regs[pidtid] |
| 808 | + self.test_sequence.add_log_lines( |
| 809 | + ["read packet: $Hgp{:x}.{:x}#00".format(*pidtid), |
| 810 | + "send packet: $OK#00", |
| 811 | + "read packet: $p{:x}#00".format(old_val[0]), |
| 812 | + {"direction": "send", |
| 813 | + "regex": r"^[$](.+)#.*$", |
| 814 | + "capture": {1: "data"}}, |
| 815 | + ], True) |
| 816 | + ret = self.expect_gdbremote_sequence() |
| 817 | + data = ret.get("data") |
| 818 | + self.assertIsNotNone(data) |
| 819 | + self.assertEqual(data, old_val[1]) |
0 commit comments