diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index cd3d2d89333f1..224c523e69c5c 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -1270,6 +1270,7 @@ class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { void OptionParsingStarting(ExecutionContext *execution_context) override { m_json_thread = false; m_json_stopinfo = false; + m_backing_thread = false; } Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, @@ -1286,6 +1287,10 @@ class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { m_json_stopinfo = true; break; + case 'b': + m_backing_thread = true; + break; + default: llvm_unreachable("Unimplemented option"); } @@ -1298,6 +1303,7 @@ class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { bool m_json_thread; bool m_json_stopinfo; + bool m_backing_thread; }; CommandObjectThreadInfo(CommandInterpreter &interpreter) @@ -1334,6 +1340,8 @@ class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { } Thread *thread = thread_sp.get(); + if (m_options.m_backing_thread && thread->GetBackingThread()) + thread = thread->GetBackingThread().get(); Stream &strm = result.GetOutputStream(); if (!thread->GetDescription(strm, eDescriptionLevelFull, diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index 8831fed38435b..cc579d767eb06 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -1108,6 +1108,9 @@ let Command = "thread info" in { " JSON format.">; def thread_info_stop_info : Option<"stop-info", "s">, Desc<"Display the " "extended stop info in JSON format.">; + def thread_info_backing_thread : Option<"backing-thread", "b">, + Desc<"If this is an OS plugin thread, query the backing thread instead; has" + " no effect otherwise.">; } let Command = "thread return" in { diff --git a/lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py b/lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py index fe78edd98f4d4..e4997f0742d02 100644 --- a/lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py +++ b/lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py @@ -131,6 +131,26 @@ def run_python_os_funcionality(self): "Make sure there is no thread 0x333333333 after we unload the python OS plug-in", ) + tid_regex = re.compile(r"tid = ((0x)?[0-9a-fA-F]+)") + + def get_tid_from_thread_info_command(self, thread, use_backing_thread): + interp = self.dbg.GetCommandInterpreter() + result = lldb.SBCommandReturnObject() + + backing_thread_arg = "" + if use_backing_thread: + backing_thread_arg = "--backing-thread" + + interp.HandleCommand( + "thread info {0} {1}".format(thread.GetIndexID(), backing_thread_arg), + result, + True, + ) + self.assertTrue(result.Succeeded(), "failed to run thread info") + match = self.tid_regex.search(result.GetOutput()) + self.assertNotEqual(match, None) + return int(match.group(1), 0) + def run_python_os_step(self): """Test that the Python operating system plugin works correctly and allows single stepping of a virtual thread that is backed by a real thread""" @@ -209,6 +229,11 @@ def run_python_os_step(self): # it to thread.StepOver() + tid_os = self.get_tid_from_thread_info_command(thread, False) + self.assertEqual(tid_os, 0x111111111) + tid_real = self.get_tid_from_thread_info_command(thread, True) + self.assertNotEqual(tid_os, tid_real) + frame = thread.GetFrameAtIndex(0) self.assertTrue( frame.IsValid(), "Make sure we get a frame from thread 0x111111111"