I would like to write a python script to analyze the debugger state of an algorithm, but I can't figure out how to get the basic example of indexing a vector to work.
for example, when debugging the following file (gdb_test.cpp):
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v = {1, 2, 3, 4, 5};
std::cout << v.size() << std::endl;
for (const auto& element : v)
{
std::cout << element << std::endl;
}
}
With gdb and sourcing the following script (print_vector.py) which is intended to print out the first three elements of an input vector provided by name:
import gdb
class print_vector(gdb.Command):
def __init__(self):
super(print_vector, self).__init__('print_vector',
gdb.COMMAND_SUPPORT,
gdb.COMPLETE_FILENAME)
def invoke(self, arg, from_tty):
# Access the variable from gdb.
frame = gdb.selected_frame()
args = arg.split('; ')
val = frame.read_var(args[0])
for i in range(3):
print(val[0])
print_vector()
With commands:
g++ gdb_test.cpp -std=c++11 -g
gdb ./a.out
(gdb) b gdb_test.cpp:10
(gdb) r
(gdb) source print_vector.py
(gdb) print_vector v
I get the error
Python Exception <class 'gdb.error'> Cannot subscript requested type.:
Error occurred in Python command: Cannot subscript requested type.
Which is referring to the print(val[0])
-line. The problem is that gdb.Value
objects can't be indexed as lists. Is there some other way to access the elements?
I have also tried things like val['at'][0]
and val['at(0)']
, neither of which works. Loading the elements one-by-one with one call to gdb.parse_and_eval
each works but is too slow.
The problem is that the C++ objects exposed to Python are not "first class" Python objects - so, they don't feature a Python __getitem__
method that maps to the corresponding mechanism to get an item in the "C++" class of the object.
On the other hand, the API does expose a parse_and_eval
method that will handle a string as if it was typed in the C++ source - therefore allowing one to use v[i]
from Python in an easy way -
For the example above, you can change your Python source to:
import gdb
class print_vector(gdb.Command):
def __init__(self):
super(print_vector, self).__init__('print_vector',
gdb.COMMAND_SUPPORT,
gdb.COMPLETE_FILENAME)
def invoke(self, arg, from_tty):
# Access the variable from gdb.
frame = gdb.selected_frame()
args = arg.split('; ')
valname = args[0]
for i in range(3):
content_value = gdb.parse_and_eval(f"{valname}[{i}]")
print(int(content_value))
print_vector()
To see this working. For more complex code, it may be worth to create a wrapper class in Python for gdb.Value objects that will implement a __getitem__
that does this automatically.
I ended up using the following function in c++11:
def vector_to_list(std_vector):
out_list = []
value_reference = std_vector['_M_impl']['_M_start']
while value_reference != std_vector['_M_impl']['_M_finish']:
out_list.append(value_reference.dereference())
value_reference += 1
return out_list
If std_vector
is a gdb.Value
-object holding a std::vector<T>
this function returns a python list of gdb.Value
-objects of type T
. Based on this blog-post: https://hgad.net/posts/object-inspection-in-gdb/
I found this to be significantly faster than calling gdb.parse_and_eval['v[i]']
for all the i
's
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.