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?
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?
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> >
.
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}}
No symbol operator* in current context
; not built with optimisation (-g -O0
), make
is verbose. gdb version 10. –
Dulcie 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
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.
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.
.gdbinit
under $HOME
–
Dulcie 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
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):
<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 ./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 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 /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 © 2022 - 2024 — McMap. All rights reserved.