1*0eae32dcSDimitry Andric //===-- ProcessFreeBSDKernel.cpp ------------------------------------------===// 2*0eae32dcSDimitry Andric // 3*0eae32dcSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0eae32dcSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0eae32dcSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0eae32dcSDimitry Andric // 7*0eae32dcSDimitry Andric //===----------------------------------------------------------------------===// 8*0eae32dcSDimitry Andric 9*0eae32dcSDimitry Andric #include "lldb/Core/Module.h" 10*0eae32dcSDimitry Andric #include "lldb/Core/PluginManager.h" 11*0eae32dcSDimitry Andric #include "lldb/Target/DynamicLoader.h" 12*0eae32dcSDimitry Andric 13*0eae32dcSDimitry Andric #include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" 14*0eae32dcSDimitry Andric #include "ProcessFreeBSDKernel.h" 15*0eae32dcSDimitry Andric #include "ThreadFreeBSDKernel.h" 16*0eae32dcSDimitry Andric 17*0eae32dcSDimitry Andric #if LLDB_ENABLE_FBSDVMCORE 18*0eae32dcSDimitry Andric #include <fvc.h> 19*0eae32dcSDimitry Andric #endif 20*0eae32dcSDimitry Andric #if defined(__FreeBSD__) 21*0eae32dcSDimitry Andric #include <kvm.h> 22*0eae32dcSDimitry Andric #endif 23*0eae32dcSDimitry Andric 24*0eae32dcSDimitry Andric using namespace lldb; 25*0eae32dcSDimitry Andric using namespace lldb_private; 26*0eae32dcSDimitry Andric 27*0eae32dcSDimitry Andric LLDB_PLUGIN_DEFINE(ProcessFreeBSDKernel) 28*0eae32dcSDimitry Andric 29*0eae32dcSDimitry Andric namespace { 30*0eae32dcSDimitry Andric 31*0eae32dcSDimitry Andric #if LLDB_ENABLE_FBSDVMCORE 32*0eae32dcSDimitry Andric class ProcessFreeBSDKernelFVC : public ProcessFreeBSDKernel { 33*0eae32dcSDimitry Andric public: 34*0eae32dcSDimitry Andric ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp, lldb::ListenerSP listener, 35*0eae32dcSDimitry Andric fvc_t *fvc); 36*0eae32dcSDimitry Andric 37*0eae32dcSDimitry Andric ~ProcessFreeBSDKernelFVC(); 38*0eae32dcSDimitry Andric 39*0eae32dcSDimitry Andric size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, 40*0eae32dcSDimitry Andric lldb_private::Status &error) override; 41*0eae32dcSDimitry Andric 42*0eae32dcSDimitry Andric private: 43*0eae32dcSDimitry Andric fvc_t *m_fvc; 44*0eae32dcSDimitry Andric 45*0eae32dcSDimitry Andric const char *GetError(); 46*0eae32dcSDimitry Andric }; 47*0eae32dcSDimitry Andric #endif // LLDB_ENABLE_FBSDVMCORE 48*0eae32dcSDimitry Andric 49*0eae32dcSDimitry Andric #if defined(__FreeBSD__) 50*0eae32dcSDimitry Andric class ProcessFreeBSDKernelKVM : public ProcessFreeBSDKernel { 51*0eae32dcSDimitry Andric public: 52*0eae32dcSDimitry Andric ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp, lldb::ListenerSP listener, 53*0eae32dcSDimitry Andric kvm_t *fvc); 54*0eae32dcSDimitry Andric 55*0eae32dcSDimitry Andric ~ProcessFreeBSDKernelKVM(); 56*0eae32dcSDimitry Andric 57*0eae32dcSDimitry Andric size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, 58*0eae32dcSDimitry Andric lldb_private::Status &error) override; 59*0eae32dcSDimitry Andric 60*0eae32dcSDimitry Andric private: 61*0eae32dcSDimitry Andric kvm_t *m_kvm; 62*0eae32dcSDimitry Andric 63*0eae32dcSDimitry Andric const char *GetError(); 64*0eae32dcSDimitry Andric }; 65*0eae32dcSDimitry Andric #endif // defined(__FreeBSD__) 66*0eae32dcSDimitry Andric 67*0eae32dcSDimitry Andric } // namespace 68*0eae32dcSDimitry Andric 69*0eae32dcSDimitry Andric ProcessFreeBSDKernel::ProcessFreeBSDKernel(lldb::TargetSP target_sp, 70*0eae32dcSDimitry Andric ListenerSP listener_sp) 71*0eae32dcSDimitry Andric : PostMortemProcess(target_sp, listener_sp) {} 72*0eae32dcSDimitry Andric 73*0eae32dcSDimitry Andric lldb::ProcessSP ProcessFreeBSDKernel::CreateInstance(lldb::TargetSP target_sp, 74*0eae32dcSDimitry Andric ListenerSP listener_sp, 75*0eae32dcSDimitry Andric const FileSpec *crash_file, 76*0eae32dcSDimitry Andric bool can_connect) { 77*0eae32dcSDimitry Andric ModuleSP executable = target_sp->GetExecutableModule(); 78*0eae32dcSDimitry Andric if (crash_file && !can_connect && executable) { 79*0eae32dcSDimitry Andric #if LLDB_ENABLE_FBSDVMCORE 80*0eae32dcSDimitry Andric fvc_t *fvc = 81*0eae32dcSDimitry Andric fvc_open(executable->GetFileSpec().GetPath().c_str(), 82*0eae32dcSDimitry Andric crash_file->GetPath().c_str(), nullptr, nullptr, nullptr); 83*0eae32dcSDimitry Andric if (fvc) 84*0eae32dcSDimitry Andric return std::make_shared<ProcessFreeBSDKernelFVC>(target_sp, listener_sp, 85*0eae32dcSDimitry Andric fvc); 86*0eae32dcSDimitry Andric #endif 87*0eae32dcSDimitry Andric 88*0eae32dcSDimitry Andric #if defined(__FreeBSD__) 89*0eae32dcSDimitry Andric kvm_t *kvm = 90*0eae32dcSDimitry Andric kvm_open2(executable->GetFileSpec().GetPath().c_str(), 91*0eae32dcSDimitry Andric crash_file->GetPath().c_str(), O_RDONLY, nullptr, nullptr); 92*0eae32dcSDimitry Andric if (kvm) 93*0eae32dcSDimitry Andric return std::make_shared<ProcessFreeBSDKernelKVM>(target_sp, listener_sp, 94*0eae32dcSDimitry Andric kvm); 95*0eae32dcSDimitry Andric #endif 96*0eae32dcSDimitry Andric } 97*0eae32dcSDimitry Andric return nullptr; 98*0eae32dcSDimitry Andric } 99*0eae32dcSDimitry Andric 100*0eae32dcSDimitry Andric void ProcessFreeBSDKernel::Initialize() { 101*0eae32dcSDimitry Andric static llvm::once_flag g_once_flag; 102*0eae32dcSDimitry Andric 103*0eae32dcSDimitry Andric llvm::call_once(g_once_flag, []() { 104*0eae32dcSDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(), 105*0eae32dcSDimitry Andric GetPluginDescriptionStatic(), CreateInstance); 106*0eae32dcSDimitry Andric }); 107*0eae32dcSDimitry Andric } 108*0eae32dcSDimitry Andric 109*0eae32dcSDimitry Andric void ProcessFreeBSDKernel::Terminate() { 110*0eae32dcSDimitry Andric PluginManager::UnregisterPlugin(ProcessFreeBSDKernel::CreateInstance); 111*0eae32dcSDimitry Andric } 112*0eae32dcSDimitry Andric 113*0eae32dcSDimitry Andric Status ProcessFreeBSDKernel::DoDestroy() { return Status(); } 114*0eae32dcSDimitry Andric 115*0eae32dcSDimitry Andric bool ProcessFreeBSDKernel::CanDebug(lldb::TargetSP target_sp, 116*0eae32dcSDimitry Andric bool plugin_specified_by_name) { 117*0eae32dcSDimitry Andric return true; 118*0eae32dcSDimitry Andric } 119*0eae32dcSDimitry Andric 120*0eae32dcSDimitry Andric void ProcessFreeBSDKernel::RefreshStateAfterStop() {} 121*0eae32dcSDimitry Andric 122*0eae32dcSDimitry Andric bool ProcessFreeBSDKernel::DoUpdateThreadList(ThreadList &old_thread_list, 123*0eae32dcSDimitry Andric ThreadList &new_thread_list) { 124*0eae32dcSDimitry Andric if (old_thread_list.GetSize(false) == 0) { 125*0eae32dcSDimitry Andric // Make up the thread the first time this is called so we can set our one 126*0eae32dcSDimitry Andric // and only core thread state up. 127*0eae32dcSDimitry Andric 128*0eae32dcSDimitry Andric // We cannot construct a thread without a register context as that crashes 129*0eae32dcSDimitry Andric // LLDB but we can construct a process without threads to provide minimal 130*0eae32dcSDimitry Andric // memory reading support. 131*0eae32dcSDimitry Andric switch (GetTarget().GetArchitecture().GetMachine()) { 132*0eae32dcSDimitry Andric case llvm::Triple::aarch64: 133*0eae32dcSDimitry Andric case llvm::Triple::x86: 134*0eae32dcSDimitry Andric case llvm::Triple::x86_64: 135*0eae32dcSDimitry Andric break; 136*0eae32dcSDimitry Andric default: 137*0eae32dcSDimitry Andric return false; 138*0eae32dcSDimitry Andric } 139*0eae32dcSDimitry Andric 140*0eae32dcSDimitry Andric const Symbol *pcb_sym = 141*0eae32dcSDimitry Andric GetTarget().GetExecutableModule()->FindFirstSymbolWithNameAndType( 142*0eae32dcSDimitry Andric ConstString("dumppcb")); 143*0eae32dcSDimitry Andric ThreadSP thread_sp(new ThreadFreeBSDKernel( 144*0eae32dcSDimitry Andric *this, 1, pcb_sym ? pcb_sym->GetFileAddress() : LLDB_INVALID_ADDRESS)); 145*0eae32dcSDimitry Andric new_thread_list.AddThread(thread_sp); 146*0eae32dcSDimitry Andric } else { 147*0eae32dcSDimitry Andric const uint32_t num_threads = old_thread_list.GetSize(false); 148*0eae32dcSDimitry Andric for (uint32_t i = 0; i < num_threads; ++i) 149*0eae32dcSDimitry Andric new_thread_list.AddThread(old_thread_list.GetThreadAtIndex(i, false)); 150*0eae32dcSDimitry Andric } 151*0eae32dcSDimitry Andric return new_thread_list.GetSize(false) > 0; 152*0eae32dcSDimitry Andric } 153*0eae32dcSDimitry Andric 154*0eae32dcSDimitry Andric Status ProcessFreeBSDKernel::DoLoadCore() { 155*0eae32dcSDimitry Andric // The core is already loaded by CreateInstance(). 156*0eae32dcSDimitry Andric return Status(); 157*0eae32dcSDimitry Andric } 158*0eae32dcSDimitry Andric 159*0eae32dcSDimitry Andric DynamicLoader *ProcessFreeBSDKernel::GetDynamicLoader() { 160*0eae32dcSDimitry Andric if (m_dyld_up.get() == nullptr) 161*0eae32dcSDimitry Andric m_dyld_up.reset(DynamicLoader::FindPlugin( 162*0eae32dcSDimitry Andric this, DynamicLoaderStatic::GetPluginNameStatic())); 163*0eae32dcSDimitry Andric return m_dyld_up.get(); 164*0eae32dcSDimitry Andric } 165*0eae32dcSDimitry Andric 166*0eae32dcSDimitry Andric #if LLDB_ENABLE_FBSDVMCORE 167*0eae32dcSDimitry Andric 168*0eae32dcSDimitry Andric ProcessFreeBSDKernelFVC::ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp, 169*0eae32dcSDimitry Andric ListenerSP listener_sp, 170*0eae32dcSDimitry Andric fvc_t *fvc) 171*0eae32dcSDimitry Andric : ProcessFreeBSDKernel(target_sp, listener_sp), m_fvc(fvc) {} 172*0eae32dcSDimitry Andric 173*0eae32dcSDimitry Andric ProcessFreeBSDKernelFVC::~ProcessFreeBSDKernelFVC() { 174*0eae32dcSDimitry Andric if (m_fvc) 175*0eae32dcSDimitry Andric fvc_close(m_fvc); 176*0eae32dcSDimitry Andric } 177*0eae32dcSDimitry Andric 178*0eae32dcSDimitry Andric size_t ProcessFreeBSDKernelFVC::DoReadMemory(lldb::addr_t addr, void *buf, 179*0eae32dcSDimitry Andric size_t size, Status &error) { 180*0eae32dcSDimitry Andric ssize_t rd = 0; 181*0eae32dcSDimitry Andric rd = fvc_read(m_fvc, addr, buf, size); 182*0eae32dcSDimitry Andric if (rd < 0 || static_cast<size_t>(rd) != size) { 183*0eae32dcSDimitry Andric error.SetErrorStringWithFormat("Reading memory failed: %s", GetError()); 184*0eae32dcSDimitry Andric return rd > 0 ? rd : 0; 185*0eae32dcSDimitry Andric } 186*0eae32dcSDimitry Andric return rd; 187*0eae32dcSDimitry Andric } 188*0eae32dcSDimitry Andric 189*0eae32dcSDimitry Andric const char *ProcessFreeBSDKernelFVC::GetError() { return fvc_geterr(m_fvc); } 190*0eae32dcSDimitry Andric 191*0eae32dcSDimitry Andric #endif // LLDB_ENABLE_FBSDVMCORE 192*0eae32dcSDimitry Andric 193*0eae32dcSDimitry Andric #if defined(__FreeBSD__) 194*0eae32dcSDimitry Andric 195*0eae32dcSDimitry Andric ProcessFreeBSDKernelKVM::ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp, 196*0eae32dcSDimitry Andric ListenerSP listener_sp, 197*0eae32dcSDimitry Andric kvm_t *fvc) 198*0eae32dcSDimitry Andric : ProcessFreeBSDKernel(target_sp, listener_sp), m_kvm(fvc) {} 199*0eae32dcSDimitry Andric 200*0eae32dcSDimitry Andric ProcessFreeBSDKernelKVM::~ProcessFreeBSDKernelKVM() { 201*0eae32dcSDimitry Andric if (m_kvm) 202*0eae32dcSDimitry Andric kvm_close(m_kvm); 203*0eae32dcSDimitry Andric } 204*0eae32dcSDimitry Andric 205*0eae32dcSDimitry Andric size_t ProcessFreeBSDKernelKVM::DoReadMemory(lldb::addr_t addr, void *buf, 206*0eae32dcSDimitry Andric size_t size, Status &error) { 207*0eae32dcSDimitry Andric ssize_t rd = 0; 208*0eae32dcSDimitry Andric rd = kvm_read2(m_kvm, addr, buf, size); 209*0eae32dcSDimitry Andric if (rd < 0 || static_cast<size_t>(rd) != size) { 210*0eae32dcSDimitry Andric error.SetErrorStringWithFormat("Reading memory failed: %s", GetError()); 211*0eae32dcSDimitry Andric return rd > 0 ? rd : 0; 212*0eae32dcSDimitry Andric } 213*0eae32dcSDimitry Andric return rd; 214*0eae32dcSDimitry Andric } 215*0eae32dcSDimitry Andric 216*0eae32dcSDimitry Andric const char *ProcessFreeBSDKernelKVM::GetError() { return kvm_geterr(m_kvm); } 217*0eae32dcSDimitry Andric 218*0eae32dcSDimitry Andric #endif // defined(__FreeBSD__) 219