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