diff options
Diffstat (limited to 'source/Core/ValueObject.cpp')
-rw-r--r-- | source/Core/ValueObject.cpp | 7011 |
1 files changed, 3057 insertions, 3954 deletions
diff --git a/source/Core/ValueObject.cpp b/source/Core/ValueObject.cpp index 3e0a31833ef6..fc2312d60d57 100644 --- a/source/Core/ValueObject.cpp +++ b/source/Core/ValueObject.cpp @@ -41,9 +41,9 @@ #include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/Type.h" #include "lldb/Target/ExecutionContext.h" @@ -65,2032 +65,1684 @@ static user_id_t g_value_obj_uid = 0; //---------------------------------------------------------------------- // ValueObject constructor //---------------------------------------------------------------------- -ValueObject::ValueObject (ValueObject &parent) : - UserID (++g_value_obj_uid), // Unique identifier for every value object - m_parent (&parent), - m_root (NULL), - m_update_point (parent.GetUpdatePoint ()), - m_name (), - m_data (), - m_value (), - m_error (), - m_value_str (), - m_old_value_str (), - m_location_str (), - m_summary_str (), - m_object_desc_str (), - m_validation_result(), - m_manager(parent.GetManager()), - m_children (), - m_synthetic_children (), - m_dynamic_value (NULL), - m_synthetic_value(NULL), - m_deref_valobj(NULL), - m_format (eFormatDefault), - m_last_format (eFormatDefault), - m_last_format_mgr_revision(0), - m_type_summary_sp(), - m_type_format_sp(), - m_synthetic_children_sp(), - m_type_validator_sp(), - m_user_id_of_forced_summary(), - m_address_type_of_ptr_or_ref_children(eAddressTypeInvalid), - m_value_checksum(), - m_preferred_display_language(lldb::eLanguageTypeUnknown), - m_language_flags(0), - m_value_is_valid (false), - m_value_did_change (false), - m_children_count_valid (false), - m_old_value_valid (false), - m_is_deref_of_parent (false), - m_is_array_item_for_pointer(false), - m_is_bitfield_for_scalar(false), - m_is_child_at_offset(false), - m_is_getting_summary(false), - m_did_calculate_complete_objc_class_type(false), - m_is_synthetic_children_generated(parent.m_is_synthetic_children_generated) -{ - m_manager->ManageObject(this); +ValueObject::ValueObject(ValueObject &parent) + : UserID(++g_value_obj_uid), // Unique identifier for every value object + m_parent(&parent), m_root(NULL), m_update_point(parent.GetUpdatePoint()), + m_name(), m_data(), m_value(), m_error(), m_value_str(), + m_old_value_str(), m_location_str(), m_summary_str(), m_object_desc_str(), + m_validation_result(), m_manager(parent.GetManager()), m_children(), + m_synthetic_children(), m_dynamic_value(NULL), m_synthetic_value(NULL), + m_deref_valobj(NULL), m_format(eFormatDefault), + m_last_format(eFormatDefault), m_last_format_mgr_revision(0), + m_type_summary_sp(), m_type_format_sp(), m_synthetic_children_sp(), + m_type_validator_sp(), m_user_id_of_forced_summary(), + m_address_type_of_ptr_or_ref_children(eAddressTypeInvalid), + m_value_checksum(), + m_preferred_display_language(lldb::eLanguageTypeUnknown), + m_language_flags(0), m_value_is_valid(false), m_value_did_change(false), + m_children_count_valid(false), m_old_value_valid(false), + m_is_deref_of_parent(false), m_is_array_item_for_pointer(false), + m_is_bitfield_for_scalar(false), m_is_child_at_offset(false), + m_is_getting_summary(false), + m_did_calculate_complete_objc_class_type(false), + m_is_synthetic_children_generated( + parent.m_is_synthetic_children_generated) { + m_manager->ManageObject(this); } //---------------------------------------------------------------------- // ValueObject constructor //---------------------------------------------------------------------- -ValueObject::ValueObject (ExecutionContextScope *exe_scope, - AddressType child_ptr_or_ref_addr_type) : - UserID (++g_value_obj_uid), // Unique identifier for every value object - m_parent (NULL), - m_root (NULL), - m_update_point (exe_scope), - m_name (), - m_data (), - m_value (), - m_error (), - m_value_str (), - m_old_value_str (), - m_location_str (), - m_summary_str (), - m_object_desc_str (), - m_validation_result(), - m_manager(), - m_children (), - m_synthetic_children (), - m_dynamic_value (NULL), - m_synthetic_value(NULL), - m_deref_valobj(NULL), - m_format (eFormatDefault), - m_last_format (eFormatDefault), - m_last_format_mgr_revision(0), - m_type_summary_sp(), - m_type_format_sp(), - m_synthetic_children_sp(), - m_type_validator_sp(), - m_user_id_of_forced_summary(), - m_address_type_of_ptr_or_ref_children(child_ptr_or_ref_addr_type), - m_value_checksum(), - m_preferred_display_language(lldb::eLanguageTypeUnknown), - m_language_flags(0), - m_value_is_valid (false), - m_value_did_change (false), - m_children_count_valid (false), - m_old_value_valid (false), - m_is_deref_of_parent (false), - m_is_array_item_for_pointer(false), - m_is_bitfield_for_scalar(false), - m_is_child_at_offset(false), - m_is_getting_summary(false), - m_did_calculate_complete_objc_class_type(false), - m_is_synthetic_children_generated(false) -{ - m_manager = new ValueObjectManager(); - m_manager->ManageObject (this); +ValueObject::ValueObject(ExecutionContextScope *exe_scope, + AddressType child_ptr_or_ref_addr_type) + : UserID(++g_value_obj_uid), // Unique identifier for every value object + m_parent(NULL), m_root(NULL), m_update_point(exe_scope), m_name(), + m_data(), m_value(), m_error(), m_value_str(), m_old_value_str(), + m_location_str(), m_summary_str(), m_object_desc_str(), + m_validation_result(), m_manager(), m_children(), m_synthetic_children(), + m_dynamic_value(NULL), m_synthetic_value(NULL), m_deref_valobj(NULL), + m_format(eFormatDefault), m_last_format(eFormatDefault), + m_last_format_mgr_revision(0), m_type_summary_sp(), m_type_format_sp(), + m_synthetic_children_sp(), m_type_validator_sp(), + m_user_id_of_forced_summary(), + m_address_type_of_ptr_or_ref_children(child_ptr_or_ref_addr_type), + m_value_checksum(), + m_preferred_display_language(lldb::eLanguageTypeUnknown), + m_language_flags(0), m_value_is_valid(false), m_value_did_change(false), + m_children_count_valid(false), m_old_value_valid(false), + m_is_deref_of_parent(false), m_is_array_item_for_pointer(false), + m_is_bitfield_for_scalar(false), m_is_child_at_offset(false), + m_is_getting_summary(false), + m_did_calculate_complete_objc_class_type(false), + m_is_synthetic_children_generated(false) { + m_manager = new ValueObjectManager(); + m_manager->ManageObject(this); } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -ValueObject::~ValueObject () -{ -} +ValueObject::~ValueObject() {} + +bool ValueObject::UpdateValueIfNeeded(bool update_format) { + + bool did_change_formats = false; + + if (update_format) + did_change_formats = UpdateFormatsIfNeeded(); + + // If this is a constant value, then our success is predicated on whether + // we have an error or not + if (GetIsConstant()) { + // if you are constant, things might still have changed behind your back + // (e.g. you are a frozen object and things have changed deeper than you + // cared to freeze-dry yourself) + // in this case, your value has not changed, but "computed" entries might + // have, so you might now have + // a different summary, or a different object description. clear these so we + // will recompute them + if (update_format && !did_change_formats) + ClearUserVisibleData(eClearUserVisibleDataItemsSummary | + eClearUserVisibleDataItemsDescription); + return m_error.Success(); + } -bool -ValueObject::UpdateValueIfNeeded (bool update_format) -{ - - bool did_change_formats = false; - - if (update_format) - did_change_formats = UpdateFormatsIfNeeded(); - - // If this is a constant value, then our success is predicated on whether - // we have an error or not - if (GetIsConstant()) - { - // if you are constant, things might still have changed behind your back - // (e.g. you are a frozen object and things have changed deeper than you cared to freeze-dry yourself) - // in this case, your value has not changed, but "computed" entries might have, so you might now have - // a different summary, or a different object description. clear these so we will recompute them - if (update_format && !did_change_formats) - ClearUserVisibleData(eClearUserVisibleDataItemsSummary | eClearUserVisibleDataItemsDescription); - return m_error.Success(); + bool first_update = IsChecksumEmpty(); + + if (NeedsUpdating()) { + m_update_point.SetUpdated(); + + // Save the old value using swap to avoid a string copy which + // also will clear our m_value_str + if (m_value_str.empty()) { + m_old_value_valid = false; + } else { + m_old_value_valid = true; + m_old_value_str.swap(m_value_str); + ClearUserVisibleData(eClearUserVisibleDataItemsValue); } - bool first_update = IsChecksumEmpty(); - - if (NeedsUpdating()) - { - m_update_point.SetUpdated(); - - // Save the old value using swap to avoid a string copy which - // also will clear our m_value_str - if (m_value_str.empty()) - { - m_old_value_valid = false; - } - else - { - m_old_value_valid = true; - m_old_value_str.swap (m_value_str); - ClearUserVisibleData(eClearUserVisibleDataItemsValue); - } + ClearUserVisibleData(); - ClearUserVisibleData(); - - if (IsInScope()) - { - const bool value_was_valid = GetValueIsValid(); - SetValueDidChange (false); - - m_error.Clear(); - - // Call the pure virtual function to update the value - - bool need_compare_checksums = false; - llvm::SmallVector<uint8_t, 16> old_checksum; - - if (!first_update && CanProvideValue()) - { - need_compare_checksums = true; - old_checksum.resize(m_value_checksum.size()); - std::copy(m_value_checksum.begin(), m_value_checksum.end(), old_checksum.begin()); - } - - bool success = UpdateValue (); - - SetValueIsValid (success); - - if (success) - { - const uint64_t max_checksum_size = 128; - m_data.Checksum(m_value_checksum, - max_checksum_size); - } - else - { - need_compare_checksums = false; - m_value_checksum.clear(); - } - - assert (!need_compare_checksums || (!old_checksum.empty() && !m_value_checksum.empty())); - - if (first_update) - SetValueDidChange (false); - else if (!m_value_did_change && success == false) - { - // The value wasn't gotten successfully, so we mark this - // as changed if the value used to be valid and now isn't - SetValueDidChange (value_was_valid); - } - else if (need_compare_checksums) - { - SetValueDidChange(memcmp(&old_checksum[0], &m_value_checksum[0], m_value_checksum.size())); - } - - } - else - { - m_error.SetErrorString("out of scope"); - } + if (IsInScope()) { + const bool value_was_valid = GetValueIsValid(); + SetValueDidChange(false); + + m_error.Clear(); + + // Call the pure virtual function to update the value + + bool need_compare_checksums = false; + llvm::SmallVector<uint8_t, 16> old_checksum; + + if (!first_update && CanProvideValue()) { + need_compare_checksums = true; + old_checksum.resize(m_value_checksum.size()); + std::copy(m_value_checksum.begin(), m_value_checksum.end(), + old_checksum.begin()); + } + + bool success = UpdateValue(); + + SetValueIsValid(success); + + if (success) { + const uint64_t max_checksum_size = 128; + m_data.Checksum(m_value_checksum, max_checksum_size); + } else { + need_compare_checksums = false; + m_value_checksum.clear(); + } + + assert(!need_compare_checksums || + (!old_checksum.empty() && !m_value_checksum.empty())); + + if (first_update) + SetValueDidChange(false); + else if (!m_value_did_change && success == false) { + // The value wasn't gotten successfully, so we mark this + // as changed if the value used to be valid and now isn't + SetValueDidChange(value_was_valid); + } else if (need_compare_checksums) { + SetValueDidChange(memcmp(&old_checksum[0], &m_value_checksum[0], + m_value_checksum.size())); + } + + } else { + m_error.SetErrorString("out of scope"); } - return m_error.Success(); + } + return m_error.Success(); } -bool -ValueObject::UpdateFormatsIfNeeded() -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_DATAFORMATTERS)); - if (log) - log->Printf("[%s %p] checking for FormatManager revisions. ValueObject rev: %d - Global rev: %d", - GetName().GetCString(), static_cast<void*>(this), - m_last_format_mgr_revision, - DataVisualization::GetCurrentRevision()); +bool ValueObject::UpdateFormatsIfNeeded() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS)); + if (log) + log->Printf("[%s %p] checking for FormatManager revisions. ValueObject " + "rev: %d - Global rev: %d", + GetName().GetCString(), static_cast<void *>(this), + m_last_format_mgr_revision, + DataVisualization::GetCurrentRevision()); - bool any_change = false; + bool any_change = false; - if ( (m_last_format_mgr_revision != DataVisualization::GetCurrentRevision())) - { - m_last_format_mgr_revision = DataVisualization::GetCurrentRevision(); - any_change = true; - - SetValueFormat(DataVisualization::GetFormat (*this, eNoDynamicValues)); - SetSummaryFormat(DataVisualization::GetSummaryFormat (*this, GetDynamicValueType())); + if ((m_last_format_mgr_revision != DataVisualization::GetCurrentRevision())) { + m_last_format_mgr_revision = DataVisualization::GetCurrentRevision(); + any_change = true; + + SetValueFormat(DataVisualization::GetFormat(*this, eNoDynamicValues)); + SetSummaryFormat( + DataVisualization::GetSummaryFormat(*this, GetDynamicValueType())); #ifndef LLDB_DISABLE_PYTHON - SetSyntheticChildren(DataVisualization::GetSyntheticChildren (*this, GetDynamicValueType())); + SetSyntheticChildren( + DataVisualization::GetSyntheticChildren(*this, GetDynamicValueType())); #endif - SetValidator(DataVisualization::GetValidator(*this, GetDynamicValueType())); - } + SetValidator(DataVisualization::GetValidator(*this, GetDynamicValueType())); + } - return any_change; + return any_change; } -void -ValueObject::SetNeedsUpdate () -{ - m_update_point.SetNeedsUpdate(); - // We have to clear the value string here so ConstResult children will notice if their values are - // changed by hand (i.e. with SetValueAsCString). - ClearUserVisibleData(eClearUserVisibleDataItemsValue); +void ValueObject::SetNeedsUpdate() { + m_update_point.SetNeedsUpdate(); + // We have to clear the value string here so ConstResult children will notice + // if their values are + // changed by hand (i.e. with SetValueAsCString). + ClearUserVisibleData(eClearUserVisibleDataItemsValue); } -void -ValueObject::ClearDynamicTypeInformation () -{ - m_children_count_valid = false; - m_did_calculate_complete_objc_class_type = false; - m_last_format_mgr_revision = 0; - m_override_type = CompilerType(); - SetValueFormat(lldb::TypeFormatImplSP()); - SetSummaryFormat(lldb::TypeSummaryImplSP()); - SetSyntheticChildren(lldb::SyntheticChildrenSP()); +void ValueObject::ClearDynamicTypeInformation() { + m_children_count_valid = false; + m_did_calculate_complete_objc_class_type = false; + m_last_format_mgr_revision = 0; + m_override_type = CompilerType(); + SetValueFormat(lldb::TypeFormatImplSP()); + SetSummaryFormat(lldb::TypeSummaryImplSP()); + SetSyntheticChildren(lldb::SyntheticChildrenSP()); } -CompilerType -ValueObject::MaybeCalculateCompleteType () -{ - CompilerType compiler_type(GetCompilerTypeImpl()); - - if (m_did_calculate_complete_objc_class_type) - { - if (m_override_type.IsValid()) - return m_override_type; - else - return compiler_type; - } - - CompilerType class_type; - bool is_pointer_type = false; - - if (ClangASTContext::IsObjCObjectPointerType(compiler_type, &class_type)) - { - is_pointer_type = true; - } - else if (ClangASTContext::IsObjCObjectOrInterfaceType(compiler_type)) - { - class_type = compiler_type; - } +CompilerType ValueObject::MaybeCalculateCompleteType() { + CompilerType compiler_type(GetCompilerTypeImpl()); + + if (m_did_calculate_complete_objc_class_type) { + if (m_override_type.IsValid()) + return m_override_type; else - { - return compiler_type; - } - - m_did_calculate_complete_objc_class_type = true; - - if (class_type) - { - ConstString class_name (class_type.GetConstTypeName()); - - if (class_name) - { - ProcessSP process_sp(GetUpdatePoint().GetExecutionContextRef().GetProcessSP()); - - if (process_sp) - { - ObjCLanguageRuntime *objc_language_runtime(process_sp->GetObjCLanguageRuntime()); - - if (objc_language_runtime) - { - TypeSP complete_objc_class_type_sp = objc_language_runtime->LookupInCompleteClassCache(class_name); - - if (complete_objc_class_type_sp) - { - CompilerType complete_class(complete_objc_class_type_sp->GetFullCompilerType ()); - - if (complete_class.GetCompleteType()) - { - if (is_pointer_type) - { - m_override_type = complete_class.GetPointerType(); - } - else - { - m_override_type = complete_class; - } - - if (m_override_type.IsValid()) - return m_override_type; - } - } - } - } - } - } + return compiler_type; + } + + CompilerType class_type; + bool is_pointer_type = false; + + if (ClangASTContext::IsObjCObjectPointerType(compiler_type, &class_type)) { + is_pointer_type = true; + } else if (ClangASTContext::IsObjCObjectOrInterfaceType(compiler_type)) { + class_type = compiler_type; + } else { return compiler_type; -} + } -CompilerType -ValueObject::GetCompilerType () -{ - return MaybeCalculateCompleteType(); -} + m_did_calculate_complete_objc_class_type = true; -TypeImpl -ValueObject::GetTypeImpl () -{ - return TypeImpl(GetCompilerType()); -} + if (class_type) { + ConstString class_name(class_type.GetConstTypeName()); -DataExtractor & -ValueObject::GetDataExtractor () -{ - UpdateValueIfNeeded(false); - return m_data; -} + if (class_name) { + ProcessSP process_sp( + GetUpdatePoint().GetExecutionContextRef().GetProcessSP()); -const Error & -ValueObject::GetError() -{ - UpdateValueIfNeeded(false); - return m_error; -} + if (process_sp) { + ObjCLanguageRuntime *objc_language_runtime( + process_sp->GetObjCLanguageRuntime()); -const ConstString & -ValueObject::GetName() const -{ - return m_name; -} + if (objc_language_runtime) { + TypeSP complete_objc_class_type_sp = + objc_language_runtime->LookupInCompleteClassCache(class_name); -const char * -ValueObject::GetLocationAsCString () -{ - return GetLocationAsCStringImpl(m_value, - m_data); -} + if (complete_objc_class_type_sp) { + CompilerType complete_class( + complete_objc_class_type_sp->GetFullCompilerType()); -const char * -ValueObject::GetLocationAsCStringImpl (const Value& value, - const DataExtractor& data) -{ - if (UpdateValueIfNeeded(false)) - { - if (m_location_str.empty()) - { - StreamString sstr; - - Value::ValueType value_type = value.GetValueType(); - - switch (value_type) - { - case Value::eValueTypeScalar: - case Value::eValueTypeVector: - if (value.GetContextType() == Value::eContextTypeRegisterInfo) - { - RegisterInfo *reg_info = value.GetRegisterInfo(); - if (reg_info) - { - if (reg_info->name) - m_location_str = reg_info->name; - else if (reg_info->alt_name) - m_location_str = reg_info->alt_name; - if (m_location_str.empty()) - m_location_str = (reg_info->encoding == lldb::eEncodingVector) ? "vector" : "scalar"; - } - } - if (m_location_str.empty()) - m_location_str = (value_type == Value::eValueTypeVector) ? "vector" : "scalar"; - break; - - case Value::eValueTypeLoadAddress: - case Value::eValueTypeFileAddress: - case Value::eValueTypeHostAddress: - { - uint32_t addr_nibble_size = data.GetAddressByteSize() * 2; - sstr.Printf("0x%*.*llx", addr_nibble_size, addr_nibble_size, value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS)); - m_location_str.swap(sstr.GetString()); - } - break; + if (complete_class.GetCompleteType()) { + if (is_pointer_type) { + m_override_type = complete_class.GetPointerType(); + } else { + m_override_type = complete_class; + } + + if (m_override_type.IsValid()) + return m_override_type; } + } } + } } - return m_location_str.c_str(); + } + return compiler_type; } -Value & -ValueObject::GetValue() -{ - return m_value; +CompilerType ValueObject::GetCompilerType() { + return MaybeCalculateCompleteType(); } -const Value & -ValueObject::GetValue() const -{ - return m_value; -} +TypeImpl ValueObject::GetTypeImpl() { return TypeImpl(GetCompilerType()); } -bool -ValueObject::ResolveValue (Scalar &scalar) -{ - if (UpdateValueIfNeeded(false)) // make sure that you are up to date before returning anything - { - ExecutionContext exe_ctx (GetExecutionContextRef()); - Value tmp_value(m_value); - scalar = tmp_value.ResolveValue(&exe_ctx); - if (scalar.IsValid()) - { - const uint32_t bitfield_bit_size = GetBitfieldBitSize(); - if (bitfield_bit_size) - return scalar.ExtractBitfield (bitfield_bit_size, GetBitfieldBitOffset()); - return true; - } - } - return false; +DataExtractor &ValueObject::GetDataExtractor() { + UpdateValueIfNeeded(false); + return m_data; } -bool -ValueObject::IsLogicalTrue (Error& error) -{ - if (Language *language = Language::FindPlugin(GetObjectRuntimeLanguage())) - { - LazyBool is_logical_true = language->IsLogicalTrue(*this, error); - switch (is_logical_true) - { - case eLazyBoolYes: - case eLazyBoolNo: - return (is_logical_true == true); - case eLazyBoolCalculate: - break; - } - } - - Scalar scalar_value; - - if (!ResolveValue (scalar_value)) - { - error.SetErrorString("failed to get a scalar result"); - return false; - } - - bool ret; - if (scalar_value.ULongLong(1) == 0) - ret = false; - else - ret = true; - error.Clear(); - return ret; +const Error &ValueObject::GetError() { + UpdateValueIfNeeded(false); + return m_error; } -bool -ValueObject::GetValueIsValid () const -{ - return m_value_is_valid; +const ConstString &ValueObject::GetName() const { return m_name; } + +const char *ValueObject::GetLocationAsCString() { + return GetLocationAsCStringImpl(m_value, m_data); } +const char *ValueObject::GetLocationAsCStringImpl(const Value &value, + const DataExtractor &data) { + if (UpdateValueIfNeeded(false)) { + if (m_location_str.empty()) { + StreamString sstr; -void -ValueObject::SetValueIsValid (bool b) -{ - m_value_is_valid = b; -} + Value::ValueType value_type = value.GetValueType(); + + switch (value_type) { + case Value::eValueTypeScalar: + case Value::eValueTypeVector: + if (value.GetContextType() == Value::eContextTypeRegisterInfo) { + RegisterInfo *reg_info = value.GetRegisterInfo(); + if (reg_info) { + if (reg_info->name) + m_location_str = reg_info->name; + else if (reg_info->alt_name) + m_location_str = reg_info->alt_name; + if (m_location_str.empty()) + m_location_str = (reg_info->encoding == lldb::eEncodingVector) + ? "vector" + : "scalar"; + } + } + if (m_location_str.empty()) + m_location_str = + (value_type == Value::eValueTypeVector) ? "vector" : "scalar"; + break; + + case Value::eValueTypeLoadAddress: + case Value::eValueTypeFileAddress: + case Value::eValueTypeHostAddress: { + uint32_t addr_nibble_size = data.GetAddressByteSize() * 2; + sstr.Printf("0x%*.*llx", addr_nibble_size, addr_nibble_size, + value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS)); + m_location_str = sstr.GetString(); + } break; + } + } + } + return m_location_str.c_str(); +} + +Value &ValueObject::GetValue() { return m_value; } + +const Value &ValueObject::GetValue() const { return m_value; } + +bool ValueObject::ResolveValue(Scalar &scalar) { + if (UpdateValueIfNeeded( + false)) // make sure that you are up to date before returning anything + { + ExecutionContext exe_ctx(GetExecutionContextRef()); + Value tmp_value(m_value); + scalar = tmp_value.ResolveValue(&exe_ctx); + if (scalar.IsValid()) { + const uint32_t bitfield_bit_size = GetBitfieldBitSize(); + if (bitfield_bit_size) + return scalar.ExtractBitfield(bitfield_bit_size, + GetBitfieldBitOffset()); + return true; + } + } + return false; +} + +bool ValueObject::IsLogicalTrue(Error &error) { + if (Language *language = Language::FindPlugin(GetObjectRuntimeLanguage())) { + LazyBool is_logical_true = language->IsLogicalTrue(*this, error); + switch (is_logical_true) { + case eLazyBoolYes: + case eLazyBoolNo: + return (is_logical_true == true); + case eLazyBoolCalculate: + break; + } + } + + Scalar scalar_value; + + if (!ResolveValue(scalar_value)) { + error.SetErrorString("failed to get a scalar result"); + return false; + } -bool -ValueObject::GetValueDidChange () -{ - return m_value_did_change; + bool ret; + if (scalar_value.ULongLong(1) == 0) + ret = false; + else + ret = true; + error.Clear(); + return ret; } -void -ValueObject::SetValueDidChange (bool value_changed) -{ - m_value_did_change = value_changed; +bool ValueObject::GetValueIsValid() const { return m_value_is_valid; } + +void ValueObject::SetValueIsValid(bool b) { m_value_is_valid = b; } + +bool ValueObject::GetValueDidChange() { return m_value_did_change; } + +void ValueObject::SetValueDidChange(bool value_changed) { + m_value_did_change = value_changed; } -ValueObjectSP -ValueObject::GetChildAtIndex (size_t idx, bool can_create) -{ - ValueObjectSP child_sp; - // We may need to update our value if we are dynamic - if (IsPossibleDynamicType ()) - UpdateValueIfNeeded(false); - if (idx < GetNumChildren()) - { - // Check if we have already made the child value object? - if (can_create && !m_children.HasChildAtIndex(idx)) - { - // No we haven't created the child at this index, so lets have our - // subclass do it and cache the result for quick future access. - m_children.SetChildAtIndex(idx,CreateChildAtIndex (idx, false, 0)); - } - - ValueObject* child = m_children.GetChildAtIndex(idx); - if (child != NULL) - return child->GetSP(); +ValueObjectSP ValueObject::GetChildAtIndex(size_t idx, bool can_create) { + ValueObjectSP child_sp; + // We may need to update our value if we are dynamic + if (IsPossibleDynamicType()) + UpdateValueIfNeeded(false); + if (idx < GetNumChildren()) { + // Check if we have already made the child value object? + if (can_create && !m_children.HasChildAtIndex(idx)) { + // No we haven't created the child at this index, so lets have our + // subclass do it and cache the result for quick future access. + m_children.SetChildAtIndex(idx, CreateChildAtIndex(idx, false, 0)); } - return child_sp; + + ValueObject *child = m_children.GetChildAtIndex(idx); + if (child != NULL) + return child->GetSP(); + } + return child_sp; } ValueObjectSP -ValueObject::GetChildAtIndexPath (const std::initializer_list<size_t>& idxs, - size_t* index_of_error) -{ - return GetChildAtIndexPath( std::vector<size_t>(idxs), - index_of_error ); +ValueObject::GetChildAtIndexPath(const std::initializer_list<size_t> &idxs, + size_t *index_of_error) { + return GetChildAtIndexPath(std::vector<size_t>(idxs), index_of_error); } -ValueObjectSP -ValueObject::GetChildAtIndexPath (const std::initializer_list< std::pair<size_t, bool> >& idxs, - size_t* index_of_error) -{ - return GetChildAtIndexPath( std::vector<std::pair<size_t,bool>>(idxs), - index_of_error ); +ValueObjectSP ValueObject::GetChildAtIndexPath( + const std::initializer_list<std::pair<size_t, bool>> &idxs, + size_t *index_of_error) { + return GetChildAtIndexPath(std::vector<std::pair<size_t, bool>>(idxs), + index_of_error); } lldb::ValueObjectSP -ValueObject::GetChildAtIndexPath (const std::vector<size_t> &idxs, - size_t* index_of_error) -{ - if (idxs.size() == 0) - return GetSP(); - ValueObjectSP root(GetSP()); - for (size_t idx : idxs) - { - root = root->GetChildAtIndex(idx, true); - if (!root) - { - if (index_of_error) - *index_of_error = idx; - return root; - } +ValueObject::GetChildAtIndexPath(const std::vector<size_t> &idxs, + size_t *index_of_error) { + if (idxs.size() == 0) + return GetSP(); + ValueObjectSP root(GetSP()); + for (size_t idx : idxs) { + root = root->GetChildAtIndex(idx, true); + if (!root) { + if (index_of_error) + *index_of_error = idx; + return root; } - return root; + } + return root; } -lldb::ValueObjectSP -ValueObject::GetChildAtIndexPath (const std::vector< std::pair<size_t, bool> > &idxs, - size_t* index_of_error) -{ - if (idxs.size() == 0) - return GetSP(); - ValueObjectSP root(GetSP()); - for (std::pair<size_t, bool> idx : idxs) - { - root = root->GetChildAtIndex(idx.first, idx.second); - if (!root) - { - if (index_of_error) - *index_of_error = idx.first; - return root; - } +lldb::ValueObjectSP ValueObject::GetChildAtIndexPath( + const std::vector<std::pair<size_t, bool>> &idxs, size_t *index_of_error) { + if (idxs.size() == 0) + return GetSP(); + ValueObjectSP root(GetSP()); + for (std::pair<size_t, bool> idx : idxs) { + root = root->GetChildAtIndex(idx.first, idx.second); + if (!root) { + if (index_of_error) + *index_of_error = idx.first; + return root; } - return root; + } + return root; } lldb::ValueObjectSP -ValueObject::GetChildAtNamePath (const std::initializer_list<ConstString> &names, - ConstString* name_of_error) -{ - return GetChildAtNamePath( std::vector<ConstString>(names), - name_of_error ); +ValueObject::GetChildAtNamePath(const std::initializer_list<ConstString> &names, + ConstString *name_of_error) { + return GetChildAtNamePath(std::vector<ConstString>(names), name_of_error); } -lldb::ValueObjectSP -ValueObject::GetChildAtNamePath (const std::initializer_list< std::pair<ConstString, bool> > &names, - ConstString* name_of_error) -{ - return GetChildAtNamePath( std::vector<std::pair<ConstString,bool>>(names), - name_of_error ); +lldb::ValueObjectSP ValueObject::GetChildAtNamePath( + const std::initializer_list<std::pair<ConstString, bool>> &names, + ConstString *name_of_error) { + return GetChildAtNamePath(std::vector<std::pair<ConstString, bool>>(names), + name_of_error); } lldb::ValueObjectSP -ValueObject::GetChildAtNamePath (const std::vector<ConstString> &names, - ConstString* name_of_error) -{ - if (names.size() == 0) - return GetSP(); - ValueObjectSP root(GetSP()); - for (ConstString name : names) - { - root = root->GetChildMemberWithName(name, true); - if (!root) - { - if (name_of_error) - *name_of_error = name; - return root; - } +ValueObject::GetChildAtNamePath(const std::vector<ConstString> &names, + ConstString *name_of_error) { + if (names.size() == 0) + return GetSP(); + ValueObjectSP root(GetSP()); + for (ConstString name : names) { + root = root->GetChildMemberWithName(name, true); + if (!root) { + if (name_of_error) + *name_of_error = name; + return root; + } + } + return root; +} + +lldb::ValueObjectSP ValueObject::GetChildAtNamePath( + const std::vector<std::pair<ConstString, bool>> &names, + ConstString *name_of_error) { + if (names.size() == 0) + return GetSP(); + ValueObjectSP root(GetSP()); + for (std::pair<ConstString, bool> name : names) { + root = root->GetChildMemberWithName(name.first, name.second); + if (!root) { + if (name_of_error) + *name_of_error = name.first; + return root; } - return root; + } + return root; } -lldb::ValueObjectSP -ValueObject::GetChildAtNamePath (const std::vector< std::pair<ConstString, bool> > &names, - ConstString* name_of_error) -{ - if (names.size() == 0) - return GetSP(); - ValueObjectSP root(GetSP()); - for (std::pair<ConstString, bool> name : names) - { - root = root->GetChildMemberWithName(name.first, name.second); - if (!root) - { - if (name_of_error) - *name_of_error = name.first; - return root; - } - } - return root; +size_t ValueObject::GetIndexOfChildWithName(const ConstString &name) { + bool omit_empty_base_classes = true; + return GetCompilerType().GetIndexOfChildWithName(name.GetCString(), + omit_empty_base_classes); } -size_t -ValueObject::GetIndexOfChildWithName (const ConstString &name) -{ - bool omit_empty_base_classes = true; - return GetCompilerType().GetIndexOfChildWithName (name.GetCString(), omit_empty_base_classes); +ValueObjectSP ValueObject::GetChildMemberWithName(const ConstString &name, + bool can_create) { + // when getting a child by name, it could be buried inside some base + // classes (which really aren't part of the expression path), so we + // need a vector of indexes that can get us down to the correct child + ValueObjectSP child_sp; + + // We may need to update our value if we are dynamic + if (IsPossibleDynamicType()) + UpdateValueIfNeeded(false); + + std::vector<uint32_t> child_indexes; + bool omit_empty_base_classes = true; + const size_t num_child_indexes = + GetCompilerType().GetIndexOfChildMemberWithName( + name.GetCString(), omit_empty_base_classes, child_indexes); + if (num_child_indexes > 0) { + std::vector<uint32_t>::const_iterator pos = child_indexes.begin(); + std::vector<uint32_t>::const_iterator end = child_indexes.end(); + + child_sp = GetChildAtIndex(*pos, can_create); + for (++pos; pos != end; ++pos) { + if (child_sp) { + ValueObjectSP new_child_sp(child_sp->GetChildAtIndex(*pos, can_create)); + child_sp = new_child_sp; + } else { + child_sp.reset(); + } + } + } + return child_sp; +} + +size_t ValueObject::GetNumChildren(uint32_t max) { + UpdateValueIfNeeded(); + + if (max < UINT32_MAX) { + if (m_children_count_valid) { + size_t children_count = m_children.GetChildrenCount(); + return children_count <= max ? children_count : max; + } else + return CalculateNumChildren(max); + } + + if (!m_children_count_valid) { + SetNumChildren(CalculateNumChildren()); + } + return m_children.GetChildrenCount(); +} + +bool ValueObject::MightHaveChildren() { + bool has_children = false; + const uint32_t type_info = GetTypeInfo(); + if (type_info) { + if (type_info & (eTypeHasChildren | eTypeIsPointer | eTypeIsReference)) + has_children = true; + } else { + has_children = GetNumChildren() > 0; + } + return has_children; } -ValueObjectSP -ValueObject::GetChildMemberWithName (const ConstString &name, bool can_create) -{ - // when getting a child by name, it could be buried inside some base - // classes (which really aren't part of the expression path), so we - // need a vector of indexes that can get us down to the correct child - ValueObjectSP child_sp; - - // We may need to update our value if we are dynamic - if (IsPossibleDynamicType ()) - UpdateValueIfNeeded(false); - - std::vector<uint32_t> child_indexes; - bool omit_empty_base_classes = true; - const size_t num_child_indexes = GetCompilerType().GetIndexOfChildMemberWithName (name.GetCString(), - omit_empty_base_classes, - child_indexes); - if (num_child_indexes > 0) - { - std::vector<uint32_t>::const_iterator pos = child_indexes.begin (); - std::vector<uint32_t>::const_iterator end = child_indexes.end (); +// Should only be called by ValueObject::GetNumChildren() +void ValueObject::SetNumChildren(size_t num_children) { + m_children_count_valid = true; + m_children.SetChildrenCount(num_children); +} + +void ValueObject::SetName(const ConstString &name) { m_name = name; } + +ValueObject *ValueObject::CreateChildAtIndex(size_t idx, + bool synthetic_array_member, + int32_t synthetic_index) { + ValueObject *valobj = NULL; + + bool omit_empty_base_classes = true; + bool ignore_array_bounds = synthetic_array_member; + std::string child_name_str; + uint32_t child_byte_size = 0; + int32_t child_byte_offset = 0; + uint32_t child_bitfield_bit_size = 0; + uint32_t child_bitfield_bit_offset = 0; + bool child_is_base_class = false; + bool child_is_deref_of_parent = false; + uint64_t language_flags = 0; + + const bool transparent_pointers = synthetic_array_member == false; + CompilerType child_compiler_type; + + ExecutionContext exe_ctx(GetExecutionContextRef()); + + child_compiler_type = GetCompilerType().GetChildCompilerTypeAtIndex( + &exe_ctx, idx, transparent_pointers, omit_empty_base_classes, + ignore_array_bounds, child_name_str, child_byte_size, child_byte_offset, + child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, + child_is_deref_of_parent, this, language_flags); + if (child_compiler_type) { + if (synthetic_index) + child_byte_offset += child_byte_size * synthetic_index; + + ConstString child_name; + if (!child_name_str.empty()) + child_name.SetCString(child_name_str.c_str()); + + valobj = new ValueObjectChild( + *this, child_compiler_type, child_name, child_byte_size, + child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, + child_is_base_class, child_is_deref_of_parent, eAddressTypeInvalid, + language_flags); + // if (valobj) + // valobj->SetAddressTypeOfChildren(eAddressTypeInvalid); + } + + return valobj; +} + +bool ValueObject::GetSummaryAsCString(TypeSummaryImpl *summary_ptr, + std::string &destination, + lldb::LanguageType lang) { + return GetSummaryAsCString(summary_ptr, destination, + TypeSummaryOptions().SetLanguage(lang)); +} + +bool ValueObject::GetSummaryAsCString(TypeSummaryImpl *summary_ptr, + std::string &destination, + const TypeSummaryOptions &options) { + destination.clear(); + + // ideally we would like to bail out if passing NULL, but if we do so + // we end up not providing the summary for function pointers anymore + if (/*summary_ptr == NULL ||*/ m_is_getting_summary) + return false; - child_sp = GetChildAtIndex(*pos, can_create); - for (++pos; pos != end; ++pos) - { - if (child_sp) - { - ValueObjectSP new_child_sp(child_sp->GetChildAtIndex (*pos, can_create)); - child_sp = new_child_sp; - } - else - { - child_sp.reset(); - } + m_is_getting_summary = true; + + TypeSummaryOptions actual_options(options); + + if (actual_options.GetLanguage() == lldb::eLanguageTypeUnknown) + actual_options.SetLanguage(GetPreferredDisplayLanguage()); + + // this is a hot path in code and we prefer to avoid setting this string all + // too often also clearing out other + // information that we might care to see in a crash log. might be useful in + // very specific situations though. + /*Host::SetCrashDescriptionWithFormat("Trying to fetch a summary for %s %s. + Summary provider's description is %s", + GetTypeName().GetCString(), + GetName().GetCString(), + summary_ptr->GetDescription().c_str());*/ + + if (UpdateValueIfNeeded(false) && summary_ptr) { + if (HasSyntheticValue()) + m_synthetic_value->UpdateValueIfNeeded(); // the summary might depend on + // the synthetic children being + // up-to-date (e.g. ${svar%#}) + summary_ptr->FormatObject(this, destination, actual_options); + } + m_is_getting_summary = false; + return !destination.empty(); +} + +const char *ValueObject::GetSummaryAsCString(lldb::LanguageType lang) { + if (UpdateValueIfNeeded(true) && m_summary_str.empty()) { + TypeSummaryOptions summary_options; + summary_options.SetLanguage(lang); + GetSummaryAsCString(GetSummaryFormat().get(), m_summary_str, + summary_options); + } + if (m_summary_str.empty()) + return NULL; + return m_summary_str.c_str(); +} - } - } - return child_sp; +bool ValueObject::GetSummaryAsCString(std::string &destination, + const TypeSummaryOptions &options) { + return GetSummaryAsCString(GetSummaryFormat().get(), destination, options); } +bool ValueObject::IsCStringContainer(bool check_pointer) { + CompilerType pointee_or_element_compiler_type; + const Flags type_flags(GetTypeInfo(&pointee_or_element_compiler_type)); + bool is_char_arr_ptr(type_flags.AnySet(eTypeIsArray | eTypeIsPointer) && + pointee_or_element_compiler_type.IsCharType()); + if (!is_char_arr_ptr) + return false; + if (!check_pointer) + return true; + if (type_flags.Test(eTypeIsArray)) + return true; + addr_t cstr_address = LLDB_INVALID_ADDRESS; + AddressType cstr_address_type = eAddressTypeInvalid; + cstr_address = GetAddressOf(true, &cstr_address_type); + return (cstr_address != LLDB_INVALID_ADDRESS); +} + +size_t ValueObject::GetPointeeData(DataExtractor &data, uint32_t item_idx, + uint32_t item_count) { + CompilerType pointee_or_element_compiler_type; + const uint32_t type_info = GetTypeInfo(&pointee_or_element_compiler_type); + const bool is_pointer_type = type_info & eTypeIsPointer; + const bool is_array_type = type_info & eTypeIsArray; + if (!(is_pointer_type || is_array_type)) + return 0; -size_t -ValueObject::GetNumChildren (uint32_t max) -{ - UpdateValueIfNeeded(); + if (item_count == 0) + return 0; - if (max < UINT32_MAX) - { - if (m_children_count_valid) - { - size_t children_count = m_children.GetChildrenCount(); - return children_count <= max ? children_count : max; - } - else - return CalculateNumChildren(max); - } + ExecutionContext exe_ctx(GetExecutionContextRef()); - if (!m_children_count_valid) - { - SetNumChildren (CalculateNumChildren()); - } - return m_children.GetChildrenCount(); -} + const uint64_t item_type_size = pointee_or_element_compiler_type.GetByteSize( + exe_ctx.GetBestExecutionContextScope()); + const uint64_t bytes = item_count * item_type_size; + const uint64_t offset = item_idx * item_type_size; -bool -ValueObject::MightHaveChildren() -{ - bool has_children = false; - const uint32_t type_info = GetTypeInfo(); - if (type_info) - { - if (type_info & (eTypeHasChildren | - eTypeIsPointer | - eTypeIsReference)) - has_children = true; - } - else - { - has_children = GetNumChildren () > 0; + if (item_idx == 0 && item_count == 1) // simply a deref + { + if (is_pointer_type) { + Error error; + ValueObjectSP pointee_sp = Dereference(error); + if (error.Fail() || pointee_sp.get() == NULL) + return 0; + return pointee_sp->GetData(data, error); + } else { + ValueObjectSP child_sp = GetChildAtIndex(0, true); + if (child_sp.get() == NULL) + return 0; + Error error; + return child_sp->GetData(data, error); } - return has_children; -} + return true; + } else /* (items > 1) */ + { + Error error; + lldb_private::DataBufferHeap *heap_buf_ptr = NULL; + lldb::DataBufferSP data_sp(heap_buf_ptr = + new lldb_private::DataBufferHeap()); + + AddressType addr_type; + lldb::addr_t addr = is_pointer_type ? GetPointerValue(&addr_type) + : GetAddressOf(true, &addr_type); + + switch (addr_type) { + case eAddressTypeFile: { + ModuleSP module_sp(GetModule()); + if (module_sp) { + addr = addr + offset; + Address so_addr; + module_sp->ResolveFileAddress(addr, so_addr); + ExecutionContext exe_ctx(GetExecutionContextRef()); + Target *target = exe_ctx.GetTargetPtr(); + if (target) { + heap_buf_ptr->SetByteSize(bytes); + size_t bytes_read = target->ReadMemory( + so_addr, false, heap_buf_ptr->GetBytes(), bytes, error); + if (error.Success()) { + data.SetData(data_sp); + return bytes_read; + } + } + } + } break; + case eAddressTypeLoad: { + ExecutionContext exe_ctx(GetExecutionContextRef()); + Process *process = exe_ctx.GetProcessPtr(); + if (process) { + heap_buf_ptr->SetByteSize(bytes); + size_t bytes_read = process->ReadMemory( + addr + offset, heap_buf_ptr->GetBytes(), bytes, error); + if (error.Success() || bytes_read > 0) { + data.SetData(data_sp); + return bytes_read; + } + } + } break; + case eAddressTypeHost: { + const uint64_t max_bytes = + GetCompilerType().GetByteSize(exe_ctx.GetBestExecutionContextScope()); + if (max_bytes > offset) { + size_t bytes_read = std::min<uint64_t>(max_bytes - offset, bytes); + addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + if (addr == 0 || addr == LLDB_INVALID_ADDRESS) + break; + heap_buf_ptr->CopyData((uint8_t *)(addr + offset), bytes_read); + data.SetData(data_sp); + return bytes_read; + } + } break; + case eAddressTypeInvalid: + break; + } + } + return 0; +} + +uint64_t ValueObject::GetData(DataExtractor &data, Error &error) { + UpdateValueIfNeeded(false); + ExecutionContext exe_ctx(GetExecutionContextRef()); + error = m_value.GetValueAsData(&exe_ctx, data, 0, GetModule().get()); + if (error.Fail()) { + if (m_data.GetByteSize()) { + data = m_data; + error.Clear(); + return data.GetByteSize(); + } else { + return 0; + } + } + data.SetAddressByteSize(m_data.GetAddressByteSize()); + data.SetByteOrder(m_data.GetByteOrder()); + return data.GetByteSize(); +} + +bool ValueObject::SetData(DataExtractor &data, Error &error) { + error.Clear(); + // Make sure our value is up to date first so that our location and location + // type is valid. + if (!UpdateValueIfNeeded(false)) { + error.SetErrorString("unable to read value"); + return false; + } -// Should only be called by ValueObject::GetNumChildren() -void -ValueObject::SetNumChildren (size_t num_children) -{ - m_children_count_valid = true; - m_children.SetChildrenCount(num_children); -} + uint64_t count = 0; + const Encoding encoding = GetCompilerType().GetEncoding(count); -void -ValueObject::SetName (const ConstString &name) -{ - m_name = name; -} + const size_t byte_size = GetByteSize(); -ValueObject * -ValueObject::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index) -{ - ValueObject *valobj = NULL; - - bool omit_empty_base_classes = true; - bool ignore_array_bounds = synthetic_array_member; - std::string child_name_str; - uint32_t child_byte_size = 0; - int32_t child_byte_offset = 0; - uint32_t child_bitfield_bit_size = 0; - uint32_t child_bitfield_bit_offset = 0; - bool child_is_base_class = false; - bool child_is_deref_of_parent = false; - uint64_t language_flags = 0; + Value::ValueType value_type = m_value.GetValueType(); - const bool transparent_pointers = synthetic_array_member == false; - CompilerType child_compiler_type; - - ExecutionContext exe_ctx (GetExecutionContextRef()); - - child_compiler_type = GetCompilerType().GetChildCompilerTypeAtIndex(&exe_ctx, - idx, - transparent_pointers, - omit_empty_base_classes, - ignore_array_bounds, - child_name_str, - child_byte_size, - child_byte_offset, - child_bitfield_bit_size, - child_bitfield_bit_offset, - child_is_base_class, - child_is_deref_of_parent, - this, - language_flags); - if (child_compiler_type) - { - if (synthetic_index) - child_byte_offset += child_byte_size * synthetic_index; - - ConstString child_name; - if (!child_name_str.empty()) - child_name.SetCString (child_name_str.c_str()); - - valobj = new ValueObjectChild (*this, - child_compiler_type, - child_name, - child_byte_size, - child_byte_offset, - child_bitfield_bit_size, - child_bitfield_bit_offset, - child_is_base_class, - child_is_deref_of_parent, - eAddressTypeInvalid, - language_flags); - //if (valobj) - // valobj->SetAddressTypeOfChildren(eAddressTypeInvalid); - } - - return valobj; -} + switch (value_type) { + case Value::eValueTypeScalar: { + Error set_error = + m_value.GetScalar().SetValueFromData(data, encoding, byte_size); -bool -ValueObject::GetSummaryAsCString (TypeSummaryImpl* summary_ptr, - std::string& destination, - lldb::LanguageType lang) -{ - return GetSummaryAsCString(summary_ptr, destination, TypeSummaryOptions().SetLanguage(lang)); -} - -bool -ValueObject::GetSummaryAsCString (TypeSummaryImpl* summary_ptr, - std::string& destination, - const TypeSummaryOptions& options) -{ - destination.clear(); - - // ideally we would like to bail out if passing NULL, but if we do so - // we end up not providing the summary for function pointers anymore - if (/*summary_ptr == NULL ||*/ m_is_getting_summary) - return false; - - m_is_getting_summary = true; - - TypeSummaryOptions actual_options(options); - - if (actual_options.GetLanguage() == lldb::eLanguageTypeUnknown) - actual_options.SetLanguage(GetPreferredDisplayLanguage()); - - // this is a hot path in code and we prefer to avoid setting this string all too often also clearing out other - // information that we might care to see in a crash log. might be useful in very specific situations though. - /*Host::SetCrashDescriptionWithFormat("Trying to fetch a summary for %s %s. Summary provider's description is %s", - GetTypeName().GetCString(), - GetName().GetCString(), - summary_ptr->GetDescription().c_str());*/ - - if (UpdateValueIfNeeded (false) && summary_ptr) - { - if (HasSyntheticValue()) - m_synthetic_value->UpdateValueIfNeeded(); // the summary might depend on the synthetic children being up-to-date (e.g. ${svar%#}) - summary_ptr->FormatObject(this, destination, actual_options); + if (!set_error.Success()) { + error.SetErrorStringWithFormat("unable to set scalar value: %s", + set_error.AsCString()); + return false; } - m_is_getting_summary = false; - return !destination.empty(); -} + } break; + case Value::eValueTypeLoadAddress: { + // If it is a load address, then the scalar value is the storage location + // of the data, and we have to shove this value down to that load location. + ExecutionContext exe_ctx(GetExecutionContextRef()); + Process *process = exe_ctx.GetProcessPtr(); + if (process) { + addr_t target_addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + size_t bytes_written = process->WriteMemory( + target_addr, data.GetDataStart(), byte_size, error); + if (!error.Success()) + return false; + if (bytes_written != byte_size) { + error.SetErrorString("unable to write value to memory"); + return false; + } + } + } break; + case Value::eValueTypeHostAddress: { + // If it is a host address, then we stuff the scalar as a DataBuffer into + // the Value's data. + DataBufferSP buffer_sp(new DataBufferHeap(byte_size, 0)); + m_data.SetData(buffer_sp, 0); + data.CopyByteOrderedData(0, byte_size, + const_cast<uint8_t *>(m_data.GetDataStart()), + byte_size, m_data.GetByteOrder()); + m_value.GetScalar() = (uintptr_t)m_data.GetDataStart(); + } break; + case Value::eValueTypeFileAddress: + case Value::eValueTypeVector: + break; + } + + // If we have reached this point, then we have successfully changed the value. + SetNeedsUpdate(); + return true; +} + +static bool CopyStringDataToBufferSP(const StreamString &source, + lldb::DataBufferSP &destination) { + destination.reset(new DataBufferHeap(source.GetSize() + 1, 0)); + memcpy(destination->GetBytes(), source.GetString().data(), source.GetSize()); + return true; +} + +std::pair<size_t, bool> +ValueObject::ReadPointedString(lldb::DataBufferSP &buffer_sp, Error &error, + uint32_t max_length, bool honor_array, + Format item_format) { + bool was_capped = false; + StreamString s; + ExecutionContext exe_ctx(GetExecutionContextRef()); + Target *target = exe_ctx.GetTargetPtr(); + + if (!target) { + s << "<no target to read from>"; + error.SetErrorString("no target to read from"); + CopyStringDataToBufferSP(s, buffer_sp); + return {0, was_capped}; + } -const char * -ValueObject::GetSummaryAsCString (lldb::LanguageType lang) -{ - if (UpdateValueIfNeeded(true) && m_summary_str.empty()) - { - TypeSummaryOptions summary_options; - summary_options.SetLanguage(lang); - GetSummaryAsCString(GetSummaryFormat().get(), - m_summary_str, - summary_options); - } - if (m_summary_str.empty()) - return NULL; - return m_summary_str.c_str(); -} + if (max_length == 0) + max_length = target->GetMaximumSizeOfStringSummary(); -bool -ValueObject::GetSummaryAsCString (std::string& destination, - const TypeSummaryOptions& options) -{ - return GetSummaryAsCString(GetSummaryFormat().get(), - destination, - options); -} + size_t bytes_read = 0; + size_t total_bytes_read = 0; -bool -ValueObject::IsCStringContainer(bool check_pointer) -{ - CompilerType pointee_or_element_compiler_type; - const Flags type_flags (GetTypeInfo (&pointee_or_element_compiler_type)); - bool is_char_arr_ptr (type_flags.AnySet (eTypeIsArray | eTypeIsPointer) && - pointee_or_element_compiler_type.IsCharType ()); - if (!is_char_arr_ptr) - return false; - if (!check_pointer) - return true; - if (type_flags.Test(eTypeIsArray)) - return true; + CompilerType compiler_type = GetCompilerType(); + CompilerType elem_or_pointee_compiler_type; + const Flags type_flags(GetTypeInfo(&elem_or_pointee_compiler_type)); + if (type_flags.AnySet(eTypeIsArray | eTypeIsPointer) && + elem_or_pointee_compiler_type.IsCharType()) { addr_t cstr_address = LLDB_INVALID_ADDRESS; AddressType cstr_address_type = eAddressTypeInvalid; - cstr_address = GetAddressOf (true, &cstr_address_type); - return (cstr_address != LLDB_INVALID_ADDRESS); -} -size_t -ValueObject::GetPointeeData (DataExtractor& data, - uint32_t item_idx, - uint32_t item_count) -{ - CompilerType pointee_or_element_compiler_type; - const uint32_t type_info = GetTypeInfo (&pointee_or_element_compiler_type); - const bool is_pointer_type = type_info & eTypeIsPointer; - const bool is_array_type = type_info & eTypeIsArray; - if (!(is_pointer_type || is_array_type)) - return 0; - - if (item_count == 0) - return 0; - - ExecutionContext exe_ctx (GetExecutionContextRef()); - - const uint64_t item_type_size = pointee_or_element_compiler_type.GetByteSize(exe_ctx.GetBestExecutionContextScope()); - const uint64_t bytes = item_count * item_type_size; - const uint64_t offset = item_idx * item_type_size; - - if (item_idx == 0 && item_count == 1) // simply a deref - { - if (is_pointer_type) - { - Error error; - ValueObjectSP pointee_sp = Dereference(error); - if (error.Fail() || pointee_sp.get() == NULL) - return 0; - return pointee_sp->GetData(data, error); - } - else - { - ValueObjectSP child_sp = GetChildAtIndex(0, true); - if (child_sp.get() == NULL) - return 0; - Error error; - return child_sp->GetData(data, error); - } - return true; - } - else /* (items > 1) */ - { - Error error; - lldb_private::DataBufferHeap* heap_buf_ptr = NULL; - lldb::DataBufferSP data_sp(heap_buf_ptr = new lldb_private::DataBufferHeap()); - - AddressType addr_type; - lldb::addr_t addr = is_pointer_type ? GetPointerValue(&addr_type) : GetAddressOf(true, &addr_type); - - switch (addr_type) - { - case eAddressTypeFile: - { - ModuleSP module_sp (GetModule()); - if (module_sp) - { - addr = addr + offset; - Address so_addr; - module_sp->ResolveFileAddress(addr, so_addr); - ExecutionContext exe_ctx (GetExecutionContextRef()); - Target* target = exe_ctx.GetTargetPtr(); - if (target) - { - heap_buf_ptr->SetByteSize(bytes); - size_t bytes_read = target->ReadMemory(so_addr, false, heap_buf_ptr->GetBytes(), bytes, error); - if (error.Success()) - { - data.SetData(data_sp); - return bytes_read; - } - } - } - } - break; - case eAddressTypeLoad: - { - ExecutionContext exe_ctx (GetExecutionContextRef()); - Process *process = exe_ctx.GetProcessPtr(); - if (process) - { - heap_buf_ptr->SetByteSize(bytes); - size_t bytes_read = process->ReadMemory(addr + offset, heap_buf_ptr->GetBytes(), bytes, error); - if (error.Success() || bytes_read > 0) - { - data.SetData(data_sp); - return bytes_read; - } - } - } - break; - case eAddressTypeHost: - { - const uint64_t max_bytes = GetCompilerType().GetByteSize(exe_ctx.GetBestExecutionContextScope()); - if (max_bytes > offset) - { - size_t bytes_read = std::min<uint64_t>(max_bytes - offset, bytes); - addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); - if (addr == 0 || addr == LLDB_INVALID_ADDRESS) - break; - heap_buf_ptr->CopyData((uint8_t*)(addr + offset), bytes_read); - data.SetData(data_sp); - return bytes_read; - } - } - break; - case eAddressTypeInvalid: - break; - } - } - return 0; -} + size_t cstr_len = 0; + bool capped_data = false; + const bool is_array = type_flags.Test(eTypeIsArray); + if (is_array) { + // We have an array + uint64_t array_size = 0; + if (compiler_type.IsArrayType(NULL, &array_size, NULL)) { + cstr_len = array_size; + if (cstr_len > max_length) { + capped_data = true; + cstr_len = max_length; + } + } + cstr_address = GetAddressOf(true, &cstr_address_type); + } else { + // We have a pointer + cstr_address = GetPointerValue(&cstr_address_type); + } + + if (cstr_address == 0 || cstr_address == LLDB_INVALID_ADDRESS) { + if (cstr_address_type == eAddressTypeHost && is_array) { + const char *cstr = GetDataExtractor().PeekCStr(0); + if (cstr == nullptr) { + s << "<invalid address>"; + error.SetErrorString("invalid address"); + CopyStringDataToBufferSP(s, buffer_sp); + return {0, was_capped}; + } + buffer_sp.reset(new DataBufferHeap(cstr_len, 0)); + memcpy(buffer_sp->GetBytes(), cstr, cstr_len); + return {cstr_len, was_capped}; + } else { + s << "<invalid address>"; + error.SetErrorString("invalid address"); + CopyStringDataToBufferSP(s, buffer_sp); + return {0, was_capped}; + } + } + + Address cstr_so_addr(cstr_address); + DataExtractor data; + if (cstr_len > 0 && honor_array) { + // I am using GetPointeeData() here to abstract the fact that some + // ValueObjects are actually frozen pointers in the host + // but the pointed-to data lives in the debuggee, and GetPointeeData() + // automatically takes care of this + GetPointeeData(data, 0, cstr_len); + + if ((bytes_read = data.GetByteSize()) > 0) { + total_bytes_read = bytes_read; + for (size_t offset = 0; offset < bytes_read; offset++) + s.Printf("%c", *data.PeekData(offset, 1)); + if (capped_data) + was_capped = true; + } + } else { + cstr_len = max_length; + const size_t k_max_buf_size = 64; + + size_t offset = 0; + + int cstr_len_displayed = -1; + bool capped_cstr = false; + // I am using GetPointeeData() here to abstract the fact that some + // ValueObjects are actually frozen pointers in the host + // but the pointed-to data lives in the debuggee, and GetPointeeData() + // automatically takes care of this + while ((bytes_read = GetPointeeData(data, offset, k_max_buf_size)) > 0) { + total_bytes_read += bytes_read; + const char *cstr = data.PeekCStr(0); + size_t len = strnlen(cstr, k_max_buf_size); + if (cstr_len_displayed < 0) + cstr_len_displayed = len; + + if (len == 0) + break; + cstr_len_displayed += len; + if (len > bytes_read) + len = bytes_read; + if (len > cstr_len) + len = cstr_len; + + for (size_t offset = 0; offset < bytes_read; offset++) + s.Printf("%c", *data.PeekData(offset, 1)); + + if (len < k_max_buf_size) + break; + + if (len >= cstr_len) { + capped_cstr = true; + break; + } + + cstr_len -= len; + offset += len; + } + + if (cstr_len_displayed >= 0) { + if (capped_cstr) + was_capped = true; + } + } + } else { + error.SetErrorString("not a string object"); + s << "<not a string object>"; + } + CopyStringDataToBufferSP(s, buffer_sp); + return {total_bytes_read, was_capped}; +} + +std::pair<TypeValidatorResult, std::string> ValueObject::GetValidationStatus() { + if (!UpdateValueIfNeeded(true)) + return {TypeValidatorResult::Success, + ""}; // not the validator's job to discuss update problems + + if (m_validation_result.hasValue()) + return m_validation_result.getValue(); + + if (!m_type_validator_sp) + return {TypeValidatorResult::Success, ""}; // no validator no failure + + auto outcome = m_type_validator_sp->FormatObject(this); + + return (m_validation_result = {outcome.m_result, outcome.m_message}) + .getValue(); +} + +const char *ValueObject::GetObjectDescription() { + + if (!UpdateValueIfNeeded(true)) + return NULL; -uint64_t -ValueObject::GetData (DataExtractor& data, Error &error) -{ - UpdateValueIfNeeded(false); - ExecutionContext exe_ctx (GetExecutionContextRef()); - error = m_value.GetValueAsData(&exe_ctx, data, 0, GetModule().get()); - if (error.Fail()) - { - if (m_data.GetByteSize()) - { - data = m_data; - error.Clear(); - return data.GetByteSize(); - } - else - { - return 0; - } - } - data.SetAddressByteSize(m_data.GetAddressByteSize()); - data.SetByteOrder(m_data.GetByteOrder()); - return data.GetByteSize(); -} + if (!m_object_desc_str.empty()) + return m_object_desc_str.c_str(); -bool -ValueObject::SetData (DataExtractor &data, Error &error) -{ - error.Clear(); - // Make sure our value is up to date first so that our location and location - // type is valid. - if (!UpdateValueIfNeeded(false)) - { - error.SetErrorString("unable to read value"); - return false; - } - - uint64_t count = 0; - const Encoding encoding = GetCompilerType().GetEncoding(count); - - const size_t byte_size = GetByteSize(); - - Value::ValueType value_type = m_value.GetValueType(); - - switch (value_type) - { - case Value::eValueTypeScalar: - { - Error set_error = m_value.GetScalar().SetValueFromData(data, encoding, byte_size); - - if (!set_error.Success()) - { - error.SetErrorStringWithFormat("unable to set scalar value: %s", set_error.AsCString()); - return false; - } - } - break; - case Value::eValueTypeLoadAddress: - { - // If it is a load address, then the scalar value is the storage location - // of the data, and we have to shove this value down to that load location. - ExecutionContext exe_ctx (GetExecutionContextRef()); - Process *process = exe_ctx.GetProcessPtr(); - if (process) - { - addr_t target_addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); - size_t bytes_written = process->WriteMemory(target_addr, - data.GetDataStart(), - byte_size, - error); - if (!error.Success()) - return false; - if (bytes_written != byte_size) - { - error.SetErrorString("unable to write value to memory"); - return false; - } - } - } - break; - case Value::eValueTypeHostAddress: - { - // If it is a host address, then we stuff the scalar as a DataBuffer into the Value's data. - DataBufferSP buffer_sp (new DataBufferHeap(byte_size, 0)); - m_data.SetData(buffer_sp, 0); - data.CopyByteOrderedData (0, - byte_size, - const_cast<uint8_t *>(m_data.GetDataStart()), - byte_size, - m_data.GetByteOrder()); - m_value.GetScalar() = (uintptr_t)m_data.GetDataStart(); - } - break; - case Value::eValueTypeFileAddress: - case Value::eValueTypeVector: - break; - } - - // If we have reached this point, then we have successfully changed the value. - SetNeedsUpdate(); - return true; -} + ExecutionContext exe_ctx(GetExecutionContextRef()); + Process *process = exe_ctx.GetProcessPtr(); + if (process == NULL) + return NULL; -static bool -CopyStringDataToBufferSP(const StreamString& source, - lldb::DataBufferSP& destination) -{ - destination.reset(new DataBufferHeap(source.GetSize()+1,0)); - memcpy(destination->GetBytes(), source.GetString().c_str(), source.GetSize()); - return true; -} + StreamString s; -std::pair<size_t,bool> -ValueObject::ReadPointedString (lldb::DataBufferSP& buffer_sp, - Error& error, - uint32_t max_length, - bool honor_array, - Format item_format) -{ - bool was_capped = false; - StreamString s; - ExecutionContext exe_ctx (GetExecutionContextRef()); - Target* target = exe_ctx.GetTargetPtr(); - - if (!target) - { - s << "<no target to read from>"; - error.SetErrorString("no target to read from"); - CopyStringDataToBufferSP(s, buffer_sp); - return {0,was_capped}; - } - - if (max_length == 0) - max_length = target->GetMaximumSizeOfStringSummary(); - - size_t bytes_read = 0; - size_t total_bytes_read = 0; - + LanguageType language = GetObjectRuntimeLanguage(); + LanguageRuntime *runtime = process->GetLanguageRuntime(language); + + if (runtime == NULL) { + // Aw, hell, if the things a pointer, or even just an integer, let's try + // ObjC anyway... CompilerType compiler_type = GetCompilerType(); - CompilerType elem_or_pointee_compiler_type; - const Flags type_flags (GetTypeInfo (&elem_or_pointee_compiler_type)); - if (type_flags.AnySet (eTypeIsArray | eTypeIsPointer) && - elem_or_pointee_compiler_type.IsCharType ()) - { - addr_t cstr_address = LLDB_INVALID_ADDRESS; - AddressType cstr_address_type = eAddressTypeInvalid; - - size_t cstr_len = 0; - bool capped_data = false; - if (type_flags.Test (eTypeIsArray)) - { - // We have an array - uint64_t array_size = 0; - if (compiler_type.IsArrayType(NULL, &array_size, NULL)) - { - cstr_len = array_size; - if (cstr_len > max_length) - { - capped_data = true; - cstr_len = max_length; - } - } - cstr_address = GetAddressOf (true, &cstr_address_type); - } - else - { - // We have a pointer - cstr_address = GetPointerValue (&cstr_address_type); - } - - if (cstr_address == 0 || cstr_address == LLDB_INVALID_ADDRESS) - { - s << "<invalid address>"; - error.SetErrorString("invalid address"); - CopyStringDataToBufferSP(s, buffer_sp); - return {0,was_capped}; - } - - Address cstr_so_addr (cstr_address); - DataExtractor data; - if (cstr_len > 0 && honor_array) - { - // I am using GetPointeeData() here to abstract the fact that some ValueObjects are actually frozen pointers in the host - // but the pointed-to data lives in the debuggee, and GetPointeeData() automatically takes care of this - GetPointeeData(data, 0, cstr_len); - - if ((bytes_read = data.GetByteSize()) > 0) - { - total_bytes_read = bytes_read; - for (size_t offset = 0; offset < bytes_read; offset++) - s.Printf("%c", *data.PeekData(offset, 1)); - if (capped_data) - was_capped = true; - } - } - else - { - cstr_len = max_length; - const size_t k_max_buf_size = 64; - - size_t offset = 0; - - int cstr_len_displayed = -1; - bool capped_cstr = false; - // I am using GetPointeeData() here to abstract the fact that some ValueObjects are actually frozen pointers in the host - // but the pointed-to data lives in the debuggee, and GetPointeeData() automatically takes care of this - while ((bytes_read = GetPointeeData(data, offset, k_max_buf_size)) > 0) - { - total_bytes_read += bytes_read; - const char *cstr = data.PeekCStr(0); - size_t len = strnlen (cstr, k_max_buf_size); - if (cstr_len_displayed < 0) - cstr_len_displayed = len; - - if (len == 0) - break; - cstr_len_displayed += len; - if (len > bytes_read) - len = bytes_read; - if (len > cstr_len) - len = cstr_len; - - for (size_t offset = 0; offset < bytes_read; offset++) - s.Printf("%c", *data.PeekData(offset, 1)); - - if (len < k_max_buf_size) - break; - - if (len >= cstr_len) - { - capped_cstr = true; - break; - } - - cstr_len -= len; - offset += len; - } - - if (cstr_len_displayed >= 0) - { - if (capped_cstr) - was_capped = true; - } - } + if (compiler_type) { + bool is_signed; + if (compiler_type.IsIntegerType(is_signed) || + compiler_type.IsPointerType()) { + runtime = process->GetLanguageRuntime(eLanguageTypeObjC); + } } - else - { - error.SetErrorString("not a string object"); - s << "<not a string object>"; - } - CopyStringDataToBufferSP(s, buffer_sp); - return {total_bytes_read,was_capped}; + } + + if (runtime && runtime->GetObjectDescription(s, *this)) { + m_object_desc_str.append(s.GetString()); + } + + if (m_object_desc_str.empty()) + return NULL; + else + return m_object_desc_str.c_str(); } -std::pair<TypeValidatorResult, std::string> -ValueObject::GetValidationStatus () -{ - if (!UpdateValueIfNeeded(true)) - return {TypeValidatorResult::Success,""}; // not the validator's job to discuss update problems - - if (m_validation_result.hasValue()) - return m_validation_result.getValue(); - - if (!m_type_validator_sp) - return {TypeValidatorResult::Success,""}; // no validator no failure - - auto outcome = m_type_validator_sp->FormatObject(this); - - return (m_validation_result = {outcome.m_result,outcome.m_message}).getValue(); +bool ValueObject::GetValueAsCString(const lldb_private::TypeFormatImpl &format, + std::string &destination) { + if (UpdateValueIfNeeded(false)) + return format.FormatObject(this, destination); + else + return false; } -const char * -ValueObject::GetObjectDescription () -{ - - if (!UpdateValueIfNeeded (true)) - return NULL; +bool ValueObject::GetValueAsCString(lldb::Format format, + std::string &destination) { + return GetValueAsCString(TypeFormatImpl_Format(format), destination); +} + +const char *ValueObject::GetValueAsCString() { + if (UpdateValueIfNeeded(true)) { + lldb::TypeFormatImplSP format_sp; + lldb::Format my_format = GetFormat(); + if (my_format == lldb::eFormatDefault) { + if (m_type_format_sp) + format_sp = m_type_format_sp; + else { + if (m_is_bitfield_for_scalar) + my_format = eFormatUnsigned; + else { + if (m_value.GetContextType() == Value::eContextTypeRegisterInfo) { + const RegisterInfo *reg_info = m_value.GetRegisterInfo(); + if (reg_info) + my_format = reg_info->format; + } else { + my_format = GetValue().GetCompilerType().GetFormat(); + } + } + } + } + if (my_format != m_last_format || m_value_str.empty()) { + m_last_format = my_format; + if (!format_sp) + format_sp.reset(new TypeFormatImpl_Format(my_format)); + if (GetValueAsCString(*format_sp.get(), m_value_str)) { + if (!m_value_did_change && m_old_value_valid) { + // The value was gotten successfully, so we consider the + // value as changed if the value string differs + SetValueDidChange(m_old_value_str != m_value_str); + } + } + } + } + if (m_value_str.empty()) + return NULL; + return m_value_str.c_str(); +} - if (!m_object_desc_str.empty()) - return m_object_desc_str.c_str(); +// if > 8bytes, 0 is returned. this method should mostly be used +// to read address values out of pointers +uint64_t ValueObject::GetValueAsUnsigned(uint64_t fail_value, bool *success) { + // If our byte size is zero this is an aggregate type that has children + if (CanProvideValue()) { + Scalar scalar; + if (ResolveValue(scalar)) { + if (success) + *success = true; + return scalar.ULongLong(fail_value); + } + // fallthrough, otherwise... + } + + if (success) + *success = false; + return fail_value; +} + +int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) { + // If our byte size is zero this is an aggregate type that has children + if (CanProvideValue()) { + Scalar scalar; + if (ResolveValue(scalar)) { + if (success) + *success = true; + return scalar.SLongLong(fail_value); + } + // fallthrough, otherwise... + } + + if (success) + *success = false; + return fail_value; +} + +// if any more "special cases" are added to +// ValueObject::DumpPrintableRepresentation() please keep +// this call up to date by returning true for your new special cases. We will +// eventually move +// to checking this call result before trying to display special cases +bool ValueObject::HasSpecialPrintableRepresentation( + ValueObjectRepresentationStyle val_obj_display, Format custom_format) { + Flags flags(GetTypeInfo()); + if (flags.AnySet(eTypeIsArray | eTypeIsPointer) && + val_obj_display == ValueObject::eValueObjectRepresentationStyleValue) { + if (IsCStringContainer(true) && + (custom_format == eFormatCString || custom_format == eFormatCharArray || + custom_format == eFormatChar || custom_format == eFormatVectorOfChar)) + return true; + + if (flags.Test(eTypeIsArray)) { + if ((custom_format == eFormatBytes) || + (custom_format == eFormatBytesWithASCII)) + return true; - ExecutionContext exe_ctx (GetExecutionContextRef()); - Process *process = exe_ctx.GetProcessPtr(); - if (process == NULL) - return NULL; - - StreamString s; - - LanguageType language = GetObjectRuntimeLanguage(); - LanguageRuntime *runtime = process->GetLanguageRuntime(language); - - if (runtime == NULL) - { - // Aw, hell, if the things a pointer, or even just an integer, let's try ObjC anyway... - CompilerType compiler_type = GetCompilerType(); - if (compiler_type) - { - bool is_signed; - if (compiler_type.IsIntegerType (is_signed) || compiler_type.IsPointerType ()) - { - runtime = process->GetLanguageRuntime(eLanguageTypeObjC); - } - } - } - - if (runtime && runtime->GetObjectDescription(s, *this)) - { - m_object_desc_str.append (s.GetData()); + if ((custom_format == eFormatVectorOfChar) || + (custom_format == eFormatVectorOfFloat32) || + (custom_format == eFormatVectorOfFloat64) || + (custom_format == eFormatVectorOfSInt16) || + (custom_format == eFormatVectorOfSInt32) || + (custom_format == eFormatVectorOfSInt64) || + (custom_format == eFormatVectorOfSInt8) || + (custom_format == eFormatVectorOfUInt128) || + (custom_format == eFormatVectorOfUInt16) || + (custom_format == eFormatVectorOfUInt32) || + (custom_format == eFormatVectorOfUInt64) || + (custom_format == eFormatVectorOfUInt8)) + return true; } - - if (m_object_desc_str.empty()) - return NULL; - else - return m_object_desc_str.c_str(); + } + return false; } -bool -ValueObject::GetValueAsCString (const lldb_private::TypeFormatImpl& format, - std::string& destination) -{ - if (UpdateValueIfNeeded(false)) - return format.FormatObject(this,destination); - else - return false; -} +bool ValueObject::DumpPrintableRepresentation( + Stream &s, ValueObjectRepresentationStyle val_obj_display, + Format custom_format, PrintableRepresentationSpecialCases special, + bool do_dump_error) { -bool -ValueObject::GetValueAsCString (lldb::Format format, - std::string& destination) -{ - return GetValueAsCString(TypeFormatImpl_Format(format),destination); -} + Flags flags(GetTypeInfo()); -const char * -ValueObject::GetValueAsCString () -{ - if (UpdateValueIfNeeded(true)) - { - lldb::TypeFormatImplSP format_sp; - lldb::Format my_format = GetFormat(); - if (my_format == lldb::eFormatDefault) - { - if (m_type_format_sp) - format_sp = m_type_format_sp; - else - { - if (m_is_bitfield_for_scalar) - my_format = eFormatUnsigned; - else - { - if (m_value.GetContextType() == Value::eContextTypeRegisterInfo) - { - const RegisterInfo *reg_info = m_value.GetRegisterInfo(); - if (reg_info) - my_format = reg_info->format; - } - else - { - my_format = GetValue().GetCompilerType().GetFormat(); - } - } - } - } - if (my_format != m_last_format || m_value_str.empty()) - { - m_last_format = my_format; - if (!format_sp) - format_sp.reset(new TypeFormatImpl_Format(my_format)); - if (GetValueAsCString(*format_sp.get(), m_value_str)) - { - if (!m_value_did_change && m_old_value_valid) - { - // The value was gotten successfully, so we consider the - // value as changed if the value string differs - SetValueDidChange (m_old_value_str != m_value_str); - } - } - } - } - if (m_value_str.empty()) - return NULL; - return m_value_str.c_str(); -} + bool allow_special = + (special == ValueObject::PrintableRepresentationSpecialCases::eAllow); + const bool only_special = false; -// if > 8bytes, 0 is returned. this method should mostly be used -// to read address values out of pointers -uint64_t -ValueObject::GetValueAsUnsigned (uint64_t fail_value, bool *success) -{ - // If our byte size is zero this is an aggregate type that has children - if (CanProvideValue()) - { - Scalar scalar; - if (ResolveValue (scalar)) - { - if (success) - *success = true; - return scalar.ULongLong(fail_value); - } - // fallthrough, otherwise... - } + if (allow_special) { + if (flags.AnySet(eTypeIsArray | eTypeIsPointer) && + val_obj_display == ValueObject::eValueObjectRepresentationStyleValue) { + // when being asked to get a printable display an array or pointer type + // directly, + // try to "do the right thing" - if (success) - *success = false; - return fail_value; -} + if (IsCStringContainer(true) && + (custom_format == eFormatCString || + custom_format == eFormatCharArray || custom_format == eFormatChar || + custom_format == + eFormatVectorOfChar)) // print char[] & char* directly + { + Error error; + lldb::DataBufferSP buffer_sp; + std::pair<size_t, bool> read_string = ReadPointedString( + buffer_sp, error, 0, (custom_format == eFormatVectorOfChar) || + (custom_format == eFormatCharArray)); + lldb_private::formatters::StringPrinter:: + ReadBufferAndDumpToStreamOptions options(*this); + options.SetData(DataExtractor( + buffer_sp, lldb::eByteOrderInvalid, + 8)); // none of this matters for a string - pass some defaults + options.SetStream(&s); + options.SetPrefixToken(0); + options.SetQuote('"'); + options.SetSourceSize(buffer_sp->GetByteSize()); + options.SetIsTruncated(read_string.second); + formatters::StringPrinter::ReadBufferAndDumpToStream< + lldb_private::formatters::StringPrinter::StringElementType::ASCII>( + options); + return !error.Fail(); + } + + if (custom_format == eFormatEnum) + return false; -int64_t -ValueObject::GetValueAsSigned (int64_t fail_value, bool *success) -{ - // If our byte size is zero this is an aggregate type that has children - if (CanProvideValue()) - { - Scalar scalar; - if (ResolveValue (scalar)) - { - if (success) - *success = true; - return scalar.SLongLong(fail_value); - } - // fallthrough, otherwise... - } - - if (success) - *success = false; - return fail_value; -} + // this only works for arrays, because I have no way to know when + // the pointed memory ends, and no special \0 end of data marker + if (flags.Test(eTypeIsArray)) { + if ((custom_format == eFormatBytes) || + (custom_format == eFormatBytesWithASCII)) { + const size_t count = GetNumChildren(); -// if any more "special cases" are added to ValueObject::DumpPrintableRepresentation() please keep -// this call up to date by returning true for your new special cases. We will eventually move -// to checking this call result before trying to display special cases -bool -ValueObject::HasSpecialPrintableRepresentation(ValueObjectRepresentationStyle val_obj_display, - Format custom_format) -{ - Flags flags(GetTypeInfo()); - if (flags.AnySet(eTypeIsArray | eTypeIsPointer) - && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue) - { - if (IsCStringContainer(true) && - (custom_format == eFormatCString || - custom_format == eFormatCharArray || - custom_format == eFormatChar || - custom_format == eFormatVectorOfChar)) - return true; - - if (flags.Test(eTypeIsArray)) - { - if ((custom_format == eFormatBytes) || - (custom_format == eFormatBytesWithASCII)) - return true; - - if ((custom_format == eFormatVectorOfChar) || - (custom_format == eFormatVectorOfFloat32) || - (custom_format == eFormatVectorOfFloat64) || - (custom_format == eFormatVectorOfSInt16) || - (custom_format == eFormatVectorOfSInt32) || - (custom_format == eFormatVectorOfSInt64) || - (custom_format == eFormatVectorOfSInt8) || - (custom_format == eFormatVectorOfUInt128) || - (custom_format == eFormatVectorOfUInt16) || - (custom_format == eFormatVectorOfUInt32) || - (custom_format == eFormatVectorOfUInt64) || - (custom_format == eFormatVectorOfUInt8)) - return true; - } - } - return false; -} + s << '['; + for (size_t low = 0; low < count; low++) { -bool -ValueObject::DumpPrintableRepresentation(Stream& s, - ValueObjectRepresentationStyle val_obj_display, - Format custom_format, - PrintableRepresentationSpecialCases special, - bool do_dump_error) -{ - - Flags flags(GetTypeInfo()); - - bool allow_special = ((special & ePrintableRepresentationSpecialCasesAllow) == ePrintableRepresentationSpecialCasesAllow); - bool only_special = ((special & ePrintableRepresentationSpecialCasesOnly) == ePrintableRepresentationSpecialCasesOnly); - - if (allow_special) - { - if (flags.AnySet(eTypeIsArray | eTypeIsPointer) - && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue) - { - // when being asked to get a printable display an array or pointer type directly, - // try to "do the right thing" - - if (IsCStringContainer(true) && - (custom_format == eFormatCString || - custom_format == eFormatCharArray || - custom_format == eFormatChar || - custom_format == eFormatVectorOfChar)) // print char[] & char* directly - { - Error error; - lldb::DataBufferSP buffer_sp; - std::pair<size_t, bool> read_string = ReadPointedString(buffer_sp, - error, - 0, - (custom_format == eFormatVectorOfChar) || - (custom_format == eFormatCharArray)); - lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStreamOptions options(*this); - options.SetData(DataExtractor(buffer_sp, lldb::eByteOrderInvalid, 8)); // none of this matters for a string - pass some defaults - options.SetStream(&s); - options.SetPrefixToken(0); - options.SetQuote('"'); - options.SetSourceSize(buffer_sp->GetByteSize()); - options.SetIsTruncated(read_string.second); - formatters::StringPrinter::ReadBufferAndDumpToStream<lldb_private::formatters::StringPrinter::StringElementType::ASCII>(options); - return !error.Fail(); + if (low) + s << ','; + + ValueObjectSP child = GetChildAtIndex(low, true); + if (!child.get()) { + s << "<invalid child>"; + continue; } - - if (custom_format == eFormatEnum) - return false; - - // this only works for arrays, because I have no way to know when - // the pointed memory ends, and no special \0 end of data marker - if (flags.Test(eTypeIsArray)) - { - if ((custom_format == eFormatBytes) || - (custom_format == eFormatBytesWithASCII)) - { - const size_t count = GetNumChildren(); - - s << '['; - for (size_t low = 0; low < count; low++) - { - - if (low) - s << ','; - - ValueObjectSP child = GetChildAtIndex(low,true); - if (!child.get()) - { - s << "<invalid child>"; - continue; - } - child->DumpPrintableRepresentation(s, ValueObject::eValueObjectRepresentationStyleValue, custom_format); - } - - s << ']'; - - return true; - } - - if ((custom_format == eFormatVectorOfChar) || - (custom_format == eFormatVectorOfFloat32) || - (custom_format == eFormatVectorOfFloat64) || - (custom_format == eFormatVectorOfSInt16) || - (custom_format == eFormatVectorOfSInt32) || - (custom_format == eFormatVectorOfSInt64) || - (custom_format == eFormatVectorOfSInt8) || - (custom_format == eFormatVectorOfUInt128) || - (custom_format == eFormatVectorOfUInt16) || - (custom_format == eFormatVectorOfUInt32) || - (custom_format == eFormatVectorOfUInt64) || - (custom_format == eFormatVectorOfUInt8)) // arrays of bytes, bytes with ASCII or any vector format should be printed directly - { - const size_t count = GetNumChildren(); - - Format format = FormatManager::GetSingleItemFormat(custom_format); - - s << '['; - for (size_t low = 0; low < count; low++) - { - - if (low) - s << ','; - - ValueObjectSP child = GetChildAtIndex(low,true); - if (!child.get()) - { - s << "<invalid child>"; - continue; - } - child->DumpPrintableRepresentation(s, ValueObject::eValueObjectRepresentationStyleValue, format); - } - - s << ']'; - - return true; - } + child->DumpPrintableRepresentation( + s, ValueObject::eValueObjectRepresentationStyleValue, + custom_format); + } + + s << ']'; + + return true; + } + + if ((custom_format == eFormatVectorOfChar) || + (custom_format == eFormatVectorOfFloat32) || + (custom_format == eFormatVectorOfFloat64) || + (custom_format == eFormatVectorOfSInt16) || + (custom_format == eFormatVectorOfSInt32) || + (custom_format == eFormatVectorOfSInt64) || + (custom_format == eFormatVectorOfSInt8) || + (custom_format == eFormatVectorOfUInt128) || + (custom_format == eFormatVectorOfUInt16) || + (custom_format == eFormatVectorOfUInt32) || + (custom_format == eFormatVectorOfUInt64) || + (custom_format == eFormatVectorOfUInt8)) // arrays of bytes, bytes + // with ASCII or any vector + // format should be printed + // directly + { + const size_t count = GetNumChildren(); + + Format format = FormatManager::GetSingleItemFormat(custom_format); + + s << '['; + for (size_t low = 0; low < count; low++) { + + if (low) + s << ','; + + ValueObjectSP child = GetChildAtIndex(low, true); + if (!child.get()) { + s << "<invalid child>"; + continue; } - - if ((custom_format == eFormatBoolean) || - (custom_format == eFormatBinary) || - (custom_format == eFormatChar) || - (custom_format == eFormatCharPrintable) || - (custom_format == eFormatComplexFloat) || - (custom_format == eFormatDecimal) || - (custom_format == eFormatHex) || - (custom_format == eFormatHexUppercase) || - (custom_format == eFormatFloat) || - (custom_format == eFormatOctal) || - (custom_format == eFormatOSType) || - (custom_format == eFormatUnicode16) || - (custom_format == eFormatUnicode32) || - (custom_format == eFormatUnsigned) || - (custom_format == eFormatPointer) || - (custom_format == eFormatComplexInteger) || - (custom_format == eFormatComplex) || - (custom_format == eFormatDefault)) // use the [] operator - return false; - } - } - - if (only_special) + child->DumpPrintableRepresentation( + s, ValueObject::eValueObjectRepresentationStyleValue, format); + } + + s << ']'; + + return true; + } + } + + if ((custom_format == eFormatBoolean) || + (custom_format == eFormatBinary) || (custom_format == eFormatChar) || + (custom_format == eFormatCharPrintable) || + (custom_format == eFormatComplexFloat) || + (custom_format == eFormatDecimal) || (custom_format == eFormatHex) || + (custom_format == eFormatHexUppercase) || + (custom_format == eFormatFloat) || (custom_format == eFormatOctal) || + (custom_format == eFormatOSType) || + (custom_format == eFormatUnicode16) || + (custom_format == eFormatUnicode32) || + (custom_format == eFormatUnsigned) || + (custom_format == eFormatPointer) || + (custom_format == eFormatComplexInteger) || + (custom_format == eFormatComplex) || + (custom_format == eFormatDefault)) // use the [] operator return false; - - bool var_success = false; - - { - const char *cstr = NULL; - - // this is a local stream that we are using to ensure that the data pointed to by cstr survives - // long enough for us to copy it to its destination - it is necessary to have this temporary storage - // area for cases where our desired output is not backed by some other longer-term storage - StreamString strm; - - if (custom_format != eFormatInvalid) - SetFormat(custom_format); - - switch(val_obj_display) - { - case eValueObjectRepresentationStyleValue: - cstr = GetValueAsCString(); - break; - - case eValueObjectRepresentationStyleSummary: - cstr = GetSummaryAsCString(); - break; - - case eValueObjectRepresentationStyleLanguageSpecific: - cstr = GetObjectDescription(); - break; - - case eValueObjectRepresentationStyleLocation: - cstr = GetLocationAsCString(); - break; - - case eValueObjectRepresentationStyleChildrenCount: - strm.Printf("%" PRIu64 "", (uint64_t)GetNumChildren()); - cstr = strm.GetString().c_str(); - break; - - case eValueObjectRepresentationStyleType: - cstr = GetTypeName().AsCString(); - break; - - case eValueObjectRepresentationStyleName: - cstr = GetName().AsCString(); - break; - - case eValueObjectRepresentationStyleExpressionPath: - GetExpressionPath(strm, false); - cstr = strm.GetString().c_str(); - break; - } - - if (!cstr) - { - if (val_obj_display == eValueObjectRepresentationStyleValue) - cstr = GetSummaryAsCString(); - else if (val_obj_display == eValueObjectRepresentationStyleSummary) - { - if (!CanProvideValue()) - { - strm.Printf("%s @ %s", GetTypeName().AsCString(), GetLocationAsCString()); - cstr = strm.GetString().c_str(); - } - else - cstr = GetValueAsCString(); - } - } - - if (cstr) - s.PutCString(cstr); - else - { - if (m_error.Fail()) - { - if (do_dump_error) - s.Printf("<%s>", m_error.AsCString()); - else - return false; - } - else if (val_obj_display == eValueObjectRepresentationStyleSummary) - s.PutCString("<no summary available>"); - else if (val_obj_display == eValueObjectRepresentationStyleValue) - s.PutCString("<no value available>"); - else if (val_obj_display == eValueObjectRepresentationStyleLanguageSpecific) - s.PutCString("<not a valid Objective-C object>"); // edit this if we have other runtimes that support a description - else - s.PutCString("<no printable representation>"); - } - - // we should only return false here if we could not do *anything* - // even if we have an error message as output, that's a success - // from our callers' perspective, so return true - var_success = true; - - if (custom_format != eFormatInvalid) - SetFormat(eFormatDefault); } - - return var_success; -} + } -addr_t -ValueObject::GetAddressOf (bool scalar_is_load_address, AddressType *address_type) -{ - // Can't take address of a bitfield - if (IsBitfield()) - return LLDB_INVALID_ADDRESS; - - if (!UpdateValueIfNeeded(false)) - return LLDB_INVALID_ADDRESS; - - switch (m_value.GetValueType()) - { - case Value::eValueTypeScalar: - case Value::eValueTypeVector: - if (scalar_is_load_address) - { - if(address_type) - *address_type = eAddressTypeLoad; - return m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); - } - break; + if (only_special) + return false; - case Value::eValueTypeLoadAddress: - case Value::eValueTypeFileAddress: - { - if(address_type) - *address_type = m_value.GetValueAddressType (); - return m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); - } - break; - case Value::eValueTypeHostAddress: - { - if(address_type) - *address_type = m_value.GetValueAddressType (); - return LLDB_INVALID_ADDRESS; - } - break; - } - if (address_type) - *address_type = eAddressTypeInvalid; + bool var_success = false; + + { + llvm::StringRef str; + + // this is a local stream that we are using to ensure that the data pointed + // to by cstr survives long enough for us to copy it to its destination - it + // is necessary to have this temporary storage area for cases where our + // desired output is not backed by some other longer-term storage + StreamString strm; + + if (custom_format != eFormatInvalid) + SetFormat(custom_format); + + switch (val_obj_display) { + case eValueObjectRepresentationStyleValue: + str = GetValueAsCString(); + break; + + case eValueObjectRepresentationStyleSummary: + str = GetSummaryAsCString(); + break; + + case eValueObjectRepresentationStyleLanguageSpecific: + str = GetObjectDescription(); + break; + + case eValueObjectRepresentationStyleLocation: + str = GetLocationAsCString(); + break; + + case eValueObjectRepresentationStyleChildrenCount: + strm.Printf("%" PRIu64 "", (uint64_t)GetNumChildren()); + str = strm.GetString(); + break; + + case eValueObjectRepresentationStyleType: + str = GetTypeName().GetStringRef(); + break; + + case eValueObjectRepresentationStyleName: + str = GetName().GetStringRef(); + break; + + case eValueObjectRepresentationStyleExpressionPath: + GetExpressionPath(strm, false); + str = strm.GetString(); + break; + } + + if (str.empty()) { + if (val_obj_display == eValueObjectRepresentationStyleValue) + str = GetSummaryAsCString(); + else if (val_obj_display == eValueObjectRepresentationStyleSummary) { + if (!CanProvideValue()) { + strm.Printf("%s @ %s", GetTypeName().AsCString(), + GetLocationAsCString()); + str = strm.GetString(); + } else + str = GetValueAsCString(); + } + } + + if (!str.empty()) + s << str; + else { + if (m_error.Fail()) { + if (do_dump_error) + s.Printf("<%s>", m_error.AsCString()); + else + return false; + } else if (val_obj_display == eValueObjectRepresentationStyleSummary) + s.PutCString("<no summary available>"); + else if (val_obj_display == eValueObjectRepresentationStyleValue) + s.PutCString("<no value available>"); + else if (val_obj_display == + eValueObjectRepresentationStyleLanguageSpecific) + s.PutCString("<not a valid Objective-C object>"); // edit this if we + // have other runtimes + // that support a + // description + else + s.PutCString("<no printable representation>"); + } + + // we should only return false here if we could not do *anything* + // even if we have an error message as output, that's a success + // from our callers' perspective, so return true + var_success = true; + + if (custom_format != eFormatInvalid) + SetFormat(eFormatDefault); + } + + return var_success; +} + +addr_t ValueObject::GetAddressOf(bool scalar_is_load_address, + AddressType *address_type) { + // Can't take address of a bitfield + if (IsBitfield()) return LLDB_INVALID_ADDRESS; -} -addr_t -ValueObject::GetPointerValue (AddressType *address_type) -{ - addr_t address = LLDB_INVALID_ADDRESS; - if(address_type) - *address_type = eAddressTypeInvalid; - - if (!UpdateValueIfNeeded(false)) - return address; - - switch (m_value.GetValueType()) - { - case Value::eValueTypeScalar: - case Value::eValueTypeVector: - address = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); - break; + if (!UpdateValueIfNeeded(false)) + return LLDB_INVALID_ADDRESS; - case Value::eValueTypeHostAddress: - case Value::eValueTypeLoadAddress: - case Value::eValueTypeFileAddress: - { - lldb::offset_t data_offset = 0; - address = m_data.GetPointer(&data_offset); - } - break; + switch (m_value.GetValueType()) { + case Value::eValueTypeScalar: + case Value::eValueTypeVector: + if (scalar_is_load_address) { + if (address_type) + *address_type = eAddressTypeLoad; + return m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); } + break; + case Value::eValueTypeLoadAddress: + case Value::eValueTypeFileAddress: { if (address_type) - *address_type = GetAddressTypeOfChildren(); + *address_type = m_value.GetValueAddressType(); + return m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + } break; + case Value::eValueTypeHostAddress: { + if (address_type) + *address_type = m_value.GetValueAddressType(); + return LLDB_INVALID_ADDRESS; + } break; + } + if (address_type) + *address_type = eAddressTypeInvalid; + return LLDB_INVALID_ADDRESS; +} +addr_t ValueObject::GetPointerValue(AddressType *address_type) { + addr_t address = LLDB_INVALID_ADDRESS; + if (address_type) + *address_type = eAddressTypeInvalid; + + if (!UpdateValueIfNeeded(false)) return address; -} -bool -ValueObject::SetValueFromCString (const char *value_str, Error& error) -{ - error.Clear(); - // Make sure our value is up to date first so that our location and location - // type is valid. - if (!UpdateValueIfNeeded(false)) - { - error.SetErrorString("unable to read value"); - return false; - } + switch (m_value.GetValueType()) { + case Value::eValueTypeScalar: + case Value::eValueTypeVector: + address = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + break; - uint64_t count = 0; - const Encoding encoding = GetCompilerType().GetEncoding (count); + case Value::eValueTypeHostAddress: + case Value::eValueTypeLoadAddress: + case Value::eValueTypeFileAddress: { + lldb::offset_t data_offset = 0; + address = m_data.GetPointer(&data_offset); + } break; + } - const size_t byte_size = GetByteSize(); + if (address_type) + *address_type = GetAddressTypeOfChildren(); - Value::ValueType value_type = m_value.GetValueType(); - - if (value_type == Value::eValueTypeScalar) - { - // If the value is already a scalar, then let the scalar change itself: - m_value.GetScalar().SetValueFromCString (value_str, encoding, byte_size); - } - else if (byte_size <= 16) - { - // If the value fits in a scalar, then make a new scalar and again let the - // scalar code do the conversion, then figure out where to put the new value. - Scalar new_scalar; - error = new_scalar.SetValueFromCString (value_str, encoding, byte_size); - if (error.Success()) - { - switch (value_type) - { - case Value::eValueTypeLoadAddress: - { - // If it is a load address, then the scalar value is the storage location - // of the data, and we have to shove this value down to that load location. - ExecutionContext exe_ctx (GetExecutionContextRef()); - Process *process = exe_ctx.GetProcessPtr(); - if (process) - { - addr_t target_addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); - size_t bytes_written = process->WriteScalarToMemory (target_addr, - new_scalar, - byte_size, - error); - if (!error.Success()) - return false; - if (bytes_written != byte_size) - { - error.SetErrorString("unable to write value to memory"); - return false; - } - } - } - break; - case Value::eValueTypeHostAddress: - { - // If it is a host address, then we stuff the scalar as a DataBuffer into the Value's data. - DataExtractor new_data; - new_data.SetByteOrder (m_data.GetByteOrder()); - - DataBufferSP buffer_sp (new DataBufferHeap(byte_size, 0)); - m_data.SetData(buffer_sp, 0); - bool success = new_scalar.GetData(new_data); - if (success) - { - new_data.CopyByteOrderedData (0, - byte_size, - const_cast<uint8_t *>(m_data.GetDataStart()), - byte_size, - m_data.GetByteOrder()); - } - m_value.GetScalar() = (uintptr_t)m_data.GetDataStart(); - - } - break; - case Value::eValueTypeFileAddress: - case Value::eValueTypeScalar: - case Value::eValueTypeVector: - break; - } - } - else - { - return false; - } - } - else - { - // We don't support setting things bigger than a scalar at present. - error.SetErrorString("unable to write aggregate data type"); - return false; - } - - // If we have reached this point, then we have successfully changed the value. - SetNeedsUpdate(); - return true; + return address; } -bool -ValueObject::GetDeclaration (Declaration &decl) -{ - decl.Clear(); +bool ValueObject::SetValueFromCString(const char *value_str, Error &error) { + error.Clear(); + // Make sure our value is up to date first so that our location and location + // type is valid. + if (!UpdateValueIfNeeded(false)) { + error.SetErrorString("unable to read value"); return false; -} + } + + uint64_t count = 0; + const Encoding encoding = GetCompilerType().GetEncoding(count); + + const size_t byte_size = GetByteSize(); + + Value::ValueType value_type = m_value.GetValueType(); + + if (value_type == Value::eValueTypeScalar) { + // If the value is already a scalar, then let the scalar change itself: + m_value.GetScalar().SetValueFromCString(value_str, encoding, byte_size); + } else if (byte_size <= 16) { + // If the value fits in a scalar, then make a new scalar and again let the + // scalar code do the conversion, then figure out where to put the new + // value. + Scalar new_scalar; + error = new_scalar.SetValueFromCString(value_str, encoding, byte_size); + if (error.Success()) { + switch (value_type) { + case Value::eValueTypeLoadAddress: { + // If it is a load address, then the scalar value is the storage + // location + // of the data, and we have to shove this value down to that load + // location. + ExecutionContext exe_ctx(GetExecutionContextRef()); + Process *process = exe_ctx.GetProcessPtr(); + if (process) { + addr_t target_addr = + m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + size_t bytes_written = process->WriteScalarToMemory( + target_addr, new_scalar, byte_size, error); + if (!error.Success()) + return false; + if (bytes_written != byte_size) { + error.SetErrorString("unable to write value to memory"); + return false; + } + } + } break; + case Value::eValueTypeHostAddress: { + // If it is a host address, then we stuff the scalar as a DataBuffer + // into the Value's data. + DataExtractor new_data; + new_data.SetByteOrder(m_data.GetByteOrder()); + + DataBufferSP buffer_sp(new DataBufferHeap(byte_size, 0)); + m_data.SetData(buffer_sp, 0); + bool success = new_scalar.GetData(new_data); + if (success) { + new_data.CopyByteOrderedData( + 0, byte_size, const_cast<uint8_t *>(m_data.GetDataStart()), + byte_size, m_data.GetByteOrder()); + } + m_value.GetScalar() = (uintptr_t)m_data.GetDataStart(); + + } break; + case Value::eValueTypeFileAddress: + case Value::eValueTypeScalar: + case Value::eValueTypeVector: + break; + } + } else { + return false; + } + } else { + // We don't support setting things bigger than a scalar at present. + error.SetErrorString("unable to write aggregate data type"); + return false; + } -ConstString -ValueObject::GetTypeName() -{ - return GetCompilerType().GetConstTypeName(); + // If we have reached this point, then we have successfully changed the value. + SetNeedsUpdate(); + return true; } -ConstString -ValueObject::GetDisplayTypeName() -{ - return GetTypeName(); +bool ValueObject::GetDeclaration(Declaration &decl) { + decl.Clear(); + return false; } -ConstString -ValueObject::GetQualifiedTypeName() -{ - return GetCompilerType().GetConstQualifiedTypeName(); +ConstString ValueObject::GetTypeName() { + return GetCompilerType().GetConstTypeName(); } +ConstString ValueObject::GetDisplayTypeName() { return GetTypeName(); } -LanguageType -ValueObject::GetObjectRuntimeLanguage () -{ - return GetCompilerType().GetMinimumLanguage (); +ConstString ValueObject::GetQualifiedTypeName() { + return GetCompilerType().GetConstQualifiedTypeName(); } -void -ValueObject::AddSyntheticChild (const ConstString &key, ValueObject *valobj) -{ - m_synthetic_children[key] = valobj; +LanguageType ValueObject::GetObjectRuntimeLanguage() { + return GetCompilerType().GetMinimumLanguage(); } -ValueObjectSP -ValueObject::GetSyntheticChild (const ConstString &key) const -{ - ValueObjectSP synthetic_child_sp; - std::map<ConstString, ValueObject *>::const_iterator pos = m_synthetic_children.find (key); - if (pos != m_synthetic_children.end()) - synthetic_child_sp = pos->second->GetSP(); - return synthetic_child_sp; +void ValueObject::AddSyntheticChild(const ConstString &key, + ValueObject *valobj) { + m_synthetic_children[key] = valobj; } -uint32_t -ValueObject::GetTypeInfo (CompilerType *pointee_or_element_compiler_type) -{ - return GetCompilerType().GetTypeInfo (pointee_or_element_compiler_type); +ValueObjectSP ValueObject::GetSyntheticChild(const ConstString &key) const { + ValueObjectSP synthetic_child_sp; + std::map<ConstString, ValueObject *>::const_iterator pos = + m_synthetic_children.find(key); + if (pos != m_synthetic_children.end()) + synthetic_child_sp = pos->second->GetSP(); + return synthetic_child_sp; } -bool -ValueObject::IsPointerType () -{ - return GetCompilerType().IsPointerType(); +uint32_t +ValueObject::GetTypeInfo(CompilerType *pointee_or_element_compiler_type) { + return GetCompilerType().GetTypeInfo(pointee_or_element_compiler_type); } -bool -ValueObject::IsArrayType () -{ - return GetCompilerType().IsArrayType (NULL, NULL, NULL); -} +bool ValueObject::IsPointerType() { return GetCompilerType().IsPointerType(); } -bool -ValueObject::IsScalarType () -{ - return GetCompilerType().IsScalarType (); +bool ValueObject::IsArrayType() { + return GetCompilerType().IsArrayType(NULL, NULL, NULL); } -bool -ValueObject::IsIntegerType (bool &is_signed) -{ - return GetCompilerType().IsIntegerType (is_signed); +bool ValueObject::IsScalarType() { return GetCompilerType().IsScalarType(); } + +bool ValueObject::IsIntegerType(bool &is_signed) { + return GetCompilerType().IsIntegerType(is_signed); } -bool -ValueObject::IsPointerOrReferenceType () -{ - return GetCompilerType().IsPointerOrReferenceType (); +bool ValueObject::IsPointerOrReferenceType() { + return GetCompilerType().IsPointerOrReferenceType(); } -bool -ValueObject::IsPossibleDynamicType () -{ - ExecutionContext exe_ctx (GetExecutionContextRef()); - Process *process = exe_ctx.GetProcessPtr(); - if (process) - return process->IsPossibleDynamicValue(*this); - else - return GetCompilerType().IsPossibleDynamicType (NULL, true, true); +bool ValueObject::IsPossibleDynamicType() { + ExecutionContext exe_ctx(GetExecutionContextRef()); + Process *process = exe_ctx.GetProcessPtr(); + if (process) + return process->IsPossibleDynamicValue(*this); + else + return GetCompilerType().IsPossibleDynamicType(NULL, true, true); } -bool -ValueObject::IsRuntimeSupportValue () -{ - Process *process(GetProcessSP().get()); - if (process) - { - LanguageRuntime *runtime = process->GetLanguageRuntime(GetObjectRuntimeLanguage()); - if (!runtime) - runtime = process->GetObjCLanguageRuntime(); - if (runtime) - return runtime->IsRuntimeSupportValue(*this); - } - return false; +bool ValueObject::IsRuntimeSupportValue() { + Process *process(GetProcessSP().get()); + if (process) { + LanguageRuntime *runtime = + process->GetLanguageRuntime(GetObjectRuntimeLanguage()); + if (!runtime) + runtime = process->GetObjCLanguageRuntime(); + if (runtime) + return runtime->IsRuntimeSupportValue(*this); + } + return false; } -bool -ValueObject::IsNilReference () -{ - if (Language *language = Language::FindPlugin(GetObjectRuntimeLanguage())) - { - return language->IsNilReference(*this); - } - return false; +bool ValueObject::IsNilReference() { + if (Language *language = Language::FindPlugin(GetObjectRuntimeLanguage())) { + return language->IsNilReference(*this); + } + return false; } -bool -ValueObject::IsUninitializedReference () -{ - if (Language *language = Language::FindPlugin(GetObjectRuntimeLanguage())) - { - return language->IsUninitializedReference(*this); - } - return false; +bool ValueObject::IsUninitializedReference() { + if (Language *language = Language::FindPlugin(GetObjectRuntimeLanguage())) { + return language->IsUninitializedReference(*this); + } + return false; } // This allows you to create an array member using and index @@ -2104,2243 +1756,1694 @@ ValueObject::IsUninitializedReference () // The size of the "item_array" is 1, but many times in practice // there are more items in "item_array". -ValueObjectSP -ValueObject::GetSyntheticArrayMember (size_t index, bool can_create) -{ - ValueObjectSP synthetic_child_sp; - if (IsPointerType () || IsArrayType()) - { - char index_str[64]; - snprintf(index_str, sizeof(index_str), "[%" PRIu64 "]", (uint64_t)index); - ConstString index_const_str(index_str); - // Check if we have already created a synthetic array member in this - // valid object. If we have we will re-use it. - synthetic_child_sp = GetSyntheticChild (index_const_str); - if (!synthetic_child_sp) - { - ValueObject *synthetic_child; - // We haven't made a synthetic array member for INDEX yet, so - // lets make one and cache it for any future reference. - synthetic_child = CreateChildAtIndex(0, true, index); - - // Cache the value if we got one back... - if (synthetic_child) - { - AddSyntheticChild(index_const_str, synthetic_child); - synthetic_child_sp = synthetic_child->GetSP(); - synthetic_child_sp->SetName(ConstString(index_str)); - synthetic_child_sp->m_is_array_item_for_pointer = true; - } - } - } - return synthetic_child_sp; -} - -ValueObjectSP -ValueObject::GetSyntheticBitFieldChild (uint32_t from, uint32_t to, bool can_create) -{ - ValueObjectSP synthetic_child_sp; - if (IsScalarType ()) - { - char index_str[64]; - snprintf(index_str, sizeof(index_str), "[%i-%i]", from, to); - ConstString index_const_str(index_str); - // Check if we have already created a synthetic array member in this - // valid object. If we have we will re-use it. - synthetic_child_sp = GetSyntheticChild (index_const_str); - if (!synthetic_child_sp) - { - uint32_t bit_field_size = to - from + 1; - uint32_t bit_field_offset = from; - if (GetDataExtractor().GetByteOrder() == eByteOrderBig) - bit_field_offset = GetByteSize() * 8 - bit_field_size - bit_field_offset; - // We haven't made a synthetic array member for INDEX yet, so - // lets make one and cache it for any future reference. - ValueObjectChild *synthetic_child = new ValueObjectChild (*this, - GetCompilerType(), - index_const_str, - GetByteSize(), - 0, - bit_field_size, - bit_field_offset, - false, - false, - eAddressTypeInvalid, - 0); - - // Cache the value if we got one back... - if (synthetic_child) - { - AddSyntheticChild(index_const_str, synthetic_child); - synthetic_child_sp = synthetic_child->GetSP(); - synthetic_child_sp->SetName(ConstString(index_str)); - synthetic_child_sp->m_is_bitfield_for_scalar = true; - } - } - } - return synthetic_child_sp; -} - -ValueObjectSP -ValueObject::GetSyntheticChildAtOffset(uint32_t offset, - const CompilerType& type, - bool can_create, - ConstString name_const_str) -{ - - ValueObjectSP synthetic_child_sp; - - if (name_const_str.IsEmpty()) - { - char name_str[64]; - snprintf(name_str, sizeof(name_str), "@%i", offset); - name_const_str.SetCString(name_str); - } - +ValueObjectSP ValueObject::GetSyntheticArrayMember(size_t index, + bool can_create) { + ValueObjectSP synthetic_child_sp; + if (IsPointerType() || IsArrayType()) { + char index_str[64]; + snprintf(index_str, sizeof(index_str), "[%" PRIu64 "]", (uint64_t)index); + ConstString index_const_str(index_str); // Check if we have already created a synthetic array member in this // valid object. If we have we will re-use it. - synthetic_child_sp = GetSyntheticChild (name_const_str); - - if (synthetic_child_sp.get()) - return synthetic_child_sp; - - if (!can_create) - return ValueObjectSP(); - - ExecutionContext exe_ctx (GetExecutionContextRef()); - - ValueObjectChild *synthetic_child = new ValueObjectChild(*this, - type, - name_const_str, - type.GetByteSize(exe_ctx.GetBestExecutionContextScope()), - offset, - 0, - 0, - false, - false, - eAddressTypeInvalid, - 0); - if (synthetic_child) - { - AddSyntheticChild(name_const_str, synthetic_child); + synthetic_child_sp = GetSyntheticChild(index_const_str); + if (!synthetic_child_sp) { + ValueObject *synthetic_child; + // We haven't made a synthetic array member for INDEX yet, so + // lets make one and cache it for any future reference. + synthetic_child = CreateChildAtIndex(0, true, index); + + // Cache the value if we got one back... + if (synthetic_child) { + AddSyntheticChild(index_const_str, synthetic_child); synthetic_child_sp = synthetic_child->GetSP(); - synthetic_child_sp->SetName(name_const_str); - synthetic_child_sp->m_is_child_at_offset = true; + synthetic_child_sp->SetName(ConstString(index_str)); + synthetic_child_sp->m_is_array_item_for_pointer = true; + } } - return synthetic_child_sp; + } + return synthetic_child_sp; } -ValueObjectSP -ValueObject::GetSyntheticBase (uint32_t offset, - const CompilerType& type, - bool can_create, - ConstString name_const_str) -{ - ValueObjectSP synthetic_child_sp; - - if (name_const_str.IsEmpty()) - { - char name_str[128]; - snprintf(name_str, sizeof(name_str), "base%s@%i", type.GetTypeName().AsCString("<unknown>"), offset); - name_const_str.SetCString(name_str); - } - +ValueObjectSP ValueObject::GetSyntheticBitFieldChild(uint32_t from, uint32_t to, + bool can_create) { + ValueObjectSP synthetic_child_sp; + if (IsScalarType()) { + char index_str[64]; + snprintf(index_str, sizeof(index_str), "[%i-%i]", from, to); + ConstString index_const_str(index_str); // Check if we have already created a synthetic array member in this // valid object. If we have we will re-use it. - synthetic_child_sp = GetSyntheticChild (name_const_str); - - if (synthetic_child_sp.get()) - return synthetic_child_sp; - - if (!can_create) - return ValueObjectSP(); - - const bool is_base_class = true; - - ExecutionContext exe_ctx (GetExecutionContextRef()); - - ValueObjectChild *synthetic_child = new ValueObjectChild(*this, - type, - name_const_str, - type.GetByteSize(exe_ctx.GetBestExecutionContextScope()), - offset, - 0, - 0, - is_base_class, - false, - eAddressTypeInvalid, - 0); - if (synthetic_child) - { - AddSyntheticChild(name_const_str, synthetic_child); + synthetic_child_sp = GetSyntheticChild(index_const_str); + if (!synthetic_child_sp) { + uint32_t bit_field_size = to - from + 1; + uint32_t bit_field_offset = from; + if (GetDataExtractor().GetByteOrder() == eByteOrderBig) + bit_field_offset = + GetByteSize() * 8 - bit_field_size - bit_field_offset; + // We haven't made a synthetic array member for INDEX yet, so + // lets make one and cache it for any future reference. + ValueObjectChild *synthetic_child = new ValueObjectChild( + *this, GetCompilerType(), index_const_str, GetByteSize(), 0, + bit_field_size, bit_field_offset, false, false, eAddressTypeInvalid, + 0); + + // Cache the value if we got one back... + if (synthetic_child) { + AddSyntheticChild(index_const_str, synthetic_child); synthetic_child_sp = synthetic_child->GetSP(); - synthetic_child_sp->SetName(name_const_str); + synthetic_child_sp->SetName(ConstString(index_str)); + synthetic_child_sp->m_is_bitfield_for_scalar = true; + } } - return synthetic_child_sp; + } + return synthetic_child_sp; } +ValueObjectSP ValueObject::GetSyntheticChildAtOffset( + uint32_t offset, const CompilerType &type, bool can_create, + ConstString name_const_str) { + + ValueObjectSP synthetic_child_sp; + + if (name_const_str.IsEmpty()) { + char name_str[64]; + snprintf(name_str, sizeof(name_str), "@%i", offset); + name_const_str.SetCString(name_str); + } + + // Check if we have already created a synthetic array member in this + // valid object. If we have we will re-use it. + synthetic_child_sp = GetSyntheticChild(name_const_str); + + if (synthetic_child_sp.get()) + return synthetic_child_sp; + + if (!can_create) + return ValueObjectSP(); + + ExecutionContext exe_ctx(GetExecutionContextRef()); + + ValueObjectChild *synthetic_child = new ValueObjectChild( + *this, type, name_const_str, + type.GetByteSize(exe_ctx.GetBestExecutionContextScope()), offset, 0, 0, + false, false, eAddressTypeInvalid, 0); + if (synthetic_child) { + AddSyntheticChild(name_const_str, synthetic_child); + synthetic_child_sp = synthetic_child->GetSP(); + synthetic_child_sp->SetName(name_const_str); + synthetic_child_sp->m_is_child_at_offset = true; + } + return synthetic_child_sp; +} + +ValueObjectSP ValueObject::GetSyntheticBase(uint32_t offset, + const CompilerType &type, + bool can_create, + ConstString name_const_str) { + ValueObjectSP synthetic_child_sp; + + if (name_const_str.IsEmpty()) { + char name_str[128]; + snprintf(name_str, sizeof(name_str), "base%s@%i", + type.GetTypeName().AsCString("<unknown>"), offset); + name_const_str.SetCString(name_str); + } + + // Check if we have already created a synthetic array member in this + // valid object. If we have we will re-use it. + synthetic_child_sp = GetSyntheticChild(name_const_str); + + if (synthetic_child_sp.get()) + return synthetic_child_sp; + + if (!can_create) + return ValueObjectSP(); + + const bool is_base_class = true; + + ExecutionContext exe_ctx(GetExecutionContextRef()); + + ValueObjectChild *synthetic_child = new ValueObjectChild( + *this, type, name_const_str, + type.GetByteSize(exe_ctx.GetBestExecutionContextScope()), offset, 0, 0, + is_base_class, false, eAddressTypeInvalid, 0); + if (synthetic_child) { + AddSyntheticChild(name_const_str, synthetic_child); + synthetic_child_sp = synthetic_child->GetSP(); + synthetic_child_sp->SetName(name_const_str); + } + return synthetic_child_sp; +} // your expression path needs to have a leading . or -> // (unless it somehow "looks like" an array, in which case it has // a leading [ symbol). while the [ is meaningful and should be shown // to the user, . and -> are just parser design, but by no means // added information for the user.. strip them off -static const char* -SkipLeadingExpressionPathSeparators(const char* expression) -{ - if (!expression || !expression[0]) - return expression; - if (expression[0] == '.') - return expression+1; - if (expression[0] == '-' && expression[1] == '>') - return expression+2; +static const char *SkipLeadingExpressionPathSeparators(const char *expression) { + if (!expression || !expression[0]) return expression; + if (expression[0] == '.') + return expression + 1; + if (expression[0] == '-' && expression[1] == '>') + return expression + 2; + return expression; } ValueObjectSP -ValueObject::GetSyntheticExpressionPathChild(const char* expression, bool can_create) -{ - ValueObjectSP synthetic_child_sp; - ConstString name_const_string(expression); - // Check if we have already created a synthetic array member in this - // valid object. If we have we will re-use it. - synthetic_child_sp = GetSyntheticChild (name_const_string); - if (!synthetic_child_sp) - { - // We haven't made a synthetic array member for expression yet, so - // lets make one and cache it for any future reference. - synthetic_child_sp = GetValueForExpressionPath(expression, - NULL, NULL, NULL, - GetValueForExpressionPathOptions().SetSyntheticChildrenTraversal(GetValueForExpressionPathOptions::SyntheticChildrenTraversal::None)); - - // Cache the value if we got one back... - if (synthetic_child_sp.get()) - { - // FIXME: this causes a "real" child to end up with its name changed to the contents of expression - AddSyntheticChild(name_const_string, synthetic_child_sp.get()); - synthetic_child_sp->SetName(ConstString(SkipLeadingExpressionPathSeparators(expression))); - } +ValueObject::GetSyntheticExpressionPathChild(const char *expression, + bool can_create) { + ValueObjectSP synthetic_child_sp; + ConstString name_const_string(expression); + // Check if we have already created a synthetic array member in this + // valid object. If we have we will re-use it. + synthetic_child_sp = GetSyntheticChild(name_const_string); + if (!synthetic_child_sp) { + // We haven't made a synthetic array member for expression yet, so + // lets make one and cache it for any future reference. + synthetic_child_sp = GetValueForExpressionPath( + expression, NULL, NULL, + GetValueForExpressionPathOptions().SetSyntheticChildrenTraversal( + GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: + None)); + + // Cache the value if we got one back... + if (synthetic_child_sp.get()) { + // FIXME: this causes a "real" child to end up with its name changed to + // the contents of expression + AddSyntheticChild(name_const_string, synthetic_child_sp.get()); + synthetic_child_sp->SetName( + ConstString(SkipLeadingExpressionPathSeparators(expression))); + } + } + return synthetic_child_sp; +} + +void ValueObject::CalculateSyntheticValue(bool use_synthetic) { + if (use_synthetic == false) + return; + + TargetSP target_sp(GetTargetSP()); + if (target_sp && target_sp->GetEnableSyntheticValue() == false) { + m_synthetic_value = NULL; + return; + } + + lldb::SyntheticChildrenSP current_synth_sp(m_synthetic_children_sp); + + if (!UpdateFormatsIfNeeded() && m_synthetic_value) + return; + + if (m_synthetic_children_sp.get() == NULL) + return; + + if (current_synth_sp == m_synthetic_children_sp && m_synthetic_value) + return; + + m_synthetic_value = new ValueObjectSynthetic(*this, m_synthetic_children_sp); +} + +void ValueObject::CalculateDynamicValue(DynamicValueType use_dynamic) { + if (use_dynamic == eNoDynamicValues) + return; + + if (!m_dynamic_value && !IsDynamic()) { + ExecutionContext exe_ctx(GetExecutionContextRef()); + Process *process = exe_ctx.GetProcessPtr(); + if (process && process->IsPossibleDynamicValue(*this)) { + ClearDynamicTypeInformation(); + m_dynamic_value = new ValueObjectDynamicValue(*this, use_dynamic); } - return synthetic_child_sp; + } } -void -ValueObject::CalculateSyntheticValue (bool use_synthetic) -{ - if (use_synthetic == false) - return; - - TargetSP target_sp(GetTargetSP()); - if (target_sp && target_sp->GetEnableSyntheticValue() == false) - { - m_synthetic_value = NULL; - return; - } - - lldb::SyntheticChildrenSP current_synth_sp(m_synthetic_children_sp); - - if (!UpdateFormatsIfNeeded() && m_synthetic_value) - return; - - if (m_synthetic_children_sp.get() == NULL) - return; - - if (current_synth_sp == m_synthetic_children_sp && m_synthetic_value) - return; - - m_synthetic_value = new ValueObjectSynthetic(*this, m_synthetic_children_sp); -} +ValueObjectSP ValueObject::GetDynamicValue(DynamicValueType use_dynamic) { + if (use_dynamic == eNoDynamicValues) + return ValueObjectSP(); -void -ValueObject::CalculateDynamicValue (DynamicValueType use_dynamic) -{ - if (use_dynamic == eNoDynamicValues) - return; - - if (!m_dynamic_value && !IsDynamic()) - { - ExecutionContext exe_ctx (GetExecutionContextRef()); - Process *process = exe_ctx.GetProcessPtr(); - if (process && process->IsPossibleDynamicValue(*this)) - { - ClearDynamicTypeInformation (); - m_dynamic_value = new ValueObjectDynamicValue (*this, use_dynamic); - } - } + if (!IsDynamic() && m_dynamic_value == NULL) { + CalculateDynamicValue(use_dynamic); + } + if (m_dynamic_value) + return m_dynamic_value->GetSP(); + else + return ValueObjectSP(); } -ValueObjectSP -ValueObject::GetDynamicValue (DynamicValueType use_dynamic) -{ - if (use_dynamic == eNoDynamicValues) - return ValueObjectSP(); - - if (!IsDynamic() && m_dynamic_value == NULL) - { - CalculateDynamicValue(use_dynamic); - } - if (m_dynamic_value) - return m_dynamic_value->GetSP(); - else - return ValueObjectSP(); -} +ValueObjectSP ValueObject::GetStaticValue() { return GetSP(); } -ValueObjectSP -ValueObject::GetStaticValue() -{ - return GetSP(); -} +lldb::ValueObjectSP ValueObject::GetNonSyntheticValue() { return GetSP(); } -lldb::ValueObjectSP -ValueObject::GetNonSyntheticValue () -{ - return GetSP(); -} +ValueObjectSP ValueObject::GetSyntheticValue(bool use_synthetic) { + if (use_synthetic == false) + return ValueObjectSP(); -ValueObjectSP -ValueObject::GetSyntheticValue (bool use_synthetic) -{ - if (use_synthetic == false) - return ValueObjectSP(); + CalculateSyntheticValue(use_synthetic); - CalculateSyntheticValue(use_synthetic); - - if (m_synthetic_value) - return m_synthetic_value->GetSP(); - else - return ValueObjectSP(); + if (m_synthetic_value) + return m_synthetic_value->GetSP(); + else + return ValueObjectSP(); } -bool -ValueObject::HasSyntheticValue() -{ - UpdateFormatsIfNeeded(); - - if (m_synthetic_children_sp.get() == NULL) - return false; - - CalculateSyntheticValue(true); - - if (m_synthetic_value) - return true; - else - return false; -} +bool ValueObject::HasSyntheticValue() { + UpdateFormatsIfNeeded(); -bool -ValueObject::GetBaseClassPath (Stream &s) -{ - if (IsBaseClass()) - { - bool parent_had_base_class = GetParent() && GetParent()->GetBaseClassPath (s); - CompilerType compiler_type = GetCompilerType(); - std::string cxx_class_name; - bool this_had_base_class = ClangASTContext::GetCXXClassName (compiler_type, cxx_class_name); - if (this_had_base_class) - { - if (parent_had_base_class) - s.PutCString("::"); - s.PutCString(cxx_class_name.c_str()); - } - return parent_had_base_class || this_had_base_class; - } + if (m_synthetic_children_sp.get() == NULL) return false; -} + CalculateSyntheticValue(true); -ValueObject * -ValueObject::GetNonBaseClassParent() -{ - if (GetParent()) - { - if (GetParent()->IsBaseClass()) - return GetParent()->GetNonBaseClassParent(); - else - return GetParent(); - } - return NULL; + if (m_synthetic_value) + return true; + else + return false; } +bool ValueObject::GetBaseClassPath(Stream &s) { + if (IsBaseClass()) { + bool parent_had_base_class = + GetParent() && GetParent()->GetBaseClassPath(s); + CompilerType compiler_type = GetCompilerType(); + std::string cxx_class_name; + bool this_had_base_class = + ClangASTContext::GetCXXClassName(compiler_type, cxx_class_name); + if (this_had_base_class) { + if (parent_had_base_class) + s.PutCString("::"); + s.PutCString(cxx_class_name); + } + return parent_had_base_class || this_had_base_class; + } + return false; +} + +ValueObject *ValueObject::GetNonBaseClassParent() { + if (GetParent()) { + if (GetParent()->IsBaseClass()) + return GetParent()->GetNonBaseClassParent(); + else + return GetParent(); + } + return NULL; +} -bool -ValueObject::IsBaseClass (uint32_t& depth) -{ - if (!IsBaseClass()) - { - depth = 0; - return false; - } - if (GetParent()) - { - GetParent()->IsBaseClass(depth); - depth = depth + 1; - return true; - } - // TODO: a base of no parent? weird.. - depth = 1; +bool ValueObject::IsBaseClass(uint32_t &depth) { + if (!IsBaseClass()) { + depth = 0; + return false; + } + if (GetParent()) { + GetParent()->IsBaseClass(depth); + depth = depth + 1; return true; -} + } + // TODO: a base of no parent? weird.. + depth = 1; + return true; +} + +void ValueObject::GetExpressionPath(Stream &s, bool qualify_cxx_base_classes, + GetExpressionPathFormat epformat) { + // synthetic children do not actually "exist" as part of the hierarchy, and + // sometimes they are consed up in ways + // that don't make sense from an underlying language/API standpoint. So, use a + // special code path here to return + // something that can hopefully be used in expression + if (m_is_synthetic_children_generated) { + UpdateValueIfNeeded(); -void -ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExpressionPathFormat epformat) -{ - // synthetic children do not actually "exist" as part of the hierarchy, and sometimes they are consed up in ways - // that don't make sense from an underlying language/API standpoint. So, use a special code path here to return - // something that can hopefully be used in expression - if (m_is_synthetic_children_generated) - { - UpdateValueIfNeeded(); - - if (m_value.GetValueType() == Value::eValueTypeLoadAddress) - { - if (IsPointerOrReferenceType()) - { - s.Printf("((%s)0x%" PRIx64 ")", - GetTypeName().AsCString("void"), - GetValueAsUnsigned(0)); - return; + if (m_value.GetValueType() == Value::eValueTypeLoadAddress) { + if (IsPointerOrReferenceType()) { + s.Printf("((%s)0x%" PRIx64 ")", GetTypeName().AsCString("void"), + GetValueAsUnsigned(0)); + return; + } else { + uint64_t load_addr = + m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + if (load_addr != LLDB_INVALID_ADDRESS) { + s.Printf("(*( (%s *)0x%" PRIx64 "))", GetTypeName().AsCString("void"), + load_addr); + return; + } + } + } + + if (CanProvideValue()) { + s.Printf("((%s)%s)", GetTypeName().AsCString("void"), + GetValueAsCString()); + return; + } + + return; + } + + const bool is_deref_of_parent = IsDereferenceOfParent(); + + if (is_deref_of_parent && + epformat == eGetExpressionPathFormatDereferencePointers) { + // this is the original format of GetExpressionPath() producing code like + // *(a_ptr).memberName, which is entirely + // fine, until you put this into + // StackFrame::GetValueForVariableExpressionPath() which prefers to see + // a_ptr->memberName. + // the eHonorPointers mode is meant to produce strings in this latter format + s.PutCString("*("); + } + + ValueObject *parent = GetParent(); + + if (parent) + parent->GetExpressionPath(s, qualify_cxx_base_classes, epformat); + + // if we are a deref_of_parent just because we are synthetic array + // members made up to allow ptr[%d] syntax to work in variable + // printing, then add our name ([%d]) to the expression path + if (m_is_array_item_for_pointer && + epformat == eGetExpressionPathFormatHonorPointers) + s.PutCString(m_name.AsCString()); + + if (!IsBaseClass()) { + if (!is_deref_of_parent) { + ValueObject *non_base_class_parent = GetNonBaseClassParent(); + if (non_base_class_parent && + !non_base_class_parent->GetName().IsEmpty()) { + CompilerType non_base_class_parent_compiler_type = + non_base_class_parent->GetCompilerType(); + if (non_base_class_parent_compiler_type) { + if (parent && parent->IsDereferenceOfParent() && + epformat == eGetExpressionPathFormatHonorPointers) { + s.PutCString("->"); + } else { + const uint32_t non_base_class_parent_type_info = + non_base_class_parent_compiler_type.GetTypeInfo(); + + if (non_base_class_parent_type_info & eTypeIsPointer) { + s.PutCString("->"); + } else if ((non_base_class_parent_type_info & eTypeHasChildren) && + !(non_base_class_parent_type_info & eTypeIsArray)) { + s.PutChar('.'); } - else - { - uint64_t load_addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); - if (load_addr != LLDB_INVALID_ADDRESS) - { - s.Printf("(*( (%s *)0x%" PRIx64 "))", - GetTypeName().AsCString("void"), - load_addr); - return; - } + } + } + } + + const char *name = GetName().GetCString(); + if (name) { + if (qualify_cxx_base_classes) { + if (GetBaseClassPath(s)) + s.PutCString("::"); + } + s.PutCString(name); + } + } + } + + if (is_deref_of_parent && + epformat == eGetExpressionPathFormatDereferencePointers) { + s.PutChar(')'); + } +} + +ValueObjectSP ValueObject::GetValueForExpressionPath( + llvm::StringRef expression, ExpressionPathScanEndReason *reason_to_stop, + ExpressionPathEndResultType *final_value_type, + const GetValueForExpressionPathOptions &options, + ExpressionPathAftermath *final_task_on_target) { + + ExpressionPathScanEndReason dummy_reason_to_stop = + ValueObject::eExpressionPathScanEndReasonUnknown; + ExpressionPathEndResultType dummy_final_value_type = + ValueObject::eExpressionPathEndResultTypeInvalid; + ExpressionPathAftermath dummy_final_task_on_target = + ValueObject::eExpressionPathAftermathNothing; + + ValueObjectSP ret_val = GetValueForExpressionPath_Impl( + expression, reason_to_stop ? reason_to_stop : &dummy_reason_to_stop, + final_value_type ? final_value_type : &dummy_final_value_type, options, + final_task_on_target ? final_task_on_target + : &dummy_final_task_on_target); + + if (!final_task_on_target || + *final_task_on_target == ValueObject::eExpressionPathAftermathNothing) + return ret_val; + + if (ret_val.get() && + ((final_value_type ? *final_value_type : dummy_final_value_type) == + eExpressionPathEndResultTypePlain)) // I can only deref and takeaddress + // of plain objects + { + if ((final_task_on_target ? *final_task_on_target + : dummy_final_task_on_target) == + ValueObject::eExpressionPathAftermathDereference) { + Error error; + ValueObjectSP final_value = ret_val->Dereference(error); + if (error.Fail() || !final_value.get()) { + if (reason_to_stop) + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonDereferencingFailed; + if (final_value_type) + *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid; + return ValueObjectSP(); + } else { + if (final_task_on_target) + *final_task_on_target = ValueObject::eExpressionPathAftermathNothing; + return final_value; + } + } + if (*final_task_on_target == + ValueObject::eExpressionPathAftermathTakeAddress) { + Error error; + ValueObjectSP final_value = ret_val->AddressOf(error); + if (error.Fail() || !final_value.get()) { + if (reason_to_stop) + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonTakingAddressFailed; + if (final_value_type) + *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid; + return ValueObjectSP(); + } else { + if (final_task_on_target) + *final_task_on_target = ValueObject::eExpressionPathAftermathNothing; + return final_value; + } + } + } + return ret_val; // final_task_on_target will still have its original value, so + // you know I did not do it +} + +ValueObjectSP ValueObject::GetValueForExpressionPath_Impl( + llvm::StringRef expression, ExpressionPathScanEndReason *reason_to_stop, + ExpressionPathEndResultType *final_result, + const GetValueForExpressionPathOptions &options, + ExpressionPathAftermath *what_next) { + ValueObjectSP root = GetSP(); + + if (!root) + return nullptr; + + llvm::StringRef remainder = expression; + + while (true) { + llvm::StringRef temp_expression = remainder; + + CompilerType root_compiler_type = root->GetCompilerType(); + CompilerType pointee_compiler_type; + Flags pointee_compiler_type_info; + + Flags root_compiler_type_info( + root_compiler_type.GetTypeInfo(&pointee_compiler_type)); + if (pointee_compiler_type) + pointee_compiler_type_info.Reset(pointee_compiler_type.GetTypeInfo()); + + if (temp_expression.empty()) { + *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString; + return root; + } + + switch (temp_expression.front()) { + case '-': { + temp_expression = temp_expression.drop_front(); + if (options.m_check_dot_vs_arrow_syntax && + root_compiler_type_info.Test(eTypeIsPointer)) // if you are trying to + // use -> on a + // non-pointer and I + // must catch the error + { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonArrowInsteadOfDot; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return ValueObjectSP(); + } + if (root_compiler_type_info.Test(eTypeIsObjC) && // if yo are trying to + // extract an ObjC IVar + // when this is forbidden + root_compiler_type_info.Test(eTypeIsPointer) && + options.m_no_fragile_ivar) { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonFragileIVarNotAllowed; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return ValueObjectSP(); + } + if (!temp_expression.startswith(">")) { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return ValueObjectSP(); + } + } + LLVM_FALLTHROUGH; + case '.': // or fallthrough from -> + { + if (options.m_check_dot_vs_arrow_syntax && + temp_expression.front() == '.' && + root_compiler_type_info.Test(eTypeIsPointer)) // if you are trying to + // use . on a pointer + // and I must catch the + // error + { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonDotInsteadOfArrow; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return nullptr; + } + temp_expression = temp_expression.drop_front(); // skip . or > + + size_t next_sep_pos = temp_expression.find_first_of("-.[", 1); + ConstString child_name; + if (next_sep_pos == llvm::StringRef::npos) // if no other separator just + // expand this last layer + { + child_name.SetString(temp_expression); + ValueObjectSP child_valobj_sp = + root->GetChildMemberWithName(child_name, true); + + if (child_valobj_sp.get()) // we know we are done, so just return + { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonEndOfString; + *final_result = ValueObject::eExpressionPathEndResultTypePlain; + return child_valobj_sp; + } else { + switch (options.m_synthetic_children_traversal) { + case GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: + None: + break; + case GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: + FromSynthetic: + if (root->IsSynthetic()) { + child_valobj_sp = root->GetNonSyntheticValue(); + if (child_valobj_sp.get()) + child_valobj_sp = + child_valobj_sp->GetChildMemberWithName(child_name, true); } - } - - if (CanProvideValue()) - { - s.Printf("((%s)%s)", - GetTypeName().AsCString("void"), - GetValueAsCString()); - return; - } - - return; - } - - const bool is_deref_of_parent = IsDereferenceOfParent (); - - if (is_deref_of_parent && epformat == eGetExpressionPathFormatDereferencePointers) - { - // this is the original format of GetExpressionPath() producing code like *(a_ptr).memberName, which is entirely - // fine, until you put this into StackFrame::GetValueForVariableExpressionPath() which prefers to see a_ptr->memberName. - // the eHonorPointers mode is meant to produce strings in this latter format - s.PutCString("*("); - } - - ValueObject* parent = GetParent(); - - if (parent) - parent->GetExpressionPath (s, qualify_cxx_base_classes, epformat); - - // if we are a deref_of_parent just because we are synthetic array - // members made up to allow ptr[%d] syntax to work in variable - // printing, then add our name ([%d]) to the expression path - if (m_is_array_item_for_pointer && epformat == eGetExpressionPathFormatHonorPointers) - s.PutCString(m_name.AsCString()); - - if (!IsBaseClass()) - { - if (!is_deref_of_parent) - { - ValueObject *non_base_class_parent = GetNonBaseClassParent(); - if (non_base_class_parent && !non_base_class_parent->GetName().IsEmpty()) - { - CompilerType non_base_class_parent_compiler_type = non_base_class_parent->GetCompilerType(); - if (non_base_class_parent_compiler_type) - { - if (parent && parent->IsDereferenceOfParent() && epformat == eGetExpressionPathFormatHonorPointers) - { - s.PutCString("->"); - } - else - { - const uint32_t non_base_class_parent_type_info = non_base_class_parent_compiler_type.GetTypeInfo(); - - if (non_base_class_parent_type_info & eTypeIsPointer) - { - s.PutCString("->"); - } - else if ((non_base_class_parent_type_info & eTypeHasChildren) && - !(non_base_class_parent_type_info & eTypeIsArray)) - { - s.PutChar('.'); - } - } - } + break; + case GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: + ToSynthetic: + if (!root->IsSynthetic()) { + child_valobj_sp = root->GetSyntheticValue(); + if (child_valobj_sp.get()) + child_valobj_sp = + child_valobj_sp->GetChildMemberWithName(child_name, true); } - - const char *name = GetName().GetCString(); - if (name) - { - if (qualify_cxx_base_classes) - { - if (GetBaseClassPath (s)) - s.PutCString("::"); - } - s.PutCString(name); + break; + case GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: + Both: + if (root->IsSynthetic()) { + child_valobj_sp = root->GetNonSyntheticValue(); + if (child_valobj_sp.get()) + child_valobj_sp = + child_valobj_sp->GetChildMemberWithName(child_name, true); + } else { + child_valobj_sp = root->GetSyntheticValue(); + if (child_valobj_sp.get()) + child_valobj_sp = + child_valobj_sp->GetChildMemberWithName(child_name, true); } - } - } - - if (is_deref_of_parent && epformat == eGetExpressionPathFormatDereferencePointers) - { - s.PutChar(')'); - } -} - -ValueObjectSP -ValueObject::GetValueForExpressionPath(const char* expression, - const char** first_unparsed, - ExpressionPathScanEndReason* reason_to_stop, - ExpressionPathEndResultType* final_value_type, - const GetValueForExpressionPathOptions& options, - ExpressionPathAftermath* final_task_on_target) -{ - - const char* dummy_first_unparsed; - ExpressionPathScanEndReason dummy_reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnknown; - ExpressionPathEndResultType dummy_final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid; - ExpressionPathAftermath dummy_final_task_on_target = ValueObject::eExpressionPathAftermathNothing; - - ValueObjectSP ret_val = GetValueForExpressionPath_Impl(expression, - first_unparsed ? first_unparsed : &dummy_first_unparsed, - reason_to_stop ? reason_to_stop : &dummy_reason_to_stop, - final_value_type ? final_value_type : &dummy_final_value_type, - options, - final_task_on_target ? final_task_on_target : &dummy_final_task_on_target); - - if (!final_task_on_target || *final_task_on_target == ValueObject::eExpressionPathAftermathNothing) - return ret_val; - - if (ret_val.get() && ((final_value_type ? *final_value_type : dummy_final_value_type) == eExpressionPathEndResultTypePlain)) // I can only deref and takeaddress of plain objects - { - if ( (final_task_on_target ? *final_task_on_target : dummy_final_task_on_target) == ValueObject::eExpressionPathAftermathDereference) - { - Error error; - ValueObjectSP final_value = ret_val->Dereference(error); - if (error.Fail() || !final_value.get()) - { - if (reason_to_stop) - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDereferencingFailed; - if (final_value_type) - *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); + break; + } + } + + // if we are here and options.m_no_synthetic_children is true, + // child_valobj_sp is going to be a NULL SP, + // so we hit the "else" branch, and return an error + if (child_valobj_sp.get()) // if it worked, just return + { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonEndOfString; + *final_result = ValueObject::eExpressionPathEndResultTypePlain; + return child_valobj_sp; + } else { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonNoSuchChild; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return nullptr; + } + } else // other layers do expand + { + llvm::StringRef next_separator = temp_expression.substr(next_sep_pos); + + child_name.SetString(temp_expression.slice(0, next_sep_pos)); + + ValueObjectSP child_valobj_sp = + root->GetChildMemberWithName(child_name, true); + if (child_valobj_sp.get()) // store the new root and move on + { + root = child_valobj_sp; + remainder = next_separator; + *final_result = ValueObject::eExpressionPathEndResultTypePlain; + continue; + } else { + switch (options.m_synthetic_children_traversal) { + case GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: + None: + break; + case GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: + FromSynthetic: + if (root->IsSynthetic()) { + child_valobj_sp = root->GetNonSyntheticValue(); + if (child_valobj_sp.get()) + child_valobj_sp = + child_valobj_sp->GetChildMemberWithName(child_name, true); } - else - { - if (final_task_on_target) - *final_task_on_target = ValueObject::eExpressionPathAftermathNothing; - return final_value; + break; + case GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: + ToSynthetic: + if (!root->IsSynthetic()) { + child_valobj_sp = root->GetSyntheticValue(); + if (child_valobj_sp.get()) + child_valobj_sp = + child_valobj_sp->GetChildMemberWithName(child_name, true); } - } - if (*final_task_on_target == ValueObject::eExpressionPathAftermathTakeAddress) - { + break; + case GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: + Both: + if (root->IsSynthetic()) { + child_valobj_sp = root->GetNonSyntheticValue(); + if (child_valobj_sp.get()) + child_valobj_sp = + child_valobj_sp->GetChildMemberWithName(child_name, true); + } else { + child_valobj_sp = root->GetSyntheticValue(); + if (child_valobj_sp.get()) + child_valobj_sp = + child_valobj_sp->GetChildMemberWithName(child_name, true); + } + break; + } + } + + // if we are here and options.m_no_synthetic_children is true, + // child_valobj_sp is going to be a NULL SP, + // so we hit the "else" branch, and return an error + if (child_valobj_sp.get()) // if it worked, move on + { + root = child_valobj_sp; + remainder = next_separator; + *final_result = ValueObject::eExpressionPathEndResultTypePlain; + continue; + } else { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonNoSuchChild; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return nullptr; + } + } + break; + } + case '[': { + if (!root_compiler_type_info.Test(eTypeIsArray) && + !root_compiler_type_info.Test(eTypeIsPointer) && + !root_compiler_type_info.Test( + eTypeIsVector)) // if this is not a T[] nor a T* + { + if (!root_compiler_type_info.Test( + eTypeIsScalar)) // if this is not even a scalar... + { + if (options.m_synthetic_children_traversal == + GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: + None) // ...only chance left is synthetic + { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonRangeOperatorInvalid; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return ValueObjectSP(); + } + } else if (!options.m_allow_bitfields_syntax) // if this is a scalar, + // check that we can + // expand bitfields + { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonRangeOperatorNotAllowed; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return ValueObjectSP(); + } + } + if (temp_expression[1] == + ']') // if this is an unbounded range it only works for arrays + { + if (!root_compiler_type_info.Test(eTypeIsArray)) { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return nullptr; + } else // even if something follows, we cannot expand unbounded ranges, + // just let the caller do it + { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonArrayRangeOperatorMet; + *final_result = + ValueObject::eExpressionPathEndResultTypeUnboundedRange; + return root; + } + } + + size_t close_bracket_position = temp_expression.find(']', 1); + if (close_bracket_position == + llvm::StringRef::npos) // if there is no ], this is a syntax error + { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return nullptr; + } + + llvm::StringRef bracket_expr = + temp_expression.slice(1, close_bracket_position); + + // If this was an empty expression it would have been caught by the if + // above. + assert(!bracket_expr.empty()); + + if (!bracket_expr.contains('-')) { + // if no separator, this is of the form [N]. Note that this cannot + // be an unbounded range of the form [], because that case was handled + // above with an unconditional return. + unsigned long index = 0; + if (bracket_expr.getAsInteger(0, index)) { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return nullptr; + } + + // from here on we do have a valid index + if (root_compiler_type_info.Test(eTypeIsArray)) { + ValueObjectSP child_valobj_sp = root->GetChildAtIndex(index, true); + if (!child_valobj_sp) + child_valobj_sp = root->GetSyntheticArrayMember(index, true); + if (!child_valobj_sp) + if (root->HasSyntheticValue() && + root->GetSyntheticValue()->GetNumChildren() > index) + child_valobj_sp = + root->GetSyntheticValue()->GetChildAtIndex(index, true); + if (child_valobj_sp) { + root = child_valobj_sp; + remainder = + temp_expression.substr(close_bracket_position + 1); // skip ] + *final_result = ValueObject::eExpressionPathEndResultTypePlain; + continue; + } else { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonNoSuchChild; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return nullptr; + } + } else if (root_compiler_type_info.Test(eTypeIsPointer)) { + if (*what_next == + ValueObject:: + eExpressionPathAftermathDereference && // if this is a + // ptr-to-scalar, I + // am accessing it + // by index and I + // would have + // deref'ed anyway, + // then do it now + // and use this as + // a bitfield + pointee_compiler_type_info.Test(eTypeIsScalar)) { Error error; - ValueObjectSP final_value = ret_val->AddressOf(error); - if (error.Fail() || !final_value.get()) - { - if (reason_to_stop) - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonTakingAddressFailed; - if (final_value_type) - *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); + root = root->Dereference(error); + if (error.Fail() || !root) { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonDereferencingFailed; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return nullptr; + } else { + *what_next = eExpressionPathAftermathNothing; + continue; } - else - { - if (final_task_on_target) - *final_task_on_target = ValueObject::eExpressionPathAftermathNothing; - return final_value; + } else { + if (root->GetCompilerType().GetMinimumLanguage() == + eLanguageTypeObjC && + pointee_compiler_type_info.AllClear(eTypeIsPointer) && + root->HasSyntheticValue() && + (options.m_synthetic_children_traversal == + GetValueForExpressionPathOptions:: + SyntheticChildrenTraversal::ToSynthetic || + options.m_synthetic_children_traversal == + GetValueForExpressionPathOptions:: + SyntheticChildrenTraversal::Both)) { + root = root->GetSyntheticValue()->GetChildAtIndex(index, true); + } else + root = root->GetSyntheticArrayMember(index, true); + if (!root) { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonNoSuchChild; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return nullptr; + } else { + remainder = + temp_expression.substr(close_bracket_position + 1); // skip ] + *final_result = ValueObject::eExpressionPathEndResultTypePlain; + continue; } - } - } - return ret_val; // final_task_on_target will still have its original value, so you know I did not do it + } + } else if (root_compiler_type_info.Test(eTypeIsScalar)) { + root = root->GetSyntheticBitFieldChild(index, index, true); + if (!root) { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonNoSuchChild; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return nullptr; + } else // we do not know how to expand members of bitfields, so we + // just return and let the caller do any further processing + { + *reason_to_stop = ValueObject:: + eExpressionPathScanEndReasonBitfieldRangeOperatorMet; + *final_result = ValueObject::eExpressionPathEndResultTypeBitfield; + return root; + } + } else if (root_compiler_type_info.Test(eTypeIsVector)) { + root = root->GetChildAtIndex(index, true); + if (!root) { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonNoSuchChild; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return ValueObjectSP(); + } else { + remainder = + temp_expression.substr(close_bracket_position + 1); // skip ] + *final_result = ValueObject::eExpressionPathEndResultTypePlain; + continue; + } + } else if (options.m_synthetic_children_traversal == + GetValueForExpressionPathOptions:: + SyntheticChildrenTraversal::ToSynthetic || + options.m_synthetic_children_traversal == + GetValueForExpressionPathOptions:: + SyntheticChildrenTraversal::Both) { + if (root->HasSyntheticValue()) + root = root->GetSyntheticValue(); + else if (!root->IsSynthetic()) { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonSyntheticValueMissing; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return nullptr; + } + // if we are here, then root itself is a synthetic VO.. should be good + // to go + + if (!root) { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonSyntheticValueMissing; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return nullptr; + } + root = root->GetChildAtIndex(index, true); + if (!root) { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonNoSuchChild; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return nullptr; + } else { + remainder = + temp_expression.substr(close_bracket_position + 1); // skip ] + *final_result = ValueObject::eExpressionPathEndResultTypePlain; + continue; + } + } else { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonNoSuchChild; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return nullptr; + } + } else { + // we have a low and a high index + llvm::StringRef sleft, sright; + unsigned long low_index, high_index; + std::tie(sleft, sright) = bracket_expr.split('-'); + if (sleft.getAsInteger(0, low_index) || + sright.getAsInteger(0, high_index)) { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return nullptr; + } + + if (low_index > high_index) // swap indices if required + std::swap(low_index, high_index); + + if (root_compiler_type_info.Test( + eTypeIsScalar)) // expansion only works for scalars + { + root = root->GetSyntheticBitFieldChild(low_index, high_index, true); + if (!root) { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonNoSuchChild; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return nullptr; + } else { + *reason_to_stop = ValueObject:: + eExpressionPathScanEndReasonBitfieldRangeOperatorMet; + *final_result = ValueObject::eExpressionPathEndResultTypeBitfield; + return root; + } + } else if (root_compiler_type_info.Test( + eTypeIsPointer) && // if this is a ptr-to-scalar, I am + // accessing it by index and I would + // have deref'ed anyway, then do it + // now and use this as a bitfield + *what_next == + ValueObject::eExpressionPathAftermathDereference && + pointee_compiler_type_info.Test(eTypeIsScalar)) { + Error error; + root = root->Dereference(error); + if (error.Fail() || !root) { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonDereferencingFailed; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return nullptr; + } else { + *what_next = ValueObject::eExpressionPathAftermathNothing; + continue; + } + } else { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonArrayRangeOperatorMet; + *final_result = ValueObject::eExpressionPathEndResultTypeBoundedRange; + return root; + } + } + break; + } + default: // some non-separator is in the way + { + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; + *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; + return nullptr; + } + } + } +} + +void ValueObject::LogValueObject(Log *log) { + if (log) + return LogValueObject(log, DumpValueObjectOptions(*this)); +} + +void ValueObject::LogValueObject(Log *log, + const DumpValueObjectOptions &options) { + if (log) { + StreamString s; + Dump(s, options); + if (s.GetSize()) + log->PutCString(s.GetData()); + } } -int -ValueObject::GetValuesForExpressionPath(const char* expression, - ValueObjectListSP& list, - const char** first_unparsed, - ExpressionPathScanEndReason* reason_to_stop, - ExpressionPathEndResultType* final_value_type, - const GetValueForExpressionPathOptions& options, - ExpressionPathAftermath* final_task_on_target) -{ - const char* dummy_first_unparsed; - ExpressionPathScanEndReason dummy_reason_to_stop; - ExpressionPathEndResultType dummy_final_value_type; - ExpressionPathAftermath dummy_final_task_on_target = ValueObject::eExpressionPathAftermathNothing; - - ValueObjectSP ret_val = GetValueForExpressionPath_Impl(expression, - first_unparsed ? first_unparsed : &dummy_first_unparsed, - reason_to_stop ? reason_to_stop : &dummy_reason_to_stop, - final_value_type ? final_value_type : &dummy_final_value_type, - options, - final_task_on_target ? final_task_on_target : &dummy_final_task_on_target); - - if (!ret_val.get()) // if there are errors, I add nothing to the list - return 0; - - if ( (reason_to_stop ? *reason_to_stop : dummy_reason_to_stop) != eExpressionPathScanEndReasonArrayRangeOperatorMet) - { - // I need not expand a range, just post-process the final value and return - if (!final_task_on_target || *final_task_on_target == ValueObject::eExpressionPathAftermathNothing) - { - list->Append(ret_val); - return 1; - } - if (ret_val.get() && (final_value_type ? *final_value_type : dummy_final_value_type) == eExpressionPathEndResultTypePlain) // I can only deref and takeaddress of plain objects - { - if (*final_task_on_target == ValueObject::eExpressionPathAftermathDereference) - { - Error error; - ValueObjectSP final_value = ret_val->Dereference(error); - if (error.Fail() || !final_value.get()) - { - if (reason_to_stop) - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDereferencingFailed; - if (final_value_type) - *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid; - return 0; - } - else - { - *final_task_on_target = ValueObject::eExpressionPathAftermathNothing; - list->Append(final_value); - return 1; - } - } - if (*final_task_on_target == ValueObject::eExpressionPathAftermathTakeAddress) - { - Error error; - ValueObjectSP final_value = ret_val->AddressOf(error); - if (error.Fail() || !final_value.get()) - { - if (reason_to_stop) - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonTakingAddressFailed; - if (final_value_type) - *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid; - return 0; - } - else - { - *final_task_on_target = ValueObject::eExpressionPathAftermathNothing; - list->Append(final_value); - return 1; - } - } - } - } - else - { - return ExpandArraySliceExpression(first_unparsed ? *first_unparsed : dummy_first_unparsed, - first_unparsed ? first_unparsed : &dummy_first_unparsed, - ret_val, - list, - reason_to_stop ? reason_to_stop : &dummy_reason_to_stop, - final_value_type ? final_value_type : &dummy_final_value_type, - options, - final_task_on_target ? final_task_on_target : &dummy_final_task_on_target); - } - // in any non-covered case, just do the obviously right thing - list->Append(ret_val); - return 1; -} +void ValueObject::Dump(Stream &s) { Dump(s, DumpValueObjectOptions(*this)); } -ValueObjectSP -ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr, - const char** first_unparsed, - ExpressionPathScanEndReason* reason_to_stop, - ExpressionPathEndResultType* final_result, - const GetValueForExpressionPathOptions& options, - ExpressionPathAftermath* what_next) -{ - ValueObjectSP root = GetSP(); - - if (!root.get()) - return ValueObjectSP(); - - *first_unparsed = expression_cstr; - - while (true) - { - - const char* expression_cstr = *first_unparsed; // hide the top level expression_cstr - - CompilerType root_compiler_type = root->GetCompilerType(); - CompilerType pointee_compiler_type; - Flags pointee_compiler_type_info; - - Flags root_compiler_type_info(root_compiler_type.GetTypeInfo(&pointee_compiler_type)); - if (pointee_compiler_type) - pointee_compiler_type_info.Reset(pointee_compiler_type.GetTypeInfo()); - - if (!expression_cstr || *expression_cstr == '\0') - { - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString; - return root; - } - - switch (*expression_cstr) - { - case '-': - { - if (options.m_check_dot_vs_arrow_syntax && - root_compiler_type_info.Test(eTypeIsPointer) ) // if you are trying to use -> on a non-pointer and I must catch the error - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonArrowInsteadOfDot; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - if (root_compiler_type_info.Test(eTypeIsObjC) && // if yo are trying to extract an ObjC IVar when this is forbidden - root_compiler_type_info.Test(eTypeIsPointer) && - options.m_no_fragile_ivar) - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonFragileIVarNotAllowed; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - if (expression_cstr[1] != '>') - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - expression_cstr++; // skip the - - } - LLVM_FALLTHROUGH; - case '.': // or fallthrough from -> - { - if (options.m_check_dot_vs_arrow_syntax && *expression_cstr == '.' && - root_compiler_type_info.Test(eTypeIsPointer)) // if you are trying to use . on a pointer and I must catch the error - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDotInsteadOfArrow; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - expression_cstr++; // skip . - const char *next_separator = strpbrk(expression_cstr+1,"-.["); - ConstString child_name; - if (!next_separator) // if no other separator just expand this last layer - { - child_name.SetCString (expression_cstr); - ValueObjectSP child_valobj_sp = root->GetChildMemberWithName(child_name, true); - - if (child_valobj_sp.get()) // we know we are done, so just return - { - *first_unparsed = ""; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString; - *final_result = ValueObject::eExpressionPathEndResultTypePlain; - return child_valobj_sp; - } - else - { - switch (options.m_synthetic_children_traversal) - { - case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::None: - break; - case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::FromSynthetic: - if (root->IsSynthetic()) - { - child_valobj_sp = root->GetNonSyntheticValue(); - if (child_valobj_sp.get()) - child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true); - } - break; - case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::ToSynthetic: - if (!root->IsSynthetic()) - { - child_valobj_sp = root->GetSyntheticValue(); - if (child_valobj_sp.get()) - child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true); - } - break; - case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::Both: - if (root->IsSynthetic()) - { - child_valobj_sp = root->GetNonSyntheticValue(); - if (child_valobj_sp.get()) - child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true); - } - else - { - child_valobj_sp = root->GetSyntheticValue(); - if (child_valobj_sp.get()) - child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true); - } - break; - } - } - - // if we are here and options.m_no_synthetic_children is true, child_valobj_sp is going to be a NULL SP, - // so we hit the "else" branch, and return an error - if(child_valobj_sp.get()) // if it worked, just return - { - *first_unparsed = ""; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString; - *final_result = ValueObject::eExpressionPathEndResultTypePlain; - return child_valobj_sp; - } - else - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - } - else // other layers do expand - { - child_name.SetCStringWithLength(expression_cstr, next_separator - expression_cstr); - ValueObjectSP child_valobj_sp = root->GetChildMemberWithName(child_name, true); - if (child_valobj_sp.get()) // store the new root and move on - { - root = child_valobj_sp; - *first_unparsed = next_separator; - *final_result = ValueObject::eExpressionPathEndResultTypePlain; - continue; - } - else - { - switch (options.m_synthetic_children_traversal) - { - case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::None: - break; - case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::FromSynthetic: - if (root->IsSynthetic()) - { - child_valobj_sp = root->GetNonSyntheticValue(); - if (child_valobj_sp.get()) - child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true); - } - break; - case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::ToSynthetic: - if (!root->IsSynthetic()) - { - child_valobj_sp = root->GetSyntheticValue(); - if (child_valobj_sp.get()) - child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true); - } - break; - case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::Both: - if (root->IsSynthetic()) - { - child_valobj_sp = root->GetNonSyntheticValue(); - if (child_valobj_sp.get()) - child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true); - } - else - { - child_valobj_sp = root->GetSyntheticValue(); - if (child_valobj_sp.get()) - child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true); - } - break; - } - } - - // if we are here and options.m_no_synthetic_children is true, child_valobj_sp is going to be a NULL SP, - // so we hit the "else" branch, and return an error - if(child_valobj_sp.get()) // if it worked, move on - { - root = child_valobj_sp; - *first_unparsed = next_separator; - *final_result = ValueObject::eExpressionPathEndResultTypePlain; - continue; - } - else - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - } - break; - } - case '[': - { - if (!root_compiler_type_info.Test(eTypeIsArray) && !root_compiler_type_info.Test(eTypeIsPointer) && !root_compiler_type_info.Test(eTypeIsVector)) // if this is not a T[] nor a T* - { - if (!root_compiler_type_info.Test(eTypeIsScalar)) // if this is not even a scalar... - { - if (options.m_synthetic_children_traversal == GetValueForExpressionPathOptions::SyntheticChildrenTraversal::None) // ...only chance left is synthetic - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorInvalid; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - } - else if (!options.m_allow_bitfields_syntax) // if this is a scalar, check that we can expand bitfields - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorNotAllowed; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - } - if (*(expression_cstr+1) == ']') // if this is an unbounded range it only works for arrays - { - if (!root_compiler_type_info.Test(eTypeIsArray)) - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - else // even if something follows, we cannot expand unbounded ranges, just let the caller do it - { - *first_unparsed = expression_cstr+2; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonArrayRangeOperatorMet; - *final_result = ValueObject::eExpressionPathEndResultTypeUnboundedRange; - return root; - } - } - const char *separator_position = ::strchr(expression_cstr+1,'-'); - const char *close_bracket_position = ::strchr(expression_cstr+1,']'); - if (!close_bracket_position) // if there is no ], this is a syntax error - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - if (!separator_position || separator_position > close_bracket_position) // if no separator, this is either [] or [N] - { - char *end = NULL; - unsigned long index = ::strtoul (expression_cstr+1, &end, 0); - if (!end || end != close_bracket_position) // if something weird is in our way return an error - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - if (end - expression_cstr == 1) // if this is [], only return a valid value for arrays - { - if (root_compiler_type_info.Test(eTypeIsArray)) - { - *first_unparsed = expression_cstr+2; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonArrayRangeOperatorMet; - *final_result = ValueObject::eExpressionPathEndResultTypeUnboundedRange; - return root; - } - else - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - } - // from here on we do have a valid index - if (root_compiler_type_info.Test(eTypeIsArray)) - { - ValueObjectSP child_valobj_sp = root->GetChildAtIndex(index, true); - if (!child_valobj_sp) - child_valobj_sp = root->GetSyntheticArrayMember(index, true); - if (!child_valobj_sp) - if (root->HasSyntheticValue() && root->GetSyntheticValue()->GetNumChildren() > index) - child_valobj_sp = root->GetSyntheticValue()->GetChildAtIndex(index, true); - if (child_valobj_sp) - { - root = child_valobj_sp; - *first_unparsed = end+1; // skip ] - *final_result = ValueObject::eExpressionPathEndResultTypePlain; - continue; - } - else - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - } - else if (root_compiler_type_info.Test(eTypeIsPointer)) - { - if (*what_next == ValueObject::eExpressionPathAftermathDereference && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield - pointee_compiler_type_info.Test(eTypeIsScalar)) - { - Error error; - root = root->Dereference(error); - if (error.Fail() || !root.get()) - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDereferencingFailed; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - else - { - *what_next = eExpressionPathAftermathNothing; - continue; - } - } - else - { - if (root->GetCompilerType().GetMinimumLanguage() == eLanguageTypeObjC - && pointee_compiler_type_info.AllClear(eTypeIsPointer) - && root->HasSyntheticValue() - && (options.m_synthetic_children_traversal == GetValueForExpressionPathOptions::SyntheticChildrenTraversal::ToSynthetic || - options.m_synthetic_children_traversal == GetValueForExpressionPathOptions::SyntheticChildrenTraversal::Both)) - { - root = root->GetSyntheticValue()->GetChildAtIndex(index, true); - } - else - root = root->GetSyntheticArrayMember(index, true); - if (!root.get()) - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - else - { - *first_unparsed = end+1; // skip ] - *final_result = ValueObject::eExpressionPathEndResultTypePlain; - continue; - } - } - } - else if (root_compiler_type_info.Test(eTypeIsScalar)) - { - root = root->GetSyntheticBitFieldChild(index, index, true); - if (!root.get()) - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - else // we do not know how to expand members of bitfields, so we just return and let the caller do any further processing - { - *first_unparsed = end+1; // skip ] - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonBitfieldRangeOperatorMet; - *final_result = ValueObject::eExpressionPathEndResultTypeBitfield; - return root; - } - } - else if (root_compiler_type_info.Test(eTypeIsVector)) - { - root = root->GetChildAtIndex(index, true); - if (!root.get()) - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - else - { - *first_unparsed = end+1; // skip ] - *final_result = ValueObject::eExpressionPathEndResultTypePlain; - continue; - } - } - else if (options.m_synthetic_children_traversal == GetValueForExpressionPathOptions::SyntheticChildrenTraversal::ToSynthetic || - options.m_synthetic_children_traversal == GetValueForExpressionPathOptions::SyntheticChildrenTraversal::Both) - { - if (root->HasSyntheticValue()) - root = root->GetSyntheticValue(); - else if (!root->IsSynthetic()) - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonSyntheticValueMissing; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - // if we are here, then root itself is a synthetic VO.. should be good to go - - if (!root.get()) - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonSyntheticValueMissing; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - root = root->GetChildAtIndex(index, true); - if (!root.get()) - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - else - { - *first_unparsed = end+1; // skip ] - *final_result = ValueObject::eExpressionPathEndResultTypePlain; - continue; - } - } - else - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - } - else // we have a low and a high index - { - char *end = NULL; - unsigned long index_lower = ::strtoul (expression_cstr+1, &end, 0); - if (!end || end != separator_position) // if something weird is in our way return an error - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - unsigned long index_higher = ::strtoul (separator_position+1, &end, 0); - if (!end || end != close_bracket_position) // if something weird is in our way return an error - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - if (index_lower > index_higher) // swap indices if required - { - unsigned long temp = index_lower; - index_lower = index_higher; - index_higher = temp; - } - if (root_compiler_type_info.Test(eTypeIsScalar)) // expansion only works for scalars - { - root = root->GetSyntheticBitFieldChild(index_lower, index_higher, true); - if (!root.get()) - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - else - { - *first_unparsed = end+1; // skip ] - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonBitfieldRangeOperatorMet; - *final_result = ValueObject::eExpressionPathEndResultTypeBitfield; - return root; - } - } - else if (root_compiler_type_info.Test(eTypeIsPointer) && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield - *what_next == ValueObject::eExpressionPathAftermathDereference && - pointee_compiler_type_info.Test(eTypeIsScalar)) - { - Error error; - root = root->Dereference(error); - if (error.Fail() || !root.get()) - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDereferencingFailed; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - } - else - { - *what_next = ValueObject::eExpressionPathAftermathNothing; - continue; - } - } - else - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonArrayRangeOperatorMet; - *final_result = ValueObject::eExpressionPathEndResultTypeBoundedRange; - return root; - } - } - break; - } - default: // some non-separator is in the way - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); - break; - } - } - } +void ValueObject::Dump(Stream &s, const DumpValueObjectOptions &options) { + ValueObjectPrinter printer(this, &s, options); + printer.PrintValueObject(); } -int -ValueObject::ExpandArraySliceExpression(const char* expression_cstr, - const char** first_unparsed, - ValueObjectSP root, - ValueObjectListSP& list, - ExpressionPathScanEndReason* reason_to_stop, - ExpressionPathEndResultType* final_result, - const GetValueForExpressionPathOptions& options, - ExpressionPathAftermath* what_next) -{ - if (!root.get()) - return 0; - - *first_unparsed = expression_cstr; - - while (true) - { - - const char* expression_cstr = *first_unparsed; // hide the top level expression_cstr - - CompilerType root_compiler_type = root->GetCompilerType(); - CompilerType pointee_compiler_type; - Flags pointee_compiler_type_info; - Flags root_compiler_type_info(root_compiler_type.GetTypeInfo(&pointee_compiler_type)); - if (pointee_compiler_type) - pointee_compiler_type_info.Reset(pointee_compiler_type.GetTypeInfo()); - - if (!expression_cstr || *expression_cstr == '\0') - { - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString; - list->Append(root); - return 1; - } - - switch (*expression_cstr) - { - case '[': - { - if (!root_compiler_type_info.Test(eTypeIsArray) && !root_compiler_type_info.Test(eTypeIsPointer)) // if this is not a T[] nor a T* - { - if (!root_compiler_type_info.Test(eTypeIsScalar)) // if this is not even a scalar, this syntax is just plain wrong! - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorInvalid; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return 0; - } - else if (!options.m_allow_bitfields_syntax) // if this is a scalar, check that we can expand bitfields - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorNotAllowed; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return 0; - } - } - if (*(expression_cstr+1) == ']') // if this is an unbounded range it only works for arrays - { - if (!root_compiler_type_info.Test(eTypeIsArray)) - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return 0; - } - else // expand this into list - { - const size_t max_index = root->GetNumChildren() - 1; - for (size_t index = 0; index < max_index; index++) - { - ValueObjectSP child = - root->GetChildAtIndex(index, true); - list->Append(child); - } - *first_unparsed = expression_cstr+2; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded; - *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList; - return max_index; // tell me number of items I added to the VOList - } - } - const char *separator_position = ::strchr(expression_cstr+1,'-'); - const char *close_bracket_position = ::strchr(expression_cstr+1,']'); - if (!close_bracket_position) // if there is no ], this is a syntax error - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return 0; - } - if (!separator_position || separator_position > close_bracket_position) // if no separator, this is either [] or [N] - { - char *end = NULL; - unsigned long index = ::strtoul (expression_cstr+1, &end, 0); - if (!end || end != close_bracket_position) // if something weird is in our way return an error - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return 0; - } - if (end - expression_cstr == 1) // if this is [], only return a valid value for arrays - { - if (root_compiler_type_info.Test(eTypeIsArray)) - { - const size_t max_index = root->GetNumChildren() - 1; - for (size_t index = 0; index < max_index; index++) - { - ValueObjectSP child = - root->GetChildAtIndex(index, true); - list->Append(child); - } - *first_unparsed = expression_cstr+2; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded; - *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList; - return max_index; // tell me number of items I added to the VOList - } - else - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return 0; - } - } - // from here on we do have a valid index - if (root_compiler_type_info.Test(eTypeIsArray)) - { - root = root->GetChildAtIndex(index, true); - if (!root.get()) - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return 0; - } - else - { - list->Append(root); - *first_unparsed = end+1; // skip ] - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded; - *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList; - return 1; - } - } - else if (root_compiler_type_info.Test(eTypeIsPointer)) - { - if (*what_next == ValueObject::eExpressionPathAftermathDereference && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield - pointee_compiler_type_info.Test(eTypeIsScalar)) - { - Error error; - root = root->Dereference(error); - if (error.Fail() || !root.get()) - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDereferencingFailed; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return 0; - } - else - { - *what_next = eExpressionPathAftermathNothing; - continue; - } - } - else - { - root = root->GetSyntheticArrayMember(index, true); - if (!root.get()) - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return 0; - } - else - { - list->Append(root); - *first_unparsed = end+1; // skip ] - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded; - *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList; - return 1; - } - } - } - else /*if (ClangASTContext::IsScalarType(root_compiler_type))*/ - { - root = root->GetSyntheticBitFieldChild(index, index, true); - if (!root.get()) - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return 0; - } - else // we do not know how to expand members of bitfields, so we just return and let the caller do any further processing - { - list->Append(root); - *first_unparsed = end+1; // skip ] - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded; - *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList; - return 1; - } - } - } - else // we have a low and a high index - { - char *end = NULL; - unsigned long index_lower = ::strtoul (expression_cstr+1, &end, 0); - if (!end || end != separator_position) // if something weird is in our way return an error - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return 0; - } - unsigned long index_higher = ::strtoul (separator_position+1, &end, 0); - if (!end || end != close_bracket_position) // if something weird is in our way return an error - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return 0; - } - if (index_lower > index_higher) // swap indices if required - { - unsigned long temp = index_lower; - index_lower = index_higher; - index_higher = temp; - } - if (root_compiler_type_info.Test(eTypeIsScalar)) // expansion only works for scalars - { - root = root->GetSyntheticBitFieldChild(index_lower, index_higher, true); - if (!root.get()) - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return 0; - } - else - { - list->Append(root); - *first_unparsed = end+1; // skip ] - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded; - *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList; - return 1; - } - } - else if (root_compiler_type_info.Test(eTypeIsPointer) && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield - *what_next == ValueObject::eExpressionPathAftermathDereference && - pointee_compiler_type_info.Test(eTypeIsScalar)) - { - Error error; - root = root->Dereference(error); - if (error.Fail() || !root.get()) - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDereferencingFailed; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return 0; - } - else - { - *what_next = ValueObject::eExpressionPathAftermathNothing; - continue; - } - } - else - { - for (unsigned long index = index_lower; - index <= index_higher; index++) - { - ValueObjectSP child = - root->GetChildAtIndex(index, true); - list->Append(child); - } - *first_unparsed = end+1; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded; - *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList; - return index_higher-index_lower+1; // tell me number of items I added to the VOList - } - } - break; - } - default: // some non-[ separator, or something entirely wrong, is in the way - { - *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; - *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; - return 0; - break; - } - } - } -} +ValueObjectSP ValueObject::CreateConstantValue(const ConstString &name) { + ValueObjectSP valobj_sp; -void -ValueObject::LogValueObject (Log *log) -{ - if (log) - return LogValueObject (log, DumpValueObjectOptions(*this)); -} + if (UpdateValueIfNeeded(false) && m_error.Success()) { + ExecutionContext exe_ctx(GetExecutionContextRef()); -void -ValueObject::LogValueObject (Log *log, const DumpValueObjectOptions& options) -{ - if (log) - { - StreamString s; - Dump (s, options); - if (s.GetSize()) - log->PutCString(s.GetData()); - } -} + DataExtractor data; + data.SetByteOrder(m_data.GetByteOrder()); + data.SetAddressByteSize(m_data.GetAddressByteSize()); -void -ValueObject::Dump (Stream &s) -{ - Dump (s, DumpValueObjectOptions(*this)); -} + if (IsBitfield()) { + Value v(Scalar(GetValueAsUnsigned(UINT64_MAX))); + m_error = v.GetValueAsData(&exe_ctx, data, 0, GetModule().get()); + } else + m_error = m_value.GetValueAsData(&exe_ctx, data, 0, GetModule().get()); -void -ValueObject::Dump (Stream &s, - const DumpValueObjectOptions& options) -{ - ValueObjectPrinter printer(this,&s,options); - printer.PrintValueObject(); -} + valobj_sp = ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), GetCompilerType(), name, data, + GetAddressOf()); + } -ValueObjectSP -ValueObject::CreateConstantValue (const ConstString &name) -{ - ValueObjectSP valobj_sp; - - if (UpdateValueIfNeeded(false) && m_error.Success()) - { - ExecutionContext exe_ctx (GetExecutionContextRef()); - - DataExtractor data; - data.SetByteOrder (m_data.GetByteOrder()); - data.SetAddressByteSize(m_data.GetAddressByteSize()); - - if (IsBitfield()) - { - Value v(Scalar(GetValueAsUnsigned(UINT64_MAX))); - m_error = v.GetValueAsData (&exe_ctx, data, 0, GetModule().get()); - } - else - m_error = m_value.GetValueAsData (&exe_ctx, data, 0, GetModule().get()); - - valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), - GetCompilerType(), - name, - data, - GetAddressOf()); - } - - if (!valobj_sp) - { - ExecutionContext exe_ctx (GetExecutionContextRef()); - valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), m_error); - } - return valobj_sp; + if (!valobj_sp) { + ExecutionContext exe_ctx(GetExecutionContextRef()); + valobj_sp = ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), m_error); + } + return valobj_sp; } -ValueObjectSP -ValueObject::GetQualifiedRepresentationIfAvailable (lldb::DynamicValueType dynValue, - bool synthValue) -{ - ValueObjectSP result_sp(GetSP()); - - switch (dynValue) - { - case lldb::eDynamicCanRunTarget: - case lldb::eDynamicDontRunTarget: - { - if (!result_sp->IsDynamic()) - { - if (result_sp->GetDynamicValue(dynValue)) - result_sp = result_sp->GetDynamicValue(dynValue); - } - } - break; - case lldb::eNoDynamicValues: - { - if (result_sp->IsDynamic()) - { - if (result_sp->GetStaticValue()) - result_sp = result_sp->GetStaticValue(); - } - } - break; +ValueObjectSP ValueObject::GetQualifiedRepresentationIfAvailable( + lldb::DynamicValueType dynValue, bool synthValue) { + ValueObjectSP result_sp(GetSP()); + + switch (dynValue) { + case lldb::eDynamicCanRunTarget: + case lldb::eDynamicDontRunTarget: { + if (!result_sp->IsDynamic()) { + if (result_sp->GetDynamicValue(dynValue)) + result_sp = result_sp->GetDynamicValue(dynValue); } - - if (synthValue) - { - if (!result_sp->IsSynthetic()) - { - if (result_sp->GetSyntheticValue()) - result_sp = result_sp->GetSyntheticValue(); - } + } break; + case lldb::eNoDynamicValues: { + if (result_sp->IsDynamic()) { + if (result_sp->GetStaticValue()) + result_sp = result_sp->GetStaticValue(); } - else - { - if (result_sp->IsSynthetic()) - { - if (result_sp->GetNonSyntheticValue()) - result_sp = result_sp->GetNonSyntheticValue(); - } - } - - return result_sp; -} + } break; + } -lldb::addr_t -ValueObject::GetCPPVTableAddress (AddressType &address_type) -{ - CompilerType pointee_type; - CompilerType this_type(GetCompilerType()); - uint32_t type_info = this_type.GetTypeInfo(&pointee_type); - if (type_info) - { - bool ptr_or_ref = false; - if (type_info & (eTypeIsPointer | eTypeIsReference)) - { - ptr_or_ref = true; - type_info = pointee_type.GetTypeInfo(); - } - - const uint32_t cpp_class = eTypeIsClass | eTypeIsCPlusPlus; - if ((type_info & cpp_class) == cpp_class) - { - if (ptr_or_ref) - { - address_type = GetAddressTypeOfChildren(); - return GetValueAsUnsigned(LLDB_INVALID_ADDRESS); - } - else - return GetAddressOf (false, &address_type); - } + if (synthValue) { + if (!result_sp->IsSynthetic()) { + if (result_sp->GetSyntheticValue()) + result_sp = result_sp->GetSyntheticValue(); + } + } else { + if (result_sp->IsSynthetic()) { + if (result_sp->GetNonSyntheticValue()) + result_sp = result_sp->GetNonSyntheticValue(); } + } - address_type = eAddressTypeInvalid; - return LLDB_INVALID_ADDRESS; + return result_sp; } -ValueObjectSP -ValueObject::Dereference (Error &error) -{ - if (m_deref_valobj) - return m_deref_valobj->GetSP(); - - const bool is_pointer_or_reference_type = IsPointerOrReferenceType(); - if (is_pointer_or_reference_type) - { - bool omit_empty_base_classes = true; - bool ignore_array_bounds = false; - - std::string child_name_str; - uint32_t child_byte_size = 0; - int32_t child_byte_offset = 0; - uint32_t child_bitfield_bit_size = 0; - uint32_t child_bitfield_bit_offset = 0; - bool child_is_base_class = false; - bool child_is_deref_of_parent = false; - const bool transparent_pointers = false; - CompilerType compiler_type = GetCompilerType(); - CompilerType child_compiler_type; - uint64_t language_flags; - - ExecutionContext exe_ctx (GetExecutionContextRef()); - - child_compiler_type = compiler_type.GetChildCompilerTypeAtIndex (&exe_ctx, - 0, - transparent_pointers, - omit_empty_base_classes, - ignore_array_bounds, - child_name_str, - child_byte_size, - child_byte_offset, - child_bitfield_bit_size, - child_bitfield_bit_offset, - child_is_base_class, - child_is_deref_of_parent, - this, - language_flags); - if (child_compiler_type && child_byte_size) - { - ConstString child_name; - if (!child_name_str.empty()) - child_name.SetCString (child_name_str.c_str()); - - m_deref_valobj = new ValueObjectChild (*this, - child_compiler_type, - child_name, - child_byte_size, - child_byte_offset, - child_bitfield_bit_size, - child_bitfield_bit_offset, - child_is_base_class, - child_is_deref_of_parent, - eAddressTypeInvalid, - language_flags); - } +lldb::addr_t ValueObject::GetCPPVTableAddress(AddressType &address_type) { + CompilerType pointee_type; + CompilerType this_type(GetCompilerType()); + uint32_t type_info = this_type.GetTypeInfo(&pointee_type); + if (type_info) { + bool ptr_or_ref = false; + if (type_info & (eTypeIsPointer | eTypeIsReference)) { + ptr_or_ref = true; + type_info = pointee_type.GetTypeInfo(); } - if (m_deref_valobj) - { - error.Clear(); - return m_deref_valobj->GetSP(); + const uint32_t cpp_class = eTypeIsClass | eTypeIsCPlusPlus; + if ((type_info & cpp_class) == cpp_class) { + if (ptr_or_ref) { + address_type = GetAddressTypeOfChildren(); + return GetValueAsUnsigned(LLDB_INVALID_ADDRESS); + } else + return GetAddressOf(false, &address_type); } - else - { - StreamString strm; - GetExpressionPath(strm, true); + } - if (is_pointer_or_reference_type) - error.SetErrorStringWithFormat("dereference failed: (%s) %s", GetTypeName().AsCString("<invalid type>"), strm.GetString().c_str()); - else - error.SetErrorStringWithFormat("not a pointer or reference type: (%s) %s", GetTypeName().AsCString("<invalid type>"), strm.GetString().c_str()); - return ValueObjectSP(); - } + address_type = eAddressTypeInvalid; + return LLDB_INVALID_ADDRESS; } -ValueObjectSP -ValueObject::AddressOf (Error &error) -{ - if (m_addr_of_valobj_sp) - return m_addr_of_valobj_sp; - - AddressType address_type = eAddressTypeInvalid; - const bool scalar_is_load_address = false; - addr_t addr = GetAddressOf (scalar_is_load_address, &address_type); - error.Clear(); - if (addr != LLDB_INVALID_ADDRESS && address_type != eAddressTypeHost) - { - switch (address_type) - { - case eAddressTypeInvalid: - { - StreamString expr_path_strm; - GetExpressionPath(expr_path_strm, true); - error.SetErrorStringWithFormat("'%s' is not in memory", expr_path_strm.GetString().c_str()); - } - break; - - case eAddressTypeFile: - case eAddressTypeLoad: - { - CompilerType compiler_type = GetCompilerType(); - if (compiler_type) - { - std::string name (1, '&'); - name.append (m_name.AsCString("")); - ExecutionContext exe_ctx (GetExecutionContextRef()); - m_addr_of_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), - compiler_type.GetPointerType(), - ConstString (name.c_str()), - addr, - eAddressTypeInvalid, - m_data.GetAddressByteSize()); - } - } - break; - default: - break; - } - } - else - { - StreamString expr_path_strm; - GetExpressionPath(expr_path_strm, true); - error.SetErrorStringWithFormat("'%s' doesn't have a valid address", expr_path_strm.GetString().c_str()); - } - - return m_addr_of_valobj_sp; -} +ValueObjectSP ValueObject::Dereference(Error &error) { + if (m_deref_valobj) + return m_deref_valobj->GetSP(); -ValueObjectSP -ValueObject::Cast (const CompilerType &compiler_type) -{ - return ValueObjectCast::Create (*this, GetName(), compiler_type); -} + const bool is_pointer_or_reference_type = IsPointerOrReferenceType(); + if (is_pointer_or_reference_type) { + bool omit_empty_base_classes = true; + bool ignore_array_bounds = false; -ValueObjectSP -ValueObject::CastPointerType (const char *name, CompilerType &compiler_type) -{ - ValueObjectSP valobj_sp; - AddressType address_type; - addr_t ptr_value = GetPointerValue (&address_type); - - if (ptr_value != LLDB_INVALID_ADDRESS) - { - Address ptr_addr (ptr_value); - ExecutionContext exe_ctx (GetExecutionContextRef()); - valobj_sp = ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(), - name, - ptr_addr, - compiler_type); - } - return valobj_sp; -} + std::string child_name_str; + uint32_t child_byte_size = 0; + int32_t child_byte_offset = 0; + uint32_t child_bitfield_bit_size = 0; + uint32_t child_bitfield_bit_offset = 0; + bool child_is_base_class = false; + bool child_is_deref_of_parent = false; + const bool transparent_pointers = false; + CompilerType compiler_type = GetCompilerType(); + CompilerType child_compiler_type; + uint64_t language_flags; -ValueObjectSP -ValueObject::CastPointerType (const char *name, TypeSP &type_sp) -{ - ValueObjectSP valobj_sp; - AddressType address_type; - addr_t ptr_value = GetPointerValue (&address_type); - - if (ptr_value != LLDB_INVALID_ADDRESS) - { - Address ptr_addr (ptr_value); - ExecutionContext exe_ctx (GetExecutionContextRef()); - valobj_sp = ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(), - name, - ptr_addr, - type_sp); - } - return valobj_sp; -} + ExecutionContext exe_ctx(GetExecutionContextRef()); -ValueObject::EvaluationPoint::EvaluationPoint () : - m_mod_id(), - m_exe_ctx_ref(), - m_needs_update (true) -{ -} + child_compiler_type = compiler_type.GetChildCompilerTypeAtIndex( + &exe_ctx, 0, transparent_pointers, omit_empty_base_classes, + ignore_array_bounds, child_name_str, child_byte_size, child_byte_offset, + child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, + child_is_deref_of_parent, this, language_flags); + if (child_compiler_type && child_byte_size) { + ConstString child_name; + if (!child_name_str.empty()) + child_name.SetCString(child_name_str.c_str()); -ValueObject::EvaluationPoint::EvaluationPoint (ExecutionContextScope *exe_scope, bool use_selected): - m_mod_id(), - m_exe_ctx_ref(), - m_needs_update (true) -{ - ExecutionContext exe_ctx(exe_scope); - TargetSP target_sp (exe_ctx.GetTargetSP()); - if (target_sp) - { - m_exe_ctx_ref.SetTargetSP (target_sp); - ProcessSP process_sp (exe_ctx.GetProcessSP()); - if (!process_sp) - process_sp = target_sp->GetProcessSP(); - - if (process_sp) - { - m_mod_id = process_sp->GetModID(); - m_exe_ctx_ref.SetProcessSP (process_sp); - - ThreadSP thread_sp (exe_ctx.GetThreadSP()); - - if (!thread_sp) - { - if (use_selected) - thread_sp = process_sp->GetThreadList().GetSelectedThread(); - } - - if (thread_sp) - { - m_exe_ctx_ref.SetThreadSP(thread_sp); - - StackFrameSP frame_sp (exe_ctx.GetFrameSP()); - if (!frame_sp) - { - if (use_selected) - frame_sp = thread_sp->GetSelectedFrame(); - } - if (frame_sp) - m_exe_ctx_ref.SetFrameSP(frame_sp); - } - } + m_deref_valobj = new ValueObjectChild( + *this, child_compiler_type, child_name, child_byte_size, + child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, + child_is_base_class, child_is_deref_of_parent, eAddressTypeInvalid, + language_flags); } -} + } -ValueObject::EvaluationPoint::EvaluationPoint (const ValueObject::EvaluationPoint &rhs) : - m_mod_id(), - m_exe_ctx_ref(rhs.m_exe_ctx_ref), - m_needs_update (true) -{ -} + if (m_deref_valobj) { + error.Clear(); + return m_deref_valobj->GetSP(); + } else { + StreamString strm; + GetExpressionPath(strm, true); -ValueObject::EvaluationPoint::~EvaluationPoint () -{ + if (is_pointer_or_reference_type) + error.SetErrorStringWithFormat("dereference failed: (%s) %s", + GetTypeName().AsCString("<invalid type>"), + strm.GetData()); + else + error.SetErrorStringWithFormat("not a pointer or reference type: (%s) %s", + GetTypeName().AsCString("<invalid type>"), + strm.GetData()); + return ValueObjectSP(); + } } -// This function checks the EvaluationPoint against the current process state. If the current -// state matches the evaluation point, or the evaluation point is already invalid, then we return -// false, meaning "no change". If the current state is different, we update our state, and return -// true meaning "yes, change". If we did see a change, we also set m_needs_update to true, so +ValueObjectSP ValueObject::AddressOf(Error &error) { + if (m_addr_of_valobj_sp) + return m_addr_of_valobj_sp; + + AddressType address_type = eAddressTypeInvalid; + const bool scalar_is_load_address = false; + addr_t addr = GetAddressOf(scalar_is_load_address, &address_type); + error.Clear(); + if (addr != LLDB_INVALID_ADDRESS && address_type != eAddressTypeHost) { + switch (address_type) { + case eAddressTypeInvalid: { + StreamString expr_path_strm; + GetExpressionPath(expr_path_strm, true); + error.SetErrorStringWithFormat("'%s' is not in memory", + expr_path_strm.GetData()); + } break; + + case eAddressTypeFile: + case eAddressTypeLoad: { + CompilerType compiler_type = GetCompilerType(); + if (compiler_type) { + std::string name(1, '&'); + name.append(m_name.AsCString("")); + ExecutionContext exe_ctx(GetExecutionContextRef()); + m_addr_of_valobj_sp = ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + compiler_type.GetPointerType(), ConstString(name.c_str()), addr, + eAddressTypeInvalid, m_data.GetAddressByteSize()); + } + } break; + default: + break; + } + } else { + StreamString expr_path_strm; + GetExpressionPath(expr_path_strm, true); + error.SetErrorStringWithFormat("'%s' doesn't have a valid address", + expr_path_strm.GetData()); + } + + return m_addr_of_valobj_sp; +} + +ValueObjectSP ValueObject::Cast(const CompilerType &compiler_type) { + return ValueObjectCast::Create(*this, GetName(), compiler_type); +} + +ValueObjectSP ValueObject::CastPointerType(const char *name, + CompilerType &compiler_type) { + ValueObjectSP valobj_sp; + AddressType address_type; + addr_t ptr_value = GetPointerValue(&address_type); + + if (ptr_value != LLDB_INVALID_ADDRESS) { + Address ptr_addr(ptr_value); + ExecutionContext exe_ctx(GetExecutionContextRef()); + valobj_sp = ValueObjectMemory::Create( + exe_ctx.GetBestExecutionContextScope(), name, ptr_addr, compiler_type); + } + return valobj_sp; +} + +ValueObjectSP ValueObject::CastPointerType(const char *name, TypeSP &type_sp) { + ValueObjectSP valobj_sp; + AddressType address_type; + addr_t ptr_value = GetPointerValue(&address_type); + + if (ptr_value != LLDB_INVALID_ADDRESS) { + Address ptr_addr(ptr_value); + ExecutionContext exe_ctx(GetExecutionContextRef()); + valobj_sp = ValueObjectMemory::Create( + exe_ctx.GetBestExecutionContextScope(), name, ptr_addr, type_sp); + } + return valobj_sp; +} + +ValueObject::EvaluationPoint::EvaluationPoint() + : m_mod_id(), m_exe_ctx_ref(), m_needs_update(true) {} + +ValueObject::EvaluationPoint::EvaluationPoint(ExecutionContextScope *exe_scope, + bool use_selected) + : m_mod_id(), m_exe_ctx_ref(), m_needs_update(true) { + ExecutionContext exe_ctx(exe_scope); + TargetSP target_sp(exe_ctx.GetTargetSP()); + if (target_sp) { + m_exe_ctx_ref.SetTargetSP(target_sp); + ProcessSP process_sp(exe_ctx.GetProcessSP()); + if (!process_sp) + process_sp = target_sp->GetProcessSP(); + + if (process_sp) { + m_mod_id = process_sp->GetModID(); + m_exe_ctx_ref.SetProcessSP(process_sp); + + ThreadSP thread_sp(exe_ctx.GetThreadSP()); + + if (!thread_sp) { + if (use_selected) + thread_sp = process_sp->GetThreadList().GetSelectedThread(); + } + + if (thread_sp) { + m_exe_ctx_ref.SetThreadSP(thread_sp); + + StackFrameSP frame_sp(exe_ctx.GetFrameSP()); + if (!frame_sp) { + if (use_selected) + frame_sp = thread_sp->GetSelectedFrame(); + } + if (frame_sp) + m_exe_ctx_ref.SetFrameSP(frame_sp); + } + } + } +} + +ValueObject::EvaluationPoint::EvaluationPoint( + const ValueObject::EvaluationPoint &rhs) + : m_mod_id(), m_exe_ctx_ref(rhs.m_exe_ctx_ref), m_needs_update(true) {} + +ValueObject::EvaluationPoint::~EvaluationPoint() {} + +// This function checks the EvaluationPoint against the current process state. +// If the current +// state matches the evaluation point, or the evaluation point is already +// invalid, then we return +// false, meaning "no change". If the current state is different, we update our +// state, and return +// true meaning "yes, change". If we did see a change, we also set +// m_needs_update to true, so // future calls to NeedsUpdate will return true. // exe_scope will be set to the current execution context scope. -bool -ValueObject::EvaluationPoint::SyncWithProcessState(bool accept_invalid_exe_ctx) -{ - // Start with the target, if it is NULL, then we're obviously not going to get any further: - const bool thread_and_frame_only_if_stopped = true; - ExecutionContext exe_ctx(m_exe_ctx_ref.Lock(thread_and_frame_only_if_stopped)); - - if (exe_ctx.GetTargetPtr() == NULL) - return false; - - // If we don't have a process nothing can change. - Process *process = exe_ctx.GetProcessPtr(); - if (process == NULL) - return false; - - // If our stop id is the current stop ID, nothing has changed: - ProcessModID current_mod_id = process->GetModID(); - - // If the current stop id is 0, either we haven't run yet, or the process state has been cleared. - // In either case, we aren't going to be able to sync with the process state. - if (current_mod_id.GetStopID() == 0) - return false; - - bool changed = false; - const bool was_valid = m_mod_id.IsValid(); - if (was_valid) - { - if (m_mod_id == current_mod_id) - { - // Everything is already up to date in this object, no need to - // update the execution context scope. - changed = false; - } - else - { - m_mod_id = current_mod_id; - m_needs_update = true; - changed = true; - } - } - - // Now re-look up the thread and frame in case the underlying objects have gone away & been recreated. - // That way we'll be sure to return a valid exe_scope. - // If we used to have a thread or a frame but can't find it anymore, then mark ourselves as invalid. - - if (!accept_invalid_exe_ctx) - { - if (m_exe_ctx_ref.HasThreadRef()) - { - ThreadSP thread_sp (m_exe_ctx_ref.GetThreadSP()); - if (thread_sp) - { - if (m_exe_ctx_ref.HasFrameRef()) - { - StackFrameSP frame_sp (m_exe_ctx_ref.GetFrameSP()); - if (!frame_sp) - { - // We used to have a frame, but now it is gone - SetInvalid(); - changed = was_valid; - } - } - } - else - { - // We used to have a thread, but now it is gone - SetInvalid(); - changed = was_valid; - } - } - } +bool ValueObject::EvaluationPoint::SyncWithProcessState( + bool accept_invalid_exe_ctx) { + // Start with the target, if it is NULL, then we're obviously not going to get + // any further: + const bool thread_and_frame_only_if_stopped = true; + ExecutionContext exe_ctx( + m_exe_ctx_ref.Lock(thread_and_frame_only_if_stopped)); - return changed; -} + if (exe_ctx.GetTargetPtr() == NULL) + return false; -void -ValueObject::EvaluationPoint::SetUpdated () -{ - ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP()); - if (process_sp) - m_mod_id = process_sp->GetModID(); - m_needs_update = false; -} - - - -void -ValueObject::ClearUserVisibleData(uint32_t clear_mask) -{ - if ((clear_mask & eClearUserVisibleDataItemsValue) == eClearUserVisibleDataItemsValue) - m_value_str.clear(); - - if ((clear_mask & eClearUserVisibleDataItemsLocation) == eClearUserVisibleDataItemsLocation) - m_location_str.clear(); - - if ((clear_mask & eClearUserVisibleDataItemsSummary) == eClearUserVisibleDataItemsSummary) - m_summary_str.clear(); - - if ((clear_mask & eClearUserVisibleDataItemsDescription) == eClearUserVisibleDataItemsDescription) - m_object_desc_str.clear(); - - if ((clear_mask & eClearUserVisibleDataItemsSyntheticChildren) == eClearUserVisibleDataItemsSyntheticChildren) - { - if (m_synthetic_value) - m_synthetic_value = NULL; - } - - if ((clear_mask & eClearUserVisibleDataItemsValidator) == eClearUserVisibleDataItemsValidator) - m_validation_result.reset(); -} + // If we don't have a process nothing can change. + Process *process = exe_ctx.GetProcessPtr(); + if (process == NULL) + return false; -SymbolContextScope * -ValueObject::GetSymbolContextScope() -{ - if (m_parent) - { - if (!m_parent->IsPointerOrReferenceType()) - return m_parent->GetSymbolContextScope(); - } - return NULL; -} + // If our stop id is the current stop ID, nothing has changed: + ProcessModID current_mod_id = process->GetModID(); -lldb::ValueObjectSP -ValueObject::CreateValueObjectFromExpression (const char* name, - const char* expression, - const ExecutionContext& exe_ctx) -{ - return CreateValueObjectFromExpression(name, expression, exe_ctx, EvaluateExpressionOptions()); -} + // If the current stop id is 0, either we haven't run yet, or the process + // state has been cleared. + // In either case, we aren't going to be able to sync with the process state. + if (current_mod_id.GetStopID() == 0) + return false; + bool changed = false; + const bool was_valid = m_mod_id.IsValid(); + if (was_valid) { + if (m_mod_id == current_mod_id) { + // Everything is already up to date in this object, no need to + // update the execution context scope. + changed = false; + } else { + m_mod_id = current_mod_id; + m_needs_update = true; + changed = true; + } + } + + // Now re-look up the thread and frame in case the underlying objects have + // gone away & been recreated. + // That way we'll be sure to return a valid exe_scope. + // If we used to have a thread or a frame but can't find it anymore, then mark + // ourselves as invalid. + + if (!accept_invalid_exe_ctx) { + if (m_exe_ctx_ref.HasThreadRef()) { + ThreadSP thread_sp(m_exe_ctx_ref.GetThreadSP()); + if (thread_sp) { + if (m_exe_ctx_ref.HasFrameRef()) { + StackFrameSP frame_sp(m_exe_ctx_ref.GetFrameSP()); + if (!frame_sp) { + // We used to have a frame, but now it is gone + SetInvalid(); + changed = was_valid; + } + } + } else { + // We used to have a thread, but now it is gone + SetInvalid(); + changed = was_valid; + } + } + } + + return changed; +} + +void ValueObject::EvaluationPoint::SetUpdated() { + ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP()); + if (process_sp) + m_mod_id = process_sp->GetModID(); + m_needs_update = false; +} + +void ValueObject::ClearUserVisibleData(uint32_t clear_mask) { + if ((clear_mask & eClearUserVisibleDataItemsValue) == + eClearUserVisibleDataItemsValue) + m_value_str.clear(); + + if ((clear_mask & eClearUserVisibleDataItemsLocation) == + eClearUserVisibleDataItemsLocation) + m_location_str.clear(); + + if ((clear_mask & eClearUserVisibleDataItemsSummary) == + eClearUserVisibleDataItemsSummary) + m_summary_str.clear(); + + if ((clear_mask & eClearUserVisibleDataItemsDescription) == + eClearUserVisibleDataItemsDescription) + m_object_desc_str.clear(); + + if ((clear_mask & eClearUserVisibleDataItemsSyntheticChildren) == + eClearUserVisibleDataItemsSyntheticChildren) { + if (m_synthetic_value) + m_synthetic_value = NULL; + } -lldb::ValueObjectSP -ValueObject::CreateValueObjectFromExpression (const char* name, - const char* expression, - const ExecutionContext& exe_ctx, - const EvaluateExpressionOptions& options) -{ - lldb::ValueObjectSP retval_sp; - lldb::TargetSP target_sp(exe_ctx.GetTargetSP()); - if (!target_sp) - return retval_sp; - if (!expression || !*expression) - return retval_sp; - target_sp->EvaluateExpression (expression, - exe_ctx.GetFrameSP().get(), - retval_sp, - options); - if (retval_sp && name && *name) - retval_sp->SetName(ConstString(name)); - return retval_sp; + if ((clear_mask & eClearUserVisibleDataItemsValidator) == + eClearUserVisibleDataItemsValidator) + m_validation_result.reset(); } -lldb::ValueObjectSP -ValueObject::CreateValueObjectFromAddress (const char* name, - uint64_t address, - const ExecutionContext& exe_ctx, - CompilerType type) -{ - if (type) - { - CompilerType pointer_type(type.GetPointerType()); - if (pointer_type) - { - lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(&address,sizeof(lldb::addr_t))); - lldb::ValueObjectSP ptr_result_valobj_sp(ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), - pointer_type, - ConstString(name), - buffer, - exe_ctx.GetByteOrder(), - exe_ctx.GetAddressByteSize())); - if (ptr_result_valobj_sp) - { - ptr_result_valobj_sp->GetValue().SetValueType(Value::eValueTypeLoadAddress); - Error err; - ptr_result_valobj_sp = ptr_result_valobj_sp->Dereference(err); - if (ptr_result_valobj_sp && name && *name) - ptr_result_valobj_sp->SetName(ConstString(name)); - } - return ptr_result_valobj_sp; - } - } - return lldb::ValueObjectSP(); +SymbolContextScope *ValueObject::GetSymbolContextScope() { + if (m_parent) { + if (!m_parent->IsPointerOrReferenceType()) + return m_parent->GetSymbolContextScope(); + } + return NULL; } lldb::ValueObjectSP -ValueObject::CreateValueObjectFromData (const char* name, - const DataExtractor& data, - const ExecutionContext& exe_ctx, - CompilerType type) -{ - lldb::ValueObjectSP new_value_sp; - new_value_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), - type, - ConstString(name), - data, - LLDB_INVALID_ADDRESS); - new_value_sp->SetAddressTypeOfChildren(eAddressTypeLoad); - if (new_value_sp && name && *name) - new_value_sp->SetName(ConstString(name)); - return new_value_sp; +ValueObject::CreateValueObjectFromExpression(llvm::StringRef name, + llvm::StringRef expression, + const ExecutionContext &exe_ctx) { + return CreateValueObjectFromExpression(name, expression, exe_ctx, + EvaluateExpressionOptions()); +} + +lldb::ValueObjectSP ValueObject::CreateValueObjectFromExpression( + llvm::StringRef name, llvm::StringRef expression, + const ExecutionContext &exe_ctx, const EvaluateExpressionOptions &options) { + lldb::ValueObjectSP retval_sp; + lldb::TargetSP target_sp(exe_ctx.GetTargetSP()); + if (!target_sp) + return retval_sp; + if (expression.empty()) + return retval_sp; + target_sp->EvaluateExpression(expression, exe_ctx.GetFrameSP().get(), + retval_sp, options); + if (retval_sp && !name.empty()) + retval_sp->SetName(ConstString(name)); + return retval_sp; +} + +lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress( + llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx, + CompilerType type) { + if (type) { + CompilerType pointer_type(type.GetPointerType()); + if (pointer_type) { + lldb::DataBufferSP buffer( + new lldb_private::DataBufferHeap(&address, sizeof(lldb::addr_t))); + lldb::ValueObjectSP ptr_result_valobj_sp(ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), pointer_type, + ConstString(name), buffer, exe_ctx.GetByteOrder(), + exe_ctx.GetAddressByteSize())); + if (ptr_result_valobj_sp) { + ptr_result_valobj_sp->GetValue().SetValueType( + Value::eValueTypeLoadAddress); + Error err; + ptr_result_valobj_sp = ptr_result_valobj_sp->Dereference(err); + if (ptr_result_valobj_sp && !name.empty()) + ptr_result_valobj_sp->SetName(ConstString(name)); + } + return ptr_result_valobj_sp; + } + } + return lldb::ValueObjectSP(); +} + +lldb::ValueObjectSP ValueObject::CreateValueObjectFromData( + llvm::StringRef name, const DataExtractor &data, + const ExecutionContext &exe_ctx, CompilerType type) { + lldb::ValueObjectSP new_value_sp; + new_value_sp = ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), type, ConstString(name), data, + LLDB_INVALID_ADDRESS); + new_value_sp->SetAddressTypeOfChildren(eAddressTypeLoad); + if (new_value_sp && !name.empty()) + new_value_sp->SetName(ConstString(name)); + return new_value_sp; +} + +ModuleSP ValueObject::GetModule() { + ValueObject *root(GetRoot()); + if (root != this) + return root->GetModule(); + return lldb::ModuleSP(); +} + +ValueObject *ValueObject::GetRoot() { + if (m_root) + return m_root; + return (m_root = FollowParentChain([](ValueObject *vo) -> bool { + return (vo->m_parent != nullptr); + })); } -ModuleSP -ValueObject::GetModule () -{ - ValueObject* root(GetRoot()); +ValueObject * +ValueObject::FollowParentChain(std::function<bool(ValueObject *)> f) { + ValueObject *vo = this; + while (vo) { + if (f(vo) == false) + break; + vo = vo->m_parent; + } + return vo; +} + +AddressType ValueObject::GetAddressTypeOfChildren() { + if (m_address_type_of_ptr_or_ref_children == eAddressTypeInvalid) { + ValueObject *root(GetRoot()); if (root != this) - return root->GetModule(); - return lldb::ModuleSP(); + return root->GetAddressTypeOfChildren(); + } + return m_address_type_of_ptr_or_ref_children; } -ValueObject* -ValueObject::GetRoot () -{ - if (m_root) - return m_root; - return (m_root = FollowParentChain( [] (ValueObject* vo) -> bool { - return (vo->m_parent != nullptr); - })); +lldb::DynamicValueType ValueObject::GetDynamicValueType() { + ValueObject *with_dv_info = this; + while (with_dv_info) { + if (with_dv_info->HasDynamicValueTypeInfo()) + return with_dv_info->GetDynamicValueTypeImpl(); + with_dv_info = with_dv_info->m_parent; + } + return lldb::eNoDynamicValues; } -ValueObject* -ValueObject::FollowParentChain (std::function<bool(ValueObject*)> f) -{ - ValueObject* vo = this; - while (vo) - { - if (f(vo) == false) - break; - vo = vo->m_parent; - } - return vo; +lldb::Format ValueObject::GetFormat() const { + const ValueObject *with_fmt_info = this; + while (with_fmt_info) { + if (with_fmt_info->m_format != lldb::eFormatDefault) + return with_fmt_info->m_format; + with_fmt_info = with_fmt_info->m_parent; + } + return m_format; } -AddressType -ValueObject::GetAddressTypeOfChildren() -{ - if (m_address_type_of_ptr_or_ref_children == eAddressTypeInvalid) - { - ValueObject* root(GetRoot()); - if (root != this) - return root->GetAddressTypeOfChildren(); +lldb::LanguageType ValueObject::GetPreferredDisplayLanguage() { + lldb::LanguageType type = m_preferred_display_language; + if (m_preferred_display_language == lldb::eLanguageTypeUnknown) { + if (GetRoot()) { + if (GetRoot() == this) { + if (StackFrameSP frame_sp = GetFrameSP()) { + const SymbolContext &sc( + frame_sp->GetSymbolContext(eSymbolContextCompUnit)); + if (CompileUnit *cu = sc.comp_unit) + type = cu->GetLanguage(); + } + } else { + type = GetRoot()->GetPreferredDisplayLanguage(); + } } - return m_address_type_of_ptr_or_ref_children; + } + return (m_preferred_display_language = type); // only compute it once } -lldb::DynamicValueType -ValueObject::GetDynamicValueType () -{ - ValueObject* with_dv_info = this; - while (with_dv_info) - { - if (with_dv_info->HasDynamicValueTypeInfo()) - return with_dv_info->GetDynamicValueTypeImpl(); - with_dv_info = with_dv_info->m_parent; - } - return lldb::eNoDynamicValues; +void ValueObject::SetPreferredDisplayLanguage(lldb::LanguageType lt) { + m_preferred_display_language = lt; } -lldb::Format -ValueObject::GetFormat () const -{ - const ValueObject* with_fmt_info = this; - while (with_fmt_info) - { - if (with_fmt_info->m_format != lldb::eFormatDefault) - return with_fmt_info->m_format; - with_fmt_info = with_fmt_info->m_parent; - } - return m_format; +void ValueObject::SetPreferredDisplayLanguageIfNeeded(lldb::LanguageType lt) { + if (m_preferred_display_language == lldb::eLanguageTypeUnknown) + SetPreferredDisplayLanguage(lt); } -lldb::LanguageType -ValueObject::GetPreferredDisplayLanguage () -{ - lldb::LanguageType type = m_preferred_display_language; - if (m_preferred_display_language == lldb::eLanguageTypeUnknown) - { - if (GetRoot()) - { - if (GetRoot() == this) - { - if (StackFrameSP frame_sp = GetFrameSP()) - { - const SymbolContext& sc(frame_sp->GetSymbolContext(eSymbolContextCompUnit)); - if (CompileUnit* cu = sc.comp_unit) - type = cu->GetLanguage(); - } - } - else - { - type = GetRoot()->GetPreferredDisplayLanguage(); - } - } - } - return (m_preferred_display_language = type); // only compute it once +bool ValueObject::CanProvideValue() { + // we need to support invalid types as providers of values because some + // bare-board + // debugging scenarios have no notion of types, but still manage to have raw + // numeric + // values for things like registers. sigh. + const CompilerType &type(GetCompilerType()); + return (false == type.IsValid()) || + (0 != (type.GetTypeInfo() & eTypeHasValue)); } -void -ValueObject::SetPreferredDisplayLanguage (lldb::LanguageType lt) -{ - m_preferred_display_language = lt; -} +bool ValueObject::IsChecksumEmpty() { return m_value_checksum.empty(); } -void -ValueObject::SetPreferredDisplayLanguageIfNeeded (lldb::LanguageType lt) -{ - if (m_preferred_display_language == lldb::eLanguageTypeUnknown) - SetPreferredDisplayLanguage(lt); -} +ValueObjectSP ValueObject::Persist() { + if (!UpdateValueIfNeeded()) + return nullptr; -bool -ValueObject::CanProvideValue () -{ - // we need to support invalid types as providers of values because some bare-board - // debugging scenarios have no notion of types, but still manage to have raw numeric - // values for things like registers. sigh. - const CompilerType &type(GetCompilerType()); - return (false == type.IsValid()) || (0 != (type.GetTypeInfo() & eTypeHasValue)); -} + TargetSP target_sp(GetTargetSP()); + if (!target_sp) + return nullptr; + + PersistentExpressionState *persistent_state = + target_sp->GetPersistentExpressionStateForLanguage( + GetPreferredDisplayLanguage()); + + if (!persistent_state) + return nullptr; -bool -ValueObject::IsChecksumEmpty () -{ - return m_value_checksum.empty(); + ConstString name(persistent_state->GetNextPersistentVariableName()); + + ValueObjectSP const_result_sp = + ValueObjectConstResult::Create(target_sp.get(), GetValue(), name); + + ExpressionVariableSP clang_var_sp = + persistent_state->CreatePersistentVariable(const_result_sp); + clang_var_sp->m_live_sp = clang_var_sp->m_frozen_sp; + clang_var_sp->m_flags |= ExpressionVariable::EVIsProgramReference; + + return clang_var_sp->GetValueObject(); } -ValueObjectSP -ValueObject::Persist () -{ - if (!UpdateValueIfNeeded()) - return nullptr; - - TargetSP target_sp(GetTargetSP()); - if (!target_sp) - return nullptr; - - PersistentExpressionState *persistent_state = target_sp->GetPersistentExpressionStateForLanguage(GetPreferredDisplayLanguage()); - - if (!persistent_state) - return nullptr; - - ConstString name(persistent_state->GetNextPersistentVariableName()); - - ValueObjectSP const_result_sp = ValueObjectConstResult::Create (target_sp.get(), GetValue(), name); - - ExpressionVariableSP clang_var_sp = persistent_state->CreatePersistentVariable(const_result_sp); - clang_var_sp->m_live_sp = clang_var_sp->m_frozen_sp; - clang_var_sp->m_flags |= ExpressionVariable::EVIsProgramReference; - - return clang_var_sp->GetValueObject(); +bool ValueObject::IsSyntheticChildrenGenerated() { + return m_is_synthetic_children_generated; } -bool -ValueObject::IsSyntheticChildrenGenerated () -{ - return m_is_synthetic_children_generated; +void ValueObject::SetSyntheticChildrenGenerated(bool b) { + m_is_synthetic_children_generated = b; } -void -ValueObject::SetSyntheticChildrenGenerated (bool b) -{ - m_is_synthetic_children_generated = b; +uint64_t ValueObject::GetLanguageFlags() { return m_language_flags; } + +void ValueObject::SetLanguageFlags(uint64_t flags) { m_language_flags = flags; } + +ValueObjectManager::ValueObjectManager(lldb::ValueObjectSP in_valobj_sp, + lldb::DynamicValueType use_dynamic, + bool use_synthetic) : m_root_valobj_sp(), + m_user_valobj_sp(), m_use_dynamic(use_dynamic), m_stop_id(UINT32_MAX), + m_use_synthetic(use_synthetic) { + if (!in_valobj_sp) + return; + // If the user passes in a value object that is dynamic or synthetic, then + // water it down to the static type. + m_root_valobj_sp = in_valobj_sp->GetQualifiedRepresentationIfAvailable(lldb::eNoDynamicValues, false); } -uint64_t -ValueObject::GetLanguageFlags () -{ - return m_language_flags; +bool ValueObjectManager::IsValid() const { + if (!m_root_valobj_sp) + return false; + lldb::TargetSP target_sp = GetTargetSP(); + if (target_sp) + return target_sp->IsValid(); + return false; } -void -ValueObject::SetLanguageFlags (uint64_t flags) -{ - m_language_flags = flags; +lldb::ValueObjectSP ValueObjectManager::GetSP() { + lldb::ProcessSP process_sp = GetProcessSP(); + if (!process_sp) + return lldb::ValueObjectSP(); + + const uint32_t current_stop_id = process_sp->GetLastNaturalStopID(); + if (current_stop_id == m_stop_id) + return m_user_valobj_sp; + + m_stop_id = current_stop_id; + + if (!m_root_valobj_sp) { + m_user_valobj_sp.reset(); + return m_root_valobj_sp; + } + + m_user_valobj_sp = m_root_valobj_sp; + + if (m_use_dynamic != lldb::eNoDynamicValues) { + lldb::ValueObjectSP dynamic_sp = m_user_valobj_sp->GetDynamicValue(m_use_dynamic); + if (dynamic_sp) + m_user_valobj_sp = dynamic_sp; + } + + if (m_use_synthetic) { + lldb::ValueObjectSP synthetic_sp = m_user_valobj_sp->GetSyntheticValue(m_use_synthetic); + if (synthetic_sp) + m_user_valobj_sp = synthetic_sp; + } + + return m_user_valobj_sp; +} + +void ValueObjectManager::SetUseDynamic(lldb::DynamicValueType use_dynamic) { + if (use_dynamic != m_use_dynamic) { + m_use_dynamic = use_dynamic; + m_user_valobj_sp.reset(); + m_stop_id = UINT32_MAX; + } +} + +void ValueObjectManager::SetUseSynthetic(bool use_synthetic) { + if (m_use_synthetic != use_synthetic) { + m_use_synthetic = use_synthetic; + m_user_valobj_sp.reset(); + m_stop_id = UINT32_MAX; + } +} + +lldb::TargetSP ValueObjectManager::GetTargetSP() const { + if (!m_root_valobj_sp) + return m_root_valobj_sp->GetTargetSP(); + return lldb::TargetSP(); +} + +lldb::ProcessSP ValueObjectManager::GetProcessSP() const { + if (m_root_valobj_sp) + return m_root_valobj_sp->GetProcessSP(); + return lldb::ProcessSP(); +} + +lldb::ThreadSP ValueObjectManager::GetThreadSP() const { + if (m_root_valobj_sp) + return m_root_valobj_sp->GetThreadSP(); + return lldb::ThreadSP(); +} + +lldb::StackFrameSP ValueObjectManager::GetFrameSP() const { + if (m_root_valobj_sp) + return m_root_valobj_sp->GetFrameSP(); + return lldb::StackFrameSP(); } + |