diff options
Diffstat (limited to 'lldb')
19 files changed, 1436 insertions, 441 deletions
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h index 7bbdf0632fb..af8524144be 100644 --- a/lldb/include/lldb/Core/Debugger.h +++ b/lldb/include/lldb/Core/Debugger.h @@ -474,159 +474,100 @@ private: public: - class ValueFormats + class Formatting { public: - static bool - Get(ValueObject& vobj, ValueFormat::SharedPointer &entry); - - static void - Add(const ConstString &type, const ValueFormat::SharedPointer &entry); - - static bool - Delete(const ConstString &type); - - static void - Clear(); - - static void - LoopThrough(ValueFormat::ValueCallback callback, void* callback_baton); - - static uint32_t - GetCurrentRevision(); - - static uint32_t - GetCount(); - }; - - class SummaryFormats - { - public: - - static bool - Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry); - - static void - Add(const ConstString &type, const SummaryFormat::SharedPointer &entry); - - static bool - Delete(const ConstString &type); - - static void - Clear(); - - static void - LoopThrough(SummaryFormat::SummaryCallback callback, void* callback_baton); - - static uint32_t - GetCurrentRevision(); - - static uint32_t - GetCount(); - }; - - class SystemSummaryFormats - { - public: - - static bool - Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry); - - static void - Add(const ConstString &type, const SummaryFormat::SharedPointer &entry); - - static bool - Delete(const ConstString &type); - - static void - Clear(); - - static void - LoopThrough(SummaryFormat::SummaryCallback callback, void* callback_baton); - - static uint32_t - GetCurrentRevision(); - - static uint32_t - GetCount(); - }; - - class RegexSummaryFormats - { - public: - - static bool - Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry); - - static void - Add(const lldb::RegularExpressionSP &type, const SummaryFormat::SharedPointer &entry); - - static bool - Delete(const ConstString &type); - - static void - Clear(); - - static void - LoopThrough(SummaryFormat::RegexSummaryCallback callback, void* callback_baton); - - static uint32_t - GetCurrentRevision(); - - static uint32_t - GetCount(); - }; - - class SystemRegexSummaryFormats - { - public: - - static bool - Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry); - - static void - Add(const lldb::RegularExpressionSP &type, const SummaryFormat::SharedPointer &entry); - - static bool - Delete(const ConstString &type); - - static void - Clear(); - - static void - LoopThrough(SummaryFormat::RegexSummaryCallback callback, void* callback_baton); - - static uint32_t - GetCurrentRevision(); - - static uint32_t - GetCount(); - }; - - class NamedSummaryFormats - { - public: - - static bool - Get(const ConstString &type, SummaryFormat::SharedPointer &entry); - - static void - Add(const ConstString &type, const SummaryFormat::SharedPointer &entry); + class ValueFormats + { + public: + static bool + Get(ValueObject& vobj, ValueFormat::SharedPointer &entry); + + static void + Add(const ConstString &type, const ValueFormat::SharedPointer &entry); + + static bool + Delete(const ConstString &type); + + static void + Clear(); + + static void + LoopThrough(ValueFormat::ValueCallback callback, void* callback_baton); + + static uint32_t + GetCurrentRevision(); + + static uint32_t + GetCount(); + }; + + static lldb::FormatCategorySP + SummaryFormats(const char* category_name = NULL); static bool - Delete(const ConstString &type); - - static void - Clear(); + GetSummaryFormat(ValueObject& vobj, + lldb::SummaryFormatSP& entry); - static void - LoopThrough(SummaryFormat::SummaryCallback callback, void* callback_baton); - - static uint32_t - GetCurrentRevision(); - - static uint32_t - GetCount(); + class NamedSummaryFormats + { + public: + static bool + Get(const ConstString &type, SummaryFormat::SharedPointer &entry); + + static void + Add(const ConstString &type, const SummaryFormat::SharedPointer &entry); + + static bool + Delete(const ConstString &type); + + static void + Clear(); + + static void + LoopThrough(SummaryFormat::SummaryCallback callback, void* callback_baton); + + static uint32_t + GetCurrentRevision(); + + static uint32_t + GetCount(); + }; + + class Categories + { + public: + + static bool + Get(const ConstString &category, lldb::FormatCategorySP &entry); + + static void + Add(const ConstString &category); + + static bool + Delete(const ConstString &category); + + static void + Clear(); + + static void + Clear(ConstString &category); + + static void + Enable(ConstString& category); + + static void + Disable(ConstString& category); + + static void + LoopThrough(FormatManager::CategoryCallback callback, void* callback_baton); + + static uint32_t + GetCurrentRevision(); + + static uint32_t + GetCount(); + }; }; }; diff --git a/lldb/include/lldb/Core/FormatManager.h b/lldb/include/lldb/Core/FormatManager.h index 42579fc6b1c..69bc63a3fb3 100644 --- a/lldb/include/lldb/Core/FormatManager.h +++ b/lldb/include/lldb/Core/FormatManager.h @@ -29,6 +29,7 @@ namespace std #include <hash_map> #endif +#include <list> #include <map> #include <stack> @@ -152,20 +153,24 @@ struct SummaryFormat bool m_show_members_oneliner; bool m_is_system; + uint32_t m_priority; + SummaryFormat(bool casc = false, bool skipptr = false, bool skipref = false, bool nochildren = true, bool novalue = true, bool oneliner = false, - bool system = false) : + bool system = false, + uint32_t priority = 2) : m_cascades(casc), m_skip_pointers(skipptr), m_skip_references(skipref), m_dont_show_children(nochildren), m_dont_show_value(novalue), m_show_members_oneliner(oneliner), - m_is_system(system) + m_is_system(system), + m_priority(priority) { } @@ -209,6 +214,18 @@ struct SummaryFormat return m_is_system; } + uint32_t + GetPriority() const + { + return m_priority; + } + + void + SetPriority(uint32_t newprio) + { + m_priority = newprio; + } + virtual ~SummaryFormat() { @@ -238,8 +255,9 @@ struct StringSummaryFormat : public SummaryFormat bool novalue = true, bool oneliner = false, bool system = false, - std::string f = "") : - SummaryFormat(casc,skipptr,skipref,nochildren,novalue,oneliner,system), + std::string f = "", + uint32_t priority = 2) : + SummaryFormat(casc,skipptr,skipref,nochildren,novalue,oneliner,system, priority), m_format(f) { } @@ -289,8 +307,9 @@ struct ScriptSummaryFormat : public SummaryFormat bool oneliner = false, bool system = false, std::string fname = "", - std::string pscri = "") : - SummaryFormat(casc,skipptr,skipref,nochildren,novalue,oneliner,system), + std::string pscri = "", + uint32_t priority = 2) : + SummaryFormat(casc,skipptr,skipref,nochildren,novalue,oneliner,system,priority), m_function_name(fname), m_python_script(pscri) { @@ -422,6 +441,8 @@ struct ScriptFormat template<typename KeyType, typename ValueType> class FormatNavigator; +class FormatManager; + template<typename KeyType, typename ValueType> class FormatMap { @@ -431,6 +452,7 @@ private: IFormatChangeListener* listener; friend class FormatNavigator<KeyType, ValueType>; + friend class FormatManager; public: typedef std::map<KeyType, ValueSP> MapType; @@ -528,6 +550,8 @@ public: }; +class FormatCategory; + template<typename KeyType, typename ValueType> class FormatNavigator { @@ -542,6 +566,10 @@ public: typedef typename MapType::key_type MapKeyType; typedef typename MapType::mapped_type MapValueType; typedef typename BackEndType::CallbackType CallbackType; + + typedef typename lldb::SharedPtr<FormatNavigator<KeyType, ValueType> >::Type SharedPointer; + + friend class FormatCategory; FormatNavigator(IFormatChangeListener* lst = NULL) : m_format_map(lst) @@ -561,16 +589,21 @@ public: { return m_format_map.Delete(type); } - + bool - Get(ValueObject& vobj, MapValueType& entry) + Get(ValueObject& vobj, + MapValueType& entry, + uint32_t* why = NULL) { + uint32_t value = lldb::eFormatterDirectChoice; clang::QualType type = clang::QualType::getFromOpaquePtr(vobj.GetClangType()); - bool ret = Get(vobj, type, entry); - if(ret) + bool ret = Get(vobj, type, entry, value); + if (ret) entry = MapValueType(entry); else - entry = MapValueType(); + entry = MapValueType(); + if (why) + *why = value; return ret; } @@ -591,7 +624,7 @@ public: { return m_format_map.GetCount(); } - + private: DISALLOW_COPY_AND_ASSIGN(FormatNavigator); @@ -606,7 +639,8 @@ private: bool Get(ValueObject& vobj, clang::QualType type, - MapValueType& entry) + MapValueType& entry, + uint32_t& reason) { if (type.isNull()) return false; @@ -629,13 +663,19 @@ private: // look for a "base type", whatever that means if (typePtr->isReferenceType()) { - if (Get(vobj,type.getNonReferenceType(),entry) && !entry->m_skip_references) + if (Get(vobj,type.getNonReferenceType(),entry, reason) && !entry->m_skip_references) + { + reason |= lldb::eFormatterStrippedPointerReference; return true; + } } if (typePtr->isPointerType()) { - if (Get(vobj, typePtr->getPointeeType(), entry) && !entry->m_skip_pointers) + if (Get(vobj, typePtr->getPointeeType(), entry, reason) && !entry->m_skip_pointers) + { + reason |= lldb::eFormatterStrippedPointerReference; return true; + } } if (typePtr->isObjCObjectPointerType()) { @@ -649,8 +689,11 @@ private: ValueObject* target = vobj.Dereference(error).get(); if(error.Fail() || !target) return false; - if (Get(*target, typePtr->getPointeeType(), entry) && !entry->m_skip_pointers) + if (Get(*target, typePtr->getPointeeType(), entry, reason) && !entry->m_skip_pointers) + { + reason |= lldb::eFormatterStrippedPointerReference; return true; + } } const clang::ObjCObjectType *objc_class_type = typePtr->getAs<clang::ObjCObjectType>(); if (objc_class_type) @@ -669,8 +712,11 @@ private: { //printf("the end is here\n"); clang::QualType ivar_qual_type(ast->getObjCInterfaceType(superclass_interface_decl)); - if (Get(vobj, ivar_qual_type, entry) && entry->m_cascades) + if (Get(vobj, ivar_qual_type, entry, reason) && entry->m_cascades) + { + reason |= lldb::eFormatterNavigatedBaseClasses; return true; + } } } } @@ -691,8 +737,11 @@ private: end = record->bases_end(); for (pos = record->bases_begin(); pos != end; pos++) { - if((Get(vobj, pos->getType(), entry)) && entry->m_cascades) - return true; // if it does not cascade, just move on to other base classes which might + if((Get(vobj, pos->getType(), entry, reason)) && entry->m_cascades) + { + reason |= lldb::eFormatterNavigatedBaseClasses; + return true; + } } } if (record->getNumVBases() > 0) @@ -700,8 +749,11 @@ private: end = record->vbases_end(); for (pos = record->vbases_begin(); pos != end; pos++) { - if((Get(vobj, pos->getType(), entry)) && entry->m_cascades) + if((Get(vobj, pos->getType(), entry, reason)) && entry->m_cascades) + { + reason |= lldb::eFormatterNavigatedBaseClasses; return true; + } } } } @@ -711,8 +763,11 @@ private: const clang::TypedefType* type_tdef = type->getAs<clang::TypedefType>(); if (type_tdef) { - if ((Get(vobj, type_tdef->getDecl()->getUnderlyingType(), entry)) && entry->m_cascades) + if ((Get(vobj, type_tdef->getDecl()->getUnderlyingType(), entry, reason)) && entry->m_cascades) + { + reason |= lldb::eFormatterNavigatedTypedefs; return true; + } } return false; } @@ -726,42 +781,194 @@ template<> bool FormatNavigator<lldb::RegularExpressionSP, SummaryFormat>::Delete(const char* type); -class FormatManager : public IFormatChangeListener +class FormatCategory { private: - - typedef FormatNavigator<const char*, ValueFormat> ValueNavigator; typedef FormatNavigator<const char*, SummaryFormat> SummaryNavigator; typedef FormatNavigator<lldb::RegularExpressionSP, SummaryFormat> RegexSummaryNavigator; - typedef FormatNavigator<const char*, SummaryFormat> ScriptNavigator; - typedef ValueNavigator::MapType ValueMap; typedef SummaryNavigator::MapType SummaryMap; typedef RegexSummaryNavigator::MapType RegexSummaryMap; + + SummaryNavigator::SharedPointer m_summary_nav; + RegexSummaryNavigator::SharedPointer m_regex_summary_nav; + + bool m_enabled; + + IFormatChangeListener* m_change_listener; + + Mutex m_mutex; + +public: + + typedef SummaryNavigator::SharedPointer SummaryNavigatorSP; + typedef RegexSummaryNavigator::SharedPointer RegexSummaryNavigatorSP; + + FormatCategory(IFormatChangeListener* clist) : + m_summary_nav(new SummaryNavigator(clist)), + m_regex_summary_nav(new RegexSummaryNavigator(clist)), + m_enabled(false), + m_change_listener(clist), + m_mutex(Mutex::eMutexTypeRecursive) + {} + + SummaryNavigatorSP + Summary() + { + return SummaryNavigatorSP(m_summary_nav); + } + + RegexSummaryNavigatorSP + RegexSummary() + { + return RegexSummaryNavigatorSP(m_regex_summary_nav); + } + + bool + IsEnabled() const + { + return m_enabled; + } + + void + Enable(bool value = true) + { + Mutex::Locker(m_mutex); + m_enabled = value; + if(m_change_listener) + m_change_listener->Changed(); + } + + void + Disable() + { + Enable(false); + } + + bool + Get(ValueObject& vobj, + lldb::SummaryFormatSP& entry, + uint32_t* reason = NULL) + { + if (!IsEnabled()) + return false; + if (Summary()->Get(vobj, entry, reason)) + return true; + bool regex = RegexSummary()->Get(vobj, entry, reason); + if (regex && reason) + *reason |= lldb::eFormatterRegularExpressionSummary; // penalize regex summaries over normal ones + return regex; + } + + void + Clear() + { + m_summary_nav->Clear(); + m_regex_summary_nav->Clear(); + } + + bool + Delete(const char* name) + { + bool del_sum = m_summary_nav->Delete(name); + bool del_rex = m_regex_summary_nav->Delete(name); + + return (del_sum || del_rex); + } + + void + ChooseAsPreferential(const char* name); + + typedef lldb::SharedPtr<FormatCategory>::Type SharedPointer; +}; + +class FormatManager : public IFormatChangeListener +{ +private: + + typedef FormatNavigator<const char*, ValueFormat> ValueNavigator; + + typedef FormatMap<const char*, FormatCategory> CategoryMap; + + typedef ValueNavigator::MapType ValueMap; typedef FormatMap<const char*, SummaryFormat> NamedSummariesMap; - typedef ScriptNavigator::MapType ScriptMap; + + typedef std::list<FormatCategory::SharedPointer> ActiveCategoriesList; + + typedef ActiveCategoriesList::iterator ActiveCategoriesIterator; ValueNavigator m_value_nav; - SummaryNavigator m_summary_nav; - SummaryNavigator m_system_summary_nav; - RegexSummaryNavigator m_regex_summary_nav; - RegexSummaryNavigator m_system_regex_summary_nav; - NamedSummariesMap m_named_summaries_map; - uint32_t m_last_revision; + CategoryMap m_categories_map; + ActiveCategoriesList m_active_categories; + + const char* m_default_category_name; + const char* m_system_category_name; + + typedef CategoryMap::MapType::iterator CategoryMapIterator; -public: + bool + Get_ExactMatch(ValueObject& vobj, + lldb::SummaryFormatSP& entry) + { + ActiveCategoriesIterator begin, end = m_active_categories.end(); + + SummaryFormat::SharedPointer current_category_pick; + uint32_t reason_to_pick_current; + + for (begin = m_active_categories.begin(); begin != end; begin++) + { + FormatCategory::SharedPointer category = *begin; + if ( category->Get(vobj, current_category_pick, &reason_to_pick_current) && reason_to_pick_current == lldb::eFormatterDirectChoice ) + { + entry = SummaryFormat::SharedPointer(current_category_pick); + return true; + } + } + return false; + } + bool + Get_AnyMatch(ValueObject& vobj, + lldb::SummaryFormatSP& entry) + { + ActiveCategoriesIterator begin, end = m_active_categories.end(); + + SummaryFormat::SharedPointer current_category_pick; + + for (begin = m_active_categories.begin(); begin != end; begin++) + { + FormatCategory::SharedPointer category = *begin; + if ( category->Get(vobj, current_category_pick, NULL) ) + { + entry = SummaryFormat::SharedPointer(current_category_pick); + return true; + } + } + return false; + } + +public: + + typedef bool (*CategoryCallback)(void*, const char*, const FormatCategory::SharedPointer&); + FormatManager() : m_value_nav(this), - m_summary_nav(this), - m_system_summary_nav(this), - m_regex_summary_nav(this), - m_system_regex_summary_nav(this), m_named_summaries_map(this), - m_last_revision(0) + m_last_revision(0), + m_categories_map(this), + m_active_categories() { + + // build default categories + + m_default_category_name = ConstString("default").GetCString(); + m_system_category_name = ConstString("system").GetCString(); + + Category(m_default_category_name)->Enable(); + Category(m_system_category_name)->Enable(); + // add some default stuff // most formats, summaries, ... actually belong to the users' lldbinit file rather than here SummaryFormat::SharedPointer string_format(new StringSummaryFormat(false, @@ -771,34 +978,119 @@ public: false, false, true, - "${var%s}")); + "${var%s}", + 1)); SummaryFormat::SharedPointer string_array_format(new StringSummaryFormat(false, - true, - false, - false, - false, - false, - true, - "${var%s}")); + true, + false, + false, + false, + false, + true, + "${var%s}", + 1)); lldb::RegularExpressionSP any_size_char_arr(new RegularExpression("char \\[[0-9]+\\]")); - - SystemSummary().Add(ConstString("char *").GetCString(), string_format); - SystemSummary().Add(ConstString("const char *").GetCString(), string_format); - SystemRegexSummary().Add(any_size_char_arr, string_array_format); + + Summary(m_system_category_name)->Add(ConstString("char *").GetCString(), string_format); + Summary(m_system_category_name)->Add(ConstString("const char *").GetCString(), string_format); + RegexSummary(m_system_category_name)->Add(any_size_char_arr, string_array_format); + + m_active_categories.push_front(Category(m_system_category_name)); + m_active_categories.push_front(Category(m_default_category_name)); + } - + + CategoryMap& Categories() { return m_categories_map; } ValueNavigator& Value() { return m_value_nav; } - SummaryNavigator& Summary() { return m_summary_nav; } - SummaryNavigator& SystemSummary() { return m_system_summary_nav; } - RegexSummaryNavigator& RegexSummary() { return m_regex_summary_nav; } - RegexSummaryNavigator& SystemRegexSummary() { return m_system_regex_summary_nav; } NamedSummariesMap& NamedSummary() { return m_named_summaries_map; } + + void + EnableCategory(const char* category_name) + { + Category(category_name)->Enable(); + m_active_categories.push_front(Category(category_name)); + } + + class delete_matching_categories + { + FormatCategory::SharedPointer ptr; + public: + delete_matching_categories(FormatCategory::SharedPointer p) : ptr(p) + {} + + bool operator()(const FormatCategory::SharedPointer& other) + { + return ptr.get() == other.get(); + } + }; + + void + DisableCategory(const char* category_name) + { + Category(category_name)->Disable(); + m_active_categories.remove_if(delete_matching_categories(Category(category_name))); + } + void + LoopThroughCategories(CategoryCallback callback, void* param) + { + CategoryMapIterator begin, end = m_categories_map.m_map.end(); + + for (begin = m_categories_map.m_map.begin(); begin != end; begin++) + { + if (!callback(param, begin->first, begin->second)) + return; + } + } + + FormatCategory::SummaryNavigatorSP + Summary(const char* category_name = NULL) + { + if (!category_name) + return Summary(m_default_category_name); + lldb::FormatCategorySP category; + if (m_categories_map.Get(category_name, category)) + return category->Summary(); + return FormatCategory::SummaryNavigatorSP(); + } + + FormatCategory::RegexSummaryNavigatorSP + RegexSummary(const char* category_name = NULL) + { + if (!category_name) + return RegexSummary(m_default_category_name); + lldb::FormatCategorySP category; + if (m_categories_map.Get(category_name, category)) + return category->RegexSummary(); + return FormatCategory::RegexSummaryNavigatorSP(); + } + + lldb::FormatCategorySP + Category(const char* category_name = NULL) + { + if (!category_name) + return Category(m_default_category_name); + lldb::FormatCategorySP category; + if (m_categories_map.Get(category_name, category)) + return category; + Categories().Add(category_name,lldb::FormatCategorySP(new FormatCategory(this))); + return Category(category_name); + } + + bool + Get(ValueObject& vobj, + lldb::SummaryFormatSP& entry) + { + if ( Get_ExactMatch(vobj,entry) ) + return true; + return Get_AnyMatch(vobj,entry); + } + static bool GetFormatFromCString (const char *format_cstr, bool partial_match_ok, diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h index 34e2a805734..a631a215fd8 100644 --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -490,6 +490,20 @@ namespace lldb { eFunctionNameTypeSelector = (1u << 5) // Find function by selector name (ObjC) names } FunctionNameType; + // this enum determines how a FormatNavigator picked a specific format for a datatype + // these values can be used together (e.g. eFormatterStrippedPointerReference | eFormatterNavigatedBaseClasses + // if you went from DerivedType& to BaseType to find a valid format). the priority rules are embedded in the + // ordering of these values (i.e. if you want to make a choice look really bad, give it a high value in this + // enum). eFormatterDirectChoice should always be left at 0 because it's our favorite choice all the time + typedef enum FormatterChoiceCriterion + { + eFormatterDirectChoice = 0x00000000, + eFormatterStrippedPointerReference = 0x00000001, + eFormatterNavigatedTypedefs = 0x00000002, + eFormatterNavigatedBaseClasses = 0x00000004, + eFormatterRegularExpressionSummary = 0x00000004 + } FormatterChoiceCriterion; + } // namespace lldb diff --git a/lldb/include/lldb/lldb-forward-rtti.h b/lldb/include/lldb/lldb-forward-rtti.h index 858e521ebd9..e07771a8cb2 100644 --- a/lldb/include/lldb/lldb-forward-rtti.h +++ b/lldb/include/lldb/lldb-forward-rtti.h @@ -38,6 +38,7 @@ namespace lldb { typedef SharedPtr<lldb_private::Disassembler>::Type DisassemblerSP; typedef SharedPtr<lldb_private::DynamicLoader>::Type DynamicLoaderSP; typedef SharedPtr<lldb_private::Event>::Type EventSP; + typedef SharedPtr<lldb_private::FormatCategory>::Type FormatCategorySP; typedef SharedPtr<lldb_private::Function>::Type FunctionSP; typedef SharedPtr<lldb_private::InlineFunctionInfo>::Type InlineFunctionInfoSP; typedef SharedPtr<lldb_private::InputReader>::Type InputReaderSP; diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index c476a1d01c8..4e4938bca7c 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -76,6 +76,7 @@ class ExecutionContextScope; class FileSpec; class FileSpecList; class Flags; +class FormatCategory; class FormatManager; class FuncUnwinders; class Function; diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp index e99c1e09fd0..12670a1e9e5 100644 --- a/lldb/source/Commands/CommandObjectFrame.cpp +++ b/lldb/source/Commands/CommandObjectFrame.cpp @@ -442,7 +442,7 @@ public: SummaryFormatSP summary_format_sp; if (!m_option_variable.summary.empty()) - Debugger::NamedSummaryFormats::Get(ConstString(m_option_variable.summary.c_str()), summary_format_sp); + Debugger::Formatting::NamedSummaryFormats::Get(ConstString(m_option_variable.summary.c_str()), summary_format_sp); if (variable_list) { diff --git a/lldb/source/Commands/CommandObjectType.cpp b/lldb/source/Commands/CommandObjectType.cpp index d408a603e85..8db88e759ed 100644 --- a/lldb/source/Commands/CommandObjectType.cpp +++ b/lldb/source/Commands/CommandObjectType.cpp @@ -196,7 +196,7 @@ public: const char* typeA = command.GetArgumentAtIndex(i); ConstString typeCS(typeA); if (typeCS) - Debugger::ValueFormats::Add(typeCS, entry); + Debugger::Formatting::ValueFormats::Add(typeCS, entry); else { result.AppendError("empty typenames not allowed"); @@ -273,7 +273,7 @@ public: } - if (Debugger::ValueFormats::Delete(typeCS)) + if (Debugger::Formatting::ValueFormats::Delete(typeCS)) { result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); @@ -311,7 +311,7 @@ public: bool Execute (Args& command, CommandReturnObject &result) { - Debugger::ValueFormats::Clear(); + Debugger::Formatting::ValueFormats::Clear(); result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } @@ -372,7 +372,7 @@ public: } else param = new CommandObjectTypeFormatList_LoopCallbackParam(this,&result); - Debugger::ValueFormats::LoopThrough(CommandObjectTypeFormatList_LoopCallback, param); + Debugger::Formatting::ValueFormats::LoopThrough(CommandObjectTypeFormatList_LoopCallback, param); delete param; result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); @@ -549,7 +549,7 @@ public: CommandObjectTypeSummaryAdd::AddSummary(ConstString(type_name), script_format, (options->m_regex ? CommandObjectTypeSummaryAdd::eRegexSummary : CommandObjectTypeSummaryAdd::eRegularSummary), - options->m_is_system, + options->m_category, &error); if (error.Fail()) { @@ -566,7 +566,7 @@ public: CommandObjectTypeSummaryAdd::AddSummary(*(options->m_name), script_format, CommandObjectTypeSummaryAdd::eNamedSummary, - options->m_is_system, + options->m_category, &error); if (error.Fail()) { @@ -635,7 +635,7 @@ CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue (uint32_t option_idx m_is_add_script = true; break; case 'w': - m_is_system = true; + m_category = ConstString(option_arg).GetCString(); break; default: error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option); @@ -660,6 +660,7 @@ CommandObjectTypeSummaryAdd::CommandOptions::OptionParsingStarting () m_python_function = ""; m_is_add_script = false; m_is_system = false; + m_category = NULL; } void @@ -786,7 +787,8 @@ CommandObjectTypeSummaryAdd::Execute_ScriptSummary (Args& command, CommandReturn m_options.m_one_liner, m_options.m_regex, m_options.m_is_system, - m_options.m_name); + m_options.m_name, + m_options.m_category); for(int i = 0; i < argc; i++) { const char* typeA = command.GetArgumentAtIndex(i); @@ -815,7 +817,7 @@ CommandObjectTypeSummaryAdd::Execute_ScriptSummary (Args& command, CommandReturn CommandObjectTypeSummaryAdd::AddSummary(ConstString(type_name), script_format, (m_options.m_regex ? eRegexSummary : eRegularSummary), - m_options.m_is_system, + m_options.m_category, &error); if (error.Fail()) { @@ -829,7 +831,7 @@ CommandObjectTypeSummaryAdd::Execute_ScriptSummary (Args& command, CommandReturn { if ( (bool)(*(m_options.m_name)) ) { - AddSummary(*(m_options.m_name), script_format, eNamedSummary, m_options.m_is_system, &error); + AddSummary(*(m_options.m_name), script_format, eNamedSummary, m_options.m_category, &error); if (error.Fail()) { result.AppendError(error.AsCString()); @@ -903,7 +905,7 @@ CommandObjectTypeSummaryAdd::Execute_StringSummary (Args& command, CommandReturn AddSummary(typeCS, entry, (m_options.m_regex ? eRegexSummary : eRegularSummary), - m_options.m_is_system, + m_options.m_category, &error); if (error.Fail()) @@ -918,7 +920,7 @@ CommandObjectTypeSummaryAdd::Execute_StringSummary (Args& command, CommandReturn { if ( (bool)(*(m_options.m_name)) ) { - AddSummary(*(m_options.m_name), entry, eNamedSummary, m_options.m_is_system, &error); + AddSummary(*(m_options.m_name), entry, eNamedSummary, m_options.m_category, &error); if (error.Fail()) { result.AppendError(error.AsCString()); @@ -1037,7 +1039,7 @@ bool CommandObjectTypeSummaryAdd::AddSummary(const ConstString& type_name, SummaryFormatSP entry, SummaryFormatType type, - bool is_system, + const char* category, Error* error) { if (type == eRegexSummary) @@ -1050,30 +1052,20 @@ CommandObjectTypeSummaryAdd::AddSummary(const ConstString& type_name, return false; } - if (!is_system) - { - Debugger::RegexSummaryFormats::Delete(type_name); - Debugger::RegexSummaryFormats::Add(typeRX, entry); - } - else - { - Debugger::SystemRegexSummaryFormats::Delete(type_name); - Debugger::SystemRegexSummaryFormats::Add(typeRX, entry); - } + Debugger::Formatting::SummaryFormats(category)->RegexSummary()->Delete(type_name.GetCString()); + Debugger::Formatting::SummaryFormats(category)->RegexSummary()->Add(typeRX, entry); + return true; } else if (type == eNamedSummary) { // system named summaries do not exist (yet?) - Debugger::NamedSummaryFormats::Add(type_name,entry); + Debugger::Formatting::NamedSummaryFormats::Add(type_name,entry); return true; } else { - if (!is_system) - Debugger::SummaryFormats::Add(type_name,entry); - else - Debugger::SystemSummaryFormats::Add(type_name,entry); + Debugger::Formatting::SummaryFormats(category)->Summary()->Add(type_name.GetCString(), entry); return true; } } @@ -1081,7 +1073,7 @@ CommandObjectTypeSummaryAdd::AddSummary(const ConstString& type_name, OptionDefinition CommandObjectTypeSummaryAdd::CommandOptions::g_option_table[] = { - { LLDB_OPT_SET_ALL, false, "system", 'w', no_argument, NULL, 0, eArgTypeBoolean, "This is a system summary (makes it harder to delete it by accident)."}, + { LLDB_OPT_SET_ALL, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."}, { LLDB_OPT_SET_ALL, false, "cascade", 'C', required_argument, NULL, 0, eArgTypeBoolean, "If true, cascade to derived typedefs."}, { LLDB_OPT_SET_ALL, false, "no-value", 'v', no_argument, NULL, 0, eArgTypeBoolean, "Don't show the value, just show the summary, for this type."}, { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', no_argument, NULL, 0, eArgTypeBoolean, "Don't use this format for pointers-to-type objects."}, @@ -1126,7 +1118,10 @@ private: switch (short_option) { case 'a': - m_delete_system = true; + m_delete_all = true; + break; + case 'w': + m_category = ConstString(option_arg).GetCString(); break; default: error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option); @@ -1139,7 +1134,8 @@ private: void OptionParsingStarting () { - m_delete_system = false; + m_delete_all = false; + m_category = NULL; } const OptionDefinition* @@ -1154,7 +1150,9 @@ private: // Instance variables to hold the values for command options. - bool m_delete_system; + bool m_delete_all; + const char* m_category; + }; CommandOptions m_options; @@ -1164,6 +1162,17 @@ private: { return &m_options; } + + static bool + PerCategoryCallback(void* param, + const char* cate_name, + const FormatCategory::SharedPointer& cate) + { + const char* name = (const char*)param; + cate->Summary()->Delete(name); + cate->RegexSummary()->Delete(name); + return true; + } public: CommandObjectTypeSummaryDelete (CommandInterpreter &interpreter) : @@ -1210,13 +1219,17 @@ public: return false; } - bool delete_summary = Debugger::SummaryFormats::Delete(typeCS); - bool delete_regex = Debugger::RegexSummaryFormats::Delete(typeCS); - bool delete_named = Debugger::NamedSummaryFormats::Delete(typeCS); - bool delete_sys = m_options.m_delete_system ? Debugger::SystemSummaryFormats::Delete(typeCS) : false; - bool delete_sys_regex = m_options.m_delete_system ? Debugger::SystemRegexSummaryFormats::Delete(typeCS) : false; + if (m_options.m_delete_all) + { + Debugger::Formatting::Categories::LoopThrough(PerCategoryCallback, (void*)typeCS.GetCString()); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return result.Succeeded(); + } - if (delete_summary || delete_regex || delete_named || delete_sys || delete_sys_regex) + bool delete_category = Debugger::Formatting::SummaryFormats(m_options.m_category)->Delete(typeCS.GetCString()); + bool delete_named = Debugger::Formatting::NamedSummaryFormats::Delete(typeCS); + + if (delete_category || delete_named) { result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); @@ -1234,14 +1247,11 @@ public: OptionDefinition CommandObjectTypeSummaryDelete::CommandOptions::g_option_table[] = { - { LLDB_OPT_SET_ALL, false, "all", 'a', no_argument, NULL, 0, eArgTypeBoolean, "Also delete system summaries (not recommended)."}, + { LLDB_OPT_SET_1, false, "all", 'a', no_argument, NULL, 0, eArgTypeBoolean, "Delete from every category."}, + { LLDB_OPT_SET_2, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Delete from given category."}, { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } }; -//------------------------------------------------------------------------- -// CommandObjectTypeSummaryClear -//------------------------------------------------------------------------- - class CommandObjectTypeSummaryClear : public CommandObject { private: @@ -1267,7 +1277,7 @@ private: switch (short_option) { case 'a': - m_delete_system = true; + m_delete_all = true; break; default: error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option); @@ -1280,7 +1290,7 @@ private: void OptionParsingStarting () { - m_delete_system = false; + m_delete_all = false; } const OptionDefinition* @@ -1295,7 +1305,8 @@ private: // Instance variables to hold the values for command options. - bool m_delete_system; + bool m_delete_all; + bool m_delete_named; }; CommandOptions m_options; @@ -1305,7 +1316,18 @@ private: { return &m_options; } - + + static bool + PerCategoryCallback(void* param, + const char* cate_name, + const FormatCategory::SharedPointer& cate) + { + cate->Summary()->Clear(); + cate->RegexSummary()->Clear(); + return true; + + } + public: CommandObjectTypeSummaryClear (CommandInterpreter &interpreter) : CommandObject (interpreter, @@ -1322,15 +1344,19 @@ public: bool Execute (Args& command, CommandReturnObject &result) { - Debugger::SummaryFormats::Clear(); - Debugger::RegexSummaryFormats::Clear(); - Debugger::NamedSummaryFormats::Clear(); - if (m_options.m_delete_system) + if (m_options.m_delete_all) + Debugger::Formatting::Categories::LoopThrough(PerCategoryCallback, NULL); + else if (command.GetArgumentCount() > 0) { - Debugger::SystemSummaryFormats::Clear(); - Debugger::SystemRegexSummaryFormats::Clear(); + const char* cat_name = command.GetArgumentAtIndex(0); + ConstString cat_nameCS(cat_name); + Debugger::Formatting::SummaryFormats(cat_nameCS.GetCString())->Clear(); } + else + Debugger::Formatting::SummaryFormats()->Clear(); + + Debugger::Formatting::NamedSummaryFormats::Clear(); result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); @@ -1341,7 +1367,7 @@ public: OptionDefinition CommandObjectTypeSummaryClear::CommandOptions::g_option_table[] = { - { LLDB_OPT_SET_ALL, false, "all", 'a', no_argument, NULL, 0, eArgTypeBoolean, "Also clear system summaries (not recommended)."}, + { LLDB_OPT_SET_ALL, false, "all", 'a', no_argument, NULL, 0, eArgTypeBoolean, "Clear every category."}, { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } }; @@ -1362,14 +1388,6 @@ struct CommandObjectTypeSummaryList_LoopCallbackParam { RegularExpression* X = NULL) : self(S), result(R), regex(X) {} }; -struct CommandObjectTypeRXSummaryList_LoopCallbackParam { - CommandObjectTypeSummaryList* self; - CommandReturnObject* result; - RegularExpression* regex; - CommandObjectTypeRXSummaryList_LoopCallbackParam(CommandObjectTypeSummaryList* S, CommandReturnObject* R, - RegularExpression* X = NULL) : self(S), result(R), regex(X) {} -}; - class CommandObjectTypeSummaryList : public CommandObject { public: @@ -1400,7 +1418,6 @@ public: const size_t argc = command.GetArgumentCount(); CommandObjectTypeSummaryList_LoopCallbackParam *param; - CommandObjectTypeRXSummaryList_LoopCallbackParam *rxparam; if (argc == 1) { RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0)); @@ -1409,26 +1426,10 @@ public: } else param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result); - Debugger::SummaryFormats::LoopThrough(CommandObjectTypeSummaryList_LoopCallback, param); - Debugger::SystemSummaryFormats::LoopThrough(CommandObjectTypeSummaryList_LoopCallback, param); - delete param; - - if (Debugger::RegexSummaryFormats::GetCount() > 0 || Debugger::SystemRegexSummaryFormats::GetCount() > 0 ) - { - result.GetOutputStream().Printf("Regex-based summaries (slower):\n"); - if (argc == 1) { - RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0)); - regex->Compile(command.GetArgumentAtIndex(0)); - rxparam = new CommandObjectTypeRXSummaryList_LoopCallbackParam(this,&result,regex); - } - else - rxparam = new CommandObjectTypeRXSummaryList_LoopCallbackParam(this,&result); - Debugger::RegexSummaryFormats::LoopThrough(CommandObjectTypeRXSummaryList_LoopCallback, rxparam); - Debugger::SystemRegexSummaryFormats::LoopThrough(CommandObjectTypeRXSummaryList_LoopCallback, rxparam); - delete rxparam; - } - if (Debugger::NamedSummaryFormats::GetCount() > 0) + Debugger::Formatting::Categories::LoopThrough(PerCategoryCallback,param); + + if (Debugger::Formatting::NamedSummaryFormats::GetCount() > 0) { result.GetOutputStream().Printf("Named summaries:\n"); if (argc == 1) { @@ -1438,7 +1439,7 @@ public: } else param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result); - Debugger::NamedSummaryFormats::LoopThrough(CommandObjectTypeSummaryList_LoopCallback, param); + Debugger::Formatting::NamedSummaryFormats::LoopThrough(CommandObjectTypeSummaryList_LoopCallback, param); delete param; } @@ -1448,6 +1449,28 @@ public: private: + static bool + PerCategoryCallback(void* param, + const char* cate_name, + const FormatCategory::SharedPointer& cate) + { + + CommandReturnObject* result = ((CommandObjectTypeSummaryList_LoopCallbackParam*)param)->result; + + result->GetOutputStream().Printf("-----------------------\nCategory: %s (%s)\n-----------------------\n", + cate_name, + (cate->IsEnabled() ? "enabled" : "disabled")); + + cate->Summary()->LoopThrough(CommandObjectTypeSummaryList_LoopCallback, param); + + if (cate->RegexSummary()->GetCount() > 0) + { + result->GetOutputStream().Printf("Regex-based summaries (slower):\n"); + cate->RegexSummary()->LoopThrough(CommandObjectTypeRXSummaryList_LoopCallback, param); + } + return true; + } + bool LoopCallback (const char* type, const SummaryFormat::SharedPointer& entry, @@ -1479,10 +1502,233 @@ CommandObjectTypeRXSummaryList_LoopCallback ( lldb::RegularExpressionSP regex, const SummaryFormat::SharedPointer& entry) { - CommandObjectTypeRXSummaryList_LoopCallbackParam* param = (CommandObjectTypeRXSummaryList_LoopCallbackParam*)pt2self; + CommandObjectTypeSummaryList_LoopCallbackParam* param = (CommandObjectTypeSummaryList_LoopCallbackParam*)pt2self; return param->self->LoopCallback(regex->GetText(), entry, param->regex, param->result); } +//------------------------------------------------------------------------- +// CommandObjectTypeCategoryEnable +//------------------------------------------------------------------------- + +class CommandObjectTypeCategoryEnable : public CommandObject +{ +public: + CommandObjectTypeCategoryEnable (CommandInterpreter &interpreter) : + CommandObject (interpreter, + "type category enable", + "Enable a category as a source of summaries.", + NULL) + { + CommandArgumentEntry type_arg; + CommandArgumentData type_style_arg; + + type_style_arg.arg_type = eArgTypeName; + type_style_arg.arg_repetition = eArgRepeatPlain; + + type_arg.push_back (type_style_arg); + + m_arguments.push_back (type_arg); + + } + + ~CommandObjectTypeCategoryEnable () + { + } + + bool + Execute (Args& command, CommandReturnObject &result) + { + const size_t argc = command.GetArgumentCount(); + + if (argc != 1) + { + result.AppendErrorWithFormat ("%s takes 1 arg.\n", m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + const char* typeA = command.GetArgumentAtIndex(0); + ConstString typeCS(typeA); + + if (!typeCS) + { + result.AppendError("empty category name not allowed"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + Debugger::Formatting::Categories::Enable(typeCS); + result.SetStatus(eReturnStatusSuccessFinishResult); + return result.Succeeded(); + } + +}; + +//------------------------------------------------------------------------- +// CommandObjectTypeCategoryDelete +//------------------------------------------------------------------------- + +class CommandObjectTypeCategoryDelete : public CommandObject +{ +public: + CommandObjectTypeCategoryDelete (CommandInterpreter &interpreter) : + CommandObject (interpreter, + "type category delete", + "Delete a category and all associated summaries.", + NULL) + { + CommandArgumentEntry type_arg; + CommandArgumentData type_style_arg; + + type_style_arg.arg_type = eArgTypeName; + type_style_arg.arg_repetition = eArgRepeatPlain; + + type_arg.push_back (type_style_arg); + + m_arguments.push_back (type_arg); + + } + + ~CommandObjectTypeCategoryDelete () + { + } + + bool + Execute (Args& command, CommandReturnObject &result) + { + const size_t argc = command.GetArgumentCount(); + + if (argc != 1) + { + result.AppendErrorWithFormat ("%s takes 1 arg.\n", m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + const char* typeA = command.GetArgumentAtIndex(0); + ConstString typeCS(typeA); + + if (!typeCS) + { + result.AppendError("empty category name not allowed"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + if (Debugger::Formatting::Categories::Delete(typeCS)) + { + result.SetStatus(eReturnStatusSuccessFinishResult); + return result.Succeeded(); + } + else + { + result.AppendErrorWithFormat ("cannot delete category %s.\n", typeA); + result.SetStatus(eReturnStatusFailed); + return false; + } + } + +}; + +//------------------------------------------------------------------------- +// CommandObjectTypeCategoryDisable +//------------------------------------------------------------------------- + +class CommandObjectTypeCategoryDisable : public CommandObject +{ +public: + CommandObjectTypeCategoryDisable (CommandInterpreter &interpreter) : + CommandObject (interpreter, + "type category disable", + "Disable a category as a source of summaries.", + NULL) + { + CommandArgumentEntry type_arg; + CommandArgumentData type_style_arg; + + type_style_arg.arg_type = eArgTypeName; + type_style_arg.arg_repetition = eArgRepeatPlain; + + type_arg.push_back (type_style_arg); + + m_arguments.push_back (type_arg); + + } + + ~CommandObjectTypeCategoryDisable () + { + } + + bool + Execute (Args& command, CommandReturnObject &result) + { + const size_t argc = command.GetArgumentCount(); + + if (argc != 1) + { + result.AppendErrorWithFormat ("%s takes 1 arg.\n", m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + const char* typeA = command.GetArgumentAtIndex(0); + ConstString typeCS(typeA); + + if (!typeCS) + { + result.AppendError("empty category name not allowed"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + Debugger::Formatting::Categories::Disable(typeCS); + result.SetStatus(eReturnStatusSuccessFinishResult); + return result.Succeeded(); + } + +}; + +//------------------------------------------------------------------------- +// CommandObjectTypeCategoryList +//------------------------------------------------------------------------- + +class CommandObjectTypeCategoryList : public CommandObject +{ +private: + static bool + PerCategoryCallback(void* param, + const char* cate_name, + const FormatCategory::SharedPointer& cate) + { + CommandReturnObject* result = (CommandReturnObject*)param; + result->GetOutputStream().Printf("Category %s is%s enabled\n", + cate_name, + (cate->IsEnabled() ? "" : " not")); + return true; + } +public: + CommandObjectTypeCategoryList (CommandInterpreter &interpreter) : + CommandObject (interpreter, + "type category list", + "Provide a list of all existing categories.", + NULL) + { + } + + ~CommandObjectTypeCategoryList () + { + } + + bool + Execute (Args& command, CommandReturnObject &result) + { + Debugger::Formatting::Categories::LoopThrough(PerCategoryCallback, (void*)&result); + result.SetStatus(eReturnStatusSuccessFinishResult); + return result.Succeeded(); + } + +}; + class CommandObjectTypeFormat : public CommandObjectMultiword { public: @@ -1504,6 +1750,27 @@ public: } }; +class CommandObjectTypeCategory : public CommandObjectMultiword +{ +public: + CommandObjectTypeCategory (CommandInterpreter &interpreter) : + CommandObjectMultiword (interpreter, + "type category", + "A set of commands for operating on categories", + "type category [<sub-command-options>] ") + { + LoadSubCommand ("enable", CommandObjectSP (new CommandObjectTypeCategoryEnable (interpreter))); + LoadSubCommand ("disable", CommandObjectSP (new CommandObjectTypeCategoryDisable (interpreter))); + LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeCategoryDelete (interpreter))); + LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeCategoryList (interpreter))); + } + + + ~CommandObjectTypeCategory () + { + } +}; + class CommandObjectTypeSummary : public CommandObjectMultiword { public: @@ -1535,6 +1802,7 @@ CommandObjectType::CommandObjectType (CommandInterpreter &interpreter) : "A set of commands for operating on the type system", "type [<sub-command-options>]") { + LoadSubCommand ("category", CommandObjectSP (new CommandObjectTypeCategory (interpreter))); LoadSubCommand ("format", CommandObjectSP (new CommandObjectTypeFormat (interpreter))); LoadSubCommand ("summary", CommandObjectSP (new CommandObjectTypeSummary (interpreter))); } diff --git a/lldb/source/Commands/CommandObjectType.h b/lldb/source/Commands/CommandObjectType.h index 0c453785e41..d9242879bea 100644 --- a/lldb/source/Commands/CommandObjectType.h +++ b/lldb/source/Commands/CommandObjectType.h @@ -43,6 +43,8 @@ public: ConstString* m_name; + const char* m_category; + ScriptAddOptions(bool sptr, bool sref, bool casc, @@ -51,7 +53,8 @@ public: bool onel, bool regx, bool syst, - ConstString* name) : + ConstString* name, + const char* catg) : m_skip_pointers(sptr), m_skip_references(sref), m_cascade(casc), @@ -62,7 +65,8 @@ public: m_one_liner(onel), m_regex(regx), m_is_system(syst), - m_name(name) + m_name(name), + m_category(catg) { } @@ -127,6 +131,7 @@ private: std::string m_python_function; bool m_is_add_script; bool m_is_system; + const char* m_category; }; CommandOptions m_options; @@ -169,7 +174,7 @@ public: AddSummary(const ConstString& type_name, lldb::SummaryFormatSP entry, SummaryFormatType type, - bool is_system, + const char* category, Error* error = NULL); }; diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index cde5da77d05..1c62a8cb46f 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -1714,253 +1714,175 @@ GetFormatManager() { } bool -Debugger::ValueFormats::Get(ValueObject& vobj, ValueFormat::SharedPointer &entry) +Debugger::Formatting::ValueFormats::Get(ValueObject& vobj, ValueFormat::SharedPointer &entry) { return GetFormatManager().Value().Get(vobj,entry); } void -Debugger::ValueFormats::Add(const ConstString &type, const ValueFormat::SharedPointer &entry) +Debugger::Formatting::ValueFormats::Add(const ConstString &type, const ValueFormat::SharedPointer &entry) { GetFormatManager().Value().Add(type.AsCString(),entry); } bool -Debugger::ValueFormats::Delete(const ConstString &type) +Debugger::Formatting::ValueFormats::Delete(const ConstString &type) { return GetFormatManager().Value().Delete(type.AsCString()); } void -Debugger::ValueFormats::Clear() +Debugger::Formatting::ValueFormats::Clear() { GetFormatManager().Value().Clear(); } void -Debugger::ValueFormats::LoopThrough(ValueFormat::ValueCallback callback, void* callback_baton) +Debugger::Formatting::ValueFormats::LoopThrough(ValueFormat::ValueCallback callback, void* callback_baton) { GetFormatManager().Value().LoopThrough(callback, callback_baton); } uint32_t -Debugger::ValueFormats::GetCurrentRevision() +Debugger::Formatting::ValueFormats::GetCurrentRevision() { return GetFormatManager().GetCurrentRevision(); } uint32_t -Debugger::ValueFormats::GetCount() +Debugger::Formatting::ValueFormats::GetCount() { return GetFormatManager().Value().GetCount(); } -bool -Debugger::SummaryFormats::Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry) -{ - return GetFormatManager().Summary().Get(vobj,entry); -} - -void -Debugger::SummaryFormats::Add(const ConstString &type, const SummaryFormat::SharedPointer &entry) -{ - GetFormatManager().Summary().Add(type.AsCString(),entry); -} - -bool -Debugger::SummaryFormats::Delete(const ConstString &type) -{ - return GetFormatManager().Summary().Delete(type.AsCString()); -} - -void -Debugger::SummaryFormats::Clear() -{ - GetFormatManager().Summary().Clear(); -} - -void -Debugger::SummaryFormats::LoopThrough(SummaryFormat::SummaryCallback callback, void* callback_baton) -{ - GetFormatManager().Summary().LoopThrough(callback, callback_baton); -} - -uint32_t -Debugger::SummaryFormats::GetCurrentRevision() -{ - return GetFormatManager().GetCurrentRevision(); -} - -uint32_t -Debugger::SummaryFormats::GetCount() +lldb::FormatCategorySP +Debugger::Formatting::SummaryFormats(const char* category_name) { - return GetFormatManager().Summary().GetCount(); + return GetFormatManager().Category(category_name); } bool -Debugger::SystemSummaryFormats::Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry) -{ - return GetFormatManager().SystemSummary().Get(vobj,entry); -} - -void -Debugger::SystemSummaryFormats::Add(const ConstString &type, const SummaryFormat::SharedPointer &entry) -{ - GetFormatManager().SystemSummary().Add(type.AsCString(),entry); -} - -bool -Debugger::SystemSummaryFormats::Delete(const ConstString &type) -{ - return GetFormatManager().SystemSummary().Delete(type.AsCString()); -} - -void -Debugger::SystemSummaryFormats::Clear() +Debugger::Formatting::GetSummaryFormat(ValueObject& vobj, + lldb::SummaryFormatSP& entry) { - GetFormatManager().SystemSummary().Clear(); -} - -void -Debugger::SystemSummaryFormats::LoopThrough(SummaryFormat::SummaryCallback callback, void* callback_baton) -{ - GetFormatManager().SystemSummary().LoopThrough(callback, callback_baton); -} - -uint32_t -Debugger::SystemSummaryFormats::GetCurrentRevision() -{ - return GetFormatManager().GetCurrentRevision(); -} - -uint32_t -Debugger::SystemSummaryFormats::GetCount() -{ - return GetFormatManager().SystemSummary().GetCount(); + return GetFormatManager().Get(vobj, entry); } bool -Debugger::RegexSummaryFormats::Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry) +Debugger::Formatting::Categories::Get(const ConstString &category, lldb::FormatCategorySP &entry) { - return GetFormatManager().RegexSummary().Get(vobj,entry); + entry = GetFormatManager().Category(category.GetCString()); + return true; } void -Debugger::RegexSummaryFormats::Add(const lldb::RegularExpressionSP &type, const SummaryFormat::SharedPointer &entry) +Debugger::Formatting::Categories::Add(const ConstString &category) { - GetFormatManager().RegexSummary().Add(type,entry); + GetFormatManager().Category(category.GetCString()); } bool -Debugger::RegexSummaryFormats::Delete(const ConstString &type) +Debugger::Formatting::Categories::Delete(const ConstString &category) { - return GetFormatManager().RegexSummary().Delete(type.AsCString()); + GetFormatManager().DisableCategory(category.GetCString()); + return GetFormatManager().Categories().Delete(category.GetCString()); } void -Debugger::RegexSummaryFormats::Clear() +Debugger::Formatting::Categories::Clear() { - GetFormatManager().RegexSummary().Clear(); + GetFormatManager().Categories().Clear(); } void -Debugger::RegexSummaryFormats::LoopThrough(SummaryFormat::RegexSummaryCallback callback, void* callback_baton) -{ - GetFormatManager().RegexSummary().LoopThrough(callback, callback_baton); -} - -uint32_t -Debugger::RegexSummaryFormats::GetCurrentRevision() -{ - return GetFormatManager().GetCurrentRevision(); -} - -uint32_t -Debugger::RegexSummaryFormats::GetCount() -{ - return GetFormatManager().RegexSummary().GetCount(); -} - -bool -Debugger::SystemRegexSummaryFormats::Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry) +Debugger::Formatting::Categories::Clear(ConstString &category) { - return GetFormatManager().SystemRegexSummary().Get(vobj,entry); + GetFormatManager().Category(category.GetCString())->Clear(); } void -Debugger::SystemRegexSummaryFormats::Add(const lldb::RegularExpressionSP &type, const SummaryFormat::SharedPointer &entry) +Debugger::Formatting::Categories::Enable(ConstString& category) { - GetFormatManager().SystemRegexSummary().Add(type,entry); -} - -bool -Debugger::SystemRegexSummaryFormats::Delete(const ConstString &type) -{ - return GetFormatManager().SystemRegexSummary().Delete(type.AsCString()); + if (GetFormatManager().Category(category.GetCString())->IsEnabled() == false) + { + //GetFormatManager().Category(category.GetCString())->Enable(); + GetFormatManager().EnableCategory(category.GetCString()); + } + else + { + //GetFormatManager().Category(category.GetCString())->Disable(); + GetFormatManager().DisableCategory(category.GetCString()); + //GetFormatManager().Category(category.GetCString())->Enable(); + GetFormatManager().EnableCategory(category.GetCString()); + } } void -Debugger::SystemRegexSummaryFormats::Clear() +Debugger::Formatting::Categories::Disable(ConstString& category) { - GetFormatManager().SystemRegexSummary().Clear(); + if (GetFormatManager().Category(category.GetCString())->IsEnabled() == true) + { + //GetFormatManager().Category(category.GetCString())->Disable(); + GetFormatManager().DisableCategory(category.GetCString()); + } } void -Debugger::SystemRegexSummaryFormats::LoopThrough(SummaryFormat::RegexSummaryCallback callback, void* callback_baton) +Debugger::Formatting::Categories::LoopThrough(FormatManager::CategoryCallback callback, void* callback_baton) { - GetFormatManager().SystemRegexSummary().LoopThrough(callback, callback_baton); + GetFormatManager().LoopThroughCategories(callback, callback_baton); } uint32_t -Debugger::SystemRegexSummaryFormats::GetCurrentRevision() +Debugger::Formatting::Categories::GetCurrentRevision() { return GetFormatManager().GetCurrentRevision(); } uint32_t -Debugger::SystemRegexSummaryFormats::GetCount() +Debugger::Formatting::Categories::GetCount() { - return GetFormatManager().SystemRegexSummary().GetCount(); + return GetFormatManager().Categories().GetCount(); } bool -Debugger::NamedSummaryFormats::Get(const ConstString &type, SummaryFormat::SharedPointer &entry) +Debugger::Formatting::NamedSummaryFormats::Get(const ConstString &type, SummaryFormat::SharedPointer &entry) { return GetFormatManager().NamedSummary().Get(type.AsCString(),entry); } void -Debugger::NamedSummaryFormats::Add(const ConstString &type, const SummaryFormat::SharedPointer &entry) +Debugger::Formatting::NamedSummaryFormats::Add(const ConstString &type, const SummaryFormat::SharedPointer &entry) { GetFormatManager().NamedSummary().Add(type.AsCString(),entry); } bool -Debugger::NamedSummaryFormats::Delete(const ConstString &type) +Debugger::Formatting::NamedSummaryFormats::Delete(const ConstString &type) { return GetFormatManager().NamedSummary().Delete(type.AsCString()); } void -Debugger::NamedSummaryFormats::Clear() +Debugger::Formatting::NamedSummaryFormats::Clear() { GetFormatManager().NamedSummary().Clear(); } void -Debugger::NamedSummaryFormats::LoopThrough(SummaryFormat::SummaryCallback callback, void* callback_baton) +Debugger::Formatting::NamedSummaryFormats::LoopThrough(SummaryFormat::SummaryCallback callback, void* callback_baton) { GetFormatManager().NamedSummary().LoopThrough(callback, callback_baton); } uint32_t -Debugger::NamedSummaryFormats::GetCurrentRevision() +Debugger::Formatting::NamedSummaryFormats::GetCurrentRevision() { return GetFormatManager().GetCurrentRevision(); } uint32_t -Debugger::NamedSummaryFormats::GetCount() +Debugger::Formatting::NamedSummaryFormats::GetCount() { return GetFormatManager().NamedSummary().GetCount(); } diff --git a/lldb/source/Core/FormatManager.cpp b/lldb/source/Core/FormatManager.cpp index 7be3791adbb..2ce91aed8fd 100644 --- a/lldb/source/Core/FormatManager.cpp +++ b/lldb/source/Core/FormatManager.cpp @@ -184,6 +184,8 @@ FormatNavigator<lldb::RegularExpressionSP, SummaryFormat>::Delete(const char* ty if ( ::strcmp(type,regex->GetText()) == 0) { m_format_map.map().erase(pos); + if(m_format_map.listener) + m_format_map.listener->Changed(); return true; } } @@ -270,3 +272,23 @@ StringSummaryFormat::FormatObject(lldb::ValueObjectSP object) } } +void +FormatCategory::ChooseAsPreferential(const char* name) +{ + Mutex::Locker(m_mutex); + lldb::SummaryFormatSP format; + + uint32_t revision = Debugger::Formatting::ValueFormats::GetCurrentRevision(); + + if ( Summary()->Get(name, format) ) + format->SetPriority(revision); + + format.reset(); + + if ( RegexSummary()->Get(name, format) ) + format->SetPriority(revision); + + if(m_change_listener) + m_change_listener->Changed(); + +} diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index 4f0c8dc9069..fc89f0fd4a4 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -202,22 +202,21 @@ ValueObject::UpdateFormatsIfNeeded() ClearCustomSummaryFormat(); m_summary_str.clear(); } - if (m_last_format_mgr_revision != Debugger::ValueFormats::GetCurrentRevision()) + if (m_last_format_mgr_revision != Debugger::Formatting::ValueFormats::GetCurrentRevision()) { if (m_last_summary_format.get()) m_last_summary_format.reset((StringSummaryFormat*)NULL); if (m_last_value_format.get()) m_last_value_format.reset((ValueFormat*)NULL); - Debugger::ValueFormats::Get(*this, m_last_value_format); + Debugger::Formatting::ValueFormats::Get(*this, m_last_value_format); // to find a summary we look for a direct summary, then if there is none // we look for a regex summary. if there is none we look for a system // summary (direct), and if also that fails, we look for a system // regex summary - if (!Debugger::SummaryFormats::Get(*this, m_last_summary_format)) - if (!Debugger::RegexSummaryFormats::Get(*this, m_last_summary_format)) - if (!Debugger::SystemSummaryFormats::Get(*this, m_last_summary_format)) - Debugger::SystemRegexSummaryFormats::Get(*this, m_last_summary_format); - m_last_format_mgr_revision = Debugger::ValueFormats::GetCurrentRevision(); + + Debugger::Formatting::GetSummaryFormat(*this, m_last_summary_format); + + m_last_format_mgr_revision = Debugger::Formatting::ValueFormats::GetCurrentRevision(); ClearUserVisibleData(); } diff --git a/lldb/test/functionalities/data-formatter/data-formatter-categories/Makefile b/lldb/test/functionalities/data-formatter/data-formatter-categories/Makefile new file mode 100644 index 00000000000..314f1cb2f07 --- /dev/null +++ b/lldb/test/functionalities/data-formatter/data-formatter-categories/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +CXX_SOURCES := main.cpp + +include $(LEVEL)/Makefile.rules diff --git a/lldb/test/functionalities/data-formatter/data-formatter-categories/TestDataFormatterCategories.py b/lldb/test/functionalities/data-formatter/data-formatter-categories/TestDataFormatterCategories.py new file mode 100644 index 00000000000..266a12fdb5e --- /dev/null +++ b/lldb/test/functionalities/data-formatter/data-formatter-categories/TestDataFormatterCategories.py @@ -0,0 +1,252 @@ +""" +Test lldb data formatter subsystem. +""" + +import os, time +import unittest2 +import lldb +from lldbtest import * + +class DataFormatterTestCase(TestBase): + + mydir = os.path.join("functionalities", "data-formatter", "data-formatter-categories") + + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + def test_with_dsym_and_run_command(self): + """Test data formatter commands.""" + self.buildDsym() + self.data_formatter_commands() + + def test_with_dwarf_and_run_command(self): + """Test data formatter commands.""" + self.buildDwarf() + self.data_formatter_commands() + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line number to break at. + self.line = line_number('main.cpp', '// Set break point at this line.') + + def data_formatter_commands(self): + """Test that that file and class static variables display correctly.""" + self.runCmd("file a.out", 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 category delete Category1', check=False) + self.runCmd('type category delete Category2', check=False) + self.runCmd('type category delete NewCategory', check=False) + + # Execute the cleanup function during test case tear down. + self.addTearDownHook(cleanup) + + # Add a summary to a new category and check that it works + self.runCmd("type summary add Rectangle -f \"ARectangle\" -w NewCategory") + + self.expect("frame variable r1 r2 r3", matching=False, + substrs = ['r1 = ARectangle', + 'r2 = ARectangle', + 'r3 = ARectangle']) + + self.runCmd("type category enable NewCategory") + + self.expect("frame variable r1 r2 r3", matching=True, + substrs = ['r1 = ARectangle', + 'r2 = ARectangle', + 'r3 = ARectangle']) + + # Disable the category and check that the old stuff is there + self.runCmd("type category disable NewCategory") + + self.expect("frame variable r1 r2 r3", + substrs = ['r1 = {', + 'r2 = {', + 'r3 = {']) + + # Re-enable the category and check that it works + self.runCmd("type category enable NewCategory") + + self.expect("frame variable r1 r2 r3", + substrs = ['r1 = ARectangle', + 'r2 = ARectangle', + 'r3 = ARectangle']) + + # Delete the category and the old stuff should be there + self.runCmd("type category delete NewCategory") + + self.expect("frame variable r1 r2 r3", + substrs = ['r1 = {', + 'r2 = {', + 'r3 = {']) + + # Add summaries to two different categories and check that we can switch + self.runCmd("type summary add -f \"Width = ${var.w}, Height = ${var.h}\" Rectangle -w Category1") + self.runCmd("type summary add -s \"return 'Area = ' + str( int(valobj.GetChildMemberWithName('w').GetValue()) * int(valobj.GetChildMemberWithName('h').GetValue()) );\" Rectangle -w Category2") + + self.runCmd("type category enable Category2") + self.runCmd("type category enable Category1") + + self.expect("frame variable r1 r2 r3", + substrs = ['r1 = Width = ', + 'r2 = Width = ', + 'r3 = Width = ']) + + self.runCmd("type category disable Category1") + + self.expect("frame variable r1 r2 r3", + substrs = ['r1 = Area = ', + 'r2 = Area = ', + 'r3 = Area = ']) + + # switch again + + self.runCmd("type category enable Category1") + + self.expect("frame variable r1 r2 r3", + substrs = ['r1 = Width = ', + 'r2 = Width = ', + 'r3 = Width = ']) + + # Re-enable the category and show that the preference is persisted + self.runCmd("type category disable Category2") + self.runCmd("type category enable Category2") + + self.expect("frame variable r1 r2 r3", + substrs = ['r1 = Area = ', + 'r2 = Area = ', + 'r3 = Area = ']) + + # Now delete the favorite summary + self.runCmd("type summary delete Rectangle -w Category2") + + self.expect("frame variable r1 r2 r3", + substrs = ['r1 = Width = ', + 'r2 = Width = ', + 'r3 = Width = ']) + + # Delete the summary from the default category (that does not have it) + self.runCmd("type summary delete Rectangle", check=False) + + self.expect("frame variable r1 r2 r3", + substrs = ['r1 = Width = ', + 'r2 = Width = ', + 'r3 = Width = ']) + + # Now add another summary to another category and switch back and forth + self.runCmd("type category delete Category1") + self.runCmd("type category delete Category2") + + self.runCmd("type summary add Rectangle -f \"Category1\" -w Category1") + self.runCmd("type summary add Rectangle -f \"Category2\" -w Category2") + + self.runCmd("type category enable Category2") + self.runCmd("type category enable Category1") + + self.expect("frame variable r1 r2 r3", + substrs = ['r1 = Category1', + 'r2 = Category1', + 'r3 = Category1']) + + self.runCmd("type category disable Category1") + + self.expect("frame variable r1 r2 r3", + substrs = ['r1 = Category2', + 'r2 = Category2', + 'r3 = Category2']) + + self.runCmd("type category disable Category1") + self.runCmd("type category enable Category1") + + self.expect("frame variable r1 r2 r3", + substrs = ['r1 = Category1', + 'r2 = Category1', + 'r3 = Category1']) + + self.runCmd("type category delete Category1") + self.runCmd("type category delete Category2") + + self.expect("frame variable r1 r2 r3", + substrs = ['r1 = {', + 'r2 = {', + 'r3 = {']) + + # Check that multiple summaries can go into one category + self.runCmd("type summary add -f \"Width = ${var.w}, Height = ${var.h}\" Rectangle -w Category1") + self.runCmd("type summary add -f \"Radius = ${var.r}\" Circle -w Category1") + + self.runCmd("type category enable Category1") + + self.expect("frame variable r1 r2 r3", + substrs = ['r1 = Width = ', + 'r2 = Width = ', + 'r3 = Width = ']) + + self.expect("frame variable c1 c2 c3", + substrs = ['c1 = Radius = ', + 'c2 = Radius = ', + 'c3 = Radius = ']) + + self.runCmd("type summary delete Circle -w Category1") + + self.expect("frame variable c1 c2 c3", + substrs = ['c1 = {', + 'c2 = {', + 'c3 = {']) + + # Add a regex based summary to a category + self.runCmd("type summary add -f \"Radius = ${var.r}\" -x Circle -w Category1") + + self.expect("frame variable r1 r2 r3", + substrs = ['r1 = Width = ', + 'r2 = Width = ', + 'r3 = Width = ']) + + self.expect("frame variable c1 c2 c3", + substrs = ['c1 = Radius = ', + 'c2 = Radius = ', + 'c3 = Radius = ']) + + # Delete it + self.runCmd("type summary delete Circle -w Category1") + + self.expect("frame variable c1 c2 c3", + substrs = ['c1 = {', + 'c2 = {', + 'c3 = {']) + + # Change a summary inside a category and check that the change is reflected + self.runCmd("type summary add Circle -w Category1 -f \"summary1\"") + + self.expect("frame variable c1 c2 c3", + substrs = ['c1 = summary1', + 'c2 = summary1', + 'c3 = summary1']) + + self.runCmd("type summary add Circle -w Category1 -f \"summary2\"") + + self.expect("frame variable c1 c2 c3", + substrs = ['c1 = summary2', + 'c2 = summary2', + 'c3 = summary2']) + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/test/functionalities/data-formatter/data-formatter-categories/main.cpp b/lldb/test/functionalities/data-formatter/data-formatter-categories/main.cpp new file mode 100644 index 00000000000..389adc9a25a --- /dev/null +++ b/lldb/test/functionalities/data-formatter/data-formatter-categories/main.cpp @@ -0,0 +1,37 @@ +//===-- main.cpp ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +struct Rectangle { + int w; + int h; + Rectangle(int W = 3, int H = 5) : w(W), h(H) {} +}; + +struct Circle { + int r; + Circle(int R = 6) : r(R) {} +}; + +int main (int argc, const char * argv[]) +{ + Rectangle r1(5,6); + Rectangle r2(9,16); + Rectangle r3(4,4); + + Circle c1(5); + Circle c2(6); + Circle c3(7); + + return 0; // Set break point at this line. +} + diff --git a/lldb/test/functionalities/data-formatter/data-formatter-globals/Makefile b/lldb/test/functionalities/data-formatter/data-formatter-globals/Makefile new file mode 100644 index 00000000000..314f1cb2f07 --- /dev/null +++ b/lldb/test/functionalities/data-formatter/data-formatter-globals/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +CXX_SOURCES := main.cpp + +include $(LEVEL)/Makefile.rules diff --git a/lldb/test/functionalities/data-formatter/data-formatter-globals/TestDataFormatterGlobals.py b/lldb/test/functionalities/data-formatter/data-formatter-globals/TestDataFormatterGlobals.py new file mode 100644 index 00000000000..b56b48e23b0 --- /dev/null +++ b/lldb/test/functionalities/data-formatter/data-formatter-globals/TestDataFormatterGlobals.py @@ -0,0 +1,83 @@ +""" +Test lldb data formatter subsystem. +""" + +import os, time +import unittest2 +import lldb +from lldbtest import * + +class DataFormatterTestCase(TestBase): + + mydir = os.path.join("functionalities", "data-formatter", "data-formatter-globals") + + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + def test_with_dsym_and_run_command(self): + """Test data formatter commands.""" + self.buildDsym() + self.data_formatter_commands() + + def test_with_dwarf_and_run_command(self): + """Test data formatter commands.""" + self.buildDwarf() + self.data_formatter_commands() + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line number to break at. + self.line = line_number('main.cpp', '// Set break point at this line.') + + def data_formatter_commands(self): + """Test that that file and class static variables display correctly.""" + self.runCmd("file a.out", 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) + + # 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) + + # Execute the cleanup function during test case tear down. + self.addTearDownHook(cleanup) + + self.runCmd("type summary add -f \"JustATest\" Point") + + # Simply check we can get at global variables + self.expect("target variable g_point", + substrs = ['JustATest']) + + self.expect("target variable g_point_pointer", + substrs = ['(Point *) g_point_pointer =']) + + # Print some information about the variables + # (we ignore the actual values) + self.runCmd("type summary add -f \"(x=${var.x},y=${var.y})\" Point") + + self.expect("target variable g_point", + substrs = ['x=', + 'y=']) + + self.expect("target variable g_point_pointer", + substrs = ['(Point *) g_point_pointer =']) + + # Test Python code on resulting SBValue + self.runCmd("type summary add -s \"return 'x=' + str(valobj.GetChildMemberWithName('x').GetValue());\" Point") + + self.expect("target variable g_point", + substrs = ['x=']) + + self.expect("target variable g_point_pointer", + substrs = ['(Point *) g_point_pointer =']) + + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/test/functionalities/data-formatter/data-formatter-globals/main.cpp b/lldb/test/functionalities/data-formatter/data-formatter-globals/main.cpp new file mode 100644 index 00000000000..521f7a6931e --- /dev/null +++ b/lldb/test/functionalities/data-formatter/data-formatter-globals/main.cpp @@ -0,0 +1,27 @@ +//===-- main.cpp ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +struct Point { + int x; + int y; + Point(int X = 3, int Y = 2) : x(X), y(Y) {} +}; + +Point g_point(3,4); +Point* g_point_pointer = new Point(7,5); + +int main (int argc, const char * argv[]) +{ + return 0; // Set break point at this line. +} + diff --git a/lldb/test/functionalities/data-formatter/data-formatter-skip-summary/TestDataFormatterSkipSummary.py b/lldb/test/functionalities/data-formatter/data-formatter-skip-summary/TestDataFormatterSkipSummary.py index f5d86d96655..55f7e947eca 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-skip-summary/TestDataFormatterSkipSummary.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-skip-summary/TestDataFormatterSkipSummary.py @@ -130,7 +130,7 @@ class DataFormatterTestCase(TestBase): '}']) # Expand same expression, skipping 3 layers of summaries - self.expect('frame variable data1.m_child1->m_child2 -Y3', + self.expect('frame variable data1.m_child1->m_child2 -T -Y3', substrs = ['(DeepData_3) data1.m_child1->m_child2 = {', 'm_some_text = "Just a test"', 'm_child2 = {', diff --git a/lldb/www/varformats.html b/lldb/www/varformats.html index 3fd647db18e..9260e0d6525 100755 --- a/lldb/www/varformats.html +++ b/lldb/www/varformats.html @@ -401,8 +401,10 @@ <code> <b>(lldb)</b> fr var one<br> (i_am_cool) one = int = 3, float = 3.14159, char = 69<br> </code> </p> - <p>The way to obtain this effect is to bind a <i>summary string</i> to - the datatype using the <code>type summary add</code> + + <p>There are two ways to use type summaries: the first one is to bind a <i> + summary string</i> to the datatype; the second is to bind a Python script to the + datatype. Both options are enabled by the <code>type summary add</code> command.</p> <p>In the example, the command we type was:</p> <table class="stats" width="620" cellspacing="0"> @@ -410,6 +412,10 @@ <b>(lldb)</b> type summary add -f "int = ${var.integer}, float = ${var.floating}, char = ${var.character%u}" i_am_cool </td> <table> + + <p>Initially, we will focus on summary strings, and then describe the Python binding + mechanism.</p> + </div> </div> <div class="post"> @@ -717,11 +723,128 @@ </div> <div class="post"> - <h1 class="postheader">Regular expression typenames</h1> + <h1 class="postheader">Python scripting</h1> <div class="postcontent"> + + <p>Most of the times, summary strings prove good enough for the job of summarizing + the contents of a variable. However, as soon as you need to do more than picking + some values and rearranging them for display, summary strings stop being an + effective tool. This is because summary strings lack the power to actually perform + some computation on the value of variables.</p> + <p>To solve this issue, you can bind some Python scripting code as a summary for + your datatype, and that script has the ability to both extract children variables + as the summary strings do and to perform active computation on the extracted + values. As a small example, let's say we have a Rectangle class:</p> + + <code> +class Rectangle<br/> +{<br/> +private:<br/> + int height;<br/> + int width;<br/> +public:<br/> + Rectangle() : height(3), width(5) {}<br/> + Rectangle(int H) : height(H), width(H*2-1) {}<br/> + Rectangle(int H, int W) : height(H), width(W) {}<br/> + + int GetHeight() { return height; }<br/> + int GetWidth() { return width; }<br/> + +};<br/> +</code> + + <p>Summary strings are effective to reduce the screen real estate used by + the default viewing mode, but are not effective if we want to display the + area, perimeter and length of diagonal of <code>Rectangle</code> objects</p> + + <p>To obtain this, we can simply attach a small Python script to the <code>Rectangle</code> + class, as shown in this example:</p> + + <table class="stats" width="620" cellspacing="0"> + <td class="content"> + <b>(lldb)</b> type summary add -P Rectangle<br/> + Enter your Python command(s). Type 'DONE' to end.<br/> +def function (valobj,dict):<br/> + height_val = valobj.GetChildMemberWithName('height')<br/> + width_val = valobj.GetChildMemberWithName('width')<br/> + height_str = height_val.GetValue()<br/> + width_str = width_val.GetValue()<br/> + height = int(height_str)<br/> + width = int(width_str)<br/> + area = height*width<br/> + perimeter = 2*height + 2*width<br/> + diag = sqrt(height*height+width*width)<br/> + return 'Area: ' + str(area) + ', Perimeter: ' + str(perimeter) + ', Diagonal: ' + str(diag)<br/> + DONE<br/> +<b>(lldb)</b> script<br/> +Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.<br/> +>>> from math import sqrt<br/> +>>> quit()<br/> +<b>(lldb)</b> frame variable<br/> +(Rectangle) r1 = Area: 20, Perimeter: 18, Diagonal: 6.40312423743<br/> +(Rectangle) r2 = Area: 72, Perimeter: 36, Diagonal: 13.416407865<br/> +(Rectangle) r3 = Area: 16, Perimeter: 16, Diagonal: 5.65685424949<br/> + </td> + </table> + + <p>In this scenario, you need to enter the interactive interpreter to import the + function sqrt() from the math library. As the example shows, everything you enter + into the interactive interpreter is saved for you to use it in scripts. This way + you can define your own utility functions and use them in your summary scripts if + necessary.</p> + + <p>In order to write effective summary scripts, you need to know the LLDB public + API, which is the way Python code can access the LLDB object model. For further + details on the API you should look at <a href="scripting.html">this page</a>, or at + the LLDB <a href="docs.html">doxygen documentation</a> when it becomes available.</p> + + <p>As a brief introduction, your script is encapsulated into a function that is + passed two parameters: <code>valobj</code> and <code>dict</code>.</p> + + <p><code>dict</code> is an internal support parameter used by LLDB and you should + not use it.<br/><code>valobj</code> is the object encapsulating the actual + variable being displayed, and its type is SBValue. The most important thing you can + do with an SBValue is retrieve its children objects, by calling + <code>GetChildMemberWithName()</code>, passing it the child's name as a string, or ask + it for its value, by calling <code>GetValue()</code>, which returns a Python string. + </p> + + <p>If you need to delve into several levels of hierarchy, as you can do with summary + strings, you must use the method <code>GetValueForExpressionPath()</code>, passing it + an expression path just like those you could use for summary strings. However, if you need + to access array slices, you cannot do that (yet) via this method call, and you must + use <code>GetChildMemberWithName()</code> querying it for the array items one by one. + + <p>Other than interactively typing a Python script there are two other ways for you + to input a Python script as a summary: + + <ul> + <li> using the -s option to <code>type summary add </code> and typing the script + code as an option argument; as in: </ul> + + <table class="stats" width="620" cellspacing="0"> + <td class="content"> + <b>(lldb)</b> type summary add -s "height = + int(valobj.GetChildMemberWithName('height').GetValue());width = + int(valobj.GetChildMemberWithName('width').GetValue()); + return 'Area: ' + str(height*width)" Rectangle<br/> + </td> + </table> + <ul> + <li> using the -F option to <code>type summary add </code> and giving the name of a + Python function with the correct prototype. Most probably, you will define (or have + already defined) the function in the interactive interpreter, or somehow + loaded it from a file. + </ul> + + </p> + </div> </div> + <div class="post"> + <h1 class="postheader">Regular expression typenames</h1> + <div class="postcontent"> <p>As you noticed, in order to associate the custom summary string to the array types, one must give the array size as part of the typename. This can long become @@ -845,12 +968,10 @@ <li>There's no way to do multiple dereferencing, and you need to be careful what the dereferencing operation is binding to in complicated scenarios</li> - <li>There is no way to call functions inside summary - strings, not even <code>const</code> ones</li> <li><code>type format add</code> does not support the <code>-x</code> option</li> - <li>Object location cannot be printed in the summary - string</li> + <strike><li>Object location cannot be printed in the summary + string</li></strike> </ul> </div> </div> |