Summaries work well when one is able to navigate through an expression path.
In order for LLDB to do so, appropriate debugging information must be available.
Some types are opaque, i.e. no knowledge of their internals is provided.
When that's the case, expression paths do not work correctly.
In other cases, the internals are available to use in expression paths, but they
do not provide a user-friendly representation of the object's value.
For instance, consider an STL vector, as implemented by the GNU C++ Library:
(lldb) frame variable numbers -T
(std::vector<int>) numbers = {
(std::_Vector_base<int, std::allocator<int> >) std::_Vector_base<int, std::allocator<int> > = {
(std::_Vector_base<int, std::allocator&tl;int> >::_Vector_impl) _M_impl = {
(int *) _M_start = 0x00000001001008a0
(int *) _M_finish = 0x00000001001008a8
(int *) _M_end_of_storage = 0x00000001001008a8
}
}
}
Here, you can see how the type is implemented, and you can write a summary for that implementation
but that is not going to help you infer what items are actually stored in the vector.
What you would like to see is probably something like:
(lldb) frame variable numbers -T
(std::vector<int>) numbers = {
(int) [0] = 1
(int) [1] = 12
(int) [2] = 123
(int) [3] = 1234
}
Synthetic children are a way to get that result.
The feature is based upon the idea of providing a new set of children for a variable that replaces the ones
available by default through the debug information. In the example, we can use synthetic children to provide
the vector items as children for the std::vector object.
In order to create synthetic children, you need to provide a Python class that adheres to a given interface
(the word is italicized because Python has no explicit notion of interface, by that word we mean a given set of methods
must be implemented by the Python class):
class SyntheticChildrenProvider:
def __init__(self, valobj, internal_dict):
this call should initialize the Python object using valobj as the variable to provide synthetic children for
def num_children(self):
this call should return the number of children that you want your object to have
def get_child_index(self,name):
this call should return the index of the synthetic child whose name is given as argument
def get_child_at_index(self,index):
this call should return a new LLDB SBValue object representing the child at the index given as argument
def update(self):
this call should be used to update the internal state of this Python object whenever the state of the variables in LLDB changes.[1]
def has_children(self):
this call should return True if this object might have children, and False if this object can be guaranteed not to have children.[2]
[1] This method is optional. Also, it may optionally choose to return a value (starting with SVN rev153061/LLDB-134). If it returns a value, and that value is
True
, LLDB will be allowed to cache the children and the children count it previously obtained, and will not return to the provider class to ask. If nothing,
None
, or anything other than
True
is returned, LLDB will discard the cached information and ask. Regardless, whenever necessary LLDB will call
update
.
[2] This method is optional (starting with SVN rev166495/LLDB-175). While implementing it in terms of
num_children
is acceptable, implementors are encouraged to look for optimized coding alternatives whenever reasonable.
For examples of how synthetic children are created, you are encouraged to look at examples/synthetic in the LLDB trunk. Please, be aware that the code in those files (except bitfield/)
is legacy code and is not maintained.
You may especially want to begin looking at this example to get
a feel for this feature, as it is a very easy and well commented example.
The design pattern consistently used in synthetic providers shipping with LLDB
is to use the
__init__
to store the SBValue instance as a part of
self
. The
update
function is then used
to perform the actual initialization.
Once a synthetic children provider is written, one must load it into LLDB before it can be used.
Currently, one can use the LLDB script
command to type Python code interactively,
or use the command script import fileName
command to load Python code from a Python module
(ordinary rules apply to importing modules this way). A third option is to type the code for
the provider class interactively while adding it.
For example, let's pretend we have a class Foo
for which a synthetic children provider class
Foo_Provider
is available, in a Python module contained in file ~/Foo_Tools.py
. The following interaction
sets Foo_Provider
as a synthetic children provider in LLDB:
(lldb) command script import ~/Foo_Tools.py
(lldb) type synthetic add Foo --python-class Foo_Tools.Foo_Provider
|
(lldb) frame variable a_foo
(Foo) a_foo = {
x = 1
y = "Hello world"
}
LLDB has synthetic children providers for a core subset of STL classes, both in the version provided by libstdcpp and by libcxx, as well as for several Foundation classes.
Synthetic children extend summary strings by enabling a new special variable: ${svar
.
This symbol tells LLDB to refer expression paths to the
synthetic children instead of the real ones. For instance,
(lldb) type summary add --expand -x "std::vector<" --summary-string "${svar%#} items"
|
(lldb) frame variable numbers
(std::vector<int>) numbers = 4 items {
(int) [0] = 1
(int) [1] = 12
(int) [2] = 123
(int) [3] = 1234
}
In some cases, if LLDB is unable to use the real object to get a child specified in an expression path, it will automatically refer to the
synthetic children. While in summaries it is best to always use ${svar
to make your intentions clearer, interactive debugging
can benefit from this behavior, as in:
(lldb) frame variable numbers[0] numbers[1]
(int) numbers[0] = 1
(int) numbers[1] = 12
Unlike many other visualization features, however, the access to synthetic children only works when using frame variable
, and is
not supported in expression
:
(lldb) expression numbers[0]
Error [IRForTarget]: Call to a function '_ZNSt33vector<int, std::allocator<int> >ixEm' that is not present in the target
error: Couldn't convert the expression to DWARF
The reason for this is that classes might have an overloaded operator []
, or other special provisions
and the expression
command chooses to ignore synthetic children in the interest of equivalency with code you asked to have compiled from source.
Filters are a solution to the display of complex classes.
At times, classes have many member variables but not all of these are actually
necessary for the user to see.
A filter will solve this issue by only letting the user see those member
variables he cares about. Of course, the equivalent of a filter can be implemented easily
using synthetic children, but a filter lets you get the job done without having to write
Python code.
For instance, if your class Foobar
has member variables named A
thru Z
, but you only need to see
the ones named B
, H
and Q
, you can define a filter:
(lldb) type filter add Foobar --child B --child H --child Q
|
(lldb) frame variable a_foobar
(Foobar) a_foobar = {
(int) B = 1
(char) H = 'H'
(std::string) Q = "Hello world"
}
When doing Objective-C development, you may notice that some of your variables
come out as of type id
(for instance, items extracted from NSArray
).
By default, LLDB will not show you the real type of the object. it can actually dynamically discover the type of an Objective-C
variable, much like the runtime itself does when invoking a selector. In order
to be shown the result of that discovery that, however, a special option to frame variable
or expression
is
required:
--dynamic-type
.
--dynamic-type
can have one of three values:
no-dynamic-values
: the default, prevents dynamic type discovery
no-run-target
: enables dynamic type discovery as long as running
code on the target is not required
run-target
: enables code execution on the target in order to perform
dynamic type discovery
If you specify a value of either no-run-target
or run-target
,
LLDB will detect the dynamic type of your variables and show the appropriate formatters
for them. As an example:
(NSString *) $0 = 0x00000001048000b0 @"Hello"
(lldb) expr -d no-run @"Hello"
|
(__NSCFString *) $1 = 0x00000001048000b0 @"Hello"
Because LLDB uses a detection algorithm that does not need to invoke any functions
on the target process, no-run-target
is enough for this to work.
As a side note, the summary for NSString shown in the example is built right into LLDB.
It was initially implemented through Python (the code is still available for reference at
CFString.py).
However, this is out of sync with the current implementation of the NSString formatter (which is a C++ function compiled into the LLDB core).
Categories are a way to group related formatters. For instance, LLDB itself groups
the formatters for the libstdc++ types in a category named gnu-libstdc++
.
Basically, categories act like containers in which to store formatters for a same library
or OS release.
By default, several categories are created in LLDB:
default
: this is the category where every formatter ends up, unless another category is specified
objc
: formatters for basic and common Objective-C types that do not specifically depend on Mac OS X
gnu-libstdc++
: formatters for std::string, std::vector, std::list and std::map as implemented by libstdcpp
libcxx
: formatters for std::string, std::vector, std::list and std::map as implemented by libcxx
system
: truly basic types for which a formatter is required
AppKit
: Cocoa classes
CoreFoundation
: CF classes
CoreGraphics
: CG classes
CoreServices
: CS classes
VectorTypes
: compact display for several vector types
If you want to use a custom category for your formatters, all the
type ... add
(except for
type format add
),
provide a
--category
(
-w
) option, that names the category to add the formatter to.
To delete the formatter, you then have to specify the correct category.
Categories can be in one of two states: enabled and disabled. A category is initially disabled,
and can be enabled using the type category enable
command. To disable an enabled category,
the command to use is type category disable
.
The order in which categories are enabled or disabled
is significant, in that LLDB uses that order when looking for formatters. Therefore, when you enable a category, it becomes
the second one to be searched (after default
, which always stays on top of the list). The default categories are enabled in such a way that the search order is:
- default
- objc
- CoreFoundation
- AppKit
- CoreServices
- CoreGraphics
- gnu-libstdc++
- libcxx
- VectorTypes
- system
As said, gnu-libstdc++
and libcxx
contain formatters for C++ STL
data types. system
contains formatters for char*
and char[]
, which reflect the behavior
of older versions of LLDB which had built-in formatters for these types. Because now these are formatters, you can even
replace them with your own if so you wish.
There is no special command to create a category. When you place a formatter in a category, if that category does not
exist, it is automatically created. For instance,
(lldb) type summary add Foobar --summary-string "a foobar" --category newcategory
|
automatically creates a (disabled) category named newcategory.
Another way to create a new (empty) category, is to enable it, as in:
(lldb) type category enable newcategory
|
However, in this case LLDB warns you that enabling an empty category has no effect. If you add formatters to the
category after enabling it, they will be honored. But an empty category per se does not change the way any
type is displayed. The reason the debugger warns you is that enabling an empty category might be a typo, and you
effectively wanted to enable a similarly-named but not-empty category.
While the rules for finding an appropriate format for a
type are relatively simple (just go through typedef
hierarchies), searching other formatters goes through
a rather intricate set of rules. Namely, what happens is that LLDB
starts looking in each enabled category, according to the order in which
they were enabled (latest enabled first). In each category, LLDB does
the following:
- If there is a formatter for the type of the variable,
use it
- If this object is a pointer, and there is a formatter
for the pointee type that does not skip pointers, use
it
- If this object is a reference, and there is a
formatter for the referred type that does not skip
references, use it
- If this object is an Objective-C class and dynamic types are enabled,
look for a formatter for the dynamic type of the object. If dynamic types are disabled,
or the search failed, look for a formatter for the declared type of the object
- If this object's type is a typedef, go through
typedef hierarchy (LLDB might not be able to do this if
the compiler has not emitted enough information. If the
required information to traverse typedef hierarchies is
missing, type cascading will not work. The
clang compiler,
part of the LLVM project, emits the correct debugging
information for LLDB to cascade). If at any level of the hierarchy
there is a valid formatter that can cascade, use it.
- If everything has failed, repeat the above search,
looking for regular expressions instead of exact
matches
If any of those attempts returned a valid formatter to be used,
that one is used, and the search is terminated (without going to look
in other categories). If nothing was found in the current category, the next
enabled category is scanned according to the same algorithm. If there are no
more enabled categories, the search has failed.
Warning: previous versions of LLDB defined cascading to mean
not only going through typedef chains, but also through inheritance chains.
This feature has been removed since it significantly degrades performance.
You need to set up your formatters for every type in inheritance chains to which
you want the formatter to apply.