Index | Thread | Search

From:
Yuichiro NAITO <naito.yuichiro@gmail.com>
Subject:
lldb: Kernel corefile support
To:
tech@openbsd.org
Date:
Wed, 05 Jun 2024 12:43:20 +0900

Download raw body.

Thread
Hi, I ported the lldb OpenBSD kernel core file plugin from FreeBSD.
It works on amd64 architecture. I also ported i386 and arm64 architectures
for my technical challenge to learn them. I know lldb is not compiled on i386
and the 'dumpsys' kernel function doesn't work on arm64.

My plugin reads the 'pcb' structure to get a stack frame of a crashed thread
and all 'proc' threads. To read the 'pcb' structure, it needs to include
<machine/pcb.h>. I'm not sure how to get the offsets of the stack pointer and
the frame pointer of 'pcb' in another way.

An example backtrace and thread list that is stopped by 'sysctl ddb.trigger=1'
with a bsd.gdb kernel.

Is my patch OK?

# lldb bsd.1 -c bsd.1.core
(lldb) target create "bsd.1" --core "bsd.1.core"
Core file '/var/crash/bsd.1.core' (x86_64) was loaded.
(lldb) bt
* thread #1, name = 'Crashed Thread'
  * frame #0: 0xffffffff8114dcfc bsd.1`db_fncall(addr=<unavailable>, have_addr=<unavailable>, count=<unavailable>, modif=<unavailable>) at db_command.c:808:11
    frame #1: 0xffffffff8114dcfc bsd.1`db_fncall(addr=<unavailable>, have_addr=<unavailable>, count=<unavailable>, modif=<unavailable>) at db_command.c:808:11
    frame #2: 0xffffffff8114d96e bsd.1`db_command(last_cmdp=0xffffffff825a7fc0, cmd_table=<unavailable>) at db_command.c:292:3
    frame #3: 0xffffffff8114eb0a bsd.1`db_command_loop at db_command.c:738:3
    frame #4: 0xffffffff81fe6219 bsd.1`db_trap(type=<unavailable>, code=<unavailable>) at db_trap.c:92:3
    frame #5: 0xffffffff815c9a51 bsd.1`db_ktrap(type=1, code=0, regs=0xffff80001ca8a010) at db_interface.c:150:2
    frame #6: 0xffffffff81a303f7 bsd.1`kerntrap(frame=0x0000000000000000) at trap.c:323:7
    frame #7: 0xffffffff821001ce bsd.1`alltraps_kern + 126
    frame #8: 0xffffffff815ca5b4 bsd.1`db_enter [inlined] breakpoint at cpufunc.h:414:2
    frame #9: 0xffffffff815ca5b3 bsd.1`db_enter at db_interface.c:436:2
    frame #10: 0xffffffff81af3b7a bsd.1`ddb_sysctl(name=<unavailable>, namelen=<unavailable>, oldp=<unavailable>, oldlenp=<unavailable>, newp=<unavailable>, newlen=<unavailable>, p=0xffff80001ca52a68) at db_usrreq.c:81:5
    frame #11: 0xffffffff81db2a5b bsd.1`sys_sysctl(p=0x0000000000000001, v=0x00007be0397e0d30, retval=<unavailable>) at kern_sysctl.c:254:10
    frame #12: 0xffffffff81a30de1 bsd.1`syscall [inlined] mi_syscall(p=0xffff80001ca8a210, code=-2120020511, callp=<unavailable>, argp=0xffff80001ca8a2a0, retval=<unavailable>) at syscall_mi.h:180:10
    frame #13: 0xffffffff81a30dbc bsd.1`syscall(frame=0xffff80001ca8a2a0) at trap.c:577:10
    frame #14: 0xffffffff820ff134 bsd.1`Xsyscall_meltdown + 308
    frame #15: 0xffffffff820ff055 bsd.1`Xsyscall_meltdown + 85
    frame #16: 0xffff80001ca8a2a0
    frame #17: 0x00000ab61a54eedb
(lldb) thread list
Process 0 stopped
* thread #1: tid = 0x0000, 0xffffffff8114dcfc bsd.1`db_fncall(addr=<unavailable>, have_addr=<unavailable>, count=<unavailable>, modif=<unavailable>) at db_command.c:808:11, name = 'Crashed Thread'
  thread #2: tid = 0x4d1b1, name = '(pid:27380) sysctl (cpu 0)'
  thread #3: tid = 0x33db6, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:4343) ksh'
  thread #4: tid = 0x2baf4, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:61728) cron'
  thread #5: tid = 0x3dde2, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:74120) avahi-daemon'
  thread #6: tid = 0x1f57f, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:62798) dbus-daemon'
  thread #7: tid = 0x329c, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:68716) sndiod'
  thread #8: tid = 0x7772, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:6352) sndiod'
  thread #9: tid = 0x16b9a, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:16751) smtpd'
  thread #10: tid = 0x23a11, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:47666) smtpd'
  thread #11: tid = 0x470ba, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:35809) smtpd'
  thread #12: tid = 0x517e5, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:23758) smtpd'
  thread #13: tid = 0x49bbc, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:50263) smtpd'
  thread #14: tid = 0x64ea2, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:64209) smtpd'
  thread #15: tid = 0x73ee5, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:9349) smtpd'
  thread #16: tid = 0x7fba2, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:77759) sshd'
  thread #17: tid = 0x19050, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:3913) ntpd'
  thread #18: tid = 0x41e7b, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:76783) ntpd'
  thread #19: tid = 0x1133, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:6608) ntpd'
  thread #20: tid = 0x30ec7, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:48134) pflogd'
  thread #21: tid = 0x4b79c, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:12813) pflogd'
  thread #22: tid = 0x611bf, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:74795) syslogd'
  thread #23: tid = 0x7a02d, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:12529) syslogd'
  thread #24: tid = 0x26d34, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:3765) resolvd'
  thread #25: tid = 0x5bfb, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:57496) dhcpleased'
  thread #26: tid = 0x7d804, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:49745) dhcpleased'
  thread #27: tid = 0x728f4, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:49185) dhcpleased'
  thread #28: tid = 0x7122c, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:68535) slaacd'
  thread #29: tid = 0x5fa71, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:7648) slaacd'
  thread #30: tid = 0x4cf5a, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:49587) slaacd'
  thread #31: tid = 0x7eeea, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:6793) smr'
  thread #32: tid = 0x5f4c9, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:73371) zerothread'
  thread #33: tid = 0x5e195, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:59627) aiodoned'
  thread #34: tid = 0x38817, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:47650) update'
  thread #35: tid = 0x773fb, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:83391) cleaner'
  thread #36: tid = 0x13986, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:4549) reaper'
  thread #37: tid = 0x2aa52, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:59949) pagedaemon'
  thread #38: tid = 0x6c4a2, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:62370) acpi0'
  thread #39: tid = 0x1d72e, 0xffffffff8196b002 bsd.1`sched_idle(v=<unavailable>) at kern_sched.c:183:27, name = '(pid:42019) idle3 (cpu 3)'
  thread #40: tid = 0x41e3, 0xffffffff8196b002 bsd.1`sched_idle(v=<unavailable>) at kern_sched.c:183:27, name = '(pid:57382) idle2 (cpu 2)'
  thread #41: tid = 0x2ff0d, 0xffffffff8196b002 bsd.1`sched_idle(v=<unavailable>) at kern_sched.c:183:27, name = '(pid:56434) idle1 (cpu 1)'
  thread #42: tid = 0x2d73b, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:8366) softnet3'
  thread #43: tid = 0x47810, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:63010) softnet2'
  thread #44: tid = 0xc228, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:80989) softnet1'
  thread #45: tid = 0x017b, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:44883) softnet0'
  thread #46: tid = 0x555b9, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:80021) systqmp'
  thread #47: tid = 0x3a5ce, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:32001) systq'
  thread #48: tid = 0x75b43, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:89538) softclockmp'
  thread #49: tid = 0x27cbd, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:56248) softclock'
  thread #50: tid = 0x55f80, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:73828) idle0'
  thread #51: tid = 0x6f358, 0xffffffff81f32cb8 bsd.1`mi_switch at sched_bsd.c:419:3, name = '(pid:1) init'
* thread #1: tid = 0x0000, 0xffffffff8114dcfc bsd.1`db_fncall(addr=<unavailable>, have_addr=<unavailable>, count=<unavailable>, modif=<unavailable>) at db_command.c:808:11, name = 'Crashed Thread'


diff --git a/gnu/llvm/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp b/gnu/llvm/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp
index 7aa5620b14d..cec6c50a007 100644
--- a/gnu/llvm/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp
+++ b/gnu/llvm/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp
@@ -25,6 +25,7 @@
 #include "lldb/Utility/State.h"
 #include "lldb/Utility/Status.h"
 #include "lldb/Utility/StreamString.h"
+#include "Plugins/Process/OpenBSDKernel/ProcessOpenBSDKernel.h"
 
 // Define these constants from OpenBSD mman.h for use when targeting remote
 // openbsd systems even when host has different values.
@@ -91,6 +92,7 @@ void PlatformOpenBSD::Initialize() {
         PlatformOpenBSD::GetPluginNameStatic(false),
         PlatformOpenBSD::GetPluginDescriptionStatic(false),
         PlatformOpenBSD::CreateInstance, nullptr);
+    ProcessOpenBSDKernel::Initialize();
   }
 }
 
@@ -98,6 +100,7 @@ void PlatformOpenBSD::Terminate() {
   if (g_initialize_count > 0) {
     if (--g_initialize_count == 0) {
       PluginManager::UnregisterPlugin(PlatformOpenBSD::CreateInstance);
+      ProcessOpenBSDKernel::Terminate();
     }
   }
 
diff --git a/gnu/llvm/lldb/source/Plugins/Process/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/Process/CMakeLists.txt
index ec35a428a88..2c5f2cf59cb 100644
--- a/gnu/llvm/lldb/source/Plugins/Process/CMakeLists.txt
+++ b/gnu/llvm/lldb/source/Plugins/Process/CMakeLists.txt
@@ -22,3 +22,4 @@ add_subdirectory(elf-core)
 add_subdirectory(mach-core)
 add_subdirectory(minidump)
 add_subdirectory(FreeBSDKernel)
+add_subdirectory(OpenBSDKernel)
diff --git a/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/CMakeLists.txt
new file mode 100644
index 00000000000..40976662fb3
--- /dev/null
+++ b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_lldb_library(lldbPluginProcessOpenBSDKernel PLUGIN
+  ProcessOpenBSDKernel.cpp
+  RegisterContextOpenBSDKernel_arm64.cpp
+  RegisterContextOpenBSDKernel_i386.cpp
+  RegisterContextOpenBSDKernel_x86_64.cpp
+  ThreadOpenBSDKernel.cpp
+
+  LINK_LIBS
+    lldbCore
+    lldbTarget
+    kvm
+  LINK_COMPONENTS
+    Support
+  )
diff --git a/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/ProcessOpenBSDKernel.cpp b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/ProcessOpenBSDKernel.cpp
new file mode 100644
index 00000000000..300a35d4051
--- /dev/null
+++ b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/ProcessOpenBSDKernel.cpp
@@ -0,0 +1,223 @@
+//===-- ProcessOpenBSDKernel.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 "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
+#include "ProcessOpenBSDKernel.h"
+#include "ThreadOpenBSDKernel.h"
+
+#if defined(__OpenBSD__)
+#include <kvm.h>
+#define _KERNEL
+#include <machine/cpu.h>
+#include <sys/proc.h>
+#undef _KERNEL
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(ProcessOpenBSDKernel)
+
+namespace {
+
+#if defined(__OpenBSD__)
+class ProcessOpenBSDKernelKVM : public ProcessOpenBSDKernel {
+public:
+  ProcessOpenBSDKernelKVM(lldb::TargetSP target_sp, lldb::ListenerSP listener,
+                          kvm_t *fvc);
+
+  ~ProcessOpenBSDKernelKVM();
+
+  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(__OpenBSD__)
+
+} // namespace
+
+ProcessOpenBSDKernel::ProcessOpenBSDKernel(lldb::TargetSP target_sp,
+                                           ListenerSP listener_sp)
+    : PostMortemProcess(target_sp, listener_sp) {}
+
+lldb::ProcessSP ProcessOpenBSDKernel::CreateInstance(lldb::TargetSP target_sp,
+                                                     ListenerSP listener_sp,
+                                                     const FileSpec *crash_file,
+                                                     bool can_connect) {
+  ModuleSP executable = target_sp->GetExecutableModule();
+  if (crash_file && !can_connect && executable) {
+#if defined(__OpenBSD__)
+    kvm_t *kvm =
+        kvm_open(executable->GetFileSpec().GetPath().c_str(),
+		 crash_file->GetPath().c_str(), nullptr, O_RDONLY, nullptr);
+    if (kvm)
+      return std::make_shared<ProcessOpenBSDKernelKVM>(target_sp, listener_sp,
+                                                       kvm);
+#endif
+  }
+  return nullptr;
+}
+
+void ProcessOpenBSDKernel::Initialize() {
+  static llvm::once_flag g_once_flag;
+
+  llvm::call_once(g_once_flag, []() {
+    PluginManager::RegisterPlugin(GetPluginNameStatic(),
+                                  GetPluginDescriptionStatic(), CreateInstance);
+  });
+}
+
+void ProcessOpenBSDKernel::Terminate() {
+  PluginManager::UnregisterPlugin(ProcessOpenBSDKernel::CreateInstance);
+}
+
+Status ProcessOpenBSDKernel::DoDestroy() { return Status(); }
+
+bool ProcessOpenBSDKernel::CanDebug(lldb::TargetSP target_sp,
+                                    bool plugin_specified_by_name) {
+  return true;
+}
+
+void ProcessOpenBSDKernel::RefreshStateAfterStop() {}
+
+bool ProcessOpenBSDKernel::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;
+    }
+
+    Status error;
+    int32_t i;
+    lldb::addr_t dumppcb = FindSymbol("dumppcb");
+    uint32_t offset_p_list = offsetof(proc, p_list);
+    uint32_t offset_p_addr = offsetof(proc, p_addr);
+    uint32_t offset_p_tid = offsetof(proc, p_tid);
+    uint32_t offset_p_p = offsetof(proc, p_p);
+    uint32_t offset_ps_comm = offsetof(process, ps_comm);
+    uint32_t offset_ps_pid = offsetof(process, ps_pid);
+    uint32_t offset_ci_curproc = offsetof(cpu_info, ci_curproc);
+    char    comm[_MAXCOMLEN];
+
+    int32_t ncpu = ReadSignedIntegerFromMemory(FindSymbol("ncpus"),
+					       4, -1, error);
+    if (ncpu < 0)
+      return false;
+
+    lldb::addr_t cpu_procs[ncpu];
+
+    if (dumppcb != LLDB_INVALID_ADDRESS) {
+      std::string thread_desc = llvm::formatv("Crashed Thread");
+      ThreadSP thread_sp {
+		new ThreadOpenBSDKernel(*this, 0, dumppcb, thread_desc)};
+        new_thread_list.AddThread(thread_sp);
+    }
+
+    lldb::addr_t cpu_info = FindSymbol("cpu_info");
+    lldb::addr_t cpu_info_array = (cpu_info == LLDB_INVALID_ADDRESS) ?
+      ReadPointerFromMemory(FindSymbol("cpu_info_list"), error) : cpu_info;
+    for (i = 0; i < ncpu ; i++) {
+      lldb::addr_t ci =
+	ReadPointerFromMemory(cpu_info_array + sizeof(void*) * i, error);
+      cpu_procs[i] = ReadPointerFromMemory(ci + offset_ci_curproc, error);
+    }
+
+    for (lldb::addr_t proc = ReadPointerFromMemory(FindSymbol("allproc"), error);
+         proc != 0 && proc != LLDB_INVALID_ADDRESS;
+         proc = ReadPointerFromMemory(proc + offset_p_list, error)) {
+
+      lldb::tid_t tid = ReadSignedIntegerFromMemory(proc + offset_p_tid, 4, -1,
+						    error);
+      lldb::addr_t process = ReadPointerFromMemory(proc + offset_p_p, error);
+      ReadMemory(process + offset_ps_comm, &comm, sizeof(comm), error);
+      u_int32_t pid = ReadSignedIntegerFromMemory(process + offset_ps_pid, 4,
+						  -1, error);
+      lldb::addr_t p_addr = ReadPointerFromMemory(proc + offset_p_addr, error);
+      for (i = 0; i < ncpu; i++)
+	if (cpu_procs[i] == proc)
+	  break;
+      std::string thread_desc;
+      if (i == ncpu)
+	thread_desc = llvm::formatv("(pid:{0}) {1}", pid, comm);
+      else
+	thread_desc = llvm::formatv("(pid:{0}) {1} (cpu {2})", pid, comm, i);
+      ThreadSP thread_sp {
+		new ThreadOpenBSDKernel(*this, tid, p_addr, thread_desc)};
+        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 ProcessOpenBSDKernel::DoLoadCore() {
+  // The core is already loaded by CreateInstance().
+  return Status();
+}
+
+DynamicLoader *ProcessOpenBSDKernel::GetDynamicLoader() {
+  if (m_dyld_up.get() == nullptr)
+    m_dyld_up.reset(DynamicLoader::FindPlugin(
+        this, DynamicLoaderStatic::GetPluginNameStatic()));
+  return m_dyld_up.get();
+}
+
+lldb::addr_t ProcessOpenBSDKernel::FindSymbol(const char *name) {
+  ModuleSP mod_sp = GetTarget().GetExecutableModule();
+  const Symbol *sym = mod_sp->FindFirstSymbolWithNameAndType(ConstString(name));
+  return sym ? sym->GetLoadAddress(&GetTarget()) : LLDB_INVALID_ADDRESS;
+}
+
+#if defined(__OpenBSD__)
+
+ProcessOpenBSDKernelKVM::ProcessOpenBSDKernelKVM(lldb::TargetSP target_sp,
+                                                 ListenerSP listener_sp,
+                                                 kvm_t *fvc)
+    : ProcessOpenBSDKernel(target_sp, listener_sp), m_kvm(fvc) {}
+
+ProcessOpenBSDKernelKVM::~ProcessOpenBSDKernelKVM() {
+  if (m_kvm)
+    kvm_close(m_kvm);
+}
+
+size_t ProcessOpenBSDKernelKVM::DoReadMemory(lldb::addr_t addr, void *buf,
+                                             size_t size, Status &error) {
+  ssize_t rd = 0;
+  rd = kvm_read(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 *ProcessOpenBSDKernelKVM::GetError() { return kvm_geterr(m_kvm); }
+
+#endif // defined(__OpenBSD__)
diff --git a/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/ProcessOpenBSDKernel.h b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/ProcessOpenBSDKernel.h
new file mode 100644
index 00000000000..666dd9c2c67
--- /dev/null
+++ b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/ProcessOpenBSDKernel.h
@@ -0,0 +1,53 @@
+//===-- ProcessOpenBSDKernel.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_OPENBSDKERNEL_PROCESSOPENBSDKERNEL_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_OPENBSDKERNEL_PROCESSOPENBSDKERNEL_H
+
+#include "lldb/Target/PostMortemProcess.h"
+
+class ProcessOpenBSDKernel : public lldb_private::PostMortemProcess {
+public:
+  ProcessOpenBSDKernel(lldb::TargetSP target_sp, lldb::ListenerSP listener);
+
+  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 "openbsd-kernel"; }
+
+  static llvm::StringRef GetPluginDescriptionStatic() {
+    return "OpenBSD 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;
+
+  lldb_private::DynamicLoader *GetDynamicLoader() override;
+
+protected:
+  bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list,
+                          lldb_private::ThreadList &new_thread_list) override;
+
+  lldb::addr_t FindSymbol(const char* name);
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_OPENBSDKERNEL_PROCESSOPENBSDKERNEL_H
diff --git a/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_arm64.cpp b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_arm64.cpp
new file mode 100644
index 00000000000..1ebfc6a799f
--- /dev/null
+++ b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_arm64.cpp
@@ -0,0 +1,107 @@
+//===-- RegisterContextOpenBSDKernel_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
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__OpenBSD__)
+#include <sys/types.h>
+#include <sys/time.h>
+#define _KERNEL
+#include <machine/cpu.h>
+#undef _KERNEL
+#include <machine/pcb.h>
+#include <frame.h>
+#endif
+
+#include "RegisterContextOpenBSDKernel_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;
+
+RegisterContextOpenBSDKernel_arm64::RegisterContextOpenBSDKernel_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 RegisterContextOpenBSDKernel_arm64::ReadGPR() { return true; }
+
+bool RegisterContextOpenBSDKernel_arm64::ReadFPR() { return true; }
+
+bool RegisterContextOpenBSDKernel_arm64::WriteGPR() {
+  assert(0);
+  return false;
+}
+
+bool RegisterContextOpenBSDKernel_arm64::WriteFPR() {
+  assert(0);
+  return false;
+}
+
+bool RegisterContextOpenBSDKernel_arm64::ReadRegister(
+    const RegisterInfo *reg_info, RegisterValue &value) {
+  if (m_pcb_addr == LLDB_INVALID_ADDRESS)
+    return false;
+
+#ifdef __aarch64__
+  Status error;
+  struct pcb pcb;
+  size_t rd = m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb),
+						error);
+  if (rd != sizeof(pcb))
+    return false;
+
+  /*
+    Usually pcb is written in `cpu_switchto` function. This function writes
+    registers as same as the structure of  `swichframe`  in the stack.
+    We read the frame if it is.
+   */
+  struct switchframe sf;
+  rd = m_thread.GetProcess()->ReadMemory(pcb.pcb_sp, &sf, sizeof(sf), error);
+  if (rd != sizeof(sf))
+    return false;
+
+  uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+  switch (reg) {
+#define REG(x)					\
+    case gpr_##x##_arm64:			\
+      value = (u_int64_t)sf.sf_##x;		\
+      return true;
+
+    REG(x19);
+    REG(x20);
+    REG(x21);
+    REG(x22);
+    REG(x23);
+    REG(x24);
+    REG(x25);
+    REG(x26);
+    REG(x27);
+    REG(x28);
+  case gpr_fp_arm64:
+    value = (u_int64_t)sf.sf_x29;
+    return true;
+  case gpr_sp_arm64:
+    value = (u_int64_t)pcb.pcb_sp;
+    return true;
+  case gpr_pc_arm64:
+    value = (u_int64_t)sf.sf_lr;
+    return true;
+  }
+#endif
+  return false;
+}
+
+bool RegisterContextOpenBSDKernel_arm64::WriteRegister(
+    const RegisterInfo *reg_info, const RegisterValue &value) {
+  return false;
+}
diff --git a/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_arm64.h b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_arm64.h
new file mode 100644
index 00000000000..b21a074c3e7
--- /dev/null
+++ b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_arm64.h
@@ -0,0 +1,41 @@
+//===-- RegisterContextOpenBSDKernel_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_OPENBSDKERNEL_REGISTERCONTEXTOPENBSDKERNEL_ARM64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_OPENBSDKERNEL_REGISTERCONTEXTOPENBSDKERNEL_ARM64_H
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+
+class RegisterContextOpenBSDKernel_arm64 : public RegisterContextPOSIX_arm64 {
+public:
+  RegisterContextOpenBSDKernel_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_OPENBSDKERNEL_REGISTERCONTEXTOPENBSDKERNEL_ARM64_H
diff --git a/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_i386.cpp b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_i386.cpp
new file mode 100644
index 00000000000..9a909a4e07d
--- /dev/null
+++ b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_i386.cpp
@@ -0,0 +1,110 @@
+//===-- RegisterContextOpenBSDKernel_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
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__OpenBSD__)
+#include <sys/types.h>
+#include <sys/time.h>
+#define _KERNEL
+#include <machine/cpu.h>
+#undef _KERNEL
+#include <machine/pcb.h>
+#include <frame.h>
+#endif
+
+#include "RegisterContextOpenBSDKernel_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;
+
+RegisterContextOpenBSDKernel_i386::RegisterContextOpenBSDKernel_i386(
+    Thread &thread, RegisterInfoInterface *register_info, lldb::addr_t pcb_addr)
+    : RegisterContextPOSIX_x86(thread, 0, register_info), m_pcb_addr(pcb_addr) {
+}
+
+bool RegisterContextOpenBSDKernel_i386::ReadGPR() { return true; }
+
+bool RegisterContextOpenBSDKernel_i386::ReadFPR() { return true; }
+
+bool RegisterContextOpenBSDKernel_i386::WriteGPR() {
+  assert(0);
+  return false;
+}
+
+bool RegisterContextOpenBSDKernel_i386::WriteFPR() {
+  assert(0);
+  return false;
+}
+
+bool RegisterContextOpenBSDKernel_i386::ReadRegister(
+    const RegisterInfo *reg_info, RegisterValue &value) {
+  if (m_pcb_addr == LLDB_INVALID_ADDRESS)
+    return false;
+
+#ifdef __i386__
+  struct pcb pcb;
+
+  Status error;
+  size_t rd =
+      m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);
+  if (rd != sizeof(pcb))
+    return false;
+
+  if ((pcb.pcb_flags & PCB_SAVECTX) != 0) {
+    uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+    switch (reg) {
+#define PCBREG(x)							\
+    case lldb_##x##_i386:						\
+      value = pcb.pcb_##x;						\
+      return true;
+    PCBREG(ebp);
+    PCBREG(esp);
+    case lldb_eip_i386:
+      value = m_thread.GetProcess()->ReadPointerFromMemory(pcb.pcb_ebp + 4,
+							   error);
+      return true;
+    }
+    return false;
+  }
+
+  /*
+    Usually pcb is written in `cpu_switchto` function. This function writes
+    registers as same as the structure of  `swichframe`  in the stack.
+    We read the frame if it is.
+   */
+  struct switchframe sf;
+  rd = m_thread.GetProcess()->ReadMemory(pcb.pcb_esp, &sf, sizeof(sf), error);
+  if (rd != sizeof(sf))
+    return false;
+
+  uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+  switch (reg) {
+#define SFREG(x)							\
+    case lldb_##x##_i386:						\
+      value = sf.sf_##x;						\
+      return true;
+
+    SFREG(edi);
+    SFREG(esi);
+    SFREG(ebx);
+    SFREG(eip);
+    PCBREG(ebp);
+    PCBREG(esp);
+  }
+#endif
+  return false;
+}
+
+bool RegisterContextOpenBSDKernel_i386::WriteRegister(
+    const RegisterInfo *reg_info, const RegisterValue &value) {
+  return false;
+}
diff --git a/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_i386.h b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_i386.h
new file mode 100644
index 00000000000..1d44dedf0c5
--- /dev/null
+++ b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_i386.h
@@ -0,0 +1,41 @@
+//===-- RegisterContextOpenBSDKernel_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_OPENBSDKERNEL_REGISTERCONTEXTOPENBSDKERNEL_I386_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_OPENBSDKERNEL_REGISTERCONTEXTOPENBSDKERNEL_I386_H
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+
+class RegisterContextOpenBSDKernel_i386 : public RegisterContextPOSIX_x86 {
+public:
+  RegisterContextOpenBSDKernel_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_OPENBSDKERNEL_REGISTERCONTEXTOPENBSDKERNEL_I386_H
diff --git a/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_x86_64.cpp b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_x86_64.cpp
new file mode 100644
index 00000000000..501fa858a92
--- /dev/null
+++ b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_x86_64.cpp
@@ -0,0 +1,111 @@
+//===-- RegisterContextOpenBSDKernel_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
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__OpenBSD__)
+#include <sys/types.h>
+#include <sys/time.h>
+#define _KERNEL
+#include <machine/cpu.h>
+#undef _KERNEL
+#include <machine/pcb.h>
+#include <frame.h>
+#endif
+
+#include "RegisterContextOpenBSDKernel_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;
+
+RegisterContextOpenBSDKernel_x86_64::RegisterContextOpenBSDKernel_x86_64(
+    Thread &thread, RegisterInfoInterface *register_info,
+    lldb::addr_t pcb)
+  : RegisterContextPOSIX_x86(thread, 0, register_info),
+    m_pcb_addr(pcb) {
+}
+
+bool RegisterContextOpenBSDKernel_x86_64::ReadGPR() { return true; }
+
+bool RegisterContextOpenBSDKernel_x86_64::ReadFPR() { return true; }
+
+bool RegisterContextOpenBSDKernel_x86_64::WriteGPR() {
+  assert(0);
+  return false;
+}
+
+bool RegisterContextOpenBSDKernel_x86_64::WriteFPR() {
+  assert(0);
+  return false;
+}
+
+bool RegisterContextOpenBSDKernel_x86_64::ReadRegister(
+    const RegisterInfo *reg_info, RegisterValue &value) {
+  Status error;
+
+  if (m_pcb_addr == LLDB_INVALID_ADDRESS)
+    return false;
+
+#ifdef __amd64__
+  struct pcb pcb;
+  size_t rd = m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb),
+						error);
+  if (rd != sizeof(pcb))
+    return false;
+
+  /*
+    Usually pcb is written in `cpu_switchto` function. This function writes
+    registers as same as the structure of  `swichframe`  in the stack.
+    We read the frame if it is.
+   */
+  struct switchframe sf;
+  rd = m_thread.GetProcess()->ReadMemory(pcb.pcb_rsp, &sf, sizeof(sf), error);
+  if (rd != sizeof(sf))
+    return false;
+
+  uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+  if (pcb.pcb_rbp == (u_int64_t)sf.sf_rbp) {
+#define SFREG(x)				\
+    case lldb_##x##_x86_64:			\
+      value = (u_int64_t)sf.sf_##x;		\
+      return true;
+#define PCBREG(x)				\
+    case lldb_##x##_x86_64:			\
+      value = pcb.pcb_##x;			\
+      return true;
+    switch (reg) {
+      SFREG(r15);
+      SFREG(r14);
+      SFREG(r13);
+      SFREG(r12);
+      SFREG(rbp);
+      SFREG(rbx);
+      SFREG(rip);
+      PCBREG(rsp);
+    }
+  } else {
+    switch (reg) {
+      PCBREG(rbp);
+      PCBREG(rsp);
+    case lldb_rip_x86_64:
+      value = m_thread.GetProcess()->ReadPointerFromMemory(pcb.pcb_rbp + 8,
+							   error);
+      return true;
+    }
+  }
+#endif
+  return false;
+}
+
+bool RegisterContextOpenBSDKernel_x86_64::WriteRegister(
+    const RegisterInfo *reg_info, const RegisterValue &value) {
+  return false;
+}
diff --git a/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_x86_64.h b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_x86_64.h
new file mode 100644
index 00000000000..63c06fd5d9c
--- /dev/null
+++ b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_x86_64.h
@@ -0,0 +1,41 @@
+//===-- RegisterContextOpenBSDKernel_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_OPENBSDKERNEL_REGISTERCONTEXTOPENBSDKERNEL_X86_64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_OPENBSDKERNEL_REGISTERCONTEXTOPENBSDKERNEL_X86_64_H
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h"
+#include "Plugins/Process/elf-core/RegisterUtilities.h"
+
+class RegisterContextOpenBSDKernel_x86_64 : public RegisterContextPOSIX_x86 {
+public:
+  RegisterContextOpenBSDKernel_x86_64(
+      lldb_private::Thread &thread,
+      lldb_private::RegisterInfoInterface *register_info,
+      lldb::addr_t pcb);
+
+  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_OPENBSDKERNEL_REGISTERCONTEXTOPENBSDKERNEL_X86_64_H
diff --git a/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/ThreadOpenBSDKernel.cpp b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/ThreadOpenBSDKernel.cpp
new file mode 100644
index 00000000000..921101a418f
--- /dev/null
+++ b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/ThreadOpenBSDKernel.cpp
@@ -0,0 +1,86 @@
+//===-- ThreadOpenBSDKernel.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 "ThreadOpenBSDKernel.h"
+
+#include "lldb/Target/Unwind.h"
+#include "lldb/Utility/Log.h"
+
+#include "Plugins/Process/Utility/RegisterContextOpenBSD_i386.h"
+#include "Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
+#include "ProcessOpenBSDKernel.h"
+#include "RegisterContextOpenBSDKernel_arm64.h"
+#include "RegisterContextOpenBSDKernel_i386.h"
+#include "RegisterContextOpenBSDKernel_x86_64.h"
+#include "ThreadOpenBSDKernel.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ThreadOpenBSDKernel::ThreadOpenBSDKernel(Process &process, lldb::tid_t tid,
+					 lldb::addr_t pcb,
+                                         std::string thread_name)
+    : Thread(process, tid), m_thread_name(std::move(thread_name)),
+      m_pcb(pcb) {}
+
+ThreadOpenBSDKernel::~ThreadOpenBSDKernel() {}
+
+void ThreadOpenBSDKernel::RefreshStateAfterStop() {}
+
+lldb::RegisterContextSP ThreadOpenBSDKernel::GetRegisterContext() {
+  if (!m_reg_context_sp)
+    m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
+  return m_reg_context_sp;
+}
+
+lldb::RegisterContextSP
+ThreadOpenBSDKernel::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;
+
+    ProcessOpenBSDKernel *process =
+        static_cast<ProcessOpenBSDKernel *>(GetProcess().get());
+    ArchSpec arch = process->GetTarget().GetArchitecture();
+
+    switch (arch.GetMachine()) {
+    case llvm::Triple::aarch64:
+      m_thread_reg_ctx_sp =
+          std::make_shared<RegisterContextOpenBSDKernel_arm64>(
+              *this, std::make_unique<RegisterInfoPOSIX_arm64>(arch, 0),
+              m_pcb);
+      break;
+    case llvm::Triple::x86:
+      m_thread_reg_ctx_sp = std::make_shared<RegisterContextOpenBSDKernel_i386>(
+          *this, new RegisterContextOpenBSD_i386(arch), m_pcb);
+      break;
+    case llvm::Triple::x86_64:
+      m_thread_reg_ctx_sp =
+          std::make_shared<RegisterContextOpenBSDKernel_x86_64>(
+		  *this, new RegisterContextOpenBSD_x86_64(arch), m_pcb);
+      break;
+    default:
+      assert(false && "Unsupported architecture passed to ThreadOpenBSDKernel");
+      break;
+    }
+
+    reg_ctx_sp = m_thread_reg_ctx_sp;
+  } else {
+    reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame);
+  }
+  return reg_ctx_sp;
+}
+
+bool ThreadOpenBSDKernel::CalculateStopInfo() { return false; }
diff --git a/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/ThreadOpenBSDKernel.h b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/ThreadOpenBSDKernel.h
new file mode 100644
index 00000000000..9324eb50712
--- /dev/null
+++ b/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/ThreadOpenBSDKernel.h
@@ -0,0 +1,50 @@
+//===-- ThreadOpenBSDKernel.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_OPENBSDKERNEL_THREADOPENBSDKERNEL_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_OPENBSDKERNEL_THREADOPENBSDKERNEL_H
+
+#include "lldb/Target/Thread.h"
+
+class ThreadOpenBSDKernel : public lldb_private::Thread {
+public:
+  ThreadOpenBSDKernel(lldb_private::Process &process, lldb::tid_t tid,
+                      lldb::addr_t pcb, std::string thread_name);
+
+  ~ThreadOpenBSDKernel() override;
+
+  void RefreshStateAfterStop() override;
+
+  lldb::RegisterContextSP GetRegisterContext() override;
+
+  lldb::RegisterContextSP
+  CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
+
+  const char *GetName() override {
+    if (m_thread_name.empty())
+      return nullptr;
+    return m_thread_name.c_str();
+  }
+
+  void SetName(const char *name) override {
+    if (name && name[0])
+      m_thread_name.assign(name);
+    else
+      m_thread_name.clear();
+  }
+
+protected:
+  bool CalculateStopInfo() override;
+
+private:
+  std::string m_thread_name;
+  lldb::RegisterContextSP m_thread_reg_ctx_sp;
+  lldb::addr_t m_pcb;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_OPENBSDKERNEL_THREADOPENBSDKERNEL_H
diff --git a/gnu/usr.bin/clang/liblldbPluginProcess/Makefile b/gnu/usr.bin/clang/liblldbPluginProcess/Makefile
index a075e152c07..c7b240f6f12 100644
--- a/gnu/usr.bin/clang/liblldbPluginProcess/Makefile
+++ b/gnu/usr.bin/clang/liblldbPluginProcess/Makefile
@@ -124,6 +124,13 @@ SRCS+=	MinidumpTypes.cpp \
 SRCS+=	ScriptedProcess.cpp \
 	ScriptedThread.cpp
 
+# Process/OpenBSDKernel
+SRCS+=	ProcessOpenBSDKernel.cpp \
+	RegisterContextOpenBSDKernel_arm64.cpp \
+	RegisterContextOpenBSDKernel_i386.cpp \
+	RegisterContextOpenBSDKernel_x86_64.cpp \
+	ThreadOpenBSDKernel.cpp
+
 .PATH:	${.CURDIR}/../../../llvm/lldb/source/Plugins/Process/OpenBSD
 .PATH:	${.CURDIR}/../../../llvm/lldb/source/Plugins/Process/POSIX
 .PATH:	${.CURDIR}/../../../llvm/lldb/source/Plugins/Process/gdb-remote
@@ -132,6 +139,7 @@ SRCS+=	ScriptedProcess.cpp \
 .PATH:	${.CURDIR}/../../../llvm/lldb/source/Plugins/Process/mach-core
 .PATH:	${.CURDIR}/../../../llvm/lldb/source/Plugins/Process/minidump
 .PATH:	${.CURDIR}/../../../llvm/lldb/source/Plugins/Process/scripted
+.PATH:	${.CURDIR}/../../../llvm/lldb/source/Plugins/Process/OpenBSDKernel
 
 install:
 	@# Nothing here so far ...
diff --git a/gnu/usr.bin/clang/lldb/Makefile b/gnu/usr.bin/clang/lldb/Makefile
index 31a1ffc7b8b..652769fd92b 100644
--- a/gnu/usr.bin/clang/lldb/Makefile
+++ b/gnu/usr.bin/clang/lldb/Makefile
@@ -10,7 +10,7 @@ SRCS=	Driver.cpp \
 	Platform.cpp \
 	Version.cpp
 
-LDADD+=		-lcurses -ledit -lpanel
+LDADD+=		-lcurses -ledit -lpanel -lkvm
 
 CPPFLAGS+=	${LLDB_INCLUDES}
 CPPFLAGS+=	${CLANG_INCLUDES}

-- 
Yuichiro NAITO (naito.yuichiro@gmail.com)