xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Process/OpenBSDKernel/ProcessOpenBSDKernel.cpp (revision 513cf72f82c16dd38f89b0e7a0ec4a163d87f81f)
1 //===-- ProcessOpenBSDKernel.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 "ProcessOpenBSDKernel.h"
15 #include "ThreadOpenBSDKernel.h"
16 
17 #if defined(__OpenBSD__)
18 #include <kvm.h>
19 #define _KERNEL
20 #include <machine/cpu.h>
21 #include <sys/proc.h>
22 #undef _KERNEL
23 #endif
24 
25 using namespace lldb;
26 using namespace lldb_private;
27 
28 LLDB_PLUGIN_DEFINE(ProcessOpenBSDKernel)
29 
30 namespace {
31 
32 #if defined(__OpenBSD__)
33 class ProcessOpenBSDKernelKVM : public ProcessOpenBSDKernel {
34 public:
35   ProcessOpenBSDKernelKVM(lldb::TargetSP target_sp, lldb::ListenerSP listener,
36 			  kvm_t *fvc);
37 
38   ~ProcessOpenBSDKernelKVM();
39 
40   size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
41 		      lldb_private::Status &error) override;
42 
43 private:
44   kvm_t *m_kvm;
45 
46   const char *GetError();
47 };
48 #endif // defined(__OpenBSD__)
49 
50 } // namespace
51 
52 ProcessOpenBSDKernel::ProcessOpenBSDKernel(lldb::TargetSP target_sp,
53 					   ListenerSP listener_sp)
54     : PostMortemProcess(target_sp, listener_sp) {}
55 
56 lldb::ProcessSP ProcessOpenBSDKernel::CreateInstance(lldb::TargetSP target_sp,
57 						     ListenerSP listener_sp,
58 						     const FileSpec *crash_file,
59 						     bool can_connect) {
60   ModuleSP executable = target_sp->GetExecutableModule();
61   if (crash_file && !can_connect && executable) {
62 #if defined(__OpenBSD__)
63     kvm_t *kvm =
64 	kvm_open(executable->GetFileSpec().GetPath().c_str(),
65 		 crash_file->GetPath().c_str(), nullptr, O_RDONLY, nullptr);
66     if (kvm)
67       return std::make_shared<ProcessOpenBSDKernelKVM>(target_sp, listener_sp,
68 						       kvm);
69 #endif
70   }
71   return nullptr;
72 }
73 
74 void ProcessOpenBSDKernel::Initialize() {
75   static llvm::once_flag g_once_flag;
76 
77   llvm::call_once(g_once_flag, []() {
78     PluginManager::RegisterPlugin(GetPluginNameStatic(),
79 				  GetPluginDescriptionStatic(), CreateInstance);
80   });
81 }
82 
83 void ProcessOpenBSDKernel::Terminate() {
84   PluginManager::UnregisterPlugin(ProcessOpenBSDKernel::CreateInstance);
85 }
86 
87 Status ProcessOpenBSDKernel::DoDestroy() { return Status(); }
88 
89 bool ProcessOpenBSDKernel::CanDebug(lldb::TargetSP target_sp,
90 				    bool plugin_specified_by_name) {
91   return true;
92 }
93 
94 void ProcessOpenBSDKernel::RefreshStateAfterStop() {}
95 
96 bool ProcessOpenBSDKernel::DoUpdateThreadList(ThreadList &old_thread_list,
97 					      ThreadList &new_thread_list) {
98   if (old_thread_list.GetSize(false) == 0) {
99     // Make up the thread the first time this is called so we can set our one
100     // and only core thread state up.
101 
102     // We cannot construct a thread without a register context as that crashes
103     // LLDB but we can construct a process without threads to provide minimal
104     // memory reading support.
105     switch (GetTarget().GetArchitecture().GetMachine()) {
106     case llvm::Triple::aarch64:
107     case llvm::Triple::x86:
108     case llvm::Triple::x86_64:
109       break;
110     default:
111       return false;
112     }
113 
114     Status error;
115     int32_t i;
116     lldb::addr_t dumppcb = FindSymbol("dumppcb");
117     uint32_t offset_p_list = offsetof(proc, p_list);
118     uint32_t offset_p_addr = offsetof(proc, p_addr);
119     uint32_t offset_p_tid = offsetof(proc, p_tid);
120     uint32_t offset_p_p = offsetof(proc, p_p);
121     uint32_t offset_ps_comm = offsetof(process, ps_comm);
122     uint32_t offset_ps_pid = offsetof(process, ps_pid);
123     uint32_t offset_ci_curproc = offsetof(cpu_info, ci_curproc);
124     char    comm[_MAXCOMLEN];
125 
126     int32_t ncpu = ReadSignedIntegerFromMemory(FindSymbol("ncpus"),
127 					       4, -1, error);
128     if (ncpu < 0)
129       return false;
130 
131     lldb::addr_t cpu_procs[ncpu];
132 
133     if (dumppcb != LLDB_INVALID_ADDRESS) {
134       std::string thread_desc = llvm::formatv("Crashed Thread");
135       ThreadSP thread_sp {
136 		new ThreadOpenBSDKernel(*this, 0, dumppcb, thread_desc)};
137 	new_thread_list.AddThread(thread_sp);
138     }
139 
140     lldb::addr_t cpu_info = FindSymbol("cpu_info");
141     lldb::addr_t cpu_info_array = (cpu_info == LLDB_INVALID_ADDRESS) ?
142       ReadPointerFromMemory(FindSymbol("cpu_info_list"), error) : cpu_info;
143     for (i = 0; i < ncpu ; i++) {
144       lldb::addr_t ci =
145 	ReadPointerFromMemory(cpu_info_array + sizeof(void*) * i, error);
146       cpu_procs[i] = ReadPointerFromMemory(ci + offset_ci_curproc, error);
147     }
148 
149     for (lldb::addr_t proc = ReadPointerFromMemory(FindSymbol("allproc"), error);
150 	 proc != 0 && proc != LLDB_INVALID_ADDRESS;
151 	 proc = ReadPointerFromMemory(proc + offset_p_list, error)) {
152 
153       lldb::tid_t tid = ReadSignedIntegerFromMemory(proc + offset_p_tid, 4, -1,
154 						    error);
155       lldb::addr_t process = ReadPointerFromMemory(proc + offset_p_p, error);
156       ReadMemory(process + offset_ps_comm, &comm, sizeof(comm), error);
157       u_int32_t pid = ReadSignedIntegerFromMemory(process + offset_ps_pid, 4,
158 						  -1, error);
159       lldb::addr_t p_addr = ReadPointerFromMemory(proc + offset_p_addr, error);
160       for (i = 0; i < ncpu; i++)
161 	if (cpu_procs[i] == proc)
162 	  break;
163       std::string thread_desc;
164       if (i == ncpu)
165 	thread_desc = llvm::formatv("(pid:{0}) {1}", pid, comm);
166       else
167 	thread_desc = llvm::formatv("(pid:{0}) {1} (cpu {2})", pid, comm, i);
168       ThreadSP thread_sp {
169 		new ThreadOpenBSDKernel(*this, tid, p_addr, thread_desc)};
170 	new_thread_list.AddThread(thread_sp);
171     }
172   } else {
173     const uint32_t num_threads = old_thread_list.GetSize(false);
174     for (uint32_t i = 0; i < num_threads; ++i)
175       new_thread_list.AddThread(old_thread_list.GetThreadAtIndex(i, false));
176   }
177   return new_thread_list.GetSize(false) > 0;
178 }
179 
180 Status ProcessOpenBSDKernel::DoLoadCore() {
181   // The core is already loaded by CreateInstance().
182   return Status();
183 }
184 
185 DynamicLoader *ProcessOpenBSDKernel::GetDynamicLoader() {
186   if (m_dyld_up.get() == nullptr)
187     m_dyld_up.reset(DynamicLoader::FindPlugin(
188 	this, DynamicLoaderStatic::GetPluginNameStatic()));
189   return m_dyld_up.get();
190 }
191 
192 lldb::addr_t ProcessOpenBSDKernel::FindSymbol(const char *name) {
193   ModuleSP mod_sp = GetTarget().GetExecutableModule();
194   const Symbol *sym = mod_sp->FindFirstSymbolWithNameAndType(ConstString(name));
195   return sym ? sym->GetLoadAddress(&GetTarget()) : LLDB_INVALID_ADDRESS;
196 }
197 
198 #if defined(__OpenBSD__)
199 
200 ProcessOpenBSDKernelKVM::ProcessOpenBSDKernelKVM(lldb::TargetSP target_sp,
201 						 ListenerSP listener_sp,
202 						 kvm_t *fvc)
203     : ProcessOpenBSDKernel(target_sp, listener_sp), m_kvm(fvc) {}
204 
205 ProcessOpenBSDKernelKVM::~ProcessOpenBSDKernelKVM() {
206   if (m_kvm)
207     kvm_close(m_kvm);
208 }
209 
210 size_t ProcessOpenBSDKernelKVM::DoReadMemory(lldb::addr_t addr, void *buf,
211 					     size_t size, Status &error) {
212   ssize_t rd = 0;
213   rd = kvm_read(m_kvm, addr, buf, size);
214   if (rd < 0 || static_cast<size_t>(rd) != size) {
215     error.SetErrorStringWithFormat("Reading memory failed: %s", GetError());
216     return rd > 0 ? rd : 0;
217   }
218   return rd;
219 }
220 
221 const char *ProcessOpenBSDKernelKVM::GetError() { return kvm_geterr(m_kvm); }
222 
223 #endif // defined(__OpenBSD__)
224