Index: lldb/bindings/python/python-typemaps.swig =================================================================== --- lldb/bindings/python/python-typemaps.swig +++ lldb/bindings/python/python-typemaps.swig @@ -59,6 +59,58 @@ free((char *) $1); } +%typemap(in) lldb::ScriptedObject { + if ($input == Py_None) { + $1 = NULL; + } else { + PythonObject obj(PyRefType::Borrowed, $input); + if (!obj.IsValid()) { + PyErr_SetString(PyExc_TypeError, "Scripted object is not valid"); + SWIG_fail; + } + + auto lldb_module = PythonModule::Import("lldb"); + if (!lldb_module) { + llvm::StringRef err_msg = llvm::toString(lldb_module.takeError()); + PyErr_SetString(PyExc_TypeError, err_msg.data()); + SWIG_fail; + } + + auto sb_structured_data_class = lldb_module.get().Get("SBStructuredData"); + if (!sb_structured_data_class) { + llvm::StringRef err_msg = llvm::toString(sb_structured_data_class.takeError()); + PyErr_SetString(PyExc_TypeError, err_msg.data()); + SWIG_fail; + } + + if (obj.IsInstance(sb_structured_data_class.get())) { + $1 = $input; + } else { + auto type = obj.GetType(); + if (!type) { + llvm::StringRef err_msg = llvm::toString(type.takeError()); + PyErr_SetString(PyExc_TypeError, err_msg.data()); + SWIG_fail; + } + + auto type_name = As(type.get().GetAttribute("__name__")); + if (!type_name) { + llvm::StringRef err_msg = llvm::toString(type_name.takeError()); + PyErr_SetString(PyExc_TypeError, err_msg.data()); + SWIG_fail; + } + + if (llvm::StringRef(type_name.get()).startswith("SB")) { + // TODO: Add type name to error string. + PyErr_SetString(PyExc_TypeError, "input type is invalid"); + SWIG_fail; + } else { + $1 = $input; + } + } + } +} + %typemap(out) lldb::ScriptedObject { $result = nullptr; if (const void* impl = $1) Index: lldb/include/lldb/API/SBDebugger.h =================================================================== --- lldb/include/lldb/API/SBDebugger.h +++ lldb/include/lldb/API/SBDebugger.h @@ -472,6 +472,9 @@ SBTrace LoadTraceFromFile(SBError &error, const SBFileSpec &trace_description_file); + SBStructuredData + CreateStructuredDataFromScriptObject(const ScriptedTypedObject obj) const; + protected: friend class lldb_private::CommandPluginInterfaceImplementation; friend class lldb_private::python::SWIGBridge; Index: lldb/include/lldb/API/SBDefines.h =================================================================== --- lldb/include/lldb/API/SBDefines.h +++ lldb/include/lldb/API/SBDefines.h @@ -127,6 +127,14 @@ void *baton); typedef void *ScriptedObject; + +typedef struct ScriptedTypedObject { + ScriptedTypedObject(ScriptedObject ptr, lldb::ScriptLanguage lang) + : ptr(ptr), lang(lang) {} + + ScriptedObject ptr; + lldb::ScriptLanguage lang; +} ScriptedTypedObject; } #endif // LLDB_API_SBDEFINES_H Index: lldb/include/lldb/API/SBStructuredData.h =================================================================== --- lldb/include/lldb/API/SBStructuredData.h +++ lldb/include/lldb/API/SBStructuredData.h @@ -31,6 +31,10 @@ ~SBStructuredData(); + static SBStructuredData + CreateFromScriptObject(const ScriptedTypedObject obj, + const lldb::SBDebugger &debugger); + lldb::SBStructuredData &operator=(const lldb::SBStructuredData &rhs); explicit operator bool() const; @@ -101,6 +105,9 @@ /// \a dst in all cases. size_t GetStringValue(char *dst, size_t dst_len) const; + /// Return the generic pointer if this data structure is a generic type. + lldb::ScriptedObject GetGenericValue() const; + protected: friend class SBAttachInfo; friend class SBLaunchInfo; Index: lldb/include/lldb/Core/StructuredDataImpl.h =================================================================== --- lldb/include/lldb/Core/StructuredDataImpl.h +++ lldb/include/lldb/Core/StructuredDataImpl.h @@ -161,6 +161,17 @@ return (::snprintf(dst, dst_len, "%s", result.data())); } + void *GetGenericValue() const { + if (!m_data_sp) + return nullptr; + + StructuredData::Generic *generic_data = m_data_sp->GetAsGeneric(); + if (!generic_data) + return nullptr; + + return generic_data->GetValue(); + } + StructuredData::ObjectSP GetObjectSP() const { return m_data_sp; } private: Index: lldb/include/lldb/Interpreter/ScriptInterpreter.h =================================================================== --- lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -591,6 +591,11 @@ return *m_scripted_platform_interface_up; } + virtual StructuredData::ObjectSP + CreateStructuredDataFromScriptedObject(void *obj) { + return {}; + } + lldb::DataExtractorSP GetDataExtractorFromSBData(const lldb::SBData &data) const; Index: lldb/source/API/SBDebugger.cpp =================================================================== --- lldb/source/API/SBDebugger.cpp +++ lldb/source/API/SBDebugger.cpp @@ -1702,6 +1702,23 @@ return SBTrace::LoadTraceFromFile(error, *this, trace_description_file); } +SBStructuredData SBDebugger::CreateStructuredDataFromScriptObject( + const ScriptedTypedObject obj) const { + LLDB_INSTRUMENT_VA(this, obj); + + ScriptInterpreter *interpreter = + m_opaque_sp->GetScriptInterpreter(true, obj.lang); + + if (!interpreter) + return {}; + + StructuredDataImpl sd_impl( + interpreter->CreateStructuredDataFromScriptedObject(obj.ptr)); + if (sd_impl.IsValid()) + return SBStructuredData(sd_impl); + return {}; +} + void SBDebugger::RequestInterrupt() { LLDB_INSTRUMENT_VA(this); Index: lldb/source/API/SBStructuredData.cpp =================================================================== --- lldb/source/API/SBStructuredData.cpp +++ lldb/source/API/SBStructuredData.cpp @@ -10,6 +10,7 @@ #include "lldb/Core/StructuredDataImpl.h" #include "lldb/Utility/Instrumentation.h" +#include "lldb/API/SBDebugger.h" #include "lldb/API/SBStream.h" #include "lldb/API/SBStringList.h" #include "lldb/Target/StructuredDataPlugin.h" @@ -45,6 +46,12 @@ SBStructuredData::~SBStructuredData() = default; +SBStructuredData +SBStructuredData::CreateFromScriptObject(const ScriptedTypedObject obj, + const lldb::SBDebugger &debugger) { + return debugger.CreateStructuredDataFromScriptObject(obj); +} + SBStructuredData &SBStructuredData:: operator=(const lldb::SBStructuredData &rhs) { LLDB_INSTRUMENT_VA(this, rhs); @@ -197,3 +204,9 @@ return m_impl_up->GetStringValue(dst, dst_len); } + +lldb::ScriptedObject SBStructuredData::GetGenericValue() const { + LLDB_INSTRUMENT_VA(this); + + return m_impl_up->GetGenericValue(); +} Index: lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h +++ lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h @@ -343,6 +343,15 @@ return python::Take(obj); } + llvm::Expected GetType() const { + if (!m_py_obj) + return nullDeref(); + PyObject *obj = PyObject_Type(m_py_obj); + if (!obj) + return exception(); + return python::Take(obj); + } + llvm::Expected IsTrue() { if (!m_py_obj) return nullDeref(); Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -1519,6 +1519,16 @@ return std::make_unique(*this); } +StructuredData::ObjectSP +ScriptInterpreterPythonImpl::CreateStructuredDataFromScriptedObject( + lldb::ScriptedObject obj) { + PythonObject py_obj(PyRefType::Borrowed, static_cast(obj)); + if (!py_obj.IsValid() || py_obj.IsNone()) + return {}; + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); + return py_obj.CreateStructuredObject(); +} + StructuredData::GenericSP ScriptInterpreterPythonImpl::OSPlugin_CreatePluginObject( const char *class_name, lldb::ProcessSP process_sp) { Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -83,6 +83,9 @@ std::string &error_str, lldb::ThreadPlanSP thread_plan) override; + StructuredData::ObjectSP + CreateStructuredDataFromScriptedObject(lldb::ScriptedObject obj) override; + bool ScriptedThreadPlanExplainsStop(StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error) override; Index: lldb/test/API/python_api/sbstructureddata/TestStructuredDataAPI.py =================================================================== --- lldb/test/API/python_api/sbstructureddata/TestStructuredDataAPI.py +++ lldb/test/API/python_api/sbstructureddata/TestStructuredDataAPI.py @@ -76,6 +76,40 @@ # Tests for array data type self.array_struct_test(dict_struct) + s.Clear() + self.assertSuccess(example.GetAsJSON(s)) + py_obj = json.loads(s.GetData()) + self.assertTrue(py_obj) + self.assertIn("key_dict", py_obj) + + py_dict = py_obj["key_dict"] + self.assertEqual(py_dict["key_string"], "STRING") + self.assertEqual(py_dict["key_uint"], 0xFFFFFFFF00000000) + self.assertEqual(py_dict["key_sint"], -42) + self.assertEqual(py_dict["key_float"], 2.99) + self.assertEqual(py_dict["key_bool"], True) + self.assertEqual(py_dict["key_array"], ["23", "arr"]) + + class MyRandomClass: + payload = "foo" + + py_dict["key_generic"] = MyRandomClass() + + stp = lldb.ScriptedTypedObject(py_dict, lldb.eScriptLanguagePython) + self.assertEqual(stp.ptr, py_dict) + + sd = self.dbg.CreateStructuredDataFromScriptObject(stp) + self.assertTrue(sd.IsValid()) + self.assertEqual(sd.GetSize(), len(py_dict)) + + generic_sd = sd.GetValueForKey("key_generic") + self.assertTrue(generic_sd.IsValid()) + self.assertEqual(generic_sd.GetType(), lldb.eStructuredDataTypeGeneric) + + my_random_class = generic_sd.GetGenericValue() + self.assertTrue(my_random_class) + self.assertEqual(my_random_class.payload, MyRandomClass.payload) + def invalid_struct_test(self, example): invalid_struct = lldb.SBStructuredData() invalid_struct = example.GetValueForKey("invalid_key")