Consider the following example:
std::string s = "Hello!!";
(gdb) p s
$1 = "Hello!!";
Essentially, just providing the variable name is good enough to display the string. I don't have to, for example, type "p s.c_str()."
Is gdb using any implicit operator to get the display string? I need to do something similar for my class. Here is a trivial example of my class:
class MyClass {
private:
std::string _name;
};
You need to write a pretty-printer for your class. It is not something you do in your C++ class, but something you do in gdb (although matching your C++ class). The easiest way to do that is through gdb's Python API (you can also use the Guile language).
GDB already comes with pretty-printers for most of the standard library classes and that is why you can easily see an std::string
object, an std::vector
, etc. If you type info pretty-printer
in gdb it will tell you about the pretty-printers it currently knows about and you will notice many std::something
pretty printers.
If you use pass /r
to the print command in gdb it will print the variable without using any possible registered pretty-printer that matches it. Try that with an std::string
to see how it would be printed if gdb didn't come with a pretty-printer for it.
So, how can you write your own pretty-printers? For that, you should read GDB's documentation on this topic. But I find it much easier to start by reading and tweaking some existing pretty-printer you can find and then read gdb's documentation for the details.
For instance, I have a Coordinate
class in one of my projects as below
class Coordinate {
private:
double x;
double y;
double z;
public:
...
}
It's very easy to write a pretty-printer for this class. You create a python file with the following code
class CoordinatePrinter:
def __init__(self, val):
# val is the python representation of you C++ variable.
# It is a "gdb.Value" object and you can query the member
# atributes of the C++ object as below. Since the result is
# another "gdb.Value" I'am converting it to a python float
self.x = float(val['x'])
self.y = float(val['y'])
self.z = float(val['z'])
# Whatever the `to_string` method returns is what will be printed in
# gdb when this pretty-printer is used
def to_string(self):
return "Coordinate(x={:.2G}, y={:.2G}, z={:.2G})".format(self.x, self.y, self.z)
import gdb.printing
# Create a "collection" of pretty-printers
# Note that the argument passed to "RegexpCollectionPrettyPrinter" is the name of the pretty-printer and you can choose your own
pp = gdb.printing.RegexpCollectionPrettyPrinter('cppsim')
# Register a pretty-printer for the Coordinate class. The second argument is a
# regular expression and my Coordinate class is in a namespace called `cppsim`
pp.add_printer('Coordinate', '^cppsim::Coordinate$', CoordinatePrinter)
# Register our collection into GDB
gdb.printing.register_pretty_printer(gdb.current_objfile(), pp, replace=True)
Now all we need to do is to source
this python file in gdb. For that, write in your .gdbinit file
source full_path_to_your_python_file_with_pretty_printers.py
When you start gdb it will run your .gdbinit
file, which will load your pretty-printers. Note that these pretty-printers will often also work inside IDEs that use gdb.
If you are interested in more examples, I have created pretty-printers to some classes in the Armadillo library (vector, matrices and general linear algebra) which are available here.
If you have libstdc++ pretty-printers installed (you already have them installed) your class is already gdb-friendly because they will be invoked when printing members of your class. If you have a lot of other class members besides _name
you can also use set print pretty
for easier distinguishing between them:
(gdb) p my_class
$1 = {_name = ""}
(gdb) set print pretty
(gdb) p my_class
$2 = {
_name = ""
}
(gdb)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With