| //===-- SBValue.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/API/SBValue.h" | |
| #include "lldb/Utility/Instrumentation.h" | |
| #include "lldb/API/SBDeclaration.h" | |
| #include "lldb/API/SBStream.h" | |
| #include "lldb/API/SBTypeFilter.h" | |
| #include "lldb/API/SBTypeFormat.h" | |
| #include "lldb/API/SBTypeSummary.h" | |
| #include "lldb/API/SBTypeSynthetic.h" | |
| #include "lldb/Breakpoint/Watchpoint.h" | |
| #include "lldb/Core/Declaration.h" | |
| #include "lldb/Core/Module.h" | |
| #include "lldb/Core/Section.h" | |
| #include "lldb/Core/Value.h" | |
| #include "lldb/DataFormatters/DataVisualization.h" | |
| #include "lldb/DataFormatters/DumpValueObjectOptions.h" | |
| #include "lldb/Symbol/Block.h" | |
| #include "lldb/Symbol/ObjectFile.h" | |
| #include "lldb/Symbol/Type.h" | |
| #include "lldb/Symbol/Variable.h" | |
| #include "lldb/Symbol/VariableList.h" | |
| #include "lldb/Target/ExecutionContext.h" | |
| #include "lldb/Target/Process.h" | |
| #include "lldb/Target/StackFrame.h" | |
| #include "lldb/Target/Target.h" | |
| #include "lldb/Target/Thread.h" | |
| #include "lldb/Utility/DataExtractor.h" | |
| #include "lldb/Utility/Scalar.h" | |
| #include "lldb/Utility/Stream.h" | |
| #include "lldb/ValueObject/ValueObject.h" | |
| #include "lldb/ValueObject/ValueObjectConstResult.h" | |
| #include "lldb/API/SBDebugger.h" | |
| #include "lldb/API/SBExpressionOptions.h" | |
| #include "lldb/API/SBFrame.h" | |
| #include "lldb/API/SBProcess.h" | |
| #include "lldb/API/SBTarget.h" | |
| #include "lldb/API/SBThread.h" | |
| #include "lldb/lldb-enumerations.h" | |
| #include <memory> | |
| using namespace lldb; | |
| using namespace lldb_private; | |
| SBValue::SBValue() { LLDB_INSTRUMENT_VA(this); } | |
| SBValue::SBValue(const lldb::ValueObjectSP &value_sp) { | |
| LLDB_INSTRUMENT_VA(this, value_sp); | |
| SetSP(value_sp); | |
| } | |
| SBValue::SBValue(const SBValue &rhs) { | |
| LLDB_INSTRUMENT_VA(this, rhs); | |
| SetSP(rhs.m_opaque_sp); | |
| } | |
| SBValue &SBValue::operator=(const SBValue &rhs) { | |
| LLDB_INSTRUMENT_VA(this, rhs); | |
| if (this != &rhs) { | |
| SetSP(rhs.m_opaque_sp); | |
| } | |
| return *this; | |
| } | |
| SBValue::~SBValue() = default; | |
| bool SBValue::IsValid() { | |
| LLDB_INSTRUMENT_VA(this); | |
| return this->operator bool(); | |
| } | |
| SBValue::operator bool() const { | |
| LLDB_INSTRUMENT_VA(this); | |
| // If this function ever changes to anything that does more than just check | |
| // if the opaque shared pointer is non NULL, then we need to update all "if | |
| // (m_opaque_sp)" code in this file. | |
| return m_opaque_sp.get() != nullptr && m_opaque_sp->IsValid() && | |
| m_opaque_sp->GetRootSP().get() != nullptr; | |
| } | |
| void SBValue::Clear() { | |
| LLDB_INSTRUMENT_VA(this); | |
| m_opaque_sp.reset(); | |
| } | |
| SBError SBValue::GetError() { | |
| LLDB_INSTRUMENT_VA(this); | |
| SBError sb_error; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) | |
| sb_error.SetError(value_sp->GetError().Clone()); | |
| else | |
| sb_error = Status::FromErrorStringWithFormat("error: %s", | |
| locker.GetError().AsCString()); | |
| return sb_error; | |
| } | |
| user_id_t SBValue::GetID() { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) | |
| return value_sp->GetID(); | |
| return LLDB_INVALID_UID; | |
| } | |
| const char *SBValue::GetName() { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (!value_sp) | |
| return nullptr; | |
| return value_sp->GetName().GetCString(); | |
| } | |
| const char *SBValue::GetTypeName() { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (!value_sp) | |
| return nullptr; | |
| return value_sp->GetQualifiedTypeName().GetCString(); | |
| } | |
| const char *SBValue::GetDisplayTypeName() { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (!value_sp) | |
| return nullptr; | |
| return value_sp->GetDisplayTypeName().GetCString(); | |
| } | |
| size_t SBValue::GetByteSize() { | |
| LLDB_INSTRUMENT_VA(this); | |
| size_t result = 0; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| result = llvm::expectedToOptional(value_sp->GetByteSize()).value_or(0); | |
| } | |
| return result; | |
| } | |
| bool SBValue::IsInScope() { | |
| LLDB_INSTRUMENT_VA(this); | |
| bool result = false; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| result = value_sp->IsInScope(); | |
| } | |
| return result; | |
| } | |
| const char *SBValue::GetValue() { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (!value_sp) | |
| return nullptr; | |
| return ConstString(value_sp->GetValueAsCString()).GetCString(); | |
| } | |
| ValueType SBValue::GetValueType() { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueType result = eValueTypeInvalid; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) | |
| result = value_sp->GetValueType(); | |
| return result; | |
| } | |
| const char *SBValue::GetObjectDescription() { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (!value_sp) | |
| return nullptr; | |
| llvm::Expected<std::string> str = value_sp->GetObjectDescription(); | |
| if (!str) { | |
| llvm::consumeError(str.takeError()); | |
| return nullptr; | |
| } | |
| return ConstString(*str).AsCString(nullptr); | |
| } | |
| SBType SBValue::GetType() { | |
| LLDB_INSTRUMENT_VA(this); | |
| SBType sb_type; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| TypeImplSP type_sp; | |
| if (value_sp) { | |
| type_sp = std::make_shared<TypeImpl>(value_sp->GetTypeImpl()); | |
| sb_type.SetSP(type_sp); | |
| } | |
| return sb_type; | |
| } | |
| bool SBValue::GetValueDidChange() { | |
| LLDB_INSTRUMENT_VA(this); | |
| bool result = false; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| if (value_sp->UpdateValueIfNeeded(false)) | |
| result = value_sp->GetValueDidChange(); | |
| } | |
| return result; | |
| } | |
| const char *SBValue::GetSummary() { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (!value_sp) | |
| return nullptr; | |
| return ConstString(value_sp->GetSummaryAsCString()).GetCString(); | |
| } | |
| const char *SBValue::GetSummary(lldb::SBStream &stream, | |
| lldb::SBTypeSummaryOptions &options) { | |
| LLDB_INSTRUMENT_VA(this, stream, options); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| std::string buffer; | |
| if (value_sp->GetSummaryAsCString(buffer, options.ref()) && !buffer.empty()) | |
| stream.Printf("%s", buffer.c_str()); | |
| } | |
| return ConstString(stream.GetData()).GetCString(); | |
| } | |
| const char *SBValue::GetLocation() { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (!value_sp) | |
| return nullptr; | |
| return ConstString(value_sp->GetLocationAsCString()).GetCString(); | |
| } | |
| // Deprecated - use the one that takes an lldb::SBError | |
| bool SBValue::SetValueFromCString(const char *value_str) { | |
| LLDB_INSTRUMENT_VA(this, value_str); | |
| lldb::SBError dummy; | |
| return SetValueFromCString(value_str, dummy); | |
| } | |
| bool SBValue::SetValueFromCString(const char *value_str, lldb::SBError &error) { | |
| LLDB_INSTRUMENT_VA(this, value_str, error); | |
| bool success = false; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| success = value_sp->SetValueFromCString(value_str, error.ref()); | |
| } else | |
| error = Status::FromErrorStringWithFormat("Could not get value: %s", | |
| locker.GetError().AsCString()); | |
| return success; | |
| } | |
| bool SBValue::CanSetValue() { | |
| LLDB_INSTRUMENT_VA(this); | |
| return CanSet().Success(); | |
| } | |
| lldb::SBError SBValue::CanSet() { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (!value_sp) | |
| return SBError(Status::FromErrorStringWithFormat( | |
| "Could not get value: %s", locker.GetError().AsCString())); | |
| return SBError(Status::FromError(value_sp->CanSetValue())); | |
| } | |
| lldb::SBTypeFormat SBValue::GetTypeFormat() { | |
| LLDB_INSTRUMENT_VA(this); | |
| lldb::SBTypeFormat format; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| if (value_sp->UpdateValueIfNeeded(true)) { | |
| lldb::TypeFormatImplSP format_sp = value_sp->GetValueFormat(); | |
| if (format_sp) | |
| format.SetSP(format_sp); | |
| } | |
| } | |
| return format; | |
| } | |
| lldb::SBTypeSummary SBValue::GetTypeSummary() { | |
| LLDB_INSTRUMENT_VA(this); | |
| lldb::SBTypeSummary summary; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| if (value_sp->UpdateValueIfNeeded(true)) { | |
| lldb::TypeSummaryImplSP summary_sp = value_sp->GetSummaryFormat(); | |
| if (summary_sp) | |
| summary.SetSP(summary_sp); | |
| } | |
| } | |
| return summary; | |
| } | |
| lldb::SBTypeFilter SBValue::GetTypeFilter() { | |
| LLDB_INSTRUMENT_VA(this); | |
| lldb::SBTypeFilter filter; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| if (value_sp->UpdateValueIfNeeded(true)) { | |
| lldb::SyntheticChildrenSP synthetic_sp = value_sp->GetSyntheticChildren(); | |
| if (synthetic_sp && !synthetic_sp->IsScripted()) { | |
| TypeFilterImplSP filter_sp = | |
| std::static_pointer_cast<TypeFilterImpl>(synthetic_sp); | |
| filter.SetSP(filter_sp); | |
| } | |
| } | |
| } | |
| return filter; | |
| } | |
| lldb::SBTypeSynthetic SBValue::GetTypeSynthetic() { | |
| LLDB_INSTRUMENT_VA(this); | |
| lldb::SBTypeSynthetic synthetic; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| if (value_sp->UpdateValueIfNeeded(true)) { | |
| lldb::SyntheticChildrenSP children_sp = value_sp->GetSyntheticChildren(); | |
| if (children_sp && children_sp->IsScripted()) { | |
| ScriptedSyntheticChildrenSP synth_sp = | |
| std::static_pointer_cast<ScriptedSyntheticChildren>(children_sp); | |
| synthetic.SetSP(synth_sp); | |
| } | |
| } | |
| } | |
| return synthetic; | |
| } | |
| void SBValue::SetTypeSynthetic(lldb::SBTypeSynthetic &synthetic) { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| lldb::ScriptedSyntheticChildrenSP synthetic_sp(synthetic.GetSP()); | |
| if (value_sp) { | |
| value_sp->SetSyntheticChildrenOverride(synthetic_sp); | |
| } | |
| } | |
| lldb::SBScriptObject SBValue::GetTypeSyntheticImplementation() { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (!value_sp) | |
| return lldb::SBScriptObject(nullptr, eScriptLanguageDefault); | |
| auto frontend = value_sp->GetSyntheticChildrenFrontEnd(); | |
| if (!frontend) | |
| return lldb::SBScriptObject(nullptr, eScriptLanguageDefault); | |
| return lldb::SBScriptObject(frontend->GetImplementation(), | |
| eScriptLanguageDefault); | |
| } | |
| lldb::SBValue SBValue::CreateChildAtOffset(const char *name, uint32_t offset, | |
| SBType type) { | |
| LLDB_INSTRUMENT_VA(this, name, offset, type); | |
| lldb::SBValue sb_value; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| lldb::ValueObjectSP new_value_sp; | |
| if (value_sp) { | |
| TypeImplSP type_sp(type.GetSP()); | |
| if (type.IsValid()) { | |
| sb_value.SetSP(value_sp->GetSyntheticChildAtOffset( | |
| offset, type_sp->GetCompilerType(false), true), | |
| GetPreferDynamicValue(), GetPreferSyntheticValue(), name); | |
| } | |
| } | |
| return sb_value; | |
| } | |
| lldb::SBValue SBValue::Cast(SBType type) { | |
| LLDB_INSTRUMENT_VA(this, type); | |
| lldb::SBValue sb_value; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| TypeImplSP type_sp(type.GetSP()); | |
| if (value_sp && type_sp) | |
| sb_value.SetSP(value_sp->Cast(type_sp->GetCompilerType(false)), | |
| GetPreferDynamicValue(), GetPreferSyntheticValue()); | |
| return sb_value; | |
| } | |
| lldb::SBValue SBValue::CreateValueFromExpression(const char *name, | |
| const char *expression) { | |
| LLDB_INSTRUMENT_VA(this, name, expression); | |
| SBExpressionOptions options; | |
| options.ref().SetKeepInMemory(true); | |
| TargetSP target_sp(GetTarget().GetSP()); | |
| if (target_sp) | |
| options.SetTryDILFirst(target_sp->GetUseDILForCreatingValues()); | |
| return CreateValueFromExpression(name, expression, options); | |
| } | |
| lldb::SBValue SBValue::CreateValueFromExpression(const char *name, | |
| const char *expression, | |
| SBExpressionOptions &options) { | |
| LLDB_INSTRUMENT_VA(this, name, expression, options); | |
| lldb::ValueObjectSP new_value_sp; | |
| StackFrameSP frame_sp(GetFrame().GetFrameSP()); | |
| TargetSP target_sp(GetTarget().GetSP()); | |
| // If enabled, attempt to use DIL to evaluate the expression. | |
| bool DIL_success = false; | |
| if (frame_sp && target_sp) { | |
| if (options.GetTryDILFirst()) { | |
| Status error; | |
| uint32_t expr_path_options = | |
| StackFrame::eExpressionPathOptionCheckPtrVsMember | | |
| StackFrame::eExpressionPathOptionsAllowDirectIVarAccess; | |
| lldb::VariableSP var_sp; | |
| new_value_sp = frame_sp->GetValueForVariableExpressionPath( | |
| expression, options.GetFetchDynamicValue(), expr_path_options, var_sp, | |
| error); | |
| DIL_success = new_value_sp && new_value_sp->GetError().Success(); | |
| } | |
| } | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| // Fall back to full expression evaluation if DIL did not succeed. | |
| if (!DIL_success && value_sp) { | |
| ExecutionContext exe_ctx(value_sp->GetExecutionContextRef()); | |
| new_value_sp = value_sp->CreateChildValueObjectFromExpression( | |
| name, expression, exe_ctx, options.ref()); | |
| } | |
| if (new_value_sp) | |
| new_value_sp->SetName(name); | |
| lldb::SBValue sb_value; | |
| sb_value.SetSP(new_value_sp); | |
| Log *log = GetLog(LLDBLog::Expressions); | |
| if (new_value_sp && new_value_sp->GetError().Success()) | |
| LLDB_LOGF(log, | |
| "** [SBValue::CreateValueFromExpression] Expression result: " | |
| "(%s) %s = %s (evaluated by: %s) **", | |
| new_value_sp->GetTypeName().GetCString(), | |
| new_value_sp->GetName().GetCString(), | |
| new_value_sp->GetValueAsCString(), | |
| DIL_success ? "DIL" : "UserExpression"); | |
| else | |
| LLDB_LOGF(log, | |
| "** [SBValue::CreateValueFromExpression] Expression evaluation " | |
| "failed: %s **", | |
| new_value_sp ? new_value_sp->GetError().AsCString() | |
| : "unknown error"); | |
| return sb_value; | |
| } | |
| lldb::SBValue SBValue::CreateValueFromAddress(const char *name, | |
| lldb::addr_t address, | |
| SBType sb_type) { | |
| LLDB_INSTRUMENT_VA(this, name, address, sb_type); | |
| lldb::SBValue sb_value; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| lldb::ValueObjectSP new_value_sp; | |
| lldb::TypeImplSP type_impl_sp(sb_type.GetSP()); | |
| if (value_sp && type_impl_sp) { | |
| CompilerType ast_type(type_impl_sp->GetCompilerType(true)); | |
| ExecutionContext exe_ctx(value_sp->GetExecutionContextRef()); | |
| new_value_sp = value_sp->CreateChildValueObjectFromAddress( | |
| name, address, exe_ctx, ast_type); | |
| } | |
| sb_value.SetSP(new_value_sp); | |
| return sb_value; | |
| } | |
| lldb::SBValue SBValue::CreateValueFromData(const char *name, SBData data, | |
| SBType sb_type) { | |
| LLDB_INSTRUMENT_VA(this, name, data, sb_type); | |
| lldb::SBValue sb_value; | |
| lldb::ValueObjectSP new_value_sp; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| lldb::TypeImplSP type_impl_sp(sb_type.GetSP()); | |
| if (value_sp && type_impl_sp) { | |
| ExecutionContext exe_ctx(value_sp->GetExecutionContextRef()); | |
| new_value_sp = value_sp->CreateChildValueObjectFromData( | |
| name, **data, exe_ctx, type_impl_sp->GetCompilerType(true)); | |
| new_value_sp->SetAddressTypeOfChildren(eAddressTypeLoad); | |
| } | |
| sb_value.SetSP(new_value_sp); | |
| return sb_value; | |
| } | |
| lldb::SBValue SBValue::CreateBoolValue(const char *name, bool value) { | |
| LLDB_INSTRUMENT_VA(this, name); | |
| lldb::SBValue sb_value; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| auto get_new_value = [&]() -> lldb::ValueObjectSP { | |
| if (!value_sp) | |
| return {}; | |
| lldb::TargetSP target_sp = value_sp->GetTargetSP(); | |
| if (!target_sp) | |
| return {}; | |
| lldb::LanguageType language = lldb::eLanguageTypeC; | |
| ExecutionContext exe_ctx(value_sp->GetExecutionContextRef()); | |
| if (StackFrame *frame = exe_ctx.GetFramePtr()) | |
| language = frame->GuessLanguage().AsLanguageType(); | |
| auto type_system_or_err = | |
| target_sp->GetScratchTypeSystemForLanguage(language); | |
| if (!type_system_or_err) { | |
| LLDB_LOG_ERROR(GetLog(LLDBLog::Types), type_system_or_err.takeError(), | |
| "cannot get a type system: {0}"); | |
| return {}; | |
| } | |
| return value_sp->CreateChildValueObjectFromBool( | |
| exe_ctx, *type_system_or_err, value, name); | |
| }; | |
| sb_value.SetSP(get_new_value()); | |
| return sb_value; | |
| } | |
| SBValue SBValue::GetChildAtIndex(uint32_t idx) { | |
| LLDB_INSTRUMENT_VA(this, idx); | |
| lldb::DynamicValueType use_dynamic = eNoDynamicValues; | |
| TargetSP target_sp; | |
| if (m_opaque_sp) | |
| target_sp = m_opaque_sp->GetTargetSP(); | |
| if (target_sp) | |
| use_dynamic = target_sp->GetPreferDynamicValue(); | |
| return GetChildAtIndex(idx, use_dynamic, /*treat_as_array=*/false); | |
| } | |
| SBValue SBValue::GetChildAtIndex(uint32_t idx, | |
| lldb::DynamicValueType use_dynamic, | |
| bool treat_as_array) { | |
| LLDB_INSTRUMENT_VA(this, idx, use_dynamic, treat_as_array); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| lldb::ValueObjectSP child_sp; | |
| if (value_sp) { | |
| const bool can_create = true; | |
| if (treat_as_array && | |
| (value_sp->IsPointerType() || value_sp->IsArrayType())) | |
| child_sp = value_sp->GetSyntheticArrayMember(idx, can_create); | |
| else | |
| child_sp = value_sp->GetChildAtIndex(idx); | |
| } | |
| SBValue sb_value; | |
| sb_value.SetSP(child_sp, use_dynamic, GetPreferSyntheticValue()); | |
| return sb_value; | |
| } | |
| uint32_t SBValue::GetIndexOfChildWithName(const char *name) { | |
| LLDB_INSTRUMENT_VA(this, name); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| if (auto idx_or_err = value_sp->GetIndexOfChildWithName(name)) | |
| return *idx_or_err; | |
| else | |
| LLDB_LOG_ERROR(GetLog(LLDBLog::API), idx_or_err.takeError(), "{0}"); | |
| } | |
| return UINT32_MAX; | |
| } | |
| SBValue SBValue::GetChildMemberWithName(const char *name) { | |
| LLDB_INSTRUMENT_VA(this, name); | |
| lldb::DynamicValueType use_dynamic_value = eNoDynamicValues; | |
| TargetSP target_sp; | |
| if (m_opaque_sp) | |
| target_sp = m_opaque_sp->GetTargetSP(); | |
| if (target_sp) | |
| use_dynamic_value = target_sp->GetPreferDynamicValue(); | |
| return GetChildMemberWithName(name, use_dynamic_value); | |
| } | |
| SBValue | |
| SBValue::GetChildMemberWithName(const char *name, | |
| lldb::DynamicValueType use_dynamic_value) { | |
| LLDB_INSTRUMENT_VA(this, name, use_dynamic_value); | |
| lldb::ValueObjectSP child_sp; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| child_sp = value_sp->GetChildMemberWithName(name); | |
| } | |
| SBValue sb_value; | |
| sb_value.SetSP(child_sp, use_dynamic_value, GetPreferSyntheticValue()); | |
| return sb_value; | |
| } | |
| lldb::SBValue SBValue::GetParent() { | |
| LLDB_INSTRUMENT_VA(this); | |
| SBValue sb_value; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| ValueObject *parent = value_sp->GetParent(); | |
| if (parent) | |
| sb_value.SetSP(parent->GetSP()); | |
| } | |
| return sb_value; | |
| } | |
| lldb::SBValue SBValue::GetDynamicValue(lldb::DynamicValueType use_dynamic) { | |
| LLDB_INSTRUMENT_VA(this, use_dynamic); | |
| SBValue value_sb; | |
| if (IsValid()) { | |
| ValueImplSP proxy_sp(new ValueImpl(m_opaque_sp->GetRootSP(), use_dynamic, | |
| m_opaque_sp->GetUseSynthetic())); | |
| value_sb.SetSP(proxy_sp); | |
| } | |
| return value_sb; | |
| } | |
| lldb::SBValue SBValue::GetStaticValue() { | |
| LLDB_INSTRUMENT_VA(this); | |
| SBValue value_sb; | |
| if (IsValid()) { | |
| ValueImplSP proxy_sp(new ValueImpl(m_opaque_sp->GetRootSP(), | |
| eNoDynamicValues, | |
| m_opaque_sp->GetUseSynthetic())); | |
| value_sb.SetSP(proxy_sp); | |
| } | |
| return value_sb; | |
| } | |
| lldb::SBValue SBValue::GetNonSyntheticValue() { | |
| LLDB_INSTRUMENT_VA(this); | |
| SBValue value_sb; | |
| if (IsValid()) { | |
| ValueImplSP proxy_sp(new ValueImpl(m_opaque_sp->GetRootSP(), | |
| m_opaque_sp->GetUseDynamic(), false)); | |
| value_sb.SetSP(proxy_sp); | |
| } | |
| return value_sb; | |
| } | |
| lldb::SBValue SBValue::GetSyntheticValue() { | |
| LLDB_INSTRUMENT_VA(this); | |
| SBValue value_sb; | |
| if (IsValid()) { | |
| ValueImplSP proxy_sp(new ValueImpl(m_opaque_sp->GetRootSP(), | |
| m_opaque_sp->GetUseDynamic(), true)); | |
| value_sb.SetSP(proxy_sp); | |
| if (!value_sb.IsSynthetic()) { | |
| return {}; | |
| } | |
| } | |
| return value_sb; | |
| } | |
| lldb::DynamicValueType SBValue::GetPreferDynamicValue() { | |
| LLDB_INSTRUMENT_VA(this); | |
| if (!IsValid()) | |
| return eNoDynamicValues; | |
| return m_opaque_sp->GetUseDynamic(); | |
| } | |
| void SBValue::SetPreferDynamicValue(lldb::DynamicValueType use_dynamic) { | |
| LLDB_INSTRUMENT_VA(this, use_dynamic); | |
| if (IsValid()) | |
| return m_opaque_sp->SetUseDynamic(use_dynamic); | |
| } | |
| bool SBValue::GetPreferSyntheticValue() { | |
| LLDB_INSTRUMENT_VA(this); | |
| if (!IsValid()) | |
| return false; | |
| return m_opaque_sp->GetUseSynthetic(); | |
| } | |
| void SBValue::SetPreferSyntheticValue(bool use_synthetic) { | |
| LLDB_INSTRUMENT_VA(this, use_synthetic); | |
| if (IsValid()) | |
| return m_opaque_sp->SetUseSynthetic(use_synthetic); | |
| } | |
| bool SBValue::IsDynamic() { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) | |
| return value_sp->IsDynamic(); | |
| return false; | |
| } | |
| bool SBValue::IsSynthetic() { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) | |
| return value_sp->IsSynthetic(); | |
| return false; | |
| } | |
| bool SBValue::IsSyntheticChildrenGenerated() { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) | |
| return value_sp->IsSyntheticChildrenGenerated(); | |
| return false; | |
| } | |
| void SBValue::SetSyntheticChildrenGenerated(bool is) { | |
| LLDB_INSTRUMENT_VA(this, is); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) | |
| return value_sp->SetSyntheticChildrenGenerated(is); | |
| } | |
| lldb::SBValue SBValue::GetValueForExpressionPath(const char *expr_path) { | |
| LLDB_INSTRUMENT_VA(this, expr_path); | |
| lldb::ValueObjectSP child_sp; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| // using default values for all the fancy options, just do it if you can | |
| child_sp = value_sp->GetValueForExpressionPath(expr_path); | |
| } | |
| SBValue sb_value; | |
| sb_value.SetSP(child_sp, GetPreferDynamicValue(), GetPreferSyntheticValue()); | |
| return sb_value; | |
| } | |
| int64_t SBValue::GetValueAsSigned(SBError &error, int64_t fail_value) { | |
| LLDB_INSTRUMENT_VA(this, error, fail_value); | |
| error.Clear(); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| bool success = true; | |
| uint64_t ret_val = fail_value; | |
| ret_val = value_sp->GetValueAsSigned(fail_value, &success); | |
| if (!success) | |
| error = Status::FromErrorString("could not resolve value"); | |
| return ret_val; | |
| } else | |
| error = Status::FromErrorStringWithFormat("could not get SBValue: %s", | |
| locker.GetError().AsCString()); | |
| return fail_value; | |
| } | |
| uint64_t SBValue::GetValueAsUnsigned(SBError &error, uint64_t fail_value) { | |
| LLDB_INSTRUMENT_VA(this, error, fail_value); | |
| error.Clear(); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| bool success = true; | |
| uint64_t ret_val = fail_value; | |
| ret_val = value_sp->GetValueAsUnsigned(fail_value, &success); | |
| if (!success) | |
| error = Status::FromErrorString("could not resolve value"); | |
| return ret_val; | |
| } else | |
| error = Status::FromErrorStringWithFormat("could not get SBValue: %s", | |
| locker.GetError().AsCString()); | |
| return fail_value; | |
| } | |
| int64_t SBValue::GetValueAsSigned(int64_t fail_value) { | |
| LLDB_INSTRUMENT_VA(this, fail_value); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| return value_sp->GetValueAsSigned(fail_value); | |
| } | |
| return fail_value; | |
| } | |
| uint64_t SBValue::GetValueAsUnsigned(uint64_t fail_value) { | |
| LLDB_INSTRUMENT_VA(this, fail_value); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| return value_sp->GetValueAsUnsigned(fail_value); | |
| } | |
| return fail_value; | |
| } | |
| lldb::addr_t SBValue::GetValueAsAddress() { | |
| addr_t fail_value = LLDB_INVALID_ADDRESS; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| bool success = true; | |
| uint64_t ret_val = fail_value; | |
| ret_val = value_sp->GetValueAsUnsigned(fail_value, &success); | |
| if (!success) | |
| return fail_value; | |
| ProcessSP process_sp = m_opaque_sp->GetProcessSP(); | |
| if (!process_sp) | |
| return ret_val; | |
| return process_sp->FixDataAddress(ret_val); | |
| } | |
| return fail_value; | |
| } | |
| bool SBValue::MightHaveChildren() { | |
| LLDB_INSTRUMENT_VA(this); | |
| bool has_children = false; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) | |
| has_children = value_sp->MightHaveChildren(); | |
| return has_children; | |
| } | |
| bool SBValue::IsRuntimeSupportValue() { | |
| LLDB_INSTRUMENT_VA(this); | |
| bool is_support = false; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) | |
| is_support = value_sp->IsRuntimeSupportValue(); | |
| return is_support; | |
| } | |
| uint32_t SBValue::GetNumChildren() { | |
| LLDB_INSTRUMENT_VA(this); | |
| return GetNumChildren(UINT32_MAX); | |
| } | |
| uint32_t SBValue::GetNumChildren(uint32_t max) { | |
| LLDB_INSTRUMENT_VA(this, max); | |
| uint32_t num_children = 0; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) | |
| num_children = value_sp->GetNumChildrenIgnoringErrors(max); | |
| return num_children; | |
| } | |
| SBValue SBValue::Dereference() { | |
| LLDB_INSTRUMENT_VA(this); | |
| SBValue sb_value; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| Status error; | |
| sb_value = value_sp->Dereference(error); | |
| } | |
| return sb_value; | |
| } | |
| // Deprecated - please use GetType().IsPointerType() instead. | |
| bool SBValue::TypeIsPointerType() { | |
| LLDB_INSTRUMENT_VA(this); | |
| return GetType().IsPointerType(); | |
| } | |
| void *SBValue::GetOpaqueType() { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) | |
| return value_sp->GetCompilerType().GetOpaqueQualType(); | |
| return nullptr; | |
| } | |
| lldb::SBTarget SBValue::GetTarget() { | |
| LLDB_INSTRUMENT_VA(this); | |
| SBTarget sb_target; | |
| TargetSP target_sp; | |
| if (m_opaque_sp) { | |
| target_sp = m_opaque_sp->GetTargetSP(); | |
| sb_target.SetSP(target_sp); | |
| } | |
| return sb_target; | |
| } | |
| lldb::SBProcess SBValue::GetProcess() { | |
| LLDB_INSTRUMENT_VA(this); | |
| SBProcess sb_process; | |
| ProcessSP process_sp; | |
| if (m_opaque_sp) { | |
| process_sp = m_opaque_sp->GetProcessSP(); | |
| sb_process.SetSP(process_sp); | |
| } | |
| return sb_process; | |
| } | |
| lldb::SBThread SBValue::GetThread() { | |
| LLDB_INSTRUMENT_VA(this); | |
| SBThread sb_thread; | |
| ThreadSP thread_sp; | |
| if (m_opaque_sp) { | |
| thread_sp = m_opaque_sp->GetThreadSP(); | |
| sb_thread.SetThread(thread_sp); | |
| } | |
| return sb_thread; | |
| } | |
| lldb::SBFrame SBValue::GetFrame() { | |
| LLDB_INSTRUMENT_VA(this); | |
| SBFrame sb_frame; | |
| StackFrameSP frame_sp; | |
| if (m_opaque_sp) { | |
| frame_sp = m_opaque_sp->GetFrameSP(); | |
| sb_frame.SetFrameSP(frame_sp); | |
| } | |
| return sb_frame; | |
| } | |
| lldb::ValueObjectSP SBValue::GetSP(ValueLocker &locker) const { | |
| // IsValid means that the SBValue has a value in it. But that's not the | |
| // only time that ValueObjects are useful. We also want to return the value | |
| // if there's an error state in it. | |
| if (!m_opaque_sp || (!m_opaque_sp->IsValid() && | |
| (m_opaque_sp->GetRootSP() && | |
| !m_opaque_sp->GetRootSP()->GetError().Fail()))) { | |
| locker.GetError() = Status::FromErrorString("No value"); | |
| return ValueObjectSP(); | |
| } | |
| return locker.GetLockedSP(*m_opaque_sp.get()); | |
| } | |
| lldb::ValueObjectSP SBValue::GetSP() const { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| return GetSP(locker); | |
| } | |
| void SBValue::SetSP(ValueImplSP impl_sp) { m_opaque_sp = impl_sp; } | |
| void SBValue::SetSP(const lldb::ValueObjectSP &sp) { | |
| if (sp) { | |
| lldb::TargetSP target_sp(sp->GetTargetSP()); | |
| if (target_sp) { | |
| lldb::DynamicValueType use_dynamic = target_sp->GetPreferDynamicValue(); | |
| bool use_synthetic = | |
| target_sp->TargetProperties::GetEnableSyntheticValue(); | |
| m_opaque_sp = std::make_shared<ValueImpl>(sp, use_dynamic, use_synthetic); | |
| } else | |
| m_opaque_sp = std::make_shared<ValueImpl>(sp, eNoDynamicValues, true); | |
| } else | |
| m_opaque_sp = std::make_shared<ValueImpl>(sp, eNoDynamicValues, false); | |
| } | |
| void SBValue::SetSP(const lldb::ValueObjectSP &sp, | |
| lldb::DynamicValueType use_dynamic) { | |
| if (sp) { | |
| lldb::TargetSP target_sp(sp->GetTargetSP()); | |
| if (target_sp) { | |
| bool use_synthetic = | |
| target_sp->TargetProperties::GetEnableSyntheticValue(); | |
| SetSP(sp, use_dynamic, use_synthetic); | |
| } else | |
| SetSP(sp, use_dynamic, true); | |
| } else | |
| SetSP(sp, use_dynamic, false); | |
| } | |
| void SBValue::SetSP(const lldb::ValueObjectSP &sp, bool use_synthetic) { | |
| if (sp) { | |
| lldb::TargetSP target_sp(sp->GetTargetSP()); | |
| if (target_sp) { | |
| lldb::DynamicValueType use_dynamic = target_sp->GetPreferDynamicValue(); | |
| SetSP(sp, use_dynamic, use_synthetic); | |
| } else | |
| SetSP(sp, eNoDynamicValues, use_synthetic); | |
| } else | |
| SetSP(sp, eNoDynamicValues, use_synthetic); | |
| } | |
| void SBValue::SetSP(const lldb::ValueObjectSP &sp, | |
| lldb::DynamicValueType use_dynamic, bool use_synthetic) { | |
| m_opaque_sp = std::make_shared<ValueImpl>(sp, use_dynamic, use_synthetic); | |
| } | |
| void SBValue::SetSP(const lldb::ValueObjectSP &sp, | |
| lldb::DynamicValueType use_dynamic, bool use_synthetic, | |
| const char *name) { | |
| m_opaque_sp = | |
| std::make_shared<ValueImpl>(sp, use_dynamic, use_synthetic, name); | |
| } | |
| bool SBValue::GetExpressionPath(SBStream &description) { | |
| LLDB_INSTRUMENT_VA(this, description); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| value_sp->GetExpressionPath(description.ref()); | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool SBValue::GetExpressionPath(SBStream &description, | |
| bool qualify_cxx_base_classes) { | |
| LLDB_INSTRUMENT_VA(this, description, qualify_cxx_base_classes); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| value_sp->GetExpressionPath(description.ref()); | |
| return true; | |
| } | |
| return false; | |
| } | |
| lldb::SBValue SBValue::EvaluateExpression(const char *expr) const { | |
| LLDB_INSTRUMENT_VA(this, expr); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (!value_sp) | |
| return SBValue(); | |
| lldb::TargetSP target_sp = value_sp->GetTargetSP(); | |
| if (!target_sp) | |
| return SBValue(); | |
| lldb::SBExpressionOptions options; | |
| options.SetFetchDynamicValue(target_sp->GetPreferDynamicValue()); | |
| options.SetUnwindOnError(true); | |
| options.SetIgnoreBreakpoints(true); | |
| return EvaluateExpression(expr, options, nullptr); | |
| } | |
| lldb::SBValue | |
| SBValue::EvaluateExpression(const char *expr, | |
| const SBExpressionOptions &options) const { | |
| LLDB_INSTRUMENT_VA(this, expr, options); | |
| return EvaluateExpression(expr, options, nullptr); | |
| } | |
| lldb::SBValue SBValue::EvaluateExpression(const char *expr, | |
| const SBExpressionOptions &options, | |
| const char *name) const { | |
| LLDB_INSTRUMENT_VA(this, expr, options, name); | |
| if (!expr || expr[0] == '\0') { | |
| return SBValue(); | |
| } | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (!value_sp) { | |
| return SBValue(); | |
| } | |
| lldb::TargetSP target_sp = value_sp->GetTargetSP(); | |
| if (!target_sp) { | |
| return SBValue(); | |
| } | |
| TargetAPIMutex api_lock = target_sp->GetAPIMutex(); | |
| std::lock_guard<TargetAPIMutex> guard(api_lock); | |
| ExecutionContext exe_ctx(target_sp.get()); | |
| StackFrame *frame = exe_ctx.GetFramePtr(); | |
| if (!frame) { | |
| return SBValue(); | |
| } | |
| ValueObjectSP res_val_sp; | |
| target_sp->EvaluateExpression(expr, frame, res_val_sp, options.ref(), nullptr, | |
| value_sp.get()); | |
| if (name) | |
| res_val_sp->SetName(name); | |
| SBValue result; | |
| result.SetSP(res_val_sp, options.GetFetchDynamicValue()); | |
| return result; | |
| } | |
| bool SBValue::GetDescription(SBStream &description) { | |
| LLDB_INSTRUMENT_VA(this, description); | |
| return GetDescription(description, eDescriptionLevelFull); | |
| } | |
| static DumpValueObjectOptions | |
| GetDumpOptions(lldb::DescriptionLevel description_level, | |
| lldb::DynamicValueType dyn, bool use_synthetic) { | |
| DumpValueObjectOptions options; | |
| switch (description_level) { | |
| case eDescriptionLevelInitial: | |
| return options; | |
| case eDescriptionLevelBrief: | |
| options.SetAllowOnelinerMode(true); | |
| options.SetHideRootName(true); | |
| options.SetHideRootType(true); | |
| break; | |
| case eDescriptionLevelVerbose: | |
| options.SetShowTypes(true); | |
| options.SetShowLocation(true); | |
| break; | |
| default: | |
| break; | |
| } | |
| options.SetUseDynamicType(dyn); | |
| options.SetUseSyntheticValue(use_synthetic); | |
| return options; | |
| } | |
| bool SBValue::GetDescription(SBStream &description, | |
| lldb::DescriptionLevel description_level) { | |
| LLDB_INSTRUMENT_VA(this, description, description_level); | |
| Stream &strm = description.ref(); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| const DumpValueObjectOptions options = | |
| GetDumpOptions(description_level, m_opaque_sp->GetUseDynamic(), | |
| m_opaque_sp->GetUseSynthetic()); | |
| if (llvm::Error error = value_sp->Dump(strm, options)) { | |
| strm << "error: " << toString(std::move(error)); | |
| return false; | |
| } | |
| } else { | |
| strm.PutCString("No value"); | |
| } | |
| return true; | |
| } | |
| lldb::Format SBValue::GetFormat() { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) | |
| return value_sp->GetFormat(); | |
| return eFormatDefault; | |
| } | |
| void SBValue::SetFormat(lldb::Format format) { | |
| LLDB_INSTRUMENT_VA(this, format); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) | |
| value_sp->SetFormat(format); | |
| } | |
| lldb::SBValue SBValue::AddressOf() { | |
| LLDB_INSTRUMENT_VA(this); | |
| SBValue sb_value; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| Status error; | |
| sb_value.SetSP(value_sp->AddressOf(error), GetPreferDynamicValue(), | |
| GetPreferSyntheticValue()); | |
| } | |
| return sb_value; | |
| } | |
| lldb::addr_t SBValue::GetLoadAddress() { | |
| LLDB_INSTRUMENT_VA(this); | |
| lldb::addr_t value = LLDB_INVALID_ADDRESS; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) | |
| return value_sp->GetLoadAddress(); | |
| return value; | |
| } | |
| lldb::SBAddress SBValue::GetAddress() { | |
| LLDB_INSTRUMENT_VA(this); | |
| Address addr; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| TargetSP target_sp(value_sp->GetTargetSP()); | |
| if (target_sp) { | |
| auto [value, addr_type] = | |
| value_sp->GetAddressOf(/*scalar_is_load_address=*/true); | |
| if (addr_type == eAddressTypeFile) { | |
| ModuleSP module_sp(value_sp->GetModule()); | |
| if (module_sp) | |
| module_sp->ResolveFileAddress(value, addr); | |
| } else if (addr_type == eAddressTypeLoad) { | |
| // no need to check the return value on this.. if it can actually do | |
| // the resolve addr will be in the form (section,offset), otherwise it | |
| // will simply be returned as (NULL, value) | |
| addr.SetLoadAddress(value, target_sp.get()); | |
| } | |
| } | |
| } | |
| return SBAddress(addr); | |
| } | |
| lldb::SBData SBValue::GetPointeeData(uint32_t item_idx, uint32_t item_count) { | |
| LLDB_INSTRUMENT_VA(this, item_idx, item_count); | |
| lldb::SBData sb_data; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| TargetSP target_sp(value_sp->GetTargetSP()); | |
| if (target_sp) { | |
| DataExtractorSP data_sp(new DataExtractor()); | |
| value_sp->GetPointeeData(*data_sp, item_idx, item_count); | |
| if (data_sp->GetByteSize() > 0) | |
| *sb_data = data_sp; | |
| } | |
| } | |
| return sb_data; | |
| } | |
| lldb::SBData SBValue::GetData() { | |
| LLDB_INSTRUMENT_VA(this); | |
| lldb::SBData sb_data; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) { | |
| DataExtractorSP data_sp(new DataExtractor()); | |
| Status error; | |
| value_sp->GetData(*data_sp, error); | |
| if (error.Success()) | |
| *sb_data = data_sp; | |
| } | |
| return sb_data; | |
| } | |
| bool SBValue::SetData(lldb::SBData &data, SBError &error) { | |
| LLDB_INSTRUMENT_VA(this, data, error); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| bool ret = true; | |
| if (value_sp) { | |
| DataExtractor *data_extractor = data.get(); | |
| if (!data_extractor) { | |
| error = Status::FromErrorString("No data to set"); | |
| ret = false; | |
| } else { | |
| Status set_error; | |
| value_sp->SetData(*data_extractor, set_error); | |
| if (!set_error.Success()) { | |
| error = Status::FromErrorStringWithFormat("Couldn't set data: %s", | |
| set_error.AsCString()); | |
| ret = false; | |
| } | |
| } | |
| } else { | |
| error = Status::FromErrorStringWithFormat( | |
| "Couldn't set data: could not get SBValue: %s", | |
| locker.GetError().AsCString()); | |
| ret = false; | |
| } | |
| return ret; | |
| } | |
| lldb::SBValue SBValue::Clone(const char *new_name) { | |
| LLDB_INSTRUMENT_VA(this, new_name); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (value_sp) | |
| return lldb::SBValue(value_sp->Clone(new_name)); | |
| else | |
| return lldb::SBValue(); | |
| } | |
| lldb::SBDeclaration SBValue::GetDeclaration() { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| SBDeclaration decl_sb; | |
| if (value_sp) { | |
| Declaration decl; | |
| if (value_sp->GetDeclaration(decl)) | |
| decl_sb.SetDeclaration(decl); | |
| } | |
| return decl_sb; | |
| } | |
| lldb::SBWatchpoint SBValue::Watch(bool resolve_location, bool read, bool write, | |
| SBError &error) { | |
| LLDB_INSTRUMENT_VA(this, resolve_location, read, write, error); | |
| SBWatchpoint sb_watchpoint; | |
| // If the SBValue is not valid, there's no point in even trying to watch it. | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| TargetSP target_sp(GetTarget().GetSP()); | |
| if (value_sp && target_sp) { | |
| // Read and Write cannot both be false. | |
| if (!read && !write) | |
| return sb_watchpoint; | |
| // If the value is not in scope, don't try and watch and invalid value | |
| if (!IsInScope()) | |
| return sb_watchpoint; | |
| addr_t addr = GetLoadAddress(); | |
| if (addr == LLDB_INVALID_ADDRESS) | |
| return sb_watchpoint; | |
| size_t byte_size = GetByteSize(); | |
| if (byte_size == 0) | |
| return sb_watchpoint; | |
| uint32_t watch_type = 0; | |
| if (read) { | |
| watch_type |= LLDB_WATCH_TYPE_READ; | |
| // read + write, the most likely intention | |
| // is to catch all writes to this, not just | |
| // value modifications. | |
| if (write) | |
| watch_type |= LLDB_WATCH_TYPE_WRITE; | |
| } else { | |
| if (write) | |
| watch_type |= LLDB_WATCH_TYPE_MODIFY; | |
| } | |
| Status rc; | |
| CompilerType type(value_sp->GetCompilerType()); | |
| WatchpointSP watchpoint_sp = | |
| target_sp->CreateWatchpoint(addr, byte_size, &type, watch_type, rc); | |
| error.SetError(std::move(rc)); | |
| if (watchpoint_sp) { | |
| sb_watchpoint.SetSP(watchpoint_sp); | |
| Declaration decl; | |
| if (value_sp->GetDeclaration(decl)) { | |
| if (decl.GetFile()) { | |
| StreamString ss; | |
| // True to show fullpath for declaration file. | |
| decl.DumpStopContext(&ss, true); | |
| watchpoint_sp->SetDeclInfo(std::string(ss.GetString())); | |
| } | |
| } | |
| // If it is a local variable, disable the watchpoint after we leave | |
| // the current frame. If not, the watchpoint keeps firing | |
| // when a later function reuses the same stack memory. | |
| if (VariableSP var_sp = value_sp->GetVariable()) { | |
| watchpoint_sp->SetWatchVariable(true); | |
| watchpoint_sp->SetWatchSpec(value_sp->GetName().GetString()); | |
| if (var_sp->GetScope() == eValueTypeVariableLocal) { | |
| const auto &exe_ctx = value_sp->GetExecutionContextRef(); | |
| watchpoint_sp->SetupVariableWatchpointDisabler(exe_ctx.GetFrameSP()); | |
| } | |
| } | |
| } | |
| } else if (target_sp) { | |
| error = Status::FromErrorStringWithFormat("could not get SBValue: %s", | |
| locker.GetError().AsCString()); | |
| } else { | |
| error = Status::FromErrorString( | |
| "could not set watchpoint, a target is required"); | |
| } | |
| return sb_watchpoint; | |
| } | |
| // FIXME: Remove this method impl (as well as the decl in .h) once it is no | |
| // longer needed. | |
| // Backward compatibility fix in the interim. | |
| lldb::SBWatchpoint SBValue::Watch(bool resolve_location, bool read, | |
| bool write) { | |
| LLDB_INSTRUMENT_VA(this, resolve_location, read, write); | |
| SBError error; | |
| return Watch(resolve_location, read, write, error); | |
| } | |
| lldb::SBWatchpoint SBValue::WatchPointee(bool resolve_location, bool read, | |
| bool write, SBError &error) { | |
| LLDB_INSTRUMENT_VA(this, resolve_location, read, write, error); | |
| SBWatchpoint sb_watchpoint; | |
| if (IsInScope() && GetType().IsPointerType()) | |
| sb_watchpoint = Dereference().Watch(resolve_location, read, write, error); | |
| return sb_watchpoint; | |
| } | |
| lldb::SBValue SBValue::Persist() { | |
| LLDB_INSTRUMENT_VA(this); | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| SBValue persisted_sb; | |
| if (value_sp) { | |
| persisted_sb.SetSP(value_sp->Persist()); | |
| } | |
| return persisted_sb; | |
| } | |
| lldb::SBValue SBValue::GetVTable() { | |
| SBValue vtable_sb; | |
| ValueLocker locker; | |
| lldb::ValueObjectSP value_sp(GetSP(locker)); | |
| if (!value_sp) | |
| return vtable_sb; | |
| vtable_sb.SetSP(value_sp->GetVTable()); | |
| return vtable_sb; | |
| } |