diff --git a/lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt b/lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt --- a/lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt +++ b/lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt @@ -1,4 +1,12 @@ -if (NOT FBSDVMCore_FOUND) +set(FBSDKERNEL_LIBS) +if(FBSDVMCore_FOUND) + list(APPEND FBSDKERNEL_LIBS fbsdvmcore) +endif() +if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") + list(APPEND FBSDKERNEL_LIBS kvm) +endif() + +if (NOT FBSDKERNEL_LIBS) message(STATUS "Skipping FreeBSDKernel plugin due to missing libfbsdvmcore") return() endif() @@ -13,7 +21,7 @@ LINK_LIBS lldbCore lldbTarget - fbsdvmcore + ${FBSDKERNEL_LIBS} LINK_COMPONENTS Support ) diff --git a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h --- a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h +++ b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h @@ -13,10 +13,7 @@ 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; + ProcessFreeBSDKernel(lldb::TargetSP target_sp, lldb::ListenerSP listener); static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener, @@ -44,17 +41,11 @@ 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 --- a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp +++ b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp @@ -10,42 +10,91 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Target/DynamicLoader.h" +#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" #include "ProcessFreeBSDKernel.h" #include "ThreadFreeBSDKernel.h" -#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" +#if LLDB_ENABLE_FBSDVMCORE #include +#endif +#if defined(__FreeBSD__) +#include +#endif 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) {} +namespace { -ProcessFreeBSDKernel::~ProcessFreeBSDKernel() { - if (m_fvc) - fvc_close(static_cast(m_fvc)); -} +#if LLDB_ENABLE_FBSDVMCORE +class ProcessFreeBSDKernelFVC : public ProcessFreeBSDKernel { +public: + ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp, lldb::ListenerSP listener, + fvc_t *fvc); + + ~ProcessFreeBSDKernelFVC(); + + size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, + lldb_private::Status &error) override; + +private: + fvc_t *m_fvc; + + const char *GetError(); +}; +#endif // LLDB_ENABLE_FBSDVMCORE + +#if defined(__FreeBSD__) +class ProcessFreeBSDKernelKVM : public ProcessFreeBSDKernel { +public: + ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp, lldb::ListenerSP listener, + kvm_t *fvc); + + ~ProcessFreeBSDKernelKVM(); + + 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(__FreeBSD__) + +} // namespace + +ProcessFreeBSDKernel::ProcessFreeBSDKernel(lldb::TargetSP target_sp, + ListenerSP listener_sp) + : PostMortemProcess(target_sp, listener_sp) {} 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 LLDB_ENABLE_FBSDVMCORE + fvc_t *fvc = + fvc_open(executable->GetFileSpec().GetPath().c_str(), + crash_file->GetPath().c_str(), nullptr, nullptr, nullptr); if (fvc) - process_sp = std::make_shared( - target_sp, listener_sp, *crash_file, fvc); + return std::make_shared(target_sp, listener_sp, + fvc); +#endif + +#if defined(__FreeBSD__) + kvm_t *kvm = + kvm_open2(executable->GetFileSpec().GetPath().c_str(), + crash_file->GetPath().c_str(), O_RDONLY, nullptr, nullptr); + if (kvm) + return std::make_shared(target_sp, listener_sp, + kvm); +#endif } - return process_sp; + return nullptr; } void ProcessFreeBSDKernel::Initialize() { @@ -107,20 +156,63 @@ 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); +DynamicLoader *ProcessFreeBSDKernel::GetDynamicLoader() { + if (m_dyld_up.get() == nullptr) + m_dyld_up.reset(DynamicLoader::FindPlugin( + this, DynamicLoaderStatic::GetPluginNameStatic())); + return m_dyld_up.get(); +} + +#if LLDB_ENABLE_FBSDVMCORE + +ProcessFreeBSDKernelFVC::ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp, + ListenerSP listener_sp, + fvc_t *fvc) + : ProcessFreeBSDKernel(target_sp, listener_sp), m_fvc(fvc) {} + +ProcessFreeBSDKernelFVC::~ProcessFreeBSDKernelFVC() { + if (m_fvc) + fvc_close(m_fvc); +} + +size_t ProcessFreeBSDKernelFVC::DoReadMemory(lldb::addr_t addr, void *buf, + size_t size, Status &error) { + ssize_t rd = 0; + rd = fvc_read(m_fvc, addr, buf, size); if (rd < 0 || static_cast(rd) != size) { - error.SetErrorStringWithFormat("Reading memory failed: %s", - fvc_geterr(static_cast(m_fvc))); + error.SetErrorStringWithFormat("Reading memory failed: %s", GetError()); 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(); +const char *ProcessFreeBSDKernelFVC::GetError() { return fvc_geterr(m_fvc); } + +#endif // LLDB_ENABLE_FBSDVMCORE + +#if defined(__FreeBSD__) + +ProcessFreeBSDKernelKVM::ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp, + ListenerSP listener_sp, + kvm_t *fvc) + : ProcessFreeBSDKernel(target_sp, listener_sp), m_kvm(fvc) {} + +ProcessFreeBSDKernelKVM::~ProcessFreeBSDKernelKVM() { + if (m_kvm) + kvm_close(m_kvm); } + +size_t ProcessFreeBSDKernelKVM::DoReadMemory(lldb::addr_t addr, void *buf, + size_t size, Status &error) { + ssize_t rd = 0; + rd = kvm_read2(m_kvm, addr, buf, size); + if (rd < 0 || static_cast(rd) != size) { + error.SetErrorStringWithFormat("Reading memory failed: %s", GetError()); + return rd > 0 ? rd : 0; + } + return rd; +} + +const char *ProcessFreeBSDKernelKVM::GetError() { return kvm_geterr(m_kvm); } + +#endif // defined(__FreeBSD__) diff --git a/lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelLive.py b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelLive.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelLive.py @@ -0,0 +1,44 @@ +import os +import struct +import subprocess + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class FreeBSDKernelVMCoreTestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + mydir = TestBase.compute_mydir(__file__) + + def test_mem(self): + kernel_exec = "/boot/kernel/kernel" + mem_device = "/dev/mem" + + if not os.access(kernel_exec, os.R_OK): + self.skipTest("Kernel @ %s is not readable" % (kernel_exec,)) + if not os.access(mem_device, os.R_OK): + self.skipTest("Memory @ %s is not readable" % (mem_device,)) + + target = self.dbg.CreateTarget(kernel_exec) + process = target.LoadCore(mem_device) + hz_value = int(subprocess.check_output(["sysctl", "-n", "kern.hz"])) + + self.assertTrue(process, PROCESS_IS_VALID) + self.assertEqual(process.GetNumThreads(), 1) + self.assertEqual(process.GetProcessID(), 0) + + # test memory reading + self.expect("expr -- *(int *) &hz", + substrs=["(int) $0 = %d" % hz_value]) + + main_mod = target.GetModuleAtIndex(0) + hz_addr = (main_mod.FindSymbols("hz")[0].symbol.addr + .GetLoadAddress(target)) + error = lldb.SBError() + self.assertEqual(process.ReadMemory(hz_addr, 4, error), + struct.pack("