1*312b43daSMed Ismail Bennani //===-- ScriptedProcess.cpp -----------------------------------------------===// 2*312b43daSMed Ismail Bennani // 3*312b43daSMed Ismail Bennani // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*312b43daSMed Ismail Bennani // See https://llvm.org/LICENSE.txt for license information. 5*312b43daSMed Ismail Bennani // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*312b43daSMed Ismail Bennani // 7*312b43daSMed Ismail Bennani //===----------------------------------------------------------------------===// 8*312b43daSMed Ismail Bennani 9*312b43daSMed Ismail Bennani #include "ScriptedProcess.h" 10*312b43daSMed Ismail Bennani 11*312b43daSMed Ismail Bennani #include "lldb/Core/Debugger.h" 12*312b43daSMed Ismail Bennani #include "lldb/Core/Module.h" 13*312b43daSMed Ismail Bennani #include "lldb/Core/PluginManager.h" 14*312b43daSMed Ismail Bennani 15*312b43daSMed Ismail Bennani #include "lldb/Host/OptionParser.h" 16*312b43daSMed Ismail Bennani #include "lldb/Host/ThreadLauncher.h" 17*312b43daSMed Ismail Bennani #include "lldb/Interpreter/CommandInterpreter.h" 18*312b43daSMed Ismail Bennani #include "lldb/Interpreter/OptionArgParser.h" 19*312b43daSMed Ismail Bennani #include "lldb/Interpreter/OptionGroupBoolean.h" 20*312b43daSMed Ismail Bennani #include "lldb/Interpreter/ScriptInterpreter.h" 21*312b43daSMed Ismail Bennani #include "lldb/Target/MemoryRegionInfo.h" 22*312b43daSMed Ismail Bennani #include "lldb/Target/RegisterContext.h" 23*312b43daSMed Ismail Bennani 24*312b43daSMed Ismail Bennani #include "lldb/Utility/Log.h" 25*312b43daSMed Ismail Bennani #include "lldb/Utility/Logging.h" 26*312b43daSMed Ismail Bennani #include "lldb/Utility/State.h" 27*312b43daSMed Ismail Bennani 28*312b43daSMed Ismail Bennani #include <mutex> 29*312b43daSMed Ismail Bennani 30*312b43daSMed Ismail Bennani LLDB_PLUGIN_DEFINE(ScriptedProcess) 31*312b43daSMed Ismail Bennani 32*312b43daSMed Ismail Bennani using namespace lldb; 33*312b43daSMed Ismail Bennani using namespace lldb_private; 34*312b43daSMed Ismail Bennani 35*312b43daSMed Ismail Bennani ConstString ScriptedProcess::GetPluginNameStatic() { 36*312b43daSMed Ismail Bennani static ConstString g_name("ScriptedProcess"); 37*312b43daSMed Ismail Bennani return g_name; 38*312b43daSMed Ismail Bennani } 39*312b43daSMed Ismail Bennani 40*312b43daSMed Ismail Bennani const char *ScriptedProcess::GetPluginDescriptionStatic() { 41*312b43daSMed Ismail Bennani return "Scripted Process plug-in."; 42*312b43daSMed Ismail Bennani } 43*312b43daSMed Ismail Bennani 44*312b43daSMed Ismail Bennani static constexpr lldb::ScriptLanguage g_supported_script_languages[] = { 45*312b43daSMed Ismail Bennani ScriptLanguage::eScriptLanguagePython, 46*312b43daSMed Ismail Bennani }; 47*312b43daSMed Ismail Bennani 48*312b43daSMed Ismail Bennani bool ScriptedProcess::IsScriptLanguageSupported(lldb::ScriptLanguage language) { 49*312b43daSMed Ismail Bennani llvm::ArrayRef<lldb::ScriptLanguage> supported_languages = 50*312b43daSMed Ismail Bennani llvm::makeArrayRef(g_supported_script_languages); 51*312b43daSMed Ismail Bennani 52*312b43daSMed Ismail Bennani return llvm::is_contained(supported_languages, language); 53*312b43daSMed Ismail Bennani } 54*312b43daSMed Ismail Bennani 55*312b43daSMed Ismail Bennani void ScriptedProcess::CheckInterpreterAndScriptObject() const { 56*312b43daSMed Ismail Bennani lldbassert(m_interpreter && "Invalid Script Interpreter."); 57*312b43daSMed Ismail Bennani lldbassert(m_script_object_sp && "Invalid Script Object."); 58*312b43daSMed Ismail Bennani } 59*312b43daSMed Ismail Bennani 60*312b43daSMed Ismail Bennani lldb::ProcessSP ScriptedProcess::CreateInstance(lldb::TargetSP target_sp, 61*312b43daSMed Ismail Bennani lldb::ListenerSP listener_sp, 62*312b43daSMed Ismail Bennani const FileSpec *file, 63*312b43daSMed Ismail Bennani bool can_connect) { 64*312b43daSMed Ismail Bennani if (!target_sp || 65*312b43daSMed Ismail Bennani !IsScriptLanguageSupported(target_sp->GetDebugger().GetScriptLanguage())) 66*312b43daSMed Ismail Bennani return nullptr; 67*312b43daSMed Ismail Bennani 68*312b43daSMed Ismail Bennani Status error; 69*312b43daSMed Ismail Bennani ScriptedProcess::ScriptedProcessInfo scripted_process_info( 70*312b43daSMed Ismail Bennani target_sp->GetProcessLaunchInfo()); 71*312b43daSMed Ismail Bennani 72*312b43daSMed Ismail Bennani auto process_sp = std::make_shared<ScriptedProcess>( 73*312b43daSMed Ismail Bennani target_sp, listener_sp, scripted_process_info, error); 74*312b43daSMed Ismail Bennani 75*312b43daSMed Ismail Bennani if (error.Fail() || !process_sp || !process_sp->m_script_object_sp || 76*312b43daSMed Ismail Bennani !process_sp->m_script_object_sp->IsValid()) { 77*312b43daSMed Ismail Bennani LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS), "%s", 78*312b43daSMed Ismail Bennani error.AsCString()); 79*312b43daSMed Ismail Bennani return nullptr; 80*312b43daSMed Ismail Bennani } 81*312b43daSMed Ismail Bennani 82*312b43daSMed Ismail Bennani return process_sp; 83*312b43daSMed Ismail Bennani } 84*312b43daSMed Ismail Bennani 85*312b43daSMed Ismail Bennani bool ScriptedProcess::CanDebug(lldb::TargetSP target_sp, 86*312b43daSMed Ismail Bennani bool plugin_specified_by_name) { 87*312b43daSMed Ismail Bennani return true; 88*312b43daSMed Ismail Bennani } 89*312b43daSMed Ismail Bennani 90*312b43daSMed Ismail Bennani ScriptedProcess::ScriptedProcess( 91*312b43daSMed Ismail Bennani lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, 92*312b43daSMed Ismail Bennani const ScriptedProcess::ScriptedProcessInfo &scripted_process_info, 93*312b43daSMed Ismail Bennani Status &error) 94*312b43daSMed Ismail Bennani : Process(target_sp, listener_sp), 95*312b43daSMed Ismail Bennani m_scripted_process_info(scripted_process_info) { 96*312b43daSMed Ismail Bennani 97*312b43daSMed Ismail Bennani if (!target_sp) { 98*312b43daSMed Ismail Bennani error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s", 99*312b43daSMed Ismail Bennani __FUNCTION__, "Invalid target"); 100*312b43daSMed Ismail Bennani return; 101*312b43daSMed Ismail Bennani } 102*312b43daSMed Ismail Bennani 103*312b43daSMed Ismail Bennani m_interpreter = target_sp->GetDebugger().GetScriptInterpreter(); 104*312b43daSMed Ismail Bennani 105*312b43daSMed Ismail Bennani if (!m_interpreter) { 106*312b43daSMed Ismail Bennani error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s", 107*312b43daSMed Ismail Bennani __FUNCTION__, 108*312b43daSMed Ismail Bennani "Debugger has no Script Interpreter"); 109*312b43daSMed Ismail Bennani return; 110*312b43daSMed Ismail Bennani } 111*312b43daSMed Ismail Bennani 112*312b43daSMed Ismail Bennani StructuredData::ObjectSP object_sp = GetInterface().CreatePluginObject( 113*312b43daSMed Ismail Bennani m_scripted_process_info.GetClassName().c_str(), target_sp, 114*312b43daSMed Ismail Bennani m_scripted_process_info.GetDictionarySP()); 115*312b43daSMed Ismail Bennani 116*312b43daSMed Ismail Bennani if (!object_sp || !object_sp->IsValid()) { 117*312b43daSMed Ismail Bennani error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s", 118*312b43daSMed Ismail Bennani __FUNCTION__, 119*312b43daSMed Ismail Bennani "Failed to create valid script object"); 120*312b43daSMed Ismail Bennani return; 121*312b43daSMed Ismail Bennani } 122*312b43daSMed Ismail Bennani 123*312b43daSMed Ismail Bennani m_script_object_sp = object_sp; 124*312b43daSMed Ismail Bennani } 125*312b43daSMed Ismail Bennani 126*312b43daSMed Ismail Bennani ScriptedProcess::~ScriptedProcess() { 127*312b43daSMed Ismail Bennani Clear(); 128*312b43daSMed Ismail Bennani // We need to call finalize on the process before destroying ourselves to 129*312b43daSMed Ismail Bennani // make sure all of the broadcaster cleanup goes as planned. If we destruct 130*312b43daSMed Ismail Bennani // this class, then Process::~Process() might have problems trying to fully 131*312b43daSMed Ismail Bennani // destroy the broadcaster. 132*312b43daSMed Ismail Bennani Finalize(); 133*312b43daSMed Ismail Bennani } 134*312b43daSMed Ismail Bennani 135*312b43daSMed Ismail Bennani void ScriptedProcess::Initialize() { 136*312b43daSMed Ismail Bennani static llvm::once_flag g_once_flag; 137*312b43daSMed Ismail Bennani 138*312b43daSMed Ismail Bennani llvm::call_once(g_once_flag, []() { 139*312b43daSMed Ismail Bennani PluginManager::RegisterPlugin(GetPluginNameStatic(), 140*312b43daSMed Ismail Bennani GetPluginDescriptionStatic(), CreateInstance); 141*312b43daSMed Ismail Bennani }); 142*312b43daSMed Ismail Bennani } 143*312b43daSMed Ismail Bennani 144*312b43daSMed Ismail Bennani void ScriptedProcess::Terminate() { 145*312b43daSMed Ismail Bennani PluginManager::UnregisterPlugin(ScriptedProcess::CreateInstance); 146*312b43daSMed Ismail Bennani } 147*312b43daSMed Ismail Bennani 148*312b43daSMed Ismail Bennani ConstString ScriptedProcess::GetPluginName() { return GetPluginNameStatic(); } 149*312b43daSMed Ismail Bennani 150*312b43daSMed Ismail Bennani uint32_t ScriptedProcess::GetPluginVersion() { return 1; } 151*312b43daSMed Ismail Bennani 152*312b43daSMed Ismail Bennani Status ScriptedProcess::DoLoadCore() { 153*312b43daSMed Ismail Bennani ProcessLaunchInfo launch_info = GetTarget().GetProcessLaunchInfo(); 154*312b43daSMed Ismail Bennani 155*312b43daSMed Ismail Bennani return DoLaunch(nullptr, launch_info); 156*312b43daSMed Ismail Bennani } 157*312b43daSMed Ismail Bennani 158*312b43daSMed Ismail Bennani Status ScriptedProcess::DoLaunch(Module *exe_module, 159*312b43daSMed Ismail Bennani ProcessLaunchInfo &launch_info) { 160*312b43daSMed Ismail Bennani CheckInterpreterAndScriptObject(); 161*312b43daSMed Ismail Bennani 162*312b43daSMed Ismail Bennani /* FIXME: This doesn't reflect how lldb actually launches a process. 163*312b43daSMed Ismail Bennani In reality, it attaches to debugserver, then resume the process. */ 164*312b43daSMed Ismail Bennani Status error = GetInterface().Launch(); 165*312b43daSMed Ismail Bennani SetPrivateState(eStateRunning); 166*312b43daSMed Ismail Bennani 167*312b43daSMed Ismail Bennani if (error.Fail()) 168*312b43daSMed Ismail Bennani return error; 169*312b43daSMed Ismail Bennani 170*312b43daSMed Ismail Bennani // TODO: Fetch next state from stopped event queue then send stop event 171*312b43daSMed Ismail Bennani // const StateType state = SetThreadStopInfo(response); 172*312b43daSMed Ismail Bennani // if (state != eStateInvalid) { 173*312b43daSMed Ismail Bennani // SetPrivateState(state); 174*312b43daSMed Ismail Bennani 175*312b43daSMed Ismail Bennani SetPrivateState(eStateStopped); 176*312b43daSMed Ismail Bennani 177*312b43daSMed Ismail Bennani UpdateThreadListIfNeeded(); 178*312b43daSMed Ismail Bennani GetThreadList(); 179*312b43daSMed Ismail Bennani 180*312b43daSMed Ismail Bennani return {}; 181*312b43daSMed Ismail Bennani } 182*312b43daSMed Ismail Bennani 183*312b43daSMed Ismail Bennani void ScriptedProcess::DidLaunch() { 184*312b43daSMed Ismail Bennani CheckInterpreterAndScriptObject(); 185*312b43daSMed Ismail Bennani m_pid = GetInterface().GetProcessID(); 186*312b43daSMed Ismail Bennani } 187*312b43daSMed Ismail Bennani 188*312b43daSMed Ismail Bennani Status ScriptedProcess::DoResume() { 189*312b43daSMed Ismail Bennani CheckInterpreterAndScriptObject(); 190*312b43daSMed Ismail Bennani 191*312b43daSMed Ismail Bennani Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); 192*312b43daSMed Ismail Bennani // FIXME: Fetch data from thread. 193*312b43daSMed Ismail Bennani const StateType thread_resume_state = eStateRunning; 194*312b43daSMed Ismail Bennani LLDB_LOGF(log, "ScriptedProcess::%s thread_resume_state = %s", __FUNCTION__, 195*312b43daSMed Ismail Bennani StateAsCString(thread_resume_state)); 196*312b43daSMed Ismail Bennani 197*312b43daSMed Ismail Bennani bool resume = (thread_resume_state == eStateRunning); 198*312b43daSMed Ismail Bennani assert(thread_resume_state == eStateRunning && "invalid thread resume state"); 199*312b43daSMed Ismail Bennani 200*312b43daSMed Ismail Bennani Status error; 201*312b43daSMed Ismail Bennani if (resume) { 202*312b43daSMed Ismail Bennani LLDB_LOGF(log, "ScriptedProcess::%s sending resume", __FUNCTION__); 203*312b43daSMed Ismail Bennani 204*312b43daSMed Ismail Bennani SetPrivateState(eStateRunning); 205*312b43daSMed Ismail Bennani SetPrivateState(eStateStopped); 206*312b43daSMed Ismail Bennani error = GetInterface().Resume(); 207*312b43daSMed Ismail Bennani } 208*312b43daSMed Ismail Bennani 209*312b43daSMed Ismail Bennani return error; 210*312b43daSMed Ismail Bennani } 211*312b43daSMed Ismail Bennani 212*312b43daSMed Ismail Bennani Status ScriptedProcess::DoStop() { 213*312b43daSMed Ismail Bennani CheckInterpreterAndScriptObject(); 214*312b43daSMed Ismail Bennani 215*312b43daSMed Ismail Bennani Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); 216*312b43daSMed Ismail Bennani 217*312b43daSMed Ismail Bennani if (GetInterface().ShouldStop()) { 218*312b43daSMed Ismail Bennani SetPrivateState(eStateStopped); 219*312b43daSMed Ismail Bennani LLDB_LOGF(log, "ScriptedProcess::%s Immediate stop", __FUNCTION__); 220*312b43daSMed Ismail Bennani return {}; 221*312b43daSMed Ismail Bennani } 222*312b43daSMed Ismail Bennani 223*312b43daSMed Ismail Bennani LLDB_LOGF(log, "ScriptedProcess::%s Delayed stop", __FUNCTION__); 224*312b43daSMed Ismail Bennani return GetInterface().Stop(); 225*312b43daSMed Ismail Bennani } 226*312b43daSMed Ismail Bennani 227*312b43daSMed Ismail Bennani Status ScriptedProcess::DoDestroy() { return Status(); } 228*312b43daSMed Ismail Bennani 229*312b43daSMed Ismail Bennani bool ScriptedProcess::IsAlive() { 230*312b43daSMed Ismail Bennani if (m_interpreter && m_script_object_sp) 231*312b43daSMed Ismail Bennani return GetInterface().IsAlive(); 232*312b43daSMed Ismail Bennani return false; 233*312b43daSMed Ismail Bennani } 234*312b43daSMed Ismail Bennani 235*312b43daSMed Ismail Bennani size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, 236*312b43daSMed Ismail Bennani Status &error) { 237*312b43daSMed Ismail Bennani 238*312b43daSMed Ismail Bennani auto error_with_message = [&error](llvm::StringRef message) { 239*312b43daSMed Ismail Bennani error.SetErrorString(message); 240*312b43daSMed Ismail Bennani return 0; 241*312b43daSMed Ismail Bennani }; 242*312b43daSMed Ismail Bennani 243*312b43daSMed Ismail Bennani if (!m_interpreter) 244*312b43daSMed Ismail Bennani return error_with_message("No interpreter."); 245*312b43daSMed Ismail Bennani 246*312b43daSMed Ismail Bennani lldb::DataExtractorSP data_extractor_sp = 247*312b43daSMed Ismail Bennani GetInterface().ReadMemoryAtAddress(addr, size, error); 248*312b43daSMed Ismail Bennani 249*312b43daSMed Ismail Bennani if (!data_extractor_sp || error.Fail()) 250*312b43daSMed Ismail Bennani return 0; 251*312b43daSMed Ismail Bennani 252*312b43daSMed Ismail Bennani offset_t bytes_copied = data_extractor_sp->CopyByteOrderedData( 253*312b43daSMed Ismail Bennani 0, data_extractor_sp->GetByteSize(), buf, size, GetByteOrder()); 254*312b43daSMed Ismail Bennani 255*312b43daSMed Ismail Bennani if (!bytes_copied || bytes_copied == LLDB_INVALID_OFFSET) 256*312b43daSMed Ismail Bennani return error_with_message("Failed to copy read memory to buffer."); 257*312b43daSMed Ismail Bennani 258*312b43daSMed Ismail Bennani return size; 259*312b43daSMed Ismail Bennani } 260*312b43daSMed Ismail Bennani 261*312b43daSMed Ismail Bennani ArchSpec ScriptedProcess::GetArchitecture() { 262*312b43daSMed Ismail Bennani return GetTarget().GetArchitecture(); 263*312b43daSMed Ismail Bennani } 264*312b43daSMed Ismail Bennani 265*312b43daSMed Ismail Bennani Status ScriptedProcess::GetMemoryRegionInfo(lldb::addr_t load_addr, 266*312b43daSMed Ismail Bennani MemoryRegionInfo ®ion) { 267*312b43daSMed Ismail Bennani // TODO: Implement 268*312b43daSMed Ismail Bennani return Status(); 269*312b43daSMed Ismail Bennani } 270*312b43daSMed Ismail Bennani 271*312b43daSMed Ismail Bennani Status ScriptedProcess::GetMemoryRegions(MemoryRegionInfos ®ion_list) { 272*312b43daSMed Ismail Bennani CheckInterpreterAndScriptObject(); 273*312b43daSMed Ismail Bennani 274*312b43daSMed Ismail Bennani lldb::addr_t address = 0; 275*312b43daSMed Ismail Bennani lldb::MemoryRegionInfoSP mem_region_sp = nullptr; 276*312b43daSMed Ismail Bennani 277*312b43daSMed Ismail Bennani while ((mem_region_sp = 278*312b43daSMed Ismail Bennani GetInterface().GetMemoryRegionContainingAddress(address))) { 279*312b43daSMed Ismail Bennani auto range = mem_region_sp->GetRange(); 280*312b43daSMed Ismail Bennani address += range.GetRangeBase() + range.GetByteSize(); 281*312b43daSMed Ismail Bennani region_list.push_back(*mem_region_sp.get()); 282*312b43daSMed Ismail Bennani } 283*312b43daSMed Ismail Bennani 284*312b43daSMed Ismail Bennani return {}; 285*312b43daSMed Ismail Bennani } 286*312b43daSMed Ismail Bennani 287*312b43daSMed Ismail Bennani void ScriptedProcess::Clear() { Process::m_thread_list.Clear(); } 288*312b43daSMed Ismail Bennani 289*312b43daSMed Ismail Bennani bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list, 290*312b43daSMed Ismail Bennani ThreadList &new_thread_list) { 291*312b43daSMed Ismail Bennani // TODO: Implement 292*312b43daSMed Ismail Bennani // This is supposed to get the current set of threads, if any of them are in 293*312b43daSMed Ismail Bennani // old_thread_list then they get copied to new_thread_list, and then any 294*312b43daSMed Ismail Bennani // actually new threads will get added to new_thread_list. 295*312b43daSMed Ismail Bennani return new_thread_list.GetSize(false) > 0; 296*312b43daSMed Ismail Bennani } 297*312b43daSMed Ismail Bennani 298*312b43daSMed Ismail Bennani bool ScriptedProcess::GetProcessInfo(ProcessInstanceInfo &info) { 299*312b43daSMed Ismail Bennani info.Clear(); 300*312b43daSMed Ismail Bennani info.SetProcessID(GetID()); 301*312b43daSMed Ismail Bennani info.SetArchitecture(GetArchitecture()); 302*312b43daSMed Ismail Bennani lldb::ModuleSP module_sp = GetTarget().GetExecutableModule(); 303*312b43daSMed Ismail Bennani if (module_sp) { 304*312b43daSMed Ismail Bennani const bool add_exe_file_as_first_arg = false; 305*312b43daSMed Ismail Bennani info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(), 306*312b43daSMed Ismail Bennani add_exe_file_as_first_arg); 307*312b43daSMed Ismail Bennani } 308*312b43daSMed Ismail Bennani return true; 309*312b43daSMed Ismail Bennani } 310*312b43daSMed Ismail Bennani 311*312b43daSMed Ismail Bennani ScriptedProcessInterface &ScriptedProcess::GetInterface() const { 312*312b43daSMed Ismail Bennani return m_interpreter->GetScriptedProcessInterface(); 313*312b43daSMed Ismail Bennani } 314