diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h --- a/lldb/include/lldb/Core/ValueObject.h +++ b/lldb/include/lldb/Core/ValueObject.h @@ -963,9 +963,14 @@ void SetPreferredDisplayLanguageIfNeeded(lldb::LanguageType); +protected: + virtual void DoUpdateChildrenAddressType(ValueObject &valobj) { return; }; + private: virtual CompilerType MaybeCalculateCompleteType(); - void UpdateChildrenAddressType(); + void UpdateChildrenAddressType() { + GetRoot()->DoUpdateChildrenAddressType(*this); + } lldb::ValueObjectSP GetValueForExpressionPath_Impl( llvm::StringRef expression_cstr, diff --git a/lldb/include/lldb/Core/ValueObjectVariable.h b/lldb/include/lldb/Core/ValueObjectVariable.h --- a/lldb/include/lldb/Core/ValueObjectVariable.h +++ b/lldb/include/lldb/Core/ValueObjectVariable.h @@ -67,6 +67,8 @@ protected: bool UpdateValue() override; + + void DoUpdateChildrenAddressType(ValueObject &valobj) override; CompilerType GetCompilerTypeImpl() override; diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -140,58 +140,6 @@ // Destructor ValueObject::~ValueObject() {} -void ValueObject::UpdateChildrenAddressType() { - Value::ValueType value_type = m_value.GetValueType(); - ExecutionContext exe_ctx(GetExecutionContextRef()); - Process *process = exe_ctx.GetProcessPtr(); - const bool process_is_alive = process && process->IsAlive(); - const uint32_t type_info = GetCompilerType().GetTypeInfo(); - const bool is_pointer_or_ref = - (type_info & (lldb::eTypeIsPointer | lldb::eTypeIsReference)) != 0; - - switch (value_type) { - case Value::eValueTypeFileAddress: - // If this type is a pointer, then its children will be considered load - // addresses if the pointer or reference is dereferenced, but only if - // the process is alive. - // - // There could be global variables like in the following code: - // struct LinkedListNode { Foo* foo; LinkedListNode* next; }; - // Foo g_foo1; - // Foo g_foo2; - // LinkedListNode g_second_node = { &g_foo2, NULL }; - // LinkedListNode g_first_node = { &g_foo1, &g_second_node }; - // - // When we aren't running, we should be able to look at these variables - // using the "target variable" command. Children of the "g_first_node" - // always will be of the same address type as the parent. But children - // of the "next" member of LinkedListNode will become load addresses if - // we have a live process, or remain a file address if it was a file - // address. - if (process_is_alive && is_pointer_or_ref) - SetAddressTypeOfChildren(eAddressTypeLoad); - else - SetAddressTypeOfChildren(eAddressTypeFile); - break; - case Value::eValueTypeHostAddress: - // Same as above for load addresses, except children of pointer or refs - // are always load addresses. Host addresses are used to store freeze - // dried variables. If this type is a struct, the entire struct - // contents will be copied into the heap of the - // LLDB process, but we do not currently follow any pointers. - if (is_pointer_or_ref) - SetAddressTypeOfChildren(eAddressTypeLoad); - else - SetAddressTypeOfChildren(eAddressTypeHost); - break; - case Value::eValueTypeLoadAddress: - case Value::eValueTypeScalar: - case Value::eValueTypeVector: - SetAddressTypeOfChildren(eAddressTypeLoad); - break; - } -} - bool ValueObject::UpdateValueIfNeeded(bool update_format) { bool did_change_formats = false; diff --git a/lldb/source/Core/ValueObjectVariable.cpp b/lldb/source/Core/ValueObjectVariable.cpp --- a/lldb/source/Core/ValueObjectVariable.cpp +++ b/lldb/source/Core/ValueObjectVariable.cpp @@ -242,9 +242,64 @@ m_resolved_value.SetContext(Value::eContextTypeInvalid, nullptr); } } + return m_error.Success(); } +void ValueObjectVariable::DoUpdateChildrenAddressType(ValueObject &valobj) { + Value::ValueType value_type = valobj.GetValue().GetValueType(); + ExecutionContext exe_ctx(GetExecutionContextRef()); + Process *process = exe_ctx.GetProcessPtr(); + const bool process_is_alive = process && process->IsAlive(); + const uint32_t type_info = valobj.GetCompilerType().GetTypeInfo(); + const bool is_pointer_or_ref = + (type_info & (lldb::eTypeIsPointer | lldb::eTypeIsReference)) != 0; + + switch (value_type) { + case Value::eValueTypeFileAddress: + // If this type is a pointer, then its children will be considered load + // addresses if the pointer or reference is dereferenced, but only if + // the process is alive. + // + // There could be global variables like in the following code: + // struct LinkedListNode { Foo* foo; LinkedListNode* next; }; + // Foo g_foo1; + // Foo g_foo2; + // LinkedListNode g_second_node = { &g_foo2, NULL }; + // LinkedListNode g_first_node = { &g_foo1, &g_second_node }; + // + // When we aren't running, we should be able to look at these variables + // using the "target variable" command. Children of the "g_first_node" + // always will be of the same address type as the parent. But children + // of the "next" member of LinkedListNode will become load addresses if + // we have a live process, or remain a file address if it was a file + // address. + if (process_is_alive && is_pointer_or_ref) + valobj.SetAddressTypeOfChildren(eAddressTypeLoad); + else + valobj.SetAddressTypeOfChildren(eAddressTypeFile); + break; + case Value::eValueTypeHostAddress: + // Same as above for load addresses, except children of pointer or refs + // are always load addresses. Host addresses are used to store freeze + // dried variables. If this type is a struct, the entire struct + // contents will be copied into the heap of the + // LLDB process, but we do not currently follow any pointers. + if (is_pointer_or_ref) + valobj.SetAddressTypeOfChildren(eAddressTypeLoad); + else + valobj.SetAddressTypeOfChildren(eAddressTypeHost); + break; + case Value::eValueTypeLoadAddress: + case Value::eValueTypeScalar: + case Value::eValueTypeVector: + valobj.SetAddressTypeOfChildren(eAddressTypeLoad); + break; + } +} + + + bool ValueObjectVariable::IsInScope() { const ExecutionContextRef &exe_ctx_ref = GetExecutionContextRef(); if (exe_ctx_ref.HasFrameRef()) {