Index: lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt =================================================================== --- lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt +++ 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 ) Index: lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h =================================================================== --- lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h +++ lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h @@ -13,8 +13,18 @@ class ProcessFreeBSDKernel : public lldb_private::PostMortemProcess { public: + enum class CoreProvider { +#if LLDB_ENABLE_FBSDVMCORE + fvc, +#endif +#if defined(__FreeBSD__) + kvm, +#endif + }; + ProcessFreeBSDKernel(lldb::TargetSP target_sp, lldb::ListenerSP listener, - const lldb_private::FileSpec &core_file, void *fvc); + const lldb_private::FileSpec &core_file, void *fvc, + CoreProvider core_provider); ~ProcessFreeBSDKernel() override; @@ -55,6 +65,9 @@ private: void *m_fvc; + CoreProvider m_core_provider; + + const char *GetError(); }; #endif // LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_PROCESSFREEBSDKERNEL_H Index: lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp =================================================================== --- lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp +++ lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp @@ -10,11 +10,16 @@ #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; @@ -23,12 +28,26 @@ ProcessFreeBSDKernel::ProcessFreeBSDKernel(lldb::TargetSP target_sp, ListenerSP listener_sp, - const FileSpec &core_file, void *fvc) - : PostMortemProcess(target_sp, listener_sp), m_fvc(fvc) {} + const FileSpec &core_file, void *fvc, + CoreProvider core_provider) + : PostMortemProcess(target_sp, listener_sp), m_fvc(fvc), + m_core_provider(core_provider) {} ProcessFreeBSDKernel::~ProcessFreeBSDKernel() { - if (m_fvc) - fvc_close(static_cast(m_fvc)); + if (m_fvc) { + switch (m_core_provider) { +#if LLDB_ENABLE_FBSDVMCORE + case CoreProvider::fvc: + fvc_close(static_cast(m_fvc)); + break; +#endif +#if defined(__FreeBSD__) + case CoreProvider::kvm: + kvm_close(static_cast(m_fvc)); + break; +#endif + } + } } lldb::ProcessSP ProcessFreeBSDKernel::CreateInstance(lldb::TargetSP target_sp, @@ -38,12 +57,23 @@ 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); + target_sp, listener_sp, *crash_file, fvc, CoreProvider::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) + process_sp = std::make_shared( + target_sp, listener_sp, *crash_file, kvm, CoreProvider::kvm); +#endif } return process_sp; } @@ -109,10 +139,21 @@ 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); + ssize_t rd = 0; + switch (m_core_provider) { +#if LLDB_ENABLE_FBSDVMCORE + case CoreProvider::fvc: + rd = fvc_read(static_cast(m_fvc), addr, buf, size); + break; +#endif +#if defined(__FreeBSD__) + case CoreProvider::kvm: + rd = kvm_read2(static_cast(m_fvc), addr, buf, size); + break; +#endif + } 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; @@ -124,3 +165,16 @@ this, DynamicLoaderStatic::GetPluginNameStatic())); return m_dyld_up.get(); } + +const char *ProcessFreeBSDKernel::GetError() { + switch (m_core_provider) { +#if LLDB_ENABLE_FBSDVMCORE + case CoreProvider::fvc: + return fvc_geterr(static_cast(m_fvc)); +#endif +#if defined(__FreeBSD__) + case CoreProvider::kvm: + return kvm_geterr(static_cast(m_fvc)); +#endif + } +} Index: lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelLive.py =================================================================== --- /dev/null +++ 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("