Is there a way to print an Armadillo matrix in gdb?
Asked Answered
A

5

10

I'm using gdb to debug my c++ program. I'm using the armadillo numerical library to define my matrices. I have an armadillo matrix defined like so:

mat A = randu<mat>(5,5);

Is it possible to print the whole matrix while using the gdb debugger?

Ashford answered 29/2, 2012 at 12:47 Comment(1)
Recent gdb (latest release is GDB 7.4) can be scripted in Python. Did you consider it??Eudiometer
R
10

The question may be old, but stumbling over it made me find a solution for my own work.

Due to the template-based nature of the Armadillo library you need to provide some helpers of your own:

#include <iostream>
#include <armadillo>

template<class Matrix>
void print_matrix(Matrix matrix) {
    matrix.print(std::cout);
}

//provide explicit instantiations of the template function for 
//every matrix type you use somewhere in your program.
template void print_matrix<arma::mat>(arma::mat matrix);
template void print_matrix<arma::cx_mat>(arma::cx_mat matrix);

int main() {
    arma::mat matrix = arma::randu(10,10);

    return 0;
}

Now you can easily call print_matrix from within gdb:

(gdb) call print_matrix<arma::Mat<double> >(matrix) 
   0.8402   0.4774   0.0163   0.5129   0.5267   0.5260   0.2383   0.5316   0.6879   0.9565
   0.3944   0.6289   0.2429   0.8391   0.7699   0.0861   0.9706   0.0393   0.1660   0.5886
   0.7831   0.3648   0.1372   0.6126   0.4002   0.1922   0.9022   0.4376   0.4401   0.6573
   0.7984   0.5134   0.8042   0.2960   0.8915   0.6632   0.8509   0.9318   0.8801   0.8587
   0.9116   0.9522   0.1567   0.6376   0.2833   0.8902   0.2667   0.9308   0.8292   0.4396
   0.1976   0.9162   0.4009   0.5243   0.3525   0.3489   0.5398   0.7210   0.3303   0.9240
   0.3352   0.6357   0.1298   0.4936   0.8077   0.0642   0.3752   0.2843   0.2290   0.3984
   0.7682   0.7173   0.1088   0.9728   0.9190   0.0200   0.7602   0.7385   0.8934   0.8148
   0.2778   0.1416   0.9989   0.2925   0.0698   0.4577   0.5125   0.6400   0.3504   0.6842
   0.5540   0.6070   0.2183   0.7714   0.9493   0.0631   0.6677   0.3540   0.6867   0.9110

Thanks to tab completion you only need to actually type a few characters of print_matrix<arma::Mat<double> >.

Rossiter answered 31/3, 2014 at 16:24 Comment(1)
+1. This must be the most elegant way to pretty print armadillo matrices. However, executing the command "-exec call print_matrix<arma::Mat<double> >(matrix)" in VS Code Debug Console crashes my debugging session with error message: "Error: GDB exited unexpectedly. ERROR: GDB exited unexpectedly. Debugging will now abort." I think I miss one small piece of the puzzle to get there. Any idead from anyone? I'd highly appreciate it.Stiff
E
4

The simplest way is to print directly in gdb, unfortunately no fancy format

> print *A.mem@5@5
$1 = {{0.84018771715470952, 0.39438292681909304,0.78309922375860586,0.79844003347607329, 0.91164735793678431},
{0.19755136929338396, 0.33522275571488902, 0.768229594811904, 0.27777471080318777, 0.55396995579543051}, 
{0.47739705186216025, 0.62887092476192441, 0.36478447279184334, 0.51340091019561551, 0.95222972517471283}, 
{0.91619506800370065, 0.63571172795990094, 0.71729692943268308, 0.14160255535580338, 0.60696887625705864}, 
{0.016300571624329581, 0.24288677062973696, 0.13723157678601872, 0.80417675422699042, 0.15667908925408455}}
Evictee answered 10/2, 2017 at 21:41 Comment(5)
@RolenClaes +1. Great! No fluff solution. Bit hard to read the output though, but requires no setup, or whatsoever. Just works out of the box! Thanks.Stiff
@RolenClaes I wonder if there are improved solutions since 2017.Stiff
@Stiff Not that I know regarding GDB-improvments but you may always use pretty-printing, see sigpack.sourceforge.net/md_2-build.htmlEvictee
@RolenClaes Ok, I see. Thanks for the answer and link.Stiff
Not working for me in CLion with gdb on Linux; gdb complains No symbol operator* in current context; not built with optimisation (-g -O0), make is verbose. gdb version 10.Dulcie
A
4

The best option is using gdb's python API to create pretty printers for the armadillo classes. It works better than calling a C/C++ function, since it is always accessible (even when debugging from a core file where there is no program running). Furthermore, there is no risk of the linker discarding the function when it is not used in your program (thus making it unavailable when you are debugging in gdb).

The pretty printer code is loaded (sourced) from the .gdbinit file in your home folder. It will work in gdb running in a terminal as well as from an IDE (assuming the IDE does not avoid loading the .gdbinit file).

As an example, suppose you have the following two matrices

arma::mat m1{{1.1, 2.2,  3},
             {  4,   5,  6}, 
             {  7,   8,  9},
             { 10,  11, 12},
             { 13,  14, 15},
             { 16,  17, 18}};

arma::cx_mat m2{{1.1 - 1.1j, 2.2 - 7.7j, 3},
                {         4,          5, 6},
                {         7,          8, 9},
                {         10,        11, 12},
                {         13,        14, 15},
                {         16,        17, 18}};

A pretty printer might shown them as

m1

m2

Notice how the complex matrix m2 has its elements displayed both in rectangular form as well as in polar form (displaying the polar form can be disabled). This also works better with the rest of gdb. For instance, gdb allows you to the maximum number of elements to show in an array. The pretty printer will respect that if it is implemented to display the elements as standard arrays in gdb.


This is how the m1 and m2 matrices are displayed in CLion.

m1 in CLion

m2 in CLion


This pretty printer can be obtained from here. There are a few other things such as some xmethods (python re-implementation of some C++ methods) and conversion to numpy arrays.

Disclaimer: I'm the author of these pretty printers.

Ascites answered 10/10, 2019 at 22:4 Comment(1)
If no one was bothered leaving comment here I come; this I can confirm that Linux system gdb version 10 with this works like a charm. Only thing needed was to clone the repo and two lines in .gdbinit under $HOMEDulcie
O
2

You can call C functions in gdb, so you just need a function that prints your objects. E.g:

(gdb) call printf("%.2f", 3.1428)
$7 = 4
(gdb) call fflush(stdout)
3.14$8 = 0
On answered 29/2, 2012 at 13:22 Comment(0)
D
1

For those using QtCreator, you can inspect the values from your IDE by extending GDB with Python Debugging Helpers (maybe other IDEs support this feature too).

Place the following script in, for example, ~/debugHelpers.py

#!/usr/bin/python

import gdb      # gdb.Value()
import dumper   # dumper.Children()

def qdump__arma__Mat(d, value):
    array = value["mem"]
    cols = value["n_cols"]
    rows = value["n_rows"]
    maxDisplayItems = 50
    innerType = d.templateArgument(value.type, 0)
    p = gdb.Value(array.cast(innerType.pointer()))
    d.putItemCount(cols)
    d.putNumChild(cols)
    if d.isExpanded():
        numDisplayItems = min(maxDisplayItems, cols)
        with dumper.Children(d, numChild=cols,
               maxNumChild=numDisplayItems,
               childType="<column>",
               addrBase=p,
               addrStep=p.dereference().__sizeof__):
            for i in range(0, int(numDisplayItems)):
                with dumper.Children(d):
                    d.putItemCount(rows)
                    d.putNumChild(rows)
                    if d.isExpanded():
                        numDisplayItems = min(maxDisplayItems, rows)
                        with dumper.Children(d, numChild=rows,
                               maxNumChild=numDisplayItems,
                               childType=innerType,
                               addrBase=p,
                               addrStep=p.dereference().__sizeof__):
                            for j in range(0, int(numDisplayItems)):
                                d.putSubItem(j, p.dereference())
                                p += 1

And call it adding this line to your ~/.gdbinit:

python exec(open('/<full_path>/debugHelpers.py').read())

or add it from your IDE; in QtCreator use Tools > Options > Debugger > GDB (tab) > Extra Debugging Helpers (near the bottom).

This particular script will return the matrix arranged by columns (natural memory arrangement in my architecture):

enter image description here

Sources: Writing Debug Visualizers for GDB / QtCreator 2.8

Denysedenzil answered 1/5, 2015 at 9:5 Comment(7)
I'm having trouble getting this to work in QtCreator 3.4.0. All Armadillo matrices get the value <not accessible>. I think it might be related to that my gdb is linked to Python 3. Do you have any suggestions? I'm adding the script using python exec(open(filename).read()), which is Python 3 compatible (execfile isn't).Duty
I have finally gotten your script to work after some work. I ended up compiling the latest gdb (7.9.1), linking it to Python 2 instead of 3 using ./configure --prefix /usr/local/gdb-python2 --with-python, and then using that gdb in QtCreator. I also had to add import gdb and from dumper import * to the top of your debugHelpers.py. But I would still love a version of the script that works with gdb and Python 3, since Python 3 seems to be the default now.Duty
I now have it working with gdb linked to Python 3. First add import gdb and import dumper, then change the Children() calls to dumper.Children() and range(0, numDisplayItems) to range(0, int(numDisplayItems)). A complete script can be found here (link to pastebin).Duty
Hi @FilipSund, excellent!. Before I accept your edit: I tried the script you propose with my Python2-enabled gdb, but I cannot import the 'dumper' module. Can you work around this with Python 2?, otherwise I will post two flavors of the script.Denysedenzil
Yeah, I've seen that error when running gdb in the terminal. But if you add the script to QtCreator using the "Extra Debugging Helpers" option it works as intended. To use it in gdb I think you have to add /usr/share/qtcreator/debugger/ (or similarly) to the python path, f.ex. by adding python sys.path.append("/usr/share/qtcreator/debugger/") to .gdbinit, or running interpreter-exec console "python sys.path.append('/usr/share/qtcreator/debugger/')" in gdb before loading the script (this is what QtCreator does when you start the debugger). Or perhaps adding it in the script is easier!Duty
I updated the answer including your changes, it is the only option that works for me now with QtCreator 3.4.1 and GDB 7.7.1. Python version is still 2.7.9.Denysedenzil
After updating to QtCreator 4.2.0 I'm having some trouble with this debugging helper. I'm getting <not accessible> for all Armadillo matrices. Any ideas?Duty

© 2022 - 2024 — McMap. All rights reserved.