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 ®ion) {
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 ®ion_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