Martin Vejdarski
Posted on May 14, 2020
Prerequisites
This post is a quick introduction to variable formatting in LLDB, and so it assumes some familiarity with LLDB and C++ debugging.
To learn more about LLDB, please visit either of the following:
- Official Tutorial
- PDR: LLDB Tutorial
- Advanced Debugging — Part 1: LLDB Console
- Improve Debugging Efficiency with LLDB
- LLDB and the Command Line
What is variable formatting?
LLDB has ways of quickly representing the values of variables we see when debugging either through an IDE or the command line.
For example, this is how debug variables and their values look like in CLion:
Why do we need to customize them?
While the defaults work perfectly well in the majority of cases, there are times when having a custom summary can significantly enhance readability and save time.
Consider the following example with color:
using Color = uint32_t;
Color color = 0xFF880022; // ARGB
Without any formatters, the value would appear as an integer:
We can format Color
types as hex by running the following command in an LLDB command-line session:
type format add -f hex Color
The value is now more readable:
The ARGB channels can also be displayed via Python scripting (more below):
How to add custom summaries?
LLDB commands may be run either through the command-line (also available during a debug session in the IDE) or via a .lldbinit
file in the home directory.
It is also possible to automatically load .lldbinit
files from the current directory by specifying settings set target.load-cwd-lldbinit true
in ~/.lldbinit
, which is useful for project-specific customizations.
Additional .lldb
and .py
files may be loaded via:
command script import /path/to/script.py
command source /path/to/script.lldb
The ARGB summary above can now be defined as a Python function:
def ColorSummary(valobj, internal_dict):
value = valobj.GetValueAsUnsigned(0);
alpha = (value >> 24) & 0xFF
red = (value >> 16) & 0xFF
green = (value >> 8) & 0xFF
blue = (value >> 0) & 0xFF
return 'A: {}, R: {}, G: {}, B: {}'.format(alpha, red, green, blue)
To register it, first import the file, Summaries.py
, and associate the ColorSummary
function to the Color
type:
command script import ./Summaries.py
type summary add -F Summaries.ColorSummary Color
More information about defining function summaries can be found here.
The valobj
variable is just a wrapper around the C++ variable and its type is an lldb.SBValue.
Synthetic Children
LLDB also supports defining custom children for any type. Instead of having the color channels be part of the summary, let's define them as synthetic children.
class ColorSyntheticProvider:
def __init__(self, valobj, internal_dict):
self.valobj = valobj
def num_children(self):
return 4
def get_child_at_index(self, index):
if index < 0 or index > 3:
return None
value = self.valobj.GetValueAsUnsigned(0);
value = (value >> 24 - index * 8) & 0xFF
name = ['A', 'R', 'G', 'B'][index]
childType = self.valobj.target.GetBasicType(lldb.eBasicTypeInt)
return self.valobj.CreateValueFromData(name,
lldb.SBData.CreateDataFromInt(value),
childType)
Reference: Synthetic Children, lldb.eBasicTypeInt, lldb.SBData
And the command to register the provider inside the .lldbinit
file:
type synthetic add -l Summaries.ColorSyntheticProvider Color
Where to go from here?
- The official documentation is excellent and covers all the details.
- Filters may be used to hide children that are not useful for debugging.
- Regex Typenames are particularly handy for registering summaries for templated types.
- More examples can be found on the LLVM repository.
-
For specific information about any command, simply type
help <command> <sub-command>
.
Posted on May 14, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.