[Lldb-commits] [lldb] [lldb][Process/FreeBSDKernelCore] Add command for refreshing thread list (PR #188692)

Minsoo Choo via lldb-commits lldb-commits at lists.llvm.org
Sun Mar 29 07:02:13 PDT 2026


https://github.com/mchoo7 updated https://github.com/llvm/llvm-project/pull/188692

>From 50ffd88d7d3f7d461eb850ba5d6461bfbc440234 Mon Sep 17 00:00:00 2001
From: Minsoo Choo <minsoochoo0122 at proton.me>
Date: Wed, 25 Mar 2026 22:12:30 +0900
Subject: [PATCH 1/2] [lldb][Process/FreeBSDKernelCore] Add command for
 refreshing thread list

Signed-off-by: Minsoo Choo <minsoochoo0122 at proton.me>
---
 .../ProcessFreeBSDKernelCore.cpp              | 64 +++++++++++++++++++
 .../ProcessFreeBSDKernelCore.h                |  6 ++
 2 files changed, 70 insertions(+)

diff --git a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/ProcessFreeBSDKernelCore.cpp b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/ProcessFreeBSDKernelCore.cpp
index da8e22caaa80f..57196564c4bef 100644
--- a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/ProcessFreeBSDKernelCore.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/ProcessFreeBSDKernelCore.cpp
@@ -9,6 +9,8 @@
 #include "lldb/Core/Module.h"
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
 #include "lldb/Symbol/Type.h"
 #include "lldb/Target/DynamicLoader.h"
 #include "lldb/Utility/LLDBLog.h"
@@ -60,6 +62,52 @@ static PluginProperties &GetGlobalPluginProperties() {
   return g_settings;
 }
 
+class CommandObjectProcessFreeBSDKernelCoreRefreshThreads
+    : public CommandObjectParsed {
+public:
+  CommandObjectProcessFreeBSDKernelCoreRefreshThreads(
+      CommandInterpreter &interpreter)
+      : CommandObjectParsed(
+            interpreter, "process plugin refresh-threads",
+            "Refresh the thread list from the FreeBSD kernel core dump. "
+            "This flushes the memory cache and re-reads the kernel's "
+            "allproc/zombie lists to rebuild the thread list from scratch.",
+            "process plugin refresh-threads") {}
+
+  ~CommandObjectProcessFreeBSDKernelCoreRefreshThreads() override = default;
+
+protected:
+  void DoExecute(Args &command, CommandReturnObject &result) override {
+    // TODO: Return early for elf-core based implementation.
+
+    auto *process = static_cast<ProcessFreeBSDKernelCore *>(
+        m_interpreter.GetExecutionContext().GetProcessPtr());
+    if (!process) {
+      result.AppendError("no process");
+      return;
+    }
+
+    // Clear the memory cache so DoUpdateThreadList() will re-read
+    // allproc, zombproc, and all thread/proc structures fresh from
+    // the core dump instead of getting stale cached values.
+    process->m_memory_cache.Clear();
+
+    // Explicitly clear the thread list after Flush() to guarantee that
+    // UpdateThreadListIfNeeded() sees size == 0 and enters the rebuild
+    // path regardless of stop-ID state.
+    process->GetThreadList().Clear();
+
+    // Rebuild the process thread list.
+    process->UpdateThreadListIfNeeded();
+
+    const uint32_t num_threads = process->GetThreadList().GetSize(false);
+    result.AppendMessageWithFormat(
+        "Thread list refreshed, %u thread%s found.\n", num_threads,
+        num_threads == 1 ? "" : "s");
+    result.SetStatus(eReturnStatusSuccessFinishResult);
+  }
+};
+
 ProcessFreeBSDKernelCore::ProcessFreeBSDKernelCore(lldb::TargetSP target_sp,
                                                    ListenerSP listener_sp,
                                                    kvm_t *kvm,
@@ -112,6 +160,22 @@ bool ProcessFreeBSDKernelCore::CanDebug(lldb::TargetSP target_sp,
   return true;
 }
 
+CommandObject *ProcessFreeBSDKernelCore::GetPluginCommandObject() {
+  if (!m_command_sp) {
+    CommandInterpreter &interp =
+        GetTarget().GetDebugger().GetCommandInterpreter();
+    m_command_sp = std::make_unique<CommandObjectMultiword>(
+        interp, "process plugin",
+        "Commands for the FreeBSD kernel process plug-in.",
+        "process plugin <subcommand> [<subcommand-options>]");
+    m_command_sp->LoadSubCommand(
+        "refresh-threads",
+        CommandObjectSP(
+            new CommandObjectProcessFreeBSDKernelCoreRefreshThreads(interp)));
+  }
+  return m_command_sp.get();
+}
+
 Status ProcessFreeBSDKernelCore::DoLoadCore() {
   // The core is already loaded by CreateInstance().
   SetKernelDisplacement();
diff --git a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/ProcessFreeBSDKernelCore.h b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/ProcessFreeBSDKernelCore.h
index d82e55ea74bd9..ac30d9e194305 100644
--- a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/ProcessFreeBSDKernelCore.h
+++ b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/ProcessFreeBSDKernelCore.h
@@ -43,6 +43,8 @@ class ProcessFreeBSDKernelCore : public lldb_private::PostMortemProcess {
   bool CanDebug(lldb::TargetSP target_sp,
                 bool plugin_specified_by_name) override;
 
+  lldb_private::CommandObject *GetPluginCommandObject() override;
+
   lldb_private::Status DoLoadCore() override;
 
   lldb_private::DynamicLoader *GetDynamicLoader() override;
@@ -55,6 +57,8 @@ class ProcessFreeBSDKernelCore : public lldb_private::PostMortemProcess {
                        lldb_private::Status &error) override;
 
 protected:
+  friend class CommandObjectProcessFreeBSDKernelCoreRefreshThreads;
+
   bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list,
                           lldb_private::ThreadList &new_thread_list) override;
 
@@ -70,6 +74,8 @@ class ProcessFreeBSDKernelCore : public lldb_private::PostMortemProcess {
 
   const char *GetError();
 
+  std::unique_ptr<lldb_private::CommandObjectMultiword> m_command_sp;
+
   bool m_printed_unread_message = false;
 
   kvm_t *m_kvm;

>From c4e23c531cbe00b5895e61e83f131c2fff5fff3e Mon Sep 17 00:00:00 2001
From: Minsoo Choo <minsoochoo0122 at proton.me>
Date: Sun, 29 Mar 2026 22:39:04 +0900
Subject: [PATCH 2/2] fixup! [lldb][Process/FreeBSDKernelCore] Add command for
 refreshing thread list

Signed-off-by: Minsoo Choo <minsoochoo0122 at proton.me>
---
 .../ProcessFreeBSDKernelCore.cpp              | 49 ++++++++++---------
 1 file changed, 26 insertions(+), 23 deletions(-)

diff --git a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/ProcessFreeBSDKernelCore.cpp b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/ProcessFreeBSDKernelCore.cpp
index 57196564c4bef..c633ef02844b9 100644
--- a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/ProcessFreeBSDKernelCore.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/ProcessFreeBSDKernelCore.cpp
@@ -69,10 +69,14 @@ class CommandObjectProcessFreeBSDKernelCoreRefreshThreads
       CommandInterpreter &interpreter)
       : CommandObjectParsed(
             interpreter, "process plugin refresh-threads",
-            "Refresh the thread list from the FreeBSD kernel core dump. "
-            "This flushes the memory cache and re-reads the kernel's "
-            "allproc/zombie lists to rebuild the thread list from scratch.",
-            "process plugin refresh-threads") {}
+            "Refresh the thread list from the FreeBSD kernel core. The thread "
+            "list and related data structures may be being read from live "
+            "memory (/dev/mem), which may have changed since the last refresh. "
+            "This command clears LLDB's thread list and memory cache then "
+            "re-reads the kernel's allproc/zombie lists to rebuild the thread "
+            "list from scratch.",
+            "process plugin refresh-threads",
+            eCommandRequiresProcess | eCommandTryTargetAPILock) {}
 
   ~CommandObjectProcessFreeBSDKernelCoreRefreshThreads() override = default;
 
@@ -80,29 +84,28 @@ class CommandObjectProcessFreeBSDKernelCoreRefreshThreads
   void DoExecute(Args &command, CommandReturnObject &result) override {
     // TODO: Return early for elf-core based implementation.
 
-    auto *process = static_cast<ProcessFreeBSDKernelCore *>(
+    auto process = static_cast<ProcessFreeBSDKernelCore *>(
         m_interpreter.GetExecutionContext().GetProcessPtr());
-    if (!process) {
-      result.AppendError("no process");
-      return;
-    }
 
-    // Clear the memory cache so DoUpdateThreadList() will re-read
-    // allproc, zombproc, and all thread/proc structures fresh from
-    // the core dump instead of getting stale cached values.
+    // Clear the memory cache so DoUpdateThreadList() will re-read allproc,
+    // zombproc, and all thread/proc structures fresh from the core dump instead
+    // of getting stale cached values.
     process->m_memory_cache.Clear();
 
-    // Explicitly clear the thread list after Flush() to guarantee that
-    // UpdateThreadListIfNeeded() sees size == 0 and enters the rebuild
-    // path regardless of stop-ID state.
-    process->GetThreadList().Clear();
-
-    // Rebuild the process thread list.
-    process->UpdateThreadListIfNeeded();
-
-    const uint32_t num_threads = process->GetThreadList().GetSize(false);
-    result.AppendMessageWithFormat(
-        "Thread list refreshed, %u thread%s found.\n", num_threads,
+    // Clear both thread lists to guarantee that UpdateThreadListIfNeeded() sees
+    // size == 0 and enters the rebuild path regardless of stop-ID state.
+    // UpdateThreadListIfNeeded() passes m_thread_list_real as old_thread_list
+    // to DoUpdateThreadList(), and DoUpdateThreadList() only rebuilds from
+    // scratch when old_thread_list is empty. m_thread_list is the public copy
+    // that is sync'd from m_thread_list_real afterwards.
+    process->m_thread_list_real.Clear();
+    process->m_thread_list.Clear();
+
+    // This calls UpdateThreadListIfNeeded() to rebuild the process thread list.
+    const uint32_t num_threads =
+        process->GetThreadList().GetSize(/*can_update=*/true);
+    result.AppendMessageWithFormatv(
+        "Thread list refreshed, {0} thread{1} found.", num_threads,
         num_threads == 1 ? "" : "s");
     result.SetStatus(eReturnStatusSuccessFinishResult);
   }



More information about the lldb-commits mailing list