Debugging Templates with Gdb

debugging templates with GDB

if your problem is just about placing breakpoint in your code. Here is a little snippet

ex: main.cpp

#include <iostream>

template <typename T>
void coin(T v)
{
std::cout << v << std::endl;
}

template<typename T>
class Foo
{
public:

T bar(T c)
{
return c * 2;
}
};

int main(int argc, char** argv)
{
Foo<int> f;
coin(f.bar(21));
}

compile with
g++ -O0 -g main.cpp

gdb ./a.out
(gdb) b Foo<int>::bar(int)
Breakpoint 2 at 0x804871d: file main.cpp, line 16.
(gdb) b void coin<int>(int)
Breakpoint 1 at 0x804872a: file main.cpp, line 6.
(gdb) r
... debugging start

otherwise you could just use

(gdb) b main.cpp:16

debug c++ template with gdb

You can use ptype rather than p to print a type. With a recent enough (couple of years old) g++ and gdb, this will work.

Consider this source:

#include <iostream>

template<typename T>
struct S
{
S(T t)
{
std::cout << t;
}
};

int main()
{
S<const char*> s2("hello");
S<int> s1(23);
return 0;
}

Here I can step into the constructor for s2 and see T:

(gdb) ptype T
type = const char *

Take a look the current frame:

(gdb) frame
#0 S<char const*>::S (this=0x7fffffffe35f, t=0x400940 "hello") at q.cc:8
8 std::cout << t;

I can set a breakpoint using the function name given there:

(gdb) b S<const char *>::S
Breakpoint 2 at 0x40087a: file q.cc, line 8.

debugging C++ code with templates and STL with gdb

I am assuming that you mean visualizing STL code better (and not the debug mode which give safe iterators and additional runtime checks). I am not sure if you have looked at these posts:

  • GNU GCC Documentation: Debugging Support

Using gdb

Starting with version 7.0, GDB includes support for writing pretty-printers in Python. Pretty printers for STL classes are distributed with GCC from version 4.5.0. The most recent version of these printers are always found in libstdc++ svn repository. To enable these printers, check-out the latest printers to a local directory:

  • Pretty printing STL lists

Also, try using KDevelop/DDD if possible -- they do help.

Will my gdb work when using templates?

Normal Class

class foo
{
private:
int x;
public:
foo(int n = 0):x(n) {cout<<"foo::foo(int)"<<endl;}
~foo() {cout<<"foo::~foo()"<<endl;}
};

To put the breakpoint, we follow as below
$gdb: b foo::foo(int)
b foo::~foo()

=========================================================

Template class Example

template<typename T>
class bar
{
private:
T x;
public:
bar(T n = 0):x(n) {cout<<"bar::bar(int)"<<endl;}
~bar() {cout<<"bar::~bar()"<<endl;}
};

To put the breakpoint, we follow as below
$gdb: b bar<int>::bar(int)
b foo<int>::~bar()

The only thing we need to understand is(which I guess confuted you), that when we debug template class, we can not use the break point like bar<T>::bar(). When program runs, program would instantiate the template class with a particular type as bar<int>::bar().

Apart from that, there is no difference while debugging the non-template vs template based class. Only thing we need to consider is, template bases class would be bit verbose and it takes some time to understand especially.

how to print value returned by template member function in gdb/lldb debugging

The current debug information for template functions, and templated entities in general is awkward because it only describes instantiations, and not templates as abstract entities, so templated functions just show up in the debug info just as functions with angle brackets somewhere in the names. That makes it tricky to go from the debug info to a compiler representation that lldb can feed into its copy of clang so that clang can parse them correctly in expressions. As you have found, that doesn't work at present.

If you really need to do this however, you can work around the problem with a little creative casting, for instance:

Find the function address, e.g.

(lldb) image lookup -n Mat::at<float>
1 match found in /tmp/a.out:
Address: a.out[0x0000000100003f30] (a.out.__TEXT.__text + 64)
Summary: a.out`float const& Mat::at<float>(int, int) at template_fun.cpp:4

Cast the call to that address by hand:

(lldb) expr ((float &(*) (Mat *, int, int))0x0000000100003f30)(&my_mat, 10, 20)
Called with 10 20
(float) $0 = 30

This isn't your real function, just a toy I made so don't pay attention to the actual result.

Note, if you end up doing this often and don't 100% love C function casting syntax, you can make a typedef for it, either in the code or in lldb like:

(lldb) expr typedef float &(*$Mat_at_type) (Mat *, int, int)

That simplifies the call:

(lldb) expr (($Mat_at_type)0x0000000100003f30)(&my_mat, 10, 20)
Called with 10 20
(float) $1 = 30

And then if you end up doing this a whole lot, you could even do:

(lldb) command alias call_at expr -- (($Mat_at_type)0x0000000100003f30)
(lldb) call_at (&my_mat, 10, 20)

Inspect template parameter pack in gdb

Related: Showing values of parameters packs in gdb

There are two problems here; the first is that g++ emits parameter pack debugging information in the DWARF format using the tags DW_TAG_GNU_template_parameter_pack and DW_TAG_GNU_formal_parameter_pack, which gdb does not yet support (PR linked).

Even when this is fixed, we run into another problem, which is that the debugging information g++ emits is broken; it's missing the parameter name (DW_AT_name) (PR linked).

TBH gdb support for C++11 is pretty abysmal (unsurprising as it was effectively abandoned for so long); another near-showstopper bug for C++11 is that it didn't support rvalue references (DW_TAG_rvalue_reference_type) until version 8, printing error messages like <unknown type in /tmp/a.out, CU 0x0, DIE 0x7f>.

The workaround (other than using clang, or an ancient version of g++ that doesn't use the DW_TAG_GNU_template_parameter_pack tags, e.g. 4.4.7) is to use the stabs debugging format with GCC extensions:

g++ -std=c++11 -gstabs+ -O0 foo.cxx

</>

(gdb) s
void printAll<int, char const (&) [3], int>(int, int&&, char const (&) [3], int&&) (i=999, args#0=@0x7fffffffe45c: 1, args#1=..., args#2=@0x7fffffffe458: 4)
at p.cpp:7
7 swallow{0,
(gdb) p 'args#0'
$1 = (int &) @0x7fffffffe45c: 1


Related Topics



Leave a reply



Submit