xref: /src/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1344a3780SDimitry Andric //===-- ScriptedProcess.cpp -----------------------------------------------===//
2344a3780SDimitry Andric //
3344a3780SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4344a3780SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5344a3780SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6344a3780SDimitry Andric //
7344a3780SDimitry Andric //===----------------------------------------------------------------------===//
8344a3780SDimitry Andric 
9344a3780SDimitry Andric #include "ScriptedProcess.h"
10344a3780SDimitry Andric 
11344a3780SDimitry Andric #include "lldb/Core/Debugger.h"
12344a3780SDimitry Andric #include "lldb/Core/Module.h"
13344a3780SDimitry Andric #include "lldb/Core/PluginManager.h"
14344a3780SDimitry Andric 
15344a3780SDimitry Andric #include "lldb/Host/OptionParser.h"
16344a3780SDimitry Andric #include "lldb/Host/ThreadLauncher.h"
17344a3780SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h"
18344a3780SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
19344a3780SDimitry Andric #include "lldb/Interpreter/OptionGroupBoolean.h"
20344a3780SDimitry Andric #include "lldb/Interpreter/ScriptInterpreter.h"
21344a3780SDimitry Andric #include "lldb/Target/MemoryRegionInfo.h"
22e3b55780SDimitry Andric #include "lldb/Target/Queue.h"
23344a3780SDimitry Andric #include "lldb/Target/RegisterContext.h"
24145449b1SDimitry Andric #include "lldb/Utility/LLDBLog.h"
257fa27ce4SDimitry Andric #include "lldb/Utility/ScriptedMetadata.h"
26344a3780SDimitry Andric #include "lldb/Utility/State.h"
27344a3780SDimitry Andric 
28344a3780SDimitry Andric #include <mutex>
29344a3780SDimitry Andric 
30344a3780SDimitry Andric LLDB_PLUGIN_DEFINE(ScriptedProcess)
31344a3780SDimitry Andric 
32344a3780SDimitry Andric using namespace lldb;
33344a3780SDimitry Andric using namespace lldb_private;
34344a3780SDimitry Andric 
GetPluginDescriptionStatic()35c0981da4SDimitry Andric llvm::StringRef ScriptedProcess::GetPluginDescriptionStatic() {
36344a3780SDimitry Andric   return "Scripted Process plug-in.";
37344a3780SDimitry Andric }
38344a3780SDimitry Andric 
39344a3780SDimitry Andric static constexpr lldb::ScriptLanguage g_supported_script_languages[] = {
40344a3780SDimitry Andric     ScriptLanguage::eScriptLanguagePython,
41344a3780SDimitry Andric };
42344a3780SDimitry Andric 
IsScriptLanguageSupported(lldb::ScriptLanguage language)43344a3780SDimitry Andric bool ScriptedProcess::IsScriptLanguageSupported(lldb::ScriptLanguage language) {
44344a3780SDimitry Andric   llvm::ArrayRef<lldb::ScriptLanguage> supported_languages =
45e3b55780SDimitry Andric       llvm::ArrayRef(g_supported_script_languages);
46344a3780SDimitry Andric 
47344a3780SDimitry Andric   return llvm::is_contained(supported_languages, language);
48344a3780SDimitry Andric }
49344a3780SDimitry Andric 
CreateInstance(lldb::TargetSP target_sp,lldb::ListenerSP listener_sp,const FileSpec * file,bool can_connect)50344a3780SDimitry Andric lldb::ProcessSP ScriptedProcess::CreateInstance(lldb::TargetSP target_sp,
51344a3780SDimitry Andric                                                 lldb::ListenerSP listener_sp,
52344a3780SDimitry Andric                                                 const FileSpec *file,
53344a3780SDimitry Andric                                                 bool can_connect) {
54344a3780SDimitry Andric   if (!target_sp ||
55344a3780SDimitry Andric       !IsScriptLanguageSupported(target_sp->GetDebugger().GetScriptLanguage()))
56344a3780SDimitry Andric     return nullptr;
57344a3780SDimitry Andric 
58e3b55780SDimitry Andric   ScriptedMetadata scripted_metadata(target_sp->GetProcessLaunchInfo());
59344a3780SDimitry Andric 
60e3b55780SDimitry Andric   Status error;
61e3b55780SDimitry Andric   auto process_sp = std::shared_ptr<ScriptedProcess>(
62e3b55780SDimitry Andric       new ScriptedProcess(target_sp, listener_sp, scripted_metadata, error));
63344a3780SDimitry Andric 
647fa27ce4SDimitry Andric   if (error.Fail() || !process_sp || !process_sp->m_interface_up) {
65145449b1SDimitry Andric     LLDB_LOGF(GetLog(LLDBLog::Process), "%s", error.AsCString());
66344a3780SDimitry Andric     return nullptr;
67344a3780SDimitry Andric   }
68344a3780SDimitry Andric 
69344a3780SDimitry Andric   return process_sp;
70344a3780SDimitry Andric }
71344a3780SDimitry Andric 
CanDebug(lldb::TargetSP target_sp,bool plugin_specified_by_name)72344a3780SDimitry Andric bool ScriptedProcess::CanDebug(lldb::TargetSP target_sp,
73344a3780SDimitry Andric                                bool plugin_specified_by_name) {
74344a3780SDimitry Andric   return true;
75344a3780SDimitry Andric }
76344a3780SDimitry Andric 
ScriptedProcess(lldb::TargetSP target_sp,lldb::ListenerSP listener_sp,const ScriptedMetadata & scripted_metadata,Status & error)77e3b55780SDimitry Andric ScriptedProcess::ScriptedProcess(lldb::TargetSP target_sp,
78e3b55780SDimitry Andric                                  lldb::ListenerSP listener_sp,
79e3b55780SDimitry Andric                                  const ScriptedMetadata &scripted_metadata,
80344a3780SDimitry Andric                                  Status &error)
81e3b55780SDimitry Andric     : Process(target_sp, listener_sp), m_scripted_metadata(scripted_metadata) {
82344a3780SDimitry Andric 
83344a3780SDimitry Andric   if (!target_sp) {
84344a3780SDimitry Andric     error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
85344a3780SDimitry Andric                                    __FUNCTION__, "Invalid target");
86344a3780SDimitry Andric     return;
87344a3780SDimitry Andric   }
88344a3780SDimitry Andric 
897fa27ce4SDimitry Andric   ScriptInterpreter *interpreter =
907fa27ce4SDimitry Andric       target_sp->GetDebugger().GetScriptInterpreter();
91344a3780SDimitry Andric 
927fa27ce4SDimitry Andric   if (!interpreter) {
93344a3780SDimitry Andric     error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
94344a3780SDimitry Andric                                    __FUNCTION__,
95344a3780SDimitry Andric                                    "Debugger has no Script Interpreter");
96344a3780SDimitry Andric     return;
97344a3780SDimitry Andric   }
98344a3780SDimitry Andric 
997fa27ce4SDimitry Andric   // Create process instance interface
1007fa27ce4SDimitry Andric   m_interface_up = interpreter->CreateScriptedProcessInterface();
1017fa27ce4SDimitry Andric   if (!m_interface_up) {
1027fa27ce4SDimitry Andric     error.SetErrorStringWithFormat(
1037fa27ce4SDimitry Andric         "ScriptedProcess::%s () - ERROR: %s", __FUNCTION__,
1047fa27ce4SDimitry Andric         "Script interpreter couldn't create Scripted Process Interface");
1057fa27ce4SDimitry Andric     return;
1067fa27ce4SDimitry Andric   }
1077fa27ce4SDimitry Andric 
108c0981da4SDimitry Andric   ExecutionContext exe_ctx(target_sp, /*get_process=*/false);
109c0981da4SDimitry Andric 
1107fa27ce4SDimitry Andric   // Create process script object
111b1c73532SDimitry Andric   auto obj_or_err = GetInterface().CreatePluginObject(
112e3b55780SDimitry Andric       m_scripted_metadata.GetClassName(), exe_ctx,
113e3b55780SDimitry Andric       m_scripted_metadata.GetArgsSP());
114344a3780SDimitry Andric 
115b1c73532SDimitry Andric   if (!obj_or_err) {
116b1c73532SDimitry Andric     llvm::consumeError(obj_or_err.takeError());
117b1c73532SDimitry Andric     error.SetErrorString("Failed to create script object.");
118b1c73532SDimitry Andric     return;
119b1c73532SDimitry Andric   }
120b1c73532SDimitry Andric 
121b1c73532SDimitry Andric   StructuredData::GenericSP object_sp = *obj_or_err;
122b1c73532SDimitry Andric 
123344a3780SDimitry Andric   if (!object_sp || !object_sp->IsValid()) {
124344a3780SDimitry Andric     error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
125344a3780SDimitry Andric                                    __FUNCTION__,
126344a3780SDimitry Andric                                    "Failed to create valid script object");
127344a3780SDimitry Andric     return;
128344a3780SDimitry Andric   }
129344a3780SDimitry Andric }
130344a3780SDimitry Andric 
~ScriptedProcess()131344a3780SDimitry Andric ScriptedProcess::~ScriptedProcess() {
132344a3780SDimitry Andric   Clear();
133b1c73532SDimitry Andric   // If the interface is not valid, we can't call Finalize(). When that happens
134b1c73532SDimitry Andric   // it means that the Scripted Process instanciation failed and the
135b1c73532SDimitry Andric   // CreateProcess function returns a nullptr, so no one besides this class
136b1c73532SDimitry Andric   // should have access to that bogus process object.
137b1c73532SDimitry Andric   if (!m_interface_up)
138b1c73532SDimitry Andric     return;
139344a3780SDimitry Andric   // We need to call finalize on the process before destroying ourselves to
140344a3780SDimitry Andric   // make sure all of the broadcaster cleanup goes as planned. If we destruct
141344a3780SDimitry Andric   // this class, then Process::~Process() might have problems trying to fully
142344a3780SDimitry Andric   // destroy the broadcaster.
143b1c73532SDimitry Andric   Finalize(true /* destructing */);
144344a3780SDimitry Andric }
145344a3780SDimitry Andric 
Initialize()146344a3780SDimitry Andric void ScriptedProcess::Initialize() {
147344a3780SDimitry Andric   static llvm::once_flag g_once_flag;
148344a3780SDimitry Andric 
149344a3780SDimitry Andric   llvm::call_once(g_once_flag, []() {
150344a3780SDimitry Andric     PluginManager::RegisterPlugin(GetPluginNameStatic(),
151344a3780SDimitry Andric                                   GetPluginDescriptionStatic(), CreateInstance);
152344a3780SDimitry Andric   });
153344a3780SDimitry Andric }
154344a3780SDimitry Andric 
Terminate()155344a3780SDimitry Andric void ScriptedProcess::Terminate() {
156344a3780SDimitry Andric   PluginManager::UnregisterPlugin(ScriptedProcess::CreateInstance);
157344a3780SDimitry Andric }
158344a3780SDimitry Andric 
DoLoadCore()159344a3780SDimitry Andric Status ScriptedProcess::DoLoadCore() {
160344a3780SDimitry Andric   ProcessLaunchInfo launch_info = GetTarget().GetProcessLaunchInfo();
161344a3780SDimitry Andric 
162344a3780SDimitry Andric   return DoLaunch(nullptr, launch_info);
163344a3780SDimitry Andric }
164344a3780SDimitry Andric 
DoLaunch(Module * exe_module,ProcessLaunchInfo & launch_info)165344a3780SDimitry Andric Status ScriptedProcess::DoLaunch(Module *exe_module,
166344a3780SDimitry Andric                                  ProcessLaunchInfo &launch_info) {
1677fa27ce4SDimitry Andric   LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s launching process", __FUNCTION__);
168344a3780SDimitry Andric 
1697fa27ce4SDimitry Andric   /* MARK: This doesn't reflect how lldb actually launches a process.
1707fa27ce4SDimitry Andric            In reality, it attaches to debugserver, then resume the process.
1717fa27ce4SDimitry Andric            That's not true in all cases.  If debugserver is remote, lldb
1727fa27ce4SDimitry Andric            asks debugserver to launch the process for it. */
173344a3780SDimitry Andric   Status error = GetInterface().Launch();
174344a3780SDimitry Andric   SetPrivateState(eStateStopped);
1757fa27ce4SDimitry Andric   return error;
176344a3780SDimitry Andric }
177344a3780SDimitry Andric 
DidLaunch()1787fa27ce4SDimitry Andric void ScriptedProcess::DidLaunch() { m_pid = GetInterface().GetProcessID(); }
1797fa27ce4SDimitry Andric 
DidResume()1807fa27ce4SDimitry Andric void ScriptedProcess::DidResume() {
1817fa27ce4SDimitry Andric   // Update the PID again, in case the user provided a placeholder pid at launch
182344a3780SDimitry Andric   m_pid = GetInterface().GetProcessID();
183344a3780SDimitry Andric }
184344a3780SDimitry Andric 
DoResume()185344a3780SDimitry Andric Status ScriptedProcess::DoResume() {
1867fa27ce4SDimitry Andric   LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s resuming process", __FUNCTION__);
187344a3780SDimitry Andric 
1887fa27ce4SDimitry Andric   return GetInterface().Resume();
1897fa27ce4SDimitry Andric }
190344a3780SDimitry Andric 
DoAttach(const ProcessAttachInfo & attach_info)1917fa27ce4SDimitry Andric Status ScriptedProcess::DoAttach(const ProcessAttachInfo &attach_info) {
1927fa27ce4SDimitry Andric   Status error = GetInterface().Attach(attach_info);
193344a3780SDimitry Andric   SetPrivateState(eStateRunning);
194344a3780SDimitry Andric   SetPrivateState(eStateStopped);
1957fa27ce4SDimitry Andric   if (error.Fail())
196344a3780SDimitry Andric     return error;
1977fa27ce4SDimitry Andric   // NOTE: We need to set the PID before finishing to attach otherwise we will
1987fa27ce4SDimitry Andric   // hit an assert when calling the attach completion handler.
1997fa27ce4SDimitry Andric   DidLaunch();
200344a3780SDimitry Andric 
201344a3780SDimitry Andric   return {};
202344a3780SDimitry Andric }
203344a3780SDimitry Andric 
2047fa27ce4SDimitry Andric Status
DoAttachToProcessWithID(lldb::pid_t pid,const ProcessAttachInfo & attach_info)2057fa27ce4SDimitry Andric ScriptedProcess::DoAttachToProcessWithID(lldb::pid_t pid,
2067fa27ce4SDimitry Andric                                          const ProcessAttachInfo &attach_info) {
2077fa27ce4SDimitry Andric   return DoAttach(attach_info);
2087fa27ce4SDimitry Andric }
2097fa27ce4SDimitry Andric 
DoAttachToProcessWithName(const char * process_name,const ProcessAttachInfo & attach_info)2107fa27ce4SDimitry Andric Status ScriptedProcess::DoAttachToProcessWithName(
2117fa27ce4SDimitry Andric     const char *process_name, const ProcessAttachInfo &attach_info) {
2127fa27ce4SDimitry Andric   return DoAttach(attach_info);
2137fa27ce4SDimitry Andric }
2147fa27ce4SDimitry Andric 
DidAttach(ArchSpec & process_arch)2157fa27ce4SDimitry Andric void ScriptedProcess::DidAttach(ArchSpec &process_arch) {
2167fa27ce4SDimitry Andric   process_arch = GetArchitecture();
217344a3780SDimitry Andric }
218344a3780SDimitry Andric 
DoDestroy()219344a3780SDimitry Andric Status ScriptedProcess::DoDestroy() { return Status(); }
220344a3780SDimitry Andric 
IsAlive()2217fa27ce4SDimitry Andric bool ScriptedProcess::IsAlive() { return GetInterface().IsAlive(); }
222344a3780SDimitry Andric 
DoReadMemory(lldb::addr_t addr,void * buf,size_t size,Status & error)223344a3780SDimitry Andric size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
224344a3780SDimitry Andric                                      Status &error) {
225344a3780SDimitry Andric   lldb::DataExtractorSP data_extractor_sp =
226344a3780SDimitry Andric       GetInterface().ReadMemoryAtAddress(addr, size, error);
227344a3780SDimitry Andric 
228c0981da4SDimitry Andric   if (!data_extractor_sp || !data_extractor_sp->GetByteSize() || error.Fail())
229344a3780SDimitry Andric     return 0;
230344a3780SDimitry Andric 
231344a3780SDimitry Andric   offset_t bytes_copied = data_extractor_sp->CopyByteOrderedData(
232344a3780SDimitry Andric       0, data_extractor_sp->GetByteSize(), buf, size, GetByteOrder());
233344a3780SDimitry Andric 
234344a3780SDimitry Andric   if (!bytes_copied || bytes_copied == LLDB_INVALID_OFFSET)
2356f8fc217SDimitry Andric     return ScriptedInterface::ErrorWithMessage<size_t>(
236c0981da4SDimitry Andric         LLVM_PRETTY_FUNCTION, "Failed to copy read memory to buffer.", error);
237344a3780SDimitry Andric 
2387fa27ce4SDimitry Andric   // FIXME: We should use the diagnostic system to report a warning if the
2397fa27ce4SDimitry Andric   // `bytes_copied` is different from `size`.
2407fa27ce4SDimitry Andric 
2417fa27ce4SDimitry Andric   return bytes_copied;
2427fa27ce4SDimitry Andric }
2437fa27ce4SDimitry Andric 
DoWriteMemory(lldb::addr_t vm_addr,const void * buf,size_t size,Status & error)2447fa27ce4SDimitry Andric size_t ScriptedProcess::DoWriteMemory(lldb::addr_t vm_addr, const void *buf,
2457fa27ce4SDimitry Andric                                       size_t size, Status &error) {
2467fa27ce4SDimitry Andric   lldb::DataExtractorSP data_extractor_sp = std::make_shared<DataExtractor>(
2477fa27ce4SDimitry Andric       buf, size, GetByteOrder(), GetAddressByteSize());
2487fa27ce4SDimitry Andric 
2497fa27ce4SDimitry Andric   if (!data_extractor_sp || !data_extractor_sp->GetByteSize())
2507fa27ce4SDimitry Andric     return 0;
2517fa27ce4SDimitry Andric 
2527fa27ce4SDimitry Andric   lldb::offset_t bytes_written =
2537fa27ce4SDimitry Andric       GetInterface().WriteMemoryAtAddress(vm_addr, data_extractor_sp, error);
2547fa27ce4SDimitry Andric 
2557fa27ce4SDimitry Andric   if (!bytes_written || bytes_written == LLDB_INVALID_OFFSET)
2567fa27ce4SDimitry Andric     return ScriptedInterface::ErrorWithMessage<size_t>(
2577fa27ce4SDimitry Andric         LLVM_PRETTY_FUNCTION, "Failed to copy write buffer to memory.", error);
2587fa27ce4SDimitry Andric 
2597fa27ce4SDimitry Andric   // FIXME: We should use the diagnostic system to report a warning if the
2607fa27ce4SDimitry Andric   // `bytes_written` is different from `size`.
2617fa27ce4SDimitry Andric 
2627fa27ce4SDimitry Andric   return bytes_written;
2637fa27ce4SDimitry Andric }
2647fa27ce4SDimitry Andric 
EnableBreakpointSite(BreakpointSite * bp_site)2657fa27ce4SDimitry Andric Status ScriptedProcess::EnableBreakpointSite(BreakpointSite *bp_site) {
2667fa27ce4SDimitry Andric   assert(bp_site != nullptr);
2677fa27ce4SDimitry Andric 
2687fa27ce4SDimitry Andric   if (bp_site->IsEnabled()) {
2697fa27ce4SDimitry Andric     return {};
2707fa27ce4SDimitry Andric   }
2717fa27ce4SDimitry Andric 
2727fa27ce4SDimitry Andric   if (bp_site->HardwareRequired()) {
2737fa27ce4SDimitry Andric     return Status("Scripted Processes don't support hardware breakpoints");
2747fa27ce4SDimitry Andric   }
2757fa27ce4SDimitry Andric 
2767fa27ce4SDimitry Andric   Status error;
2777fa27ce4SDimitry Andric   GetInterface().CreateBreakpoint(bp_site->GetLoadAddress(), error);
2787fa27ce4SDimitry Andric 
2797fa27ce4SDimitry Andric   return error;
280344a3780SDimitry Andric }
281344a3780SDimitry Andric 
GetArchitecture()282344a3780SDimitry Andric ArchSpec ScriptedProcess::GetArchitecture() {
283344a3780SDimitry Andric   return GetTarget().GetArchitecture();
284344a3780SDimitry Andric }
285344a3780SDimitry Andric 
DoGetMemoryRegionInfo(lldb::addr_t load_addr,MemoryRegionInfo & region)286145449b1SDimitry Andric Status ScriptedProcess::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
287344a3780SDimitry Andric                                               MemoryRegionInfo &region) {
288c0981da4SDimitry Andric   Status error;
289c0981da4SDimitry Andric   if (auto region_or_err =
290c0981da4SDimitry Andric           GetInterface().GetMemoryRegionContainingAddress(load_addr, error))
291c0981da4SDimitry Andric     region = *region_or_err;
292c0981da4SDimitry Andric 
293c0981da4SDimitry Andric   return error;
294344a3780SDimitry Andric }
295344a3780SDimitry Andric 
GetMemoryRegions(MemoryRegionInfos & region_list)296344a3780SDimitry Andric Status ScriptedProcess::GetMemoryRegions(MemoryRegionInfos &region_list) {
297c0981da4SDimitry Andric   Status error;
298344a3780SDimitry Andric   lldb::addr_t address = 0;
299344a3780SDimitry Andric 
300c0981da4SDimitry Andric   while (auto region_or_err =
301c0981da4SDimitry Andric              GetInterface().GetMemoryRegionContainingAddress(address, error)) {
302c0981da4SDimitry Andric     if (error.Fail())
303c0981da4SDimitry Andric       break;
304c0981da4SDimitry Andric 
305c0981da4SDimitry Andric     MemoryRegionInfo &mem_region = *region_or_err;
306c0981da4SDimitry Andric     auto range = mem_region.GetRange();
307344a3780SDimitry Andric     address += range.GetRangeBase() + range.GetByteSize();
308c0981da4SDimitry Andric     region_list.push_back(mem_region);
309344a3780SDimitry Andric   }
310344a3780SDimitry Andric 
311c0981da4SDimitry Andric   return error;
312344a3780SDimitry Andric }
313344a3780SDimitry Andric 
Clear()314344a3780SDimitry Andric void ScriptedProcess::Clear() { Process::m_thread_list.Clear(); }
315344a3780SDimitry Andric 
DoUpdateThreadList(ThreadList & old_thread_list,ThreadList & new_thread_list)316344a3780SDimitry Andric bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list,
317344a3780SDimitry Andric                                          ThreadList &new_thread_list) {
318344a3780SDimitry Andric   // TODO: Implement
319344a3780SDimitry Andric   // This is supposed to get the current set of threads, if any of them are in
320344a3780SDimitry Andric   // old_thread_list then they get copied to new_thread_list, and then any
321344a3780SDimitry Andric   // actually new threads will get added to new_thread_list.
322c0981da4SDimitry Andric   m_thread_plans.ClearThreadCache();
323c0981da4SDimitry Andric 
324c0981da4SDimitry Andric   Status error;
3256f8fc217SDimitry Andric   StructuredData::DictionarySP thread_info_sp = GetInterface().GetThreadsInfo();
326c0981da4SDimitry Andric 
3276f8fc217SDimitry Andric   if (!thread_info_sp)
3286f8fc217SDimitry Andric     return ScriptedInterface::ErrorWithMessage<bool>(
3296f8fc217SDimitry Andric         LLVM_PRETTY_FUNCTION,
3306f8fc217SDimitry Andric         "Couldn't fetch thread list from Scripted Process.", error);
3316f8fc217SDimitry Andric 
332145449b1SDimitry Andric   // Because `StructuredData::Dictionary` uses a `std::map<ConstString,
333145449b1SDimitry Andric   // ObjectSP>` for storage, each item is sorted based on the key alphabetical
334145449b1SDimitry Andric   // order. Since `GetThreadsInfo` provides thread indices as the key element,
335145449b1SDimitry Andric   // thread info comes ordered alphabetically, instead of numerically, so we
336145449b1SDimitry Andric   // need to sort the thread indices before creating thread.
337145449b1SDimitry Andric 
338145449b1SDimitry Andric   StructuredData::ArraySP keys = thread_info_sp->GetKeys();
339145449b1SDimitry Andric 
340145449b1SDimitry Andric   std::map<size_t, StructuredData::ObjectSP> sorted_threads;
341145449b1SDimitry Andric   auto sort_keys = [&sorted_threads,
342145449b1SDimitry Andric                     &thread_info_sp](StructuredData::Object *item) -> bool {
343145449b1SDimitry Andric     if (!item)
344145449b1SDimitry Andric       return false;
345145449b1SDimitry Andric 
346145449b1SDimitry Andric     llvm::StringRef key = item->GetStringValue();
347145449b1SDimitry Andric     size_t idx = 0;
348145449b1SDimitry Andric 
349145449b1SDimitry Andric     // Make sure the provided index is actually an integer
350145449b1SDimitry Andric     if (!llvm::to_integer(key, idx))
351145449b1SDimitry Andric       return false;
352145449b1SDimitry Andric 
353145449b1SDimitry Andric     sorted_threads[idx] = thread_info_sp->GetValueForKey(key);
354145449b1SDimitry Andric     return true;
355145449b1SDimitry Andric   };
356145449b1SDimitry Andric 
357145449b1SDimitry Andric   size_t thread_count = thread_info_sp->GetSize();
358145449b1SDimitry Andric 
359145449b1SDimitry Andric   if (!keys->ForEach(sort_keys) || sorted_threads.size() != thread_count)
360145449b1SDimitry Andric     // Might be worth showing the unsorted thread list instead of return early.
361145449b1SDimitry Andric     return ScriptedInterface::ErrorWithMessage<bool>(
362145449b1SDimitry Andric         LLVM_PRETTY_FUNCTION, "Couldn't sort thread list.", error);
363145449b1SDimitry Andric 
3646f8fc217SDimitry Andric   auto create_scripted_thread =
365145449b1SDimitry Andric       [this, &error, &new_thread_list](
366145449b1SDimitry Andric           const std::pair<size_t, StructuredData::ObjectSP> pair) -> bool {
367145449b1SDimitry Andric     size_t idx = pair.first;
368145449b1SDimitry Andric     StructuredData::ObjectSP object_sp = pair.second;
369145449b1SDimitry Andric 
370145449b1SDimitry Andric     if (!object_sp)
3716f8fc217SDimitry Andric       return ScriptedInterface::ErrorWithMessage<bool>(
3726f8fc217SDimitry Andric           LLVM_PRETTY_FUNCTION, "Invalid thread info object", error);
3736f8fc217SDimitry Andric 
374145449b1SDimitry Andric     auto thread_or_error =
375145449b1SDimitry Andric         ScriptedThread::Create(*this, object_sp->GetAsGeneric());
3766f8fc217SDimitry Andric 
3776f8fc217SDimitry Andric     if (!thread_or_error)
3786f8fc217SDimitry Andric       return ScriptedInterface::ErrorWithMessage<bool>(
3796f8fc217SDimitry Andric           LLVM_PRETTY_FUNCTION, toString(thread_or_error.takeError()), error);
3806f8fc217SDimitry Andric 
3816f8fc217SDimitry Andric     ThreadSP thread_sp = thread_or_error.get();
3826f8fc217SDimitry Andric     lldbassert(thread_sp && "Couldn't initialize scripted thread.");
383c0981da4SDimitry Andric 
38477fc4c14SDimitry Andric     RegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext();
38577fc4c14SDimitry Andric     if (!reg_ctx_sp)
3866f8fc217SDimitry Andric       return ScriptedInterface::ErrorWithMessage<bool>(
3876f8fc217SDimitry Andric           LLVM_PRETTY_FUNCTION,
388145449b1SDimitry Andric           llvm::Twine("Invalid Register Context for thread " + llvm::Twine(idx))
3896f8fc217SDimitry Andric               .str(),
3906f8fc217SDimitry Andric           error);
39177fc4c14SDimitry Andric 
392c0981da4SDimitry Andric     new_thread_list.AddThread(thread_sp);
393c0981da4SDimitry Andric 
3946f8fc217SDimitry Andric     return true;
3956f8fc217SDimitry Andric   };
3966f8fc217SDimitry Andric 
397145449b1SDimitry Andric   llvm::for_each(sorted_threads, create_scripted_thread);
3986f8fc217SDimitry Andric 
399344a3780SDimitry Andric   return new_thread_list.GetSize(false) > 0;
400344a3780SDimitry Andric }
401344a3780SDimitry Andric 
RefreshStateAfterStop()402c0981da4SDimitry Andric void ScriptedProcess::RefreshStateAfterStop() {
403c0981da4SDimitry Andric   // Let all threads recover from stopping and do any clean up based on the
404c0981da4SDimitry Andric   // previous thread state (if any).
405145449b1SDimitry Andric   m_thread_list.RefreshStateAfterStop();
406c0981da4SDimitry Andric }
407c0981da4SDimitry Andric 
GetProcessInfo(ProcessInstanceInfo & info)408344a3780SDimitry Andric bool ScriptedProcess::GetProcessInfo(ProcessInstanceInfo &info) {
409344a3780SDimitry Andric   info.Clear();
410344a3780SDimitry Andric   info.SetProcessID(GetID());
411344a3780SDimitry Andric   info.SetArchitecture(GetArchitecture());
412344a3780SDimitry Andric   lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();
413344a3780SDimitry Andric   if (module_sp) {
414344a3780SDimitry Andric     const bool add_exe_file_as_first_arg = false;
415344a3780SDimitry Andric     info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),
416344a3780SDimitry Andric                            add_exe_file_as_first_arg);
417344a3780SDimitry Andric   }
418344a3780SDimitry Andric   return true;
419344a3780SDimitry Andric }
420344a3780SDimitry Andric 
421145449b1SDimitry Andric lldb_private::StructuredData::ObjectSP
GetLoadedDynamicLibrariesInfos()422145449b1SDimitry Andric ScriptedProcess::GetLoadedDynamicLibrariesInfos() {
423145449b1SDimitry Andric   Status error;
424145449b1SDimitry Andric   auto error_with_message = [&error](llvm::StringRef message) {
425145449b1SDimitry Andric     return ScriptedInterface::ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION,
426145449b1SDimitry Andric                                                      message.data(), error);
427145449b1SDimitry Andric   };
428145449b1SDimitry Andric 
429145449b1SDimitry Andric   StructuredData::ArraySP loaded_images_sp = GetInterface().GetLoadedImages();
430145449b1SDimitry Andric 
431145449b1SDimitry Andric   if (!loaded_images_sp || !loaded_images_sp->GetSize())
432e3b55780SDimitry Andric     return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(
433145449b1SDimitry Andric         LLVM_PRETTY_FUNCTION, "No loaded images.", error);
434145449b1SDimitry Andric 
435145449b1SDimitry Andric   ModuleList module_list;
436145449b1SDimitry Andric   Target &target = GetTarget();
437145449b1SDimitry Andric 
438145449b1SDimitry Andric   auto reload_image = [&target, &module_list, &error_with_message](
439145449b1SDimitry Andric                           StructuredData::Object *obj) -> bool {
440145449b1SDimitry Andric     StructuredData::Dictionary *dict = obj->GetAsDictionary();
441145449b1SDimitry Andric 
442145449b1SDimitry Andric     if (!dict)
443145449b1SDimitry Andric       return error_with_message("Couldn't cast image object into dictionary.");
444145449b1SDimitry Andric 
445145449b1SDimitry Andric     ModuleSpec module_spec;
446145449b1SDimitry Andric     llvm::StringRef value;
447145449b1SDimitry Andric 
448145449b1SDimitry Andric     bool has_path = dict->HasKey("path");
449145449b1SDimitry Andric     bool has_uuid = dict->HasKey("uuid");
450145449b1SDimitry Andric     if (!has_path && !has_uuid)
451145449b1SDimitry Andric       return error_with_message("Dictionary should have key 'path' or 'uuid'");
452145449b1SDimitry Andric     if (!dict->HasKey("load_addr"))
453145449b1SDimitry Andric       return error_with_message("Dictionary is missing key 'load_addr'");
454145449b1SDimitry Andric 
455145449b1SDimitry Andric     if (has_path) {
456145449b1SDimitry Andric       dict->GetValueForKeyAsString("path", value);
457145449b1SDimitry Andric       module_spec.GetFileSpec().SetPath(value);
458145449b1SDimitry Andric     }
459145449b1SDimitry Andric 
460145449b1SDimitry Andric     if (has_uuid) {
461145449b1SDimitry Andric       dict->GetValueForKeyAsString("uuid", value);
462145449b1SDimitry Andric       module_spec.GetUUID().SetFromStringRef(value);
463145449b1SDimitry Andric     }
464145449b1SDimitry Andric     module_spec.GetArchitecture() = target.GetArchitecture();
465145449b1SDimitry Andric 
466145449b1SDimitry Andric     ModuleSP module_sp =
467145449b1SDimitry Andric         target.GetOrCreateModule(module_spec, true /* notify */);
468145449b1SDimitry Andric 
469145449b1SDimitry Andric     if (!module_sp)
470145449b1SDimitry Andric       return error_with_message("Couldn't create or get module.");
471145449b1SDimitry Andric 
472145449b1SDimitry Andric     lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
4737fa27ce4SDimitry Andric     lldb::offset_t slide = LLDB_INVALID_OFFSET;
474145449b1SDimitry Andric     dict->GetValueForKeyAsInteger("load_addr", load_addr);
475145449b1SDimitry Andric     dict->GetValueForKeyAsInteger("slide", slide);
476145449b1SDimitry Andric     if (load_addr == LLDB_INVALID_ADDRESS)
477145449b1SDimitry Andric       return error_with_message(
478145449b1SDimitry Andric           "Couldn't get valid load address or slide offset.");
479145449b1SDimitry Andric 
480145449b1SDimitry Andric     if (slide != LLDB_INVALID_OFFSET)
481145449b1SDimitry Andric       load_addr += slide;
482145449b1SDimitry Andric 
483145449b1SDimitry Andric     bool changed = false;
484145449b1SDimitry Andric     module_sp->SetLoadAddress(target, load_addr, false /*=value_is_offset*/,
485145449b1SDimitry Andric                               changed);
486145449b1SDimitry Andric 
487145449b1SDimitry Andric     if (!changed && !module_sp->GetObjectFile())
488145449b1SDimitry Andric       return error_with_message("Couldn't set the load address for module.");
489145449b1SDimitry Andric 
490145449b1SDimitry Andric     dict->GetValueForKeyAsString("path", value);
491145449b1SDimitry Andric     FileSpec objfile(value);
492145449b1SDimitry Andric     module_sp->SetFileSpecAndObjectName(objfile, objfile.GetFilename());
493145449b1SDimitry Andric 
494145449b1SDimitry Andric     return module_list.AppendIfNeeded(module_sp);
495145449b1SDimitry Andric   };
496145449b1SDimitry Andric 
497145449b1SDimitry Andric   if (!loaded_images_sp->ForEach(reload_image))
498e3b55780SDimitry Andric     return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(
499145449b1SDimitry Andric         LLVM_PRETTY_FUNCTION, "Couldn't reload all images.", error);
500145449b1SDimitry Andric 
501145449b1SDimitry Andric   target.ModulesDidLoad(module_list);
502145449b1SDimitry Andric 
503145449b1SDimitry Andric   return loaded_images_sp;
504145449b1SDimitry Andric }
505145449b1SDimitry Andric 
GetMetadata()506e3b55780SDimitry Andric lldb_private::StructuredData::DictionarySP ScriptedProcess::GetMetadata() {
507e3b55780SDimitry Andric   StructuredData::DictionarySP metadata_sp = GetInterface().GetMetadata();
508e3b55780SDimitry Andric 
509e3b55780SDimitry Andric   Status error;
510e3b55780SDimitry Andric   if (!metadata_sp || !metadata_sp->GetSize())
511e3b55780SDimitry Andric     return ScriptedInterface::ErrorWithMessage<StructuredData::DictionarySP>(
512e3b55780SDimitry Andric         LLVM_PRETTY_FUNCTION, "No metadata.", error);
513e3b55780SDimitry Andric 
514e3b55780SDimitry Andric   return metadata_sp;
515e3b55780SDimitry Andric }
516e3b55780SDimitry Andric 
UpdateQueueListIfNeeded()517e3b55780SDimitry Andric void ScriptedProcess::UpdateQueueListIfNeeded() {
5187fa27ce4SDimitry Andric   CheckScriptedInterface();
519e3b55780SDimitry Andric   for (ThreadSP thread_sp : Threads()) {
520e3b55780SDimitry Andric     if (const char *queue_name = thread_sp->GetQueueName()) {
521e3b55780SDimitry Andric       QueueSP queue_sp = std::make_shared<Queue>(
522e3b55780SDimitry Andric           m_process->shared_from_this(), thread_sp->GetQueueID(), queue_name);
523e3b55780SDimitry Andric       m_queue_list.AddQueue(queue_sp);
524e3b55780SDimitry Andric     }
525e3b55780SDimitry Andric   }
526e3b55780SDimitry Andric }
527e3b55780SDimitry Andric 
GetInterface() const528344a3780SDimitry Andric ScriptedProcessInterface &ScriptedProcess::GetInterface() const {
5297fa27ce4SDimitry Andric   CheckScriptedInterface();
5307fa27ce4SDimitry Andric   return *m_interface_up;
5317fa27ce4SDimitry Andric }
5327fa27ce4SDimitry Andric 
GetImplementation()5337fa27ce4SDimitry Andric void *ScriptedProcess::GetImplementation() {
5347fa27ce4SDimitry Andric   StructuredData::GenericSP object_instance_sp =
5357fa27ce4SDimitry Andric       GetInterface().GetScriptObjectInstance();
5367fa27ce4SDimitry Andric   if (object_instance_sp &&
5377fa27ce4SDimitry Andric       object_instance_sp->GetType() == eStructuredDataTypeGeneric)
5387fa27ce4SDimitry Andric     return object_instance_sp->GetAsGeneric()->GetValue();
5397fa27ce4SDimitry Andric   return nullptr;
540344a3780SDimitry Andric }
541