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 "ProcessFreeBSDKernel.h" 14 #include "ThreadFreeBSDKernel.h" 15 #include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" 16 17 #include <fvc.h> 18 19 using namespace lldb; 20 using namespace lldb_private; 21 22 LLDB_PLUGIN_DEFINE(ProcessFreeBSDKernel) 23 24 ProcessFreeBSDKernel::ProcessFreeBSDKernel(lldb::TargetSP target_sp, 25 ListenerSP listener_sp, 26 const FileSpec &core_file, void *fvc) 27 : PostMortemProcess(target_sp, listener_sp), m_fvc(fvc) {} 28 29 ProcessFreeBSDKernel::~ProcessFreeBSDKernel() { 30 if (m_fvc) 31 fvc_close(static_cast<fvc_t *>(m_fvc)); 32 } 33 34 lldb::ProcessSP ProcessFreeBSDKernel::CreateInstance(lldb::TargetSP target_sp, 35 ListenerSP listener_sp, 36 const FileSpec *crash_file, 37 bool can_connect) { 38 lldb::ProcessSP process_sp; 39 ModuleSP executable = target_sp->GetExecutableModule(); 40 if (crash_file && !can_connect && executable) { 41 fvc_t *fvc = fvc_open( 42 executable->GetFileSpec().GetPath().c_str(), 43 crash_file->GetPath().c_str(), nullptr, nullptr, nullptr); 44 if (fvc) 45 process_sp = std::make_shared<ProcessFreeBSDKernel>( 46 target_sp, listener_sp, *crash_file, fvc); 47 } 48 return process_sp; 49 } 50 51 void ProcessFreeBSDKernel::Initialize() { 52 static llvm::once_flag g_once_flag; 53 54 llvm::call_once(g_once_flag, []() { 55 PluginManager::RegisterPlugin(GetPluginNameStatic(), 56 GetPluginDescriptionStatic(), CreateInstance); 57 }); 58 } 59 60 void ProcessFreeBSDKernel::Terminate() { 61 PluginManager::UnregisterPlugin(ProcessFreeBSDKernel::CreateInstance); 62 } 63 64 Status ProcessFreeBSDKernel::DoDestroy() { return Status(); } 65 66 bool ProcessFreeBSDKernel::CanDebug(lldb::TargetSP target_sp, 67 bool plugin_specified_by_name) { 68 return true; 69 } 70 71 void ProcessFreeBSDKernel::RefreshStateAfterStop() {} 72 73 bool ProcessFreeBSDKernel::DoUpdateThreadList(ThreadList &old_thread_list, 74 ThreadList &new_thread_list) { 75 if (old_thread_list.GetSize(false) == 0) { 76 // Make up the thread the first time this is called so we can set our one 77 // and only core thread state up. 78 79 // We cannot construct a thread without a register context as that crashes 80 // LLDB but we can construct a process without threads to provide minimal 81 // memory reading support. 82 switch (GetTarget().GetArchitecture().GetMachine()) { 83 case llvm::Triple::aarch64: 84 case llvm::Triple::x86: 85 case llvm::Triple::x86_64: 86 break; 87 default: 88 return false; 89 } 90 91 const Symbol *pcb_sym = 92 GetTarget().GetExecutableModule()->FindFirstSymbolWithNameAndType( 93 ConstString("dumppcb")); 94 ThreadSP thread_sp(new ThreadFreeBSDKernel( 95 *this, 1, pcb_sym ? pcb_sym->GetFileAddress() : LLDB_INVALID_ADDRESS)); 96 new_thread_list.AddThread(thread_sp); 97 } else { 98 const uint32_t num_threads = old_thread_list.GetSize(false); 99 for (uint32_t i = 0; i < num_threads; ++i) 100 new_thread_list.AddThread(old_thread_list.GetThreadAtIndex(i, false)); 101 } 102 return new_thread_list.GetSize(false) > 0; 103 } 104 105 Status ProcessFreeBSDKernel::DoLoadCore() { 106 // The core is already loaded by CreateInstance(). 107 return Status(); 108 } 109 110 size_t ProcessFreeBSDKernel::DoReadMemory(lldb::addr_t addr, void *buf, 111 size_t size, Status &error) { 112 ssize_t rd = fvc_read(static_cast<fvc_t *>(m_fvc), addr, buf, size); 113 if (rd < 0 || static_cast<size_t>(rd) != size) { 114 error.SetErrorStringWithFormat("Reading memory failed: %s", 115 fvc_geterr(static_cast<fvc_t *>(m_fvc))); 116 return rd > 0 ? rd : 0; 117 } 118 return rd; 119 } 120 121 DynamicLoader *ProcessFreeBSDKernel::GetDynamicLoader() { 122 if (m_dyld_up.get() == nullptr) 123 m_dyld_up.reset(DynamicLoader::FindPlugin( 124 this, DynamicLoaderStatic::GetPluginNameStatic())); 125 return m_dyld_up.get(); 126 } 127