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