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