diff options
11 files changed, 191 insertions, 104 deletions
diff --git a/lldb/include/lldb/Core/FormatManager.h b/lldb/include/lldb/Core/FormatManager.h index 23300464001..63b04e582df 100644 --- a/lldb/include/lldb/Core/FormatManager.h +++ b/lldb/include/lldb/Core/FormatManager.h @@ -564,6 +564,15 @@ template<> bool FormatNavigator<lldb::RegularExpressionSP, SummaryFormat>::Delete(const char* type); +template<> +bool +FormatNavigator<lldb::RegularExpressionSP, SyntheticFilter>::Get(const char* key, SyntheticFilter::SharedPointer& value); + +template<> +bool +FormatNavigator<lldb::RegularExpressionSP, SyntheticFilter>::Delete(const char* type); + + class CategoryMap; class FormatCategory @@ -572,14 +581,17 @@ private: typedef FormatNavigator<const char*, SummaryFormat> SummaryNavigator; typedef FormatNavigator<lldb::RegularExpressionSP, SummaryFormat> RegexSummaryNavigator; typedef FormatNavigator<const char*, SyntheticFilter> FilterNavigator; + typedef FormatNavigator<lldb::RegularExpressionSP, SyntheticFilter> RegexFilterNavigator; typedef SummaryNavigator::MapType SummaryMap; typedef RegexSummaryNavigator::MapType RegexSummaryMap; typedef FilterNavigator::MapType FilterMap; + typedef RegexFilterNavigator::MapType RegexFilterMap; SummaryNavigator::SharedPointer m_summary_nav; RegexSummaryNavigator::SharedPointer m_regex_summary_nav; FilterNavigator::SharedPointer m_filter_nav; + RegexFilterNavigator::SharedPointer m_regex_filter_nav; bool m_enabled; @@ -611,12 +623,14 @@ public: typedef SummaryNavigator::SharedPointer SummaryNavigatorSP; typedef RegexSummaryNavigator::SharedPointer RegexSummaryNavigatorSP; typedef FilterNavigator::SharedPointer FilterNavigatorSP; + typedef RegexFilterNavigator::SharedPointer RegexFilterNavigatorSP; FormatCategory(IFormatChangeListener* clist, std::string name) : m_summary_nav(new SummaryNavigator("summary",clist)), m_regex_summary_nav(new RegexSummaryNavigator("regex-summary",clist)), m_filter_nav(new FilterNavigator("filter",clist)), + m_regex_filter_nav(new RegexFilterNavigator("regex-filter",clist)), m_enabled(false), m_change_listener(clist), m_mutex(Mutex::eMutexTypeRecursive), @@ -641,6 +655,12 @@ public: return FilterNavigatorSP(m_filter_nav); } + RegexFilterNavigatorSP + RegexFilter() + { + return RegexFilterNavigatorSP(m_regex_filter_nav); + } + bool IsEnabled() const { @@ -671,7 +691,12 @@ public: { if (!IsEnabled()) return false; - return (Filter()->Get(vobj, entry, use_dynamic, reason)); + if (Filter()->Get(vobj, entry, use_dynamic, reason)) + return true; + bool regex = RegexFilter()->Get(vobj, entry, use_dynamic, reason); + if (regex && reason) + *reason |= lldb::eFormatterChoiceCriterionRegularExpressionFilter; + return regex; } // just a shortcut for Summary()->Clear; RegexSummary()->Clear() diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h index 1bff914ed3f..bcf72b733b7 100644 --- a/lldb/include/lldb/Core/ValueObject.h +++ b/lldb/include/lldb/Core/ValueObject.h @@ -77,7 +77,8 @@ public: eDisplayValue = 1, eDisplaySummary, eDisplayLanguageSpecific, - eDisplayLocation + eDisplayLocation, + eDisplayChildrenCount, }; enum ExpressionPathScanEndReason @@ -499,8 +500,9 @@ public: const char * GetObjectDescription (); - const char * - GetPrintableRepresentation(ValueObjectRepresentationStyle val_obj_display = eDisplaySummary, + bool + GetPrintableRepresentation(Stream& s, + ValueObjectRepresentationStyle val_obj_display = eDisplaySummary, lldb::Format custom_format = lldb::eFormatInvalid); bool diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h index 34e9a6cc3ef..92f625e5109 100644 --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -506,6 +506,7 @@ namespace lldb { eFormatterChoiceCriterionNavigatedTypedefs = 0x00000002, eFormatterChoiceCriterionNavigatedBaseClasses = 0x00000004, eFormatterChoiceCriterionRegularExpressionSummary = 0x00000008, + eFormatterChoiceCriterionRegularExpressionFilter = 0x00000008, eFormatterChoiceCriterionDynamicObjCHierarchy = 0x00000010 } FormatterChoiceCriterion; diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 9442600a4d7..309afd4e87c 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -742,6 +742,8 @@ ScanFormatDescriptor(const char* var_name_begin, // if this is an S, print the summary after all else if (*format_name == 'S') *val_obj_display = ValueObject::eDisplaySummary; + else if (*format_name == '#') + *val_obj_display = ValueObject::eDisplayChildrenCount; else if (log) log->Printf("%s is an error, leaving the previous value alone", format_name); } diff --git a/lldb/source/Core/FormatClasses.cpp b/lldb/source/Core/FormatClasses.cpp index 48097087253..aeace975932 100644 --- a/lldb/source/Core/FormatClasses.cpp +++ b/lldb/source/Core/FormatClasses.cpp @@ -84,7 +84,7 @@ StringSummaryFormat::FormatObject(lldb::ValueObjectSP object) s.PutCString(", "); s.PutCString(child_sp.get()->GetName().AsCString()); s.PutChar('='); - s.PutCString(child_sp.get()->GetPrintableRepresentation()); + child_sp.get()->GetPrintableRepresentation(s); } } diff --git a/lldb/source/Core/FormatManager.cpp b/lldb/source/Core/FormatManager.cpp index e064534028f..47426fc49d5 100644 --- a/lldb/source/Core/FormatManager.cpp +++ b/lldb/source/Core/FormatManager.cpp @@ -192,6 +192,44 @@ FormatNavigator<lldb::RegularExpressionSP, SummaryFormat>::Delete(const char* ty return false; } +template<> +bool +FormatNavigator<lldb::RegularExpressionSP, SyntheticFilter>::Get(const char* key, SyntheticFilter::SharedPointer& value) +{ + Mutex::Locker(m_format_map.mutex()); + MapIterator pos, end = m_format_map.map().end(); + for (pos = m_format_map.map().begin(); pos != end; pos++) + { + lldb::RegularExpressionSP regex = pos->first; + if (regex->Execute(key)) + { + value = pos->second; + return true; + } + } + return false; +} + +template<> +bool +FormatNavigator<lldb::RegularExpressionSP, SyntheticFilter>::Delete(const char* type) +{ + Mutex::Locker(m_format_map.mutex()); + MapIterator pos, end = m_format_map.map().end(); + for (pos = m_format_map.map().begin(); pos != end; pos++) + { + lldb::RegularExpressionSP regex = pos->first; + if ( ::strcmp(type,regex->GetText()) == 0) + { + m_format_map.map().erase(pos); + if (m_format_map.listener) + m_format_map.listener->Changed(); + return true; + } + } + return false; +} + lldb::Format FormatManager::GetSingleItemFormat(lldb::Format vector_format) { diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index fce00f6d4f3..1453ee23714 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -941,11 +941,9 @@ ValueObject::GetValueAsUnsigned() return 0; } -// this call should only return pointers to data that needs no special memory management -// (either because they are hardcoded strings, or because they are backed by some other -// object); returning any new()-ed or malloc()-ed data here, will lead to leaks! -const char * -ValueObject::GetPrintableRepresentation(ValueObjectRepresentationStyle val_obj_display, +bool +ValueObject::GetPrintableRepresentation(Stream& s, + ValueObjectRepresentationStyle val_obj_display, lldb::Format custom_format) { @@ -955,6 +953,7 @@ ValueObject::GetPrintableRepresentation(ValueObjectRepresentationStyle val_obj_d SetFormat(custom_format); const char * return_value; + std::auto_ptr<char> alloc_mem; switch(val_obj_display) { @@ -970,6 +969,17 @@ ValueObject::GetPrintableRepresentation(ValueObjectRepresentationStyle val_obj_d case eDisplayLocation: return_value = GetLocationAsCString(); break; + case eDisplayChildrenCount: + // keep this out of the local scope so it will only get deleted when + // we exit the function (..and we have a copy of the data into the Stream) + alloc_mem = std::auto_ptr<char>((char*)(return_value = new char[512])); + { + int count = GetNumChildren(); + snprintf(alloc_mem.get(), 512, "%d", count); + break; + } + default: + break; } // this code snippet might lead to endless recursion, thus we use a RefCounter here to @@ -983,16 +993,26 @@ ValueObject::GetPrintableRepresentation(ValueObjectRepresentationStyle val_obj_d { if (ClangASTContext::IsAggregateType (GetClangType()) == true) { - // this thing has no value - return_value = "<no summary defined for this datatype>"; + // this thing has no value, and it seems to have no summary + // some combination of unitialized data and other factors can also + // raise this condition, so let's print a nice generic error message + return_value = "<no available summary>"; } else return_value = GetValueAsCString(); } } - return (return_value ? return_value : "<no printable representation>"); - + if (return_value) + s.PutCString(return_value); + else + s.PutCString("<no printable representation>"); + + // we should only return false here if we could not do *anything* + // even if we have an error message as output, that's a success + // from our callers' perspective, so return true + return true; + } bool @@ -1116,10 +1136,7 @@ ValueObject::DumpPrintableRepresentation(Stream& s, (custom_format == lldb::eFormatDefault)) // use the [] operator return false; } - const char *targetvalue = GetPrintableRepresentation(val_obj_display, custom_format); - if (targetvalue) - s.PutCString(targetvalue); - bool var_success = (targetvalue != NULL); + bool var_success = GetPrintableRepresentation(s, val_obj_display, custom_format); if (custom_format != eFormatInvalid) SetFormat(eFormatDefault); return var_success; diff --git a/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdListSynthProvider.py b/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdListSynthProvider.py index 1cfe8c24147..a464c80a91e 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdListSynthProvider.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdListSynthProvider.py @@ -23,21 +23,17 @@ class StdListSynthProvider: return (size - 1) def get_child_index(self,name): - if name == "len": - return self.num_children() - else: - return int(name.lstrip('[').rstrip(']')) + return int(name.lstrip('[').rstrip(']')) def get_child_at_index(self,index): - if index == self.num_children(): - return self.valobj.CreateValueFromExpression("len",str(self.num_children())) - else: - offset = index - current = self.next - while offset > 0: - current = current.GetChildMemberWithName('_M_next') - offset = offset - 1 - return current.CreateChildAtOffset('['+str(index)+']',2*current.GetType().GetByteSize(),self.data_type) + if index >= self.num_children(): + return None; + offset = index + current = self.next + while offset > 0: + current = current.GetChildMemberWithName('_M_next') + offset = offset - 1 + return current.CreateChildAtOffset('['+str(index)+']',2*current.GetType().GetByteSize(),self.data_type) def extract_type_name(self,name): self.type_name = name[16:] diff --git a/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdMapSynthProvider.py b/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdMapSynthProvider.py index bb109331e22..71357856bc6 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdMapSynthProvider.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdMapSynthProvider.py @@ -1,8 +1,11 @@ import re + class StdMapSynthProvider: + def __init__(self, valobj, dict): self.valobj = valobj; self.update() + def update(self): self.Mt = self.valobj.GetChildMemberWithName('_M_t') self.Mimpl = self.Mt.GetChildMemberWithName('_M_impl') @@ -19,6 +22,7 @@ class StdMapSynthProvider: self.data_type = self.Mt.GetTarget().FindFirstType(self.gcc_type_name) self.data_size = self.data_type.GetByteSize() self.skip_size = self.Mheader.GetType().GetByteSize() + def expand_clang_type_name(self): type_name = self.Mimpl.GetType().GetName() index = type_name.find("std::pair<") @@ -35,6 +39,7 @@ class StdMapSynthProvider: template_count = template_count - 1 index = index + 1; self.clang_type_name = type_name + def expand_gcc_type_name(self): type_name = self.Mt.GetType().GetName() index = type_name.find("std::pair<") @@ -54,36 +59,40 @@ class StdMapSynthProvider: index = index - 1 index = index + 1; self.gcc_type_name = type_name + def num_children(self): root_ptr_val = self.node_ptr_value(self.Mroot) if root_ptr_val == 0: return 0; return self.Mimpl.GetChildMemberWithName('_M_node_count').GetValueAsUnsigned(0) + def get_child_index(self,name): - if name == "len": - return self.num_children(); - else: - return int(name.lstrip('[').rstrip(']')) + return int(name.lstrip('[').rstrip(']')) + def get_child_at_index(self,index): - if index == self.num_children(): - return self.valobj.CreateValueFromExpression("len",str(self.num_children())) - else: - offset = index - current = self.left(self.Mheader); - while offset > 0: - current = self.increment_node(current) - offset = offset - 1; - # skip all the base stuff and get at the data - return current.CreateChildAtOffset('['+str(index)+']',self.skip_size,self.data_type) + if index >= self.num_children(): + return None; + offset = index + current = self.left(self.Mheader); + while offset > 0: + current = self.increment_node(current) + offset = offset - 1; + # skip all the base stuff and get at the data + return current.CreateChildAtOffset('['+str(index)+']',self.skip_size,self.data_type) + # utility functions def node_ptr_value(self,node): return node.GetValueAsUnsigned(0) + def right(self,node): return node.GetChildMemberWithName("_M_right"); + def left(self,node): return node.GetChildMemberWithName("_M_left"); + def parent(self,node): return node.GetChildMemberWithName("_M_parent"); + # from libstdc++ implementation of iterator for rbtree def increment_node(self,node): if self.node_ptr_value(self.right(node)) != 0: diff --git a/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdVectorSynthProvider.py b/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdVectorSynthProvider.py index dc226902d1e..f2b3d442925 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdVectorSynthProvider.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-python-synth/StdVectorSynthProvider.py @@ -1,55 +1,52 @@ class StdVectorSynthProvider: - def __init__(self, valobj, dict): - self.valobj = valobj; - self.update() + def __init__(self, valobj, dict): + self.valobj = valobj; + self.update() - def num_children(self): - start_val = self.start.GetValueAsUnsigned(0) - finish_val = self.finish.GetValueAsUnsigned(0) - end_val = self.end.GetValueAsUnsigned(0) - # Before a vector has been constructed, it will contain bad values - # so we really need to be careful about the length we return since - # unitialized data can cause us to return a huge number. We need - # to also check for any of the start, finish or end of storage values - # being zero (NULL). If any are, then this vector has not been - # initialized yet and we should return zero + def num_children(self): + start_val = self.start.GetValueAsUnsigned(0) + finish_val = self.finish.GetValueAsUnsigned(0) + end_val = self.end.GetValueAsUnsigned(0) + # Before a vector has been constructed, it will contain bad values + # so we really need to be careful about the length we return since + # unitialized data can cause us to return a huge number. We need + # to also check for any of the start, finish or end of storage values + # being zero (NULL). If any are, then this vector has not been + # initialized yet and we should return zero - # Make sure nothing is NULL - if start_val == 0 or finish_val == 0 or end_val == 0: - return 0 - # Make sure start is less than finish - if start_val >= finish_val: - return 0 - # Make sure finish is less than or equal to end of storage - if finish_val > end_val: - return 0 + # Make sure nothing is NULL + if start_val == 0 or finish_val == 0 or end_val == 0: + return 0 + # Make sure start is less than finish + if start_val >= finish_val: + return 0 + # Make sure finish is less than or equal to end of storage + if finish_val > end_val: + return 0 - # We might still get things wrong, so cap things at 256 items for now - # TODO: read a target "settings set" variable for this to allow it to - # be customized - num_children = (finish_val-start_val)/self.data_size - if num_children > 256: - return 256 - return num_children + # We might still get things wrong, so cap things at 256 items for now + # TODO: read a target "settings set" variable for this to allow it to + # be customized + num_children = (finish_val-start_val)/self.data_size + if num_children > 256: + return 256 + return num_children - def get_child_index(self,name): - if name == "len": - return self.num_children(); - else: - return int(name.lstrip('[').rstrip(']')) + def get_child_index(self,name): + return int(name.lstrip('[').rstrip(']')) - def get_child_at_index(self,index): - if index == self.num_children(): - return self.valobj.CreateValueFromExpression("len",str(self.num_children())) - else: - offset = index * self.data_size - return self.start.CreateChildAtOffset('['+str(index)+']',offset,self.data_type) + def get_child_at_index(self,index): + if index >= self.num_children(): + return None; + offset = index * self.data_size + return self.start.CreateChildAtOffset('['+str(index)+']',offset,self.data_type) + + def update(self): + impl = self.valobj.GetChildMemberWithName('_M_impl') + self.start = impl.GetChildMemberWithName('_M_start') + self.finish = impl.GetChildMemberWithName('_M_finish') + self.end = impl.GetChildMemberWithName('_M_end_of_storage') + self.data_type = self.start.GetType().GetPointeeType() + self.data_size = self.data_type.GetByteSize() - def update(self): - impl = self.valobj.GetChildMemberWithName('_M_impl') - self.start = impl.GetChildMemberWithName('_M_start') - self.finish = impl.GetChildMemberWithName('_M_finish') - self.end = impl.GetChildMemberWithName('_M_end_of_storage') - self.data_type = self.start.GetType().GetPointeeType() - self.data_size = self.data_type.GetByteSize() diff --git a/lldb/test/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py b/lldb/test/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py index 14859e0caef..1161f75e0ce 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py @@ -191,7 +191,7 @@ class DataFormatterTestCase(TestBase): 'smart']) # test summaries based on synthetic children - self.runCmd("type summary add std::string_vect string_vect -f \"vector has ${svar.len} items\" -e") + self.runCmd("type summary add std::string_vect string_vect -f \"vector has ${svar%#} items\" -e") self.expect("frame variable strings", substrs = ['vector has 3 items', 'goofy', @@ -215,24 +215,24 @@ class DataFormatterTestCase(TestBase): self.runCmd("frame variable numbers_list -T") self.runCmd("type synth add std::int_list std::string_list int_list string_list -l StdListSynthProvider") - self.runCmd("type summary add std::int_list std::string_list int_list string_list -f \"list has ${svar.len} items\" -e") + self.runCmd("type summary add std::int_list std::string_list int_list string_list -f \"list has ${svar%#} items\" -e") self.runCmd("type format add -f hex int") self.expect("frame variable numbers_list", - substrs = ['list has 0x00000000 items', + substrs = ['list has 0 items', '{}']) self.runCmd("n") self.expect("frame variable numbers_list", - substrs = ['list has 0x00000001 items', + substrs = ['list has 1 items', '[0] = ', '0x12345678']) self.runCmd("n");self.runCmd("n");self.runCmd("n"); self.expect("frame variable numbers_list", - substrs = ['list has 0x00000004 items', + substrs = ['list has 4 items', '[0] = ', '0x12345678', '[1] =', @@ -245,7 +245,7 @@ class DataFormatterTestCase(TestBase): self.runCmd("n");self.runCmd("n"); self.expect("frame variable numbers_list", - substrs = ['list has 0x00000006 items', + substrs = ['list has 6 items', '[0] = ', '0x12345678', '0x11223344', @@ -259,14 +259,14 @@ class DataFormatterTestCase(TestBase): self.runCmd("n") self.expect("frame variable numbers_list", - substrs = ['list has 0x00000000 items', + substrs = ['list has 0 items', '{}']) self.runCmd("n");self.runCmd("n");self.runCmd("n");self.runCmd("n"); self.expect("frame variable numbers_list", - substrs = ['list has 0x00000004 items', + substrs = ['list has 4 items', '[0] = ', '1', '[1] = ', '2', '[2] = ', '3', @@ -305,7 +305,7 @@ class DataFormatterTestCase(TestBase): self.runCmd("frame variable ii -T") self.runCmd("script from StdMapSynthProvider import *") - self.runCmd("type summary add std::intint_map intint_map -f \"map has ${svar.len} items\" -e") + self.runCmd("type summary add std::intint_map intint_map -f \"map has ${svar%#} items\" -e") self.runCmd("type synth add std::intint_map intint_map -l StdMapSynthProvider") @@ -356,7 +356,7 @@ class DataFormatterTestCase(TestBase): self.runCmd("n") self.runCmd("frame variable si -T") - self.runCmd("type summary add std::strint_map strint_map -f \"map has ${svar.len} items\" -e") + self.runCmd("type summary add std::strint_map strint_map -f \"map has ${svar%#} items\" -e") self.runCmd("type synth add std::strint_map strint_map -l StdMapSynthProvider") self.expect('frame variable si', @@ -400,7 +400,7 @@ class DataFormatterTestCase(TestBase): self.runCmd("n") self.runCmd("frame variable is -T") - self.runCmd("type summary add std::intstr_map intstr_map -f \"map has ${svar.len} items\" -e") + self.runCmd("type summary add std::intstr_map intstr_map -f \"map has ${svar%#} items\" -e") self.runCmd("type synth add std::intstr_map intstr_map -l StdMapSynthProvider") self.expect('frame variable is', @@ -433,7 +433,7 @@ class DataFormatterTestCase(TestBase): self.runCmd("n") self.runCmd("frame variable ss -T") - self.runCmd("type summary add std::strstr_map strstr_map -f \"map has ${svar.len} items\" -e") + self.runCmd("type summary add std::strstr_map strstr_map -f \"map has ${svar%#} items\" -e") self.runCmd("type synth add std::strstr_map strstr_map -l StdMapSynthProvider") self.expect('frame variable ss', |