Implement investigate kernel corefile to lldb.
authorasou <asou@openbsd.org>
Sat, 13 Jul 2024 07:25:38 +0000 (07:25 +0000)
committerasou <asou@openbsd.org>
Sat, 13 Jul 2024 07:25:38 +0000 (07:25 +0000)
15 files changed:
gnu/llvm/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp
gnu/llvm/lldb/source/Plugins/Process/CMakeLists.txt
gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/CMakeLists.txt [new file with mode: 0644]
gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/ProcessOpenBSDKernel.cpp [new file with mode: 0644]
gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/ProcessOpenBSDKernel.h [new file with mode: 0644]
gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_arm64.cpp [new file with mode: 0644]
gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_arm64.h [new file with mode: 0644]
gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_i386.cpp [new file with mode: 0644]
gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_i386.h [new file with mode: 0644]
gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_x86_64.cpp [new file with mode: 0644]
gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/RegisterContextOpenBSDKernel_x86_64.h [new file with mode: 0644]
gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/ThreadOpenBSDKernel.cpp [new file with mode: 0644]
gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/ThreadOpenBSDKernel.h [new file with mode: 0644]
gnu/usr.bin/clang/liblldbPluginProcess/Makefile
gnu/usr.bin/clang/lldb/Makefile

index 7aa5620..4d284df 100644 (file)
@@ -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();
     }
   }
 
index ec35a42..687a769 100644 (file)
@@ -22,3 +22,4 @@ add_subdirectory(elf-core)
 add_subdirectory(mach-core)
 add_subdirectory(minidump)
 add_subdirectory(FreeBSDKernel)
+add_subdirectory(OpenBSDKernel)\r
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 (file)
index 0000000..4097666
--- /dev/null
@@ -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 (file)
index 0000000..57724ca
--- /dev/null
@@ -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 (file)
index 0000000..64d90a3
--- /dev/null
@@ -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 (file)
index 0000000..1ebfc6a
--- /dev/null
@@ -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 (file)
index 0000000..96ab55b
--- /dev/null
@@ -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 (file)
index 0000000..9a909a4
--- /dev/null
@@ -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 (file)
index 0000000..da6d9a7
--- /dev/null
@@ -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 (file)
index 0000000..501fa85
--- /dev/null
@@ -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 (file)
index 0000000..7a7d26f
--- /dev/null
@@ -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 (file)
index 0000000..fec0b6c
--- /dev/null
@@ -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 (file)
index 0000000..5372e0a
--- /dev/null
@@ -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
index a075e15..af448a4 100644 (file)
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.11 2023/11/11 18:35:39 robert Exp $
+# $OpenBSD: Makefile,v 1.12 2024/07/13 07:25:38 asou Exp $
 
 LIB=   lldbPluginProcess
 NOPIC=
@@ -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 ...
index 31a1ffc..9afc1ef 100644 (file)
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.16 2024/02/08 20:28:54 miod Exp $
+# $OpenBSD: Makefile,v 1.17 2024/07/13 07:25:38 asou Exp $
 
 .include <bsd.own.mk>
 
@@ -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}