Skip to content

Conversation

felipepiovezan
Copy link
Contributor

When OS plugins are present, it can be helpful to query information about the backing thread behind an OS thread, if it exists. There is no mechanism to do so prior to this commit.

As a first step, this commit enhances thread info with a --backing-thread flag, causing the command to use the backing thread of the selected thread, if it exists.

When OS plugins are present, it can be helpful to query information
about the backing thread behind an OS thread, if it exists. There is no
mechanism to do so prior to this commit.

As a first step, this commit enhances `thread info` with a
`--backing-thread` flag, causing the command to use the backing thread
of the selected thread, if it exists.
@llvmbot
Copy link
Member

llvmbot commented Feb 28, 2025

@llvm/pr-subscribers-lldb

Author: Felipe de Azevedo Piovezan (felipepiovezan)

Changes

When OS plugins are present, it can be helpful to query information about the backing thread behind an OS thread, if it exists. There is no mechanism to do so prior to this commit.

As a first step, this commit enhances thread info with a --backing-thread flag, causing the command to use the backing thread of the selected thread, if it exists.


Full diff: https://github.com/llvm/llvm-project/pull/129275.diff

3 Files Affected:

  • (modified) lldb/source/Commands/CommandObjectThread.cpp (+8)
  • (modified) lldb/source/Commands/Options.td (+3)
  • (modified) lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py (+24)
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..33e4f75adc0d0 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,25 @@ 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("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 match.group(1)
+
     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 +228,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"

Copy link

github-actions bot commented Feb 28, 2025

✅ With the latest revision this PR passed the Python code formatter.

@jimingham
Copy link
Collaborator

jimingham commented Feb 28, 2025

Seems good to be able to see the backing threads somehow.

All the users of CommandObjectIterateOverThreads that we have right now are informational only. Showing information about the backing threads is fine, but we don't want to let users operate on the backing threads. So there has to be a way to say "only allow backing threads for read-only Command's".

It also seems like using this as it is would be tedious if I have lots of threads and not all of them are OS Plugin backed. To find backed threads I have to do thread list then thread list --backing-thread and then compare the two lists. Maybe we can have the Thread::GetDescription recognize that it's printing a backing thread, and decorate it somehow? That way you could easily pick out the backing threads in a listing.

Also, you need to either disallow or think of what unique means as a thread specifier when you are showing backing threads.

@jimingham
Copy link
Collaborator

Apparently I need more coffee... This is just in the info command (somehow I thought the change was to ThreadObjectIterateOverThreads... Done this way, that's okay.

Copy link
Collaborator

@jimingham jimingham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@felipepiovezan
Copy link
Contributor Author

Linux bots seem to print the TID using decimal numbers, so I updated the regex.

@felipepiovezan felipepiovezan merged commit 11b9466 into llvm:main Mar 1, 2025
10 checks passed
felipepiovezan added a commit to felipepiovezan/llvm-project that referenced this pull request Mar 1, 2025
…m#129275)

When OS plugins are present, it can be helpful to query information
about the backing thread behind an OS thread, if it exists. There is no
mechanism to do so prior to this commit.

As a first step, this commit enhances `thread info` with a
`--backing-thread` flag, causing the command to use the backing thread
of the selected thread, if it exists.

(cherry picked from commit 11b9466)
@DavidSpickett
Copy link
Collaborator

Please add a release note for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants