1import lldb
2from lldbsuite.test.lldbtest import *
3from lldbsuite.test.decorators import *
4from gdbclientutils import *
5
6
7class TestRecognizeBreakpoint(GDBRemoteTestBase):
8    """ This tests the case where the gdb-remote server doesn't support any
9        of the thread-info packets, and just tells which thread got the stop
10        signal with:
11              T05thread:01;
12        There was a bug in lldb that we would set the stop reason from this
13        packet too early - before we had updated the thread list.  So when we
14        later updated the thread list, we would throw away this info.  Normally
15        we would be able to reconstruct it from the thread info, but not if the
16        stub doesn't support it """
17
18    @skipIfXmlSupportMissing
19    def test(self):
20        class MyResponder(MockGDBServerResponder):
21            def __init__(self):
22                MockGDBServerResponder.__init__(self)
23                self.thread_info_count = 0
24                self.after_cont = False
25                self.current_thread = 0
26
27            def cont(self):
28                # Simulate process stopping due to a breakpoint:
29                self.after_cont = True
30                return "T05thread:01;"
31
32            def vCont(self, packet):
33                self.after_cont = True
34                return "T05thread:01;"
35
36            def haltReason(self):
37                return "T02thread:01;"
38
39            def threadStopInfo(self, num):
40                return ""
41
42            def QThreadSuffixSupported(self):
43                return ""
44
45            def QListThreadsInStopReply(self):
46                return ""
47
48            def setBreakpoint(self, packet):
49                return "OK"
50
51            def qfThreadInfo(self):
52                return "m1"
53
54            def qsThreadInfo(self):
55                if (self.thread_info_count % 2) == 0:
56                    str = "m2"
57                else:
58                    str = "l"
59                self.thread_info_count += 1
60                return str
61
62            def readRegisters(self):
63                if self.after_cont and self.current_thread == 1:
64                    return "c01e990080ffffff"
65                else:
66                    return "badcfe10325476980"
67
68            def readRegister(self, regno):
69                return ""
70
71            def qXferRead(self, obj, annex, offset, length):
72                if annex == "target.xml":
73                    return """<?xml version="1.0"?>
74                        <target version="1.0">
75                          <architecture>i386:x86-64</architecture>
76                          <feature name="org.gnu.gdb.i386.core">
77                            <reg name="rip" bitsize="64" regnum="0" type="code_ptr" group="general"/>
78                          </feature>
79                        </target>""", False
80                else:
81                    return None, False
82
83            def selectThread(self, op, thread):
84                if op != 'g':
85                    return ''
86
87                self.current_thread = thread
88                return "OK"
89
90            def other (self, packet):
91                if packet == "vCont?":
92                    return "vCont;c;C;s;S"
93                return ''
94
95        python_os_plugin_path = os.path.join(self.getSourceDir(),
96                                             'operating_system_2.py')
97        command ="settings set target.process.python-os-plugin-path '{}'".format(
98            python_os_plugin_path)
99        self.runCmd(command)
100
101        self.server.responder = MyResponder()
102        target = self.dbg.CreateTarget("")
103        process = self.connect(target)
104
105        bkpt = target.BreakpointCreateByAddress(0xffffff8000991ec0)
106        self.assertEqual(bkpt.GetNumLocations(), 1, "Fake breakpoint was resolved.")
107
108        # Get the initial stop, and we should have two threads.
109        num_threads = len(process.threads)
110        self.assertEqual(num_threads, 2, "Got two threads")
111
112        thread_0 = process.threads[0]
113        self.assertEqual(thread_0.GetStopReason(), 1, "Thread_0 stopped for no reason")
114        self.assertEqual(thread_0.GetName(), "one", "Thread_0 is called one")
115
116        thread_1 = process.threads[1]
117        self.assertEqual(thread_1.GetStopReason(), 5, "Thread_0 stopped for SIGSTOP")
118        self.assertEqual(thread_1.GetName(), "two", "Thread_0 is called two")
119
120        # Now continue and we will fake hitting a breakpoint.
121        process.Continue()
122
123        self.assertEqual(process.GetState(),lldb.eStateStopped, "Process is stopped")
124        num_threads = len(process.threads)
125
126        num_threads = len(process.threads)
127        self.assertEqual(num_threads, 2, "Got two threads")
128
129        thread_0 = process.threads[0]
130        self.assertEqual(thread_0.GetStopReason(), 1, "Thread_0 stopped for no reason")
131        self.assertEqual(thread_0.GetName(), "one", "Thread_0 is called one")
132
133        thread_1 = process.threads[1]
134        self.assertEqual(thread_1.GetStopReason(), 3, "Thread_0 stopped for SIGTRAP")
135        self.assertEqual(thread_1.GetName(), "three", "Thread_0 is called three")
136
137        self.assertTrue(thread_1.IsValid(), "Thread_1 is valid")
138        self.assertEqual(thread_1.GetStopReason(), lldb.eStopReasonBreakpoint, "Stopped at breakpoint")
139
140