| //===-- ScriptedPythonInterface.cpp ---------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "../lldb-python.h" | |
| #include "lldb/Host/Config.h" | |
| #include "lldb/Utility/Log.h" | |
| #include "lldb/lldb-enumerations.h" | |
| #include "../ScriptInterpreterPythonImpl.h" | |
| #include "ScriptedPythonInterface.h" | |
| #include "lldb/Symbol/SymbolContext.h" | |
| #include "lldb/ValueObject/ValueObjectList.h" | |
| #include <optional> | |
| using namespace lldb; | |
| using namespace lldb_private; | |
| ScriptedPythonInterface::ScriptedPythonInterface( | |
| ScriptInterpreterPythonImpl &interpreter) | |
| : ScriptedInterface(), m_interpreter(interpreter) {} | |
| template <> | |
| StructuredData::ArraySP | |
| ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>( | |
| python::PythonObject &p, Status &error) { | |
| python::PythonList result_list(python::PyRefType::Borrowed, p.get()); | |
| return result_list.CreateStructuredArray(); | |
| } | |
| template <> | |
| StructuredData::DictionarySP | |
| ScriptedPythonInterface::ExtractValueFromPythonObject< | |
| StructuredData::DictionarySP>(python::PythonObject &p, Status &error) { | |
| python::PythonDictionary result_dict(python::PyRefType::Borrowed, p.get()); | |
| return result_dict.CreateStructuredDictionary(); | |
| } | |
| template <> | |
| Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>( | |
| python::PythonObject &p, Status &error) { | |
| if (lldb::SBError *sb_error = reinterpret_cast<lldb::SBError *>( | |
| python::LLDBSWIGPython_CastPyObjectToSBError(p.get()))) | |
| return m_interpreter.GetStatusFromSBError(*sb_error); | |
| error = | |
| Status::FromErrorString("Couldn't cast lldb::SBError to lldb::Status."); | |
| return {}; | |
| } | |
| template <> | |
| Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>( | |
| python::PythonObject &p, Status &error) { | |
| if (lldb::SBEvent *sb_event = reinterpret_cast<lldb::SBEvent *>( | |
| python::LLDBSWIGPython_CastPyObjectToSBEvent(p.get()))) | |
| return m_interpreter.GetOpaqueTypeFromSBEvent(*sb_event); | |
| error = Status::FromErrorString( | |
| "Couldn't cast lldb::SBEvent to lldb_private::Event."); | |
| return nullptr; | |
| } | |
| template <> | |
| lldb::StreamSP | |
| ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>( | |
| python::PythonObject &p, Status &error) { | |
| if (lldb::SBStream *sb_stream = reinterpret_cast<lldb::SBStream *>( | |
| python::LLDBSWIGPython_CastPyObjectToSBStream(p.get()))) | |
| return m_interpreter.GetOpaqueTypeFromSBStream(*sb_stream); | |
| error = Status::FromErrorString( | |
| "Couldn't cast lldb::SBStream to lldb_private::Stream."); | |
| return nullptr; | |
| } | |
| template <> | |
| lldb::StackFrameSP | |
| ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StackFrameSP>( | |
| python::PythonObject &p, Status &error) { | |
| if (lldb::SBFrame *sb_frame = reinterpret_cast<lldb::SBFrame *>( | |
| python::LLDBSWIGPython_CastPyObjectToSBFrame(p.get()))) | |
| return m_interpreter.GetOpaqueTypeFromSBFrame(*sb_frame); | |
| error = Status::FromErrorString( | |
| "Couldn't cast lldb::SBFrame to lldb_private::StackFrame."); | |
| return nullptr; | |
| } | |
| template <> | |
| lldb::ThreadSP | |
| ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::ThreadSP>( | |
| python::PythonObject &p, Status &error) { | |
| if (lldb::SBThread *sb_thread = reinterpret_cast<lldb::SBThread *>( | |
| python::LLDBSWIGPython_CastPyObjectToSBThread(p.get()))) | |
| return m_interpreter.GetOpaqueTypeFromSBThread(*sb_thread); | |
| error = Status::FromErrorString( | |
| "Couldn't cast lldb::SBThread to lldb_private::Thread."); | |
| return nullptr; | |
| } | |
| template <> | |
| SymbolContext | |
| ScriptedPythonInterface::ExtractValueFromPythonObject<SymbolContext>( | |
| python::PythonObject &p, Status &error) { | |
| if (lldb::SBSymbolContext *sb_symbol_context = | |
| reinterpret_cast<lldb::SBSymbolContext *>( | |
| python::LLDBSWIGPython_CastPyObjectToSBSymbolContext(p.get()))) | |
| return m_interpreter.GetOpaqueTypeFromSBSymbolContext(*sb_symbol_context); | |
| error = Status::FromErrorString( | |
| "Couldn't cast lldb::SBSymbolContext to lldb_private::SymbolContext."); | |
| return {}; | |
| } | |
| template <> | |
| lldb::DataExtractorSP | |
| ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>( | |
| python::PythonObject &p, Status &error) { | |
| lldb::SBData *sb_data = reinterpret_cast<lldb::SBData *>( | |
| python::LLDBSWIGPython_CastPyObjectToSBData(p.get())); | |
| if (!sb_data) { | |
| error = Status::FromErrorStringWithFormat( | |
| "Couldn't cast lldb::SBData to lldb::DataExtractorSP."); | |
| return nullptr; | |
| } | |
| return m_interpreter.GetDataExtractorFromSBData(*sb_data); | |
| } | |
| template <> | |
| lldb::BreakpointSP | |
| ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>( | |
| python::PythonObject &p, Status &error) { | |
| lldb::SBBreakpoint *sb_breakpoint = reinterpret_cast<lldb::SBBreakpoint *>( | |
| python::LLDBSWIGPython_CastPyObjectToSBBreakpoint(p.get())); | |
| if (!sb_breakpoint) { | |
| error = Status::FromErrorStringWithFormat( | |
| "Couldn't cast lldb::SBBreakpoint to lldb::BreakpointSP."); | |
| return nullptr; | |
| } | |
| return m_interpreter.GetOpaqueTypeFromSBBreakpoint(*sb_breakpoint); | |
| } | |
| template <> | |
| lldb::BreakpointLocationSP | |
| ScriptedPythonInterface::ExtractValueFromPythonObject< | |
| lldb::BreakpointLocationSP>(python::PythonObject &p, Status &error) { | |
| lldb::SBBreakpointLocation *sb_break_loc = | |
| reinterpret_cast<lldb::SBBreakpointLocation *>( | |
| python::LLDBSWIGPython_CastPyObjectToSBBreakpointLocation(p.get())); | |
| if (!sb_break_loc) { | |
| error = Status::FromErrorStringWithFormat( | |
| "Couldn't cast lldb::SBBreakpointLocation to " | |
| "lldb::BreakpointLocationSP."); | |
| return nullptr; | |
| } | |
| return m_interpreter.GetOpaqueTypeFromSBBreakpointLocation(*sb_break_loc); | |
| } | |
| template <> | |
| lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< | |
| lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error) { | |
| lldb::SBAttachInfo *sb_attach_info = reinterpret_cast<lldb::SBAttachInfo *>( | |
| python::LLDBSWIGPython_CastPyObjectToSBAttachInfo(p.get())); | |
| if (!sb_attach_info) { | |
| error = Status::FromErrorStringWithFormat( | |
| "Couldn't cast lldb::SBAttachInfo to lldb::ProcessAttachInfoSP."); | |
| return nullptr; | |
| } | |
| return m_interpreter.GetOpaqueTypeFromSBAttachInfo(*sb_attach_info); | |
| } | |
| template <> | |
| lldb::ProcessLaunchInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< | |
| lldb::ProcessLaunchInfoSP>(python::PythonObject &p, Status &error) { | |
| lldb::SBLaunchInfo *sb_launch_info = reinterpret_cast<lldb::SBLaunchInfo *>( | |
| python::LLDBSWIGPython_CastPyObjectToSBLaunchInfo(p.get())); | |
| if (!sb_launch_info) { | |
| error = Status::FromErrorStringWithFormat( | |
| "Couldn't cast lldb::SBLaunchInfo to lldb::ProcessLaunchInfoSP."); | |
| return nullptr; | |
| } | |
| return m_interpreter.GetOpaqueTypeFromSBLaunchInfo(*sb_launch_info); | |
| } | |
| template <> | |
| std::optional<MemoryRegionInfo> | |
| ScriptedPythonInterface::ExtractValueFromPythonObject< | |
| std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error) { | |
| lldb::SBMemoryRegionInfo *sb_mem_reg_info = | |
| reinterpret_cast<lldb::SBMemoryRegionInfo *>( | |
| python::LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(p.get())); | |
| if (!sb_mem_reg_info) { | |
| error = Status::FromErrorStringWithFormat( | |
| "Couldn't cast lldb::SBMemoryRegionInfo to " | |
| "lldb_private::MemoryRegionInfo."); | |
| return {}; | |
| } | |
| return m_interpreter.GetOpaqueTypeFromSBMemoryRegionInfo(*sb_mem_reg_info); | |
| } | |
| template <> | |
| lldb::ExecutionContextRefSP | |
| ScriptedPythonInterface::ExtractValueFromPythonObject< | |
| lldb::ExecutionContextRefSP>(python::PythonObject &p, Status &error) { | |
| lldb::SBExecutionContext *sb_exe_ctx = | |
| reinterpret_cast<lldb::SBExecutionContext *>( | |
| python::LLDBSWIGPython_CastPyObjectToSBExecutionContext(p.get())); | |
| if (!sb_exe_ctx) { | |
| error = Status::FromErrorStringWithFormat( | |
| "Couldn't cast lldb::SBExecutionContext to " | |
| "lldb::ExecutionContextRefSP."); | |
| return {}; | |
| } | |
| return m_interpreter.GetOpaqueTypeFromSBExecutionContext(*sb_exe_ctx); | |
| } | |
| template <> | |
| lldb::DescriptionLevel | |
| ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DescriptionLevel>( | |
| python::PythonObject &p, Status &error) { | |
| lldb::DescriptionLevel ret_val = lldb::eDescriptionLevelBrief; | |
| llvm::Expected<unsigned long long> unsigned_or_err = p.AsUnsignedLongLong(); | |
| if (!unsigned_or_err) { | |
| error = (Status::FromError(unsigned_or_err.takeError())); | |
| return ret_val; | |
| } | |
| unsigned long long unsigned_val = *unsigned_or_err; | |
| if (unsigned_val >= lldb::DescriptionLevel::kNumDescriptionLevels) { | |
| error = Status("value too large for lldb::DescriptionLevel."); | |
| return ret_val; | |
| } | |
| return static_cast<lldb::DescriptionLevel>(unsigned_val); | |
| } | |
| template <> | |
| lldb::StackFrameListSP | |
| ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StackFrameListSP>( | |
| python::PythonObject &p, Status &error) { | |
| lldb::SBFrameList *sb_frame_list = reinterpret_cast<lldb::SBFrameList *>( | |
| python::LLDBSWIGPython_CastPyObjectToSBFrameList(p.get())); | |
| if (!sb_frame_list) { | |
| error = Status::FromErrorStringWithFormat( | |
| "couldn't cast lldb::SBFrameList to lldb::StackFrameListSP."); | |
| return {}; | |
| } | |
| return m_interpreter.GetOpaqueTypeFromSBFrameList(*sb_frame_list); | |
| } | |
| template <> | |
| lldb::ValueObjectSP | |
| ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::ValueObjectSP>( | |
| python::PythonObject &p, Status &error) { | |
| lldb::SBValue *sb_value = reinterpret_cast<lldb::SBValue *>( | |
| python::LLDBSWIGPython_CastPyObjectToSBValue(p.get())); | |
| if (!sb_value) { | |
| error = Status::FromErrorStringWithFormat( | |
| "couldn't cast lldb::SBValue to lldb::ValueObjectSP"); | |
| return {}; | |
| } | |
| return m_interpreter.GetOpaqueTypeFromSBValue(*sb_value); | |
| } | |
| template <> | |
| lldb::TargetSP | |
| ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::TargetSP>( | |
| python::PythonObject &p, Status &error) { | |
| lldb::SBTarget *sb_target = reinterpret_cast<lldb::SBTarget *>( | |
| python::LLDBSWIGPython_CastPyObjectToSBTarget(p.get())); | |
| if (!sb_target) { | |
| error = Status::FromErrorStringWithFormat( | |
| "couldn't cast lldb::SBTarget to lldb::TargetSP"); | |
| return {}; | |
| } | |
| return m_interpreter.GetOpaqueTypeFromSBTarget(*sb_target); | |
| } | |
| template <> | |
| lldb::ValueObjectListSP | |
| ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::ValueObjectListSP>( | |
| python::PythonObject &p, Status &error) { | |
| // Two Python return shapes are accepted here so callers can go through | |
| // Dispatch<ValueObjectListSP>() uniformly: an `SBValueList` wrapper | |
| // (what most extension methods return) and a plain Python `list` of | |
| // `SBValue` (what `get_recognized_arguments` is documented to return). | |
| lldb::ValueObjectListSP out = std::make_shared<ValueObjectList>(); | |
| if (auto *sb_value_list = reinterpret_cast<lldb::SBValueList *>( | |
| python::LLDBSWIGPython_CastPyObjectToSBValueList(p.get()))) { | |
| for (uint32_t i = 0, e = sb_value_list->GetSize(); i < e; ++i) { | |
| SBValue value = sb_value_list->GetValueAtIndex(i); | |
| out->Append(m_interpreter.GetOpaqueTypeFromSBValue(value)); | |
| } | |
| return out; | |
| } | |
| // Fallback: a plain Python `list` of `SBValue`. Round-trip through | |
| // `CreateStructuredObject` so we don't touch the `PyList_*` C API | |
| // directly; unknown-shape items surface as `StructuredData::Generic` | |
| // holding their opaque `PyObject*`, which we hand back to SWIG to | |
| // recover the SBValue wrapper. | |
| StructuredData::ObjectSP structured = p.CreateStructuredObject(); | |
| StructuredData::Array *arr = structured ? structured->GetAsArray() : nullptr; | |
| if (arr) { | |
| size_t index = 0; | |
| bool aborted = false; | |
| arr->ForEach([&](StructuredData::Object *item) { | |
| StructuredData::Generic *generic = item ? item->GetAsGeneric() : nullptr; | |
| if (!generic) { | |
| error = Status::FromErrorStringWithFormatv( | |
| "ValueObjectList item at index {0} is not a " | |
| "StructuredData::Generic", | |
| index); | |
| aborted = true; | |
| return false; | |
| } | |
| auto *sb_value = reinterpret_cast<lldb::SBValue *>( | |
| python::LLDBSWIGPython_CastPyObjectToSBValue( | |
| static_cast<PyObject *>(generic->GetValue()))); | |
| if (sb_value) | |
| if (auto valobj_sp = m_interpreter.GetOpaqueTypeFromSBValue(*sb_value)) | |
| out->Append(valobj_sp); | |
| ++index; | |
| return true; | |
| }); | |
| if (aborted) | |
| return {}; | |
| return out; | |
| } | |
| error = Status::FromErrorStringWithFormat( | |
| "couldn't extract ValueObjectList from Python return value"); | |
| return {}; | |
| } | |
| template <> | |
| std::optional<lldb::ValueType> | |
| ScriptedPythonInterface::ExtractValueFromPythonObject< | |
| std::optional<lldb::ValueType>>(python::PythonObject &p, Status &error) { | |
| if (p.IsNone()) | |
| return std::nullopt; | |
| llvm::Expected<unsigned long long> val = p.AsUnsignedLongLong(); | |
| if (!val) { | |
| error = Status::FromError(val.takeError()); | |
| return std::nullopt; | |
| } | |
| unsigned long long unmasked = *val & ~kValueTypeFlagsMask; | |
| unsigned long long flags = *val & kValueTypeFlagsMask; | |
| if (unmasked == eValueTypeInvalid || unmasked > kLastValueType) { | |
| error = Status::FromErrorStringWithFormatv( | |
| "value type invalid or too large (got {0} | {1:x})", unmasked, flags); | |
| return std::nullopt; | |
| } | |
| return static_cast<ValueType>(unmasked | flags); | |
| } |