[Lldb-commits] [lldb] fb78587 - [lldb] [Process/FreeBSDKernel] Introduce libkvm support

Michał Górny via lldb-commits lldb-commits at lists.llvm.org
Wed Dec 22 07:16:04 PST 2021


Author: Michał Górny
Date: 2021-12-22T16:14:03+01:00
New Revision: fb785877a95d5d51e802df618b22187b624a2b23

URL: https://github.com/llvm/llvm-project/commit/fb785877a95d5d51e802df618b22187b624a2b23
DIFF: https://github.com/llvm/llvm-project/commit/fb785877a95d5d51e802df618b22187b624a2b23.diff

LOG: [lldb] [Process/FreeBSDKernel] Introduce libkvm support

Introduce initial support for using libkvm on FreeBSD.  The library
can be used as an alternate implementation for processing kernel
coredumps but it can also be used to access live kernel memory through
specifying "/dev/mem" as the core file, i.e.:

    lldb --core /dev/mem /boot/kernel/kernel

Differential Revision: https://reviews.llvm.org/D116005

Added: 
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelLive.py

Modified: 
    lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt
    lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
    lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt b/lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt
index ad388ee76b076..ca89ab0b6dc9d 100644
--- a/lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt
@@ -1,4 +1,12 @@
-if (NOT FBSDVMCore_FOUND)
+set(FBSDKERNEL_LIBS)
+if(FBSDVMCore_FOUND)
+  list(APPEND FBSDKERNEL_LIBS fbsdvmcore)
+endif()
+if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
+  list(APPEND FBSDKERNEL_LIBS kvm)
+endif()
+
+if (NOT FBSDKERNEL_LIBS)
   message(STATUS "Skipping FreeBSDKernel plugin due to missing libfbsdvmcore")
   return()
 endif()
@@ -13,7 +21,7 @@ add_lldb_library(lldbPluginProcessFreeBSDKernel PLUGIN
   LINK_LIBS
     lldbCore
     lldbTarget
-    fbsdvmcore
+    ${FBSDKERNEL_LIBS}
   LINK_COMPONENTS
     Support
   )

diff  --git a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
index 327e25acd5895..339d33d251109 100644
--- a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
@@ -10,42 +10,91 @@
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Target/DynamicLoader.h"
 
+#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
 #include "ProcessFreeBSDKernel.h"
 #include "ThreadFreeBSDKernel.h"
-#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
 
+#if LLDB_ENABLE_FBSDVMCORE
 #include <fvc.h>
+#endif
+#if defined(__FreeBSD__)
+#include <kvm.h>
+#endif
 
 using namespace lldb;
 using namespace lldb_private;
 
 LLDB_PLUGIN_DEFINE(ProcessFreeBSDKernel)
 
-ProcessFreeBSDKernel::ProcessFreeBSDKernel(lldb::TargetSP target_sp,
-                                           ListenerSP listener_sp,
-                                           const FileSpec &core_file, void *fvc)
-    : PostMortemProcess(target_sp, listener_sp), m_fvc(fvc) {}
+namespace {
 
-ProcessFreeBSDKernel::~ProcessFreeBSDKernel() {
-  if (m_fvc)
-    fvc_close(static_cast<fvc_t *>(m_fvc));
-}
+#if LLDB_ENABLE_FBSDVMCORE
+class ProcessFreeBSDKernelFVC : public ProcessFreeBSDKernel {
+public:
+  ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp, lldb::ListenerSP listener,
+                          fvc_t *fvc);
+
+  ~ProcessFreeBSDKernelFVC();
+
+  size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
+                      lldb_private::Status &error) override;
+
+private:
+  fvc_t *m_fvc;
+
+  const char *GetError();
+};
+#endif // LLDB_ENABLE_FBSDVMCORE
+
+#if defined(__FreeBSD__)
+class ProcessFreeBSDKernelKVM : public ProcessFreeBSDKernel {
+public:
+  ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp, lldb::ListenerSP listener,
+                          kvm_t *fvc);
+
+  ~ProcessFreeBSDKernelKVM();
+
+  size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
+                      lldb_private::Status &error) override;
+
+private:
+  kvm_t *m_kvm;
+
+  const char *GetError();
+};
+#endif // defined(__FreeBSD__)
+
+} // namespace
+
+ProcessFreeBSDKernel::ProcessFreeBSDKernel(lldb::TargetSP target_sp,
+                                           ListenerSP listener_sp)
+    : PostMortemProcess(target_sp, listener_sp) {}
 
 lldb::ProcessSP ProcessFreeBSDKernel::CreateInstance(lldb::TargetSP target_sp,
                                                      ListenerSP listener_sp,
                                                      const FileSpec *crash_file,
                                                      bool can_connect) {
-  lldb::ProcessSP process_sp;
   ModuleSP executable = target_sp->GetExecutableModule();
   if (crash_file && !can_connect && executable) {
-    fvc_t *fvc = fvc_open(
-        executable->GetFileSpec().GetPath().c_str(),
-        crash_file->GetPath().c_str(), nullptr, nullptr, nullptr);
+#if LLDB_ENABLE_FBSDVMCORE
+    fvc_t *fvc =
+        fvc_open(executable->GetFileSpec().GetPath().c_str(),
+                 crash_file->GetPath().c_str(), nullptr, nullptr, nullptr);
     if (fvc)
-      process_sp = std::make_shared<ProcessFreeBSDKernel>(
-          target_sp, listener_sp, *crash_file, fvc);
+      return std::make_shared<ProcessFreeBSDKernelFVC>(target_sp, listener_sp,
+                                                       fvc);
+#endif
+
+#if defined(__FreeBSD__)
+    kvm_t *kvm =
+        kvm_open2(executable->GetFileSpec().GetPath().c_str(),
+                  crash_file->GetPath().c_str(), O_RDONLY, nullptr, nullptr);
+    if (kvm)
+      return std::make_shared<ProcessFreeBSDKernelKVM>(target_sp, listener_sp,
+                                                       kvm);
+#endif
   }
-  return process_sp;
+  return nullptr;
 }
 
 void ProcessFreeBSDKernel::Initialize() {
@@ -107,20 +156,63 @@ Status ProcessFreeBSDKernel::DoLoadCore() {
   return Status();
 }
 
-size_t ProcessFreeBSDKernel::DoReadMemory(lldb::addr_t addr, void *buf,
-                                          size_t size, Status &error) {
-  ssize_t rd = fvc_read(static_cast<fvc_t *>(m_fvc), addr, buf, size);
+DynamicLoader *ProcessFreeBSDKernel::GetDynamicLoader() {
+  if (m_dyld_up.get() == nullptr)
+    m_dyld_up.reset(DynamicLoader::FindPlugin(
+        this, DynamicLoaderStatic::GetPluginNameStatic()));
+  return m_dyld_up.get();
+}
+
+#if LLDB_ENABLE_FBSDVMCORE
+
+ProcessFreeBSDKernelFVC::ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp,
+                                                 ListenerSP listener_sp,
+                                                 fvc_t *fvc)
+    : ProcessFreeBSDKernel(target_sp, listener_sp), m_fvc(fvc) {}
+
+ProcessFreeBSDKernelFVC::~ProcessFreeBSDKernelFVC() {
+  if (m_fvc)
+    fvc_close(m_fvc);
+}
+
+size_t ProcessFreeBSDKernelFVC::DoReadMemory(lldb::addr_t addr, void *buf,
+                                             size_t size, Status &error) {
+  ssize_t rd = 0;
+  rd = fvc_read(m_fvc, addr, buf, size);
   if (rd < 0 || static_cast<size_t>(rd) != size) {
-    error.SetErrorStringWithFormat("Reading memory failed: %s",
-                                   fvc_geterr(static_cast<fvc_t *>(m_fvc)));
+    error.SetErrorStringWithFormat("Reading memory failed: %s", GetError());
     return rd > 0 ? rd : 0;
   }
   return rd;
 }
 
-DynamicLoader *ProcessFreeBSDKernel::GetDynamicLoader() {
-  if (m_dyld_up.get() == nullptr)
-    m_dyld_up.reset(DynamicLoader::FindPlugin(
-        this, DynamicLoaderStatic::GetPluginNameStatic()));
-  return m_dyld_up.get();
+const char *ProcessFreeBSDKernelFVC::GetError() { return fvc_geterr(m_fvc); }
+
+#endif // LLDB_ENABLE_FBSDVMCORE
+
+#if defined(__FreeBSD__)
+
+ProcessFreeBSDKernelKVM::ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp,
+                                                 ListenerSP listener_sp,
+                                                 kvm_t *fvc)
+    : ProcessFreeBSDKernel(target_sp, listener_sp), m_kvm(fvc) {}
+
+ProcessFreeBSDKernelKVM::~ProcessFreeBSDKernelKVM() {
+  if (m_kvm)
+    kvm_close(m_kvm);
 }
+
+size_t ProcessFreeBSDKernelKVM::DoReadMemory(lldb::addr_t addr, void *buf,
+                                             size_t size, Status &error) {
+  ssize_t rd = 0;
+  rd = kvm_read2(m_kvm, addr, buf, size);
+  if (rd < 0 || static_cast<size_t>(rd) != size) {
+    error.SetErrorStringWithFormat("Reading memory failed: %s", GetError());
+    return rd > 0 ? rd : 0;
+  }
+  return rd;
+}
+
+const char *ProcessFreeBSDKernelKVM::GetError() { return kvm_geterr(m_kvm); }
+
+#endif // defined(__FreeBSD__)

diff  --git a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
index cd10728463b57..558eec5403db6 100644
--- a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
@@ -13,10 +13,7 @@
 
 class ProcessFreeBSDKernel : public lldb_private::PostMortemProcess {
 public:
-  ProcessFreeBSDKernel(lldb::TargetSP target_sp, lldb::ListenerSP listener,
-                       const lldb_private::FileSpec &core_file, void *fvc);
-
-  ~ProcessFreeBSDKernel() override;
+  ProcessFreeBSDKernel(lldb::TargetSP target_sp, lldb::ListenerSP listener);
 
   static lldb::ProcessSP
   CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener,
@@ -44,17 +41,11 @@ class ProcessFreeBSDKernel : public lldb_private::PostMortemProcess {
 
   lldb_private::Status DoLoadCore() override;
 
-  size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
-                      lldb_private::Status &error) override;
-
   lldb_private::DynamicLoader *GetDynamicLoader() override;
 
 protected:
   bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list,
                           lldb_private::ThreadList &new_thread_list) override;
-
-private:
-  void *m_fvc;
 };
 
 #endif // LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_PROCESSFREEBSDKERNEL_H

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelLive.py b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelLive.py
new file mode 100644
index 0000000000000..98c87461a6080
--- /dev/null
+++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelLive.py
@@ -0,0 +1,44 @@
+import os
+import struct
+import subprocess
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class FreeBSDKernelVMCoreTestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def test_mem(self):
+        kernel_exec = "/boot/kernel/kernel"
+        mem_device = "/dev/mem"
+
+        if not os.access(kernel_exec, os.R_OK):
+            self.skipTest("Kernel @ %s is not readable" % (kernel_exec,))
+        if not os.access(mem_device, os.R_OK):
+            self.skipTest("Memory @ %s is not readable" % (mem_device,))
+
+        target = self.dbg.CreateTarget(kernel_exec)
+        process = target.LoadCore(mem_device)
+        hz_value = int(subprocess.check_output(["sysctl", "-n", "kern.hz"]))
+
+        self.assertTrue(process, PROCESS_IS_VALID)
+        self.assertEqual(process.GetNumThreads(), 1)
+        self.assertEqual(process.GetProcessID(), 0)
+
+        # test memory reading
+        self.expect("expr -- *(int *) &hz",
+                    substrs=["(int) $0 = %d" % hz_value])
+
+        main_mod = target.GetModuleAtIndex(0)
+        hz_addr = (main_mod.FindSymbols("hz")[0].symbol.addr
+                   .GetLoadAddress(target))
+        error = lldb.SBError()
+        self.assertEqual(process.ReadMemory(hz_addr, 4, error),
+                         struct.pack("<I", hz_value))
+
+        self.dbg.DeleteTarget(target)


        


More information about the lldb-commits mailing list