diff --git a/lldb/bindings/interface/SBTarget.i b/lldb/bindings/interface/SBTarget.i --- a/lldb/bindings/interface/SBTarget.i +++ b/lldb/bindings/interface/SBTarget.i @@ -412,6 +412,9 @@ uint32_t GetCodeByteSize (); + uint32_t + GetMaximumNumberOfChildrenToDisplay() const; + lldb::SBError SetSectionLoadAddress (lldb::SBSection section, lldb::addr_t section_base_addr); diff --git a/lldb/examples/synthetic/gnu_libstdcpp.py b/lldb/examples/synthetic/gnu_libstdcpp.py --- a/lldb/examples/synthetic/gnu_libstdcpp.py +++ b/lldb/examples/synthetic/gnu_libstdcpp.py @@ -9,6 +9,12 @@ # before relying on these formatters to do the right thing for your setup +def ForwardListSummaryProvider(valobj, dict): + list_capping_size = valobj.GetTarget().GetMaximumNumberOfChildrenToDisplay() + if valobj.GetNumChildren() >= list_capping_size: + return "(capped) size=" + str(valobj.GetNumChildren()) + return "size=" + str(valobj.GetNumChildren()) + class AbstractListSynthProvider: def __init__(self, valobj, dict, has_prev): ''' @@ -22,6 +28,11 @@ self.has_prev = has_prev logger >> "Providing synthetic children for a list named " + \ str(valobj.GetName()) + try: + self.list_capping_size = self.valobj.GetTarget().GetMaximumNumberOfChildrenToDisplay() + except: + logger >> "Error determining the capping size. The default value 256 is applied" + self.list_capping_size = 256 def next_node(self, node): logger = lldb.formatters.Logger.Logger() @@ -47,9 +58,14 @@ # try to detect if this list has a loop def has_loop(self): global _list_uses_loop_detector + # In case of list we know the exact number of children in advance so we do not need to run + # cycle detection algorithm + if self.has_prev: + _list_uses_loop_detector = False logger = lldb.formatters.Logger.Logger() if not _list_uses_loop_detector: logger >> "Asked not to use loop detection" + _list_uses_loop_detector = True return False slow = self.next fast1 = self.next @@ -99,6 +115,9 @@ '_M_next').GetValueAsUnsigned(0) != self.get_end_of_list_address(): size = size + 1 current = current.GetChildMemberWithName('_M_next') + # In case of forward_list capping size is the limit of the children to be displayed + if not self.has_prev and size >= self.list_capping_size: + break return size except: logger >> "Error determining the size" diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h --- a/lldb/include/lldb/API/SBTarget.h +++ b/lldb/include/lldb/API/SBTarget.h @@ -336,6 +336,11 @@ /// unit from the Architecture's code bus uint32_t GetCodeByteSize(); + /// Gets the target.max-children-count value + /// It should be used to limit the number of + /// children of large data structures to be displayed. + uint32_t GetMaximumNumberOfChildrenToDisplay() const; + /// Set the base load address for a module section. /// /// \param[in] section diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -1745,6 +1745,16 @@ return 0; } +uint32_t SBTarget::GetMaximumNumberOfChildrenToDisplay() const { + LLDB_RECORD_METHOD_CONST_NO_ARGS(uint32_t, SBTarget, GetMaximumNumberOfChildrenToDisplay); + + TargetSP target_sp(GetSP()); + if(target_sp){ + return target_sp->GetMaximumNumberOfChildrenToDisplay(); + } + return 0; +} + uint32_t SBTarget::GetAddressByteSize() { LLDB_RECORD_METHOD_NO_ARGS(uint32_t, SBTarget, GetAddressByteSize); @@ -2679,6 +2689,7 @@ LLDB_REGISTER_METHOD(const char *, SBTarget, GetTriple, ()); LLDB_REGISTER_METHOD(uint32_t, SBTarget, GetDataByteSize, ()); LLDB_REGISTER_METHOD(uint32_t, SBTarget, GetCodeByteSize, ()); + LLDB_REGISTER_METHOD_CONST(uint32_t, SBTarget, GetMaximumNumberOfChildrenToDisplay,()); LLDB_REGISTER_METHOD(uint32_t, SBTarget, GetAddressByteSize, ()); LLDB_REGISTER_METHOD(lldb::SBModule, SBTarget, GetModuleAtIndex, (uint32_t)); diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -961,7 +961,7 @@ cpp_category_sp->GetRegexTypeSummariesContainer()->Add( RegularExpression("^std::(__cxx11::)?forward_list<.+>(( )?&)?$"), TypeSummaryImplSP( - new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); + new ScriptSummaryFormat(stl_summary_flags, "lldb.formatters.cpp.gnu_libstdcpp.ForwardListSummaryProvider"))); AddCXXSynthetic( cpp_category_sp, diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py @@ -52,6 +52,19 @@ '[4] = 55555', '}']) + self.expect("settings show target.max-children-count", matching=True, + substrs=['target.max-children-count (int) = 256']) + + self.expect("frame variable thousand_elts",matching=False, + substrs=[ + '[256] = 256', + '[333] = 333', + '[444] = 444', + '[555] = 555', + '[666] = 666', + '...' + ]) + @add_test_categories(["libstdcxx"]) def test_libstdcpp(self): self.do_test(USE_LIBSTDCPP) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/main.cpp --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/main.cpp @@ -2,6 +2,9 @@ int main() { std::forward_list empty{}, one_elt{47}, - five_elts{1, 22, 333, 4444, 55555}; + five_elts{1, 22, 333, 4444, 55555}, thousand_elts{}; + for(int i = 0; i<1000;i++){ + thousand_elts.push_front(i); + } return 0; // break here }