如何在GDB函数断点中获取正确this指针以设置条件断点?
GDB调试C++成员函数时this指针异常的解决方法
问题场景
在GDB中为C++构造函数、析构函数或成员方法设置断点时,触发断点后显示的this指针值往往不符合预期。仅当函数包含至少一行代码时,触发断点后执行一次单步调试,this才会显示正确值,但存在以下困扰:
- 构造函数、析构函数可能为默认空实现,成员方法也可能为空,无法进行单步调试;
- 无法直接配置断点触发时自动执行单步再继续的命令序列,因为单步命令会中断后续的
continue执行; - 初始显示的
this值错误,无法直接基于已知对象地址设置条件断点。
示例代码(MyClass.cpp)
#include <iostream> class MyClass { public: MyClass() { std::cout << "MyClass() constructor, this = " << this << std::endl; } void someMethod() { std::cout << "someMethod(), this = " << this << std::endl; } ~MyClass() { std::cout << "MyClass() destructor, this = " << this << std::endl; } }; int main(int argc, char **argv) { MyClass *myClass = new MyClass(); std::cout << "MyClass located at = " << myClass << std::endl; myClass->someMethod(); delete myClass; }
编译命令
g++ -std=c++14 -g -o MyClass MyClass.cpp
异常的GDB执行过程
$ gdb ./MyClass GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2 ... Reading symbols from ./MyClass... (gdb) b MyClass::MyClass Breakpoint 1 at 0x1352: file MyClass.cpp, line 6. (gdb) b MyClass::~MyClass Breakpoint 2 at 0x13ee: file MyClass.cpp, line 14. (gdb) b MyClass::someMethod Breakpoint 3 at 0x13a0: file MyClass.cpp, line 10. (gdb) b 11 Breakpoint 4 at 0x13b0: file MyClass.cpp, line 11. (gdb) r Starting program: /home/ostkamp/src/cpp_examples/MyClass Breakpoint 1, MyClass::MyClass (this=0x7ffff7e7bb39 <operator new(unsigned long)+25>) at MyClass.cpp:6 6 MyClass() { (gdb) c Continuing. MyClass() constructor, this = 0x55555556aeb0 MyClass located at = 0x55555556aeb0 Breakpoint 3, MyClass::someMethod (this=0x7ffff7f037a3 <std::ostream::flush()+35>) at MyClass.cpp:10 10 void someMethod() { (gdb) c Continuing. Breakpoint 4, MyClass::someMethod (this=0x55555556aeb0) at MyClass.cpp:11 11 std::cout << "someMethod(), this = " << this << std::endl; (gdb) c Continuing. someMethod(), this = 0x55555556aeb0 Breakpoint 2, MyClass::~MyClass (this=0x55555556aeb0, __in_chrg=<optimized out>) at MyClass.cpp:14 14 ~MyClass() { (gdb) c Continuing. MyClass() destructor, this = 0x55555556aeb0 [Inferior 1 (process 9105) exited normally] (gdb)
可见构造函数(第6行)、someMethod(第10行)的断点显示无效this信息,而someMethod内部(第11行)的断点显示正确this,析构函数(第14行)表现不稳定。
解决方案
1. 获取正确的this指针
问题根源在于:在源码的函数声明行设置断点时,函数栈帧尚未完全建立,this指针的寄存器值还未被正确映射到调试符号的变量中。正确的做法是直接在函数的机器码入口处设置断点,此时栈帧已初始化完成,this值准确。
设置方法:
- 在GDB中使用
break *<函数名>(函数名前加星号)的命令,例如:# 给构造函数设置机器码入口断点 (gdb) break *MyClass::MyClass # 给成员方法设置机器码入口断点 (gdb) break *MyClass::someMethod # 给析构函数设置机器码入口断点 (gdb) break *MyClass::~MyClass - 对于默认生成的空构造/析构函数(无源码行),可以先通过
info functions找到函数地址,再用break *<地址>设置断点:(gdb) info functions MyClass::MyClass All functions matching regular expression "MyClass::MyClass": File MyClass.cpp: 0x0000555555555355 MyClass::MyClass(); (gdb) break *0x0000555555555355
2. 针对已知对象地址设置条件断点
利用机器码入口断点的特性,此时this值已经正确,可直接添加条件判断,仅当指定对象调用函数时触发断点:
# 仅当地址为0x55555556aeb0的对象调用someMethod时触发断点 (gdb) break *MyClass::someMethod if this == 0x55555556aeb0 # 针对默认构造函数的条件断点 (gdb) break *MyClass::MyClass if this == 0x55555556aeb0
内容的提问来源于stack exchange,提问作者ostkamp
相关产品推荐
相关产品推荐

