使用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()'.