19c7fbc3fSMichał Górny //===-- ProcessFreeBSDKernel.cpp ------------------------------------------===// 29c7fbc3fSMichał Górny // 39c7fbc3fSMichał Górny // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 49c7fbc3fSMichał Górny // See https://llvm.org/LICENSE.txt for license information. 59c7fbc3fSMichał Górny // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 69c7fbc3fSMichał Górny // 79c7fbc3fSMichał Górny //===----------------------------------------------------------------------===// 89c7fbc3fSMichał Górny 99c7fbc3fSMichał Górny #include "lldb/Core/Module.h" 109c7fbc3fSMichał Górny #include "lldb/Core/PluginManager.h" 119c7fbc3fSMichał Górny #include "lldb/Target/DynamicLoader.h" 129c7fbc3fSMichał Górny 13*fb785877SMichał Górny #include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" 149c7fbc3fSMichał Górny #include "ProcessFreeBSDKernel.h" 159c7fbc3fSMichał Górny #include "ThreadFreeBSDKernel.h" 169c7fbc3fSMichał Górny 17*fb785877SMichał Górny #if LLDB_ENABLE_FBSDVMCORE 189c7fbc3fSMichał Górny #include <fvc.h> 19*fb785877SMichał Górny #endif 20*fb785877SMichał Górny #if defined(__FreeBSD__) 21*fb785877SMichał Górny #include <kvm.h> 22*fb785877SMichał Górny #endif 239c7fbc3fSMichał Górny 249c7fbc3fSMichał Górny using namespace lldb; 259c7fbc3fSMichał Górny using namespace lldb_private; 269c7fbc3fSMichał Górny 279c7fbc3fSMichał Górny LLDB_PLUGIN_DEFINE(ProcessFreeBSDKernel) 289c7fbc3fSMichał Górny 29*fb785877SMichał Górny namespace { 309c7fbc3fSMichał Górny 31*fb785877SMichał Górny #if LLDB_ENABLE_FBSDVMCORE 32*fb785877SMichał Górny class ProcessFreeBSDKernelFVC : public ProcessFreeBSDKernel { 33*fb785877SMichał Górny public: 34*fb785877SMichał Górny ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp, lldb::ListenerSP listener, 35*fb785877SMichał Górny fvc_t *fvc); 36*fb785877SMichał Górny 37*fb785877SMichał Górny ~ProcessFreeBSDKernelFVC(); 38*fb785877SMichał Górny 39*fb785877SMichał Górny size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, 40*fb785877SMichał Górny lldb_private::Status &error) override; 41*fb785877SMichał Górny 42*fb785877SMichał Górny private: 43*fb785877SMichał Górny fvc_t *m_fvc; 44*fb785877SMichał Górny 45*fb785877SMichał Górny const char *GetError(); 46*fb785877SMichał Górny }; 47*fb785877SMichał Górny #endif // LLDB_ENABLE_FBSDVMCORE 48*fb785877SMichał Górny 49*fb785877SMichał Górny #if defined(__FreeBSD__) 50*fb785877SMichał Górny class ProcessFreeBSDKernelKVM : public ProcessFreeBSDKernel { 51*fb785877SMichał Górny public: 52*fb785877SMichał Górny ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp, lldb::ListenerSP listener, 53*fb785877SMichał Górny kvm_t *fvc); 54*fb785877SMichał Górny 55*fb785877SMichał Górny ~ProcessFreeBSDKernelKVM(); 56*fb785877SMichał Górny 57*fb785877SMichał Górny size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, 58*fb785877SMichał Górny lldb_private::Status &error) override; 59*fb785877SMichał Górny 60*fb785877SMichał Górny private: 61*fb785877SMichał Górny kvm_t *m_kvm; 62*fb785877SMichał Górny 63*fb785877SMichał Górny const char *GetError(); 64*fb785877SMichał Górny }; 65*fb785877SMichał Górny #endif // defined(__FreeBSD__) 66*fb785877SMichał Górny 67*fb785877SMichał Górny } // namespace 68*fb785877SMichał Górny 69*fb785877SMichał Górny ProcessFreeBSDKernel::ProcessFreeBSDKernel(lldb::TargetSP target_sp, 70*fb785877SMichał Górny ListenerSP listener_sp) 71*fb785877SMichał Górny : PostMortemProcess(target_sp, listener_sp) {} 729c7fbc3fSMichał Górny 739c7fbc3fSMichał Górny lldb::ProcessSP ProcessFreeBSDKernel::CreateInstance(lldb::TargetSP target_sp, 749c7fbc3fSMichał Górny ListenerSP listener_sp, 759c7fbc3fSMichał Górny const FileSpec *crash_file, 769c7fbc3fSMichał Górny bool can_connect) { 779c7fbc3fSMichał Górny ModuleSP executable = target_sp->GetExecutableModule(); 789c7fbc3fSMichał Górny if (crash_file && !can_connect && executable) { 79*fb785877SMichał Górny #if LLDB_ENABLE_FBSDVMCORE 80*fb785877SMichał Górny fvc_t *fvc = 81*fb785877SMichał Górny fvc_open(executable->GetFileSpec().GetPath().c_str(), 829c7fbc3fSMichał Górny crash_file->GetPath().c_str(), nullptr, nullptr, nullptr); 839c7fbc3fSMichał Górny if (fvc) 84*fb785877SMichał Górny return std::make_shared<ProcessFreeBSDKernelFVC>(target_sp, listener_sp, 85*fb785877SMichał Górny fvc); 86*fb785877SMichał Górny #endif 87*fb785877SMichał Górny 88*fb785877SMichał Górny #if defined(__FreeBSD__) 89*fb785877SMichał Górny kvm_t *kvm = 90*fb785877SMichał Górny kvm_open2(executable->GetFileSpec().GetPath().c_str(), 91*fb785877SMichał Górny crash_file->GetPath().c_str(), O_RDONLY, nullptr, nullptr); 92*fb785877SMichał Górny if (kvm) 93*fb785877SMichał Górny return std::make_shared<ProcessFreeBSDKernelKVM>(target_sp, listener_sp, 94*fb785877SMichał Górny kvm); 95*fb785877SMichał Górny #endif 969c7fbc3fSMichał Górny } 97*fb785877SMichał Górny return nullptr; 989c7fbc3fSMichał Górny } 999c7fbc3fSMichał Górny 1009c7fbc3fSMichał Górny void ProcessFreeBSDKernel::Initialize() { 1019c7fbc3fSMichał Górny static llvm::once_flag g_once_flag; 1029c7fbc3fSMichał Górny 1039c7fbc3fSMichał Górny llvm::call_once(g_once_flag, []() { 1049c7fbc3fSMichał Górny PluginManager::RegisterPlugin(GetPluginNameStatic(), 1059c7fbc3fSMichał Górny GetPluginDescriptionStatic(), CreateInstance); 1069c7fbc3fSMichał Górny }); 1079c7fbc3fSMichał Górny } 1089c7fbc3fSMichał Górny 1099c7fbc3fSMichał Górny void ProcessFreeBSDKernel::Terminate() { 1109c7fbc3fSMichał Górny PluginManager::UnregisterPlugin(ProcessFreeBSDKernel::CreateInstance); 1119c7fbc3fSMichał Górny } 1129c7fbc3fSMichał Górny 1139c7fbc3fSMichał Górny Status ProcessFreeBSDKernel::DoDestroy() { return Status(); } 1149c7fbc3fSMichał Górny 1159c7fbc3fSMichał Górny bool ProcessFreeBSDKernel::CanDebug(lldb::TargetSP target_sp, 1169c7fbc3fSMichał Górny bool plugin_specified_by_name) { 1179c7fbc3fSMichał Górny return true; 1189c7fbc3fSMichał Górny } 1199c7fbc3fSMichał Górny 1209c7fbc3fSMichał Górny void ProcessFreeBSDKernel::RefreshStateAfterStop() {} 1219c7fbc3fSMichał Górny 1229c7fbc3fSMichał Górny bool ProcessFreeBSDKernel::DoUpdateThreadList(ThreadList &old_thread_list, 1239c7fbc3fSMichał Górny ThreadList &new_thread_list) { 1249c7fbc3fSMichał Górny if (old_thread_list.GetSize(false) == 0) { 1259c7fbc3fSMichał Górny // Make up the thread the first time this is called so we can set our one 1269c7fbc3fSMichał Górny // and only core thread state up. 1279c7fbc3fSMichał Górny 1289c7fbc3fSMichał Górny // We cannot construct a thread without a register context as that crashes 1299c7fbc3fSMichał Górny // LLDB but we can construct a process without threads to provide minimal 1309c7fbc3fSMichał Górny // memory reading support. 1319c7fbc3fSMichał Górny switch (GetTarget().GetArchitecture().GetMachine()) { 1329c7fbc3fSMichał Górny case llvm::Triple::aarch64: 1339c7fbc3fSMichał Górny case llvm::Triple::x86: 1349c7fbc3fSMichał Górny case llvm::Triple::x86_64: 1359c7fbc3fSMichał Górny break; 1369c7fbc3fSMichał Górny default: 1379c7fbc3fSMichał Górny return false; 1389c7fbc3fSMichał Górny } 1399c7fbc3fSMichał Górny 1409c7fbc3fSMichał Górny const Symbol *pcb_sym = 1419c7fbc3fSMichał Górny GetTarget().GetExecutableModule()->FindFirstSymbolWithNameAndType( 1429c7fbc3fSMichał Górny ConstString("dumppcb")); 1439c7fbc3fSMichał Górny ThreadSP thread_sp(new ThreadFreeBSDKernel( 1449c7fbc3fSMichał Górny *this, 1, pcb_sym ? pcb_sym->GetFileAddress() : LLDB_INVALID_ADDRESS)); 1459c7fbc3fSMichał Górny new_thread_list.AddThread(thread_sp); 1469c7fbc3fSMichał Górny } else { 1479c7fbc3fSMichał Górny const uint32_t num_threads = old_thread_list.GetSize(false); 1489c7fbc3fSMichał Górny for (uint32_t i = 0; i < num_threads; ++i) 1499c7fbc3fSMichał Górny new_thread_list.AddThread(old_thread_list.GetThreadAtIndex(i, false)); 1509c7fbc3fSMichał Górny } 1519c7fbc3fSMichał Górny return new_thread_list.GetSize(false) > 0; 1529c7fbc3fSMichał Górny } 1539c7fbc3fSMichał Górny 1549c7fbc3fSMichał Górny Status ProcessFreeBSDKernel::DoLoadCore() { 1559c7fbc3fSMichał Górny // The core is already loaded by CreateInstance(). 1569c7fbc3fSMichał Górny return Status(); 1579c7fbc3fSMichał Górny } 1589c7fbc3fSMichał Górny 1599c7fbc3fSMichał Górny DynamicLoader *ProcessFreeBSDKernel::GetDynamicLoader() { 1609c7fbc3fSMichał Górny if (m_dyld_up.get() == nullptr) 1619c7fbc3fSMichał Górny m_dyld_up.reset(DynamicLoader::FindPlugin( 1629c7fbc3fSMichał Górny this, DynamicLoaderStatic::GetPluginNameStatic())); 1639c7fbc3fSMichał Górny return m_dyld_up.get(); 1649c7fbc3fSMichał Górny } 165*fb785877SMichał Górny 166*fb785877SMichał Górny #if LLDB_ENABLE_FBSDVMCORE 167*fb785877SMichał Górny 168*fb785877SMichał Górny ProcessFreeBSDKernelFVC::ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp, 169*fb785877SMichał Górny ListenerSP listener_sp, 170*fb785877SMichał Górny fvc_t *fvc) 171*fb785877SMichał Górny : ProcessFreeBSDKernel(target_sp, listener_sp), m_fvc(fvc) {} 172*fb785877SMichał Górny 173*fb785877SMichał Górny ProcessFreeBSDKernelFVC::~ProcessFreeBSDKernelFVC() { 174*fb785877SMichał Górny if (m_fvc) 175*fb785877SMichał Górny fvc_close(m_fvc); 176*fb785877SMichał Górny } 177*fb785877SMichał Górny 178*fb785877SMichał Górny size_t ProcessFreeBSDKernelFVC::DoReadMemory(lldb::addr_t addr, void *buf, 179*fb785877SMichał Górny size_t size, Status &error) { 180*fb785877SMichał Górny ssize_t rd = 0; 181*fb785877SMichał Górny rd = fvc_read(m_fvc, addr, buf, size); 182*fb785877SMichał Górny if (rd < 0 || static_cast<size_t>(rd) != size) { 183*fb785877SMichał Górny error.SetErrorStringWithFormat("Reading memory failed: %s", GetError()); 184*fb785877SMichał Górny return rd > 0 ? rd : 0; 185*fb785877SMichał Górny } 186*fb785877SMichał Górny return rd; 187*fb785877SMichał Górny } 188*fb785877SMichał Górny 189*fb785877SMichał Górny const char *ProcessFreeBSDKernelFVC::GetError() { return fvc_geterr(m_fvc); } 190*fb785877SMichał Górny 191*fb785877SMichał Górny #endif // LLDB_ENABLE_FBSDVMCORE 192*fb785877SMichał Górny 193*fb785877SMichał Górny #if defined(__FreeBSD__) 194*fb785877SMichał Górny 195*fb785877SMichał Górny ProcessFreeBSDKernelKVM::ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp, 196*fb785877SMichał Górny ListenerSP listener_sp, 197*fb785877SMichał Górny kvm_t *fvc) 198*fb785877SMichał Górny : ProcessFreeBSDKernel(target_sp, listener_sp), m_kvm(fvc) {} 199*fb785877SMichał Górny 200*fb785877SMichał Górny ProcessFreeBSDKernelKVM::~ProcessFreeBSDKernelKVM() { 201*fb785877SMichał Górny if (m_kvm) 202*fb785877SMichał Górny kvm_close(m_kvm); 203*fb785877SMichał Górny } 204*fb785877SMichał Górny 205*fb785877SMichał Górny size_t ProcessFreeBSDKernelKVM::DoReadMemory(lldb::addr_t addr, void *buf, 206*fb785877SMichał Górny size_t size, Status &error) { 207*fb785877SMichał Górny ssize_t rd = 0; 208*fb785877SMichał Górny rd = kvm_read2(m_kvm, addr, buf, size); 209*fb785877SMichał Górny if (rd < 0 || static_cast<size_t>(rd) != size) { 210*fb785877SMichał Górny error.SetErrorStringWithFormat("Reading memory failed: %s", GetError()); 211*fb785877SMichał Górny return rd > 0 ? rd : 0; 212*fb785877SMichał Górny } 213*fb785877SMichał Górny return rd; 214*fb785877SMichał Górny } 215*fb785877SMichał Górny 216*fb785877SMichał Górny const char *ProcessFreeBSDKernelKVM::GetError() { return kvm_geterr(m_kvm); } 217*fb785877SMichał Górny 218*fb785877SMichał Górny #endif // defined(__FreeBSD__) 219