在python gdb脚本中索引c ++向量



我想编写一个python脚本来分析算法的调试器状态,但是我不知道如何使索引向量的基本示例起作用。

例如,调试以下文件 (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;
    }
}

使用 gdb 并获取以下脚本 (print_vector.py(,该脚本旨在打印出由名称提供的输入向量的前三个元素:

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()

使用命令:

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

我收到错误

Python Exception <class 'gdb.error'> Cannot subscript requested type.: 
Error occurred in Python command: Cannot subscript requested type.

这是指print(val[0])行。问题是gdb.Value对象不能作为列表进行索引。还有其他方法可以访问元素吗?

我也尝试过像val['at'][0]val['at(0)']这样的东西,两者都不起作用。通过一次调用逐个加载元素以gdb.parse_and_eval每个元素都可以工作,但速度太慢。

问题是向 Python

公开的C++对象不是"第一类"Python 对象 - 因此,它们没有映射到相应机制的 Python __getitem__ 方法来获取对象的 "C++" 类中的项。

另一方面,API 确实公开了一个 parse_and_eval 方法,该方法将处理字符串,就好像它是在C++源中键入的一样 - 因此允许人们以简单的方式使用 Python 中的v[i] -

对于上面的示例,您可以将 Python 源代码更改为:

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()

看看这个工作。对于更复杂的代码,可能值得在 Python for gdb 中创建一个包装类。将实现自动执行此操作的__getitem__的值对象。

我最终在 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

如果std_vector是包含std::vector<T>gdb.Value对象,则此函数返回类型为 Tgdb.Value 对象的 python 列表。基于这篇博文:https://hgad.net/posts/object-inspection-in-gdb/

我发现这比为所有i调用gdb.parse_and_eval['v[i]']要快得多

最新更新