summaryrefslogtreecommitdiffstats
path: root/lldb
diff options
context:
space:
mode:
Diffstat (limited to 'lldb')
-rw-r--r--lldb/include/lldb/Core/Debugger.h237
-rw-r--r--lldb/include/lldb/Core/FormatManager.h404
-rw-r--r--lldb/include/lldb/lldb-enumerations.h14
-rw-r--r--lldb/include/lldb/lldb-forward-rtti.h1
-rw-r--r--lldb/include/lldb/lldb-forward.h1
-rw-r--r--lldb/source/Commands/CommandObjectFrame.cpp2
-rw-r--r--lldb/source/Commands/CommandObjectType.cpp436
-rw-r--r--lldb/source/Commands/CommandObjectType.h11
-rw-r--r--lldb/source/Core/Debugger.cpp190
-rw-r--r--lldb/source/Core/FormatManager.cpp22
-rw-r--r--lldb/source/Core/ValueObject.cpp13
-rw-r--r--lldb/test/functionalities/data-formatter/data-formatter-categories/Makefile5
-rw-r--r--lldb/test/functionalities/data-formatter/data-formatter-categories/TestDataFormatterCategories.py252
-rw-r--r--lldb/test/functionalities/data-formatter/data-formatter-categories/main.cpp37
-rw-r--r--lldb/test/functionalities/data-formatter/data-formatter-globals/Makefile5
-rw-r--r--lldb/test/functionalities/data-formatter/data-formatter-globals/TestDataFormatterGlobals.py83
-rw-r--r--lldb/test/functionalities/data-formatter/data-formatter-globals/main.cpp27
-rw-r--r--lldb/test/functionalities/data-formatter/data-formatter-skip-summary/TestDataFormatterSkipSummary.py2
-rwxr-xr-xlldb/www/varformats.html135
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/>
+ &nbsp;&nbsp;&nbsp;&nbsp;int height;<br/>
+ &nbsp;&nbsp;&nbsp;&nbsp;int width;<br/>
+public:<br/>
+ &nbsp;&nbsp;&nbsp;&nbsp;Rectangle() : height(3), width(5) {}<br/>
+ &nbsp;&nbsp;&nbsp;&nbsp;Rectangle(int H) : height(H), width(H*2-1) {}<br/>
+ &nbsp;&nbsp;&nbsp;&nbsp;Rectangle(int H, int W) : height(H), width(W) {}<br/>
+
+ &nbsp;&nbsp;&nbsp;&nbsp;int GetHeight() { return height; }<br/>
+ &nbsp;&nbsp;&nbsp;&nbsp;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/>
+ &nbsp;&nbsp;&nbsp;&nbsp;height_val = valobj.GetChildMemberWithName('height')<br/>
+ &nbsp;&nbsp;&nbsp;&nbsp;width_val = valobj.GetChildMemberWithName('width')<br/>
+ &nbsp;&nbsp;&nbsp;&nbsp;height_str = height_val.GetValue()<br/>
+ &nbsp;&nbsp;&nbsp;&nbsp;width_str = width_val.GetValue()<br/>
+ &nbsp;&nbsp;&nbsp;&nbsp;height = int(height_str)<br/>
+ &nbsp;&nbsp;&nbsp;&nbsp;width = int(width_str)<br/>
+ &nbsp;&nbsp;&nbsp;&nbsp;area = height*width<br/>
+ &nbsp;&nbsp;&nbsp;&nbsp;perimeter = 2*height + 2*width<br/>
+ &nbsp;&nbsp;&nbsp;&nbsp;diag = sqrt(height*height+width*width)<br/>
+ &nbsp;&nbsp;&nbsp;&nbsp;return 'Area: ' + str(area) + ', Perimeter: ' + str(perimeter) + ', Diagonal: ' + str(diag)<br/>
+ &nbsp;&nbsp;&nbsp;&nbsp;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>
OpenPOWER on IntegriCloud