mgorny created this revision. mgorny added reviewers: labath, emaste, krytarowski. Herald added a subscriber: arichardson. mgorny requested review of this revision.
Introduce initial support for using libkvm on FreeBSD. The library can be used as an alternate implementation for processing kernel coredumps but it can also be used to access live kernel memory through specifying "/dev/mem" as the core file, i.e.: lldb --core /dev/mem /boot/kernel/kernel https://reviews.llvm.org/D116005 Files: lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h lldb/test/API/functionalities/postmortem/FreeBSDKernel/TestFreeBSDKernelLive.py
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("<I", hz_value)) + + self.dbg.DeleteTarget(target) 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 <fvc.h> +#endif +#if defined(__FreeBSD__) +#include <kvm.h> +#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<fvc_t *>(m_fvc)); + if (m_fvc) { + switch (m_core_provider) { +#if LLDB_ENABLE_FBSDVMCORE + case CoreProvider::fvc: + fvc_close(static_cast<fvc_t *>(m_fvc)); + break; +#endif +#if defined(__FreeBSD__) + case CoreProvider::kvm: + kvm_close(static_cast<kvm_t *>(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<ProcessFreeBSDKernel>( - 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<ProcessFreeBSDKernel>( + 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<fvc_t *>(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<fvc_t *>(m_fvc), addr, buf, size); + break; +#endif +#if defined(__FreeBSD__) + case CoreProvider::kvm: + rd = kvm_read2(static_cast<kvm_t *>(m_fvc), addr, buf, size); + break; +#endif + } if (rd < 0 || static_cast<size_t>(rd) != size) { - error.SetErrorStringWithFormat("Reading memory failed: %s", - fvc_geterr(static_cast<fvc_t *>(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<fvc_t *>(m_fvc)); +#endif +#if defined(__FreeBSD__) + case CoreProvider::kvm: + return kvm_geterr(static_cast<kvm_t *>(m_fvc)); +#endif + } +} 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 )
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits