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