Skip to content

[lldb][Process/FreeBSDKernelCore] Improve DoUpdateThreadList()#183981

Merged
mchoo7 merged 5 commits intollvm:mainfrom
mchoo7:kgdb
Mar 10, 2026
Merged

[lldb][Process/FreeBSDKernelCore] Improve DoUpdateThreadList()#183981
mchoo7 merged 5 commits intollvm:mainfrom
mchoo7:kgdb

Conversation

@mchoo7
Copy link
Copy Markdown
Contributor

@mchoo7 mchoo7 commented Mar 1, 2026

This commit brings improves ProcessFreeBSDKernelCore::DoUpdateThreadList() by porting features from KGDB (fbsd_kthr.c specifically) and adding fixes. It includes:

  1. Validate stopped_cpus before accessing stoppcbs
  2. Check bounds for mp_maxid
  3. Check errors when reading proc from memory
  4. Detect new architectures from previous PRs (ppc64le, riscv64, arm) which weren't handled correctly in DoUpdateThreadList().

Fallbacks for finding offsets aren't ported since kernel exposes hardcoded variables for offsets starting from FreeBSD 11. Fallbacks aren't needed as LLDB 23 only supports FreeBSD 14 and later.

This commit also

Fixes: 2430410(#180669), 4a602c0(#180670), 3d25128(#180674)

Signed-off-by: Minsoo Choo <minsoochoo0122@proton.me>
@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Mar 1, 2026

@llvm/pr-subscribers-lldb

Author: Minsoo Choo (mchoo7)

Changes

This commit brings features in KGDB (fbsd_kthr.c specifically) that haven't been ported to LLDB, which includes:

  1. Adding zombie threads to the thread list
  2. Validate stopped_cpus before accessing stoppcbs
  3. Check bounds for mp_maxid

Fallbacks for finding offsets aren't ported since kernel exposes hardcoded variables for offsets starting from FreeBSD 11. Fallbacks aren't needed as LLDB 23 only supports FreeBSD 14 and later.

This commit also fixes the case where newly added architectures in previous PRs (ppc64le, riscv64, arm) weren't handled correctly in DoUpdateThreadList().

Fixes: 2430410(#180669), 4a602c0(#180670), 3d25128(#180674)


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

2 Files Affected:

  • (modified) lldb/source/Plugins/Process/FreeBSD-Kernel-Core/ProcessFreeBSDKernelCore.cpp (+46-9)
  • (modified) llvm/docs/ReleaseNotes.md (+1)
diff --git a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/ProcessFreeBSDKernelCore.cpp b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/ProcessFreeBSDKernelCore.cpp
index 577d8e0d50cf1..7369b5ffdcb66 100644
--- a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/ProcessFreeBSDKernelCore.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/ProcessFreeBSDKernelCore.cpp
@@ -167,7 +167,10 @@ bool ProcessFreeBSDKernelCore::DoUpdateThreadList(ThreadList &old_thread_list,
     // LLDB but we can construct a process without threads to provide minimal
     // memory reading support.
     switch (GetTarget().GetArchitecture().GetMachine()) {
+    case llvm::Triple::arm:
     case llvm::Triple::aarch64:
+    case llvm::Triple::ppc64le:
+    case llvm::Triple::riscv64:
     case llvm::Triple::x86:
     case llvm::Triple::x86_64:
       break;
@@ -217,6 +220,13 @@ bool ProcessFreeBSDKernelCore::DoUpdateThreadList(ThreadList &old_thread_list,
         ReadSignedIntegerFromMemory(FindSymbol("pcb_size"), 4, -1, error);
     lldb::addr_t stoppcbs = FindSymbol("stoppcbs");
 
+    // Read stopped_cpus bitmask and mp_maxid for CPU validation
+    lldb::addr_t stopped_cpus = FindSymbol("stopped_cpus");
+    int32_t mp_maxid =
+        ReadSignedIntegerFromMemory(FindSymbol("mp_maxid"), 4, 0, error);
+    uint32_t long_size = GetAddressByteSize(); // approximation of sizeof(long)
+    uint32_t long_bits = long_size * 8;
+
     // from FreeBSD sys/param.h
     constexpr size_t fbsd_maxcomlen = 19;
 
@@ -225,11 +235,23 @@ bool ProcessFreeBSDKernelCore::DoUpdateThreadList(ThreadList &old_thread_list,
     // the end of the list, so we have to walk it backwards. First collect all
     // the processes in the list order.
     std::vector<lldb::addr_t> process_addrs;
-    for (lldb::addr_t proc =
-             ReadPointerFromMemory(FindSymbol("allproc"), error);
-         proc != 0 && proc != LLDB_INVALID_ADDRESS;
-         proc = ReadPointerFromMemory(proc + offset_p_list, error)) {
-      process_addrs.push_back(proc);
+
+    lldb::addr_t zombproc_addr = FindSymbol("zombproc");
+    if (zombproc_addr != LLDB_INVALID_ADDRESS) {
+      for (lldb::addr_t proc = ReadPointerFromMemory(zombproc_addr, error);
+           proc != 0 && proc != LLDB_INVALID_ADDRESS;
+           proc = ReadPointerFromMemory(proc + offset_p_list, error)) {
+        process_addrs.push_back(proc);
+      }
+    }
+
+    lldb::addr_t allproc_addr = FindSymbol("allproc");
+    if (allproc_addr != LLDB_INVALID_ADDRESS) {
+      for (lldb::addr_t proc = ReadPointerFromMemory(allproc_addr, error);
+           proc != 0 && proc != LLDB_INVALID_ADDRESS;
+           proc = ReadPointerFromMemory(proc + offset_p_list, error)) {
+        process_addrs.push_back(proc);
+      }
     }
 
     // Processes are in the linked list in descending PID order, so we must walk
@@ -280,12 +302,27 @@ bool ProcessFreeBSDKernelCore::DoUpdateThreadList(ThreadList &old_thread_list,
           pcb_addr = dumppcb;
           thread_desc += " (crashed)";
         } else if (oncpu != -1) {
-          // If we managed to read stoppcbs and pcb_size, use them to find
-          // the correct PCB.
-          if (stoppcbs != LLDB_INVALID_ADDRESS && pcbsize > 0)
+          // Verify the CPU is actually in the stopped set before using
+          // its stoppcbs entry.
+          bool is_stopped = false;
+          if (stopped_cpus != LLDB_INVALID_ADDRESS && oncpu >= 0 &&
+              oncpu <= mp_maxid) {
+            uint32_t bit = oncpu % long_bits;
+            uint32_t word = oncpu / long_bits;
+            lldb::addr_t mask_addr = stopped_cpus + word * long_size;
+            uint64_t mask =
+                ReadUnsignedIntegerFromMemory(mask_addr, long_size, 0, error);
+            if (error.Success())
+              is_stopped = (mask & (1ULL << bit)) != 0;
+          }
+
+          // If we managed to read stoppcbs and pcb_size and the cpu is marked
+          // as stopped, use them to find the correct PCB.
+          if (is_stopped && stoppcbs != LLDB_INVALID_ADDRESS && pcbsize > 0) {
             pcb_addr = stoppcbs + oncpu * pcbsize;
-          else
+          } else {
             pcb_addr = LLDB_INVALID_ADDRESS;
+          }
           thread_desc += llvm::formatv(" (on CPU {0})", oncpu);
         }
 
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 2e0c5c5cb9370..4dd6bf57ee3a2 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -230,6 +230,7 @@ Changes to LLDB
   `plugin.process.freebsd-kernel-core.read-only` must be set to `false`. This setting is available when
   using `/dev/mem` or a kernel dump. However, since `kvm_write()` does not support writing to kernel dumps,
   writes to a kernel dump will still fail when the setting is false.
+* Zombie processes are now shown in the thread list as well.
 
 ### Linux
 

@DavidSpickett DavidSpickett requested review from emaste and jrtc27 March 2, 2026 10:51
@mchoo7 mchoo7 force-pushed the kgdb branch 5 times, most recently from e767a13 to aee36ec Compare March 2, 2026 18:00
Signed-off-by: Minsoo Choo <minsoochoo0122@proton.me>
Copy link
Copy Markdown
Collaborator

@DavidSpickett DavidSpickett left a comment

Choose a reason for hiding this comment

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

Looks ok to me but I'll let a FreeBSD expert be the approver.

Signed-off-by: Minsoo Choo <minsoochoo0122@proton.me>
Signed-off-by: Minsoo Choo <minsoochoo0122@proton.me>
@aokblast aokblast self-requested a review March 4, 2026 15:18
Copy link
Copy Markdown
Contributor

@aokblast aokblast left a comment

Choose a reason for hiding this comment

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

Otherwise looks good

Signed-off-by: Minsoo Choo <minsoochoo0122@proton.me>
Copy link
Copy Markdown
Contributor

@aokblast aokblast left a comment

Choose a reason for hiding this comment

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

LGTM

@mchoo7 mchoo7 merged commit 6dd5212 into llvm:main Mar 10, 2026
10 checks passed
@mchoo7 mchoo7 deleted the kgdb branch March 10, 2026 16:12
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