Reputation: 21
Recently I am working on the python extension of gdb7, I just want to use it to write a small tool to display the contents of C++ containers (such as list) friendly while debugging.But I got trouble when dealing with list. This is my C++ code for test use:
int main() {
list<int> int_lst;
for (int i = 0; i < 10; ++i)
int_lst.push_back(i);
for(list<int>::const_iterator citer = int_lst.begin();
citer != int_lst.end(); ++citer)
cout << *citer << " ";
cout << endl;
return 0;
}
And I write a small python code following the 'debugging with gdb' tutorial just try to display contents of int_lst
import gdb
class Hello(gdb.Command):
def __init__(self):
super(Hello, self).__init__("plist", gdb.COMMAND_OBSCURE)
def invoke(self, arg, from_tty):
cpp_lst = gdb.parse_and_eval("int_lst")
header = cpp_lst['_M_impl']['_M_node']
next = header['_M_next']
# next is _List_node_base, I have to cast it to its derived type for data
next.dynamic_cast(gdb.lookup_type("std::_List_node<``int>").pointer())
Hello()
In C++ STL, std::_List_node_base is the base class of nodes in list, however only the derived template class std::_List_node has the data member "_M_data" which contains the value, so I have to dynamic_cast it, but gdb complains:
Error occurred in Python command: Couldn't determine value's most derived type for dynamic_cast
I've spent a few hours on it, could anyone experienced offer me some hints about this problem, or any suggestions for me to accomplish this little tool? I really appreciate your help, thanks!
Upvotes: 2
Views: 2222
Reputation: 7248
I see the same error from dynamic_cast() as well. Using cast() instead of dynamic_cast() there works:
list-pretty-print.cc
#include <iostream>
#include <list>
/* https://github.com/scottt/debugbreak */
#include "debugbreak/debugbreak.h"
using namespace std;
int main()
{
list<int> int_lst;
debug_break();
for (int i = 0; i < 10; ++i)
int_lst.push_back(i);
debug_break();
for(list<int>::const_iterator citer = int_lst.begin();
citer != int_lst.end(); ++citer)
cout << *citer << " ";
cout << endl;
return 0;
}
list-pretty-print.py
import gdb
class PList(gdb.Command):
def __init__(self):
super(PList, self).__init__('plist', gdb.COMMAND_OBSCURE)
def invoke(self, arg, from_tty):
int_list_pointer_type = gdb.lookup_type('std::_List_node<int>').pointer()
lst = gdb.parse_and_eval('int_lst')
node = lst['_M_impl']['_M_node']
nxt = node['_M_next']
if node.address == nxt:
gdb.write('{}\n')
return
else:
gdb.write('{')
while True:
e = nxt.cast(int_list_pointer_type).dereference()
gdb.write('%d, ' % (e['_M_data'],))
nxt = e['_M_next']
if node.address == nxt:
gdb.write('}\n')
return
PList()
test-list-pretty-print.gdb
set confirm off
set pagination off
set python print-stack full
file list-pretty-print
source list-pretty-print.py
run
up 2
plist
continue
up 2
plist
quit
Sample Session
$ gdb -q -x test-list-pretty-print.gdb
Program received signal SIGTRAP, Trace/breakpoint trap.
trap_instruction () at list-pretty-print.cc:15
15 for (int i = 0; i < 10; ++i)
#2 main () at list-pretty-print.cc:13
13 debug_break();
{}
Program received signal SIGTRAP, Trace/breakpoint trap.
trap_instruction () at list-pretty-print.cc:20
20 for(list<int>::const_iterator citer = int_lst.begin();
#2 main () at list-pretty-print.cc:18
18 debug_break();
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, }
Looking at the chain of expressions, I'm not sure dynamic_cast() is supposed to work there:
(gdb) whatis int_lst
type = std::list<int, std::allocator<int> >
(gdb) whatis int_lst._M_impl
type = std::_List_base<int, std::allocator<int> >::_List_impl
(gdb) whatis int_lst._M_impl._M_node._M_next
type = std::__detail::_List_node_base *
(gdb) python print gdb.parse_and_eval('int_lst._M_impl._M_node._M_next').dynamic_type
std::__detail::_List_node_base *
(gdb) python print gdb.parse_and_eval('int_lst._M_impl._M_node._M_next').dynamic_cast(gdb.lookup_type('std::_List_node<int>').pointer())
Traceback (most recent call last):
File "<string>", line 1, in <module>
gdb.error: Couldn't determine value's most derived type for dynamic_cast
Error while executing Python code.
Upvotes: 0
Reputation: 22569
It is difficult to say what went wrong without more information.
GDB is trying to use the RTTI information to find the full object for that field. This is failing for some eason. You can try to reproduce the problem from the CLI by using "set print object on" and then printing the field in question.
Alternatively, is there a particular reason you want to use dynamic_cast? Just use the plain "cast" method instead. I think that will bypass these checks.
Note that for this specific case, you probably should just pick up the existing libstdc++ pretty-printers. These integrate with the existing "print" command in gdb and already handle every complicated data structure in libstdc++. Many distros ship all of this code in a way that automatically enables it when your program uses libstdc++.
Upvotes: 1