diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -58,6 +58,7 @@ 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/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py --- a/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -1570,7 +1570,7 @@ 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 @@ 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/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt --- a/lldb/source/Plugins/Process/CMakeLists.txt +++ b/lldb/source/Plugins/Process/CMakeLists.txt @@ -18,3 +18,4 @@ 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 --- /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.h b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h new file mode 100644 --- /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/ProcessFreeBSDKernel.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp new file mode 100644 --- /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 + +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(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( + 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(m_fvc), addr, buf, size); + if (rd < 0 || static_cast(rd) != size) { + error.SetErrorStringWithFormat("Reading memory failed: %s", + fvc_geterr(static_cast(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/RegisterContextFreeBSDKernel_arm64.h b/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_arm64.h new file mode 100644 --- /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 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_arm64.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_arm64.cpp new file mode 100644 --- /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 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_i386.h b/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_i386.h new file mode 100644 --- /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_i386.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_i386.cpp new file mode 100644 --- /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_x86_64.h b/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_x86_64.h new file mode 100644 --- /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/RegisterContextFreeBSDKernel_x86_64.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/RegisterContextFreeBSDKernel_x86_64.cpp new file mode 100644 --- /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/ThreadFreeBSDKernel.h b/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h new file mode 100644 --- /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/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp new file mode 100644 --- /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(GetProcess().get()); + ArchSpec arch = process->GetTarget().GetArchitecture(); + + switch (arch.GetMachine()) { + case llvm::Triple::aarch64: + m_thread_reg_ctx_sp = + std::make_shared( + *this, std::make_unique(arch, 0), + m_pcb_addr); + break; + case llvm::Triple::x86: + m_thread_reg_ctx_sp = + std::make_shared( + *this, new RegisterContextFreeBSD_i386(arch), m_pcb_addr); + break; + case llvm::Triple::x86_64: + m_thread_reg_ctx_sp = + std::make_shared( + *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/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelVMCore.py b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelVMCore.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelVMCore.py @@ -0,0 +1,153 @@ +import bz2 +import shutil +import struct + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class FreeBSDKernelVMCoreTestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + mydir = TestBase.compute_mydir(__file__) + + def 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("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 --- /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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@