Index: lldb/bindings/python/python-typemaps.swig =================================================================== --- lldb/bindings/python/python-typemaps.swig +++ lldb/bindings/python/python-typemaps.swig @@ -59,7 +59,59 @@ free((char *) $1); } -%typemap(out) lldb::ScriptedObject { +%typemap(in) lldb::ScriptObjectPtr { + if ($input == Py_None) { + $1 = nullptr; + } else { + PythonObject obj(PyRefType::Borrowed, $input); + if (!obj.IsValid()) { + PyErr_SetString(PyExc_TypeError, "Script object is not valid"); + SWIG_fail; + } + + auto lldb_module = PythonModule::Import("lldb"); + if (!lldb_module) { + std::string err_msg = llvm::toString(lldb_module.takeError()); + PyErr_SetString(PyExc_TypeError, err_msg.c_str()); + SWIG_fail; + } + + auto sb_structured_data_class = lldb_module.get().Get("SBStructuredData"); + if (!sb_structured_data_class) { + std::string err_msg = llvm::toString(sb_structured_data_class.takeError()); + PyErr_SetString(PyExc_TypeError, err_msg.c_str()); + SWIG_fail; + } + + if (obj.IsInstance(sb_structured_data_class.get())) { + $1 = obj.get(); + } else { + auto type = obj.GetType(); + if (!type) { + std::string err_msg = llvm::toString(type.takeError()); + PyErr_SetString(PyExc_TypeError, err_msg.c_str()); + SWIG_fail; + } + + auto type_name = As(type.get().GetAttribute("__name__")); + if (!type_name) { + std::string err_msg = llvm::toString(type_name.takeError()); + PyErr_SetString(PyExc_TypeError, err_msg.c_str()); + SWIG_fail; + } + + if (llvm::StringRef(type_name.get()).startswith("SB")) { + std::string error_msg = "Input type is invalid: " + type_name.get(); + PyErr_SetString(PyExc_TypeError, error_msg.c_str()); + SWIG_fail; + } else { + $1 = obj.get(); + } + } + } +} + +%typemap(out) lldb::ScriptObjectPtr { $result = nullptr; if (const void* impl = $1) $result = (PyObject*) impl; @@ -71,6 +123,18 @@ } } +%typemap(out) lldb::ScriptObject { + $result = nullptr; + if (const void* impl = $1.ptr) + $result = (PyObject*) impl; + if (!$result) { + $result = Py_None; + Py_INCREF(Py_None); + } else { + Py_INCREF($result); + } +} + %typemap(out) char** { int len; int i; Index: lldb/include/lldb/API/SBDebugger.h =================================================================== --- lldb/include/lldb/API/SBDebugger.h +++ lldb/include/lldb/API/SBDebugger.h @@ -484,6 +484,7 @@ friend class SBListener; friend class SBProcess; friend class SBSourceManager; + friend class SBStructuredData; friend class SBTarget; friend class SBTrace; Index: lldb/include/lldb/API/SBDefines.h =================================================================== --- lldb/include/lldb/API/SBDefines.h +++ lldb/include/lldb/API/SBDefines.h @@ -125,8 +125,6 @@ typedef void (*SBDebuggerDestroyCallback)(lldb::user_id_t debugger_id, void *baton); - -typedef void *ScriptedObject; } #endif // LLDB_API_SBDEFINES_H Index: lldb/include/lldb/API/SBProcess.h =================================================================== --- lldb/include/lldb/API/SBProcess.h +++ lldb/include/lldb/API/SBProcess.h @@ -437,7 +437,7 @@ /// lldb::SBError DeallocateMemory(lldb::addr_t ptr); - lldb::ScriptedObject GetScriptedImplementation(); + lldb::ScriptObject GetScriptedImplementation(); protected: friend class SBAddress; Index: lldb/include/lldb/API/SBStructuredData.h =================================================================== --- lldb/include/lldb/API/SBStructuredData.h +++ lldb/include/lldb/API/SBStructuredData.h @@ -29,6 +29,8 @@ SBStructuredData(const lldb::SBStructuredData &rhs); + SBStructuredData(const ScriptObject obj, const lldb::SBDebugger &debugger); + ~SBStructuredData(); lldb::SBStructuredData &operator=(const lldb::SBStructuredData &rhs); @@ -101,6 +103,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::ScriptObject 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 + CreateStructuredDataFromScriptObject(lldb::ScriptObject obj) { + return {}; + } + lldb::DataExtractorSP GetDataExtractorFromSBData(const lldb::SBData &data) const; Index: lldb/include/lldb/lldb-types.h =================================================================== --- lldb/include/lldb/lldb-types.h +++ lldb/include/lldb/lldb-types.h @@ -76,6 +76,16 @@ typedef bool (*ExpressionCancelCallback)(ExpressionEvaluationPhase phase, void *baton); +typedef void *ScriptObjectPtr; + +struct ScriptObject { + ScriptObject(ScriptObjectPtr ptr, lldb::ScriptLanguage lang) + : ptr(ptr), lang(lang) {} + + const ScriptObjectPtr ptr; + lldb::ScriptLanguage lang; +}; + typedef uint64_t addr_t; typedef uint64_t user_id_t; typedef uint64_t pid_t; Index: lldb/source/API/SBProcess.cpp =================================================================== --- lldb/source/API/SBProcess.cpp +++ lldb/source/API/SBProcess.cpp @@ -1285,8 +1285,9 @@ return sb_error; } -ScriptedObject SBProcess::GetScriptedImplementation() { +ScriptObject SBProcess::GetScriptedImplementation() { LLDB_INSTRUMENT_VA(this); ProcessSP process_sp(GetSP()); - return (process_sp) ? process_sp->GetImplementation() : nullptr; + return ScriptObject((process_sp) ? process_sp->GetImplementation() : nullptr, + eScriptLanguageDefault); } Index: lldb/source/API/SBStructuredData.cpp =================================================================== --- lldb/source/API/SBStructuredData.cpp +++ lldb/source/API/SBStructuredData.cpp @@ -7,13 +7,16 @@ //===----------------------------------------------------------------------===// #include "lldb/API/SBStructuredData.h" -#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/Core/Debugger.h" +#include "lldb/Core/StructuredDataImpl.h" +#include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/Target/StructuredDataPlugin.h" #include "lldb/Utility/Event.h" +#include "lldb/Utility/Instrumentation.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StructuredData.h" @@ -33,6 +36,22 @@ LLDB_INSTRUMENT_VA(this, rhs); } +SBStructuredData::SBStructuredData(const ScriptObject obj, + const lldb::SBDebugger &debugger) { + LLDB_INSTRUMENT_VA(this, obj, debugger); + + ScriptInterpreter *interpreter = + debugger.m_opaque_sp->GetScriptInterpreter(true, obj.lang); + + if (!interpreter) + return; + + StructuredDataImplUP impl_up = std::make_unique( + interpreter->CreateStructuredDataFromScriptObject(obj)); + if (impl_up && impl_up->IsValid()) + m_impl_up.reset(impl_up.release()); +} + SBStructuredData::SBStructuredData(const lldb::EventSP &event_sp) : m_impl_up(new StructuredDataImpl(event_sp)) { LLDB_INSTRUMENT_VA(this, event_sp); @@ -197,3 +216,9 @@ return m_impl_up->GetStringValue(dst, dst_len); } + +lldb::ScriptObject SBStructuredData::GetGenericValue() const { + LLDB_INSTRUMENT_VA(this); + + return {m_impl_up->GetGenericValue(), eScriptLanguageDefault}; +} 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::CreateStructuredDataFromScriptObject( + lldb::ScriptObject obj) { + PythonObject py_obj(PyRefType::Borrowed, static_cast(obj.ptr)); + 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 + CreateStructuredDataFromScriptObject(lldb::ScriptObject 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.ScriptObject(py_dict, lldb.eScriptLanguagePython) + self.assertEqual(stp.ptr, py_dict) + + sd = lldb.SBStructuredData(stp, self.dbg) + 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")