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