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