Index: lldb/trunk/include/lldb/Target/ThreadList.h =================================================================== --- lldb/trunk/include/lldb/Target/ThreadList.h +++ lldb/trunk/include/lldb/Target/ThreadList.h @@ -102,6 +102,8 @@ lldb::ThreadSP GetThreadSPForThreadPtr(Thread *thread_ptr); + lldb::ThreadSP GetBackingThread(const lldb::ThreadSP &real_thread); + bool ShouldStop(Event *event_ptr); Vote ShouldReportStop(Event *event_ptr); Index: lldb/trunk/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/TestThreadSelectionBug.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/TestThreadSelectionBug.py +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/TestThreadSelectionBug.py @@ -0,0 +1,50 @@ +from __future__ import print_function +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from gdbclientutils import * + + +class TestThreadSelectionBug(GDBRemoteTestBase): + def test(self): + class MyResponder(MockGDBServerResponder): + def cont(self): + # Simulate process stopping due to a raise(SIGINT) + return "T01reason:signal" + + self.server.responder = MyResponder() + target = self.createTarget("a.yaml") + process = self.connect(target) + python_os_plugin_path = os.path.join(self.getSourceDir(), + 'operating_system.py') + command = "settings set target.process.python-os-plugin-path '{}'".format( + python_os_plugin_path) + self.dbg.HandleCommand(command) + + self.assertTrue(process, PROCESS_IS_VALID) + self.assertEqual(process.GetNumThreads(), 3) + + # Verify our OS plug-in threads showed up + thread = process.GetThreadByID(0x1) + self.assertTrue( + thread.IsValid(), + "Make sure there is a thread 0x1 after we load the python OS plug-in") + thread = process.GetThreadByID(0x2) + self.assertTrue( + thread.IsValid(), + "Make sure there is a thread 0x2 after we load the python OS plug-in") + thread = process.GetThreadByID(0x3) + self.assertTrue( + thread.IsValid(), + "Make sure there is a thread 0x3 after we load the python OS plug-in") + + # Verify that a thread other than 3 is selected. + thread = process.GetSelectedThread() + self.assertNotEqual(thread.GetThreadID(), 0x3) + + # Verify that we select the thread backed by physical thread 1, rather + # than virtual thread 1. The mapping comes from the OS plugin, where we + # specified that thread 3 is backed by real thread 1. + process.Continue() + thread = process.GetSelectedThread() + self.assertEqual(thread.GetThreadID(), 0x3) Index: lldb/trunk/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/operating_system.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/operating_system.py +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/operating_system.py @@ -0,0 +1,45 @@ +import lldb +import struct + + +class OperatingSystemPlugIn(object): + """Class that provides data for an instance of a LLDB 'OperatingSystemPython' plug-in class""" + + def __init__(self, process): + '''Initialization needs a valid.SBProcess object. + + This plug-in will get created after a live process is valid and has stopped for the first time. + ''' + self.process = None + self.registers = None + self.threads = None + if isinstance(process, lldb.SBProcess) and process.IsValid(): + self.process = process + self.threads = None # Will be an dictionary containing info for each thread + + def get_target(self): + return self.process.target + + def get_thread_info(self): + if not self.threads: + self.threads = [{ + 'tid': 0x1, + 'name': 'one', + 'queue': 'queue1', + 'state': 'stopped', + 'stop_reason': 'none' + }, { + 'tid': 0x2, + 'name': 'two', + 'queue': 'queue2', + 'state': 'stopped', + 'stop_reason': 'none' + }, { + 'tid': 0x3, + 'name': 'three', + 'queue': 'queue3', + 'state': 'stopped', + 'stop_reason': 'sigstop', + 'core': 0 + }] + return self.threads Index: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -1822,10 +1822,9 @@ if (!thread_sp->StopInfoIsUpToDate()) { thread_sp->SetStopInfo(StopInfoSP()); // If there's a memory thread backed by this thread, we need to use it - // to calcualte StopInfo. - ThreadSP memory_thread_sp = - m_thread_list.FindThreadByProtocolID(thread_sp->GetProtocolID()); - if (memory_thread_sp) + // to calculate StopInfo. + if (ThreadSP memory_thread_sp = + m_thread_list.GetBackingThread(thread_sp)) thread_sp = memory_thread_sp; if (exc_type != 0) { Index: lldb/trunk/source/Target/ThreadList.cpp =================================================================== --- lldb/trunk/source/Target/ThreadList.cpp +++ lldb/trunk/source/Target/ThreadList.cpp @@ -195,6 +195,20 @@ return thread_sp; } +ThreadSP ThreadList::GetBackingThread(const ThreadSP &real_thread) { + std::lock_guard guard(GetMutex()); + + ThreadSP thread_sp; + const uint32_t num_threads = m_threads.size(); + for (uint32_t idx = 0; idx < num_threads; ++idx) { + if (m_threads[idx]->GetBackingThread() == real_thread) { + thread_sp = m_threads[idx]; + break; + } + } + return thread_sp; +} + ThreadSP ThreadList::FindThreadByIndexID(uint32_t index_id, bool can_update) { std::lock_guard guard(GetMutex());