xref: /llvm-project/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp (revision 22561cfb443267905d4190f0e2a738e6b412457f)
1312b43daSMed Ismail Bennani //===-- ScriptedProcess.cpp -----------------------------------------------===//
2312b43daSMed Ismail Bennani //
3312b43daSMed Ismail Bennani // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4312b43daSMed Ismail Bennani // See https://llvm.org/LICENSE.txt for license information.
5312b43daSMed Ismail Bennani // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6312b43daSMed Ismail Bennani //
7312b43daSMed Ismail Bennani //===----------------------------------------------------------------------===//
8312b43daSMed Ismail Bennani 
9312b43daSMed Ismail Bennani #include "ScriptedProcess.h"
10312b43daSMed Ismail Bennani 
11312b43daSMed Ismail Bennani #include "lldb/Core/Debugger.h"
12312b43daSMed Ismail Bennani #include "lldb/Core/Module.h"
13312b43daSMed Ismail Bennani #include "lldb/Core/PluginManager.h"
14312b43daSMed Ismail Bennani 
15312b43daSMed Ismail Bennani #include "lldb/Host/OptionParser.h"
16312b43daSMed Ismail Bennani #include "lldb/Host/ThreadLauncher.h"
17312b43daSMed Ismail Bennani #include "lldb/Interpreter/CommandInterpreter.h"
18312b43daSMed Ismail Bennani #include "lldb/Interpreter/OptionArgParser.h"
19312b43daSMed Ismail Bennani #include "lldb/Interpreter/OptionGroupBoolean.h"
20312b43daSMed Ismail Bennani #include "lldb/Interpreter/ScriptInterpreter.h"
21312b43daSMed Ismail Bennani #include "lldb/Target/MemoryRegionInfo.h"
2244b81f62SMed Ismail Bennani #include "lldb/Target/Queue.h"
23312b43daSMed Ismail Bennani #include "lldb/Target/RegisterContext.h"
24c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
25601583e5SMed Ismail Bennani #include "lldb/Utility/ScriptedMetadata.h"
26312b43daSMed Ismail Bennani #include "lldb/Utility/State.h"
27312b43daSMed Ismail Bennani 
28312b43daSMed Ismail Bennani #include <mutex>
29312b43daSMed Ismail Bennani 
30312b43daSMed Ismail Bennani LLDB_PLUGIN_DEFINE(ScriptedProcess)
31312b43daSMed Ismail Bennani 
32312b43daSMed Ismail Bennani using namespace lldb;
33312b43daSMed Ismail Bennani using namespace lldb_private;
34312b43daSMed Ismail Bennani 
355f4980f0SPavel Labath llvm::StringRef ScriptedProcess::GetPluginDescriptionStatic() {
36312b43daSMed Ismail Bennani   return "Scripted Process plug-in.";
37312b43daSMed Ismail Bennani }
38312b43daSMed Ismail Bennani 
39312b43daSMed Ismail Bennani static constexpr lldb::ScriptLanguage g_supported_script_languages[] = {
40312b43daSMed Ismail Bennani     ScriptLanguage::eScriptLanguagePython,
41312b43daSMed Ismail Bennani };
42312b43daSMed Ismail Bennani 
43312b43daSMed Ismail Bennani bool ScriptedProcess::IsScriptLanguageSupported(lldb::ScriptLanguage language) {
44312b43daSMed Ismail Bennani   llvm::ArrayRef<lldb::ScriptLanguage> supported_languages =
45984b800aSserge-sans-paille       llvm::ArrayRef(g_supported_script_languages);
46312b43daSMed Ismail Bennani 
47312b43daSMed Ismail Bennani   return llvm::is_contained(supported_languages, language);
48312b43daSMed Ismail Bennani }
49312b43daSMed Ismail Bennani 
50312b43daSMed Ismail Bennani lldb::ProcessSP ScriptedProcess::CreateInstance(lldb::TargetSP target_sp,
51312b43daSMed Ismail Bennani                                                 lldb::ListenerSP listener_sp,
52312b43daSMed Ismail Bennani                                                 const FileSpec *file,
53312b43daSMed Ismail Bennani                                                 bool can_connect) {
54312b43daSMed Ismail Bennani   if (!target_sp ||
55312b43daSMed Ismail Bennani       !IsScriptLanguageSupported(target_sp->GetDebugger().GetScriptLanguage()))
56312b43daSMed Ismail Bennani     return nullptr;
57312b43daSMed Ismail Bennani 
58d9f4d1b0SMed Ismail Bennani   ScriptedMetadata scripted_metadata(target_sp->GetProcessLaunchInfo());
59312b43daSMed Ismail Bennani 
60d9f4d1b0SMed Ismail Bennani   Status error;
61d9f4d1b0SMed Ismail Bennani   auto process_sp = std::shared_ptr<ScriptedProcess>(
62d9f4d1b0SMed Ismail Bennani       new ScriptedProcess(target_sp, listener_sp, scripted_metadata, error));
63312b43daSMed Ismail Bennani 
64a3d4f739SMed Ismail Bennani   if (error.Fail() || !process_sp || !process_sp->m_interface_up) {
65a007a6d8SPavel Labath     LLDB_LOGF(GetLog(LLDBLog::Process), "%s", error.AsCString());
66312b43daSMed Ismail Bennani     return nullptr;
67312b43daSMed Ismail Bennani   }
68312b43daSMed Ismail Bennani 
69312b43daSMed Ismail Bennani   return process_sp;
70312b43daSMed Ismail Bennani }
71312b43daSMed Ismail Bennani 
72312b43daSMed Ismail Bennani bool ScriptedProcess::CanDebug(lldb::TargetSP target_sp,
73312b43daSMed Ismail Bennani                                bool plugin_specified_by_name) {
74312b43daSMed Ismail Bennani   return true;
75312b43daSMed Ismail Bennani }
76312b43daSMed Ismail Bennani 
77d9f4d1b0SMed Ismail Bennani ScriptedProcess::ScriptedProcess(lldb::TargetSP target_sp,
78d9f4d1b0SMed Ismail Bennani                                  lldb::ListenerSP listener_sp,
79d9f4d1b0SMed Ismail Bennani                                  const ScriptedMetadata &scripted_metadata,
80312b43daSMed Ismail Bennani                                  Status &error)
81d9f4d1b0SMed Ismail Bennani     : Process(target_sp, listener_sp), m_scripted_metadata(scripted_metadata) {
82312b43daSMed Ismail Bennani 
83312b43daSMed Ismail Bennani   if (!target_sp) {
840642cd76SAdrian Prantl     error = Status::FromErrorStringWithFormat(
850642cd76SAdrian Prantl         "ScriptedProcess::%s () - ERROR: %s", __FUNCTION__, "Invalid target");
86312b43daSMed Ismail Bennani     return;
87312b43daSMed Ismail Bennani   }
88312b43daSMed Ismail Bennani 
89a3d4f739SMed Ismail Bennani   ScriptInterpreter *interpreter =
90a3d4f739SMed Ismail Bennani       target_sp->GetDebugger().GetScriptInterpreter();
91312b43daSMed Ismail Bennani 
92a3d4f739SMed Ismail Bennani   if (!interpreter) {
930642cd76SAdrian Prantl     error = Status::FromErrorStringWithFormat(
940642cd76SAdrian Prantl         "ScriptedProcess::%s () - ERROR: %s", __FUNCTION__,
95312b43daSMed Ismail Bennani         "Debugger has no Script Interpreter");
96312b43daSMed Ismail Bennani     return;
97312b43daSMed Ismail Bennani   }
98312b43daSMed Ismail Bennani 
99a3d4f739SMed Ismail Bennani   // Create process instance interface
100a3d4f739SMed Ismail Bennani   m_interface_up = interpreter->CreateScriptedProcessInterface();
101a3d4f739SMed Ismail Bennani   if (!m_interface_up) {
1020642cd76SAdrian Prantl     error = Status::FromErrorStringWithFormat(
103a3d4f739SMed Ismail Bennani         "ScriptedProcess::%s () - ERROR: %s", __FUNCTION__,
104a3d4f739SMed Ismail Bennani         "Script interpreter couldn't create Scripted Process Interface");
105a3d4f739SMed Ismail Bennani     return;
106a3d4f739SMed Ismail Bennani   }
107a3d4f739SMed Ismail Bennani 
1083925204cSMed Ismail Bennani   ExecutionContext exe_ctx(target_sp, /*get_process=*/false);
1093925204cSMed Ismail Bennani 
110a3d4f739SMed Ismail Bennani   // Create process script object
111f22d82ceSMed Ismail Bennani   auto obj_or_err = GetInterface().CreatePluginObject(
112d9f4d1b0SMed Ismail Bennani       m_scripted_metadata.GetClassName(), exe_ctx,
113d9f4d1b0SMed Ismail Bennani       m_scripted_metadata.GetArgsSP());
114312b43daSMed Ismail Bennani 
115f22d82ceSMed Ismail Bennani   if (!obj_or_err) {
1162abf997fSMed Ismail Bennani     llvm::consumeError(obj_or_err.takeError());
1170642cd76SAdrian Prantl     error = Status::FromErrorString("Failed to create script object.");
118f22d82ceSMed Ismail Bennani     return;
119f22d82ceSMed Ismail Bennani   }
120f22d82ceSMed Ismail Bennani 
121f22d82ceSMed Ismail Bennani   StructuredData::GenericSP object_sp = *obj_or_err;
122f22d82ceSMed Ismail Bennani 
123312b43daSMed Ismail Bennani   if (!object_sp || !object_sp->IsValid()) {
1240642cd76SAdrian Prantl     error = Status::FromErrorStringWithFormat(
1250642cd76SAdrian Prantl         "ScriptedProcess::%s () - ERROR: %s", __FUNCTION__,
126312b43daSMed Ismail Bennani         "Failed to create valid script object");
127312b43daSMed Ismail Bennani     return;
128312b43daSMed Ismail Bennani   }
129312b43daSMed Ismail Bennani }
130312b43daSMed Ismail Bennani 
131312b43daSMed Ismail Bennani ScriptedProcess::~ScriptedProcess() {
132312b43daSMed Ismail Bennani   Clear();
1330adbde65SMed Ismail Bennani   // If the interface is not valid, we can't call Finalize(). When that happens
1340adbde65SMed Ismail Bennani   // it means that the Scripted Process instanciation failed and the
1350adbde65SMed Ismail Bennani   // CreateProcess function returns a nullptr, so no one besides this class
1360adbde65SMed Ismail Bennani   // should have access to that bogus process object.
1370adbde65SMed Ismail Bennani   if (!m_interface_up)
1380adbde65SMed Ismail Bennani     return;
139312b43daSMed Ismail Bennani   // We need to call finalize on the process before destroying ourselves to
140312b43daSMed Ismail Bennani   // make sure all of the broadcaster cleanup goes as planned. If we destruct
141312b43daSMed Ismail Bennani   // this class, then Process::~Process() might have problems trying to fully
142312b43daSMed Ismail Bennani   // destroy the broadcaster.
1439d3aec55Sjimingham   Finalize(true /* destructing */);
144312b43daSMed Ismail Bennani }
145312b43daSMed Ismail Bennani 
146312b43daSMed Ismail Bennani void ScriptedProcess::Initialize() {
147312b43daSMed Ismail Bennani   static llvm::once_flag g_once_flag;
148312b43daSMed Ismail Bennani 
149312b43daSMed Ismail Bennani   llvm::call_once(g_once_flag, []() {
150312b43daSMed Ismail Bennani     PluginManager::RegisterPlugin(GetPluginNameStatic(),
151312b43daSMed Ismail Bennani                                   GetPluginDescriptionStatic(), CreateInstance);
152312b43daSMed Ismail Bennani   });
153312b43daSMed Ismail Bennani }
154312b43daSMed Ismail Bennani 
155312b43daSMed Ismail Bennani void ScriptedProcess::Terminate() {
156312b43daSMed Ismail Bennani   PluginManager::UnregisterPlugin(ScriptedProcess::CreateInstance);
157312b43daSMed Ismail Bennani }
158312b43daSMed Ismail Bennani 
159312b43daSMed Ismail Bennani Status ScriptedProcess::DoLoadCore() {
160312b43daSMed Ismail Bennani   ProcessLaunchInfo launch_info = GetTarget().GetProcessLaunchInfo();
161312b43daSMed Ismail Bennani 
162312b43daSMed Ismail Bennani   return DoLaunch(nullptr, launch_info);
163312b43daSMed Ismail Bennani }
164312b43daSMed Ismail Bennani 
165312b43daSMed Ismail Bennani Status ScriptedProcess::DoLaunch(Module *exe_module,
166312b43daSMed Ismail Bennani                                  ProcessLaunchInfo &launch_info) {
1676c961ae1SMed Ismail Bennani   LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s launching process", __FUNCTION__);
1686c961ae1SMed Ismail Bennani 
1696c961ae1SMed Ismail Bennani   /* MARK: This doesn't reflect how lldb actually launches a process.
1706c961ae1SMed Ismail Bennani            In reality, it attaches to debugserver, then resume the process.
1716c961ae1SMed Ismail Bennani            That's not true in all cases.  If debugserver is remote, lldb
1726c961ae1SMed Ismail Bennani            asks debugserver to launch the process for it. */
173312b43daSMed Ismail Bennani   Status error = GetInterface().Launch();
174312b43daSMed Ismail Bennani   SetPrivateState(eStateStopped);
1756c961ae1SMed Ismail Bennani   return error;
176312b43daSMed Ismail Bennani }
177312b43daSMed Ismail Bennani 
1789cbdfcdbSMed Ismail Bennani void ScriptedProcess::DidLaunch() { m_pid = GetInterface().GetProcessID(); }
1799cbdfcdbSMed Ismail Bennani 
18088f40919SJonas Devlieghere void ScriptedProcess::DidResume() {
1819cbdfcdbSMed Ismail Bennani   // Update the PID again, in case the user provided a placeholder pid at launch
182312b43daSMed Ismail Bennani   m_pid = GetInterface().GetProcessID();
183312b43daSMed Ismail Bennani }
184312b43daSMed Ismail Bennani 
185*22561cfbSPavel Labath Status ScriptedProcess::DoResume() {
1866c961ae1SMed Ismail Bennani   LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s resuming process", __FUNCTION__);
187312b43daSMed Ismail Bennani 
1886c961ae1SMed Ismail Bennani   return GetInterface().Resume();
189312b43daSMed Ismail Bennani }
190312b43daSMed Ismail Bennani 
191b9d4c94aSMed Ismail Bennani Status ScriptedProcess::DoAttach(const ProcessAttachInfo &attach_info) {
192b9d4c94aSMed Ismail Bennani   Status error = GetInterface().Attach(attach_info);
193b9d4c94aSMed Ismail Bennani   SetPrivateState(eStateRunning);
194b9d4c94aSMed Ismail Bennani   SetPrivateState(eStateStopped);
195b9d4c94aSMed Ismail Bennani   if (error.Fail())
196b9d4c94aSMed Ismail Bennani     return error;
197b9d4c94aSMed Ismail Bennani   // NOTE: We need to set the PID before finishing to attach otherwise we will
198b9d4c94aSMed Ismail Bennani   // hit an assert when calling the attach completion handler.
199b9d4c94aSMed Ismail Bennani   DidLaunch();
200b9d4c94aSMed Ismail Bennani 
201b9d4c94aSMed Ismail Bennani   return {};
202b9d4c94aSMed Ismail Bennani }
203b9d4c94aSMed Ismail Bennani 
204b9d4c94aSMed Ismail Bennani Status
205b9d4c94aSMed Ismail Bennani ScriptedProcess::DoAttachToProcessWithID(lldb::pid_t pid,
206b9d4c94aSMed Ismail Bennani                                          const ProcessAttachInfo &attach_info) {
207b9d4c94aSMed Ismail Bennani   return DoAttach(attach_info);
208b9d4c94aSMed Ismail Bennani }
209b9d4c94aSMed Ismail Bennani 
210b9d4c94aSMed Ismail Bennani Status ScriptedProcess::DoAttachToProcessWithName(
211b9d4c94aSMed Ismail Bennani     const char *process_name, const ProcessAttachInfo &attach_info) {
212b9d4c94aSMed Ismail Bennani   return DoAttach(attach_info);
213b9d4c94aSMed Ismail Bennani }
214b9d4c94aSMed Ismail Bennani 
215b9d4c94aSMed Ismail Bennani void ScriptedProcess::DidAttach(ArchSpec &process_arch) {
216b9d4c94aSMed Ismail Bennani   process_arch = GetArchitecture();
217b9d4c94aSMed Ismail Bennani }
218b9d4c94aSMed Ismail Bennani 
219312b43daSMed Ismail Bennani Status ScriptedProcess::DoDestroy() { return Status(); }
220312b43daSMed Ismail Bennani 
221a3d4f739SMed Ismail Bennani bool ScriptedProcess::IsAlive() { return GetInterface().IsAlive(); }
222312b43daSMed Ismail Bennani 
223312b43daSMed Ismail Bennani size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
224312b43daSMed Ismail Bennani                                      Status &error) {
225312b43daSMed Ismail Bennani   lldb::DataExtractorSP data_extractor_sp =
226312b43daSMed Ismail Bennani       GetInterface().ReadMemoryAtAddress(addr, size, error);
227312b43daSMed Ismail Bennani 
228a758c9f7SMed Ismail Bennani   if (!data_extractor_sp || !data_extractor_sp->GetByteSize() || error.Fail())
229312b43daSMed Ismail Bennani     return 0;
230312b43daSMed Ismail Bennani 
231312b43daSMed Ismail Bennani   offset_t bytes_copied = data_extractor_sp->CopyByteOrderedData(
232312b43daSMed Ismail Bennani       0, data_extractor_sp->GetByteSize(), buf, size, GetByteOrder());
233312b43daSMed Ismail Bennani 
234312b43daSMed Ismail Bennani   if (!bytes_copied || bytes_copied == LLDB_INVALID_OFFSET)
23591bb1161SMed Ismail Bennani     return ScriptedInterface::ErrorWithMessage<size_t>(
23688a941baSMed Ismail Bennani         LLVM_PRETTY_FUNCTION, "Failed to copy read memory to buffer.", error);
237312b43daSMed Ismail Bennani 
238f190ec68SMed Ismail Bennani   // FIXME: We should use the diagnostic system to report a warning if the
239f190ec68SMed Ismail Bennani   // `bytes_copied` is different from `size`.
240f190ec68SMed Ismail Bennani 
241f190ec68SMed Ismail Bennani   return bytes_copied;
242f190ec68SMed Ismail Bennani }
243f190ec68SMed Ismail Bennani 
244f190ec68SMed Ismail Bennani size_t ScriptedProcess::DoWriteMemory(lldb::addr_t vm_addr, const void *buf,
245f190ec68SMed Ismail Bennani                                       size_t size, Status &error) {
246f190ec68SMed Ismail Bennani   lldb::DataExtractorSP data_extractor_sp = std::make_shared<DataExtractor>(
247f190ec68SMed Ismail Bennani       buf, size, GetByteOrder(), GetAddressByteSize());
248f190ec68SMed Ismail Bennani 
249f190ec68SMed Ismail Bennani   if (!data_extractor_sp || !data_extractor_sp->GetByteSize())
250f190ec68SMed Ismail Bennani     return 0;
251f190ec68SMed Ismail Bennani 
252e73dd625SDavid Spickett   lldb::offset_t bytes_written =
253f190ec68SMed Ismail Bennani       GetInterface().WriteMemoryAtAddress(vm_addr, data_extractor_sp, error);
254f190ec68SMed Ismail Bennani 
255f190ec68SMed Ismail Bennani   if (!bytes_written || bytes_written == LLDB_INVALID_OFFSET)
256f190ec68SMed Ismail Bennani     return ScriptedInterface::ErrorWithMessage<size_t>(
257f190ec68SMed Ismail Bennani         LLVM_PRETTY_FUNCTION, "Failed to copy write buffer to memory.", error);
258f190ec68SMed Ismail Bennani 
259f190ec68SMed Ismail Bennani   // FIXME: We should use the diagnostic system to report a warning if the
260f190ec68SMed Ismail Bennani   // `bytes_written` is different from `size`.
261f190ec68SMed Ismail Bennani 
262f190ec68SMed Ismail Bennani   return bytes_written;
263312b43daSMed Ismail Bennani }
264312b43daSMed Ismail Bennani 
265ad03aeadSMed Ismail Bennani Status ScriptedProcess::EnableBreakpointSite(BreakpointSite *bp_site) {
266ad03aeadSMed Ismail Bennani   assert(bp_site != nullptr);
267ad03aeadSMed Ismail Bennani 
268ad03aeadSMed Ismail Bennani   if (bp_site->IsEnabled()) {
269ad03aeadSMed Ismail Bennani     return {};
270ad03aeadSMed Ismail Bennani   }
271ad03aeadSMed Ismail Bennani 
272ad03aeadSMed Ismail Bennani   if (bp_site->HardwareRequired()) {
2730642cd76SAdrian Prantl     return Status::FromErrorString(
2740642cd76SAdrian Prantl         "Scripted Processes don't support hardware breakpoints");
275ad03aeadSMed Ismail Bennani   }
276ad03aeadSMed Ismail Bennani 
277e31d0c20SMed Ismail Bennani   Status error;
278e31d0c20SMed Ismail Bennani   GetInterface().CreateBreakpoint(bp_site->GetLoadAddress(), error);
279e31d0c20SMed Ismail Bennani 
280e31d0c20SMed Ismail Bennani   return error;
281ad03aeadSMed Ismail Bennani }
282ad03aeadSMed Ismail Bennani 
283312b43daSMed Ismail Bennani ArchSpec ScriptedProcess::GetArchitecture() {
284312b43daSMed Ismail Bennani   return GetTarget().GetArchitecture();
285312b43daSMed Ismail Bennani }
286312b43daSMed Ismail Bennani 
2872937b282SDavid Spickett Status ScriptedProcess::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
288312b43daSMed Ismail Bennani                                               MemoryRegionInfo &region) {
289a758c9f7SMed Ismail Bennani   Status error;
290a758c9f7SMed Ismail Bennani   if (auto region_or_err =
291a758c9f7SMed Ismail Bennani           GetInterface().GetMemoryRegionContainingAddress(load_addr, error))
292a758c9f7SMed Ismail Bennani     region = *region_or_err;
293a758c9f7SMed Ismail Bennani 
294a758c9f7SMed Ismail Bennani   return error;
295312b43daSMed Ismail Bennani }
296312b43daSMed Ismail Bennani 
297312b43daSMed Ismail Bennani Status ScriptedProcess::GetMemoryRegions(MemoryRegionInfos &region_list) {
298a758c9f7SMed Ismail Bennani   Status error;
299312b43daSMed Ismail Bennani   lldb::addr_t address = 0;
300312b43daSMed Ismail Bennani 
301a758c9f7SMed Ismail Bennani   while (auto region_or_err =
302a758c9f7SMed Ismail Bennani              GetInterface().GetMemoryRegionContainingAddress(address, error)) {
303a758c9f7SMed Ismail Bennani     if (error.Fail())
304a758c9f7SMed Ismail Bennani       break;
305a758c9f7SMed Ismail Bennani 
306a758c9f7SMed Ismail Bennani     MemoryRegionInfo &mem_region = *region_or_err;
307a758c9f7SMed Ismail Bennani     auto range = mem_region.GetRange();
308312b43daSMed Ismail Bennani     address += range.GetRangeBase() + range.GetByteSize();
309a758c9f7SMed Ismail Bennani     region_list.push_back(mem_region);
310312b43daSMed Ismail Bennani   }
311312b43daSMed Ismail Bennani 
312a758c9f7SMed Ismail Bennani   return error;
313312b43daSMed Ismail Bennani }
314312b43daSMed Ismail Bennani 
315312b43daSMed Ismail Bennani void ScriptedProcess::Clear() { Process::m_thread_list.Clear(); }
316312b43daSMed Ismail Bennani 
317312b43daSMed Ismail Bennani bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list,
318312b43daSMed Ismail Bennani                                          ThreadList &new_thread_list) {
319312b43daSMed Ismail Bennani   // TODO: Implement
320312b43daSMed Ismail Bennani   // This is supposed to get the current set of threads, if any of them are in
321312b43daSMed Ismail Bennani   // old_thread_list then they get copied to new_thread_list, and then any
322312b43daSMed Ismail Bennani   // actually new threads will get added to new_thread_list.
323676576b6SMed Ismail Bennani   m_thread_plans.ClearThreadCache();
32459d8dd79SMed Ismail Bennani 
32559d8dd79SMed Ismail Bennani   Status error;
326d3e0f7e1SMed Ismail Bennani   StructuredData::DictionarySP thread_info_sp = GetInterface().GetThreadsInfo();
327d3e0f7e1SMed Ismail Bennani 
328d3e0f7e1SMed Ismail Bennani   if (!thread_info_sp)
32991bb1161SMed Ismail Bennani     return ScriptedInterface::ErrorWithMessage<bool>(
330d3e0f7e1SMed Ismail Bennani         LLVM_PRETTY_FUNCTION,
331d3e0f7e1SMed Ismail Bennani         "Couldn't fetch thread list from Scripted Process.", error);
332d3e0f7e1SMed Ismail Bennani 
333150db43eSMed Ismail Bennani   // Because `StructuredData::Dictionary` uses a `std::map<ConstString,
334150db43eSMed Ismail Bennani   // ObjectSP>` for storage, each item is sorted based on the key alphabetical
335150db43eSMed Ismail Bennani   // order. Since `GetThreadsInfo` provides thread indices as the key element,
336150db43eSMed Ismail Bennani   // thread info comes ordered alphabetically, instead of numerically, so we
337150db43eSMed Ismail Bennani   // need to sort the thread indices before creating thread.
338150db43eSMed Ismail Bennani 
339150db43eSMed Ismail Bennani   StructuredData::ArraySP keys = thread_info_sp->GetKeys();
340150db43eSMed Ismail Bennani 
341150db43eSMed Ismail Bennani   std::map<size_t, StructuredData::ObjectSP> sorted_threads;
342150db43eSMed Ismail Bennani   auto sort_keys = [&sorted_threads,
343150db43eSMed Ismail Bennani                     &thread_info_sp](StructuredData::Object *item) -> bool {
344150db43eSMed Ismail Bennani     if (!item)
345150db43eSMed Ismail Bennani       return false;
346150db43eSMed Ismail Bennani 
347150db43eSMed Ismail Bennani     llvm::StringRef key = item->GetStringValue();
348150db43eSMed Ismail Bennani     size_t idx = 0;
349150db43eSMed Ismail Bennani 
350150db43eSMed Ismail Bennani     // Make sure the provided index is actually an integer
351150db43eSMed Ismail Bennani     if (!llvm::to_integer(key, idx))
352150db43eSMed Ismail Bennani       return false;
353150db43eSMed Ismail Bennani 
354150db43eSMed Ismail Bennani     sorted_threads[idx] = thread_info_sp->GetValueForKey(key);
355150db43eSMed Ismail Bennani     return true;
356150db43eSMed Ismail Bennani   };
357150db43eSMed Ismail Bennani 
358150db43eSMed Ismail Bennani   size_t thread_count = thread_info_sp->GetSize();
359150db43eSMed Ismail Bennani 
360150db43eSMed Ismail Bennani   if (!keys->ForEach(sort_keys) || sorted_threads.size() != thread_count)
361150db43eSMed Ismail Bennani     // Might be worth showing the unsorted thread list instead of return early.
362150db43eSMed Ismail Bennani     return ScriptedInterface::ErrorWithMessage<bool>(
363150db43eSMed Ismail Bennani         LLVM_PRETTY_FUNCTION, "Couldn't sort thread list.", error);
364150db43eSMed Ismail Bennani 
365d3e0f7e1SMed Ismail Bennani   auto create_scripted_thread =
366150db43eSMed Ismail Bennani       [this, &error, &new_thread_list](
367150db43eSMed Ismail Bennani           const std::pair<size_t, StructuredData::ObjectSP> pair) -> bool {
368150db43eSMed Ismail Bennani     size_t idx = pair.first;
369150db43eSMed Ismail Bennani     StructuredData::ObjectSP object_sp = pair.second;
370150db43eSMed Ismail Bennani 
371150db43eSMed Ismail Bennani     if (!object_sp)
37291bb1161SMed Ismail Bennani       return ScriptedInterface::ErrorWithMessage<bool>(
373d3e0f7e1SMed Ismail Bennani           LLVM_PRETTY_FUNCTION, "Invalid thread info object", error);
374d3e0f7e1SMed Ismail Bennani 
375150db43eSMed Ismail Bennani     auto thread_or_error =
376150db43eSMed Ismail Bennani         ScriptedThread::Create(*this, object_sp->GetAsGeneric());
37759d8dd79SMed Ismail Bennani 
37845148bfeSMed Ismail Bennani     if (!thread_or_error)
37991bb1161SMed Ismail Bennani       return ScriptedInterface::ErrorWithMessage<bool>(
38045148bfeSMed Ismail Bennani           LLVM_PRETTY_FUNCTION, toString(thread_or_error.takeError()), error);
38145148bfeSMed Ismail Bennani 
38245148bfeSMed Ismail Bennani     ThreadSP thread_sp = thread_or_error.get();
38345148bfeSMed Ismail Bennani     lldbassert(thread_sp && "Couldn't initialize scripted thread.");
38459d8dd79SMed Ismail Bennani 
385caea440aSMed Ismail Bennani     RegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext();
386caea440aSMed Ismail Bennani     if (!reg_ctx_sp)
38791bb1161SMed Ismail Bennani       return ScriptedInterface::ErrorWithMessage<bool>(
388d3e0f7e1SMed Ismail Bennani           LLVM_PRETTY_FUNCTION,
389150db43eSMed Ismail Bennani           llvm::Twine("Invalid Register Context for thread " + llvm::Twine(idx))
390d3e0f7e1SMed Ismail Bennani               .str(),
391d3e0f7e1SMed Ismail Bennani           error);
392caea440aSMed Ismail Bennani 
39359d8dd79SMed Ismail Bennani     new_thread_list.AddThread(thread_sp);
39459d8dd79SMed Ismail Bennani 
395d3e0f7e1SMed Ismail Bennani     return true;
396d3e0f7e1SMed Ismail Bennani   };
397d3e0f7e1SMed Ismail Bennani 
398150db43eSMed Ismail Bennani   llvm::for_each(sorted_threads, create_scripted_thread);
399d3e0f7e1SMed Ismail Bennani 
400312b43daSMed Ismail Bennani   return new_thread_list.GetSize(false) > 0;
401312b43daSMed Ismail Bennani }
402312b43daSMed Ismail Bennani 
403676576b6SMed Ismail Bennani void ScriptedProcess::RefreshStateAfterStop() {
404676576b6SMed Ismail Bennani   // Let all threads recover from stopping and do any clean up based on the
405676576b6SMed Ismail Bennani   // previous thread state (if any).
40670665844SMed Ismail Bennani   m_thread_list.RefreshStateAfterStop();
407676576b6SMed Ismail Bennani }
408676576b6SMed Ismail Bennani 
409312b43daSMed Ismail Bennani bool ScriptedProcess::GetProcessInfo(ProcessInstanceInfo &info) {
410312b43daSMed Ismail Bennani   info.Clear();
411312b43daSMed Ismail Bennani   info.SetProcessID(GetID());
412312b43daSMed Ismail Bennani   info.SetArchitecture(GetArchitecture());
413312b43daSMed Ismail Bennani   lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();
414312b43daSMed Ismail Bennani   if (module_sp) {
415312b43daSMed Ismail Bennani     const bool add_exe_file_as_first_arg = false;
416312b43daSMed Ismail Bennani     info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),
417312b43daSMed Ismail Bennani                            add_exe_file_as_first_arg);
418312b43daSMed Ismail Bennani   }
419312b43daSMed Ismail Bennani   return true;
420312b43daSMed Ismail Bennani }
421312b43daSMed Ismail Bennani 
422680ca7f2SMed Ismail Bennani lldb_private::StructuredData::ObjectSP
423680ca7f2SMed Ismail Bennani ScriptedProcess::GetLoadedDynamicLibrariesInfos() {
424680ca7f2SMed Ismail Bennani   Status error;
425680ca7f2SMed Ismail Bennani   auto error_with_message = [&error](llvm::StringRef message) {
426680ca7f2SMed Ismail Bennani     return ScriptedInterface::ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION,
427680ca7f2SMed Ismail Bennani                                                      message.data(), error);
428680ca7f2SMed Ismail Bennani   };
429680ca7f2SMed Ismail Bennani 
430680ca7f2SMed Ismail Bennani   StructuredData::ArraySP loaded_images_sp = GetInterface().GetLoadedImages();
431680ca7f2SMed Ismail Bennani 
432680ca7f2SMed Ismail Bennani   if (!loaded_images_sp || !loaded_images_sp->GetSize())
433cc05487aSMed Ismail Bennani     return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(
434680ca7f2SMed Ismail Bennani         LLVM_PRETTY_FUNCTION, "No loaded images.", error);
435680ca7f2SMed Ismail Bennani 
436680ca7f2SMed Ismail Bennani   ModuleList module_list;
437680ca7f2SMed Ismail Bennani   Target &target = GetTarget();
438680ca7f2SMed Ismail Bennani 
439680ca7f2SMed Ismail Bennani   auto reload_image = [&target, &module_list, &error_with_message](
440680ca7f2SMed Ismail Bennani                           StructuredData::Object *obj) -> bool {
441680ca7f2SMed Ismail Bennani     StructuredData::Dictionary *dict = obj->GetAsDictionary();
442680ca7f2SMed Ismail Bennani 
443680ca7f2SMed Ismail Bennani     if (!dict)
444680ca7f2SMed Ismail Bennani       return error_with_message("Couldn't cast image object into dictionary.");
445680ca7f2SMed Ismail Bennani 
446680ca7f2SMed Ismail Bennani     ModuleSpec module_spec;
447680ca7f2SMed Ismail Bennani     llvm::StringRef value;
448680ca7f2SMed Ismail Bennani 
449680ca7f2SMed Ismail Bennani     bool has_path = dict->HasKey("path");
450680ca7f2SMed Ismail Bennani     bool has_uuid = dict->HasKey("uuid");
451680ca7f2SMed Ismail Bennani     if (!has_path && !has_uuid)
452680ca7f2SMed Ismail Bennani       return error_with_message("Dictionary should have key 'path' or 'uuid'");
453680ca7f2SMed Ismail Bennani     if (!dict->HasKey("load_addr"))
454680ca7f2SMed Ismail Bennani       return error_with_message("Dictionary is missing key 'load_addr'");
455680ca7f2SMed Ismail Bennani 
456680ca7f2SMed Ismail Bennani     if (has_path) {
457680ca7f2SMed Ismail Bennani       dict->GetValueForKeyAsString("path", value);
458680ca7f2SMed Ismail Bennani       module_spec.GetFileSpec().SetPath(value);
459680ca7f2SMed Ismail Bennani     }
460680ca7f2SMed Ismail Bennani 
461680ca7f2SMed Ismail Bennani     if (has_uuid) {
462680ca7f2SMed Ismail Bennani       dict->GetValueForKeyAsString("uuid", value);
463680ca7f2SMed Ismail Bennani       module_spec.GetUUID().SetFromStringRef(value);
464680ca7f2SMed Ismail Bennani     }
465680ca7f2SMed Ismail Bennani     module_spec.GetArchitecture() = target.GetArchitecture();
466680ca7f2SMed Ismail Bennani 
467680ca7f2SMed Ismail Bennani     ModuleSP module_sp =
468680ca7f2SMed Ismail Bennani         target.GetOrCreateModule(module_spec, true /* notify */);
469680ca7f2SMed Ismail Bennani 
470680ca7f2SMed Ismail Bennani     if (!module_sp)
471680ca7f2SMed Ismail Bennani       return error_with_message("Couldn't create or get module.");
472680ca7f2SMed Ismail Bennani 
473680ca7f2SMed Ismail Bennani     lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
4741370a1cbSMed Ismail Bennani     lldb::offset_t slide = LLDB_INVALID_OFFSET;
475680ca7f2SMed Ismail Bennani     dict->GetValueForKeyAsInteger("load_addr", load_addr);
476680ca7f2SMed Ismail Bennani     dict->GetValueForKeyAsInteger("slide", slide);
477680ca7f2SMed Ismail Bennani     if (load_addr == LLDB_INVALID_ADDRESS)
478680ca7f2SMed Ismail Bennani       return error_with_message(
479680ca7f2SMed Ismail Bennani           "Couldn't get valid load address or slide offset.");
480680ca7f2SMed Ismail Bennani 
481680ca7f2SMed Ismail Bennani     if (slide != LLDB_INVALID_OFFSET)
482680ca7f2SMed Ismail Bennani       load_addr += slide;
483680ca7f2SMed Ismail Bennani 
484680ca7f2SMed Ismail Bennani     bool changed = false;
485680ca7f2SMed Ismail Bennani     module_sp->SetLoadAddress(target, load_addr, false /*=value_is_offset*/,
486680ca7f2SMed Ismail Bennani                               changed);
487680ca7f2SMed Ismail Bennani 
488680ca7f2SMed Ismail Bennani     if (!changed && !module_sp->GetObjectFile())
489680ca7f2SMed Ismail Bennani       return error_with_message("Couldn't set the load address for module.");
490680ca7f2SMed Ismail Bennani 
491680ca7f2SMed Ismail Bennani     dict->GetValueForKeyAsString("path", value);
492680ca7f2SMed Ismail Bennani     FileSpec objfile(value);
493680ca7f2SMed Ismail Bennani     module_sp->SetFileSpecAndObjectName(objfile, objfile.GetFilename());
494680ca7f2SMed Ismail Bennani 
495680ca7f2SMed Ismail Bennani     return module_list.AppendIfNeeded(module_sp);
496680ca7f2SMed Ismail Bennani   };
497680ca7f2SMed Ismail Bennani 
498680ca7f2SMed Ismail Bennani   if (!loaded_images_sp->ForEach(reload_image))
499cc05487aSMed Ismail Bennani     return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(
500680ca7f2SMed Ismail Bennani         LLVM_PRETTY_FUNCTION, "Couldn't reload all images.", error);
501680ca7f2SMed Ismail Bennani 
502680ca7f2SMed Ismail Bennani   target.ModulesDidLoad(module_list);
503680ca7f2SMed Ismail Bennani 
504680ca7f2SMed Ismail Bennani   return loaded_images_sp;
505680ca7f2SMed Ismail Bennani }
506680ca7f2SMed Ismail Bennani 
50778d6e1d1SMed Ismail Bennani lldb_private::StructuredData::DictionarySP ScriptedProcess::GetMetadata() {
50878d6e1d1SMed Ismail Bennani   StructuredData::DictionarySP metadata_sp = GetInterface().GetMetadata();
50978d6e1d1SMed Ismail Bennani 
51078d6e1d1SMed Ismail Bennani   Status error;
51178d6e1d1SMed Ismail Bennani   if (!metadata_sp || !metadata_sp->GetSize())
51278d6e1d1SMed Ismail Bennani     return ScriptedInterface::ErrorWithMessage<StructuredData::DictionarySP>(
51378d6e1d1SMed Ismail Bennani         LLVM_PRETTY_FUNCTION, "No metadata.", error);
51478d6e1d1SMed Ismail Bennani 
51578d6e1d1SMed Ismail Bennani   return metadata_sp;
51678d6e1d1SMed Ismail Bennani }
51778d6e1d1SMed Ismail Bennani 
51844b81f62SMed Ismail Bennani void ScriptedProcess::UpdateQueueListIfNeeded() {
519a3d4f739SMed Ismail Bennani   CheckScriptedInterface();
52044b81f62SMed Ismail Bennani   for (ThreadSP thread_sp : Threads()) {
52144b81f62SMed Ismail Bennani     if (const char *queue_name = thread_sp->GetQueueName()) {
52244b81f62SMed Ismail Bennani       QueueSP queue_sp = std::make_shared<Queue>(
52344b81f62SMed Ismail Bennani           m_process->shared_from_this(), thread_sp->GetQueueID(), queue_name);
52444b81f62SMed Ismail Bennani       m_queue_list.AddQueue(queue_sp);
52544b81f62SMed Ismail Bennani     }
52644b81f62SMed Ismail Bennani   }
52744b81f62SMed Ismail Bennani }
52844b81f62SMed Ismail Bennani 
529312b43daSMed Ismail Bennani ScriptedProcessInterface &ScriptedProcess::GetInterface() const {
530a3d4f739SMed Ismail Bennani   CheckScriptedInterface();
531a3d4f739SMed Ismail Bennani   return *m_interface_up;
532312b43daSMed Ismail Bennani }
533c1928033SMed Ismail Bennani 
534c1928033SMed Ismail Bennani void *ScriptedProcess::GetImplementation() {
535a3d4f739SMed Ismail Bennani   StructuredData::GenericSP object_instance_sp =
536a3d4f739SMed Ismail Bennani       GetInterface().GetScriptObjectInstance();
537a3d4f739SMed Ismail Bennani   if (object_instance_sp &&
538a3d4f739SMed Ismail Bennani       object_instance_sp->GetType() == eStructuredDataTypeGeneric)
539a3d4f739SMed Ismail Bennani     return object_instance_sp->GetAsGeneric()->GetValue();
540c1928033SMed Ismail Bennani   return nullptr;
541c1928033SMed Ismail Bennani }
542