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