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