[Lldb-commits] [lldb] 9c7fbc3 - [lldb] Introduce a FreeBSDKernel plugin for vmcores

Michał Górny via lldb-commits lldb-commits at lists.llvm.org
Tue Dec 14 13:07:25 PST 2021


Author: Michał Górny
Date: 2021-12-14T22:07:20+01:00
New Revision: 9c7fbc3f9b05b3249468ef6aeacaf71841b5cfe3

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

LOG: [lldb] Introduce a FreeBSDKernel plugin for vmcores

Introduce a FreeBSDKernel plugin that provides the ability to read
FreeBSD kernel core dumps.  The plugin utilizes libfbsdvmcore to provide
support for both "full memory dump" and minidump formats across variety
of architectures supported by FreeBSD.  It provides the ability to read
kernel memory, as well as the crashed thread status with registers
on arm64, i386 and x86_64.

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

Added: 
    lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt
    lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
    lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
    lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_arm64.cpp
    lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_arm64.h
    lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_i386.cpp
    lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_i386.h
    lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_x86_64.cpp
    lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_x86_64.h
    lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp
    lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelVMCore.py
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-amd64.yaml
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-arm64.yaml
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-i386.yaml
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/README.rst
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/copy-sparse.py
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/libfbsdvmcore-print-offsets.patch
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/test.script
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-amd64-full.bz2
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-amd64-minidump.bz2
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-arm64-minidump.bz2
    lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-i386-minidump.bz2

Modified: 
    lldb/cmake/modules/LLDBConfig.cmake
    lldb/include/lldb/Host/Config.h.cmake
    lldb/packages/Python/lldbsuite/test/decorators.py
    lldb/packages/Python/lldbsuite/test/lldbtest.py
    lldb/source/API/SBDebugger.cpp
    lldb/source/Plugins/Process/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake
index b62cd7d24438f..687c754326bd1 100644
--- a/lldb/cmake/modules/LLDBConfig.cmake
+++ b/lldb/cmake/modules/LLDBConfig.cmake
@@ -58,6 +58,7 @@ add_optional_dependency(LLDB_ENABLE_LZMA "Enable LZMA compression support in LLD
 add_optional_dependency(LLDB_ENABLE_LUA "Enable Lua scripting support in LLDB" LuaAndSwig LUAANDSWIG_FOUND)
 add_optional_dependency(LLDB_ENABLE_PYTHON "Enable Python scripting support in LLDB" PythonAndSwig PYTHONANDSWIG_FOUND)
 add_optional_dependency(LLDB_ENABLE_LIBXML2 "Enable Libxml 2 support in LLDB" LibXml2 LIBXML2_FOUND VERSION 2.8)
+add_optional_dependency(LLDB_ENABLE_FBSDVMCORE "Enable libfbsdvmcore support in LLDB" FBSDVMCore FBSDVMCore_FOUND)
 
 option(LLDB_USE_SYSTEM_SIX "Use six.py shipped with system and do not install a copy of it" OFF)
 option(LLDB_USE_ENTITLEMENTS "When codesigning, use entitlements if available" ON)

diff  --git a/lldb/include/lldb/Host/Config.h.cmake b/lldb/include/lldb/Host/Config.h.cmake
index 777a6d1be5418..ffe919aa99561 100644
--- a/lldb/include/lldb/Host/Config.h.cmake
+++ b/lldb/include/lldb/Host/Config.h.cmake
@@ -45,6 +45,8 @@
 
 #cmakedefine01 LLDB_ENABLE_PYTHON
 
+#cmakedefine01 LLDB_ENABLE_FBSDVMCORE
+
 #cmakedefine01 LLDB_EMBED_PYTHON_HOME
 
 #cmakedefine LLDB_PYTHON_HOME R"(${LLDB_PYTHON_HOME})"

diff  --git a/lldb/packages/Python/lldbsuite/test/decorators.py b/lldb/packages/Python/lldbsuite/test/decorators.py
index b6ef3f08df22c..c44c007a20fc2 100644
--- a/lldb/packages/Python/lldbsuite/test/decorators.py
+++ b/lldb/packages/Python/lldbsuite/test/decorators.py
@@ -881,6 +881,9 @@ def skipIfXmlSupportMissing(func):
 def skipIfEditlineSupportMissing(func):
     return _get_bool_config_skip_if_decorator("editline")(func)
 
+def skipIfFBSDVMCoreSupportMissing(func):
+    return _get_bool_config_skip_if_decorator("fbsdvmcore")(func)
+
 def skipIfLLVMTargetMissing(target):
     config = lldb.SBDebugger.GetBuildConfiguration()
     targets = config.GetValueForKey("targets").GetValueForKey("value")

diff  --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py
index 924e1fed4f38c..605ba251e73f2 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbtest.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py
@@ -1570,7 +1570,7 @@ def findBuiltClang(self):
         return os.environ["CC"]
 
 
-    def yaml2obj(self, yaml_path, obj_path):
+    def yaml2obj(self, yaml_path, obj_path, max_size=None):
         """
         Create an object file at the given path from a yaml file.
 
@@ -1580,6 +1580,8 @@ def yaml2obj(self, yaml_path, obj_path):
         if not yaml2obj_bin:
             self.assertTrue(False, "No valid yaml2obj executable specified")
         command = [yaml2obj_bin, "-o=%s" % obj_path, yaml_path]
+        if max_size is not None:
+            command += ["--max-size=%d" % max_size]
         self.runBuildCommand(command)
 
     def getBuildFlags(

diff  --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp
index 5f92729592e32..fa5dcb57de7ee 100644
--- a/lldb/source/API/SBDebugger.cpp
+++ b/lldb/source/API/SBDebugger.cpp
@@ -749,6 +749,9 @@ SBStructuredData SBDebugger::GetBuildConfiguration() {
   AddBoolConfigEntry(
       *config_up, "lua", LLDB_ENABLE_LUA,
       "A boolean value that indicates if lua support is enabled in LLDB");
+  AddBoolConfigEntry(*config_up, "fbsdvmcore", LLDB_ENABLE_FBSDVMCORE,
+                     "A boolean value that indicates if fbsdvmcore support is "
+                     "enabled in LLDB");
   AddLLVMTargets(*config_up);
 
   SBStructuredData data;

diff  --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt
index bea5bac9eb217..a51d0f7afd175 100644
--- a/lldb/source/Plugins/Process/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/CMakeLists.txt
@@ -18,3 +18,4 @@ add_subdirectory(Utility)
 add_subdirectory(elf-core)
 add_subdirectory(mach-core)
 add_subdirectory(minidump)
+add_subdirectory(FreeBSDKernel)

diff  --git a/lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt b/lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt
new file mode 100644
index 0000000000000..ad388ee76b076
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt
@@ -0,0 +1,19 @@
+if (NOT FBSDVMCore_FOUND)
+  message(STATUS "Skipping FreeBSDKernel plugin due to missing libfbsdvmcore")
+  return()
+endif()
+
+add_lldb_library(lldbPluginProcessFreeBSDKernel PLUGIN
+  ProcessFreeBSDKernel.cpp
+  RegisterContextFreeBSDKernel_arm64.cpp
+  RegisterContextFreeBSDKernel_i386.cpp
+  RegisterContextFreeBSDKernel_x86_64.cpp
+  ThreadFreeBSDKernel.cpp
+
+  LINK_LIBS
+    lldbCore
+    lldbTarget
+    fbsdvmcore
+  LINK_COMPONENTS
+    Support
+  )

diff  --git a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
new file mode 100644
index 0000000000000..327e25acd5895
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp
@@ -0,0 +1,126 @@
+//===-- ProcessFreeBSDKernel.cpp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Target/DynamicLoader.h"
+
+#include "ProcessFreeBSDKernel.h"
+#include "ThreadFreeBSDKernel.h"
+#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
+
+#include <fvc.h>
+
+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) {}
+
+ProcessFreeBSDKernel::~ProcessFreeBSDKernel() {
+  if (m_fvc)
+    fvc_close(static_cast<fvc_t *>(m_fvc));
+}
+
+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 (fvc)
+      process_sp = std::make_shared<ProcessFreeBSDKernel>(
+          target_sp, listener_sp, *crash_file, fvc);
+  }
+  return process_sp;
+}
+
+void ProcessFreeBSDKernel::Initialize() {
+  static llvm::once_flag g_once_flag;
+
+  llvm::call_once(g_once_flag, []() {
+    PluginManager::RegisterPlugin(GetPluginNameStatic(),
+                                  GetPluginDescriptionStatic(), CreateInstance);
+  });
+}
+
+void ProcessFreeBSDKernel::Terminate() {
+  PluginManager::UnregisterPlugin(ProcessFreeBSDKernel::CreateInstance);
+}
+
+Status ProcessFreeBSDKernel::DoDestroy() { return Status(); }
+
+bool ProcessFreeBSDKernel::CanDebug(lldb::TargetSP target_sp,
+                                    bool plugin_specified_by_name) {
+  return true;
+}
+
+void ProcessFreeBSDKernel::RefreshStateAfterStop() {}
+
+bool ProcessFreeBSDKernel::DoUpdateThreadList(ThreadList &old_thread_list,
+                                              ThreadList &new_thread_list) {
+  if (old_thread_list.GetSize(false) == 0) {
+    // Make up the thread the first time this is called so we can set our one
+    // and only core thread state up.
+
+    // We cannot construct a thread without a register context as that crashes
+    // LLDB but we can construct a process without threads to provide minimal
+    // memory reading support.
+    switch (GetTarget().GetArchitecture().GetMachine()) {
+    case llvm::Triple::aarch64:
+    case llvm::Triple::x86:
+    case llvm::Triple::x86_64:
+      break;
+    default:
+      return false;
+    }
+
+    const Symbol *pcb_sym =
+        GetTarget().GetExecutableModule()->FindFirstSymbolWithNameAndType(
+            ConstString("dumppcb"));
+    ThreadSP thread_sp(new ThreadFreeBSDKernel(
+        *this, 1, pcb_sym ? pcb_sym->GetFileAddress() : LLDB_INVALID_ADDRESS));
+    new_thread_list.AddThread(thread_sp);
+  } else {
+    const uint32_t num_threads = old_thread_list.GetSize(false);
+    for (uint32_t i = 0; i < num_threads; ++i)
+      new_thread_list.AddThread(old_thread_list.GetThreadAtIndex(i, false));
+  }
+  return new_thread_list.GetSize(false) > 0;
+}
+
+Status ProcessFreeBSDKernel::DoLoadCore() {
+  // The core is already loaded by CreateInstance().
+  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);
+  if (rd < 0 || static_cast<size_t>(rd) != size) {
+    error.SetErrorStringWithFormat("Reading memory failed: %s",
+                                   fvc_geterr(static_cast<fvc_t *>(m_fvc)));
+    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();
+}

diff  --git a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
new file mode 100644
index 0000000000000..cd10728463b57
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h
@@ -0,0 +1,60 @@
+//===-- ProcessFreeBSDKernel.h ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_PROCESSFREEBSDKERNEL_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_PROCESSFREEBSDKERNEL_H
+
+#include "lldb/Target/PostMortemProcess.h"
+
+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;
+
+  static lldb::ProcessSP
+  CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener,
+                 const lldb_private::FileSpec *crash_file_path,
+                 bool can_connect);
+
+  static void Initialize();
+
+  static void Terminate();
+
+  static llvm::StringRef GetPluginNameStatic() { return "freebsd-kernel"; }
+
+  static llvm::StringRef GetPluginDescriptionStatic() {
+    return "FreeBSD kernel vmcore debugging plug-in.";
+  }
+
+  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+  lldb_private::Status DoDestroy() override;
+
+  bool CanDebug(lldb::TargetSP target_sp,
+                bool plugin_specified_by_name) override;
+
+  void RefreshStateAfterStop() override;
+
+  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/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_arm64.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_arm64.cpp
new file mode 100644
index 0000000000000..11843ddc82d97
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_arm64.cpp
@@ -0,0 +1,110 @@
+//===-- RegisterContextFreeBSDKernel_arm64.cpp ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextFreeBSDKernel_arm64.h"
+#include "Plugins/Process/Utility/lldb-arm64-register-enums.h"
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "llvm/Support/Endian.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextFreeBSDKernel_arm64::RegisterContextFreeBSDKernel_arm64(
+    Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm64> register_info_up,
+    lldb::addr_t pcb_addr)
+    : RegisterContextPOSIX_arm64(thread, std::move(register_info_up)),
+      m_pcb_addr(pcb_addr) {}
+
+bool RegisterContextFreeBSDKernel_arm64::ReadGPR() { return true; }
+
+bool RegisterContextFreeBSDKernel_arm64::ReadFPR() { return true; }
+
+bool RegisterContextFreeBSDKernel_arm64::WriteGPR() {
+  assert(0);
+  return false;
+}
+
+bool RegisterContextFreeBSDKernel_arm64::WriteFPR() {
+  assert(0);
+  return false;
+}
+
+bool RegisterContextFreeBSDKernel_arm64::ReadRegister(
+    const RegisterInfo *reg_info, RegisterValue &value) {
+  if (m_pcb_addr == LLDB_INVALID_ADDRESS)
+    return false;
+
+  struct {
+    llvm::support::ulittle64_t x[30];
+    llvm::support::ulittle64_t lr;
+    llvm::support::ulittle64_t _reserved;
+    llvm::support::ulittle64_t sp;
+  } pcb;
+
+  Status error;
+  size_t rd =
+      m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);
+  if (rd != sizeof(pcb))
+    return false;
+
+  uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+  switch (reg) {
+  case gpr_x0_arm64:
+  case gpr_x1_arm64:
+  case gpr_x2_arm64:
+  case gpr_x3_arm64:
+  case gpr_x4_arm64:
+  case gpr_x5_arm64:
+  case gpr_x6_arm64:
+  case gpr_x7_arm64:
+  case gpr_x8_arm64:
+  case gpr_x9_arm64:
+  case gpr_x10_arm64:
+  case gpr_x11_arm64:
+  case gpr_x12_arm64:
+  case gpr_x13_arm64:
+  case gpr_x14_arm64:
+  case gpr_x15_arm64:
+  case gpr_x16_arm64:
+  case gpr_x17_arm64:
+  case gpr_x18_arm64:
+  case gpr_x19_arm64:
+  case gpr_x20_arm64:
+  case gpr_x21_arm64:
+  case gpr_x22_arm64:
+  case gpr_x23_arm64:
+  case gpr_x24_arm64:
+  case gpr_x25_arm64:
+  case gpr_x26_arm64:
+  case gpr_x27_arm64:
+  case gpr_x28_arm64:
+  case gpr_fp_arm64:
+    static_assert(gpr_fp_arm64 - gpr_x0_arm64 == 29,
+                  "nonconsecutive arm64 register numbers");
+    value = pcb.x[reg - gpr_x0_arm64];
+    break;
+  case gpr_sp_arm64:
+    value = pcb.sp;
+    break;
+  case gpr_pc_arm64:
+    // The pc of crashing thread is stored in lr.
+    value = pcb.lr;
+    break;
+  default:
+    return false;
+  }
+  return true;
+}
+
+bool RegisterContextFreeBSDKernel_arm64::WriteRegister(
+    const RegisterInfo *reg_info, const RegisterValue &value) {
+  return false;
+}

diff  --git a/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_arm64.h b/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_arm64.h
new file mode 100644
index 0000000000000..155dda6e748f5
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_arm64.h
@@ -0,0 +1,41 @@
+//===-- RegisterContextFreeBSDKernel_arm64.h --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_REGISTERCONTEXTFREEBSDKERNEL_ARM64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_REGISTERCONTEXTFREEBSDKERNEL_ARM64_H
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+
+class RegisterContextFreeBSDKernel_arm64 : public RegisterContextPOSIX_arm64 {
+public:
+  RegisterContextFreeBSDKernel_arm64(
+      lldb_private::Thread &thread,
+      std::unique_ptr<RegisterInfoPOSIX_arm64> register_info_up,
+      lldb::addr_t pcb_addr);
+
+  bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+                    lldb_private::RegisterValue &value) override;
+
+  bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+                     const lldb_private::RegisterValue &value) override;
+
+protected:
+  bool ReadGPR() override;
+
+  bool ReadFPR() override;
+
+  bool WriteGPR() override;
+
+  bool WriteFPR() override;
+
+private:
+  lldb::addr_t m_pcb_addr;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_REGISTERCONTEXTFREEBSDKERNEL_ARM64_H

diff  --git a/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_i386.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_i386.cpp
new file mode 100644
index 0000000000000..fde85c9c9f0d4
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_i386.cpp
@@ -0,0 +1,83 @@
+//===-- RegisterContextFreeBSDKernel_i386.cpp -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextFreeBSDKernel_i386.h"
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "llvm/Support/Endian.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextFreeBSDKernel_i386::RegisterContextFreeBSDKernel_i386(
+    Thread &thread, RegisterInfoInterface *register_info, lldb::addr_t pcb_addr)
+    : RegisterContextPOSIX_x86(thread, 0, register_info), m_pcb_addr(pcb_addr) {
+}
+
+bool RegisterContextFreeBSDKernel_i386::ReadGPR() { return true; }
+
+bool RegisterContextFreeBSDKernel_i386::ReadFPR() { return true; }
+
+bool RegisterContextFreeBSDKernel_i386::WriteGPR() {
+  assert(0);
+  return false;
+}
+
+bool RegisterContextFreeBSDKernel_i386::WriteFPR() {
+  assert(0);
+  return false;
+}
+
+bool RegisterContextFreeBSDKernel_i386::ReadRegister(
+    const RegisterInfo *reg_info, RegisterValue &value) {
+  if (m_pcb_addr == LLDB_INVALID_ADDRESS)
+    return false;
+
+  struct {
+    llvm::support::ulittle32_t edi;
+    llvm::support::ulittle32_t esi;
+    llvm::support::ulittle32_t ebp;
+    llvm::support::ulittle32_t esp;
+    llvm::support::ulittle32_t ebx;
+    llvm::support::ulittle32_t eip;
+  } pcb;
+
+  Status error;
+  size_t rd =
+      m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);
+  if (rd != sizeof(pcb))
+    return false;
+
+  uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+  switch (reg) {
+#define REG(x)                                                                 \
+  case lldb_##x##_i386:                                                      \
+    value = pcb.x;                                                             \
+    break;
+
+    REG(edi);
+    REG(esi);
+    REG(ebp);
+    REG(esp);
+    REG(eip);
+
+#undef REG
+
+  default:
+    return false;
+  }
+
+  return true;
+}
+
+bool RegisterContextFreeBSDKernel_i386::WriteRegister(
+    const RegisterInfo *reg_info, const RegisterValue &value) {
+  return false;
+}

diff  --git a/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_i386.h b/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_i386.h
new file mode 100644
index 0000000000000..218e3374f8df4
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_i386.h
@@ -0,0 +1,41 @@
+//===-- RegisterContextFreeBSDKernel_i386.h ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_REGISTERCONTEXTFREEBSDKERNEL_I386_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_REGISTERCONTEXTFREEBSDKERNEL_I386_H
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+
+class RegisterContextFreeBSDKernel_i386 : public RegisterContextPOSIX_x86 {
+public:
+  RegisterContextFreeBSDKernel_i386(
+      lldb_private::Thread &thread,
+      lldb_private::RegisterInfoInterface *register_info,
+      lldb::addr_t pcb_addr);
+
+  bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+                    lldb_private::RegisterValue &value) override;
+
+  bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+                     const lldb_private::RegisterValue &value) override;
+
+protected:
+  bool ReadGPR() override;
+
+  bool ReadFPR() override;
+
+  bool WriteGPR() override;
+
+  bool WriteFPR() override;
+
+private:
+  lldb::addr_t m_pcb_addr;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_REGISTERCONTEXTFREEBSDKERNEL_I386_H

diff  --git a/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_x86_64.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_x86_64.cpp
new file mode 100644
index 0000000000000..ff57842e345cb
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_x86_64.cpp
@@ -0,0 +1,88 @@
+//===-- RegisterContextFreeBSDKernel_x86_64.cpp ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextFreeBSDKernel_x86_64.h"
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "llvm/Support/Endian.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextFreeBSDKernel_x86_64::RegisterContextFreeBSDKernel_x86_64(
+    Thread &thread, RegisterInfoInterface *register_info, lldb::addr_t pcb_addr)
+    : RegisterContextPOSIX_x86(thread, 0, register_info), m_pcb_addr(pcb_addr) {
+}
+
+bool RegisterContextFreeBSDKernel_x86_64::ReadGPR() { return true; }
+
+bool RegisterContextFreeBSDKernel_x86_64::ReadFPR() { return true; }
+
+bool RegisterContextFreeBSDKernel_x86_64::WriteGPR() {
+  assert(0);
+  return false;
+}
+
+bool RegisterContextFreeBSDKernel_x86_64::WriteFPR() {
+  assert(0);
+  return false;
+}
+
+bool RegisterContextFreeBSDKernel_x86_64::ReadRegister(
+    const RegisterInfo *reg_info, RegisterValue &value) {
+  if (m_pcb_addr == LLDB_INVALID_ADDRESS)
+    return false;
+
+  struct {
+    llvm::support::ulittle64_t r15;
+    llvm::support::ulittle64_t r14;
+    llvm::support::ulittle64_t r13;
+    llvm::support::ulittle64_t r12;
+    llvm::support::ulittle64_t rbp;
+    llvm::support::ulittle64_t rsp;
+    llvm::support::ulittle64_t rbx;
+    llvm::support::ulittle64_t rip;
+  } pcb;
+
+  Status error;
+  size_t rd =
+      m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);
+  if (rd != sizeof(pcb))
+    return false;
+
+  uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+  switch (reg) {
+#define REG(x)                                                                 \
+  case lldb_##x##_x86_64:                                                      \
+    value = pcb.x;                                                             \
+    break;
+
+    REG(r15);
+    REG(r14);
+    REG(r13);
+    REG(r12);
+    REG(rbp);
+    REG(rsp);
+    REG(rbx);
+    REG(rip);
+
+#undef REG
+
+  default:
+    return false;
+  }
+
+  return true;
+}
+
+bool RegisterContextFreeBSDKernel_x86_64::WriteRegister(
+    const RegisterInfo *reg_info, const RegisterValue &value) {
+  return false;
+}

diff  --git a/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_x86_64.h b/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_x86_64.h
new file mode 100644
index 0000000000000..9a2ac638dfea8
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_x86_64.h
@@ -0,0 +1,41 @@
+//===-- RegisterContextFreeBSDKernel_x86_64.h -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_REGISTERCONTEXTFREEBSDKERNEL_X86_64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_REGISTERCONTEXTFREEBSDKERNEL_X86_64_H
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+
+class RegisterContextFreeBSDKernel_x86_64 : public RegisterContextPOSIX_x86 {
+public:
+  RegisterContextFreeBSDKernel_x86_64(
+      lldb_private::Thread &thread,
+      lldb_private::RegisterInfoInterface *register_info,
+      lldb::addr_t pcb_addr);
+
+  bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+                    lldb_private::RegisterValue &value) override;
+
+  bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+                     const lldb_private::RegisterValue &value) override;
+
+protected:
+  bool ReadGPR() override;
+
+  bool ReadFPR() override;
+
+  bool WriteGPR() override;
+
+  bool WriteFPR() override;
+
+private:
+  lldb::addr_t m_pcb_addr;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_REGISTERCONTEXTFREEBSDKERNEL_X86_64_H

diff  --git a/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp
new file mode 100644
index 0000000000000..124c65d587ff9
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp
@@ -0,0 +1,85 @@
+//===-- ThreadFreeBSDKernel.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ThreadFreeBSDKernel.h"
+
+#include "lldb/Target/Unwind.h"
+#include "lldb/Utility/Log.h"
+
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
+#include "ProcessFreeBSDKernel.h"
+#include "RegisterContextFreeBSDKernel_arm64.h"
+#include "RegisterContextFreeBSDKernel_i386.h"
+#include "RegisterContextFreeBSDKernel_x86_64.h"
+#include "ThreadFreeBSDKernel.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ThreadFreeBSDKernel::ThreadFreeBSDKernel(Process &process, lldb::tid_t tid,
+                                         lldb::addr_t pcb_addr)
+    : Thread(process, tid), m_pcb_addr(pcb_addr) {}
+
+ThreadFreeBSDKernel::~ThreadFreeBSDKernel() {}
+
+void ThreadFreeBSDKernel::RefreshStateAfterStop() {}
+
+lldb::RegisterContextSP ThreadFreeBSDKernel::GetRegisterContext() {
+  if (!m_reg_context_sp)
+    m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
+  return m_reg_context_sp;
+}
+
+lldb::RegisterContextSP
+ThreadFreeBSDKernel::CreateRegisterContextForFrame(StackFrame *frame) {
+  RegisterContextSP reg_ctx_sp;
+  uint32_t concrete_frame_idx = 0;
+
+  if (frame)
+    concrete_frame_idx = frame->GetConcreteFrameIndex();
+
+  if (concrete_frame_idx == 0) {
+    if (m_thread_reg_ctx_sp)
+      return m_thread_reg_ctx_sp;
+
+    ProcessFreeBSDKernel *process =
+        static_cast<ProcessFreeBSDKernel *>(GetProcess().get());
+    ArchSpec arch = process->GetTarget().GetArchitecture();
+
+    switch (arch.GetMachine()) {
+    case llvm::Triple::aarch64:
+      m_thread_reg_ctx_sp =
+          std::make_shared<RegisterContextFreeBSDKernel_arm64>(
+              *this, std::make_unique<RegisterInfoPOSIX_arm64>(arch, 0),
+              m_pcb_addr);
+      break;
+    case llvm::Triple::x86:
+      m_thread_reg_ctx_sp =
+          std::make_shared<RegisterContextFreeBSDKernel_i386>(
+              *this, new RegisterContextFreeBSD_i386(arch), m_pcb_addr);
+      break;
+    case llvm::Triple::x86_64:
+      m_thread_reg_ctx_sp =
+          std::make_shared<RegisterContextFreeBSDKernel_x86_64>(
+              *this, new RegisterContextFreeBSD_x86_64(arch), m_pcb_addr);
+      break;
+    default:
+      assert(false && "Unsupported architecture passed to ThreadFreeBSDKernel");
+      break;
+    }
+
+    reg_ctx_sp = m_thread_reg_ctx_sp;
+  } else {
+    reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame);
+  }
+  return reg_ctx_sp;
+}
+
+bool ThreadFreeBSDKernel::CalculateStopInfo() { return false; }

diff  --git a/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h b/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h
new file mode 100644
index 0000000000000..2842eba64e565
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h
@@ -0,0 +1,36 @@
+//===-- ThreadFreeBSDKernel.h ------------------------------------- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_THREADFREEBSDKERNEL_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_THREADFREEBSDKERNEL_H
+
+#include "lldb/Target/Thread.h"
+
+class ThreadFreeBSDKernel : public lldb_private::Thread {
+public:
+  ThreadFreeBSDKernel(lldb_private::Process &process, lldb::tid_t tid,
+                      lldb::addr_t pcb_addr);
+
+  ~ThreadFreeBSDKernel() override;
+
+  void RefreshStateAfterStop() override;
+
+  lldb::RegisterContextSP GetRegisterContext() override;
+
+  lldb::RegisterContextSP
+  CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
+
+protected:
+  bool CalculateStopInfo() override;
+
+private:
+  lldb::RegisterContextSP m_thread_reg_ctx_sp;
+  lldb::addr_t m_pcb_addr;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_THREADFREEBSDKERNEL_H

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelVMCore.py b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelVMCore.py
new file mode 100644
index 0000000000000..39205c7fe4bc9
--- /dev/null
+++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelVMCore.py
@@ -0,0 +1,154 @@
+import bz2
+import shutil
+import struct
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+ at skipIfFBSDVMCoreSupportMissing
+class FreeBSDKernelVMCoreTestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def make_target(self, src_filename):
+        src = self.getSourcePath(src_filename)
+        dest = self.getBuildArtifact("kernel")
+        self.yaml2obj(src, dest, max_size=30*1024*1024)
+        return self.dbg.CreateTarget(dest)
+
+    def make_vmcore(self, src_filename):
+        src = self.getSourcePath(src_filename)
+        dest = self.getBuildArtifact("vmcore")
+        with bz2.open(src, "rb") as inf:
+            with open(dest, "wb") as outf:
+                shutil.copyfileobj(inf, outf)
+        return dest
+
+    def do_test(self, kernel_yaml, vmcore_bz2, bt_expected, regs_expected,
+                hz_value=100):
+        target = self.make_target(kernel_yaml)
+        vmcore_file = self.make_vmcore(vmcore_bz2)
+        process = target.LoadCore(vmcore_file)
+
+        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))
+
+        # test backtrace
+        self.assertEqual(
+            [process.GetThreadAtIndex(0).GetFrameAtIndex(i).addr
+             .GetLoadAddress(target) for i in range(len(bt_expected))],
+            bt_expected)
+
+        # test registers
+        regs = process.GetThreadAtIndex(0).GetFrameAtIndex(0).GetRegisters()
+        reg_values = {}
+        for regset in regs:
+            for reg in regset:
+                if reg.value is None:
+                    continue
+                reg_values[reg.name] = reg.value
+        self.assertEqual(reg_values, regs_expected)
+
+        self.dbg.DeleteTarget(target)
+
+    def test_amd64_full_vmcore(self):
+        self.do_test("kernel-amd64.yaml", "vmcore-amd64-full.bz2",
+                     [0xffffffff80c09ade, 0xffffffff80c09916,
+                      0xffffffff80c09d90, 0xffffffff80c09b93,
+                      0xffffffff80c57d91, 0xffffffff80c19e71,
+                      0xffffffff80c192bc, 0xffffffff80c19933,
+                      0xffffffff80c1977f, 0xffffffff8108ba8c,
+                      0xffffffff810620ce],
+                     {"rbx": "0x0000000000000000",
+                      "rbp": "0xfffffe0085cb2760",
+                      "rsp": "0xfffffe0085cb2748",
+                      "r12": "0xfffffe0045a6c300",
+                      "r13": "0xfffff800033693a8",
+                      "r14": "0x0000000000000000",
+                      "r15": "0xfffff80003369380",
+                      "rip": "0xffffffff80c09ade",
+                      })
+
+    def test_amd64_minidump(self):
+        self.do_test("kernel-amd64.yaml", "vmcore-amd64-minidump.bz2",
+                     [0xffffffff80c09ade, 0xffffffff80c09916,
+                      0xffffffff80c09d90, 0xffffffff80c09b93,
+                      0xffffffff80c57d91, 0xffffffff80c19e71,
+                      0xffffffff80c192bc, 0xffffffff80c19933,
+                      0xffffffff80c1977f, 0xffffffff8108ba8c,
+                      0xffffffff810620ce],
+                     {"rbx": "0x0000000000000000",
+                      "rbp": "0xfffffe00798c4760",
+                      "rsp": "0xfffffe00798c4748",
+                      "r12": "0xfffffe0045b11c00",
+                      "r13": "0xfffff800033693a8",
+                      "r14": "0x0000000000000000",
+                      "r15": "0xfffff80003369380",
+                      "rip": "0xffffffff80c09ade",
+                      })
+
+    def test_arm64_minidump(self):
+        self.do_test("kernel-arm64.yaml", "vmcore-arm64-minidump.bz2",
+                     [0xffff0000004b6e78],  # TODO: fix unwinding
+                      {"x0": "0x0000000000000000",
+                       "x1": "0x0000000000000000",
+                       "x2": "0x0000000000000000",
+                       "x3": "0x0000000000000000",
+                       "x4": "0x0000000000000000",
+                       "x5": "0x0000000000000000",
+                       "x6": "0x0000000000000000",
+                       "x7": "0x0000000000000000",
+                       "x8": "0xffffa00001548700",
+                       "x9": "0x0000000000000000",
+                       "x10": "0xffffa00000e04580",
+                       "x11": "0x0000000000000000",
+                       "x12": "0x000000000008950a",
+                       "x13": "0x0000000000089500",
+                       "x14": "0x0000000000000039",
+                       "x15": "0x0000000000000000",
+                       "x16": "0x00000000ffffffd8",
+                       "x17": "0x0000000000000000",
+                       "x18": "0xffff000000e6d380",
+                       "x19": "0xffff000000af9000",
+                       "x20": "0xffff000000b82000",
+                       "x21": "0xffffa00000319da8",
+                       "x22": "0xffff000000b84000",
+                       "x23": "0xffff000000b84000",
+                       "x24": "0xffff000000b55000",
+                       "x25": "0x0000000000000000",
+                       "x26": "0x0000000000040800",
+                       "x27": "0x0000000000000000",
+                       "x28": "0x00000000002019ca",
+                       "fp": "0xffff0000d58f23b0",
+                       "sp": "0xffff0000d58f23b0",
+                       "pc": "0xffff0000004b6e78",
+                       },
+                     hz_value=1000)
+
+    def test_i386_minidump(self):
+        self.do_test("kernel-i386.yaml", "vmcore-i386-minidump.bz2",
+                     [0x010025c5, 0x01002410, 0x010027d5, 0x01002644,
+                      0x01049a2f, 0x01011077, 0x01010780, 0x01010c7a,
+                      0x01010ab2, 0x013e9e2d, 0xffc033f9],
+                     {"ebp": "0x151968e4",
+                      "esp": "0x151968d8",
+                      "esi": "0x0c77aa80",
+                      "edi": "0x03f0dc80",
+                      "eip": "0x010025c5",
+                      })

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-amd64.yaml b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-amd64.yaml
new file mode 100644
index 0000000000000..6560ae7d23035
--- /dev/null
+++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-amd64.yaml
@@ -0,0 +1,38 @@
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_FREEBSD
+  Type:            ET_EXEC
+  Machine:         EM_X86_64
+  Entry:           0xFFFFFFFF8037C000
+Sections:
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    Address:         0xFFFFFFFF819BA380
+    AddressAlign:    0x80
+    Offset:          0x17BA348
+    Size:            0x445C80
+Symbols:
+  - Name:            kernbase
+    Index:           SHN_ABS
+    Binding:         STB_GLOBAL
+    Value:           0xFFFFFFFF80000000
+  - Name:            KPML4phys
+    Type:            STT_OBJECT
+    Section:         .bss
+    Binding:         STB_GLOBAL
+    Value:           0xFFFFFFFF81D47EB8
+    Size:            0x8
+  - Name:            dumppcb
+    Type:            STT_OBJECT
+    Section:         .bss
+    Value:           0xFFFFFFFF81CA6868
+    Size:            0x140
+  - Name:            hz
+    Type:            STT_OBJECT
+    Section:         .bss
+    Binding:         STB_GLOBAL
+    Value:           0xFFFFFFFF81CD4C0C
+    Size:            0x4

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-arm64.yaml b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-arm64.yaml
new file mode 100644
index 0000000000000..83f8cff337b83
--- /dev/null
+++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-arm64.yaml
@@ -0,0 +1,30 @@
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_AARCH64
+  Entry:           0xFFFF000000000800
+Sections:
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    Address:         0xFFFF000000C35000
+    AddressAlign:    0x1000
+    Size:            0x37F000
+Symbols:
+  - Name:            kernbase
+    Index:           SHN_ABS
+    Binding:         STB_GLOBAL
+    Value:           0xFFFF000000000000
+  - Name:            dumppcb
+    Type:            STT_OBJECT
+    Section:         .bss
+    Value:           0xFFFF000000DF3790
+    Size:            0x560
+  - Name:            hz
+    Type:            STT_OBJECT
+    Section:         .bss
+    Binding:         STB_GLOBAL
+    Value:           0xFFFF000000E2651C
+    Size:            0x4

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-i386.yaml b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-i386.yaml
new file mode 100644
index 0000000000000..56381df2f4d01
--- /dev/null
+++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/kernel-i386.yaml
@@ -0,0 +1,38 @@
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_FREEBSD
+  Type:            ET_EXEC
+  Machine:         EM_386
+  Entry:           0x8F9000
+Sections:
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    Address:         0x1AB7B00
+    AddressAlign:    0x80
+    Offset:          0x12B7AB0
+    Size:            0x2D48D8
+Symbols:
+  - Name:            kernbase
+    Index:           SHN_ABS
+    Binding:         STB_GLOBAL
+    Value:           0x800000
+  - Name:            dumppcb
+    Type:            STT_OBJECT
+    Section:         .bss
+    Value:           0x1D2D9A0
+    Size:            0xC0
+  - Name:            hz
+    Type:            STT_OBJECT
+    Section:         .bss
+    Binding:         STB_GLOBAL
+    Value:           0x1D4053C
+    Size:            0x4
+  - Name:            IdlePDPT
+    Type:            STT_OBJECT
+    Section:         .bss
+    Binding:         STB_GLOBAL
+    Value:           0x1D8B044
+    Size:            0x4

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/README.rst b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/README.rst
new file mode 100644
index 0000000000000..e3411e5c5703e
--- /dev/null
+++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/README.rst
@@ -0,0 +1,36 @@
+How to create vmcores for tests
+===============================
+
+1. Boot a FreeBSD VM with as little memory as possible and create a core dump
+   per `FreeBSD Handbook Kernel Debugging Chapter`_.  Note that you may need to
+   reboot with more memory after the kernel panic as otherwise savecore(8) may
+   fail.
+
+   For instance, I was able to boot FreeBSD and qemu-system-x86_64 with 128 MiB
+   RAM but had to increase it to 256 MiB for the boot after kernel panic.
+
+2. Transfer the kernel image (``/boot/kernel/kernel``) and vmcore
+   (``/var/crash/vmcore.latest``) from the VM.
+
+3. Patch libfbsdvmcore using ``libfbsdvmcore-print-offsets.patch`` and build
+   LLDB against the patched library.
+
+4. Do a test run of ``test.script`` in LLDB against the kernel + vmcore::
+
+    lldb -b -s test.script --core /path/to/core /path/to/kernel
+
+   If everything works fine, the LLDB output should be interspersed with
+   ``%RD`` lines.
+
+5. Use the ``copy-sparse.py`` tool to create a sparse version of the vmcore::
+
+       lldb -b -s test.script --core /path/to/core /path/to/kernel |
+           grep '^% RD' | python copy-sparse.py /path/to/core vmcore.sparse
+
+6. Compress the sparse vmcore file using ``bzip2``::
+
+       bzip2 -9 vmcore.sparse
+
+
+.. _FreeBSD Handbook Kernel Debugging Chapter:
+   https://docs.freebsd.org/en/books/developers-handbook/kerneldebug/

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/copy-sparse.py b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/copy-sparse.py
new file mode 100644
index 0000000000000..c572351749131
--- /dev/null
+++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/copy-sparse.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+import argparse
+import re
+import sys
+
+
+def main():
+    argp = argparse.ArgumentParser()
+    argp.add_argument('infile', type=argparse.FileType('rb'),
+                      help='Input vmcore file')
+    argp.add_argument('outfile', type=argparse.FileType('wb'),
+                      help='Output vmcore file')
+    args = argp.parse_args()
+
+    inf = args.infile
+    outf = args.outfile
+    line_re = re.compile(r"^% RD: (\d+) (\d+)")
+
+    # copy the first chunk that usually includes ELF headers
+    # (not output by patched libfbsdvmcore since libelf reads this)
+    outf.write(inf.read(1024))
+
+    for l in sys.stdin:
+        m = line_re.match(l)
+        offset, size = [int(x) for x in m.groups()]
+
+        inf.seek(offset)
+        outf.seek(offset)
+        outf.write(inf.read(size))
+
+
+if __name__ == "__main__":
+    main()

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/libfbsdvmcore-print-offsets.patch b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/libfbsdvmcore-print-offsets.patch
new file mode 100644
index 0000000000000..55dd8bcacf12c
--- /dev/null
+++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/libfbsdvmcore-print-offsets.patch
@@ -0,0 +1,166 @@
+
diff  --git a/lib/fvc.c b/lib/fvc.c
+index e6b96c1..4033f78 100644
+--- a/lib/fvc.c
++++ b/lib/fvc.c
+@@ -297,6 +297,7 @@ fvc_read(fvc_t *kd, fvc_addr_t kva, void *buf, size_t len)
+ 			_fvc_syserr(kd, kd->program, "fvc_read");
+ 			break;
+ 		}
++		printf("%% RD: %zu %d\n", pa, cc);
+ 		/*
+ 		 * If ka_kvatop returns a bogus value or our core file is
+ 		 * truncated, we might wind up seeking beyond the end of the
+@@ -331,3 +332,8 @@ fvc_kerndisp(fvc_t *kd)
+ 
+ 	return (kd->arch->ka_kerndisp(kd));
+ }
++
++ssize_t xpread(int fd, void *buf, size_t count, off_t offset) {
++	printf("%% RD: %zu %zu\n", offset, count);
++	return pread(fd, buf, count, offset);
++}
+
diff  --git a/lib/fvc.h b/lib/fvc.h
+index 8680079..ff1e0f0 100644
+--- a/lib/fvc.h
++++ b/lib/fvc.h
+@@ -54,6 +54,8 @@ typedef unsigned char fvc_vm_prot_t;
+ #define	FVC_VM_PROT_WRITE		((fvc_vm_prot_t) 0x02)
+ #define	FVC_VM_PROT_EXECUTE		((fvc_vm_prot_t) 0x04)
+ 
++ssize_t xpread(int fd, void *buf, size_t count, off_t offset);
++
+ struct fvc_page {
+ 	unsigned int	kp_version;
+ 	fvc_addr_t	kp_paddr;
+
diff  --git a/lib/fvc_amd64.c b/lib/fvc_amd64.c
+index 4d27998..69f1807 100644
+--- a/lib/fvc_amd64.c
++++ b/lib/fvc_amd64.c
+@@ -205,7 +205,7 @@ _amd64_vatop(fvc_t *kd, fvc_addr_t va, off_t *pa)
+ 		_fvc_err(kd, kd->program, "_amd64_vatop: pdpe_pa not found");
+ 		goto invalid;
+ 	}
+-	if (pread(kd->pmfd, &pdpe, sizeof(pdpe), ofs) != sizeof(pdpe)) {
++	if (xpread(kd->pmfd, &pdpe, sizeof(pdpe), ofs) != sizeof(pdpe)) {
+ 		_fvc_syserr(kd, kd->program, "_amd64_vatop: read pdpe");
+ 		goto invalid;
+ 	}
+@@ -237,7 +237,7 @@ _amd64_vatop(fvc_t *kd, fvc_addr_t va, off_t *pa)
+ 		_fvc_syserr(kd, kd->program, "_amd64_vatop: pde_pa not found");
+ 		goto invalid;
+ 	}
+-	if (pread(kd->pmfd, &pde, sizeof(pde), ofs) != sizeof(pde)) {
++	if (xpread(kd->pmfd, &pde, sizeof(pde), ofs) != sizeof(pde)) {
+ 		_fvc_syserr(kd, kd->program, "_amd64_vatop: read pde");
+ 		goto invalid;
+ 	}
+@@ -269,7 +269,7 @@ _amd64_vatop(fvc_t *kd, fvc_addr_t va, off_t *pa)
+ 		_fvc_err(kd, kd->program, "_amd64_vatop: pte_pa not found");
+ 		goto invalid;
+ 	}
+-	if (pread(kd->pmfd, &pte, sizeof(pte), ofs) != sizeof(pte)) {
++	if (xpread(kd->pmfd, &pte, sizeof(pte), ofs) != sizeof(pte)) {
+ 		_fvc_syserr(kd, kd->program, "_amd64_vatop: read");
+ 		goto invalid;
+ 	}
+
diff  --git a/lib/fvc_minidump_aarch64.c b/lib/fvc_minidump_aarch64.c
+index 4b8477a..a1c5b42 100644
+--- a/lib/fvc_minidump_aarch64.c
++++ b/lib/fvc_minidump_aarch64.c
+@@ -86,7 +86,7 @@ _aarch64_minidump_initvtop(fvc_t *kd)
+ 		return (-1);
+ 	}
+ 	kd->vmst = vmst;
+-	if (pread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) !=
++	if (xpread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) !=
+ 	    sizeof(vmst->hdr)) {
+ 		_fvc_err(kd, kd->program, "cannot read dump header");
+ 		return (-1);
+
diff  --git a/lib/fvc_minidump_amd64.c b/lib/fvc_minidump_amd64.c
+index 93e8238..0d2237f 100644
+--- a/lib/fvc_minidump_amd64.c
++++ b/lib/fvc_minidump_amd64.c
+@@ -126,7 +126,7 @@ _amd64_minidump_initvtop(fvc_t *kd)
+ 		return (-1);
+ 	}
+ 	kd->vmst = vmst;
+-	if (pread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) !=
++	if (xpread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) !=
+ 	    sizeof(vmst->hdr)) {
+ 		_fvc_err(kd, kd->program, "cannot read dump header");
+ 		return (-1);
+@@ -269,7 +269,7 @@ _amd64_minidump_vatop(fvc_t *kd, fvc_addr_t va, off_t *pa)
+ 				    (uintmax_t)a);
+ 				goto invalid;
+ 			}
+-			if (pread(kd->pmfd, &pt, AMD64_PAGE_SIZE, ofs) !=
++			if (xpread(kd->pmfd, &pt, AMD64_PAGE_SIZE, ofs) !=
+ 			    AMD64_PAGE_SIZE) {
+ 				_fvc_err(kd, kd->program,
+ 				    "cannot read page table entry for %ju",
+
diff  --git a/lib/fvc_minidump_i386.c b/lib/fvc_minidump_i386.c
+index 61cc3db..b3ab955 100644
+--- a/lib/fvc_minidump_i386.c
++++ b/lib/fvc_minidump_i386.c
+@@ -94,7 +94,7 @@ _i386_minidump_initvtop(fvc_t *kd)
+ 		return (-1);
+ 	}
+ 	kd->vmst = vmst;
+-	if (pread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) !=
++	if (xpread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) !=
+ 	    sizeof(vmst->hdr)) {
+ 		_fvc_err(kd, kd->program, "cannot read dump header");
+ 		return (-1);
+
diff  --git a/lib/fvc_private.c b/lib/fvc_private.c
+index 0069a54..fc798fe 100644
+--- a/lib/fvc_private.c
++++ b/lib/fvc_private.c
+@@ -130,7 +130,7 @@ _fvc_is_minidump(fvc_t *kd)
+ {
+ 	char minihdr[8];
+ 
+-	if (pread(kd->pmfd, &minihdr, 8, 0) == 8 &&
++	if (xpread(kd->pmfd, &minihdr, 8, 0) == 8 &&
+ 	    memcmp(&minihdr, "minidump", 8) == 0)
+ 		return (1);
+ 	return (0);
+@@ -256,6 +256,7 @@ _fvc_pmap_get(fvc_t *kd, u_long idx, size_t len)
+ 
+ 	if ((off_t)off >= kd->pt_sparse_off)
+ 		return (NULL);
++	printf("%% RD: %zu %zu\n", kd->page_map_off+off, len);
+ 	return (void *)((uintptr_t)kd->page_map + off);
+ }
+ 
+@@ -270,8 +271,13 @@ _fvc_map_get(fvc_t *kd, u_long pa, unsigned int page_size)
+ 		return NULL;
+ 
+ 	addr = (uintptr_t)kd->page_map + off;
+-	if (off >= kd->pt_sparse_off)
++	if (off >= kd->pt_sparse_off) {
++
+ 		addr = (uintptr_t)kd->sparse_map + (off - kd->pt_sparse_off);
++		printf("%% RD: %zu %u\n", off, page_size);
++	}
++	else
++		printf("%% RD: %zu %u\n", kd->page_map_off+off, page_size);
+ 	return (void *)addr;
+ }
+ 
+@@ -289,6 +295,7 @@ _fvc_pt_init(fvc_t *kd, size_t dump_avail_size, off_t dump_avail_off,
+ 	if (dump_avail_size > 0) {
+ 		kd->dump_avail = mmap(NULL, kd->dump_avail_size, PROT_READ,
+ 		    MAP_PRIVATE, kd->pmfd, dump_avail_off);
++		printf("%% RD: %zu %zu\n", dump_avail_off, dump_avail_size);
+ 	} else {
+ 		/*
+ 		 * Older version minidumps don't provide dump_avail[],
+@@ -309,7 +316,7 @@ _fvc_pt_init(fvc_t *kd, size_t dump_avail_size, off_t dump_avail_off,
+ 		    map_len);
+ 		return (-1);
+ 	}
+-	rd = pread(kd->pmfd, kd->pt_map, map_len, map_off);
++	rd = xpread(kd->pmfd, kd->pt_map, map_len, map_off);
+ 	if (rd < 0 || rd != (ssize_t)map_len) {
+ 		_fvc_err(kd, kd->program, "cannot read %zu bytes for bitmap",
+ 		    map_len);

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/test.script b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/test.script
new file mode 100644
index 0000000000000..5580c3757cc5d
--- /dev/null
+++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/tools/test.script
@@ -0,0 +1,5 @@
+thread list
+register read pc
+bt
+p *(int*)&hz
+memory read &hz

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-amd64-full.bz2 b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-amd64-full.bz2
new file mode 100644
index 0000000000000..34b368616ff06
Binary files /dev/null and b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-amd64-full.bz2 
diff er

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-amd64-minidump.bz2 b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-amd64-minidump.bz2
new file mode 100644
index 0000000000000..b99ff797b6838
Binary files /dev/null and b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-amd64-minidump.bz2 
diff er

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-arm64-minidump.bz2 b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-arm64-minidump.bz2
new file mode 100644
index 0000000000000..73770dfb563e6
Binary files /dev/null and b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-arm64-minidump.bz2 
diff er

diff  --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-i386-minidump.bz2 b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-i386-minidump.bz2
new file mode 100644
index 0000000000000..af373a1bb6aa1
Binary files /dev/null and b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/vmcore-i386-minidump.bz2 
diff er


        


More information about the lldb-commits mailing list