[Lldb-commits] [lldb] [lldb][FreeBSDKernel] Add kernel module file search using linker_path (PR #189332)

via lldb-commits lldb-commits at lists.llvm.org
Mon Mar 30 00:54:22 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Minsoo Choo (mchoo7)

<details>
<summary>Changes</summary>

The DynamicLoaderFreeBSDKernel plugin discovers loaded modules by walking the kernel's `linker_files` list but relies on LLDB's generic search to find .ko files on disk, which doesn't know about FreeBSD's module directories.

- Read the kernel's `linker_path` variable (`kern.module_path` backing store) from the core dump and search those directories for module files.
- Search the kernel binary's directory first.
- Probe `.debug` and `.symbols` suffixes before the bare filename so split debug files are found automatically.

The generic LLDB search is preserved as a fallback.

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


2 Files Affected:

- (modified) lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp (+126-1) 
- (modified) lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h (+8) 


``````````diff
diff --git a/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp b/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp
index 96883a51bd033..4eb5fd4fff33b 100644
--- a/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp
+++ b/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp
@@ -27,12 +27,14 @@
 #include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/State.h"
+#include "llvm/Support/Path.h"
 
 #include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
 
 #include "DynamicLoaderFreeBSDKernel.h"
 #include <memory>
 #include <mutex>
+#include <optional>
 
 using namespace lldb;
 using namespace lldb_private;
@@ -94,6 +96,23 @@ static bool is_reloc(Module *module) {
   return true;
 }
 
+// Suffixes to probe when looking for KLD files, in priority order.
+static const char *kld_suffixes[] = {".debug", ".symbols", ""};
+
+// Check if a path (with optional suffix) exists as a regular file.
+// If found, updates path in place and returns true.
+static bool CheckKLDPath(std::string &path) {
+  for (const char *suffix : kld_suffixes) {
+    std::string candidate = path + suffix;
+    if (FileSystem::Instance().Exists(FileSpec(candidate)) &&
+        !FileSystem::Instance().IsDirectory(FileSpec(candidate))) {
+      path = std::move(candidate);
+      return true;
+    }
+  }
+  return false;
+}
+
 // Instantiate Function of the FreeBSD Kernel Dynamic Loader Plugin called when
 // Register the Plugin
 DynamicLoader *
@@ -354,7 +373,41 @@ bool DynamicLoaderFreeBSDKernel::KModImageInfo::LoadImageUsingMemoryModule(
     const ModuleList &target_images = target.GetImages();
     m_module_sp = target_images.FindModule(m_uuid);
 
-    // Search in the file system
+    // Search using FreeBSD module path conventions before generic search.
+    // This mirrors kgdb's find_kld_path(): check kernel directory first,
+    // then each directory in kern.module_path, trying .debug/.symbols
+    // suffixes.
+    if (!m_module_sp && !IsKernel()) {
+      llvm::StringRef basename = llvm::sys::path::filename(m_name);
+
+      std::string kernel_path;
+      ModuleSP kernel_module = target.GetExecutableModule();
+      if (kernel_module)
+        kernel_path = kernel_module->GetFileSpec().GetPath();
+
+      addr_t module_path_addr = LLDB_INVALID_ADDRESS;
+      DynamicLoaderFreeBSDKernel *loader =
+          static_cast<DynamicLoaderFreeBSDKernel *>(
+              process->GetDynamicLoader());
+      if (loader)
+        module_path_addr = loader->GetLinkerPathAddr();
+
+      std::optional<std::string> found_path = FindKLDPath(
+          basename.str().c_str(), process, kernel_path, module_path_addr);
+
+      if (found_path) {
+        ModuleSpec module_spec(FileSpec(*found_path), target.GetArchitecture());
+        m_module_sp = target.GetOrCreateModule(module_spec, true);
+        if (m_module_sp) {
+          LLDB_LOGF(log,
+                    "KModImageInfo::LoadImageUsingMemoryModule: "
+                    "found '%s' via FreeBSD module path at '%s'",
+                    m_name.c_str(), found_path->c_str());
+        }
+      }
+    }
+
+    // Search in the file system (generic LLDB search)
     if (!m_module_sp) {
       ModuleSpec module_spec(FileSpec(GetPath()), target.GetArchitecture());
       if (IsKernel()) {
@@ -750,6 +803,28 @@ void DynamicLoaderFreeBSDKernel::LoadKernelModules() {
 
   if (symbol) {
     m_linker_file_list_struct_addr = symbol->GetAddress();
+
+    // Read linker_path address for FreeBSD module path searching.
+    // This is the KVA of the string backing kern.module_path sysctl.
+    static ConstString linker_path_symbol_name("linker_path");
+    const Symbol *linker_path_symbol =
+        m_kernel_image_info.GetModule()->FindFirstSymbolWithNameAndType(
+            linker_path_symbol_name, lldb::eSymbolTypeData);
+    if (linker_path_symbol) {
+      Status error;
+      m_linker_path_addr = m_process->ReadPointerFromMemory(
+          linker_path_symbol->GetAddress().GetLoadAddress(
+              &m_process->GetTarget()),
+          error);
+      if (error.Fail())
+        m_linker_path_addr = LLDB_INVALID_ADDRESS;
+      else
+        LLDB_LOGF(log,
+                  "DynamicLoaderFreeBSDKernel::LoadKernelModules: "
+                  "linker_path at 0x%" PRIx64,
+                  m_linker_path_addr);
+    }
+
     ReadAllKmods();
   } else {
     LLDB_LOGF(log, "DynamicLoaderFreeBSDKernel::LoadKernelModules "
@@ -760,6 +835,55 @@ void DynamicLoaderFreeBSDKernel::LoadKernelModules() {
 // Update symbol when use kldload by setting callback function on kldload
 void DynamicLoaderFreeBSDKernel::SetNotificationBreakPoint() {}
 
+std::optional<std::string>
+DynamicLoaderFreeBSDKernel::FindKLDPath(const char *filename, Process *process,
+                                        const std::string &kernel_path,
+                                        addr_t module_path_addr) {
+  Log *log = GetLog(LLDBLog::DynamicLoader);
+
+  // Search in the kernel binary's directory
+  if (!kernel_path.empty()) {
+    llvm::SmallString<256> dir(kernel_path);
+    llvm::sys::path::remove_filename(dir);
+    if (!dir.empty()) {
+      std::string path = (dir + "/" + filename).str();
+      if (CheckKLDPath(path)) {
+        LLDB_LOGF(log, "FindKLDPath: found '%s' in kernel directory",
+                  path.c_str());
+        return path;
+      }
+    }
+  }
+
+  // If it fails, search in each directory from linker_path (kern.module_path)
+  if (module_path_addr != LLDB_INVALID_ADDRESS && module_path_addr != 0) {
+    Status error;
+    char buf[4096];
+    size_t bytes_read = process->ReadCStringFromMemory(module_path_addr, buf,
+                                                       sizeof(buf), error);
+    if (error.Success() && bytes_read > 0) {
+      llvm::StringRef module_path_str(buf);
+      llvm::SmallVector<llvm::StringRef, 8> dirs;
+      module_path_str.split(dirs, ';', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+
+      for (const auto &d : dirs) {
+        std::string path = (d + "/" + filename).str();
+        if (CheckKLDPath(path)) {
+          LLDB_LOGF(log, "FindKLDPath: found '%s' via module_path",
+                    path.c_str());
+          return path;
+        }
+      }
+    } else {
+      LLDB_LOGF(log, "FindKLDPath: failed to read linker_path from 0x%" PRIx64,
+                module_path_addr);
+    }
+  }
+
+  LLDB_LOGF(log, "FindKLDPath: unable to find '%s'", filename);
+  return std::nullopt;
+}
+
 // Hook called when attach to a process
 void DynamicLoaderFreeBSDKernel::DidAttach() {
   PrivateInitialize(m_process);
@@ -781,6 +905,7 @@ void DynamicLoaderFreeBSDKernel::Clear(bool clear_process) {
   m_linker_file_list_struct_addr.Clear();
   m_kernel_image_info.Clear();
   m_linker_files_list.clear();
+  m_linker_path_addr = LLDB_INVALID_ADDRESS;
 }
 
 // Reinitialize class
diff --git a/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h b/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h
index d8656e9c49dfe..55830898c32b1 100644
--- a/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h
+++ b/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h
@@ -55,6 +55,8 @@ class DynamicLoaderFreeBSDKernel : public lldb_private::DynamicLoader {
 
   llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
 
+  lldb::addr_t GetLinkerPathAddr() const { return m_linker_path_addr; }
+
 protected:
   class KModImageInfo {
   public:
@@ -141,6 +143,11 @@ class DynamicLoaderFreeBSDKernel : public lldb_private::DynamicLoader {
 
   void SetNotificationBreakPoint();
 
+  static std::optional<std::string> FindKLDPath(const char *filename,
+                                                lldb_private::Process *process,
+                                                const std::string &kernel_path,
+                                                lldb::addr_t module_path_addr);
+
   static lldb_private::UUID
   CheckForKernelImageAtAddress(lldb_private::Process *process,
                                lldb::addr_t address,
@@ -160,6 +167,7 @@ class DynamicLoaderFreeBSDKernel : public lldb_private::DynamicLoader {
   KModImageInfo::collection_type m_linker_files_list;
   std::recursive_mutex m_mutex;
   std::unordered_map<std::string, lldb_private::UUID> m_kld_name_to_uuid;
+  lldb::addr_t m_linker_path_addr = LLDB_INVALID_ADDRESS;
 
 private:
   DynamicLoaderFreeBSDKernel(const DynamicLoaderFreeBSDKernel &) = delete;

``````````

</details>


https://github.com/llvm/llvm-project/pull/189332


More information about the lldb-commits mailing list