| //===----------------------------------------------------------------------===// | |
| // | |
| // 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/Core/PluginManager.h" | |
| #include "lldb/Host/Config.h" | |
| #include "lldb/Target/ExecutionContext.h" | |
| #include "lldb/Utility/LLDBLog.h" | |
| #include "lldb/Utility/Log.h" | |
| #include "lldb/ValueObject/ValueObject.h" | |
| #include "lldb/lldb-enumerations.h" | |
| #include "../SWIGPythonBridge.h" | |
| #include "../ScriptInterpreterPythonImpl.h" | |
| #include "ScriptedFramePythonInterface.h" | |
| #include <optional> | |
| using namespace lldb; | |
| using namespace lldb_private; | |
| using namespace lldb_private::python; | |
| using Locker = ScriptInterpreterPythonImpl::Locker; | |
| ScriptedFramePythonInterface::ScriptedFramePythonInterface( | |
| ScriptInterpreterPythonImpl &interpreter) | |
| : ScriptedFrameInterface(), ScriptedPythonInterface(interpreter) {} | |
| llvm::Expected<StructuredData::GenericSP> | |
| ScriptedFramePythonInterface::CreatePluginObject( | |
| const llvm::StringRef class_name, ExecutionContext &exe_ctx, | |
| StructuredData::DictionarySP args_sp, StructuredData::Generic *script_obj) { | |
| ExecutionContextRefSP exe_ctx_ref_sp = | |
| std::make_shared<ExecutionContextRef>(exe_ctx); | |
| ScriptedMetadata scripted_metadata(class_name, args_sp); | |
| return ScriptedPythonInterface::CreatePluginObject( | |
| scripted_metadata, script_obj, exe_ctx_ref_sp, args_sp); | |
| } | |
| lldb::user_id_t ScriptedFramePythonInterface::GetID() { | |
| StructuredData::ObjectSP obj = | |
| LogAndDefault(Dispatch("get_id"), LLVM_PRETTY_FUNCTION); | |
| if (!obj) | |
| return LLDB_INVALID_FRAME_ID; | |
| return obj->GetUnsignedIntegerValue(LLDB_INVALID_FRAME_ID); | |
| } | |
| lldb::addr_t ScriptedFramePythonInterface::GetPC() { | |
| StructuredData::ObjectSP obj = | |
| LogAndDefault(Dispatch("get_pc"), LLVM_PRETTY_FUNCTION); | |
| if (!obj) | |
| return LLDB_INVALID_ADDRESS; | |
| return obj->GetUnsignedIntegerValue(LLDB_INVALID_ADDRESS); | |
| } | |
| lldb::addr_t ScriptedFramePythonInterface::GetCFA() { | |
| StructuredData::ObjectSP obj = | |
| LogAndDefault(Dispatch("get_cfa"), LLVM_PRETTY_FUNCTION); | |
| if (!obj) | |
| return LLDB_INVALID_ADDRESS; | |
| return obj->GetUnsignedIntegerValue(LLDB_INVALID_ADDRESS); | |
| } | |
| std::optional<SymbolContext> ScriptedFramePythonInterface::GetSymbolContext() { | |
| llvm::Expected<SymbolContext> sym_ctx_or_err = | |
| Dispatch<SymbolContext>("get_symbol_context"); | |
| if (!sym_ctx_or_err) { | |
| LLDB_LOG_ERROR(GetLog(LLDBLog::Script), sym_ctx_or_err.takeError(), | |
| "get_symbol_context failed: {0}"); | |
| return {}; | |
| } | |
| return *sym_ctx_or_err; | |
| } | |
| std::optional<std::string> ScriptedFramePythonInterface::GetFunctionName() { | |
| StructuredData::ObjectSP obj = | |
| LogAndDefault(Dispatch("get_function_name"), LLVM_PRETTY_FUNCTION); | |
| if (!obj) | |
| return {}; | |
| return obj->GetStringValue().str(); | |
| } | |
| std::optional<std::string> | |
| ScriptedFramePythonInterface::GetDisplayFunctionName() { | |
| StructuredData::ObjectSP obj = LogAndDefault( | |
| Dispatch("get_display_function_name"), LLVM_PRETTY_FUNCTION); | |
| if (!obj) | |
| return {}; | |
| return obj->GetStringValue().str(); | |
| } | |
| bool ScriptedFramePythonInterface::IsInlined() { | |
| StructuredData::ObjectSP obj = | |
| LogAndDefault(Dispatch("is_inlined"), LLVM_PRETTY_FUNCTION); | |
| if (!obj) | |
| return false; | |
| return obj->GetBooleanValue(); | |
| } | |
| bool ScriptedFramePythonInterface::IsArtificial() { | |
| StructuredData::ObjectSP obj = | |
| LogAndDefault(Dispatch("is_artificial"), LLVM_PRETTY_FUNCTION); | |
| if (!obj) | |
| return false; | |
| return obj->GetBooleanValue(); | |
| } | |
| bool ScriptedFramePythonInterface::IsHidden() { | |
| StructuredData::ObjectSP obj = | |
| LogAndDefault(Dispatch("is_hidden"), LLVM_PRETTY_FUNCTION); | |
| if (!obj) | |
| return false; | |
| return obj->GetBooleanValue(); | |
| } | |
| StructuredData::DictionarySP ScriptedFramePythonInterface::GetRegisterInfo() { | |
| StructuredData::DictionarySP dict = | |
| LogAndDefault(Dispatch<StructuredData::DictionarySP>("get_register_info"), | |
| LLVM_PRETTY_FUNCTION); | |
| if (!dict) | |
| return {}; | |
| return dict; | |
| } | |
| std::optional<std::string> ScriptedFramePythonInterface::GetRegisterContext() { | |
| StructuredData::ObjectSP obj = | |
| LogAndDefault(Dispatch("get_register_context"), LLVM_PRETTY_FUNCTION); | |
| if (!obj) | |
| return {}; | |
| return obj->GetStringValue().str(); | |
| } | |
| lldb::ValueObjectListSP ScriptedFramePythonInterface::GetVariables() { | |
| return LogAndDefault(Dispatch<lldb::ValueObjectListSP>("get_variables"), | |
| LLVM_PRETTY_FUNCTION); | |
| } | |
| std::optional<lldb::ValueType> | |
| ScriptedFramePythonInterface::GetValueTypeForVariable( | |
| lldb::ValueObjectSP value) { | |
| return LogAndDefault(Dispatch<std::optional<lldb::ValueType>>( | |
| "get_value_type_for_variable", std::move(value)), | |
| LLVM_PRETTY_FUNCTION); | |
| } | |
| lldb::ValueObjectSP | |
| ScriptedFramePythonInterface::GetValueObjectForVariableExpression( | |
| llvm::StringRef expr, uint32_t options, Status &status) { | |
| llvm::Expected<lldb::ValueObjectSP> val_or_err = | |
| Dispatch<lldb::ValueObjectSP>("get_value_for_variable_expression", | |
| expr.data(), options, status); | |
| if (!val_or_err) { | |
| status = Status::FromError(val_or_err.takeError()); | |
| return {}; | |
| } | |
| return *val_or_err; | |
| } | |
| llvm::Expected<ScriptedMetadata> | |
| ScriptedFramePythonInterface::GetThreadPlanMetadataForStepType( | |
| lldb::StepType step_type) { | |
| ScriptedMetadata no_plan_return("", StructuredData::DictionarySP()); | |
| // A frame that doesn't implement `get_plan_spec_for_step_type` simply has no | |
| // plan to offer, which Dispatch reports as an UnimplementedError. Any other | |
| // failure - notably an exception raised inside the method - propagates. | |
| llvm::Expected<std::optional<StructuredData::DictionarySP>> dict_or_err = | |
| DispatchToOptional<StructuredData::DictionarySP>( | |
| "get_plan_spec_for_step_type", step_type); | |
| if (!dict_or_err) | |
| return llvm::joinErrors( | |
| llvm::createStringError( | |
| "error dispatching get_plan_spec_for_step_type"), | |
| dict_or_err.takeError()); | |
| // The return value is an StructuredData::Dictionary with the class name and | |
| // the extra args for the call: | |
| StructuredData::DictionarySP dict_sp = dict_or_err->value_or(nullptr); | |
| if (!dict_sp || !dict_sp->IsValid()) | |
| return no_plan_return; | |
| StructuredData::ObjectSP obj = dict_sp->GetValueForKey("class_name"); | |
| if (!obj) | |
| return llvm::createStringError("Required 'class_name' field not provided."); | |
| std::string class_string = obj->GetStringValue().str(); | |
| // Passing out an empty class name is they way to say the frame provider | |
| // doesn't know how to step from here, and the regular method should be tried | |
| // instead. So we only need to make sure the class exists if we were given a | |
| // string: | |
| if (!class_string.empty()) { | |
| const char *class_str = class_string.c_str(); | |
| if (!m_interpreter.CheckObjectExists(class_str)) | |
| return llvm::createStringError( | |
| "class_name specified a class: '%s' that does not exist.", class_str); | |
| } | |
| // Look for extra args, this is optional: | |
| StructuredData::Dictionary *extra_args_ptr = nullptr; | |
| StructuredData::DictionarySP extra_args_sp; | |
| if (dict_sp->GetValueForKeyAsDictionary("extra_args", extra_args_ptr)) | |
| extra_args_sp = std::static_pointer_cast<StructuredData::Dictionary>( | |
| extra_args_ptr->shared_from_this()); | |
| // Now make a new thread plan for stepping using the provided class name and | |
| // extra args. | |
| ScriptedMetadata plan_metadata(class_string, extra_args_sp); | |
| return plan_metadata; | |
| } | |
| void ScriptedFramePythonInterface::Initialize() { | |
| PluginManager::RegisterPlugin( | |
| GetPluginNameStatic(), | |
| "Provide frame state for scripted threads and frame providers.", | |
| CreateInstance, eScriptedExtensionScriptedFrame, eScriptLanguagePython, | |
| {}); | |
| } | |
| void ScriptedFramePythonInterface::Terminate() { | |
| PluginManager::UnregisterPlugin(CreateInstance); | |
| } |