LLDB mainline
ProcessFreeBSDKernel.cpp
Go to the documentation of this file.
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"
12
15#include "ThreadFreeBSDKernel.h"
16
17#if LLDB_ENABLE_FBSDVMCORE
18#include <fvc.h>
19#endif
20#if defined(__FreeBSD__)
21#include <kvm.h>
22#endif
23
24using namespace lldb;
25using namespace lldb_private;
26
28
29namespace {
30
31#if LLDB_ENABLE_FBSDVMCORE
32class ProcessFreeBSDKernelFVC : public ProcessFreeBSDKernel {
33public:
34 ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp, lldb::ListenerSP listener,
35 fvc_t *fvc);
36
37 ~ProcessFreeBSDKernelFVC();
38
39 size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
40 lldb_private::Status &error) override;
41
42private:
43 fvc_t *m_fvc;
44
45 const char *GetError();
46};
47#endif // LLDB_ENABLE_FBSDVMCORE
48
49#if defined(__FreeBSD__)
50class ProcessFreeBSDKernelKVM : public ProcessFreeBSDKernel {
51public:
52 ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp, lldb::ListenerSP listener,
53 kvm_t *fvc);
54
55 ~ProcessFreeBSDKernelKVM();
56
57 size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
58 lldb_private::Status &error) override;
59
60private:
61 kvm_t *m_kvm;
62
63 const char *GetError();
64};
65#endif // defined(__FreeBSD__)
66
67} // namespace
68
70 ListenerSP listener_sp)
71 : PostMortemProcess(target_sp, listener_sp) {}
72
74 ListenerSP listener_sp,
75 const FileSpec *crash_file,
76 bool can_connect) {
77 ModuleSP executable = target_sp->GetExecutableModule();
78 if (crash_file && !can_connect && executable) {
79#if LLDB_ENABLE_FBSDVMCORE
80 fvc_t *fvc =
81 fvc_open(executable->GetFileSpec().GetPath().c_str(),
82 crash_file->GetPath().c_str(), nullptr, nullptr, nullptr);
83 if (fvc)
84 return std::make_shared<ProcessFreeBSDKernelFVC>(target_sp, listener_sp,
85 fvc);
86#endif
87
88#if defined(__FreeBSD__)
89 kvm_t *kvm =
90 kvm_open2(executable->GetFileSpec().GetPath().c_str(),
91 crash_file->GetPath().c_str(), O_RDONLY, nullptr, nullptr);
92 if (kvm)
93 return std::make_shared<ProcessFreeBSDKernelKVM>(target_sp, listener_sp,
94 kvm);
95#endif
96 }
97 return nullptr;
98}
99
101 static llvm::once_flag g_once_flag;
102
103 llvm::call_once(g_once_flag, []() {
106 });
107}
108
111}
112
114
116 bool plugin_specified_by_name) {
117 return true;
118}
119
121
123 ThreadList &new_thread_list) {
124 if (old_thread_list.GetSize(false) == 0) {
125 // Make up the thread the first time this is called so we can set our one
126 // and only core thread state up.
127
128 // We cannot construct a thread without a register context as that crashes
129 // LLDB but we can construct a process without threads to provide minimal
130 // memory reading support.
131 switch (GetTarget().GetArchitecture().GetMachine()) {
132 case llvm::Triple::aarch64:
133 case llvm::Triple::x86:
134 case llvm::Triple::x86_64:
135 break;
136 default:
137 return false;
138 }
139
141
142 // struct field offsets are written as symbols so that we don't have
143 // to figure them out ourselves
144 int32_t offset_p_list = ReadSignedIntegerFromMemory(
145 FindSymbol("proc_off_p_list"), 4, -1, error);
146 int32_t offset_p_pid =
147 ReadSignedIntegerFromMemory(FindSymbol("proc_off_p_pid"), 4, -1, error);
148 int32_t offset_p_threads = ReadSignedIntegerFromMemory(
149 FindSymbol("proc_off_p_threads"), 4, -1, error);
150 int32_t offset_p_comm = ReadSignedIntegerFromMemory(
151 FindSymbol("proc_off_p_comm"), 4, -1, error);
152
153 int32_t offset_td_tid = ReadSignedIntegerFromMemory(
154 FindSymbol("thread_off_td_tid"), 4, -1, error);
155 int32_t offset_td_plist = ReadSignedIntegerFromMemory(
156 FindSymbol("thread_off_td_plist"), 4, -1, error);
157 int32_t offset_td_pcb = ReadSignedIntegerFromMemory(
158 FindSymbol("thread_off_td_pcb"), 4, -1, error);
159 int32_t offset_td_oncpu = ReadSignedIntegerFromMemory(
160 FindSymbol("thread_off_td_oncpu"), 4, -1, error);
161 int32_t offset_td_name = ReadSignedIntegerFromMemory(
162 FindSymbol("thread_off_td_name"), 4, -1, error);
163
164 // fail if we were not able to read any of the offsets
165 if (offset_p_list == -1 || offset_p_pid == -1 || offset_p_threads == -1 ||
166 offset_p_comm == -1 || offset_td_tid == -1 || offset_td_plist == -1 ||
167 offset_td_pcb == -1 || offset_td_oncpu == -1 || offset_td_name == -1)
168 return false;
169
170 // dumptid contains the thread-id of the crashing thread
171 // dumppcb contains its PCB
172 int32_t dumptid =
173 ReadSignedIntegerFromMemory(FindSymbol("dumptid"), 4, -1, error);
174 lldb::addr_t dumppcb = FindSymbol("dumppcb");
175
176 // stoppcbs is an array of PCBs on all CPUs
177 // each element is of size pcb_size
178 int32_t pcbsize =
179 ReadSignedIntegerFromMemory(FindSymbol("pcb_size"), 4, -1, error);
180 lldb::addr_t stoppcbs = FindSymbol("stoppcbs");
181
182 // from FreeBSD sys/param.h
183 constexpr size_t fbsd_maxcomlen = 19;
184
185 // iterate through a linked list of all processes
186 // allproc is a pointer to the first list element, p_list field
187 // (found at offset_p_list) specifies the next element
188 for (lldb::addr_t proc =
190 proc != 0 && proc != LLDB_INVALID_ADDRESS;
191 proc = ReadPointerFromMemory(proc + offset_p_list, error)) {
192 int32_t pid =
193 ReadSignedIntegerFromMemory(proc + offset_p_pid, 4, -1, error);
194 // process' command-line string
195 char comm[fbsd_maxcomlen + 1];
196 ReadCStringFromMemory(proc + offset_p_comm, comm, sizeof(comm), error);
197
198 // iterate through a linked list of all process' threads
199 // the initial thread is found in process' p_threads, subsequent
200 // elements are linked via td_plist field
201 for (lldb::addr_t td =
202 ReadPointerFromMemory(proc + offset_p_threads, error);
203 td != 0; td = ReadPointerFromMemory(td + offset_td_plist, error)) {
204 int32_t tid =
205 ReadSignedIntegerFromMemory(td + offset_td_tid, 4, -1, error);
206 lldb::addr_t pcb_addr =
207 ReadPointerFromMemory(td + offset_td_pcb, error);
208 // whether process was on CPU (-1 if not, otherwise CPU number)
209 int32_t oncpu =
210 ReadSignedIntegerFromMemory(td + offset_td_oncpu, 4, -2, error);
211 // thread name
212 char thread_name[fbsd_maxcomlen + 1];
213 ReadCStringFromMemory(td + offset_td_name, thread_name,
214 sizeof(thread_name), error);
215
216 // if we failed to read TID, ignore this thread
217 if (tid == -1)
218 continue;
219
220 std::string thread_desc = llvm::formatv("(pid {0}) {1}", pid, comm);
221 if (*thread_name && strcmp(thread_name, comm)) {
222 thread_desc += '/';
223 thread_desc += thread_name;
224 }
225
226 // roughly:
227 // 1. if the thread crashed, its PCB is going to be at "dumppcb"
228 // 2. if the thread was on CPU, its PCB is going to be on the CPU
229 // 3. otherwise, its PCB is in the thread struct
230 if (tid == dumptid) {
231 // NB: dumppcb can be LLDB_INVALID_ADDRESS if reading it failed
232 pcb_addr = dumppcb;
233 thread_desc += " (crashed)";
234 } else if (oncpu != -1) {
235 // if we managed to read stoppcbs and pcb_size, use them to find
236 // the correct PCB
237 if (stoppcbs != LLDB_INVALID_ADDRESS && pcbsize > 0)
238 pcb_addr = stoppcbs + oncpu * pcbsize;
239 else
240 pcb_addr = LLDB_INVALID_ADDRESS;
241 thread_desc += llvm::formatv(" (on CPU {0})", oncpu);
242 }
243
244 ThreadSP thread_sp{
245 new ThreadFreeBSDKernel(*this, tid, pcb_addr, thread_desc)};
246 new_thread_list.AddThread(thread_sp);
247 }
248 }
249 } else {
250 const uint32_t num_threads = old_thread_list.GetSize(false);
251 for (uint32_t i = 0; i < num_threads; ++i)
252 new_thread_list.AddThread(old_thread_list.GetThreadAtIndex(i, false));
253 }
254 return new_thread_list.GetSize(false) > 0;
255}
256
258 // The core is already loaded by CreateInstance().
259 return Status();
260}
261
263 if (m_dyld_up.get() == nullptr)
266 return m_dyld_up.get();
267}
268
271 const Symbol *sym = mod_sp->FindFirstSymbolWithNameAndType(ConstString(name));
272 return sym ? sym->GetLoadAddress(&GetTarget()) : LLDB_INVALID_ADDRESS;
273}
274
275#if LLDB_ENABLE_FBSDVMCORE
276
277ProcessFreeBSDKernelFVC::ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp,
278 ListenerSP listener_sp,
279 fvc_t *fvc)
280 : ProcessFreeBSDKernel(target_sp, listener_sp), m_fvc(fvc) {}
281
282ProcessFreeBSDKernelFVC::~ProcessFreeBSDKernelFVC() {
283 if (m_fvc)
284 fvc_close(m_fvc);
285}
286
287size_t ProcessFreeBSDKernelFVC::DoReadMemory(lldb::addr_t addr, void *buf,
288 size_t size, Status &error) {
289 ssize_t rd = 0;
290 rd = fvc_read(m_fvc, addr, buf, size);
291 if (rd < 0 || static_cast<size_t>(rd) != size) {
292 error.SetErrorStringWithFormat("Reading memory failed: %s", GetError());
293 return rd > 0 ? rd : 0;
294 }
295 return rd;
296}
297
298const char *ProcessFreeBSDKernelFVC::GetError() { return fvc_geterr(m_fvc); }
299
300#endif // LLDB_ENABLE_FBSDVMCORE
301
302#if defined(__FreeBSD__)
303
304ProcessFreeBSDKernelKVM::ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp,
305 ListenerSP listener_sp,
306 kvm_t *fvc)
307 : ProcessFreeBSDKernel(target_sp, listener_sp), m_kvm(fvc) {}
308
309ProcessFreeBSDKernelKVM::~ProcessFreeBSDKernelKVM() {
310 if (m_kvm)
311 kvm_close(m_kvm);
312}
313
314size_t ProcessFreeBSDKernelKVM::DoReadMemory(lldb::addr_t addr, void *buf,
315 size_t size, Status &error) {
316 ssize_t rd = 0;
317 rd = kvm_read2(m_kvm, addr, buf, size);
318 if (rd < 0 || static_cast<size_t>(rd) != size) {
319 error.SetErrorStringWithFormat("Reading memory failed: %s", GetError());
320 return rd > 0 ? rd : 0;
321 }
322 return rd;
323}
324
325const char *ProcessFreeBSDKernelKVM::GetError() { return kvm_geterr(m_kvm); }
326
327#endif // defined(__FreeBSD__)
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_PLUGIN_DEFINE(PluginName)
Definition: PluginManager.h:31
static llvm::StringRef GetPluginNameStatic()
lldb_private::Status DoLoadCore() override
bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list) override
Update the thread list following process plug-in's specific logic.
bool CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) override
Check if a plug-in instance can debug the file in module.
ProcessFreeBSDKernel(lldb::TargetSP target_sp, lldb::ListenerSP listener)
void RefreshStateAfterStop() override
Currently called as part of ShouldStop.
lldb::addr_t FindSymbol(const char *name)
lldb_private::DynamicLoader * GetDynamicLoader() override
Get the dynamic loader plug-in for this process.
static llvm::StringRef GetPluginNameStatic()
lldb_private::Status DoDestroy() override
static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener, const lldb_private::FileSpec *crash_file_path, bool can_connect)
static llvm::StringRef GetPluginDescriptionStatic()
A uniqued constant string class.
Definition: ConstString.h:40
A plug-in interface definition class for dynamic loaders.
Definition: DynamicLoader.h:52
static DynamicLoader * FindPlugin(Process *process, llvm::StringRef plugin_name)
Find a dynamic loader plugin for a given process.
A file utility class.
Definition: FileSpec.h:56
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:367
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
Base class for all processes that don't represent a live process, such as coredumps or processes trac...
int64_t ReadSignedIntegerFromMemory(lldb::addr_t load_addr, size_t byte_size, int64_t fail_value, Status &error)
Definition: Process.cpp:2078
size_t ReadCStringFromMemory(lldb::addr_t vm_addr, char *cstr, size_t cstr_max_len, Status &error)
Read a NULL terminated C string from memory.
Definition: Process.cpp:1992
lldb::DynamicLoaderUP m_dyld_up
Definition: Process.h:2998
lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Status &error)
Definition: Process.cpp:2089
virtual size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, Status &error)=0
Actually do the reading of memory from a process.
Target & GetTarget()
Get the target object pointer for this module.
Definition: Process.h:1242
An error handling class.
Definition: Status.h:44
lldb::addr_t GetLoadAddress(Target *target) const
Definition: Symbol.cpp:537
lldb::ModuleSP GetExecutableModule()
Gets the module for the main executable.
Definition: Target.cpp:1375
void AddThread(const lldb::ThreadSP &thread_sp)
uint32_t GetSize(bool can_update=true)
Definition: ThreadList.cpp:83
lldb::ThreadSP GetThreadAtIndex(uint32_t idx, bool can_update=true)
Definition: ThreadList.cpp:91
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:76
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::Thread > ThreadSP
Definition: lldb-forward.h:425
std::shared_ptr< lldb_private::Process > ProcessSP
Definition: lldb-forward.h:368
std::shared_ptr< lldb_private::Listener > ListenerSP
Definition: lldb-forward.h:349
uint64_t addr_t
Definition: lldb-types.h:79
std::shared_ptr< lldb_private::Target > TargetSP
Definition: lldb-forward.h:423
std::shared_ptr< lldb_private::Module > ModuleSP
Definition: lldb-forward.h:354