| import lldb | |
| from lldbsuite.test.lldbtest import * | |
| from lldbsuite.test.decorators import * | |
| from lldbsuite.test.gdbclientutils import * | |
| from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase | |
| class TestRecognizeBreakpoint(GDBRemoteTestBase): | |
| """This tests the case where the gdb-remote server doesn't support any | |
| of the thread-info packets, and just tells which thread got the stop | |
| signal with: | |
| T05thread:01; | |
| There was a bug in lldb that we would set the stop reason from this | |
| packet too early - before we had updated the thread list. So when we | |
| later updated the thread list, we would throw away this info. Normally | |
| we would be able to reconstruct it from the thread info, but not if the | |
| stub doesn't support it""" | |
| @skipIfXmlSupportMissing | |
| def test(self): | |
| class MyResponder(MockGDBServerResponder): | |
| def __init__(self): | |
| MockGDBServerResponder.__init__(self) | |
| self.thread_info_count = 0 | |
| self.after_cont = False | |
| self.current_thread = 0 | |
| def cont(self): | |
| # Simulate process stopping due to a breakpoint: | |
| self.after_cont = True | |
| return "T05thread:01;" | |
| def vCont(self, packet): | |
| self.after_cont = True | |
| return "T05thread:01;" | |
| def haltReason(self): | |
| return "T02thread:01;" | |
| def threadStopInfo(self, num): | |
| return "" | |
| def QThreadSuffixSupported(self): | |
| return "" | |
| def QListThreadsInStopReply(self): | |
| return "" | |
| def setBreakpoint(self, packet): | |
| return "OK" | |
| def qfThreadInfo(self): | |
| return "m1" | |
| def qsThreadInfo(self): | |
| if (self.thread_info_count % 2) == 0: | |
| str = "m2" | |
| else: | |
| str = "l" | |
| self.thread_info_count += 1 | |
| return str | |
| def readRegisters(self): | |
| if self.after_cont and self.current_thread == 1: | |
| return "c01e990080ffffff" | |
| else: | |
| return "badcfe10325476980" | |
| def readRegister(self, regno): | |
| return "" | |
| def qXferRead(self, obj, annex, offset, length): | |
| if annex == "target.xml": | |
| return ( | |
| """<?xml version="1.0"?> | |
| <target version="1.0"> | |
| <architecture>i386:x86-64</architecture> | |
| <feature name="org.gnu.gdb.i386.core"> | |
| <reg name="rip" bitsize="64" regnum="0" type="code_ptr" group="general"/> | |
| </feature> | |
| </target>""", | |
| False, | |
| ) | |
| else: | |
| return None, False | |
| def selectThread(self, op, thread): | |
| if op != "g": | |
| return "" | |
| self.current_thread = thread | |
| return "OK" | |
| def other(self, packet): | |
| if packet == "vCont?": | |
| return "vCont;c;C;s;S" | |
| return "" | |
| python_os_plugin_path = os.path.join( | |
| self.getSourceDir(), "operating_system_2.py" | |
| ) | |
| command = "settings set target.process.python-os-plugin-path '{}'".format( | |
| python_os_plugin_path | |
| ) | |
| self.runCmd(command) | |
| self.server.responder = MyResponder() | |
| target = self.dbg.CreateTarget("") | |
| process = self.connect(target) | |
| bkpt = target.BreakpointCreateByAddress(0xFFFFFF8000991EC0) | |
| self.assertEqual(bkpt.GetNumLocations(), 1, "Fake breakpoint was resolved.") | |
| # Get the initial stop, and we should have two threads. | |
| num_threads = len(process.threads) | |
| self.assertEqual(num_threads, 2, "Got two threads") | |
| thread_0 = process.threads[0] | |
| self.assertEqual(thread_0.GetStopReason(), 1, "Thread_0 stopped for no reason") | |
| self.assertEqual(thread_0.GetName(), "one", "Thread_0 is called one") | |
| thread_1 = process.threads[1] | |
| self.assertEqual(thread_1.GetStopReason(), 5, "Thread_0 stopped for SIGSTOP") | |
| self.assertEqual(thread_1.GetName(), "two", "Thread_0 is called two") | |
| # Now continue and we will fake hitting a breakpoint. | |
| process.Continue() | |
| self.assertState(process.GetState(), lldb.eStateStopped, "Process is stopped") | |
| num_threads = len(process.threads) | |
| num_threads = len(process.threads) | |
| self.assertEqual(num_threads, 2, "Got two threads") | |
| thread_0 = process.threads[0] | |
| self.assertEqual(thread_0.GetStopReason(), 1, "Thread_0 stopped for no reason") | |
| self.assertEqual(thread_0.GetName(), "one", "Thread_0 is called one") | |
| thread_1 = process.threads[1] | |
| self.assertEqual(thread_1.GetStopReason(), 3, "Thread_0 stopped for SIGTRAP") | |
| self.assertEqual(thread_1.GetName(), "three", "Thread_0 is called three") | |
| self.assertTrue(thread_1.IsValid(), "Thread_1 is valid") | |
| self.assertStopReason( | |
| thread_1.GetStopReason(), | |
| lldb.eStopReasonBreakpoint, | |
| "Stopped at breakpoint", | |
| ) |