gdb调试任意函数

时间:2022-10-16 08:58:21

使用gdb调试时,有的函数只在某些路径上会执行到,而触发这些路径执行的条件构造起来比较麻烦,比如某个server在接收到READ请求时,会调用do_read进行响应,这时如果我们想调试do_read函数,就必须在客户端构造一个READ请求来触发。

int do_read(const ReadRequest& req); 

假设我们知道do_read调用时参数ReadRequest的具体内容,能否直接使用gdb显式的调试do_read,且看下面这个例子。

main函数里没有显式调用get_capacity函数,如果我们想要调试这个函数,最直观的一种方式,当然是将get_capacity加到main里,让其出现在调用路径中即可调试。

gdb的jump可以让程序跳转到任意位置执行,实验了一下,结果是跳转到get_capacity里开始执行时,出现Segmentation fault,因为参数Box的空间没有分配。在了解参数传递顺序及栈布局的情况下,可通过一些出栈、入栈操作,在jump到get_capacity前将参数先准备好,这样get_capacity调用时,就不会有问题,但这样做太过复杂。

struct Box {
  int length;
  int width;
  int height;
};

int get_capacity(const struct Box& box)
{
  int capacity = box.length * box.width * box.height;
  printf("box capacity: %d\n", capacity);
  return capacity;
} 


int main()
{
  printf("main called no functions\n");
  return 0;
} 

gdb的call可以在调试时显式调用函数,需要先把参数准备好。如下所示,在main里设置断点,然后分配出一个box的内存,并对box进行赋值,最后将其最为参数传递给get_capacity函数,get_capacity函数被正确的调用,通过在get_capacity设置断点即可对它进行调试。

(gdb) set $box = (Box*)malloc(sizeof(Box))
(gdb) set $box->length = 3
(gdb) set $box->width = 4
(gdb) set $box->height = 5
(gdb) call get_capacity(*$box)
box capacity: 60
$1 = 60 

针对上面这种方式,存在两个疑问,求达人解惑。

直接使用box对象而不是指针时,传递时有问题,如下:

(gdb) set $box = *(Box*)malloc(sizeof(Box))
(gdb) call get_capacity($box)
Attempt to take address of value not located in memory. 

不能直接使用new来构造对象,对于复杂的类(尤其是拥有虚函数的情况),上面的方式没办法工作。

(gdb) set $box = new Box()
A syntax error in expression, near `new Box()'.