mgorny created this revision.
mgorny added reviewers: labath, emaste, krytarowski.
Herald added a subscriber: arichardson.
mgorny requested review of this revision.

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


https://reviews.llvm.org/D116005

Files:
  lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt
  lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
  lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
  
lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelLive.py

Index: lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelLive.py
===================================================================
--- /dev/null
+++ 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)
Index: lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
===================================================================
--- lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
+++ lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
@@ -13,8 +13,18 @@
 
 class ProcessFreeBSDKernel : public lldb_private::PostMortemProcess {
 public:
+  enum class CoreProvider {
+#if LLDB_ENABLE_FBSDVMCORE
+    fvc,
+#endif
+#if defined(__FreeBSD__)
+    kvm,
+#endif
+  };
+
   ProcessFreeBSDKernel(lldb::TargetSP target_sp, lldb::ListenerSP listener,
-                       const lldb_private::FileSpec &core_file, void *fvc);
+                       const lldb_private::FileSpec &core_file, void *fvc,
+                       CoreProvider core_provider);
 
   ~ProcessFreeBSDKernel() override;
 
@@ -55,6 +65,9 @@
 
 private:
   void *m_fvc;
+  CoreProvider m_core_provider;
+
+  const char *GetError();
 };
 
 #endif // LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_PROCESSFREEBSDKERNEL_H
Index: lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
===================================================================
--- lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
+++ lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
@@ -10,11 +10,16 @@
 #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;
@@ -23,12 +28,26 @@
 
 ProcessFreeBSDKernel::ProcessFreeBSDKernel(lldb::TargetSP target_sp,
                                            ListenerSP listener_sp,
-                                           const FileSpec &core_file, void *fvc)
-    : PostMortemProcess(target_sp, listener_sp), m_fvc(fvc) {}
+                                           const FileSpec &core_file, void *fvc,
+                                           CoreProvider core_provider)
+    : PostMortemProcess(target_sp, listener_sp), m_fvc(fvc),
+      m_core_provider(core_provider) {}
 
 ProcessFreeBSDKernel::~ProcessFreeBSDKernel() {
-  if (m_fvc)
-    fvc_close(static_cast<fvc_t *>(m_fvc));
+  if (m_fvc) {
+    switch (m_core_provider) {
+#if LLDB_ENABLE_FBSDVMCORE
+    case CoreProvider::fvc:
+      fvc_close(static_cast<fvc_t *>(m_fvc));
+      break;
+#endif
+#if defined(__FreeBSD__)
+    case CoreProvider::kvm:
+      kvm_close(static_cast<kvm_t *>(m_fvc));
+      break;
+#endif
+    }
+  }
 }
 
 lldb::ProcessSP ProcessFreeBSDKernel::CreateInstance(lldb::TargetSP target_sp,
@@ -38,12 +57,23 @@
   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);
+          target_sp, listener_sp, *crash_file, fvc, CoreProvider::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)
+      process_sp = std::make_shared<ProcessFreeBSDKernel>(
+          target_sp, listener_sp, *crash_file, kvm, CoreProvider::kvm);
+#endif
   }
   return process_sp;
 }
@@ -109,10 +139,21 @@
 
 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);
+  ssize_t rd = 0;
+  switch (m_core_provider) {
+#if LLDB_ENABLE_FBSDVMCORE
+  case CoreProvider::fvc:
+    rd = fvc_read(static_cast<fvc_t *>(m_fvc), addr, buf, size);
+    break;
+#endif
+#if defined(__FreeBSD__)
+  case CoreProvider::kvm:
+    rd = kvm_read2(static_cast<kvm_t *>(m_fvc), addr, buf, size);
+    break;
+#endif
+  }
   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;
@@ -124,3 +165,16 @@
         this, DynamicLoaderStatic::GetPluginNameStatic()));
   return m_dyld_up.get();
 }
+
+const char *ProcessFreeBSDKernel::GetError() {
+  switch (m_core_provider) {
+#if LLDB_ENABLE_FBSDVMCORE
+  case CoreProvider::fvc:
+    return fvc_geterr(static_cast<fvc_t *>(m_fvc));
+#endif
+#if defined(__FreeBSD__)
+  case CoreProvider::kvm:
+    return kvm_geterr(static_cast<kvm_t *>(m_fvc));
+#endif
+  }
+}
Index: lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt
+++ 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 @@
   LINK_LIBS
     lldbCore
     lldbTarget
-    fbsdvmcore
+    ${FBSDKERNEL_LIBS}
   LINK_COMPONENTS
     Support
   )
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to