Don't assume backing thread shares protocol ID.
When we're dealing with virtual (memory) threads created by the OS plugins, there's no guarantee that the real thread and the backing thread share a protocol ID. Instead, we should iterate over the memory threads to find the virtual thread that is backed by the current real thread. Differential revision: https://reviews.llvm.org/D45497 rdar://36485830 llvm-svn: 329891
This commit is contained in:
parent
4955c77c2d
commit
0045c72f9c
|
@ -102,6 +102,8 @@ public:
|
|||
|
||||
lldb::ThreadSP GetThreadSPForThreadPtr(Thread *thread_ptr);
|
||||
|
||||
lldb::ThreadSP GetBackingThread(const lldb::ThreadSP &real_thread);
|
||||
|
||||
bool ShouldStop(Event *event_ptr);
|
||||
|
||||
Vote ShouldReportStop(Event *event_ptr);
|
||||
|
|
|
@ -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)
|
|
@ -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
|
|
@ -1822,10 +1822,9 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
|
|||
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) {
|
||||
|
|
|
@ -195,6 +195,20 @@ ThreadSP ThreadList::GetThreadSPForThreadPtr(Thread *thread_ptr) {
|
|||
return thread_sp;
|
||||
}
|
||||
|
||||
ThreadSP ThreadList::GetBackingThread(const ThreadSP &real_thread) {
|
||||
std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> guard(GetMutex());
|
||||
|
||||
|
|
Loading…
Reference in New Issue