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 
14 #include "ProcessFreeBSDKernel.h"
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 
24 using namespace lldb;
25 using namespace lldb_private;
26 
28 
29 namespace {
30 
31 #if LLDB_ENABLE_FBSDVMCORE
32 class ProcessFreeBSDKernelFVC : public ProcessFreeBSDKernel {
33 public:
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 
42 private:
43  fvc_t *m_fvc;
44 
45  const char *GetError();
46 };
47 #endif // LLDB_ENABLE_FBSDVMCORE
48 
49 #if defined(__FreeBSD__)
50 class ProcessFreeBSDKernelKVM : public ProcessFreeBSDKernel {
51 public:
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 
60 private:
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 
73 lldb::ProcessSP ProcessFreeBSDKernel::CreateInstance(lldb::TargetSP target_sp,
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, []() {
104  PluginManager::RegisterPlugin(GetPluginNameStatic(),
106  });
107 }
108 
110  PluginManager::UnregisterPlugin(ProcessFreeBSDKernel::CreateInstance);
111 }
112 
114 
115 bool ProcessFreeBSDKernel::CanDebug(lldb::TargetSP target_sp,
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 
140  Status error;
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)
264  m_dyld_up.reset(DynamicLoader::FindPlugin(
266  return m_dyld_up.get();
267 }
268 
270  ModuleSP mod_sp = GetTarget().GetExecutableModule();
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 
277 ProcessFreeBSDKernelFVC::ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp,
278  ListenerSP listener_sp,
279  fvc_t *fvc)
280  : ProcessFreeBSDKernel(target_sp, listener_sp), m_fvc(fvc) {}
281 
282 ProcessFreeBSDKernelFVC::~ProcessFreeBSDKernelFVC() {
283  if (m_fvc)
284  fvc_close(m_fvc);
285 }
286 
287 size_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 
298 const char *ProcessFreeBSDKernelFVC::GetError() { return fvc_geterr(m_fvc); }
299 
300 #endif // LLDB_ENABLE_FBSDVMCORE
301 
302 #if defined(__FreeBSD__)
303 
304 ProcessFreeBSDKernelKVM::ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp,
305  ListenerSP listener_sp,
306  kvm_t *fvc)
307  : ProcessFreeBSDKernel(target_sp, listener_sp), m_kvm(fvc) {}
308 
309 ProcessFreeBSDKernelKVM::~ProcessFreeBSDKernelKVM() {
310  if (m_kvm)
311  kvm_close(m_kvm);
312 }
313 
314 size_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 
325 const char *ProcessFreeBSDKernelKVM::GetError() { return kvm_geterr(m_kvm); }
326 
327 #endif // defined(__FreeBSD__)
lldb_private::Symbol
Definition: Symbol.h:20
ProcessFreeBSDKernel.h
ProcessFreeBSDKernel::CreateInstance
static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener, const lldb_private::FileSpec *crash_file_path, bool can_connect)
Definition: ProcessFreeBSDKernel.cpp:73
ThreadFreeBSDKernel
Definition: ThreadFreeBSDKernel.h:14
lldb_private::Target::GetExecutableModule
lldb::ModuleSP GetExecutableModule()
Gets the module for the main executable.
Definition: Target.cpp:1371
Module.h
lldb_private::Process::GetTarget
Target & GetTarget()
Get the target object pointer for this module.
Definition: Process.h:1219
lldb_private::Process::ReadSignedIntegerFromMemory
int64_t ReadSignedIntegerFromMemory(lldb::addr_t load_addr, size_t byte_size, int64_t fail_value, Status &error)
Definition: Process.cpp:2077
DynamicLoaderStatic.h
lldb_private::Process::ReadCStringFromMemory
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:1991
lldb::addr_t
uint64_t addr_t
Definition: lldb-types.h:83
ProcessFreeBSDKernel::DoUpdateThreadList
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.
Definition: ProcessFreeBSDKernel.cpp:122
ProcessFreeBSDKernel::Initialize
static void Initialize()
Definition: ProcessFreeBSDKernel.cpp:100
lldb_private::FileSpec
Definition: FileSpec.h:55
error
static llvm::raw_ostream & error(Stream &strm)
Definition: CommandReturnObject.cpp:17
ProcessFreeBSDKernel::GetPluginDescriptionStatic
static llvm::StringRef GetPluginDescriptionStatic()
Definition: ProcessFreeBSDKernel.h:29
ProcessFreeBSDKernel::GetPluginNameStatic
static llvm::StringRef GetPluginNameStatic()
Definition: ProcessFreeBSDKernel.h:27
lldb_private::Process::m_dyld_up
lldb::DynamicLoaderUP m_dyld_up
Definition: Process.h:2902
ThreadFreeBSDKernel.h
lldb_private::ThreadList
Definition: ThreadList.h:26
lldb_private::ConstString
Definition: ConstString.h:39
lldb_private::PostMortemProcess
Definition: PostMortemProcess.h:23
lldb_private::DynamicLoader
Definition: DynamicLoader.h:52
string
string(SUBSTRING ${p} 10 -1 pStripped) if($
Definition: Plugins/CMakeLists.txt:40
lldb_private::ThreadList::GetThreadAtIndex
lldb::ThreadSP GetThreadAtIndex(uint32_t idx, bool can_update=true)
Definition: ThreadList.cpp:91
ProcessFreeBSDKernel::RefreshStateAfterStop
void RefreshStateAfterStop() override
Currently called as part of ShouldStop.
Definition: ProcessFreeBSDKernel.cpp:120
lldb_private::Status
Definition: Status.h:44
ProcessFreeBSDKernel::DoLoadCore
lldb_private::Status DoLoadCore() override
Definition: ProcessFreeBSDKernel.cpp:257
uint32_t
lldb_private::ThreadList::GetSize
uint32_t GetSize(bool can_update=true)
Definition: ThreadList.cpp:83
ProcessFreeBSDKernel::ProcessFreeBSDKernel
ProcessFreeBSDKernel(lldb::TargetSP target_sp, lldb::ListenerSP listener)
Definition: ProcessFreeBSDKernel.cpp:69
PluginManager.h
LLDB_INVALID_ADDRESS
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:74
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
ProcessFreeBSDKernel::CanDebug
bool CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) override
Check if a plug-in instance can debug the file in module.
Definition: ProcessFreeBSDKernel.cpp:115
ProcessFreeBSDKernel::DoDestroy
lldb_private::Status DoDestroy() override
Definition: ProcessFreeBSDKernel.cpp:113
lldb_private::ThreadCollection::AddThread
void AddThread(const lldb::ThreadSP &thread_sp)
Definition: ThreadCollection.cpp:24
ProcessFreeBSDKernel::FindSymbol
lldb::addr_t FindSymbol(const char *name)
Definition: ProcessFreeBSDKernel.cpp:269
ProcessFreeBSDKernel
Definition: ProcessFreeBSDKernel.h:14
LLDB_PLUGIN_DEFINE
#define LLDB_PLUGIN_DEFINE(PluginName)
Definition: PluginManager.h:31
lldb_private::Process::ReadPointerFromMemory
lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Status &error)
Definition: Process.cpp:2088
lldb_private::Symbol::GetLoadAddress
lldb::addr_t GetLoadAddress(Target *target) const
Definition: Symbol.cpp:493
lldb_private::FileSpec::GetPath
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:364
DynamicLoaderStatic::GetPluginNameStatic
static llvm::StringRef GetPluginNameStatic()
Definition: DynamicLoaderStatic.h:26
DynamicLoader.h
ProcessFreeBSDKernel::GetDynamicLoader
lldb_private::DynamicLoader * GetDynamicLoader() override
Get the dynamic loader plug-in for this process.
Definition: ProcessFreeBSDKernel.cpp:262
lldb
Definition: SBAddress.h:15
ProcessFreeBSDKernel::Terminate
static void Terminate()
Definition: ProcessFreeBSDKernel.cpp:109