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