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" 25*06c3fb27SDimitry 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 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 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 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 64*06c3fb27SDimitry 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 72fe6060f1SDimitry Andric bool ScriptedProcess::CanDebug(lldb::TargetSP target_sp, 73fe6060f1SDimitry Andric bool plugin_specified_by_name) { 74fe6060f1SDimitry Andric return true; 75fe6060f1SDimitry Andric } 76fe6060f1SDimitry Andric 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 89*06c3fb27SDimitry Andric ScriptInterpreter *interpreter = 90*06c3fb27SDimitry Andric target_sp->GetDebugger().GetScriptInterpreter(); 91fe6060f1SDimitry Andric 92*06c3fb27SDimitry 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 99*06c3fb27SDimitry Andric // Create process instance interface 100*06c3fb27SDimitry Andric m_interface_up = interpreter->CreateScriptedProcessInterface(); 101*06c3fb27SDimitry Andric if (!m_interface_up) { 102*06c3fb27SDimitry Andric error.SetErrorStringWithFormat( 103*06c3fb27SDimitry Andric "ScriptedProcess::%s () - ERROR: %s", __FUNCTION__, 104*06c3fb27SDimitry Andric "Script interpreter couldn't create Scripted Process Interface"); 105*06c3fb27SDimitry Andric return; 106*06c3fb27SDimitry Andric } 107*06c3fb27SDimitry Andric 108349cc55cSDimitry Andric ExecutionContext exe_ctx(target_sp, /*get_process=*/false); 109349cc55cSDimitry Andric 110*06c3fb27SDimitry Andric // Create process script object 111349cc55cSDimitry Andric StructuredData::GenericSP object_sp = GetInterface().CreatePluginObject( 112bdd1243dSDimitry Andric m_scripted_metadata.GetClassName(), exe_ctx, 113bdd1243dSDimitry Andric m_scripted_metadata.GetArgsSP()); 114fe6060f1SDimitry Andric 115fe6060f1SDimitry Andric if (!object_sp || !object_sp->IsValid()) { 116fe6060f1SDimitry Andric error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s", 117fe6060f1SDimitry Andric __FUNCTION__, 118fe6060f1SDimitry Andric "Failed to create valid script object"); 119fe6060f1SDimitry Andric return; 120fe6060f1SDimitry Andric } 121fe6060f1SDimitry Andric } 122fe6060f1SDimitry Andric 123fe6060f1SDimitry Andric ScriptedProcess::~ScriptedProcess() { 124fe6060f1SDimitry Andric Clear(); 125fe6060f1SDimitry Andric // We need to call finalize on the process before destroying ourselves to 126fe6060f1SDimitry Andric // make sure all of the broadcaster cleanup goes as planned. If we destruct 127fe6060f1SDimitry Andric // this class, then Process::~Process() might have problems trying to fully 128fe6060f1SDimitry Andric // destroy the broadcaster. 129fe6060f1SDimitry Andric Finalize(); 130fe6060f1SDimitry Andric } 131fe6060f1SDimitry Andric 132fe6060f1SDimitry Andric void ScriptedProcess::Initialize() { 133fe6060f1SDimitry Andric static llvm::once_flag g_once_flag; 134fe6060f1SDimitry Andric 135fe6060f1SDimitry Andric llvm::call_once(g_once_flag, []() { 136fe6060f1SDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(), 137fe6060f1SDimitry Andric GetPluginDescriptionStatic(), CreateInstance); 138fe6060f1SDimitry Andric }); 139fe6060f1SDimitry Andric } 140fe6060f1SDimitry Andric 141fe6060f1SDimitry Andric void ScriptedProcess::Terminate() { 142fe6060f1SDimitry Andric PluginManager::UnregisterPlugin(ScriptedProcess::CreateInstance); 143fe6060f1SDimitry Andric } 144fe6060f1SDimitry Andric 145fe6060f1SDimitry Andric Status ScriptedProcess::DoLoadCore() { 146fe6060f1SDimitry Andric ProcessLaunchInfo launch_info = GetTarget().GetProcessLaunchInfo(); 147fe6060f1SDimitry Andric 148fe6060f1SDimitry Andric return DoLaunch(nullptr, launch_info); 149fe6060f1SDimitry Andric } 150fe6060f1SDimitry Andric 151fe6060f1SDimitry Andric Status ScriptedProcess::DoLaunch(Module *exe_module, 152fe6060f1SDimitry Andric ProcessLaunchInfo &launch_info) { 153*06c3fb27SDimitry Andric LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s launching process", __FUNCTION__); 154fe6060f1SDimitry Andric 155*06c3fb27SDimitry Andric /* MARK: This doesn't reflect how lldb actually launches a process. 156*06c3fb27SDimitry Andric In reality, it attaches to debugserver, then resume the process. 157*06c3fb27SDimitry Andric That's not true in all cases. If debugserver is remote, lldb 158*06c3fb27SDimitry Andric asks debugserver to launch the process for it. */ 159fe6060f1SDimitry Andric Status error = GetInterface().Launch(); 160fe6060f1SDimitry Andric SetPrivateState(eStateStopped); 161*06c3fb27SDimitry Andric return error; 162fe6060f1SDimitry Andric } 163fe6060f1SDimitry Andric 164*06c3fb27SDimitry Andric void ScriptedProcess::DidLaunch() { m_pid = GetInterface().GetProcessID(); } 165*06c3fb27SDimitry Andric 166*06c3fb27SDimitry Andric void ScriptedProcess::DidResume() { 167*06c3fb27SDimitry Andric // Update the PID again, in case the user provided a placeholder pid at launch 168fe6060f1SDimitry Andric m_pid = GetInterface().GetProcessID(); 169fe6060f1SDimitry Andric } 170fe6060f1SDimitry Andric 171fe6060f1SDimitry Andric Status ScriptedProcess::DoResume() { 172*06c3fb27SDimitry Andric LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s resuming process", __FUNCTION__); 173fe6060f1SDimitry Andric 174*06c3fb27SDimitry Andric return GetInterface().Resume(); 175*06c3fb27SDimitry Andric } 176fe6060f1SDimitry Andric 177*06c3fb27SDimitry Andric Status ScriptedProcess::DoAttach(const ProcessAttachInfo &attach_info) { 178*06c3fb27SDimitry Andric Status error = GetInterface().Attach(attach_info); 179fe6060f1SDimitry Andric SetPrivateState(eStateRunning); 180fe6060f1SDimitry Andric SetPrivateState(eStateStopped); 181*06c3fb27SDimitry Andric if (error.Fail()) 182fe6060f1SDimitry Andric return error; 183*06c3fb27SDimitry Andric // NOTE: We need to set the PID before finishing to attach otherwise we will 184*06c3fb27SDimitry Andric // hit an assert when calling the attach completion handler. 185*06c3fb27SDimitry Andric DidLaunch(); 186fe6060f1SDimitry Andric 187fe6060f1SDimitry Andric return {}; 188fe6060f1SDimitry Andric } 189fe6060f1SDimitry Andric 190*06c3fb27SDimitry Andric Status 191*06c3fb27SDimitry Andric ScriptedProcess::DoAttachToProcessWithID(lldb::pid_t pid, 192*06c3fb27SDimitry Andric const ProcessAttachInfo &attach_info) { 193*06c3fb27SDimitry Andric return DoAttach(attach_info); 194*06c3fb27SDimitry Andric } 195*06c3fb27SDimitry Andric 196*06c3fb27SDimitry Andric Status ScriptedProcess::DoAttachToProcessWithName( 197*06c3fb27SDimitry Andric const char *process_name, const ProcessAttachInfo &attach_info) { 198*06c3fb27SDimitry Andric return DoAttach(attach_info); 199*06c3fb27SDimitry Andric } 200*06c3fb27SDimitry Andric 201*06c3fb27SDimitry Andric void ScriptedProcess::DidAttach(ArchSpec &process_arch) { 202*06c3fb27SDimitry Andric process_arch = GetArchitecture(); 203fe6060f1SDimitry Andric } 204fe6060f1SDimitry Andric 205fe6060f1SDimitry Andric Status ScriptedProcess::DoDestroy() { return Status(); } 206fe6060f1SDimitry Andric 207*06c3fb27SDimitry Andric bool ScriptedProcess::IsAlive() { return GetInterface().IsAlive(); } 208fe6060f1SDimitry Andric 209fe6060f1SDimitry Andric size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, 210fe6060f1SDimitry Andric Status &error) { 211fe6060f1SDimitry Andric lldb::DataExtractorSP data_extractor_sp = 212fe6060f1SDimitry Andric GetInterface().ReadMemoryAtAddress(addr, size, error); 213fe6060f1SDimitry Andric 214349cc55cSDimitry Andric if (!data_extractor_sp || !data_extractor_sp->GetByteSize() || error.Fail()) 215fe6060f1SDimitry Andric return 0; 216fe6060f1SDimitry Andric 217fe6060f1SDimitry Andric offset_t bytes_copied = data_extractor_sp->CopyByteOrderedData( 218fe6060f1SDimitry Andric 0, data_extractor_sp->GetByteSize(), buf, size, GetByteOrder()); 219fe6060f1SDimitry Andric 220fe6060f1SDimitry Andric if (!bytes_copied || bytes_copied == LLDB_INVALID_OFFSET) 22104eeddc0SDimitry Andric return ScriptedInterface::ErrorWithMessage<size_t>( 222349cc55cSDimitry Andric LLVM_PRETTY_FUNCTION, "Failed to copy read memory to buffer.", error); 223fe6060f1SDimitry Andric 224*06c3fb27SDimitry Andric // FIXME: We should use the diagnostic system to report a warning if the 225*06c3fb27SDimitry Andric // `bytes_copied` is different from `size`. 226*06c3fb27SDimitry Andric 227*06c3fb27SDimitry Andric return bytes_copied; 228*06c3fb27SDimitry Andric } 229*06c3fb27SDimitry Andric 230*06c3fb27SDimitry Andric size_t ScriptedProcess::DoWriteMemory(lldb::addr_t vm_addr, const void *buf, 231*06c3fb27SDimitry Andric size_t size, Status &error) { 232*06c3fb27SDimitry Andric lldb::DataExtractorSP data_extractor_sp = std::make_shared<DataExtractor>( 233*06c3fb27SDimitry Andric buf, size, GetByteOrder(), GetAddressByteSize()); 234*06c3fb27SDimitry Andric 235*06c3fb27SDimitry Andric if (!data_extractor_sp || !data_extractor_sp->GetByteSize()) 236*06c3fb27SDimitry Andric return 0; 237*06c3fb27SDimitry Andric 238*06c3fb27SDimitry Andric lldb::offset_t bytes_written = 239*06c3fb27SDimitry Andric GetInterface().WriteMemoryAtAddress(vm_addr, data_extractor_sp, error); 240*06c3fb27SDimitry Andric 241*06c3fb27SDimitry Andric if (!bytes_written || bytes_written == LLDB_INVALID_OFFSET) 242*06c3fb27SDimitry Andric return ScriptedInterface::ErrorWithMessage<size_t>( 243*06c3fb27SDimitry Andric LLVM_PRETTY_FUNCTION, "Failed to copy write buffer to memory.", error); 244*06c3fb27SDimitry Andric 245*06c3fb27SDimitry Andric // FIXME: We should use the diagnostic system to report a warning if the 246*06c3fb27SDimitry Andric // `bytes_written` is different from `size`. 247*06c3fb27SDimitry Andric 248*06c3fb27SDimitry Andric return bytes_written; 249*06c3fb27SDimitry Andric } 250*06c3fb27SDimitry Andric 251*06c3fb27SDimitry Andric Status ScriptedProcess::EnableBreakpointSite(BreakpointSite *bp_site) { 252*06c3fb27SDimitry Andric assert(bp_site != nullptr); 253*06c3fb27SDimitry Andric 254*06c3fb27SDimitry Andric if (bp_site->IsEnabled()) { 255*06c3fb27SDimitry Andric return {}; 256*06c3fb27SDimitry Andric } 257*06c3fb27SDimitry Andric 258*06c3fb27SDimitry Andric if (bp_site->HardwareRequired()) { 259*06c3fb27SDimitry Andric return Status("Scripted Processes don't support hardware breakpoints"); 260*06c3fb27SDimitry Andric } 261*06c3fb27SDimitry Andric 262*06c3fb27SDimitry Andric Status error; 263*06c3fb27SDimitry Andric GetInterface().CreateBreakpoint(bp_site->GetLoadAddress(), error); 264*06c3fb27SDimitry Andric 265*06c3fb27SDimitry Andric return error; 266fe6060f1SDimitry Andric } 267fe6060f1SDimitry Andric 268fe6060f1SDimitry Andric ArchSpec ScriptedProcess::GetArchitecture() { 269fe6060f1SDimitry Andric return GetTarget().GetArchitecture(); 270fe6060f1SDimitry Andric } 271fe6060f1SDimitry Andric 272d56accc7SDimitry Andric Status ScriptedProcess::DoGetMemoryRegionInfo(lldb::addr_t load_addr, 273fe6060f1SDimitry Andric MemoryRegionInfo ®ion) { 274349cc55cSDimitry Andric Status error; 275349cc55cSDimitry Andric if (auto region_or_err = 276349cc55cSDimitry Andric GetInterface().GetMemoryRegionContainingAddress(load_addr, error)) 277349cc55cSDimitry Andric region = *region_or_err; 278349cc55cSDimitry Andric 279349cc55cSDimitry Andric return error; 280fe6060f1SDimitry Andric } 281fe6060f1SDimitry Andric 282fe6060f1SDimitry Andric Status ScriptedProcess::GetMemoryRegions(MemoryRegionInfos ®ion_list) { 283349cc55cSDimitry Andric Status error; 284fe6060f1SDimitry Andric lldb::addr_t address = 0; 285fe6060f1SDimitry Andric 286349cc55cSDimitry Andric while (auto region_or_err = 287349cc55cSDimitry Andric GetInterface().GetMemoryRegionContainingAddress(address, error)) { 288349cc55cSDimitry Andric if (error.Fail()) 289349cc55cSDimitry Andric break; 290349cc55cSDimitry Andric 291349cc55cSDimitry Andric MemoryRegionInfo &mem_region = *region_or_err; 292349cc55cSDimitry Andric auto range = mem_region.GetRange(); 293fe6060f1SDimitry Andric address += range.GetRangeBase() + range.GetByteSize(); 294349cc55cSDimitry Andric region_list.push_back(mem_region); 295fe6060f1SDimitry Andric } 296fe6060f1SDimitry Andric 297349cc55cSDimitry Andric return error; 298fe6060f1SDimitry Andric } 299fe6060f1SDimitry Andric 300fe6060f1SDimitry Andric void ScriptedProcess::Clear() { Process::m_thread_list.Clear(); } 301fe6060f1SDimitry Andric 302fe6060f1SDimitry Andric bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list, 303fe6060f1SDimitry Andric ThreadList &new_thread_list) { 304fe6060f1SDimitry Andric // TODO: Implement 305fe6060f1SDimitry Andric // This is supposed to get the current set of threads, if any of them are in 306fe6060f1SDimitry Andric // old_thread_list then they get copied to new_thread_list, and then any 307fe6060f1SDimitry Andric // actually new threads will get added to new_thread_list. 308349cc55cSDimitry Andric m_thread_plans.ClearThreadCache(); 309349cc55cSDimitry Andric 310349cc55cSDimitry Andric Status error; 31104eeddc0SDimitry Andric StructuredData::DictionarySP thread_info_sp = GetInterface().GetThreadsInfo(); 312349cc55cSDimitry Andric 31304eeddc0SDimitry Andric if (!thread_info_sp) 31404eeddc0SDimitry Andric return ScriptedInterface::ErrorWithMessage<bool>( 31504eeddc0SDimitry Andric LLVM_PRETTY_FUNCTION, 31604eeddc0SDimitry Andric "Couldn't fetch thread list from Scripted Process.", error); 31704eeddc0SDimitry Andric 31881ad6265SDimitry Andric // Because `StructuredData::Dictionary` uses a `std::map<ConstString, 31981ad6265SDimitry Andric // ObjectSP>` for storage, each item is sorted based on the key alphabetical 32081ad6265SDimitry Andric // order. Since `GetThreadsInfo` provides thread indices as the key element, 32181ad6265SDimitry Andric // thread info comes ordered alphabetically, instead of numerically, so we 32281ad6265SDimitry Andric // need to sort the thread indices before creating thread. 32381ad6265SDimitry Andric 32481ad6265SDimitry Andric StructuredData::ArraySP keys = thread_info_sp->GetKeys(); 32581ad6265SDimitry Andric 32681ad6265SDimitry Andric std::map<size_t, StructuredData::ObjectSP> sorted_threads; 32781ad6265SDimitry Andric auto sort_keys = [&sorted_threads, 32881ad6265SDimitry Andric &thread_info_sp](StructuredData::Object *item) -> bool { 32981ad6265SDimitry Andric if (!item) 33081ad6265SDimitry Andric return false; 33181ad6265SDimitry Andric 33281ad6265SDimitry Andric llvm::StringRef key = item->GetStringValue(); 33381ad6265SDimitry Andric size_t idx = 0; 33481ad6265SDimitry Andric 33581ad6265SDimitry Andric // Make sure the provided index is actually an integer 33681ad6265SDimitry Andric if (!llvm::to_integer(key, idx)) 33781ad6265SDimitry Andric return false; 33881ad6265SDimitry Andric 33981ad6265SDimitry Andric sorted_threads[idx] = thread_info_sp->GetValueForKey(key); 34081ad6265SDimitry Andric return true; 34181ad6265SDimitry Andric }; 34281ad6265SDimitry Andric 34381ad6265SDimitry Andric size_t thread_count = thread_info_sp->GetSize(); 34481ad6265SDimitry Andric 34581ad6265SDimitry Andric if (!keys->ForEach(sort_keys) || sorted_threads.size() != thread_count) 34681ad6265SDimitry Andric // Might be worth showing the unsorted thread list instead of return early. 34781ad6265SDimitry Andric return ScriptedInterface::ErrorWithMessage<bool>( 34881ad6265SDimitry Andric LLVM_PRETTY_FUNCTION, "Couldn't sort thread list.", error); 34981ad6265SDimitry Andric 35004eeddc0SDimitry Andric auto create_scripted_thread = 35181ad6265SDimitry Andric [this, &error, &new_thread_list]( 35281ad6265SDimitry Andric const std::pair<size_t, StructuredData::ObjectSP> pair) -> bool { 35381ad6265SDimitry Andric size_t idx = pair.first; 35481ad6265SDimitry Andric StructuredData::ObjectSP object_sp = pair.second; 35581ad6265SDimitry Andric 35681ad6265SDimitry Andric if (!object_sp) 35704eeddc0SDimitry Andric return ScriptedInterface::ErrorWithMessage<bool>( 35804eeddc0SDimitry Andric LLVM_PRETTY_FUNCTION, "Invalid thread info object", error); 35904eeddc0SDimitry Andric 36081ad6265SDimitry Andric auto thread_or_error = 36181ad6265SDimitry Andric ScriptedThread::Create(*this, object_sp->GetAsGeneric()); 36204eeddc0SDimitry Andric 36304eeddc0SDimitry Andric if (!thread_or_error) 36404eeddc0SDimitry Andric return ScriptedInterface::ErrorWithMessage<bool>( 36504eeddc0SDimitry Andric LLVM_PRETTY_FUNCTION, toString(thread_or_error.takeError()), error); 36604eeddc0SDimitry Andric 36704eeddc0SDimitry Andric ThreadSP thread_sp = thread_or_error.get(); 36804eeddc0SDimitry Andric lldbassert(thread_sp && "Couldn't initialize scripted thread."); 369349cc55cSDimitry Andric 3700eae32dcSDimitry Andric RegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext(); 3710eae32dcSDimitry Andric if (!reg_ctx_sp) 37204eeddc0SDimitry Andric return ScriptedInterface::ErrorWithMessage<bool>( 37304eeddc0SDimitry Andric LLVM_PRETTY_FUNCTION, 37481ad6265SDimitry Andric llvm::Twine("Invalid Register Context for thread " + llvm::Twine(idx)) 37504eeddc0SDimitry Andric .str(), 37604eeddc0SDimitry Andric error); 3770eae32dcSDimitry Andric 378349cc55cSDimitry Andric new_thread_list.AddThread(thread_sp); 379349cc55cSDimitry Andric 38004eeddc0SDimitry Andric return true; 38104eeddc0SDimitry Andric }; 38204eeddc0SDimitry Andric 38381ad6265SDimitry Andric llvm::for_each(sorted_threads, create_scripted_thread); 38404eeddc0SDimitry Andric 385fe6060f1SDimitry Andric return new_thread_list.GetSize(false) > 0; 386fe6060f1SDimitry Andric } 387fe6060f1SDimitry Andric 388349cc55cSDimitry Andric void ScriptedProcess::RefreshStateAfterStop() { 389349cc55cSDimitry Andric // Let all threads recover from stopping and do any clean up based on the 390349cc55cSDimitry Andric // previous thread state (if any). 39181ad6265SDimitry Andric m_thread_list.RefreshStateAfterStop(); 392349cc55cSDimitry Andric } 393349cc55cSDimitry Andric 394fe6060f1SDimitry Andric bool ScriptedProcess::GetProcessInfo(ProcessInstanceInfo &info) { 395fe6060f1SDimitry Andric info.Clear(); 396fe6060f1SDimitry Andric info.SetProcessID(GetID()); 397fe6060f1SDimitry Andric info.SetArchitecture(GetArchitecture()); 398fe6060f1SDimitry Andric lldb::ModuleSP module_sp = GetTarget().GetExecutableModule(); 399fe6060f1SDimitry Andric if (module_sp) { 400fe6060f1SDimitry Andric const bool add_exe_file_as_first_arg = false; 401fe6060f1SDimitry Andric info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(), 402fe6060f1SDimitry Andric add_exe_file_as_first_arg); 403fe6060f1SDimitry Andric } 404fe6060f1SDimitry Andric return true; 405fe6060f1SDimitry Andric } 406fe6060f1SDimitry Andric 40781ad6265SDimitry Andric lldb_private::StructuredData::ObjectSP 40881ad6265SDimitry Andric ScriptedProcess::GetLoadedDynamicLibrariesInfos() { 40981ad6265SDimitry Andric Status error; 41081ad6265SDimitry Andric auto error_with_message = [&error](llvm::StringRef message) { 41181ad6265SDimitry Andric return ScriptedInterface::ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION, 41281ad6265SDimitry Andric message.data(), error); 41381ad6265SDimitry Andric }; 41481ad6265SDimitry Andric 41581ad6265SDimitry Andric StructuredData::ArraySP loaded_images_sp = GetInterface().GetLoadedImages(); 41681ad6265SDimitry Andric 41781ad6265SDimitry Andric if (!loaded_images_sp || !loaded_images_sp->GetSize()) 418bdd1243dSDimitry Andric return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>( 41981ad6265SDimitry Andric LLVM_PRETTY_FUNCTION, "No loaded images.", error); 42081ad6265SDimitry Andric 42181ad6265SDimitry Andric ModuleList module_list; 42281ad6265SDimitry Andric Target &target = GetTarget(); 42381ad6265SDimitry Andric 42481ad6265SDimitry Andric auto reload_image = [&target, &module_list, &error_with_message]( 42581ad6265SDimitry Andric StructuredData::Object *obj) -> bool { 42681ad6265SDimitry Andric StructuredData::Dictionary *dict = obj->GetAsDictionary(); 42781ad6265SDimitry Andric 42881ad6265SDimitry Andric if (!dict) 42981ad6265SDimitry Andric return error_with_message("Couldn't cast image object into dictionary."); 43081ad6265SDimitry Andric 43181ad6265SDimitry Andric ModuleSpec module_spec; 43281ad6265SDimitry Andric llvm::StringRef value; 43381ad6265SDimitry Andric 43481ad6265SDimitry Andric bool has_path = dict->HasKey("path"); 43581ad6265SDimitry Andric bool has_uuid = dict->HasKey("uuid"); 43681ad6265SDimitry Andric if (!has_path && !has_uuid) 43781ad6265SDimitry Andric return error_with_message("Dictionary should have key 'path' or 'uuid'"); 43881ad6265SDimitry Andric if (!dict->HasKey("load_addr")) 43981ad6265SDimitry Andric return error_with_message("Dictionary is missing key 'load_addr'"); 44081ad6265SDimitry Andric 44181ad6265SDimitry Andric if (has_path) { 44281ad6265SDimitry Andric dict->GetValueForKeyAsString("path", value); 44381ad6265SDimitry Andric module_spec.GetFileSpec().SetPath(value); 44481ad6265SDimitry Andric } 44581ad6265SDimitry Andric 44681ad6265SDimitry Andric if (has_uuid) { 44781ad6265SDimitry Andric dict->GetValueForKeyAsString("uuid", value); 44881ad6265SDimitry Andric module_spec.GetUUID().SetFromStringRef(value); 44981ad6265SDimitry Andric } 45081ad6265SDimitry Andric module_spec.GetArchitecture() = target.GetArchitecture(); 45181ad6265SDimitry Andric 45281ad6265SDimitry Andric ModuleSP module_sp = 45381ad6265SDimitry Andric target.GetOrCreateModule(module_spec, true /* notify */); 45481ad6265SDimitry Andric 45581ad6265SDimitry Andric if (!module_sp) 45681ad6265SDimitry Andric return error_with_message("Couldn't create or get module."); 45781ad6265SDimitry Andric 45881ad6265SDimitry Andric lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; 459*06c3fb27SDimitry Andric lldb::offset_t slide = LLDB_INVALID_OFFSET; 46081ad6265SDimitry Andric dict->GetValueForKeyAsInteger("load_addr", load_addr); 46181ad6265SDimitry Andric dict->GetValueForKeyAsInteger("slide", slide); 46281ad6265SDimitry Andric if (load_addr == LLDB_INVALID_ADDRESS) 46381ad6265SDimitry Andric return error_with_message( 46481ad6265SDimitry Andric "Couldn't get valid load address or slide offset."); 46581ad6265SDimitry Andric 46681ad6265SDimitry Andric if (slide != LLDB_INVALID_OFFSET) 46781ad6265SDimitry Andric load_addr += slide; 46881ad6265SDimitry Andric 46981ad6265SDimitry Andric bool changed = false; 47081ad6265SDimitry Andric module_sp->SetLoadAddress(target, load_addr, false /*=value_is_offset*/, 47181ad6265SDimitry Andric changed); 47281ad6265SDimitry Andric 47381ad6265SDimitry Andric if (!changed && !module_sp->GetObjectFile()) 47481ad6265SDimitry Andric return error_with_message("Couldn't set the load address for module."); 47581ad6265SDimitry Andric 47681ad6265SDimitry Andric dict->GetValueForKeyAsString("path", value); 47781ad6265SDimitry Andric FileSpec objfile(value); 47881ad6265SDimitry Andric module_sp->SetFileSpecAndObjectName(objfile, objfile.GetFilename()); 47981ad6265SDimitry Andric 48081ad6265SDimitry Andric return module_list.AppendIfNeeded(module_sp); 48181ad6265SDimitry Andric }; 48281ad6265SDimitry Andric 48381ad6265SDimitry Andric if (!loaded_images_sp->ForEach(reload_image)) 484bdd1243dSDimitry Andric return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>( 48581ad6265SDimitry Andric LLVM_PRETTY_FUNCTION, "Couldn't reload all images.", error); 48681ad6265SDimitry Andric 48781ad6265SDimitry Andric target.ModulesDidLoad(module_list); 48881ad6265SDimitry Andric 48981ad6265SDimitry Andric return loaded_images_sp; 49081ad6265SDimitry Andric } 49181ad6265SDimitry Andric 492bdd1243dSDimitry Andric lldb_private::StructuredData::DictionarySP ScriptedProcess::GetMetadata() { 493bdd1243dSDimitry Andric StructuredData::DictionarySP metadata_sp = GetInterface().GetMetadata(); 494bdd1243dSDimitry Andric 495bdd1243dSDimitry Andric Status error; 496bdd1243dSDimitry Andric if (!metadata_sp || !metadata_sp->GetSize()) 497bdd1243dSDimitry Andric return ScriptedInterface::ErrorWithMessage<StructuredData::DictionarySP>( 498bdd1243dSDimitry Andric LLVM_PRETTY_FUNCTION, "No metadata.", error); 499bdd1243dSDimitry Andric 500bdd1243dSDimitry Andric return metadata_sp; 501bdd1243dSDimitry Andric } 502bdd1243dSDimitry Andric 503bdd1243dSDimitry Andric void ScriptedProcess::UpdateQueueListIfNeeded() { 504*06c3fb27SDimitry Andric CheckScriptedInterface(); 505bdd1243dSDimitry Andric for (ThreadSP thread_sp : Threads()) { 506bdd1243dSDimitry Andric if (const char *queue_name = thread_sp->GetQueueName()) { 507bdd1243dSDimitry Andric QueueSP queue_sp = std::make_shared<Queue>( 508bdd1243dSDimitry Andric m_process->shared_from_this(), thread_sp->GetQueueID(), queue_name); 509bdd1243dSDimitry Andric m_queue_list.AddQueue(queue_sp); 510bdd1243dSDimitry Andric } 511bdd1243dSDimitry Andric } 512bdd1243dSDimitry Andric } 513bdd1243dSDimitry Andric 514fe6060f1SDimitry Andric ScriptedProcessInterface &ScriptedProcess::GetInterface() const { 515*06c3fb27SDimitry Andric CheckScriptedInterface(); 516*06c3fb27SDimitry Andric return *m_interface_up; 517*06c3fb27SDimitry Andric } 518*06c3fb27SDimitry Andric 519*06c3fb27SDimitry Andric void *ScriptedProcess::GetImplementation() { 520*06c3fb27SDimitry Andric StructuredData::GenericSP object_instance_sp = 521*06c3fb27SDimitry Andric GetInterface().GetScriptObjectInstance(); 522*06c3fb27SDimitry Andric if (object_instance_sp && 523*06c3fb27SDimitry Andric object_instance_sp->GetType() == eStructuredDataTypeGeneric) 524*06c3fb27SDimitry Andric return object_instance_sp->GetAsGeneric()->GetValue(); 525*06c3fb27SDimitry Andric return nullptr; 526fe6060f1SDimitry Andric } 527