diff options
21 files changed, 346 insertions, 113 deletions
diff --git a/lldb/examples/synthetic/gnu_libstdcpp.py b/lldb/examples/synthetic/gnu_libstdcpp.py index dc3946df5be..fb970e8bc43 100644 --- a/lldb/examples/synthetic/gnu_libstdcpp.py +++ b/lldb/examples/synthetic/gnu_libstdcpp.py @@ -85,6 +85,8 @@ class StdListSynthProvider: def extract_type(self): list_type = self.valobj.GetType().GetUnqualifiedType() + if list_type.IsReferenceType(): + list_type = list_type.GetDereferencedType() if list_type.GetNumberOfTemplateArguments() > 0: data_type = list_type.GetTemplateArgumentType(0) else: @@ -200,15 +202,15 @@ class StdMapSynthProvider: # to replace the longer versions of std::string with the shorter one in order to be able # to find the type name def fixup_class_name(self, class_name): - if class_name == 'std::basic_string<char, class std::char_traits<char>, class std::allocator<char> >': - return 'std::basic_string<char>' - if class_name == 'basic_string<char, class std::char_traits<char>, class std::allocator<char> >': - return 'std::basic_string<char>' if class_name == 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >': - return 'std::basic_string<char>' + return 'std::basic_string<char>',True if class_name == 'basic_string<char, std::char_traits<char>, std::allocator<char> >': - return 'std::basic_string<char>' - return class_name + return 'std::basic_string<char>',True + if class_name == 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >': + return 'std::basic_string<char>',True + if class_name == 'basic_string<char, std::char_traits<char>, std::allocator<char> >': + return 'std::basic_string<char>',True + return class_name,False def update(self): try: @@ -216,13 +218,27 @@ class StdMapSynthProvider: self.Mimpl = self.Mt.GetChildMemberWithName('_M_impl') self.Mheader = self.Mimpl.GetChildMemberWithName('_M_header') - map_arg_0 = str(self.valobj.GetType().GetTemplateArgumentType(0).GetName()) - map_arg_1 = str(self.valobj.GetType().GetTemplateArgumentType(1).GetName()) + map_type = self.valobj.GetType() + if map_type.IsReferenceType(): + map_type = map_type.GetDereferencedType() + + map_arg_0 = str(map_type.GetTemplateArgumentType(0).GetName()) + map_arg_1 = str(map_type.GetTemplateArgumentType(1).GetName()) - map_arg_0 = self.fixup_class_name(map_arg_0) - map_arg_1 = self.fixup_class_name(map_arg_1) + map_arg_0,fixed_0 = self.fixup_class_name(map_arg_0) + map_arg_1,fixed_1 = self.fixup_class_name(map_arg_1) + + # HACK: this is related to the above issue with the typename for std::string + # being shortened by clang - the changes to typename display and searching to honor + # namespaces make it so that we go looking for std::pair<const std::basic_string<char>, ...> + # but when we find a type for this, we then compare it against the fully-qualified + # std::pair<const std::basic_string<char, std::char_traits... and of course fail + # the way to bypass this problem is to avoid using the std:: prefix in this specific case + if fixed_0 or fixed_1: + map_arg_type = "pair<const " + map_arg_0 + ", " + map_arg_1 + else: + map_arg_type = "std::pair<const " + map_arg_0 + ", " + map_arg_1 - map_arg_type = "std::pair<const " + map_arg_0 + ", " + map_arg_1 if map_arg_1[-1] == '>': map_arg_type = map_arg_type + " >" else: diff --git a/lldb/examples/synthetic/libcxx.py b/lldb/examples/synthetic/libcxx.py index ed6928ec7d1..fb43b10ef10 100644 --- a/lldb/examples/synthetic/libcxx.py +++ b/lldb/examples/synthetic/libcxx.py @@ -253,6 +253,8 @@ class stdlist_SynthProvider: def extract_type(self): list_type = self.valobj.GetType().GetUnqualifiedType() + if list_type.IsReferenceType(): + list_type = list_type.GetDereferencedType() if list_type.GetNumberOfTemplateArguments() > 0: data_type = list_type.GetTemplateArgumentType(0) else: diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h index 249554340cd..3abb37a10c1 100644 --- a/lldb/include/lldb/API/SBValue.h +++ b/lldb/include/lldb/API/SBValue.h @@ -92,6 +92,9 @@ public: lldb::SBValue GetStaticValue (); + lldb::SBValue + GetNonSyntheticValue (); + bool IsDynamic(); @@ -370,6 +373,10 @@ protected: 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 void SetSP (const lldb::ValueObjectSP &sp); diff --git a/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h b/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h index 247c5f5c79e..c04b2ca7e1b 100644 --- a/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h +++ b/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h @@ -120,7 +120,7 @@ protected: ByIndexMap m_children_byindex; NameToIndexMap m_name_toindex; - uint32_t m_children_count; + uint32_t m_synthetic_children_count; // FIXME use the ValueObject's ChildrenManager instead of a special purpose solution private: friend class ValueObject; diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 351f99fc45c..721b98c9049 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -74,7 +74,19 @@ public: { return (lldb::DynamicValueType) g_dynamic_value_types[m_prefer_dynamic_value].value; } + + bool + GetEnableSyntheticValue () + { + return m_enable_synthetic_value; + } + void + SetEnableSyntheticValue (bool b) + { + m_enable_synthetic_value = b; + } + bool GetSkipPrologue() { @@ -236,6 +248,7 @@ protected: OptionValueFileSpec m_expr_prefix_file; std::string m_expr_prefix_contents; int m_prefer_dynamic_value; + OptionValueBoolean m_enable_synthetic_value; OptionValueBoolean m_skip_prologue; PathMappingList m_source_map; FileSpecList m_exe_search_paths; @@ -1024,6 +1037,20 @@ public: return m_suppress_stop_hooks; } + bool + SetSuppressSyntheticValue (bool suppress) + { + bool old_value = m_suppress_synthetic_value; + m_suppress_synthetic_value = suppress; + return old_value; + } + + bool + GetSuppressSyntheticValue () + { + return m_suppress_synthetic_value; + } + // StopHookSP & // GetStopHookByIndex (size_t index); // @@ -1169,6 +1196,7 @@ protected: StopHookCollection m_stop_hooks; lldb::user_id_t m_stop_hook_next_id; bool m_suppress_stop_hooks; + bool m_suppress_synthetic_value; static void ImageSearchPathsChanged (const PathMappingList &path_list, diff --git a/lldb/scripts/Python/interface/SBValue.i b/lldb/scripts/Python/interface/SBValue.i index d61c7aa7752..2b66b500cf7 100644 --- a/lldb/scripts/Python/interface/SBValue.i +++ b/lldb/scripts/Python/interface/SBValue.i @@ -127,6 +127,9 @@ public: lldb::SBValue GetStaticValue (); + lldb::SBValue + GetNonSyntheticValue (); + bool IsDynamic(); @@ -378,81 +381,78 @@ public: %pythoncode %{ __swig_getmethods__["name"] = GetName - if _newclass: x = property(GetName, None) + if _newclass: name = property(GetName, None, doc='Returns the name of this SBValue as a string') __swig_getmethods__["type"] = GetType - if _newclass: x = property(GetType, None) + if _newclass: type = property(GetType, None, doc='Returns an SBType that represents the type of this SBValue') __swig_getmethods__["size"] = GetByteSize - if _newclass: x = property(GetByteSize, None) - - __swig_getmethods__["name"] = GetName - if _newclass: x = property(GetName, None) + if _newclass: size = property(GetByteSize, None, doc='Returns the size (in bytes) of the data contained in this SBValue') __swig_getmethods__["is_in_scope"] = IsInScope - if _newclass: x = property(IsInScope, None) + if _newclass: is_in_scope = property(IsInScope, None, doc='Returns True if this SBValue represents an item that is currently in lexical scope') __swig_getmethods__["format"] = GetFormat __swig_setmethods__["format"] = SetFormat - if _newclass: x = property(GetName, SetFormat) + if _newclass: format = property(GetName, SetFormat, doc='Returns the format for this SBValue') __swig_getmethods__["value"] = GetValue __swig_setmethods__["value"] = SetValueFromCString - if _newclass: x = property(GetValue, SetValueFromCString) + if _newclass: value = property(GetValue, SetValueFromCString, doc='Returns the value of this SBValue as a string') __swig_getmethods__["value_type"] = GetValueType - if _newclass: x = property(GetValueType, None) + if _newclass: value_type = property(GetValueType, None, doc='Returns the type of entry stored in this SBValue') __swig_getmethods__["changed"] = GetValueDidChange - if _newclass: x = property(GetValueDidChange, None) + if _newclass: changed = property(GetValueDidChange, None, doc='Returns True if this SBValue represents an item that has changed') __swig_getmethods__["data"] = GetData - if _newclass: x = property(GetData, None) + if _newclass: data = property(GetData, None, doc='Returns an SBData wrapping the contents of this SBValue') __swig_getmethods__["load_addr"] = GetLoadAddress - if _newclass: x = property(GetLoadAddress, None) + if _newclass: load_addr = property(GetLoadAddress, None, doc='Returns the load address (target address) of this SBValue as a number') __swig_getmethods__["addr"] = GetAddress - if _newclass: x = property(GetAddress, None) + if _newclass: addr = property(GetAddress, None, doc='Returns the address of this SBValue as an SBAddress') __swig_getmethods__["deref"] = Dereference - if _newclass: x = property(Dereference, None) + if _newclass: deref = property(Dereference, None, doc='Returns an SBValue that is created by dereferencing this SBValue') __swig_getmethods__["address_of"] = AddressOf - if _newclass: x = property(AddressOf, None) + if _newclass: address_of = property(AddressOf, None, doc='Returns an SBValue that wraps the address-of this SBValue') __swig_getmethods__["error"] = GetError - if _newclass: x = property(GetError, None) + if _newclass: error = property(GetError, None, doc='Returns the SBError currently associated to this SBValue') __swig_getmethods__["summary"] = GetSummary - if _newclass: x = property(GetSummary, None) + if _newclass: summary = property(GetSummary, None, doc='Returns the summary for this SBValue as a string') __swig_getmethods__["description"] = GetObjectDescription - if _newclass: x = property(GetObjectDescription, None) + if _newclass: description = property(GetObjectDescription, None, doc='Returns the language-specific description of this SBValue as a string') __swig_getmethods__["location"] = GetLocation - if _newclass: x = property(GetLocation, None) + if _newclass: location = property(GetLocation, None, doc='Returns the location of this SBValue as a string') __swig_getmethods__["target"] = GetTarget - if _newclass: x = property(GetTarget, None) + if _newclass: target = property(GetTarget, None, doc='Returns an SBTarget for the target from which this SBValue comes') __swig_getmethods__["process"] = GetProcess - if _newclass: x = property(GetProcess, None) + if _newclass: process = property(GetProcess, None, doc='Returns an SBProcess for the process from which this SBValue comes') __swig_getmethods__["thread"] = GetThread - if _newclass: x = property(GetThread, None) + if _newclass: thread = property(GetThread, None, doc='Returns an SBThread for the thread from which this SBValue comes') __swig_getmethods__["frame"] = GetFrame - if _newclass: x = property(GetFrame, None) + if _newclass: frame = property(GetFrame, None, doc='Returns an SBFrame for the stack frame from which this SBValue comes') __swig_getmethods__["num_children"] = GetNumChildren - if _newclass: x = property(GetNumChildren, None) + if _newclass: num_children = property(GetNumChildren, None, doc='Returns the number of child SBValues that this SBValue has') __swig_getmethods__["unsigned"] = GetValueAsUnsigned - if _newclass: x = property(GetValueAsUnsigned, None) + if _newclass: unsigned = property(GetValueAsUnsigned, None, doc='Returns the value of this SBValue as an unsigned number') __swig_getmethods__["signed"] = GetValueAsSigned - if _newclass: x = property(GetValueAsSigned, None) + if _newclass: signed = property(GetValueAsSigned, None, doc='Returns the value of this SBValue as a signed number') def get_expr_path(self): s = SBStream() @@ -460,7 +460,7 @@ public: return s.GetData() __swig_getmethods__["path"] = get_expr_path - if _newclass: x = property(get_expr_path, None) + if _newclass: path = property(get_expr_path, None, doc='Returns the expression path that one can use to reach this SBValue') %} }; diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp index c5a5fd27294..b28004ccf70 100644 --- a/lldb/source/API/SBValue.cpp +++ b/lldb/source/API/SBValue.cpp @@ -51,21 +51,23 @@ SBValue::SBValue () : { } -SBValue::SBValue (const lldb::ValueObjectSP &value_sp) : - m_opaque_sp (value_sp) +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 } -SBValue::SBValue(const SBValue &rhs) : - m_opaque_sp (rhs.m_opaque_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 } SBValue & SBValue::operator = (const SBValue &rhs) { if (this != &rhs) - m_opaque_sp = rhs.m_opaque_sp; + { + SetSP(rhs.m_opaque_sp); // whenever setting the SP call SetSP() since it knows how to deal with synthetic values properly + } return *this; } @@ -809,6 +811,30 @@ SBValue::GetStaticValue () return SBValue(); } +lldb::SBValue +SBValue::GetNonSyntheticValue () +{ + SBValue sb_value; + lldb::ValueObjectSP value_sp(GetSP()); + if (value_sp) + { + if (value_sp->IsSynthetic()) + { + 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->GetParent()) + sb_value.m_opaque_sp = value_sp->GetParent()->GetSP(); + } + } + } + return sb_value; +} + bool SBValue::IsDynamic() { @@ -1124,6 +1150,8 @@ void SBValue::SetSP (const lldb::ValueObjectSP &sp) { m_opaque_sp = sp; + if (IsValid() && m_opaque_sp->HasSyntheticValue()) + m_opaque_sp = m_opaque_sp->GetSyntheticValue(); } diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 6b93aa971a0..d7f1460e7fb 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -1164,7 +1164,8 @@ Debugger::FormatPrompt if (*var_name_begin == 's') { - valobj = valobj->GetSyntheticValue().get(); + if (!valobj->IsSynthetic()) + valobj = valobj->GetSyntheticValue().get(); if (!valobj) break; var_name_begin++; diff --git a/lldb/source/Core/FormatManager.cpp b/lldb/source/Core/FormatManager.cpp index 0496780724a..693ae263c96 100644 --- a/lldb/source/Core/FormatManager.cpp +++ b/lldb/source/Core/FormatManager.cpp @@ -639,18 +639,24 @@ FormatManager::LoadSTLFormatters() SyntheticChildren::Flags stl_synth_flags; stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(false); - gnu_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^(std::)?vector<.+>$")), + gnu_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::vector<.+>(( )?&)?$")), SyntheticChildrenSP(new TypeSyntheticImpl(stl_synth_flags, "gnu_libstdcpp.StdVectorSynthProvider"))); - gnu_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^(std::)?map<.+> >$")), + gnu_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::map<.+> >(( )?&)?$")), SyntheticChildrenSP(new TypeSyntheticImpl(stl_synth_flags, "gnu_libstdcpp.StdMapSynthProvider"))); - gnu_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^(std::)?list<.+>$")), + gnu_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::list<.+>(( )?&)?$")), SyntheticChildrenSP(new TypeSyntheticImpl(stl_synth_flags, "gnu_libstdcpp.StdListSynthProvider"))); stl_summary_flags.SetDontShowChildren(false); - gnu_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^(std::)?vector<.+>$")), + gnu_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::vector<.+>(( )?&)?$")), + TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, + "size=${svar%#}"))); + gnu_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::map<.+> >(( )?&)?$")), + TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, + "size=${svar%#}"))); + gnu_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::list<.+>(( )?&)?$")), TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); #endif @@ -682,22 +688,22 @@ FormatManager::LoadLibcxxFormatters() SyntheticChildren::Flags stl_synth_flags; stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(false); - libcxx_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^(std::__1::)vector<.+>$")), + libcxx_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::__1::vector<.+>(( )?&)?$")), SyntheticChildrenSP(new TypeSyntheticImpl(stl_synth_flags, "libcxx.stdvector_SynthProvider"))); - libcxx_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^(std::__1::)list<.+>$")), + libcxx_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::__1::list<.+>(( )?&)?$")), SyntheticChildrenSP(new TypeSyntheticImpl(stl_synth_flags, "libcxx.stdlist_SynthProvider"))); - libcxx_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^(std::__1::)map<.+> >$")), + libcxx_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::__1::map<.+> >(( )?&)?$")), SyntheticChildrenSP(new TypeSyntheticImpl(stl_synth_flags, "libcxx.stdmap_SynthProvider"))); stl_summary_flags.SetDontShowChildren(false); - libcxx_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^(std::__1::)vector<.+>$")), + libcxx_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::__1::vector<.+>(( )?&)?")), TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); - libcxx_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^(std::__1::)list<.+>$")), + libcxx_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::__1::list<.+>(( )?&)?$")), TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); - libcxx_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^(std::__1::)map<.+> >$")), + libcxx_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::__1::map<.+> >(( )?&)?$")), TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); #endif } diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index e072b491652..57f887b20f6 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -572,6 +572,7 @@ ValueObject::GetChildMemberWithName (const ConstString &name, bool can_create) uint32_t ValueObject::GetNumChildren () { + UpdateValueIfNeeded(); if (!m_children_count_valid) { SetNumChildren (CalculateNumChildren()); @@ -2009,6 +2010,13 @@ ValueObject::CalculateSyntheticValue (bool use_synthetic) if (use_synthetic == false) return; + TargetSP target_sp(GetTargetSP()); + if (target_sp && (target_sp->GetEnableSyntheticValue() == false || target_sp->GetSuppressSyntheticValue() == true)) + { + m_synthetic_value = NULL; + return; + } + if (!UpdateFormatsIfNeeded(m_last_format_mgr_dynamic) && m_synthetic_value) return; @@ -3317,6 +3325,7 @@ DumpValueObject_Impl (Stream &s, ValueObject* synth_valobj; ValueObjectSP synth_valobj_sp = valobj->GetSyntheticValue (options.m_use_synthetic); synth_valobj = (synth_valobj_sp ? synth_valobj_sp.get() : valobj); + uint32_t num_children = synth_valobj->GetNumChildren(); bool print_dotdotdot = false; if (num_children) diff --git a/lldb/source/Core/ValueObjectSyntheticFilter.cpp b/lldb/source/Core/ValueObjectSyntheticFilter.cpp index 6d9337b623c..56eb9f6c56e 100644 --- a/lldb/source/Core/ValueObjectSyntheticFilter.cpp +++ b/lldb/source/Core/ValueObjectSyntheticFilter.cpp @@ -25,7 +25,7 @@ ValueObjectSynthetic::ValueObjectSynthetic (ValueObject &parent, lldb::Synthetic m_synth_filter_ap(filter->GetFrontEnd(parent)), m_children_byindex(), m_name_toindex(), - m_children_count(UINT32_MAX) + m_synthetic_children_count(UINT32_MAX) { #ifdef LLDB_CONFIGURATION_DEBUG std::string new_name(parent.GetName().AsCString()); @@ -56,9 +56,9 @@ uint32_t ValueObjectSynthetic::CalculateNumChildren() { UpdateValueIfNeeded(); - if (m_children_count < UINT32_MAX) - return m_children_count; - return (m_children_count = m_synth_filter_ap->CalculateNumChildren()); + if (m_synthetic_children_count < UINT32_MAX) + return m_synthetic_children_count; + return (m_synthetic_children_count = m_synth_filter_ap->CalculateNumChildren()); } clang::ASTContext * @@ -99,7 +99,11 @@ ValueObjectSynthetic::UpdateValue () // filter said that cached values are stale m_children_byindex.clear(); m_name_toindex.clear(); - m_children_count = UINT32_MAX; + // usually, an object's value can change but this does not alter its children count + // for a synthetic VO that might indeed happen, so we need to tell the upper echelons + // that they need to come back to us asking for children + m_children_count_valid = false; + m_synthetic_children_count = UINT32_MAX; } SetValueIsValid(true); diff --git a/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/lldb/source/Interpreter/ScriptInterpreterPython.cpp index 81bbf3f11ac..9c84eab00d2 100644 --- a/lldb/source/Interpreter/ScriptInterpreterPython.cpp +++ b/lldb/source/Interpreter/ScriptInterpreterPython.cpp @@ -234,6 +234,24 @@ 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::ScriptInterpreterPython (CommandInterpreter &interpreter) : ScriptInterpreter (interpreter, eScriptLanguagePython), m_embedded_python_pty (), @@ -1328,6 +1346,7 @@ 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); @@ -1586,6 +1605,7 @@ ScriptInterpreterPython::CalculateNumChildren (const lldb::ScriptInterpreterObje { Locker py_lock(this); + ForceDisableSyntheticChildren no_synthetics(GetCommandInterpreter().GetDebugger().GetSelectedTarget().get()); ret_val = g_swig_calc_children (implementor); } @@ -1612,6 +1632,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); if (child_ptr != NULL && child_ptr != Py_None) { @@ -1648,6 +1669,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); } @@ -1672,6 +1694,7 @@ ScriptInterpreterPython::UpdateSynthProviderInstance (const lldb::ScriptInterpre { Locker py_lock(this); + ForceDisableSyntheticChildren no_synthetics(GetCommandInterpreter().GetDebugger().GetSelectedTarget().get()); ret_val = g_swig_update_provider (implementor); } diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 6648d4c86be..34fb4b8f426 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -73,7 +73,8 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, const lldb::Plat m_source_manager(*this), m_stop_hooks (), m_stop_hook_next_id (0), - m_suppress_stop_hooks (false) + m_suppress_stop_hooks (false), + m_suppress_synthetic_value(false) { SetEventName (eBroadcastBitBreakpointChanged, "breakpoint-changed"); SetEventName (eBroadcastBitModulesLoaded, "modules-loaded"); @@ -183,6 +184,7 @@ Target::Destroy() m_stop_hooks.clear(); m_stop_hook_next_id = 0; m_suppress_stop_hooks = false; + m_suppress_synthetic_value = false; } @@ -2106,6 +2108,7 @@ Target::SettingsController::CreateInstanceSettings (const char *instance_name) #define TSC_DEFAULT_ARCH "default-arch" #define TSC_EXPR_PREFIX "expr-prefix" #define TSC_PREFER_DYNAMIC "prefer-dynamic-value" +#define TSC_ENABLE_SYNTHETIC "enable-synthetic-value" #define TSC_SKIP_PROLOGUE "skip-prologue" #define TSC_SOURCE_MAP "source-map" #define TSC_EXE_SEARCH_PATHS "exec-search-paths" @@ -2144,6 +2147,13 @@ GetSettingNameForPreferDynamicValue () } static const ConstString & +GetSettingNameForEnableSyntheticValue () +{ + static ConstString g_const_string (TSC_ENABLE_SYNTHETIC); + return g_const_string; +} + +static const ConstString & GetSettingNameForSourcePathMap () { static ConstString g_const_string (TSC_SOURCE_MAP); @@ -2291,6 +2301,7 @@ TargetInstanceSettings::TargetInstanceSettings m_expr_prefix_file (), m_expr_prefix_contents (), m_prefer_dynamic_value (2), + m_enable_synthetic_value(true, true), m_skip_prologue (true, true), m_source_map (NULL, NULL), m_exe_search_paths (), @@ -2330,6 +2341,7 @@ TargetInstanceSettings::TargetInstanceSettings (const TargetInstanceSettings &rh m_expr_prefix_file (rhs.m_expr_prefix_file), m_expr_prefix_contents (rhs.m_expr_prefix_contents), m_prefer_dynamic_value (rhs.m_prefer_dynamic_value), + m_enable_synthetic_value(rhs.m_enable_synthetic_value), m_skip_prologue (rhs.m_skip_prologue), m_source_map (rhs.m_source_map), m_exe_search_paths (rhs.m_exe_search_paths), @@ -2365,6 +2377,7 @@ TargetInstanceSettings::operator= (const TargetInstanceSettings &rhs) m_expr_prefix_file = rhs.m_expr_prefix_file; m_expr_prefix_contents = rhs.m_expr_prefix_contents; m_prefer_dynamic_value = rhs.m_prefer_dynamic_value; + m_enable_synthetic_value = rhs.m_enable_synthetic_value; m_skip_prologue = rhs.m_skip_prologue; m_source_map = rhs.m_source_map; m_exe_search_paths = rhs.m_exe_search_paths; @@ -2442,6 +2455,13 @@ TargetInstanceSettings::UpdateInstanceSettingsVariable (const ConstString &var_n if (err.Success()) m_prefer_dynamic_value = new_value; } + else if (var_name == GetSettingNameForEnableSyntheticValue()) + { + bool ok; + bool new_value = Args::StringToBoolean(value, true, &ok); + if (ok) + m_enable_synthetic_value.SetCurrentValue(new_value); + } else if (var_name == GetSettingNameForSkipPrologue()) { err = UserSettingsController::UpdateBooleanOptionValue (value, op, m_skip_prologue); @@ -2626,6 +2646,13 @@ TargetInstanceSettings::GetInstanceSettingsValue (const SettingEntry &entry, { value.AppendString (g_dynamic_value_types[m_prefer_dynamic_value].string_value); } + else if (var_name == GetSettingNameForEnableSyntheticValue()) + { + if (m_skip_prologue) + value.AppendString ("true"); + else + value.AppendString ("false"); + } else if (var_name == GetSettingNameForSkipPrologue()) { if (m_skip_prologue) @@ -2824,6 +2851,7 @@ Target::SettingsController::instance_settings_table[] = // ================= ================== =============== ======================= ====== ====== ========================================================================= { TSC_EXPR_PREFIX , eSetVarTypeString , NULL , NULL, false, false, "Path to a file containing expressions to be prepended to all expressions." }, { TSC_PREFER_DYNAMIC , eSetVarTypeEnum , NULL , g_dynamic_value_types, false, false, "Should printed values be shown as their dynamic value." }, + { TSC_ENABLE_SYNTHETIC , eSetVarTypeBoolean, "true" , NULL, false, false, "Should synthetic values be used by default whenever available." }, { TSC_SKIP_PROLOGUE , eSetVarTypeBoolean, "true" , NULL, false, false, "Skip function prologues when setting breakpoints by name." }, { TSC_SOURCE_MAP , eSetVarTypeArray , NULL , NULL, false, false, "Source path remappings to use when locating source files from debug information." }, { TSC_EXE_SEARCH_PATHS , eSetVarTypeArray , NULL , NULL, false, false, "Executable search paths to use when locating executable files whose paths don't match the local file system." }, diff --git a/lldb/test/functionalities/completion/TestCompletion.py b/lldb/test/functionalities/completion/TestCompletion.py index 7f7c0cbd455..e40e8e99b89 100644 --- a/lldb/test/functionalities/completion/TestCompletion.py +++ b/lldb/test/functionalities/completion/TestCompletion.py @@ -57,12 +57,12 @@ class CommandLineCompletionTestCase(TestBase): self.complete_from_to('settings append target.er', 'settings append target.error-path') def test_settings_insert_after_target_en(self): - """Test that 'settings insert-after target.en' completes to 'settings insert-after target.env-vars'.""" - self.complete_from_to('settings insert-after target.en', 'settings insert-after target.env-vars') + """Test that 'settings insert-after target.env' completes to 'settings insert-after target.env-vars'.""" + self.complete_from_to('settings insert-after target.env', 'settings insert-after target.env-vars') def test_settings_insert_before_target_en(self): - """Test that 'settings insert-before target.en' completes to 'settings insert-before target.env-vars'.""" - self.complete_from_to('settings insert-before target.en', 'settings insert-before target.env-vars') + """Test that 'settings insert-before target.env' completes to 'settings insert-before target.env-vars'.""" + self.complete_from_to('settings insert-before target.env', 'settings insert-before target.env-vars') def test_settings_replace_target_ru(self): """Test that 'settings replace target.ru' completes to 'settings replace target.run-args'.""" diff --git a/lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/map/TestDataFormatterLibccMap.py b/lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/map/TestDataFormatterLibccMap.py index 871dfe77871..366a1539807 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/map/TestDataFormatterLibccMap.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/map/TestDataFormatterLibccMap.py @@ -9,7 +9,7 @@ from lldbtest import * class LibcxxMapDataFormatterTestCase(TestBase): - mydir = os.path.join("functionalities", "data-formatter", "data-formatter-stl", "libstdcpp", "map") + mydir = os.path.join("functionalities", "data-formatter", "data-formatter-stl", "libcxx", "map") @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") def test_with_dsym_and_run_command(self): @@ -56,6 +56,8 @@ class LibcxxMapDataFormatterTestCase(TestBase): # Execute the cleanup function during test case tear down. self.addTearDownHook(cleanup) + self.expect('image list',substrs=['libc++.1.dylib','libc++abi.dylib']) + self.runCmd("frame variable ii -T") self.runCmd("type summary add -x \"std::__1::map<\" --summary-string \"map has ${svar%#} items\" -e") @@ -87,19 +89,20 @@ class LibcxxMapDataFormatterTestCase(TestBase): 'second = 1']) self.runCmd("n");self.runCmd("n"); - self.runCmd("n");self.runCmd("n");self.runCmd("n"); + self.runCmd("n");self.runCmd("n"); + self.runCmd("frame select 0") self.expect("frame variable ii", - substrs = ['map has 9 items', + substrs = ['map has 8 items', '[5] = {', 'first = 5', 'second = 0', '[7] = {', 'first = 7', 'second = 1']) - + self.expect("p ii", - substrs = ['map has 9 items', + substrs = ['map has 8 items', '[5] = {', 'first = 5', 'second = 0', @@ -114,9 +117,6 @@ class LibcxxMapDataFormatterTestCase(TestBase): self.expect("frame variable ii[3]", substrs = ['first =', 'second =']); - - self.expect("frame variable ii[8]", matching=True, - substrs = ['1234567']) # check that the expression parser does not make use of # synthetic children instead of running code @@ -126,20 +126,19 @@ class LibcxxMapDataFormatterTestCase(TestBase): #self.expect("expression ii[8]", matching=False, error=True, # substrs = ['1234567']) - self.runCmd("n") + self.runCmd("n");self.runCmd("n");self.runCmd("n");self.runCmd("n");self.runCmd("n");self.runCmd('frame select 0') self.expect('frame variable ii', substrs = ['map has 0 items', '{}']) - self.runCmd("n") self.runCmd("frame variable si -T") self.expect('frame variable si', substrs = ['map has 0 items', '{}']) - self.runCmd("n") + self.runCmd("n");self.runCmd("n");self.runCmd('frame select 0') self.expect('frame variable si', substrs = ['map has 1 items', @@ -148,9 +147,11 @@ class LibcxxMapDataFormatterTestCase(TestBase): 'second = 0']) self.runCmd("n");self.runCmd("n");self.runCmd("n");self.runCmd("n"); + self.runCmd("n");self.runCmd("n");self.runCmd("n");self.runCmd("n") + self.runCmd("n");self.runCmd("n");self.runCmd('frame select 0') self.expect("frame variable si", - substrs = ['map has 5 items', + substrs = ['map has 4 items', '[0] = ', 'first = \"zero\"', 'second = 0', @@ -162,13 +163,10 @@ class LibcxxMapDataFormatterTestCase(TestBase): 'second = 2', '[3] = ', 'first = \"three\"', - 'second = 3', - '[4] = ', - 'first = \"four\"', - 'second = 4']) + 'second = 3']) self.expect("p si", - substrs = ['map has 5 items', + substrs = ['map has 4 items', '[0] = ', 'first = \"zero\"', 'second = 0', @@ -180,15 +178,12 @@ class LibcxxMapDataFormatterTestCase(TestBase): 'second = 2', '[3] = ', 'first = \"three\"', - 'second = 3', - '[4] = ', - 'first = \"four\"', - 'second = 4']) + 'second = 3']) # check access-by-index self.expect("frame variable si[0]", - substrs = ['first = ', 'four', - 'second = 4']); + substrs = ['first = ', 'one', + 'second = 1']); # check that the expression parser does not make use of # synthetic children instead of running code @@ -198,7 +193,7 @@ class LibcxxMapDataFormatterTestCase(TestBase): #self.expect("expression si[0]", matching=False, error=True, # substrs = ['first = ', 'zero']) - self.runCmd("n") + self.runCmd("n");self.runCmd("n"); self.expect('frame variable si', substrs = ['map has 0 items', @@ -262,17 +257,18 @@ class LibcxxMapDataFormatterTestCase(TestBase): substrs = ['map has 0 items', '{}']) - self.runCmd("n") + self.runCmd("n");self.runCmd("n"); self.runCmd("frame variable ss -T") self.expect('frame variable ss', substrs = ['map has 0 items', '{}']) - self.runCmd("n");self.runCmd("n");self.runCmd("n");self.runCmd("n"); + self.runCmd("n");self.runCmd("n");self.runCmd("n");self.runCmd("n");self.runCmd("n"); + self.runCmd("n");self.runCmd("n");self.runCmd("n");self.runCmd("n");self.runCmd('frame select 0') self.expect("frame variable ss", - substrs = ['map has 4 items', + substrs = ['map has 3 items', '[0] = ', 'second = \"hello\"', 'first = \"ciao\"', @@ -281,13 +277,10 @@ class LibcxxMapDataFormatterTestCase(TestBase): 'first = \"casa\"', '[2] = ', 'second = \"cat\"', - 'first = \"gatto\"', - '[3] = ', - 'second = \"..is always a Mac!\"', - 'first = \"a Mac..\"']) + 'first = \"gatto\"']) self.expect("p ss", - substrs = ['map has 4 items', + substrs = ['map has 3 items', '[0] = ', 'second = \"hello\"', 'first = \"ciao\"', @@ -296,13 +289,10 @@ class LibcxxMapDataFormatterTestCase(TestBase): 'first = \"casa\"', '[2] = ', 'second = \"cat\"', - 'first = \"gatto\"', - '[3] = ', - 'second = \"..is always a Mac!\"', - 'first = \"a Mac..\"']) + 'first = \"gatto\"']) # check access-by-index - self.expect("frame variable ss[3]", + self.expect("frame variable ss[2]", substrs = ['gatto', 'cat']); # check that the expression parser does not make use of @@ -313,7 +303,7 @@ class LibcxxMapDataFormatterTestCase(TestBase): #self.expect("expression ss[3]", matching=False, error=True, # substrs = ['gatto']) - self.runCmd("n") + self.runCmd("n");self.runCmd("n");self.runCmd("n");self.runCmd("n");self.runCmd('frame select 0') self.expect('frame variable ss', substrs = ['map has 0 items', diff --git a/lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/map/main.cpp b/lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/map/main.cpp index 58ab9980e14..704d17d5211 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/map/main.cpp +++ b/lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/map/main.cpp @@ -1,5 +1,9 @@ -#include <map> #include <string> +#ifdef _LIBCPP_INLINE_VISIBILITY +#undef _LIBCPP_INLINE_VISIBILITY +#endif +#define _LIBCPP_INLINE_VISIBILITY +#include <map> #define intint_map std::map<int, int> #define strint_map std::map<std::string, int> diff --git a/lldb/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/list/TestDataFormatterStdList.py b/lldb/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/list/TestDataFormatterStdList.py index f65cca2e84f..ac5d9792977 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/list/TestDataFormatterStdList.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/list/TestDataFormatterStdList.py @@ -64,6 +64,9 @@ class StdListDataFormatterTestCase(TestBase): self.expect("frame variable numbers_list --raw", matching=False, substrs = ['list has 0 items', '{}']) + self.expect("frame variable &numbers_list._M_impl._M_node --raw", matching=False, + substrs = ['list has 0 items', + '{}']) self.expect("frame variable numbers_list", substrs = ['list has 0 items', diff --git a/lldb/test/functionalities/data-formatter/data-formatter-synth/TestDataFormatterSynth.py b/lldb/test/functionalities/data-formatter/data-formatter-synth/TestDataFormatterSynth.py index 0cd2f453510..950fc55993a 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-synth/TestDataFormatterSynth.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-synth/TestDataFormatterSynth.py @@ -83,16 +83,16 @@ class SynthDataFormatterTestCase(TestBase): 'z = 8']) # Summary+Synth must work together - self.runCmd("type summary add BagOfInts --summary-string \"y=${var.y}\" -e") + self.runCmd("type summary add BagOfInts --summary-string \"x=${var.x}\" -e") self.expect('frame variable int_bag', - substrs = ['y=7', + substrs = ['x=6', 'x = 6', 'z = 8']) # Same output, but using Python - self.runCmd("type summary add BagOfInts --python-script \"return 'y=%s' % valobj.GetChildMemberWithName('y').GetValue()\" -e") + self.runCmd("type summary add BagOfInts --python-script \"return 'x=%s' % valobj.GetChildMemberWithName('x').GetValue()\" -e") self.expect('frame variable int_bag', - substrs = ['y=7', + substrs = ['x=6', 'x = 6', 'z = 8']) @@ -111,10 +111,10 @@ class SynthDataFormatterTestCase(TestBase): # Add the synth again and check that it's honored deeper in the hierarchy self.runCmd("type filter add BagOfInts --child x --child z") self.expect('frame variable bag_bag', - substrs = ['x = y=70 {', + substrs = ['x = x=69 {', 'x = 69', 'z = 71', - 'y = y=67 {', + 'y = x=66 {', 'x = 66', 'z = 68']) self.expect('frame variable bag_bag', matching=False, diff --git a/lldb/test/python_api/formatters/TestFormattersSBAPI.py b/lldb/test/python_api/formatters/TestFormattersSBAPI.py index 52cf01462d1..52bf0f470b7 100644 --- a/lldb/test/python_api/formatters/TestFormattersSBAPI.py +++ b/lldb/test/python_api/formatters/TestFormattersSBAPI.py @@ -24,6 +24,13 @@ class SBFormattersAPITestCase(TestBase): self.setTearDownCleanup() self.formatters() + @python_api_test + def test_force_synth_off(self): + """Test that one can have the public API return non-synthetic SBValues if desired""" + self.buildDwarf(dictionary={'EXE':'no_synth'}) + self.setTearDownCleanup() + self.force_synth_off() + def setUp(self): # Call super's setUp(). TestBase.setUp(self) @@ -155,7 +162,18 @@ class SBFormattersAPITestCase(TestBase): self.expect("frame variable foo", matching=True, substrs = ['X = 1']) + foo_var = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame().FindVariable('foo') + self.assertTrue(foo_var.IsValid(), 'could not find foo') + + self.assertTrue(foo_var.GetNumChildren() == 2, 'synthetic value has wrong number of child items (synth)') + self.assertTrue(foo_var.GetChildMemberWithName('X').GetValueAsUnsigned() == 1, 'foo_synth.X has wrong value (synth)') + self.assertFalse(foo_var.GetChildMemberWithName('B').IsValid(), 'foo_synth.B is valid but should not (synth)') + self.dbg.GetCategory("JASSynth").SetEnabled(False) + foo_var = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame().FindVariable('foo') + self.assertTrue(foo_var.IsValid(), 'could not find foo') + + self.assertFalse(foo_var.GetNumChildren() == 2, 'still seeing synthetic value') filter = lldb.SBTypeFilter(0) filter.AppendExpressionPath("A") @@ -164,6 +182,13 @@ class SBFormattersAPITestCase(TestBase): self.expect("frame variable foo", substrs = ['A = 1', 'D = 6.28']) + foo_var = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame().FindVariable('foo') + self.assertTrue(foo_var.IsValid(), 'could not find foo') + + self.assertTrue(foo_var.GetNumChildren() == 2, 'synthetic value has wrong number of child items (filter)') + self.assertTrue(foo_var.GetChildMemberWithName('X').GetValueAsUnsigned() == 0, 'foo_synth.X has wrong value (filter)') + self.assertTrue(foo_var.GetChildMemberWithName('A').GetValueAsUnsigned() == 1, 'foo_synth.A has wrong value (filter)') + self.assertTrue(filter.ReplaceExpressionPathAtIndex(0,"C"), "failed to replace an expression path in filter") self.expect("frame variable foo", substrs = ['A = 1', 'D = 6.28']) @@ -180,6 +205,10 @@ class SBFormattersAPITestCase(TestBase): self.expect("frame variable bar", substrs = ["C = 'e'", 'D = 6.28']) + foo_var = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame().FindVariable('foo') + self.assertTrue(foo_var.IsValid(), 'could not find foo') + self.assertTrue(foo_var.GetChildMemberWithName('C').GetValueAsUnsigned() == ord('e'), 'foo_synth.C has wrong value (filter)') + chosen = self.dbg.GetFilterForType(lldb.SBTypeNameSpecifier("JustAStruct")) self.assertTrue(chosen.count == 2, "wrong filter found for JustAStruct") self.assertTrue(chosen.GetExpressionPathAtIndex(0) == 'C', "wrong item at index 0 for JustAStruct") @@ -269,6 +298,58 @@ class SBFormattersAPITestCase(TestBase): self.assertTrue(summary.IsValid(), "no summary found for foo* when one was in place") self.assertTrue(summary.GetData() == "hello static world", "wrong summary found for foo*") + def force_synth_off(self): + """Test that one can have the public API return non-synthetic SBValues if desired""" + self.runCmd("file no_synth", CURRENT_EXECUTABLE_SET) + + self.expect("breakpoint set -f main.cpp -l %d" % self.line, + BREAKPOINT_CREATED, + startstr = "Breakpoint created: 1: file ='main.cpp', line = %d, locations = 1" % + self.line) + + 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 filter clear', check=False) + self.runCmd('type synthetic clear', check=False) + self.runCmd('type category delete foobar', check=False) + self.runCmd('type category delete JASSynth', check=False) + self.runCmd('type category delete newbar', check=False) + self.runCmd('settings set target.enable-synthetic-value true') + + # Execute the cleanup function during test case tear down. + self.addTearDownHook(cleanup) + + frame = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() + int_vector = frame.FindVariable("int_vector") + if self.TraceOn(): + print int_vector + self.assertTrue(int_vector.GetNumChildren() == 0, 'synthetic vector is empty') + + self.runCmd('settings set target.enable-synthetic-value false') + frame = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() + int_vector = frame.FindVariable("int_vector") + if self.TraceOn(): + print int_vector + self.assertFalse(int_vector.GetNumChildren() == 0, '"physical" vector is not empty') + + self.runCmd('settings set target.enable-synthetic-value true') + frame = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() + int_vector = frame.FindVariable("int_vector") + if self.TraceOn(): + print int_vector + self.assertTrue(int_vector.GetNumChildren() == 0, 'synthetic vector is still empty') + + if __name__ == '__main__': import atexit lldb.SBDebugger.Initialize() diff --git a/lldb/test/python_api/formatters/jas_synth.py b/lldb/test/python_api/formatters/jas_synth.py index 16db646d660..587671888e3 100644 --- a/lldb/test/python_api/formatters/jas_synth.py +++ b/lldb/test/python_api/formatters/jas_synth.py @@ -5,6 +5,7 @@ class jasSynthProvider: def num_children(self): return 2; def get_child_at_index(self, index): + child = None if index == 0: child = self.valobj.GetChildMemberWithName('A'); if index == 1: @@ -15,7 +16,7 @@ class jasSynthProvider: return 0; if name == 'X': return 1; - return 2; + return None; def __lldb_init_module(debugger,dict): debugger.CreateCategory("JASSynth").AddTypeSynthetic(lldb.SBTypeNameSpecifier("JustAStruct"), diff --git a/lldb/test/python_api/formatters/main.cpp b/lldb/test/python_api/formatters/main.cpp index 6785749e7d2..e26467e9fb0 100644 --- a/lldb/test/python_api/formatters/main.cpp +++ b/lldb/test/python_api/formatters/main.cpp @@ -1,4 +1,5 @@ #include <stdio.h> +#include <vector> struct JustAStruct { @@ -34,5 +35,6 @@ int main(int argc, char const *argv[]) { bar.D = 6.28; bar.E = 3100419850; JustAStruct* foo_ptr = &foo; + std::vector<int> int_vector; return 0; // Set break point at this line. } |