From e3e91517ffd7e63bcb5b9d196f85e2b09802b414 Mon Sep 17 00:00:00 2001 From: Enrico Granata Date: Mon, 22 Oct 2012 18:18:36 +0000 Subject: [PATCH] Given our implementation of ValueObjects we could have a scenario where a ValueObject has a dynamic type of Foo* at one point, and then its dynamic type changes to Bar* If Bar* has synthetic children enabled, by the time we figure that out, our public API is already vending SBValues wrapping a DynamicVO, instead of a SyntheticVO and there was no trivial way for us to change the SP inside an SBValue on the fly This checkin reimplements SBValue in terms of a wrapper, ValueImpl, that allows this substitutions on-the-fly by overriding GetSP() to do The Right Thing (TM) As an additional bonus, GetNonSyntheticValue() now works, and we can get rid of the ForceDisableSyntheticChildren idiom in ScriptInterpreterPython Lastly, this checkin makes sure the synthetic VOs get the correct m_value and m_data from their parents (prevented summaries from working in some cases) llvm-svn: 166426 --- lldb/include/lldb/API/SBValue.h | 47 +++- lldb/include/lldb/Core/ValueObject.h | 2 +- .../include/lldb/Core/ValueObjectSyntheticFilter.h | 3 + lldb/scripts/Python/interface/SBValue.i | 15 + lldb/scripts/Python/python-wrapper.swig | 1 + lldb/source/API/SBBlock.cpp | 7 +- lldb/source/API/SBFrame.cpp | 23 +- lldb/source/API/SBValue.cpp | 307 +++++++++++++++------ lldb/source/Core/FormatManager.cpp | 20 +- lldb/source/Core/ValueObject.cpp | 14 +- lldb/source/Core/ValueObjectDynamicValue.cpp | 25 +- lldb/source/Core/ValueObjectSyntheticFilter.cpp | 11 + .../source/Interpreter/ScriptInterpreterPython.cpp | 37 +-- .../data-formatter/rdar-12437442/Makefile | 9 + .../rdar-12437442/TestRdar12437442.py | 91 ++++++ .../data-formatter/rdar-12437442/main.m | 25 ++ 16 files changed, 490 insertions(+), 147 deletions(-) create mode 100644 lldb/test/functionalities/data-formatter/rdar-12437442/Makefile create mode 100644 lldb/test/functionalities/data-formatter/rdar-12437442/TestRdar12437442.py create mode 100644 lldb/test/functionalities/data-formatter/rdar-12437442/main.m diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h index 0502074d..2c02a7c9 100644 --- a/lldb/include/lldb/API/SBValue.h +++ b/lldb/include/lldb/API/SBValue.h @@ -14,6 +14,9 @@ #include "lldb/API/SBDefines.h" #include "lldb/API/SBType.h" +namespace { + class ValueImpl; +} namespace lldb { @@ -95,8 +98,23 @@ public: lldb::SBValue GetNonSyntheticValue (); + lldb::DynamicValueType + GetPreferDynamicValue (); + + void + SetPreferDynamicValue (lldb::DynamicValueType use_dynamic); + + bool + GetPreferSyntheticValue (); + + void + SetPreferSyntheticValue (bool use_synthetic); + bool - IsDynamic(); + IsDynamic (); + + bool + IsSynthetic (); const char * GetLocation (); @@ -380,29 +398,40 @@ public: // currently rely on being able to extract the SharedPointer out of an SBValue. if the implementation // is deferred to the .cpp file instead of being inlined here, the platform will fail to link // correctly. however, this is temporary till a better general solution is found. FIXME - lldb::ValueObjectSP& + lldb::ValueObjectSP get_sp() { - return m_opaque_sp; + return GetSP(); } protected: - friend class SBValueList; + friend class SBBlock; friend class SBFrame; friend class SBThread; + friend class SBValueList; lldb::ValueObjectSP GetSP () const; - // anyone who needs to set the value of the SP on this SBValue should rely on SetSP() exclusively - // since this function contains logic to "do the right thing" with regard to providing to the user - // a synthetic value when possible - in the future the same should automatically occur with - // dynamic values + // these calls do the right thing WRT adjusting their settings according to the target's preferences void SetSP (const lldb::ValueObjectSP &sp); + + void + SetSP (const lldb::ValueObjectSP &sp, bool use_synthetic); + + void + SetSP (const lldb::ValueObjectSP &sp, lldb::DynamicValueType use_dynamic); + + void + SetSP (const lldb::ValueObjectSP &sp, lldb::DynamicValueType use_dynamic, bool use_synthetic); private: - lldb::ValueObjectSP m_opaque_sp; + typedef STD_SHARED_PTR(ValueImpl) ValueImplSP; + ValueImplSP m_opaque_sp; + + void + SetSP (ValueImplSP impl_sp); }; } // namespace lldb diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h index 4c594b6..cbb6234 100644 --- a/lldb/include/lldb/Core/ValueObject.h +++ b/lldb/include/lldb/Core/ValueObject.h @@ -1266,7 +1266,7 @@ protected: GetDataExtractor (); void - ResetCompleteTypeInfo (); + ClearDynamicTypeInformation (); //------------------------------------------------------------------ // Sublasses must implement the functions below. diff --git a/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h b/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h index 02fd87a..dbe9b83 100644 --- a/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h +++ b/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h @@ -142,6 +142,9 @@ private: friend class ValueObject; ValueObjectSynthetic (ValueObject &parent, lldb::SyntheticChildrenSP filter); + void + CopyParentData (); + //------------------------------------------------------------------ // For ValueObject only //------------------------------------------------------------------ diff --git a/lldb/scripts/Python/interface/SBValue.i b/lldb/scripts/Python/interface/SBValue.i index 70c3d80..00d9b56 100644 --- a/lldb/scripts/Python/interface/SBValue.i +++ b/lldb/scripts/Python/interface/SBValue.i @@ -129,9 +129,24 @@ public: lldb::SBValue GetNonSyntheticValue (); + + lldb::DynamicValueType + GetPreferDynamicValue (); + + void + SetPreferDynamicValue (lldb::DynamicValueType use_dynamic); + + bool + GetPreferSyntheticValue (); + + void + SetPreferSyntheticValue (bool use_synthetic); bool IsDynamic(); + + bool + IsSynthetic (); const char * GetLocation (); diff --git a/lldb/scripts/Python/python-wrapper.swig b/lldb/scripts/Python/python-wrapper.swig index 113447e..a3aeefb 100644 --- a/lldb/scripts/Python/python-wrapper.swig +++ b/lldb/scripts/Python/python-wrapper.swig @@ -336,6 +336,7 @@ LLDBSwigPythonCreateSyntheticProvider // I do not want the SBValue to be deallocated when going out of scope because python // has ownership of it and will manage memory for this object by itself lldb::SBValue *valobj_sb = new lldb::SBValue(valobj_sp); + valobj_sb->SetPreferSyntheticValue(false); PyObject *ValObj_PyObj = SWIG_NewPointerObj((void *)valobj_sb, SWIGTYPE_p_lldb__SBValue, 0); diff --git a/lldb/source/API/SBBlock.cpp b/lldb/source/API/SBBlock.cpp index 8f325f4..91324ed 100644 --- a/lldb/source/API/SBBlock.cpp +++ b/lldb/source/API/SBBlock.cpp @@ -299,7 +299,12 @@ SBBlock::GetVariables (lldb::SBFrame& frame, if (add_variable) { if (frame_sp) - value_list.Append (frame_sp->GetValueObjectForFrameVariable (variable_sp, use_dynamic)); + { + lldb::ValueObjectSP valobj_sp(frame_sp->GetValueObjectForFrameVariable (variable_sp,eNoDynamicValues)); + SBValue value_sb; + value_sb.SetSP(valobj_sp, use_dynamic); + value_list.Append (value_sb); + } } } } diff --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp index 3fdadde..3f66623 100644 --- a/lldb/source/API/SBFrame.cpp +++ b/lldb/source/API/SBFrame.cpp @@ -549,12 +549,12 @@ SBFrame::GetValueForVariablePath (const char *var_path, DynamicValueType use_dyn { VariableSP var_sp; Error error; - ValueObjectSP value_sp (frame->GetValueForVariableExpressionPath (var_path, - use_dynamic, + ValueObjectSP value_sp (frame->GetValueForVariableExpressionPath (var_path, + eNoDynamicValues, StackFrame::eExpressionPathOptionCheckPtrVsMember | StackFrame::eExpressionPathOptionsAllowDirectIVarAccess, var_sp, error)); - sb_value.SetSP(value_sp); + sb_value.SetSP(value_sp, use_dynamic); } else { @@ -619,8 +619,8 @@ SBFrame::FindVariable (const char *name, lldb::DynamicValueType use_dynamic) if (var_sp) { - value_sp = frame->GetValueObjectForFrameVariable(var_sp, use_dynamic); - sb_value.SetSP(value_sp); + value_sp = frame->GetValueObjectForFrameVariable(var_sp, eNoDynamicValues); + sb_value.SetSP(value_sp, use_dynamic); } } else @@ -697,8 +697,8 @@ SBFrame::FindValue (const char *name, ValueType value_type, lldb::DynamicValueTy variable_sp->GetScope() == value_type && variable_sp->GetName() == const_name) { - value_sp = frame->GetValueObjectForFrameVariable (variable_sp, use_dynamic); - sb_value.SetSP (value_sp); + value_sp = frame->GetValueObjectForFrameVariable (variable_sp, eNoDynamicValues); + sb_value.SetSP (value_sp, use_dynamic); break; } } @@ -757,7 +757,7 @@ SBFrame::FindValue (const char *name, ValueType value_type, lldb::DynamicValueTy if (expr_var_sp) { value_sp = expr_var_sp->GetValueObject(); - sb_value.SetSP (value_sp); + sb_value.SetSP (value_sp, use_dynamic); } } break; @@ -939,7 +939,10 @@ SBFrame::GetVariables (bool arguments, if (in_scope_only && !variable_sp->IsInScope(frame)) continue; - value_list.Append(frame->GetValueObjectForFrameVariable (variable_sp, use_dynamic)); + ValueObjectSP valobj_sp(frame->GetValueObjectForFrameVariable (variable_sp, eNoDynamicValues)); + SBValue value_sb; + value_sb.SetSP(valobj_sp,use_dynamic); + value_list.Append(value_sb); } } } @@ -1102,7 +1105,7 @@ SBFrame::EvaluateExpression (const char *expr, const SBExpressionOptions &option frame, expr_value_sp, options.ref()); - expr_result.SetSP(expr_value_sp); + expr_result.SetSP(expr_value_sp,options.GetFetchDynamicValue()); #ifdef LLDB_CONFIGURATION_DEBUG Host::SetCrashDescription (NULL); #endif diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp index 5b38bc5..318029f 100644 --- a/lldb/source/API/SBValue.cpp +++ b/lldb/source/API/SBValue.cpp @@ -50,6 +50,98 @@ using namespace lldb; using namespace lldb_private; +namespace { + class ValueImpl + { + public: + ValueImpl () + { + } + + ValueImpl (lldb::ValueObjectSP opaque_sp, + lldb::DynamicValueType use_dynamic, + bool use_synthetic) : + m_opaque_sp(opaque_sp), + m_use_dynamic(use_dynamic), + m_use_synthetic(use_synthetic) + { + } + + ValueImpl (const ValueImpl& rhs) : + m_opaque_sp(rhs.m_opaque_sp), + m_use_dynamic(rhs.m_use_dynamic), + m_use_synthetic(rhs.m_use_synthetic) + { + } + + ValueImpl & + operator = (const ValueImpl &rhs) + { + if (this != &rhs) + { + m_opaque_sp = rhs.m_opaque_sp; + m_use_dynamic = rhs.m_use_dynamic; + m_use_synthetic = rhs.m_use_synthetic; + } + return *this; + } + + bool + IsValid () + { + return m_opaque_sp.get() != NULL; + } + + lldb::ValueObjectSP + GetRootSP () + { + return m_opaque_sp; + } + + lldb::ValueObjectSP + GetSP () + { + if (!m_opaque_sp) + return m_opaque_sp; + lldb::ValueObjectSP value_sp = m_opaque_sp; + if (value_sp->GetDynamicValue(m_use_dynamic)) + value_sp = value_sp->GetDynamicValue(m_use_dynamic); + if (value_sp->GetSyntheticValue(m_use_synthetic)) + value_sp = value_sp->GetSyntheticValue(m_use_synthetic); + return value_sp; + } + + void + SetUseDynamic (lldb::DynamicValueType use_dynamic) + { + m_use_dynamic = use_dynamic; + } + + void + SetUseSynthetic (bool use_synthetic) + { + m_use_synthetic = use_synthetic; + } + + lldb::DynamicValueType + GetUseDynamic () + { + return m_use_dynamic; + } + + bool + GetUseSynthetic () + { + return m_use_synthetic; + } + + private: + lldb::ValueObjectSP m_opaque_sp; + lldb::DynamicValueType m_use_dynamic; + bool m_use_synthetic; + }; +} + SBValue::SBValue () : m_opaque_sp () { @@ -57,12 +149,12 @@ SBValue::SBValue () : SBValue::SBValue (const lldb::ValueObjectSP &value_sp) { - SetSP(value_sp); // whenever setting the SP call SetSP() since it knows how to deal with synthetic values properly + SetSP(value_sp); } SBValue::SBValue(const SBValue &rhs) { - SetSP(rhs.m_opaque_sp); // whenever setting the SP call SetSP() since it knows how to deal with synthetic values properly + SetSP(rhs.m_opaque_sp); } SBValue & @@ -70,7 +162,7 @@ SBValue::operator = (const SBValue &rhs) { if (this != &rhs) { - SetSP(rhs.m_opaque_sp); // whenever setting the SP call SetSP() since it knows how to deal with synthetic values properly + SetSP(rhs.m_opaque_sp); } return *this; } @@ -85,7 +177,7 @@ SBValue::IsValid () // If this function ever changes to anything that does more than just // check if the opaque shared pointer is non NULL, then we need to update // all "if (m_opaque_sp)" code in this file. - return m_opaque_sp.get() != NULL; + return m_opaque_sp.get() != NULL && m_opaque_sp->GetRootSP().get() != NULL; } void @@ -683,7 +775,7 @@ SBValue::CreateChildAtOffset (const char *name, uint32_t offset, SBType type) TypeImplSP type_sp (type.GetSP()); if (type.IsValid()) { - sb_value = SBValue(value_sp->GetSyntheticChildAtOffset(offset, type_sp->GetClangASTType(), true)); + sb_value.SetSP(value_sp->GetSyntheticChildAtOffset(offset, type_sp->GetClangASTType(), true),GetPreferDynamicValue(),GetPreferSyntheticValue()); new_value_sp = sb_value.GetSP(); if (new_value_sp) new_value_sp->SetName(ConstString(name)); @@ -712,7 +804,7 @@ SBValue::Cast (SBType type) lldb::ValueObjectSP value_sp(GetSP()); TypeImplSP type_sp (type.GetSP()); if (value_sp && type_sp) - sb_value.SetSP(value_sp->Cast(type_sp->GetClangASTType())); + sb_value.SetSP(value_sp->Cast(type_sp->GetClangASTType()),GetPreferDynamicValue(),GetPreferSyntheticValue()); return sb_value; } @@ -904,20 +996,12 @@ SBValue::GetChildAtIndex (uint32_t idx, lldb::DynamicValueType use_dynamic, bool } } - if (child_sp) - { - if (use_dynamic != lldb::eNoDynamicValues) - { - lldb::ValueObjectSP dynamic_sp(child_sp->GetDynamicValue (use_dynamic)); - if (dynamic_sp) - child_sp = dynamic_sp; - } - } } } } - SBValue sb_value (child_sp); + SBValue sb_value; + sb_value.SetSP (child_sp, use_dynamic, GetPreferSyntheticValue()); if (log) log->Printf ("SBValue(%p)::GetChildAtIndex (%u) => SBValue(%p)", value_sp.get(), idx, value_sp.get()); @@ -993,20 +1077,12 @@ SBValue::GetChildMemberWithName (const char *name, lldb::DynamicValueType use_dy { Mutex::Locker api_locker (target_sp->GetAPIMutex()); child_sp = value_sp->GetChildMemberWithName (str_name, true); - if (use_dynamic_value != lldb::eNoDynamicValues) - { - if (child_sp) - { - lldb::ValueObjectSP dynamic_sp = child_sp->GetDynamicValue (use_dynamic_value); - if (dynamic_sp) - child_sp = dynamic_sp; - } - } } } } - SBValue sb_value (child_sp); + SBValue sb_value; + sb_value.SetSP(child_sp, use_dynamic_value, GetPreferSyntheticValue()); if (log) log->Printf ("SBValue(%p)::GetChildMemberWithName (name=\"%s\") => SBValue(%p)", value_sp.get(), name, value_sp.get()); @@ -1017,74 +1093,87 @@ SBValue::GetChildMemberWithName (const char *name, lldb::DynamicValueType use_dy lldb::SBValue SBValue::GetDynamicValue (lldb::DynamicValueType use_dynamic) { - lldb::ValueObjectSP value_sp(GetSP()); - if (value_sp) + SBValue value_sb; + if (IsValid()) { - ProcessSP process_sp(value_sp->GetProcessSP()); - Process::StopLocker stop_locker; - if (process_sp && !stop_locker.TryLock(&process_sp->GetRunLock())) - { - LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); - if (log) - log->Printf ("SBValue(%p)::GetDynamicValue() => error: process is running", value_sp.get()); - } - else - { - TargetSP target_sp(value_sp->GetTargetSP()); - if (target_sp) - { - Mutex::Locker api_locker (target_sp->GetAPIMutex()); - return SBValue (value_sp->GetDynamicValue(use_dynamic)); - } - } + ValueImplSP proxy_sp(new ValueImpl(m_opaque_sp->GetRootSP(),use_dynamic,m_opaque_sp->GetUseSynthetic())); + value_sb.SetSP(proxy_sp); } - - return SBValue(); + return value_sb; } lldb::SBValue SBValue::GetStaticValue () { - lldb::ValueObjectSP value_sp(GetSP()); - if (value_sp) + SBValue value_sb; + if (IsValid()) { - TargetSP target_sp(value_sp->GetTargetSP()); - if (target_sp) - { - Mutex::Locker api_locker (target_sp->GetAPIMutex()); - return SBValue(value_sp->GetStaticValue()); - } + ValueImplSP proxy_sp(new ValueImpl(m_opaque_sp->GetRootSP(),eNoDynamicValues,m_opaque_sp->GetUseSynthetic())); + value_sb.SetSP(proxy_sp); } - - return SBValue(); + return value_sb; } lldb::SBValue SBValue::GetNonSyntheticValue () { - SBValue sb_value; + SBValue value_sb; + if (IsValid()) + { + ValueImplSP proxy_sp(new ValueImpl(m_opaque_sp->GetRootSP(),m_opaque_sp->GetUseDynamic(),false)); + value_sb.SetSP(proxy_sp); + } + return value_sb; +} + +lldb::DynamicValueType +SBValue::GetPreferDynamicValue () +{ + if (!IsValid()) + return eNoDynamicValues; + return m_opaque_sp->GetUseDynamic(); +} + +void +SBValue::SetPreferDynamicValue (lldb::DynamicValueType use_dynamic) +{ + if (IsValid()) + return m_opaque_sp->SetUseDynamic (use_dynamic); +} + +bool +SBValue::GetPreferSyntheticValue () +{ + if (!IsValid()) + return false; + return m_opaque_sp->GetUseSynthetic(); +} + +void +SBValue::SetPreferSyntheticValue (bool use_synthetic) +{ + if (IsValid()) + return m_opaque_sp->SetUseSynthetic (use_synthetic); +} + +bool +SBValue::IsDynamic() +{ lldb::ValueObjectSP value_sp(GetSP()); if (value_sp) { - if (value_sp->IsSynthetic()) + TargetSP target_sp(value_sp->GetTargetSP()); + if (target_sp) { - TargetSP target_sp(value_sp->GetTargetSP()); - if (target_sp) - { - Mutex::Locker api_locker (target_sp->GetAPIMutex()); - // deliberately breaking the rules here to optimize the case where we DO NOT want - // the synthetic value to be returned to the user - if we did not do this, we would have to tell - // the target to suppress the synthetic value, and then return the flag to its original value - if (value_sp->GetNonSyntheticValue()) - sb_value.m_opaque_sp = value_sp->GetNonSyntheticValue(); - } + Mutex::Locker api_locker (target_sp->GetAPIMutex()); + return value_sp->IsDynamic(); } } - return sb_value; + return false; } bool -SBValue::IsDynamic() +SBValue::IsSynthetic () { lldb::ValueObjectSP value_sp(GetSP()); if (value_sp) @@ -1093,7 +1182,7 @@ SBValue::IsDynamic() if (target_sp) { Mutex::Locker api_locker (target_sp->GetAPIMutex()); - return value_sp->IsDynamic(); + return value_sp->IsSynthetic(); } } return false; @@ -1126,7 +1215,8 @@ SBValue::GetValueForExpressionPath(const char* expr_path) } } - SBValue sb_value (child_sp); + SBValue sb_value; + sb_value.SetSP(child_sp,GetPreferDynamicValue(),GetPreferSyntheticValue()); if (log) log->Printf ("SBValue(%p)::GetValueForExpressionPath (expr_path=\"%s\") => SBValue(%p)", value_sp.get(), expr_path, value_sp.get()); @@ -1457,17 +1547,77 @@ SBValue::GetFrame() lldb::ValueObjectSP SBValue::GetSP () const { - return m_opaque_sp; + if (!m_opaque_sp || !m_opaque_sp->IsValid()) + return ValueObjectSP(); + return m_opaque_sp->GetSP(); +} + +void +SBValue::SetSP (ValueImplSP impl_sp) +{ + m_opaque_sp = impl_sp; } void SBValue::SetSP (const lldb::ValueObjectSP &sp) { - m_opaque_sp = sp; - if (IsValid() && m_opaque_sp->HasSyntheticValue()) - m_opaque_sp = m_opaque_sp->GetSyntheticValue(); + if (sp) + { + lldb::TargetSP target_sp(sp->GetTargetSP()); + if (target_sp) + { + lldb::DynamicValueType use_dynamic = target_sp->GetPreferDynamicValue(); + bool use_synthetic = target_sp->TargetProperties::GetEnableSyntheticValue(); + m_opaque_sp = ValueImplSP(new ValueImpl(sp, use_dynamic, use_synthetic)); + } + else + m_opaque_sp = ValueImplSP(new ValueImpl(sp,eNoDynamicValues,true)); + } + else + m_opaque_sp = ValueImplSP(new ValueImpl(sp,eNoDynamicValues,false)); } +void +SBValue::SetSP (const lldb::ValueObjectSP &sp, lldb::DynamicValueType use_dynamic) +{ + if (sp) + { + lldb::TargetSP target_sp(sp->GetTargetSP()); + if (target_sp) + { + bool use_synthetic = target_sp->TargetProperties::GetEnableSyntheticValue(); + SetSP (sp, use_dynamic, use_synthetic); + } + else + SetSP (sp, use_dynamic, true); + } + else + SetSP (sp, use_dynamic, false); +} + +void +SBValue::SetSP (const lldb::ValueObjectSP &sp, bool use_synthetic) +{ + if (sp) + { + lldb::TargetSP target_sp(sp->GetTargetSP()); + if (target_sp) + { + lldb::DynamicValueType use_dynamic = target_sp->GetPreferDynamicValue(); + SetSP (sp, use_dynamic, use_synthetic); + } + else + SetSP (sp, eNoDynamicValues, use_synthetic); + } + else + SetSP (sp, eNoDynamicValues, use_synthetic); +} + +void +SBValue::SetSP (const lldb::ValueObjectSP &sp, lldb::DynamicValueType use_dynamic, bool use_synthetic) +{ + m_opaque_sp = ValueImplSP(new ValueImpl(sp,use_dynamic,use_synthetic)); +} bool SBValue::GetExpressionPath (SBStream &description) @@ -1549,7 +1699,7 @@ SBValue::AddressOf() { Mutex::Locker api_locker (target_sp->GetAPIMutex()); Error error; - sb_value = value_sp->AddressOf (error); + sb_value.SetSP(value_sp->AddressOf (error),GetPreferDynamicValue(), GetPreferSyntheticValue()); } } LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); @@ -1805,4 +1955,3 @@ SBValue::WatchPointee (bool resolve_location, bool read, bool write, SBError &er sb_watchpoint = Dereference().Watch (resolve_location, read, write, error); return sb_watchpoint; } - diff --git a/lldb/source/Core/FormatManager.cpp b/lldb/source/Core/FormatManager.cpp index deb1169..d80b46c 100644 --- a/lldb/source/Core/FormatManager.cpp +++ b/lldb/source/Core/FormatManager.cpp @@ -437,14 +437,20 @@ CategoryMap::GetSummaryFormat (ValueObject& valobj, uint32_t reason_why; ActiveCategoriesIterator begin, end = m_active_categories.end(); + LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); + for (begin = m_active_categories.begin(); begin != end; begin++) { - lldb::TypeCategoryImplSP category = *begin; + lldb::TypeCategoryImplSP category_sp = *begin; lldb::TypeSummaryImplSP current_format; - if (!category->Get(valobj, current_format, use_dynamic, &reason_why)) + if (log) + log->Printf("[CategoryMap::GetSummaryFormat] Trying to use category %s\n", category_sp->GetName()); + if (!category_sp->Get(valobj, current_format, use_dynamic, &reason_why)) continue; return current_format; } + if (log) + log->Printf("[CategoryMap::GetSummaryFormat] nothing found - returning empty SP\n"); return lldb::TypeSummaryImplSP(); } @@ -554,14 +560,20 @@ CategoryMap::GetSyntheticChildren (ValueObject& valobj, ActiveCategoriesIterator begin, end = m_active_categories.end(); + LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); + for (begin = m_active_categories.begin(); begin != end; begin++) { - lldb::TypeCategoryImplSP category = *begin; + lldb::TypeCategoryImplSP category_sp = *begin; lldb::SyntheticChildrenSP current_format; - if (!category->Get(valobj, current_format, use_dynamic, &reason_why)) + if (log) + log->Printf("[CategoryMap::GetSyntheticChildren] Trying to use category %s\n", category_sp->GetName()); + if (!category_sp->Get(valobj, current_format, use_dynamic, &reason_why)) continue; return current_format; } + if (log) + log->Printf("[CategoryMap::GetSyntheticChildren] nothing found - returning empty SP\n"); return lldb::SyntheticChildrenSP(); } #endif diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index 0edc8be..b5b55c9 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -276,10 +276,14 @@ ValueObject::SetNeedsUpdate () } void -ValueObject::ResetCompleteTypeInfo () +ValueObject::ClearDynamicTypeInformation () { m_did_calculate_complete_objc_class_type = false; + m_last_format_mgr_revision = 0; m_override_type = ClangASTType(); + SetValueFormat(lldb::TypeFormatImplSP()); + SetSummaryFormat(lldb::TypeSummaryImplSP()); + SetSyntheticChildren(lldb::SyntheticChildrenSP()); } ClangASTType @@ -2059,12 +2063,17 @@ ValueObject::CalculateSyntheticValue (bool use_synthetic) return; } + lldb::SyntheticChildrenSP current_synth_sp(m_synthetic_children_sp); + if (!UpdateFormatsIfNeeded(m_last_format_mgr_dynamic) && 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); } @@ -2079,7 +2088,10 @@ ValueObject::CalculateDynamicValue (DynamicValueType use_dynamic) ExecutionContext exe_ctx (GetExecutionContextRef()); Process *process = exe_ctx.GetProcessPtr(); if (process && process->IsPossibleDynamicValue(*this)) + { + ClearDynamicTypeInformation (); m_dynamic_value = new ValueObjectDynamicValue (*this, use_dynamic); + } } } diff --git a/lldb/source/Core/ValueObjectDynamicValue.cpp b/lldb/source/Core/ValueObjectDynamicValue.cpp index 2921e9d..dfddbd9 100644 --- a/lldb/source/Core/ValueObjectDynamicValue.cpp +++ b/lldb/source/Core/ValueObjectDynamicValue.cpp @@ -290,29 +290,24 @@ ValueObjectDynamicValue::UpdateValue () lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); + bool has_changed_type = false; + if (!m_type_sp) { m_type_sp = dynamic_type_sp; - ResetCompleteTypeInfo (); - if (log) - log->Printf("[%s %p] now has a dynamic type %s", - GetName().GetCString(), - this, - GetTypeName().AsCString("")); + has_changed_type = true; } else if (dynamic_type_sp != m_type_sp) { // We are another type, we need to tear down our children... m_type_sp = dynamic_type_sp; SetValueDidChange (true); - ResetCompleteTypeInfo (); - if (log) - log->Printf("[%s %p] has a new dynamic type %s", - GetName().GetCString(), - this, - GetTypeName().AsCString("")); + has_changed_type = true; } + if (has_changed_type) + ClearDynamicTypeInformation (); + if (!m_address.IsValid() || m_address != dynamic_address) { if (m_address.IsValid()) @@ -341,6 +336,12 @@ ValueObjectDynamicValue::UpdateValue () // because we aren't pointing to the LOCATION that stores the pointer to us, we're pointing to us... m_value.SetValueType(Value::eValueTypeScalar); + if (has_changed_type && log) + log->Printf("[%s %p] has a new dynamic type %s", + GetName().GetCString(), + this, + GetTypeName().GetCString()); + if (m_address.IsValid() && m_type_sp) { // The variable value is in the Scalar value inside the m_value. diff --git a/lldb/source/Core/ValueObjectSyntheticFilter.cpp b/lldb/source/Core/ValueObjectSyntheticFilter.cpp index 5f58b4d..284515a 100644 --- a/lldb/source/Core/ValueObjectSyntheticFilter.cpp +++ b/lldb/source/Core/ValueObjectSyntheticFilter.cpp @@ -67,6 +67,7 @@ ValueObjectSynthetic::ValueObjectSynthetic (ValueObject &parent, lldb::Synthetic #else SetName(parent.GetName()); #endif + CopyParentData(); CreateSynthFilter(); } @@ -157,6 +158,8 @@ ValueObjectSynthetic::UpdateValue () m_synthetic_children_count = UINT32_MAX; } + CopyParentData(); + SetValueIsValid(true); return true; } @@ -230,3 +233,11 @@ ValueObjectSynthetic::GetNonSyntheticValue () { return m_parent->GetSP(); } + +void +ValueObjectSynthetic::CopyParentData () +{ + m_value = m_parent->GetValue(); + ExecutionContext exe_ctx (GetExecutionContextRef()); + m_error = m_value.GetValueAsData (&exe_ctx, GetClangAST(), m_data, 0, GetModule().get()); +} diff --git a/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/lldb/source/Interpreter/ScriptInterpreterPython.cpp index efb8841..a6a94f4 100644 --- a/lldb/source/Interpreter/ScriptInterpreterPython.cpp +++ b/lldb/source/Interpreter/ScriptInterpreterPython.cpp @@ -197,24 +197,6 @@ ScriptInterpreterPython::Locker::~Locker() DoFreeLock(); } -class ForceDisableSyntheticChildren -{ -public: - ForceDisableSyntheticChildren (Target* target) : - m_target(target) - { - m_old_value = target->GetSuppressSyntheticValue(); - target->SetSuppressSyntheticValue(true); - } - ~ForceDisableSyntheticChildren () - { - m_target->SetSuppressSyntheticValue(m_old_value); - } -private: - Target* m_target; - bool m_old_value; -}; - ScriptInterpreterPython::PythonInputReaderManager::PythonInputReaderManager (ScriptInterpreterPython *interpreter) : m_interpreter(interpreter), m_debugger_sp(), @@ -1933,10 +1915,9 @@ ScriptInterpreterPython::CreateSyntheticScriptedProvider (std::string class_name { Locker py_lock(this); - ForceDisableSyntheticChildren no_synthetics(target); - ret_val = g_swig_synthetic_script (class_name, - python_interpreter->m_dictionary_name.c_str(), - valobj); + ret_val = g_swig_synthetic_script (class_name, + python_interpreter->m_dictionary_name.c_str(), + valobj); } return MakeScriptObject(ret_val); @@ -2275,8 +2256,7 @@ ScriptInterpreterPython::CalculateNumChildren (const lldb::ScriptInterpreterObje { Locker py_lock(this); - ForceDisableSyntheticChildren no_synthetics(GetCommandInterpreter().GetDebugger().GetSelectedTarget().get()); - ret_val = g_swig_calc_children (implementor); + ret_val = g_swig_calc_children (implementor); } return ret_val; @@ -2302,8 +2282,7 @@ ScriptInterpreterPython::GetChildAtIndex (const lldb::ScriptInterpreterObjectSP& { Locker py_lock(this); - ForceDisableSyntheticChildren no_synthetics(GetCommandInterpreter().GetDebugger().GetSelectedTarget().get()); - child_ptr = g_swig_get_child_index (implementor,idx); + child_ptr = g_swig_get_child_index (implementor,idx); if (child_ptr != NULL && child_ptr != Py_None) { value_sb = (lldb::SBValue*)g_swig_cast_to_sbvalue(child_ptr); @@ -2339,8 +2318,7 @@ ScriptInterpreterPython::GetIndexOfChildWithName (const lldb::ScriptInterpreterO { Locker py_lock(this); - ForceDisableSyntheticChildren no_synthetics(GetCommandInterpreter().GetDebugger().GetSelectedTarget().get()); - ret_val = g_swig_get_index_child (implementor, child_name); + ret_val = g_swig_get_index_child (implementor, child_name); } return ret_val; @@ -2364,8 +2342,7 @@ ScriptInterpreterPython::UpdateSynthProviderInstance (const lldb::ScriptInterpre { Locker py_lock(this); - ForceDisableSyntheticChildren no_synthetics(GetCommandInterpreter().GetDebugger().GetSelectedTarget().get()); - ret_val = g_swig_update_provider (implementor); + ret_val = g_swig_update_provider (implementor); } return ret_val; diff --git a/lldb/test/functionalities/data-formatter/rdar-12437442/Makefile b/lldb/test/functionalities/data-formatter/rdar-12437442/Makefile new file mode 100644 index 0000000..9f7fb1c --- /dev/null +++ b/lldb/test/functionalities/data-formatter/rdar-12437442/Makefile @@ -0,0 +1,9 @@ +LEVEL = ../../../make + +OBJC_SOURCES := main.m + +CFLAGS_EXTRAS += -w + +include $(LEVEL)/Makefile.rules + +LDFLAGS += -framework Foundation diff --git a/lldb/test/functionalities/data-formatter/rdar-12437442/TestRdar12437442.py b/lldb/test/functionalities/data-formatter/rdar-12437442/TestRdar12437442.py new file mode 100644 index 0000000..aa3c6b0 --- /dev/null +++ b/lldb/test/functionalities/data-formatter/rdar-12437442/TestRdar12437442.py @@ -0,0 +1,91 @@ +""" +Test lldb data formatter subsystem. +""" + +import os, time +import unittest2 +import lldb +from lldbtest import * +import datetime +import lldbutil + +class DataFormatterRdar12437442TestCase(TestBase): + + mydir = os.path.join("functionalities", "data-formatter", "rdar-12437442") + + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + @dsym_test + def test_rdar12437442_with_dsym_and_run_command(self): + """Test that we update SBValues correctly as dynamic types change.""" + self.buildDsym() + self.rdar12437442_tester() + + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + @dwarf_test + def test_rdar12437442_with_dwarf_and_run_command(self): + """Test that we update SBValues correctly as dynamic types change.""" + self.buildDwarf() + self.rdar12437442_tester() + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line number to break at. + self.line = line_number('main.m', '// Set break point at this line.') + + def rdar12437442_tester(self): + """Test that we update SBValues correctly as dynamic types change.""" + self.runCmd("file a.out", CURRENT_EXECUTABLE_SET) + + lldbutil.run_break_set_by_file_and_line (self, "main.m", self.line, num_expected_locations=1, loc_exact=True) + + self.runCmd("run", RUN_SUCCEEDED) + + # The stop reason of the thread should be breakpoint. + self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, + substrs = ['stopped', + 'stop reason = breakpoint']) + + # This is the function to remove the custom formats in order to have a + # clean slate for the next test case. + def cleanup(): + self.runCmd('type format clear', check=False) + self.runCmd('type summary clear', check=False) + self.runCmd('type synth clear', check=False) + + # Execute the cleanup function during test case tear down. + self.addTearDownHook(cleanup) + + self.runCmd("log enable lldb types -f types.log") + + # Now run the bulk of the test + id_x = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame().FindVariable("x") + id_x.SetPreferDynamicValue(lldb.eDynamicCanRunTarget) + id_x.SetPreferSyntheticValue(True) + + if self.TraceOn(): + self.runCmd("frame variable x -d run-target --ptr-depth 1") + + self.assertTrue(id_x.GetSummary() == '@"5 objects"', "array does not get correct summary") + + self.runCmd("next") + + id_x = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame().FindVariable("x") + id_x.SetPreferDynamicValue(lldb.eDynamicCanRunTarget) + id_x.SetPreferSyntheticValue(True) + + if self.TraceOn(): + self.runCmd("frame variable x -d run-target --ptr-depth 1") + + self.assertTrue(id_x.GetNumChildren() == 7, "dictionary does not have 7 children") + id_x.SetPreferSyntheticValue(False) + self.assertFalse(id_x.GetNumChildren() == 7, "dictionary still looks synthetic") + id_x.SetPreferSyntheticValue(True) + self.assertTrue(id_x.GetSummary() == "7 key/value pairs", "dictionary does not get correct summary") + + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/test/functionalities/data-formatter/rdar-12437442/main.m b/lldb/test/functionalities/data-formatter/rdar-12437442/main.m new file mode 100644 index 0000000..a7e94d2 --- /dev/null +++ b/lldb/test/functionalities/data-formatter/rdar-12437442/main.m @@ -0,0 +1,25 @@ +//===-- main.m ------------------------------------------------*- ObjC -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#import + +int main (int argc, const char * argv[]) +{ + + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + + NSArray* foo = [NSArray arrayWithObjects:@1,@2,@3,@4,@5, nil]; + NSDictionary *bar = @{@1 : @"one",@2 : @"two", @3 : @"three", @4 : @"four", @5 : @"five", @6 : @"six", @7 : @"seven"}; + id x = foo; + x = bar; // Set break point at this line. + + [pool drain]; + return 0; +} + -- 2.7.4