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