jingham created this revision. Herald added subscribers: lldb-commits, JDevlieghere, abidh. Herald added a project: LLDB.
Before this patch if you used SBThread.StepUsingScriptedThreadPlan but mistyped the Python ThreadPlan class name, you wouldn't get any error, and a bogus ThreadPlan would get executed. This patch adds an error string and plumbs it through to where we look up the Python class, so now you get a decent error string. We also tell ourselves the plan has failed (by returning an empty StructuredObject) so that the plan will fail the IsValid check and so not get pushed. Repository: rLLDB LLDB https://reviews.llvm.org/D68173 Files: lldb/include/lldb/Interpreter/ScriptInterpreter.h lldb/include/lldb/Target/ThreadPlanPython.h lldb/packages/Python/lldbsuite/test/functionalities/step_scripted/TestStepScripted.py lldb/scripts/Python/python-wrapper.swig lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h lldb/source/Target/ThreadPlanPython.cpp lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
Index: lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp =================================================================== --- lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp +++ lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp @@ -95,6 +95,7 @@ extern "C" void *LLDBSwigPythonCreateScriptedThreadPlan( const char *python_class_name, const char *session_dictionary_name, + std::string &error_string, const lldb::ThreadPlanSP &thread_plan_sp) { return nullptr; } Index: lldb/source/Target/ThreadPlanPython.cpp =================================================================== --- lldb/source/Target/ThreadPlanPython.cpp +++ lldb/source/Target/ThreadPlanPython.cpp @@ -45,7 +45,9 @@ if (!m_implementation_sp) { if (error) - error->Printf("Python thread plan does not have an implementation"); + error->Printf("Error constructing Python ThreadPlan: %s", + m_error_str.empty() ? "<unknown error>" + : m_error_str.c_str()); return false; } @@ -63,7 +65,7 @@ .GetScriptInterpreter(); if (script_interp) { m_implementation_sp = script_interp->CreateScriptedThreadPlan( - m_class_name.c_str(), this->shared_from_this()); + m_class_name.c_str(), m_error_str, this->shared_from_this()); } } } Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -78,6 +78,7 @@ StructuredData::ObjectSP CreateScriptedThreadPlan(const char *class_name, + std::string &error_str, lldb::ThreadPlanSP thread_plan) override; bool ScriptedThreadPlanExplainsStop(StructuredData::ObjectSP implementor_sp, Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -97,6 +97,7 @@ extern "C" void *LLDBSwigPythonCreateScriptedThreadPlan( const char *python_class_name, const char *session_dictionary_name, + std::string &error_string, const lldb::ThreadPlanSP &thread_plan_sp); extern "C" bool LLDBSWIGPythonCallThreadPlan(void *implementor, @@ -1844,7 +1845,8 @@ } StructuredData::ObjectSP ScriptInterpreterPythonImpl::CreateScriptedThreadPlan( - const char *class_name, lldb::ThreadPlanSP thread_plan_sp) { + const char *class_name, std::string &error_str, + lldb::ThreadPlanSP thread_plan_sp) { if (class_name == nullptr || class_name[0] == '\0') return StructuredData::ObjectSP(); @@ -1864,10 +1866,11 @@ { Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - ret_val = LLDBSwigPythonCreateScriptedThreadPlan( class_name, python_interpreter->m_dictionary_name.c_str(), - thread_plan_sp); + error_str, thread_plan_sp); + if (!ret_val) + return {}; } return StructuredData::ObjectSP(new StructuredPythonObject(ret_val)); Index: lldb/scripts/Python/python-wrapper.swig =================================================================== --- lldb/scripts/Python/python-wrapper.swig +++ lldb/scripts/Python/python-wrapper.swig @@ -250,6 +250,7 @@ ( const char *python_class_name, const char *session_dictionary_name, + std::string &error_string, const lldb::ThreadPlanSP& thread_plan_sp ) { @@ -267,8 +268,11 @@ auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(session_dictionary_name); auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(python_class_name, dict); - if (!pfunc.IsAllocated()) + if (!pfunc.IsAllocated()) { + error_string.append("could not find script class: "); + error_string.append(python_class_name); return nullptr; + } PythonObject tp_arg(PyRefType::Owned, SBTypeToSWIGWrapper(tp_value)); Index: lldb/packages/Python/lldbsuite/test/functionalities/step_scripted/TestStepScripted.py =================================================================== --- lldb/packages/Python/lldbsuite/test/functionalities/step_scripted/TestStepScripted.py +++ lldb/packages/Python/lldbsuite/test/functionalities/step_scripted/TestStepScripted.py @@ -26,6 +26,7 @@ def setUp(self): TestBase.setUp(self) + self.main_source_file = lldb.SBFileSpec("main.c") self.runCmd("command script import Steps.py") def step_out_with_scripted_plan(self, name): @@ -39,3 +40,19 @@ frame = thread.GetFrameAtIndex(0) self.assertEqual("main", frame.GetFunctionName()) + + def test_misspelled_plan_name(self): + """Test that we get a useful error if we misspell the plan class name""" + self.build() + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, "Set a breakpoint here", self.main_source_file) + stop_id = process.GetStopID() + # Pass a non-existent class for the plan class: + err = thread.StepUsingScriptedThreadPlan("NoSuchModule.NoSuchPlan") + + # Make sure we got a good error: + self.assertTrue(err.Fail(), "We got a failure state") + msg = err.GetCString() + self.assertTrue("NoSuchModule.NoSuchPlan" in msg, "Mentioned missing class") + + # Make sure we didn't let the process run: + self.assertEqual(stop_id, process.GetStopID(), "Process didn't run") Index: lldb/include/lldb/Target/ThreadPlanPython.h =================================================================== --- lldb/include/lldb/Target/ThreadPlanPython.h +++ lldb/include/lldb/Target/ThreadPlanPython.h @@ -55,6 +55,7 @@ private: std::string m_class_name; + std::string m_error_str; StructuredData::ObjectSP m_implementation_sp; bool m_did_push; Index: lldb/include/lldb/Interpreter/ScriptInterpreter.h =================================================================== --- lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -208,6 +208,7 @@ virtual StructuredData::ObjectSP CreateScriptedThreadPlan(const char *class_name, + std::string &error_str, lldb::ThreadPlanSP thread_plan_sp) { return StructuredData::ObjectSP(); }
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits