From 1490c6fd8fa7a5a2cdfe2d6d0fb4eedf0d601a2d Mon Sep 17 00:00:00 2001
From: Enrico Granata
Date: Tue, 19 Jul 2011 02:34:21 +0000
Subject: [PATCH] Fixed a bug where deleting a regex summary would not
immediately reflect in the variables display The "systemwide summaries"
feature has been removed and replaced with a more general and powerful
mechanism. Categories: - summaries can now be grouped into buckets, called
"categories" (it is expected that categories correspond to libraries
and/or runtime environments) - to add a summary to a category, you can use
the -w option to type summary add and give a category name (e.g. type
summary add -f "foo" foo_t -w foo_category) - categories are by default
disabled, which means LLDB will not look into them for summaries, to
enable a category use "type category enable". once a category is enabled,
LLDB will look into that category for summaries. the rules are quite
trivial: every enabled category is searched for an exact match. if an
exact match is nowhere to be found, any match is searched for in every
enabled category (whether it involves cascading, going to base classes,
...). categories are searched into the order in which they were enabled (the
most recently enabled category first, then the second most and so on..) -
by default, most commands that deal with summaries, use a category named
"default" if no explicit -w parameter is given (the observable behavior of
LLDB should not change when categories are not explicitly used) - the
systemwide summaries are now part of a "system" category
llvm-svn: 135463
---
lldb/include/lldb/Core/Debugger.h | 235 ++++------
lldb/include/lldb/Core/FormatManager.h | 410 +++++++++++++---
lldb/include/lldb/lldb-enumerations.h | 14 +
lldb/include/lldb/lldb-forward-rtti.h | 1 +
lldb/include/lldb/lldb-forward.h | 1 +
lldb/source/Commands/CommandObjectFrame.cpp | 2 +-
lldb/source/Commands/CommandObjectType.cpp | 436 ++++++++++++++----
lldb/source/Commands/CommandObjectType.h | 11 +-
lldb/source/Core/Debugger.cpp | 238 ++++------
lldb/source/Core/FormatManager.cpp | 22 +
lldb/source/Core/ValueObject.cpp | 13 +-
.../data-formatter-categories/Makefile | 5 +
.../TestDataFormatterCategories.py | 252 ++++++++++
.../data-formatter-categories/main.cpp | 37 ++
.../data-formatter-globals/Makefile | 5 +
.../TestDataFormatterGlobals.py | 83 ++++
.../data-formatter-globals/main.cpp | 27 ++
.../TestDataFormatterSkipSummary.py | 2 +-
lldb/www/varformats.html | 135 +++++-
19 files changed, 1462 insertions(+), 467 deletions(-)
create mode 100644 lldb/test/functionalities/data-formatter/data-formatter-categories/Makefile
create mode 100644 lldb/test/functionalities/data-formatter/data-formatter-categories/TestDataFormatterCategories.py
create mode 100644 lldb/test/functionalities/data-formatter/data-formatter-categories/main.cpp
create mode 100644 lldb/test/functionalities/data-formatter/data-formatter-globals/Makefile
create mode 100644 lldb/test/functionalities/data-formatter/data-formatter-globals/TestDataFormatterGlobals.py
create mode 100644 lldb/test/functionalities/data-formatter/data-formatter-globals/main.cpp
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h
index 7bbdf0632fbf..af8524144be8 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);
+ 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 void
- Add(const ConstString &type, const ValueFormat::SharedPointer &entry);
+ static lldb::FormatCategorySP
+ SummaryFormats(const char* category_name = NULL);
static bool
- Delete(const ConstString &type);
+ GetSummaryFormat(ValueObject& vobj,
+ lldb::SummaryFormatSP& entry);
- 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);
-
- 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 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 42579fc6b1cc..69bc63a3fb33 100644
--- a/lldb/include/lldb/Core/FormatManager.h
+++ b/lldb/include/lldb/Core/FormatManager.h
@@ -29,6 +29,7 @@ namespace std
#include
#endif
+#include
#include
- The way to obtain this effect is to bind a summary string to
- the datatype using the type summary add
+
+
There are two ways to use type summaries: the first one is to bind a
+ summary string to the datatype; the second is to bind a Python script to the
+ datatype. Both options are enabled by the type summary add
command.
In the example, the command we type was:
@@ -410,6 +412,10 @@
(lldb) type summary add -f "int = ${var.integer}, float = ${var.floating}, char = ${var.character%u}" i_am_cool
+
+ Initially, we will focus on summary strings, and then describe the Python binding
+ mechanism.
+
@@ -717,11 +723,128 @@
-
+
+
+
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.
+
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:
+
+
+class Rectangle
+{
+private:
+ int height;
+ int width;
+public:
+ Rectangle() : height(3), width(5) {}
+ Rectangle(int H) : height(H), width(H*2-1) {}
+ Rectangle(int H, int W) : height(H), width(W) {}
+
+ int GetHeight() { return height; }
+ int GetWidth() { return width; }
+
+};
+
+
+
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 Rectangle objects
+
+
To obtain this, we can simply attach a small Python script to the Rectangle
+ class, as shown in this example:
+
+
+
+ (lldb) type summary add -P Rectangle
+ Enter your Python command(s). Type 'DONE' to end.
+def function (valobj,dict):
+ height_val = valobj.GetChildMemberWithName('height')
+ width_val = valobj.GetChildMemberWithName('width')
+ height_str = height_val.GetValue()
+ width_str = width_val.GetValue()
+ height = int(height_str)
+ width = int(width_str)
+ area = height*width
+ perimeter = 2*height + 2*width
+ diag = sqrt(height*height+width*width)
+ return 'Area: ' + str(area) + ', Perimeter: ' + str(perimeter) + ', Diagonal: ' + str(diag)
+ DONE
+(lldb) script
+Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.
+>>> from math import sqrt
+>>> quit()
+(lldb) frame variable
+(Rectangle) r1 = Area: 20, Perimeter: 18, Diagonal: 6.40312423743
+(Rectangle) r2 = Area: 72, Perimeter: 36, Diagonal: 13.416407865
+(Rectangle) r3 = Area: 16, Perimeter: 16, Diagonal: 5.65685424949
+ |
+
+
+
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.
+
+
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 this page, or at
+ the LLDB doxygen documentation when it becomes available.
+
+
As a brief introduction, your script is encapsulated into a function that is
+ passed two parameters: valobj and dict.
+
+
dict is an internal support parameter used by LLDB and you should
+ not use it.
valobj 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
+ GetChildMemberWithName(), passing it the child's name as a string, or ask
+ it for its value, by calling GetValue(), which returns a Python string.
+
+
+
If you need to delve into several levels of hierarchy, as you can do with summary
+ strings, you must use the method GetValueForExpressionPath(), 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 GetChildMemberWithName() querying it for the array items one by one.
+
+
Other than interactively typing a Python script there are two other ways for you
+ to input a Python script as a summary:
+
+
+ - using the -s option to
type summary add and typing the script
+ code as an option argument; as in:
+
+
+
+ (lldb) type summary add -s "height =
+ int(valobj.GetChildMemberWithName('height').GetValue());width =
+ int(valobj.GetChildMemberWithName('width').GetValue());
+ return 'Area: ' + str(height*width)" Rectangle
+ |
+
+
+ - using the -F option to
type summary add 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.
+
+
+
+
+
+
+
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 @@
There's no way to do multiple dereferencing, and you
need to be careful what the dereferencing operation is
binding to in complicated scenarios
-
There is no way to call functions inside summary
- strings, not even const ones
type format add does not support the -x
option
-
Object location cannot be printed in the summary
- string
+
Object location cannot be printed in the summary
+ string