xref: /llvm-project/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp (revision f22d82cef28a882cec4d242910933e9f5d7dcdce)
1 //===-- ScriptedProcess.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 "ScriptedProcess.h"
10 
11 #include "lldb/Core/Debugger.h"
12 #include "lldb/Core/Module.h"
13 #include "lldb/Core/PluginManager.h"
14 
15 #include "lldb/Host/OptionParser.h"
16 #include "lldb/Host/ThreadLauncher.h"
17 #include "lldb/Interpreter/CommandInterpreter.h"
18 #include "lldb/Interpreter/OptionArgParser.h"
19 #include "lldb/Interpreter/OptionGroupBoolean.h"
20 #include "lldb/Interpreter/ScriptInterpreter.h"
21 #include "lldb/Target/MemoryRegionInfo.h"
22 #include "lldb/Target/Queue.h"
23 #include "lldb/Target/RegisterContext.h"
24 #include "lldb/Utility/LLDBLog.h"
25 #include "lldb/Utility/ScriptedMetadata.h"
26 #include "lldb/Utility/State.h"
27 
28 #include <mutex>
29 
30 LLDB_PLUGIN_DEFINE(ScriptedProcess)
31 
32 using namespace lldb;
33 using namespace lldb_private;
34 
35 llvm::StringRef ScriptedProcess::GetPluginDescriptionStatic() {
36   return "Scripted Process plug-in.";
37 }
38 
39 static constexpr lldb::ScriptLanguage g_supported_script_languages[] = {
40     ScriptLanguage::eScriptLanguagePython,
41 };
42 
43 bool ScriptedProcess::IsScriptLanguageSupported(lldb::ScriptLanguage language) {
44   llvm::ArrayRef<lldb::ScriptLanguage> supported_languages =
45       llvm::ArrayRef(g_supported_script_languages);
46 
47   return llvm::is_contained(supported_languages, language);
48 }
49 
50 lldb::ProcessSP ScriptedProcess::CreateInstance(lldb::TargetSP target_sp,
51                                                 lldb::ListenerSP listener_sp,
52                                                 const FileSpec *file,
53                                                 bool can_connect) {
54   if (!target_sp ||
55       !IsScriptLanguageSupported(target_sp->GetDebugger().GetScriptLanguage()))
56     return nullptr;
57 
58   ScriptedMetadata scripted_metadata(target_sp->GetProcessLaunchInfo());
59 
60   Status error;
61   auto process_sp = std::shared_ptr<ScriptedProcess>(
62       new ScriptedProcess(target_sp, listener_sp, scripted_metadata, error));
63 
64   if (error.Fail() || !process_sp || !process_sp->m_interface_up) {
65     LLDB_LOGF(GetLog(LLDBLog::Process), "%s", error.AsCString());
66     return nullptr;
67   }
68 
69   return process_sp;
70 }
71 
72 bool ScriptedProcess::CanDebug(lldb::TargetSP target_sp,
73                                bool plugin_specified_by_name) {
74   return true;
75 }
76 
77 ScriptedProcess::ScriptedProcess(lldb::TargetSP target_sp,
78                                  lldb::ListenerSP listener_sp,
79                                  const ScriptedMetadata &scripted_metadata,
80                                  Status &error)
81     : Process(target_sp, listener_sp), m_scripted_metadata(scripted_metadata) {
82 
83   if (!target_sp) {
84     error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
85                                    __FUNCTION__, "Invalid target");
86     return;
87   }
88 
89   ScriptInterpreter *interpreter =
90       target_sp->GetDebugger().GetScriptInterpreter();
91 
92   if (!interpreter) {
93     error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
94                                    __FUNCTION__,
95                                    "Debugger has no Script Interpreter");
96     return;
97   }
98 
99   // Create process instance interface
100   m_interface_up = interpreter->CreateScriptedProcessInterface();
101   if (!m_interface_up) {
102     error.SetErrorStringWithFormat(
103         "ScriptedProcess::%s () - ERROR: %s", __FUNCTION__,
104         "Script interpreter couldn't create Scripted Process Interface");
105     return;
106   }
107 
108   ExecutionContext exe_ctx(target_sp, /*get_process=*/false);
109 
110   // Create process script object
111   auto obj_or_err = GetInterface().CreatePluginObject(
112       m_scripted_metadata.GetClassName(), exe_ctx,
113       m_scripted_metadata.GetArgsSP());
114 
115   if (!obj_or_err) {
116     error.SetErrorString("Failed to create script object.");
117     return;
118   }
119 
120   StructuredData::GenericSP object_sp = *obj_or_err;
121 
122   if (!object_sp || !object_sp->IsValid()) {
123     error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
124                                    __FUNCTION__,
125                                    "Failed to create valid script object");
126     return;
127   }
128 }
129 
130 ScriptedProcess::~ScriptedProcess() {
131   Clear();
132   // We need to call finalize on the process before destroying ourselves to
133   // make sure all of the broadcaster cleanup goes as planned. If we destruct
134   // this class, then Process::~Process() might have problems trying to fully
135   // destroy the broadcaster.
136   Finalize();
137 }
138 
139 void ScriptedProcess::Initialize() {
140   static llvm::once_flag g_once_flag;
141 
142   llvm::call_once(g_once_flag, []() {
143     PluginManager::RegisterPlugin(GetPluginNameStatic(),
144                                   GetPluginDescriptionStatic(), CreateInstance);
145   });
146 }
147 
148 void ScriptedProcess::Terminate() {
149   PluginManager::UnregisterPlugin(ScriptedProcess::CreateInstance);
150 }
151 
152 Status ScriptedProcess::DoLoadCore() {
153   ProcessLaunchInfo launch_info = GetTarget().GetProcessLaunchInfo();
154 
155   return DoLaunch(nullptr, launch_info);
156 }
157 
158 Status ScriptedProcess::DoLaunch(Module *exe_module,
159                                  ProcessLaunchInfo &launch_info) {
160   LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s launching process", __FUNCTION__);
161 
162   /* MARK: This doesn't reflect how lldb actually launches a process.
163            In reality, it attaches to debugserver, then resume the process.
164            That's not true in all cases.  If debugserver is remote, lldb
165            asks debugserver to launch the process for it. */
166   Status error = GetInterface().Launch();
167   SetPrivateState(eStateStopped);
168   return error;
169 }
170 
171 void ScriptedProcess::DidLaunch() { m_pid = GetInterface().GetProcessID(); }
172 
173 void ScriptedProcess::DidResume() {
174   // Update the PID again, in case the user provided a placeholder pid at launch
175   m_pid = GetInterface().GetProcessID();
176 }
177 
178 Status ScriptedProcess::DoResume() {
179   LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s resuming process", __FUNCTION__);
180 
181   return GetInterface().Resume();
182 }
183 
184 Status ScriptedProcess::DoAttach(const ProcessAttachInfo &attach_info) {
185   Status error = GetInterface().Attach(attach_info);
186   SetPrivateState(eStateRunning);
187   SetPrivateState(eStateStopped);
188   if (error.Fail())
189     return error;
190   // NOTE: We need to set the PID before finishing to attach otherwise we will
191   // hit an assert when calling the attach completion handler.
192   DidLaunch();
193 
194   return {};
195 }
196 
197 Status
198 ScriptedProcess::DoAttachToProcessWithID(lldb::pid_t pid,
199                                          const ProcessAttachInfo &attach_info) {
200   return DoAttach(attach_info);
201 }
202 
203 Status ScriptedProcess::DoAttachToProcessWithName(
204     const char *process_name, const ProcessAttachInfo &attach_info) {
205   return DoAttach(attach_info);
206 }
207 
208 void ScriptedProcess::DidAttach(ArchSpec &process_arch) {
209   process_arch = GetArchitecture();
210 }
211 
212 Status ScriptedProcess::DoDestroy() { return Status(); }
213 
214 bool ScriptedProcess::IsAlive() { return GetInterface().IsAlive(); }
215 
216 size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
217                                      Status &error) {
218   lldb::DataExtractorSP data_extractor_sp =
219       GetInterface().ReadMemoryAtAddress(addr, size, error);
220 
221   if (!data_extractor_sp || !data_extractor_sp->GetByteSize() || error.Fail())
222     return 0;
223 
224   offset_t bytes_copied = data_extractor_sp->CopyByteOrderedData(
225       0, data_extractor_sp->GetByteSize(), buf, size, GetByteOrder());
226 
227   if (!bytes_copied || bytes_copied == LLDB_INVALID_OFFSET)
228     return ScriptedInterface::ErrorWithMessage<size_t>(
229         LLVM_PRETTY_FUNCTION, "Failed to copy read memory to buffer.", error);
230 
231   // FIXME: We should use the diagnostic system to report a warning if the
232   // `bytes_copied` is different from `size`.
233 
234   return bytes_copied;
235 }
236 
237 size_t ScriptedProcess::DoWriteMemory(lldb::addr_t vm_addr, const void *buf,
238                                       size_t size, Status &error) {
239   lldb::DataExtractorSP data_extractor_sp = std::make_shared<DataExtractor>(
240       buf, size, GetByteOrder(), GetAddressByteSize());
241 
242   if (!data_extractor_sp || !data_extractor_sp->GetByteSize())
243     return 0;
244 
245   lldb::offset_t bytes_written =
246       GetInterface().WriteMemoryAtAddress(vm_addr, data_extractor_sp, error);
247 
248   if (!bytes_written || bytes_written == LLDB_INVALID_OFFSET)
249     return ScriptedInterface::ErrorWithMessage<size_t>(
250         LLVM_PRETTY_FUNCTION, "Failed to copy write buffer to memory.", error);
251 
252   // FIXME: We should use the diagnostic system to report a warning if the
253   // `bytes_written` is different from `size`.
254 
255   return bytes_written;
256 }
257 
258 Status ScriptedProcess::EnableBreakpointSite(BreakpointSite *bp_site) {
259   assert(bp_site != nullptr);
260 
261   if (bp_site->IsEnabled()) {
262     return {};
263   }
264 
265   if (bp_site->HardwareRequired()) {
266     return Status("Scripted Processes don't support hardware breakpoints");
267   }
268 
269   Status error;
270   GetInterface().CreateBreakpoint(bp_site->GetLoadAddress(), error);
271 
272   return error;
273 }
274 
275 ArchSpec ScriptedProcess::GetArchitecture() {
276   return GetTarget().GetArchitecture();
277 }
278 
279 Status ScriptedProcess::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
280                                               MemoryRegionInfo &region) {
281   Status error;
282   if (auto region_or_err =
283           GetInterface().GetMemoryRegionContainingAddress(load_addr, error))
284     region = *region_or_err;
285 
286   return error;
287 }
288 
289 Status ScriptedProcess::GetMemoryRegions(MemoryRegionInfos &region_list) {
290   Status error;
291   lldb::addr_t address = 0;
292 
293   while (auto region_or_err =
294              GetInterface().GetMemoryRegionContainingAddress(address, error)) {
295     if (error.Fail())
296       break;
297 
298     MemoryRegionInfo &mem_region = *region_or_err;
299     auto range = mem_region.GetRange();
300     address += range.GetRangeBase() + range.GetByteSize();
301     region_list.push_back(mem_region);
302   }
303 
304   return error;
305 }
306 
307 void ScriptedProcess::Clear() { Process::m_thread_list.Clear(); }
308 
309 bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list,
310                                          ThreadList &new_thread_list) {
311   // TODO: Implement
312   // This is supposed to get the current set of threads, if any of them are in
313   // old_thread_list then they get copied to new_thread_list, and then any
314   // actually new threads will get added to new_thread_list.
315   m_thread_plans.ClearThreadCache();
316 
317   Status error;
318   StructuredData::DictionarySP thread_info_sp = GetInterface().GetThreadsInfo();
319 
320   if (!thread_info_sp)
321     return ScriptedInterface::ErrorWithMessage<bool>(
322         LLVM_PRETTY_FUNCTION,
323         "Couldn't fetch thread list from Scripted Process.", error);
324 
325   // Because `StructuredData::Dictionary` uses a `std::map<ConstString,
326   // ObjectSP>` for storage, each item is sorted based on the key alphabetical
327   // order. Since `GetThreadsInfo` provides thread indices as the key element,
328   // thread info comes ordered alphabetically, instead of numerically, so we
329   // need to sort the thread indices before creating thread.
330 
331   StructuredData::ArraySP keys = thread_info_sp->GetKeys();
332 
333   std::map<size_t, StructuredData::ObjectSP> sorted_threads;
334   auto sort_keys = [&sorted_threads,
335                     &thread_info_sp](StructuredData::Object *item) -> bool {
336     if (!item)
337       return false;
338 
339     llvm::StringRef key = item->GetStringValue();
340     size_t idx = 0;
341 
342     // Make sure the provided index is actually an integer
343     if (!llvm::to_integer(key, idx))
344       return false;
345 
346     sorted_threads[idx] = thread_info_sp->GetValueForKey(key);
347     return true;
348   };
349 
350   size_t thread_count = thread_info_sp->GetSize();
351 
352   if (!keys->ForEach(sort_keys) || sorted_threads.size() != thread_count)
353     // Might be worth showing the unsorted thread list instead of return early.
354     return ScriptedInterface::ErrorWithMessage<bool>(
355         LLVM_PRETTY_FUNCTION, "Couldn't sort thread list.", error);
356 
357   auto create_scripted_thread =
358       [this, &error, &new_thread_list](
359           const std::pair<size_t, StructuredData::ObjectSP> pair) -> bool {
360     size_t idx = pair.first;
361     StructuredData::ObjectSP object_sp = pair.second;
362 
363     if (!object_sp)
364       return ScriptedInterface::ErrorWithMessage<bool>(
365           LLVM_PRETTY_FUNCTION, "Invalid thread info object", error);
366 
367     auto thread_or_error =
368         ScriptedThread::Create(*this, object_sp->GetAsGeneric());
369 
370     if (!thread_or_error)
371       return ScriptedInterface::ErrorWithMessage<bool>(
372           LLVM_PRETTY_FUNCTION, toString(thread_or_error.takeError()), error);
373 
374     ThreadSP thread_sp = thread_or_error.get();
375     lldbassert(thread_sp && "Couldn't initialize scripted thread.");
376 
377     RegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext();
378     if (!reg_ctx_sp)
379       return ScriptedInterface::ErrorWithMessage<bool>(
380           LLVM_PRETTY_FUNCTION,
381           llvm::Twine("Invalid Register Context for thread " + llvm::Twine(idx))
382               .str(),
383           error);
384 
385     new_thread_list.AddThread(thread_sp);
386 
387     return true;
388   };
389 
390   llvm::for_each(sorted_threads, create_scripted_thread);
391 
392   return new_thread_list.GetSize(false) > 0;
393 }
394 
395 void ScriptedProcess::RefreshStateAfterStop() {
396   // Let all threads recover from stopping and do any clean up based on the
397   // previous thread state (if any).
398   m_thread_list.RefreshStateAfterStop();
399 }
400 
401 bool ScriptedProcess::GetProcessInfo(ProcessInstanceInfo &info) {
402   info.Clear();
403   info.SetProcessID(GetID());
404   info.SetArchitecture(GetArchitecture());
405   lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();
406   if (module_sp) {
407     const bool add_exe_file_as_first_arg = false;
408     info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),
409                            add_exe_file_as_first_arg);
410   }
411   return true;
412 }
413 
414 lldb_private::StructuredData::ObjectSP
415 ScriptedProcess::GetLoadedDynamicLibrariesInfos() {
416   Status error;
417   auto error_with_message = [&error](llvm::StringRef message) {
418     return ScriptedInterface::ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION,
419                                                      message.data(), error);
420   };
421 
422   StructuredData::ArraySP loaded_images_sp = GetInterface().GetLoadedImages();
423 
424   if (!loaded_images_sp || !loaded_images_sp->GetSize())
425     return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(
426         LLVM_PRETTY_FUNCTION, "No loaded images.", error);
427 
428   ModuleList module_list;
429   Target &target = GetTarget();
430 
431   auto reload_image = [&target, &module_list, &error_with_message](
432                           StructuredData::Object *obj) -> bool {
433     StructuredData::Dictionary *dict = obj->GetAsDictionary();
434 
435     if (!dict)
436       return error_with_message("Couldn't cast image object into dictionary.");
437 
438     ModuleSpec module_spec;
439     llvm::StringRef value;
440 
441     bool has_path = dict->HasKey("path");
442     bool has_uuid = dict->HasKey("uuid");
443     if (!has_path && !has_uuid)
444       return error_with_message("Dictionary should have key 'path' or 'uuid'");
445     if (!dict->HasKey("load_addr"))
446       return error_with_message("Dictionary is missing key 'load_addr'");
447 
448     if (has_path) {
449       dict->GetValueForKeyAsString("path", value);
450       module_spec.GetFileSpec().SetPath(value);
451     }
452 
453     if (has_uuid) {
454       dict->GetValueForKeyAsString("uuid", value);
455       module_spec.GetUUID().SetFromStringRef(value);
456     }
457     module_spec.GetArchitecture() = target.GetArchitecture();
458 
459     ModuleSP module_sp =
460         target.GetOrCreateModule(module_spec, true /* notify */);
461 
462     if (!module_sp)
463       return error_with_message("Couldn't create or get module.");
464 
465     lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
466     lldb::offset_t slide = LLDB_INVALID_OFFSET;
467     dict->GetValueForKeyAsInteger("load_addr", load_addr);
468     dict->GetValueForKeyAsInteger("slide", slide);
469     if (load_addr == LLDB_INVALID_ADDRESS)
470       return error_with_message(
471           "Couldn't get valid load address or slide offset.");
472 
473     if (slide != LLDB_INVALID_OFFSET)
474       load_addr += slide;
475 
476     bool changed = false;
477     module_sp->SetLoadAddress(target, load_addr, false /*=value_is_offset*/,
478                               changed);
479 
480     if (!changed && !module_sp->GetObjectFile())
481       return error_with_message("Couldn't set the load address for module.");
482 
483     dict->GetValueForKeyAsString("path", value);
484     FileSpec objfile(value);
485     module_sp->SetFileSpecAndObjectName(objfile, objfile.GetFilename());
486 
487     return module_list.AppendIfNeeded(module_sp);
488   };
489 
490   if (!loaded_images_sp->ForEach(reload_image))
491     return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(
492         LLVM_PRETTY_FUNCTION, "Couldn't reload all images.", error);
493 
494   target.ModulesDidLoad(module_list);
495 
496   return loaded_images_sp;
497 }
498 
499 lldb_private::StructuredData::DictionarySP ScriptedProcess::GetMetadata() {
500   StructuredData::DictionarySP metadata_sp = GetInterface().GetMetadata();
501 
502   Status error;
503   if (!metadata_sp || !metadata_sp->GetSize())
504     return ScriptedInterface::ErrorWithMessage<StructuredData::DictionarySP>(
505         LLVM_PRETTY_FUNCTION, "No metadata.", error);
506 
507   return metadata_sp;
508 }
509 
510 void ScriptedProcess::UpdateQueueListIfNeeded() {
511   CheckScriptedInterface();
512   for (ThreadSP thread_sp : Threads()) {
513     if (const char *queue_name = thread_sp->GetQueueName()) {
514       QueueSP queue_sp = std::make_shared<Queue>(
515           m_process->shared_from_this(), thread_sp->GetQueueID(), queue_name);
516       m_queue_list.AddQueue(queue_sp);
517     }
518   }
519 }
520 
521 ScriptedProcessInterface &ScriptedProcess::GetInterface() const {
522   CheckScriptedInterface();
523   return *m_interface_up;
524 }
525 
526 void *ScriptedProcess::GetImplementation() {
527   StructuredData::GenericSP object_instance_sp =
528       GetInterface().GetScriptObjectInstance();
529   if (object_instance_sp &&
530       object_instance_sp->GetType() == eStructuredDataTypeGeneric)
531     return object_instance_sp->GetAsGeneric()->GetValue();
532   return nullptr;
533 }
534