From 3759044f2d634a89b1006615da884f4442fa3a7e Mon Sep 17 00:00:00 2001 From: Med Ismail Bennani Date: Mon, 1 Dec 2025 14:38:44 -0800 Subject: [PATCH] [lldb/ScriptInterpreter] Add a way to retrieve script module file path This adds a new virtual method `GetScriptedModulePath()` to `ScriptedInterface` that allows retrieving the file path of the Python module containing the scripted object implementation. The Python implementation acquires the GIL and walks through the object's `__class__.__module__` to find the module's `__file__` attribute. This will be used by ScriptedFrame to populate the module and compile unit for frames pointing to Python source files. Signed-off-by: Med Ismail Bennani --- .../Interfaces/ScriptedInterface.h | 4 ++ .../Interfaces/ScriptedPythonInterface.h | 56 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h b/lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h index a3dc52c435561..8ace90927b582 100644 --- a/lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h +++ b/lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h @@ -39,6 +39,10 @@ class ScriptedInterface { virtual llvm::SmallVector GetAbstractMethodRequirements() const = 0; + virtual llvm::Expected GetScriptedModulePath() { + return llvm::make_error(); + } + llvm::SmallVector const GetAbstractMethods() const { llvm::SmallVector abstract_methods; llvm::transform(GetAbstractMethodRequirements(), abstract_methods.begin(), diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h index 5f5665c495770..23c56610124a6 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h @@ -55,6 +55,62 @@ class ScriptedPythonInterface : virtual public ScriptedInterface { std::variant payload; }; + llvm::Expected GetScriptedModulePath() override { + using namespace python; + using Locker = ScriptInterpreterPythonImpl::Locker; + + Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); + + if (!m_object_instance_sp) + return llvm::createStringError("scripted Interface has invalid object"); + + PythonObject py_obj = + PythonObject(PyRefType::Borrowed, + static_cast(m_object_instance_sp->GetValue())); + + if (!py_obj.IsAllocated()) + return llvm::createStringError( + "scripted Interface has invalid python object"); + + PythonObject py_obj_class = py_obj.GetAttributeValue("__class__"); + if (!py_obj_class.IsValid()) + return llvm::createStringError( + "scripted Interface python object is missing '__class__' attribute"); + + PythonObject py_obj_module = py_obj_class.GetAttributeValue("__module__"); + if (!py_obj_module.IsValid()) + return llvm::createStringError( + "scripted Interface python object '__class__' is missing " + "'__module__' attribute"); + + PythonString py_obj_module_str = py_obj_module.Str(); + if (!py_obj_module_str.IsValid()) + return llvm::createStringError( + "scripted Interface python object '__class__.__module__' attribute " + "is not a string"); + + llvm::StringRef py_obj_module_str_ref = py_obj_module_str.GetString(); + PythonModule py_module = PythonModule::AddModule(py_obj_module_str_ref); + if (!py_module.IsValid()) + return llvm::createStringError("failed to import '%s' module", + py_obj_module_str_ref.data()); + + PythonObject py_module_file = py_module.GetAttributeValue("__file__"); + if (!py_module_file.IsValid()) + return llvm::createStringError( + "module '%s' is missing '__file__' attribute", + py_obj_module_str_ref.data()); + + PythonString py_module_file_str = py_module_file.Str(); + if (!py_module_file_str.IsValid()) + return llvm::createStringError( + "module '%s.__file__' attribute is not a string", + py_obj_module_str_ref.data()); + + return FileSpec(py_obj_module_str.GetString()); + } + llvm::Expected> CheckAbstractMethodImplementation( const python::PythonDictionary &class_dict) const {