mib created this revision. mib added reviewers: JDevlieghere, bulbazord. mib added a project: LLDB. Herald added a project: All. mib requested review of this revision. Herald added a subscriber: lldb-commits.
This patch should address a bug when a user have multiple scripted processes in the same debugging session. In order for the scripted process plugin to be able to call into the scripted object instance methods to fetch the necessary data to reconstruct its state, the scripted process plugin calls into a scripted process interface, that has a reference to the created script object instance. However, prior to this patch, we only had a single instance of the scripted process interface, living the script interpreter. So every time a new scripted process plugin was created, it would overwrite the script object instance that was held by the single scripted process interface in the script interpreter. That would cause all the method calls made to the scripted process interface to be dispatched by the last instanciated script object instance, which is wrong. In order to prevent that, this patch moves the scripted process interface reference to be help by the scripted process plugin itself. rdar://104882562 Signed-off-by: Med Ismail Bennani <medismail.benn...@gmail.com> Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D143308 Files: lldb/include/lldb/Interpreter/ScriptInterpreter.h lldb/include/lldb/Interpreter/ScriptedInterface.h lldb/source/Interpreter/ScriptInterpreter.cpp lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp lldb/source/Plugins/Process/scripted/ScriptedProcess.h lldb/source/Plugins/Process/scripted/ScriptedThread.cpp lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py
Index: lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py =================================================================== --- lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py +++ lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py @@ -21,10 +21,12 @@ return {} def read_memory_at_address(self, addr: int, size: int, error: lldb.SBError) -> lldb.SBData: + debugger = self.target.GetDebugger() + index = debugger.GetIndexOfTarget(self.target) data = lldb.SBData().CreateDataFromCString( self.target.GetByteOrder(), self.target.GetCodeByteSize(), - "Hello, world!") + "Hello, target " + str(index)) return data Index: lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py =================================================================== --- lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py +++ lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py @@ -98,8 +98,8 @@ id, name stop reason and register context. """ self.build() - target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) - self.assertTrue(target, VALID_TARGET) + target_0 = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) + self.assertTrue(target_0, VALID_TARGET) os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1' def cleanup(): @@ -115,12 +115,12 @@ launch_info.SetScriptedProcessClassName("dummy_scripted_process.DummyScriptedProcess") error = lldb.SBError() - process = target.Launch(launch_info, error) - self.assertTrue(process and process.IsValid(), PROCESS_IS_VALID) - self.assertEqual(process.GetProcessID(), 42) - self.assertEqual(process.GetNumThreads(), 1) + process_0 = target_0.Launch(launch_info, error) + self.assertTrue(process_0 and process.IsValid(), PROCESS_IS_VALID) + self.assertEqual(process_0.GetProcessID(), 42) + self.assertEqual(process_0.GetNumThreads(), 1) - py_impl = process.GetScriptedImplementation() + py_impl = process_0.GetScriptedImplementation() self.assertTrue(py_impl) self.assertTrue(isinstance(py_impl, dummy_scripted_process.DummyScriptedProcess)) self.assertFalse(hasattr(py_impl, 'my_super_secret_member')) @@ -128,13 +128,37 @@ self.assertTrue(hasattr(py_impl, 'my_super_secret_member')) self.assertEqual(py_impl.my_super_secret_method(), 42) + # Try reading from target #0 process ... + addr = 0x500000000 + message = "Hello, target 0" + buff = process_0.ReadCStringFromMemory(addr, len(message) + 1, error) + self.assertSuccess(error) + self.assertEqual(buff, message) + + target_1 = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) + self.assertTrue(target_1, VALID_TARGET) + error = lldb.SBError() + process_1 = target_1.Launch(launch_info, error) + self.assertTrue(process_1 and process.IsValid(), PROCESS_IS_VALID) + self.assertEqual(process_1.GetProcessID(), 42) + self.assertEqual(process_1.GetNumThreads(), 1) + + # ... then try reading from target #1 process ... + addr = 0x500000000 + message = "Hello, target 1" + buff = process_1.ReadCStringFromMemory(addr, len(message) + 1, error) + self.assertSuccess(error) + self.assertEqual(buff, message) + + # ... now, reading again from target #0 process to make sure the call + # gets dispatched to the right target. addr = 0x500000000 - message = "Hello, world!" - buff = process.ReadCStringFromMemory(addr, len(message) + 1, error) + message = "Hello, target 0" + buff = process_0.ReadCStringFromMemory(addr, len(message) + 1, error) self.assertSuccess(error) self.assertEqual(buff, message) - thread = process.GetSelectedThread() + thread = process_0.GetSelectedThread() self.assertTrue(thread, "Invalid thread.") self.assertEqual(thread.GetThreadID(), 0x19) self.assertEqual(thread.GetName(), "DummyScriptedThread.thread-1") @@ -158,5 +182,5 @@ self.assertEqual(idx, int(reg.value, 16)) self.assertTrue(frame.IsArtificial(), "Frame is not artificial") - pc = frame.GetPCAddress().GetLoadAddress(target) + pc = frame.GetPCAddress().GetLoadAddress(target_0) self.assertEqual(pc, 0x0100001b00) Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -124,6 +124,8 @@ GetRecognizedArguments(const StructuredData::ObjectSP &implementor, lldb::StackFrameSP frame_sp) override; + lldb::ScriptedProcessInterfaceUP CreateScriptedProcessInterface() override; + StructuredData::GenericSP OSPlugin_CreatePluginObject(const char *class_name, lldb::ProcessSP process_sp) override; Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -413,8 +413,6 @@ m_active_io_handler(eIOHandlerNone), m_session_is_active(false), m_pty_secondary_is_open(false), m_valid_session(true), m_lock_count(0), m_command_thread_state(nullptr) { - m_scripted_process_interface_up = - std::make_unique<ScriptedProcessPythonInterface>(*this); m_scripted_platform_interface_up = std::make_unique<ScriptedPlatformPythonInterface>(*this); m_scripted_multiplexer_interface_up = @@ -1487,6 +1485,11 @@ return ValueObjectListSP(); } +ScriptedProcessInterfaceUP +ScriptInterpreterPythonImpl::CreateScriptedProcessInterface() { + return std::make_unique<ScriptedProcessPythonInterface>(*this); +} + StructuredData::GenericSP ScriptInterpreterPythonImpl::OSPlugin_CreatePluginObject( const char *class_name, lldb::ProcessSP process_sp) { Index: lldb/source/Plugins/Process/scripted/ScriptedThread.cpp =================================================================== --- lldb/source/Plugins/Process/scripted/ScriptedThread.cpp +++ lldb/source/Plugins/Process/scripted/ScriptedThread.cpp @@ -30,7 +30,7 @@ return llvm::createStringError(llvm::inconvertibleErrorCode(), "Invalid scripted process."); - process.CheckInterpreterAndScriptObject(); + process.CheckScriptedInterface(); auto scripted_thread_interface = process.GetInterface().CreateScriptedThreadInterface(); Index: lldb/source/Plugins/Process/scripted/ScriptedProcess.h =================================================================== --- lldb/source/Plugins/Process/scripted/ScriptedProcess.h +++ lldb/source/Plugins/Process/scripted/ScriptedProcess.h @@ -106,9 +106,8 @@ private: friend class ScriptedThread; - inline void CheckInterpreterAndScriptObject() const { - lldbassert(m_interpreter && "Invalid Script Interpreter."); - lldbassert(m_script_object_sp && "Invalid Script Object."); + inline void CheckScriptedInterface() const { + lldbassert(m_interface_up && "Invalid scripted process interface."); } ScriptedProcessInterface &GetInterface() const; @@ -116,8 +115,7 @@ static bool IsScriptLanguageSupported(lldb::ScriptLanguage language); const ScriptedMetadata m_scripted_metadata; - lldb_private::ScriptInterpreter *m_interpreter = nullptr; - lldb_private::StructuredData::ObjectSP m_script_object_sp = nullptr; + lldb::ScriptedProcessInterfaceUP m_interface_up; }; } // namespace lldb_private Index: lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp =================================================================== --- lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp +++ lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp @@ -65,8 +65,7 @@ auto process_sp = std::shared_ptr<ScriptedProcess>( new ScriptedProcess(target_sp, listener_sp, scripted_metadata, error)); - if (error.Fail() || !process_sp || !process_sp->m_script_object_sp || - !process_sp->m_script_object_sp->IsValid()) { + if (error.Fail() || !process_sp || !process_sp->m_interface_up) { LLDB_LOGF(GetLog(LLDBLog::Process), "%s", error.AsCString()); return nullptr; } @@ -91,17 +90,28 @@ return; } - m_interpreter = target_sp->GetDebugger().GetScriptInterpreter(); + ScriptInterpreter *interpreter = + target_sp->GetDebugger().GetScriptInterpreter(); - if (!m_interpreter) { + if (!interpreter) { error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s", __FUNCTION__, "Debugger has no Script Interpreter"); return; } + // Create process instance interface + m_interface_up = interpreter->CreateScriptedProcessInterface(); + if (!m_interface_up) { + error.SetErrorStringWithFormat( + "ScriptedProcess::%s () - ERROR: %s", __FUNCTION__, + "Script interpreter couldn't create Scripted Process Interface"); + return; + } + ExecutionContext exe_ctx(target_sp, /*get_process=*/false); + // Create process script object StructuredData::GenericSP object_sp = GetInterface().CreatePluginObject( m_scripted_metadata.GetClassName(), exe_ctx, m_scripted_metadata.GetArgsSP()); @@ -113,8 +123,6 @@ return; } - m_script_object_sp = object_sp; - // Setup multiplexer if (auto dict_sp = GetInterface().GetScriptedMultiplexer()) Multiplex(dict_sp, error); @@ -189,8 +197,6 @@ Status ScriptedProcess::DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) { - CheckInterpreterAndScriptObject(); - /* FIXME: This doesn't reflect how lldb actually launches a process. In reality, it attaches to debugserver, then resume the process. */ Status error = GetInterface().Launch(); @@ -210,14 +216,11 @@ } void ScriptedProcess::DidLaunch() { - CheckInterpreterAndScriptObject(); m_pid = GetInterface().GetProcessID(); GetLoadedDynamicLibrariesInfos(); } Status ScriptedProcess::DoResume() { - CheckInterpreterAndScriptObject(); - Log *log = GetLog(LLDBLog::Process); // FIXME: Fetch data from thread. const StateType thread_resume_state = eStateRunning; @@ -240,8 +243,6 @@ } Status ScriptedProcess::DoAttach() { - CheckInterpreterAndScriptObject(); - Status error = GetInterface().Attach(); SetPrivateState(eStateRunning); @@ -272,8 +273,6 @@ } Status ScriptedProcess::DoStop() { - CheckInterpreterAndScriptObject(); - Log *log = GetLog(LLDBLog::Process); if (GetInterface().ShouldStop()) { @@ -288,18 +287,10 @@ Status ScriptedProcess::DoDestroy() { return Status(); } -bool ScriptedProcess::IsAlive() { - if (m_interpreter && m_script_object_sp) - return GetInterface().IsAlive(); - return false; -} +bool ScriptedProcess::IsAlive() { return GetInterface().IsAlive(); } size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, Status &error) { - if (!m_interpreter) - return ScriptedInterface::ErrorWithMessage<size_t>( - LLVM_PRETTY_FUNCTION, "No interpreter.", error); - lldb::DataExtractorSP data_extractor_sp = GetInterface().ReadMemoryAtAddress(addr, size, error); @@ -322,8 +313,6 @@ Status ScriptedProcess::DoGetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo ®ion) { - CheckInterpreterAndScriptObject(); - Status error; if (auto region_or_err = GetInterface().GetMemoryRegionContainingAddress(load_addr, error)) @@ -333,8 +322,6 @@ } Status ScriptedProcess::GetMemoryRegions(MemoryRegionInfos ®ion_list) { - CheckInterpreterAndScriptObject(); - Status error; lldb::addr_t address = 0; @@ -360,22 +347,9 @@ // This is supposed to get the current set of threads, if any of them are in // old_thread_list then they get copied to new_thread_list, and then any // actually new threads will get added to new_thread_list. - - CheckInterpreterAndScriptObject(); m_thread_plans.ClearThreadCache(); Status error; - ScriptLanguage language = m_interpreter->GetLanguage(); - - if (language != eScriptLanguagePython) - return ScriptedInterface::ErrorWithMessage<bool>( - LLVM_PRETTY_FUNCTION, - llvm::Twine("ScriptInterpreter language (" + - llvm::Twine(m_interpreter->LanguageToString(language)) + - llvm::Twine(") not supported.")) - .str(), - error); - StructuredData::DictionarySP thread_info_sp = GetInterface().GetThreadsInfo(); if (!thread_info_sp) @@ -474,8 +448,6 @@ lldb_private::StructuredData::ObjectSP ScriptedProcess::GetLoadedDynamicLibrariesInfos() { - CheckInterpreterAndScriptObject(); - Status error; auto error_with_message = [&error](llvm::StringRef message) { return ScriptedInterface::ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION, @@ -625,8 +597,6 @@ } lldb_private::StructuredData::DictionarySP ScriptedProcess::GetMetadata() { - CheckInterpreterAndScriptObject(); - StructuredData::DictionarySP metadata_sp = GetInterface().GetMetadata(); Status error; @@ -638,7 +608,7 @@ } void ScriptedProcess::UpdateQueueListIfNeeded() { - CheckInterpreterAndScriptObject(); + CheckScriptedInterface(); for (ThreadSP thread_sp : Threads()) { if (const char *queue_name = thread_sp->GetQueueName()) { QueueSP queue_sp = std::make_shared<Queue>( @@ -649,12 +619,15 @@ } ScriptedProcessInterface &ScriptedProcess::GetInterface() const { - return m_interpreter->GetScriptedProcessInterface(); + CheckScriptedInterface(); + return *m_interface_up; } void *ScriptedProcess::GetImplementation() { - if (m_script_object_sp && - m_script_object_sp->GetType() == eStructuredDataTypeGeneric) - return m_script_object_sp->GetAsGeneric()->GetValue(); + StructuredData::GenericSP object_instance_sp = + GetInterface().GetScriptObjectInstance(); + if (object_instance_sp && + object_instance_sp->GetType() == eStructuredDataTypeGeneric) + return object_instance_sp->GetAsGeneric()->GetValue(); return nullptr; } Index: lldb/source/Interpreter/ScriptInterpreter.cpp =================================================================== --- lldb/source/Interpreter/ScriptInterpreter.cpp +++ lldb/source/Interpreter/ScriptInterpreter.cpp @@ -29,11 +29,9 @@ ScriptInterpreter::ScriptInterpreter( Debugger &debugger, lldb::ScriptLanguage script_lang, - lldb::ScriptedProcessInterfaceUP scripted_process_interface_up, lldb::ScriptedPlatformInterfaceUP scripted_platform_interface_up, lldb::ScriptedMultiplexerInterfaceUP scripted_multiplexer_interface_up) : m_debugger(debugger), m_script_lang(script_lang), - m_scripted_process_interface_up(std::move(scripted_process_interface_up)), m_scripted_platform_interface_up( std::move(scripted_platform_interface_up)), m_scripted_multiplexer_interface_up( Index: lldb/include/lldb/Interpreter/ScriptedInterface.h =================================================================== --- lldb/include/lldb/Interpreter/ScriptedInterface.h +++ lldb/include/lldb/Interpreter/ScriptedInterface.h @@ -30,6 +30,10 @@ StructuredData::DictionarySP args_sp, StructuredData::Generic *script_obj = nullptr) = 0; + StructuredData::GenericSP GetScriptObjectInstance() { + return m_object_instance_sp; + } + template <typename Ret> static Ret ErrorWithMessage(llvm::StringRef caller_name, llvm::StringRef error_msg, Status &error, Index: lldb/include/lldb/Interpreter/ScriptInterpreter.h =================================================================== --- lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -154,8 +154,6 @@ ScriptInterpreter( Debugger &debugger, lldb::ScriptLanguage script_lang, - lldb::ScriptedProcessInterfaceUP scripted_process_interface_up = - std::make_unique<ScriptedProcessInterface>(), lldb::ScriptedPlatformInterfaceUP scripted_platform_interface_up = std::make_unique<ScriptedPlatformInterface>(), lldb::ScriptedMultiplexerInterfaceUP scripted_multiplexer_interface_up = @@ -579,8 +577,8 @@ lldb::ScriptLanguage GetLanguage() { return m_script_lang; } - ScriptedProcessInterface &GetScriptedProcessInterface() { - return *m_scripted_process_interface_up; + virtual lldb::ScriptedProcessInterfaceUP CreateScriptedProcessInterface() { + return std::make_unique<ScriptedProcessInterface>(); } ScriptedPlatformInterface &GetScriptedPlatformInterface() { @@ -618,7 +616,6 @@ protected: Debugger &m_debugger; lldb::ScriptLanguage m_script_lang; - lldb::ScriptedProcessInterfaceUP m_scripted_process_interface_up; lldb::ScriptedPlatformInterfaceUP m_scripted_platform_interface_up; lldb::ScriptedMultiplexerInterfaceUP m_scripted_multiplexer_interface_up; };
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits