xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1fe6060f1SDimitry Andric //===-- ScriptedProcess.cpp -----------------------------------------------===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric 
9fe6060f1SDimitry Andric #include "ScriptedProcess.h"
10fe6060f1SDimitry Andric 
11fe6060f1SDimitry Andric #include "lldb/Core/Debugger.h"
12fe6060f1SDimitry Andric #include "lldb/Core/Module.h"
13fe6060f1SDimitry Andric #include "lldb/Core/PluginManager.h"
14fe6060f1SDimitry Andric 
15fe6060f1SDimitry Andric #include "lldb/Host/OptionParser.h"
16fe6060f1SDimitry Andric #include "lldb/Host/ThreadLauncher.h"
17fe6060f1SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h"
18fe6060f1SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
19fe6060f1SDimitry Andric #include "lldb/Interpreter/OptionGroupBoolean.h"
20fe6060f1SDimitry Andric #include "lldb/Interpreter/ScriptInterpreter.h"
21fe6060f1SDimitry Andric #include "lldb/Target/MemoryRegionInfo.h"
22bdd1243dSDimitry Andric #include "lldb/Target/Queue.h"
23fe6060f1SDimitry Andric #include "lldb/Target/RegisterContext.h"
2481ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
2506c3fb27SDimitry Andric #include "lldb/Utility/ScriptedMetadata.h"
26fe6060f1SDimitry Andric #include "lldb/Utility/State.h"
27fe6060f1SDimitry Andric 
28fe6060f1SDimitry Andric #include <mutex>
29fe6060f1SDimitry Andric 
30fe6060f1SDimitry Andric LLDB_PLUGIN_DEFINE(ScriptedProcess)
31fe6060f1SDimitry Andric 
32fe6060f1SDimitry Andric using namespace lldb;
33fe6060f1SDimitry Andric using namespace lldb_private;
34fe6060f1SDimitry Andric 
GetPluginDescriptionStatic()35349cc55cSDimitry Andric llvm::StringRef ScriptedProcess::GetPluginDescriptionStatic() {
36fe6060f1SDimitry Andric   return "Scripted Process plug-in.";
37fe6060f1SDimitry Andric }
38fe6060f1SDimitry Andric 
39fe6060f1SDimitry Andric static constexpr lldb::ScriptLanguage g_supported_script_languages[] = {
40fe6060f1SDimitry Andric     ScriptLanguage::eScriptLanguagePython,
41fe6060f1SDimitry Andric };
42fe6060f1SDimitry Andric 
IsScriptLanguageSupported(lldb::ScriptLanguage language)43fe6060f1SDimitry Andric bool ScriptedProcess::IsScriptLanguageSupported(lldb::ScriptLanguage language) {
44fe6060f1SDimitry Andric   llvm::ArrayRef<lldb::ScriptLanguage> supported_languages =
45bdd1243dSDimitry Andric       llvm::ArrayRef(g_supported_script_languages);
46fe6060f1SDimitry Andric 
47fe6060f1SDimitry Andric   return llvm::is_contained(supported_languages, language);
48fe6060f1SDimitry Andric }
49fe6060f1SDimitry Andric 
CreateInstance(lldb::TargetSP target_sp,lldb::ListenerSP listener_sp,const FileSpec * file,bool can_connect)50fe6060f1SDimitry Andric lldb::ProcessSP ScriptedProcess::CreateInstance(lldb::TargetSP target_sp,
51fe6060f1SDimitry Andric                                                 lldb::ListenerSP listener_sp,
52fe6060f1SDimitry Andric                                                 const FileSpec *file,
53fe6060f1SDimitry Andric                                                 bool can_connect) {
54fe6060f1SDimitry Andric   if (!target_sp ||
55fe6060f1SDimitry Andric       !IsScriptLanguageSupported(target_sp->GetDebugger().GetScriptLanguage()))
56fe6060f1SDimitry Andric     return nullptr;
57fe6060f1SDimitry Andric 
58bdd1243dSDimitry Andric   ScriptedMetadata scripted_metadata(target_sp->GetProcessLaunchInfo());
59fe6060f1SDimitry Andric 
60bdd1243dSDimitry Andric   Status error;
61bdd1243dSDimitry Andric   auto process_sp = std::shared_ptr<ScriptedProcess>(
62bdd1243dSDimitry Andric       new ScriptedProcess(target_sp, listener_sp, scripted_metadata, error));
63fe6060f1SDimitry Andric 
6406c3fb27SDimitry Andric   if (error.Fail() || !process_sp || !process_sp->m_interface_up) {
6581ad6265SDimitry Andric     LLDB_LOGF(GetLog(LLDBLog::Process), "%s", error.AsCString());
66fe6060f1SDimitry Andric     return nullptr;
67fe6060f1SDimitry Andric   }
68fe6060f1SDimitry Andric 
69fe6060f1SDimitry Andric   return process_sp;
70fe6060f1SDimitry Andric }
71fe6060f1SDimitry Andric 
CanDebug(lldb::TargetSP target_sp,bool plugin_specified_by_name)72fe6060f1SDimitry Andric bool ScriptedProcess::CanDebug(lldb::TargetSP target_sp,
73fe6060f1SDimitry Andric                                bool plugin_specified_by_name) {
74fe6060f1SDimitry Andric   return true;
75fe6060f1SDimitry Andric }
76fe6060f1SDimitry Andric 
ScriptedProcess(lldb::TargetSP target_sp,lldb::ListenerSP listener_sp,const ScriptedMetadata & scripted_metadata,Status & error)77bdd1243dSDimitry Andric ScriptedProcess::ScriptedProcess(lldb::TargetSP target_sp,
78bdd1243dSDimitry Andric                                  lldb::ListenerSP listener_sp,
79bdd1243dSDimitry Andric                                  const ScriptedMetadata &scripted_metadata,
80fe6060f1SDimitry Andric                                  Status &error)
81bdd1243dSDimitry Andric     : Process(target_sp, listener_sp), m_scripted_metadata(scripted_metadata) {
82fe6060f1SDimitry Andric 
83fe6060f1SDimitry Andric   if (!target_sp) {
84fe6060f1SDimitry Andric     error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
85fe6060f1SDimitry Andric                                    __FUNCTION__, "Invalid target");
86fe6060f1SDimitry Andric     return;
87fe6060f1SDimitry Andric   }
88fe6060f1SDimitry Andric 
8906c3fb27SDimitry Andric   ScriptInterpreter *interpreter =
9006c3fb27SDimitry Andric       target_sp->GetDebugger().GetScriptInterpreter();
91fe6060f1SDimitry Andric 
9206c3fb27SDimitry Andric   if (!interpreter) {
93fe6060f1SDimitry Andric     error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
94fe6060f1SDimitry Andric                                    __FUNCTION__,
95fe6060f1SDimitry Andric                                    "Debugger has no Script Interpreter");
96fe6060f1SDimitry Andric     return;
97fe6060f1SDimitry Andric   }
98fe6060f1SDimitry Andric 
9906c3fb27SDimitry Andric   // Create process instance interface
10006c3fb27SDimitry Andric   m_interface_up = interpreter->CreateScriptedProcessInterface();
10106c3fb27SDimitry Andric   if (!m_interface_up) {
10206c3fb27SDimitry Andric     error.SetErrorStringWithFormat(
10306c3fb27SDimitry Andric         "ScriptedProcess::%s () - ERROR: %s", __FUNCTION__,
10406c3fb27SDimitry Andric         "Script interpreter couldn't create Scripted Process Interface");
10506c3fb27SDimitry Andric     return;
10606c3fb27SDimitry Andric   }
10706c3fb27SDimitry Andric 
108349cc55cSDimitry Andric   ExecutionContext exe_ctx(target_sp, /*get_process=*/false);
109349cc55cSDimitry Andric 
11006c3fb27SDimitry Andric   // Create process script object
111*5f757f3fSDimitry Andric   auto obj_or_err = GetInterface().CreatePluginObject(
112bdd1243dSDimitry Andric       m_scripted_metadata.GetClassName(), exe_ctx,
113bdd1243dSDimitry Andric       m_scripted_metadata.GetArgsSP());
114fe6060f1SDimitry Andric 
115*5f757f3fSDimitry Andric   if (!obj_or_err) {
116*5f757f3fSDimitry Andric     llvm::consumeError(obj_or_err.takeError());
117*5f757f3fSDimitry Andric     error.SetErrorString("Failed to create script object.");
118*5f757f3fSDimitry Andric     return;
119*5f757f3fSDimitry Andric   }
120*5f757f3fSDimitry Andric 
121*5f757f3fSDimitry Andric   StructuredData::GenericSP object_sp = *obj_or_err;
122*5f757f3fSDimitry Andric 
123fe6060f1SDimitry Andric   if (!object_sp || !object_sp->IsValid()) {
124fe6060f1SDimitry Andric     error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
125fe6060f1SDimitry Andric                                    __FUNCTION__,
126fe6060f1SDimitry Andric                                    "Failed to create valid script object");
127fe6060f1SDimitry Andric     return;
128fe6060f1SDimitry Andric   }
129fe6060f1SDimitry Andric }
130fe6060f1SDimitry Andric 
~ScriptedProcess()131fe6060f1SDimitry Andric ScriptedProcess::~ScriptedProcess() {
132fe6060f1SDimitry Andric   Clear();
133*5f757f3fSDimitry Andric   // If the interface is not valid, we can't call Finalize(). When that happens
134*5f757f3fSDimitry Andric   // it means that the Scripted Process instanciation failed and the
135*5f757f3fSDimitry Andric   // CreateProcess function returns a nullptr, so no one besides this class
136*5f757f3fSDimitry Andric   // should have access to that bogus process object.
137*5f757f3fSDimitry Andric   if (!m_interface_up)
138*5f757f3fSDimitry Andric     return;
139fe6060f1SDimitry Andric   // We need to call finalize on the process before destroying ourselves to
140fe6060f1SDimitry Andric   // make sure all of the broadcaster cleanup goes as planned. If we destruct
141fe6060f1SDimitry Andric   // this class, then Process::~Process() might have problems trying to fully
142fe6060f1SDimitry Andric   // destroy the broadcaster.
143*5f757f3fSDimitry Andric   Finalize(true /* destructing */);
144fe6060f1SDimitry Andric }
145fe6060f1SDimitry Andric 
Initialize()146fe6060f1SDimitry Andric void ScriptedProcess::Initialize() {
147fe6060f1SDimitry Andric   static llvm::once_flag g_once_flag;
148fe6060f1SDimitry Andric 
149fe6060f1SDimitry Andric   llvm::call_once(g_once_flag, []() {
150fe6060f1SDimitry Andric     PluginManager::RegisterPlugin(GetPluginNameStatic(),
151fe6060f1SDimitry Andric                                   GetPluginDescriptionStatic(), CreateInstance);
152fe6060f1SDimitry Andric   });
153fe6060f1SDimitry Andric }
154fe6060f1SDimitry Andric 
Terminate()155fe6060f1SDimitry Andric void ScriptedProcess::Terminate() {
156fe6060f1SDimitry Andric   PluginManager::UnregisterPlugin(ScriptedProcess::CreateInstance);
157fe6060f1SDimitry Andric }
158fe6060f1SDimitry Andric 
DoLoadCore()159fe6060f1SDimitry Andric Status ScriptedProcess::DoLoadCore() {
160fe6060f1SDimitry Andric   ProcessLaunchInfo launch_info = GetTarget().GetProcessLaunchInfo();
161fe6060f1SDimitry Andric 
162fe6060f1SDimitry Andric   return DoLaunch(nullptr, launch_info);
163fe6060f1SDimitry Andric }
164fe6060f1SDimitry Andric 
DoLaunch(Module * exe_module,ProcessLaunchInfo & launch_info)165fe6060f1SDimitry Andric Status ScriptedProcess::DoLaunch(Module *exe_module,
166fe6060f1SDimitry Andric                                  ProcessLaunchInfo &launch_info) {
16706c3fb27SDimitry Andric   LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s launching process", __FUNCTION__);
168fe6060f1SDimitry Andric 
16906c3fb27SDimitry Andric   /* MARK: This doesn't reflect how lldb actually launches a process.
17006c3fb27SDimitry Andric            In reality, it attaches to debugserver, then resume the process.
17106c3fb27SDimitry Andric            That's not true in all cases.  If debugserver is remote, lldb
17206c3fb27SDimitry Andric            asks debugserver to launch the process for it. */
173fe6060f1SDimitry Andric   Status error = GetInterface().Launch();
174fe6060f1SDimitry Andric   SetPrivateState(eStateStopped);
17506c3fb27SDimitry Andric   return error;
176fe6060f1SDimitry Andric }
177fe6060f1SDimitry Andric 
DidLaunch()17806c3fb27SDimitry Andric void ScriptedProcess::DidLaunch() { m_pid = GetInterface().GetProcessID(); }
17906c3fb27SDimitry Andric 
DidResume()18006c3fb27SDimitry Andric void ScriptedProcess::DidResume() {
18106c3fb27SDimitry Andric   // Update the PID again, in case the user provided a placeholder pid at launch
182fe6060f1SDimitry Andric   m_pid = GetInterface().GetProcessID();
183fe6060f1SDimitry Andric }
184fe6060f1SDimitry Andric 
DoResume()185fe6060f1SDimitry Andric Status ScriptedProcess::DoResume() {
18606c3fb27SDimitry Andric   LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s resuming process", __FUNCTION__);
187fe6060f1SDimitry Andric 
18806c3fb27SDimitry Andric   return GetInterface().Resume();
18906c3fb27SDimitry Andric }
190fe6060f1SDimitry Andric 
DoAttach(const ProcessAttachInfo & attach_info)19106c3fb27SDimitry Andric Status ScriptedProcess::DoAttach(const ProcessAttachInfo &attach_info) {
19206c3fb27SDimitry Andric   Status error = GetInterface().Attach(attach_info);
193fe6060f1SDimitry Andric   SetPrivateState(eStateRunning);
194fe6060f1SDimitry Andric   SetPrivateState(eStateStopped);
19506c3fb27SDimitry Andric   if (error.Fail())
196fe6060f1SDimitry Andric     return error;
19706c3fb27SDimitry Andric   // NOTE: We need to set the PID before finishing to attach otherwise we will
19806c3fb27SDimitry Andric   // hit an assert when calling the attach completion handler.
19906c3fb27SDimitry Andric   DidLaunch();
200fe6060f1SDimitry Andric 
201fe6060f1SDimitry Andric   return {};
202fe6060f1SDimitry Andric }
203fe6060f1SDimitry Andric 
20406c3fb27SDimitry Andric Status
DoAttachToProcessWithID(lldb::pid_t pid,const ProcessAttachInfo & attach_info)20506c3fb27SDimitry Andric ScriptedProcess::DoAttachToProcessWithID(lldb::pid_t pid,
20606c3fb27SDimitry Andric                                          const ProcessAttachInfo &attach_info) {
20706c3fb27SDimitry Andric   return DoAttach(attach_info);
20806c3fb27SDimitry Andric }
20906c3fb27SDimitry Andric 
DoAttachToProcessWithName(const char * process_name,const ProcessAttachInfo & attach_info)21006c3fb27SDimitry Andric Status ScriptedProcess::DoAttachToProcessWithName(
21106c3fb27SDimitry Andric     const char *process_name, const ProcessAttachInfo &attach_info) {
21206c3fb27SDimitry Andric   return DoAttach(attach_info);
21306c3fb27SDimitry Andric }
21406c3fb27SDimitry Andric 
DidAttach(ArchSpec & process_arch)21506c3fb27SDimitry Andric void ScriptedProcess::DidAttach(ArchSpec &process_arch) {
21606c3fb27SDimitry Andric   process_arch = GetArchitecture();
217fe6060f1SDimitry Andric }
218fe6060f1SDimitry Andric 
DoDestroy()219fe6060f1SDimitry Andric Status ScriptedProcess::DoDestroy() { return Status(); }
220fe6060f1SDimitry Andric 
IsAlive()22106c3fb27SDimitry Andric bool ScriptedProcess::IsAlive() { return GetInterface().IsAlive(); }
222fe6060f1SDimitry Andric 
DoReadMemory(lldb::addr_t addr,void * buf,size_t size,Status & error)223fe6060f1SDimitry Andric size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
224fe6060f1SDimitry Andric                                      Status &error) {
225fe6060f1SDimitry Andric   lldb::DataExtractorSP data_extractor_sp =
226fe6060f1SDimitry Andric       GetInterface().ReadMemoryAtAddress(addr, size, error);
227fe6060f1SDimitry Andric 
228349cc55cSDimitry Andric   if (!data_extractor_sp || !data_extractor_sp->GetByteSize() || error.Fail())
229fe6060f1SDimitry Andric     return 0;
230fe6060f1SDimitry Andric 
231fe6060f1SDimitry Andric   offset_t bytes_copied = data_extractor_sp->CopyByteOrderedData(
232fe6060f1SDimitry Andric       0, data_extractor_sp->GetByteSize(), buf, size, GetByteOrder());
233fe6060f1SDimitry Andric 
234fe6060f1SDimitry Andric   if (!bytes_copied || bytes_copied == LLDB_INVALID_OFFSET)
23504eeddc0SDimitry Andric     return ScriptedInterface::ErrorWithMessage<size_t>(
236349cc55cSDimitry Andric         LLVM_PRETTY_FUNCTION, "Failed to copy read memory to buffer.", error);
237fe6060f1SDimitry Andric 
23806c3fb27SDimitry Andric   // FIXME: We should use the diagnostic system to report a warning if the
23906c3fb27SDimitry Andric   // `bytes_copied` is different from `size`.
24006c3fb27SDimitry Andric 
24106c3fb27SDimitry Andric   return bytes_copied;
24206c3fb27SDimitry Andric }
24306c3fb27SDimitry Andric 
DoWriteMemory(lldb::addr_t vm_addr,const void * buf,size_t size,Status & error)24406c3fb27SDimitry Andric size_t ScriptedProcess::DoWriteMemory(lldb::addr_t vm_addr, const void *buf,
24506c3fb27SDimitry Andric                                       size_t size, Status &error) {
24606c3fb27SDimitry Andric   lldb::DataExtractorSP data_extractor_sp = std::make_shared<DataExtractor>(
24706c3fb27SDimitry Andric       buf, size, GetByteOrder(), GetAddressByteSize());
24806c3fb27SDimitry Andric 
24906c3fb27SDimitry Andric   if (!data_extractor_sp || !data_extractor_sp->GetByteSize())
25006c3fb27SDimitry Andric     return 0;
25106c3fb27SDimitry Andric 
25206c3fb27SDimitry Andric   lldb::offset_t bytes_written =
25306c3fb27SDimitry Andric       GetInterface().WriteMemoryAtAddress(vm_addr, data_extractor_sp, error);
25406c3fb27SDimitry Andric 
25506c3fb27SDimitry Andric   if (!bytes_written || bytes_written == LLDB_INVALID_OFFSET)
25606c3fb27SDimitry Andric     return ScriptedInterface::ErrorWithMessage<size_t>(
25706c3fb27SDimitry Andric         LLVM_PRETTY_FUNCTION, "Failed to copy write buffer to memory.", error);
25806c3fb27SDimitry Andric 
25906c3fb27SDimitry Andric   // FIXME: We should use the diagnostic system to report a warning if the
26006c3fb27SDimitry Andric   // `bytes_written` is different from `size`.
26106c3fb27SDimitry Andric 
26206c3fb27SDimitry Andric   return bytes_written;
26306c3fb27SDimitry Andric }
26406c3fb27SDimitry Andric 
EnableBreakpointSite(BreakpointSite * bp_site)26506c3fb27SDimitry Andric Status ScriptedProcess::EnableBreakpointSite(BreakpointSite *bp_site) {
26606c3fb27SDimitry Andric   assert(bp_site != nullptr);
26706c3fb27SDimitry Andric 
26806c3fb27SDimitry Andric   if (bp_site->IsEnabled()) {
26906c3fb27SDimitry Andric     return {};
27006c3fb27SDimitry Andric   }
27106c3fb27SDimitry Andric 
27206c3fb27SDimitry Andric   if (bp_site->HardwareRequired()) {
27306c3fb27SDimitry Andric     return Status("Scripted Processes don't support hardware breakpoints");
27406c3fb27SDimitry Andric   }
27506c3fb27SDimitry Andric 
27606c3fb27SDimitry Andric   Status error;
27706c3fb27SDimitry Andric   GetInterface().CreateBreakpoint(bp_site->GetLoadAddress(), error);
27806c3fb27SDimitry Andric 
27906c3fb27SDimitry Andric   return error;
280fe6060f1SDimitry Andric }
281fe6060f1SDimitry Andric 
GetArchitecture()282fe6060f1SDimitry Andric ArchSpec ScriptedProcess::GetArchitecture() {
283fe6060f1SDimitry Andric   return GetTarget().GetArchitecture();
284fe6060f1SDimitry Andric }
285fe6060f1SDimitry Andric 
DoGetMemoryRegionInfo(lldb::addr_t load_addr,MemoryRegionInfo & region)286d56accc7SDimitry Andric Status ScriptedProcess::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
287fe6060f1SDimitry Andric                                               MemoryRegionInfo &region) {
288349cc55cSDimitry Andric   Status error;
289349cc55cSDimitry Andric   if (auto region_or_err =
290349cc55cSDimitry Andric           GetInterface().GetMemoryRegionContainingAddress(load_addr, error))
291349cc55cSDimitry Andric     region = *region_or_err;
292349cc55cSDimitry Andric 
293349cc55cSDimitry Andric   return error;
294fe6060f1SDimitry Andric }
295fe6060f1SDimitry Andric 
GetMemoryRegions(MemoryRegionInfos & region_list)296fe6060f1SDimitry Andric Status ScriptedProcess::GetMemoryRegions(MemoryRegionInfos &region_list) {
297349cc55cSDimitry Andric   Status error;
298fe6060f1SDimitry Andric   lldb::addr_t address = 0;
299fe6060f1SDimitry Andric 
300349cc55cSDimitry Andric   while (auto region_or_err =
301349cc55cSDimitry Andric              GetInterface().GetMemoryRegionContainingAddress(address, error)) {
302349cc55cSDimitry Andric     if (error.Fail())
303349cc55cSDimitry Andric       break;
304349cc55cSDimitry Andric 
305349cc55cSDimitry Andric     MemoryRegionInfo &mem_region = *region_or_err;
306349cc55cSDimitry Andric     auto range = mem_region.GetRange();
307fe6060f1SDimitry Andric     address += range.GetRangeBase() + range.GetByteSize();
308349cc55cSDimitry Andric     region_list.push_back(mem_region);
309fe6060f1SDimitry Andric   }
310fe6060f1SDimitry Andric 
311349cc55cSDimitry Andric   return error;
312fe6060f1SDimitry Andric }
313fe6060f1SDimitry Andric 
Clear()314fe6060f1SDimitry Andric void ScriptedProcess::Clear() { Process::m_thread_list.Clear(); }
315fe6060f1SDimitry Andric 
DoUpdateThreadList(ThreadList & old_thread_list,ThreadList & new_thread_list)316fe6060f1SDimitry Andric bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list,
317fe6060f1SDimitry Andric                                          ThreadList &new_thread_list) {
318fe6060f1SDimitry Andric   // TODO: Implement
319fe6060f1SDimitry Andric   // This is supposed to get the current set of threads, if any of them are in
320fe6060f1SDimitry Andric   // old_thread_list then they get copied to new_thread_list, and then any
321fe6060f1SDimitry Andric   // actually new threads will get added to new_thread_list.
322349cc55cSDimitry Andric   m_thread_plans.ClearThreadCache();
323349cc55cSDimitry Andric 
324349cc55cSDimitry Andric   Status error;
32504eeddc0SDimitry Andric   StructuredData::DictionarySP thread_info_sp = GetInterface().GetThreadsInfo();
326349cc55cSDimitry Andric 
32704eeddc0SDimitry Andric   if (!thread_info_sp)
32804eeddc0SDimitry Andric     return ScriptedInterface::ErrorWithMessage<bool>(
32904eeddc0SDimitry Andric         LLVM_PRETTY_FUNCTION,
33004eeddc0SDimitry Andric         "Couldn't fetch thread list from Scripted Process.", error);
33104eeddc0SDimitry Andric 
33281ad6265SDimitry Andric   // Because `StructuredData::Dictionary` uses a `std::map<ConstString,
33381ad6265SDimitry Andric   // ObjectSP>` for storage, each item is sorted based on the key alphabetical
33481ad6265SDimitry Andric   // order. Since `GetThreadsInfo` provides thread indices as the key element,
33581ad6265SDimitry Andric   // thread info comes ordered alphabetically, instead of numerically, so we
33681ad6265SDimitry Andric   // need to sort the thread indices before creating thread.
33781ad6265SDimitry Andric 
33881ad6265SDimitry Andric   StructuredData::ArraySP keys = thread_info_sp->GetKeys();
33981ad6265SDimitry Andric 
34081ad6265SDimitry Andric   std::map<size_t, StructuredData::ObjectSP> sorted_threads;
34181ad6265SDimitry Andric   auto sort_keys = [&sorted_threads,
34281ad6265SDimitry Andric                     &thread_info_sp](StructuredData::Object *item) -> bool {
34381ad6265SDimitry Andric     if (!item)
34481ad6265SDimitry Andric       return false;
34581ad6265SDimitry Andric 
34681ad6265SDimitry Andric     llvm::StringRef key = item->GetStringValue();
34781ad6265SDimitry Andric     size_t idx = 0;
34881ad6265SDimitry Andric 
34981ad6265SDimitry Andric     // Make sure the provided index is actually an integer
35081ad6265SDimitry Andric     if (!llvm::to_integer(key, idx))
35181ad6265SDimitry Andric       return false;
35281ad6265SDimitry Andric 
35381ad6265SDimitry Andric     sorted_threads[idx] = thread_info_sp->GetValueForKey(key);
35481ad6265SDimitry Andric     return true;
35581ad6265SDimitry Andric   };
35681ad6265SDimitry Andric 
35781ad6265SDimitry Andric   size_t thread_count = thread_info_sp->GetSize();
35881ad6265SDimitry Andric 
35981ad6265SDimitry Andric   if (!keys->ForEach(sort_keys) || sorted_threads.size() != thread_count)
36081ad6265SDimitry Andric     // Might be worth showing the unsorted thread list instead of return early.
36181ad6265SDimitry Andric     return ScriptedInterface::ErrorWithMessage<bool>(
36281ad6265SDimitry Andric         LLVM_PRETTY_FUNCTION, "Couldn't sort thread list.", error);
36381ad6265SDimitry Andric 
36404eeddc0SDimitry Andric   auto create_scripted_thread =
36581ad6265SDimitry Andric       [this, &error, &new_thread_list](
36681ad6265SDimitry Andric           const std::pair<size_t, StructuredData::ObjectSP> pair) -> bool {
36781ad6265SDimitry Andric     size_t idx = pair.first;
36881ad6265SDimitry Andric     StructuredData::ObjectSP object_sp = pair.second;
36981ad6265SDimitry Andric 
37081ad6265SDimitry Andric     if (!object_sp)
37104eeddc0SDimitry Andric       return ScriptedInterface::ErrorWithMessage<bool>(
37204eeddc0SDimitry Andric           LLVM_PRETTY_FUNCTION, "Invalid thread info object", error);
37304eeddc0SDimitry Andric 
37481ad6265SDimitry Andric     auto thread_or_error =
37581ad6265SDimitry Andric         ScriptedThread::Create(*this, object_sp->GetAsGeneric());
37604eeddc0SDimitry Andric 
37704eeddc0SDimitry Andric     if (!thread_or_error)
37804eeddc0SDimitry Andric       return ScriptedInterface::ErrorWithMessage<bool>(
37904eeddc0SDimitry Andric           LLVM_PRETTY_FUNCTION, toString(thread_or_error.takeError()), error);
38004eeddc0SDimitry Andric 
38104eeddc0SDimitry Andric     ThreadSP thread_sp = thread_or_error.get();
38204eeddc0SDimitry Andric     lldbassert(thread_sp && "Couldn't initialize scripted thread.");
383349cc55cSDimitry Andric 
3840eae32dcSDimitry Andric     RegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext();
3850eae32dcSDimitry Andric     if (!reg_ctx_sp)
38604eeddc0SDimitry Andric       return ScriptedInterface::ErrorWithMessage<bool>(
38704eeddc0SDimitry Andric           LLVM_PRETTY_FUNCTION,
38881ad6265SDimitry Andric           llvm::Twine("Invalid Register Context for thread " + llvm::Twine(idx))
38904eeddc0SDimitry Andric               .str(),
39004eeddc0SDimitry Andric           error);
3910eae32dcSDimitry Andric 
392349cc55cSDimitry Andric     new_thread_list.AddThread(thread_sp);
393349cc55cSDimitry Andric 
39404eeddc0SDimitry Andric     return true;
39504eeddc0SDimitry Andric   };
39604eeddc0SDimitry Andric 
39781ad6265SDimitry Andric   llvm::for_each(sorted_threads, create_scripted_thread);
39804eeddc0SDimitry Andric 
399fe6060f1SDimitry Andric   return new_thread_list.GetSize(false) > 0;
400fe6060f1SDimitry Andric }
401fe6060f1SDimitry Andric 
RefreshStateAfterStop()402349cc55cSDimitry Andric void ScriptedProcess::RefreshStateAfterStop() {
403349cc55cSDimitry Andric   // Let all threads recover from stopping and do any clean up based on the
404349cc55cSDimitry Andric   // previous thread state (if any).
40581ad6265SDimitry Andric   m_thread_list.RefreshStateAfterStop();
406349cc55cSDimitry Andric }
407349cc55cSDimitry Andric 
GetProcessInfo(ProcessInstanceInfo & info)408fe6060f1SDimitry Andric bool ScriptedProcess::GetProcessInfo(ProcessInstanceInfo &info) {
409fe6060f1SDimitry Andric   info.Clear();
410fe6060f1SDimitry Andric   info.SetProcessID(GetID());
411fe6060f1SDimitry Andric   info.SetArchitecture(GetArchitecture());
412fe6060f1SDimitry Andric   lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();
413fe6060f1SDimitry Andric   if (module_sp) {
414fe6060f1SDimitry Andric     const bool add_exe_file_as_first_arg = false;
415fe6060f1SDimitry Andric     info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),
416fe6060f1SDimitry Andric                            add_exe_file_as_first_arg);
417fe6060f1SDimitry Andric   }
418fe6060f1SDimitry Andric   return true;
419fe6060f1SDimitry Andric }
420fe6060f1SDimitry Andric 
42181ad6265SDimitry Andric lldb_private::StructuredData::ObjectSP
GetLoadedDynamicLibrariesInfos()42281ad6265SDimitry Andric ScriptedProcess::GetLoadedDynamicLibrariesInfos() {
42381ad6265SDimitry Andric   Status error;
42481ad6265SDimitry Andric   auto error_with_message = [&error](llvm::StringRef message) {
42581ad6265SDimitry Andric     return ScriptedInterface::ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION,
42681ad6265SDimitry Andric                                                      message.data(), error);
42781ad6265SDimitry Andric   };
42881ad6265SDimitry Andric 
42981ad6265SDimitry Andric   StructuredData::ArraySP loaded_images_sp = GetInterface().GetLoadedImages();
43081ad6265SDimitry Andric 
43181ad6265SDimitry Andric   if (!loaded_images_sp || !loaded_images_sp->GetSize())
432bdd1243dSDimitry Andric     return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(
43381ad6265SDimitry Andric         LLVM_PRETTY_FUNCTION, "No loaded images.", error);
43481ad6265SDimitry Andric 
43581ad6265SDimitry Andric   ModuleList module_list;
43681ad6265SDimitry Andric   Target &target = GetTarget();
43781ad6265SDimitry Andric 
43881ad6265SDimitry Andric   auto reload_image = [&target, &module_list, &error_with_message](
43981ad6265SDimitry Andric                           StructuredData::Object *obj) -> bool {
44081ad6265SDimitry Andric     StructuredData::Dictionary *dict = obj->GetAsDictionary();
44181ad6265SDimitry Andric 
44281ad6265SDimitry Andric     if (!dict)
44381ad6265SDimitry Andric       return error_with_message("Couldn't cast image object into dictionary.");
44481ad6265SDimitry Andric 
44581ad6265SDimitry Andric     ModuleSpec module_spec;
44681ad6265SDimitry Andric     llvm::StringRef value;
44781ad6265SDimitry Andric 
44881ad6265SDimitry Andric     bool has_path = dict->HasKey("path");
44981ad6265SDimitry Andric     bool has_uuid = dict->HasKey("uuid");
45081ad6265SDimitry Andric     if (!has_path && !has_uuid)
45181ad6265SDimitry Andric       return error_with_message("Dictionary should have key 'path' or 'uuid'");
45281ad6265SDimitry Andric     if (!dict->HasKey("load_addr"))
45381ad6265SDimitry Andric       return error_with_message("Dictionary is missing key 'load_addr'");
45481ad6265SDimitry Andric 
45581ad6265SDimitry Andric     if (has_path) {
45681ad6265SDimitry Andric       dict->GetValueForKeyAsString("path", value);
45781ad6265SDimitry Andric       module_spec.GetFileSpec().SetPath(value);
45881ad6265SDimitry Andric     }
45981ad6265SDimitry Andric 
46081ad6265SDimitry Andric     if (has_uuid) {
46181ad6265SDimitry Andric       dict->GetValueForKeyAsString("uuid", value);
46281ad6265SDimitry Andric       module_spec.GetUUID().SetFromStringRef(value);
46381ad6265SDimitry Andric     }
46481ad6265SDimitry Andric     module_spec.GetArchitecture() = target.GetArchitecture();
46581ad6265SDimitry Andric 
46681ad6265SDimitry Andric     ModuleSP module_sp =
46781ad6265SDimitry Andric         target.GetOrCreateModule(module_spec, true /* notify */);
46881ad6265SDimitry Andric 
46981ad6265SDimitry Andric     if (!module_sp)
47081ad6265SDimitry Andric       return error_with_message("Couldn't create or get module.");
47181ad6265SDimitry Andric 
47281ad6265SDimitry Andric     lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
47306c3fb27SDimitry Andric     lldb::offset_t slide = LLDB_INVALID_OFFSET;
47481ad6265SDimitry Andric     dict->GetValueForKeyAsInteger("load_addr", load_addr);
47581ad6265SDimitry Andric     dict->GetValueForKeyAsInteger("slide", slide);
47681ad6265SDimitry Andric     if (load_addr == LLDB_INVALID_ADDRESS)
47781ad6265SDimitry Andric       return error_with_message(
47881ad6265SDimitry Andric           "Couldn't get valid load address or slide offset.");
47981ad6265SDimitry Andric 
48081ad6265SDimitry Andric     if (slide != LLDB_INVALID_OFFSET)
48181ad6265SDimitry Andric       load_addr += slide;
48281ad6265SDimitry Andric 
48381ad6265SDimitry Andric     bool changed = false;
48481ad6265SDimitry Andric     module_sp->SetLoadAddress(target, load_addr, false /*=value_is_offset*/,
48581ad6265SDimitry Andric                               changed);
48681ad6265SDimitry Andric 
48781ad6265SDimitry Andric     if (!changed && !module_sp->GetObjectFile())
48881ad6265SDimitry Andric       return error_with_message("Couldn't set the load address for module.");
48981ad6265SDimitry Andric 
49081ad6265SDimitry Andric     dict->GetValueForKeyAsString("path", value);
49181ad6265SDimitry Andric     FileSpec objfile(value);
49281ad6265SDimitry Andric     module_sp->SetFileSpecAndObjectName(objfile, objfile.GetFilename());
49381ad6265SDimitry Andric 
49481ad6265SDimitry Andric     return module_list.AppendIfNeeded(module_sp);
49581ad6265SDimitry Andric   };
49681ad6265SDimitry Andric 
49781ad6265SDimitry Andric   if (!loaded_images_sp->ForEach(reload_image))
498bdd1243dSDimitry Andric     return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(
49981ad6265SDimitry Andric         LLVM_PRETTY_FUNCTION, "Couldn't reload all images.", error);
50081ad6265SDimitry Andric 
50181ad6265SDimitry Andric   target.ModulesDidLoad(module_list);
50281ad6265SDimitry Andric 
50381ad6265SDimitry Andric   return loaded_images_sp;
50481ad6265SDimitry Andric }
50581ad6265SDimitry Andric 
GetMetadata()506bdd1243dSDimitry Andric lldb_private::StructuredData::DictionarySP ScriptedProcess::GetMetadata() {
507bdd1243dSDimitry Andric   StructuredData::DictionarySP metadata_sp = GetInterface().GetMetadata();
508bdd1243dSDimitry Andric 
509bdd1243dSDimitry Andric   Status error;
510bdd1243dSDimitry Andric   if (!metadata_sp || !metadata_sp->GetSize())
511bdd1243dSDimitry Andric     return ScriptedInterface::ErrorWithMessage<StructuredData::DictionarySP>(
512bdd1243dSDimitry Andric         LLVM_PRETTY_FUNCTION, "No metadata.", error);
513bdd1243dSDimitry Andric 
514bdd1243dSDimitry Andric   return metadata_sp;
515bdd1243dSDimitry Andric }
516bdd1243dSDimitry Andric 
UpdateQueueListIfNeeded()517bdd1243dSDimitry Andric void ScriptedProcess::UpdateQueueListIfNeeded() {
51806c3fb27SDimitry Andric   CheckScriptedInterface();
519bdd1243dSDimitry Andric   for (ThreadSP thread_sp : Threads()) {
520bdd1243dSDimitry Andric     if (const char *queue_name = thread_sp->GetQueueName()) {
521bdd1243dSDimitry Andric       QueueSP queue_sp = std::make_shared<Queue>(
522bdd1243dSDimitry Andric           m_process->shared_from_this(), thread_sp->GetQueueID(), queue_name);
523bdd1243dSDimitry Andric       m_queue_list.AddQueue(queue_sp);
524bdd1243dSDimitry Andric     }
525bdd1243dSDimitry Andric   }
526bdd1243dSDimitry Andric }
527bdd1243dSDimitry Andric 
GetInterface() const528fe6060f1SDimitry Andric ScriptedProcessInterface &ScriptedProcess::GetInterface() const {
52906c3fb27SDimitry Andric   CheckScriptedInterface();
53006c3fb27SDimitry Andric   return *m_interface_up;
53106c3fb27SDimitry Andric }
53206c3fb27SDimitry Andric 
GetImplementation()53306c3fb27SDimitry Andric void *ScriptedProcess::GetImplementation() {
53406c3fb27SDimitry Andric   StructuredData::GenericSP object_instance_sp =
53506c3fb27SDimitry Andric       GetInterface().GetScriptObjectInstance();
53606c3fb27SDimitry Andric   if (object_instance_sp &&
53706c3fb27SDimitry Andric       object_instance_sp->GetType() == eStructuredDataTypeGeneric)
53806c3fb27SDimitry Andric     return object_instance_sp->GetAsGeneric()->GetValue();
53906c3fb27SDimitry Andric   return nullptr;
540fe6060f1SDimitry Andric }
541