使用GDB调试器进行C/C++数组和向量的操作与可视化

在调试C/C++程序时,经常需要查看和操作数组和向量。本文将展示如何利用GDB调试器的Python API来实现这一功能。将以一个二维数组的本征值可视化为例,演示如何进行操作。

环境准备

首先,需要确保安装了Python和GDB调试器。此外,还需要安装numpy和matplotlib库,这两个库将用于数组操作和数据可视化。

# 安装numpy和matplotlib pip install numpy matplotlib

创建numpy数组并可视化本征值

假设有一个名为mat的二维数组,想要在调试会话中可视化其本征值。以下是如何操作的步骤:

# 定义数组 float mat[10][10] = ...; # 使用Python代码创建numpy数组 (gdb) py > import gdb_numpy > import numpy as np > import matplotlib.pyplot as plt # 将C/C++数组转换为numpy数组 > mat = gdb_numpy.to_array("mat") # 创建一个与变量mat对应的numpy数组 # 打印数组形状 > print(mat.shape (10,10) # 计算本征值 > y = np.linalg.eigvalsh(mat) # 绘制本征值 > plt.plot(y) > plt.show() # 显示图形

以上代码将显示mat数组的本征值的图形。

注意事项

在使用matplotlib.pyplot或matplotlib.pylab时,必须调用show方法来显示图形。此外,在图形关闭之前,GDB不会响应任何命令。

代码依赖

上述代码依赖于numpy库,它可以从C/C++指针、数组和STL向量创建numpy数组。有关如何安装和使用numpy的更多信息,请访问其官方网站。

# 安装代码 python setup.py install

在GDB控制台中导入gdb_numpy模块:

(gdb) py import gdb_numpy

从C/C++指针/数组/向量类型创建numpy数组,将变量名作为字符串传递给gdb_numpy模块中的to_array函数:

(gdb) py vec = gdb_numpy.to_array("vec") # vec现在是一个numpy数组

如果vec是一个STL向量或内置数组,这将创建一个适当形状的numpy数组。然而,如果vec是一个指针,那么用户必须提供第二个参数来指示其维度。

# 定义指针 float** mat = ...; # 提供维度 (gdb) py > mat = gdb_numpy.to_array("mat", (10,10))

即使只有一个维度,也必须以元组的形式传递:

float* vec = ...; (gdb) py vec = gdb_numpy.to_array("vec", (10))

该方法还支持嵌套类型:

std::vector> mat = ...; > py mat = gdb_numpy.to_array("mat") # mat是一个2D numpy数组

将简要介绍一些gdb-python API(在gdb 7之后支持),这些API在代码中使用。有关gdb中Python API的详细信息,可以在gdb文档中找到。

在gdb控制台中,可以通过命令python(或py)后跟Python命令来访问Python解释器:

(gdb) py print 1 + 2 3

如果没有为命令python提供参数,则将进入多行模式:

(gdb) py > x = 1 + 2 > print x > end 3

正在调试的C/C++程序中的变量可以在Python中使用gdb模块的parse_and_eval方法访问,该模块在通过gdb访问Python解释器时自动导入。

(gdb) py my_var = gdb.parse_and_eval("my_var")

parse_and_eval返回gdb.Value类型的实例,其中包含C/C++变量的信息。例如,可以通过type成员访问C/C++类型的名称:

(gdb) py > my_array = gdb.parse_and_eval("my_array") > print my_array.type > end double[10]

类成员可以通过索引操作符访问:

(gdb) py > my_class = gdb.parse_and_eval("my_class") > my_data = my_class['data'] # 获取my_class.data

如果变量是指针类型,则可以使用索引来解引用它:

(gdb) py print my_data[10]

扩展代码

该模块可以扩展以适应自定义容器类型。这涉及到从模块deref中的DeRefBase类派生。假设有一个用户定义的矩阵类型,希望扩展该模块以使其工作:

template class MyMatrix { public: T& operator()(int i, int j) { return data[i*columns+j]; } const T& operator()(int i, int j) const { return data[i*columns+j]; } private: T* data; int rows; int columns; };

该类型将其底层数据存储在成员data中,以便如果M是MyMatrix的实例,则M(i,j)由*(M.data+i*M.columns+j)给出。

首先,需要覆盖DeRefBase中的deref方法,该方法用于解引用容器。这是通过解引用MyMatrix实例的成员data来完成的。

def deref(self, val, indices): data = val['data'] columns = int(val['columns']) return data[indices[0] * columns + indices[1]]

例如,以下代码解引用了矩阵:

# derefMyMat是一个适当的DeRef类实例 (gdb) py print derefMyMat.deref(Mat,(i,j)) # 给出Mat(i,j)

接下来,需要更新并初始化类的某些成员。成员bounds存储矩阵的维度。

def __init__(self, Mat, shape_ind, shape): super(DeRefMyMatrix, self).__init__(Mat, shape_ind, shape) self.val = self.deref(Mat, [0,0]) # 更新为解引用类型 self.bounds = [Mat['rows'], Mat['columns']] # 矩阵的维度

其他需要更新的类成员是val。这应该是一个gdb.Value实例,对应于解引用后的对象。

self.val = self.deref(Mat,(0,0))

由于self.val的值不会被使用,所以在deref方法中使用什么索引并不重要,只要它是一个有效的索引即可。例如,也可以这样使用:

self.val = self.deref(Mat, (self.bounds[0]-1, self.bounds[1]-1)) # 只要索引有效就可以

最后,需要提供一个正则表达式来识别类。这应该是与类的类型名称匹配的内容,可以通过gdb.Value实例的type成员访问。

(gdb) py my_mat = gdb.parse_and_eval("my_mat") (gdb) py print my_mat.type MyMatrix

因此,在案例中,模式可以是^MyMatrix。

class DeRefMyMatrix(DeRefBase): pattern = re.compile('^MyMatrix') ...

需要编写的Python类是:

class DeRefMyMatrix(DeRefBase): pattern = re.compile('^MyMatrix') def __init__(self, Mat, shape_ind, shape): super(DeRefMyMatrix, self).__init__(Mat, shape_ind, shape) self.val = self.deref(Mat, [0,0]) # 更新为解引用类型 self.bounds = [Mat['rows'], Mat['columns']] # 矩阵的维度 def deref(self, val, indices): data = val['data'] columns = int(val['columns']) return data[indices[0] * columns + indices[1]]

要在gdb_numpy模块中使用此类,需要将其添加到模块中的_container_list变量。

_container_list = [... ,deref.DeRefMyMatrix]

现在可以使用gdb_numpy.to_array方法与MyMatrix类一起使用。它还将自动支持嵌套类型,例如:

MyMatrix> 4DTensor = ...; std::vector> 3DTensor = ...; MyMatrix> Another3DTensor = ...;
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485