如何在析构函数
lldb
的 ~shared_ptr
中设置符号断点?
上下文:我们想在演示程序中检查一个简单实现的前向链表的堆栈溢出,其中丢弃包含 100,000 个元素的列表会溢出,因为每个节点的析构函数都会触发它的
->next
析构函数。
#include <memory>
class Test {
public:
Test() : a(1) { }
int a;
};
int main() {
auto sptr = std::make_shared<Test>();
return 0;
}
尝试断点(最后一个是自动完成建议的):
(lldb) br set --name std::__1::shared_ptr<Test>::~shared_ptr
WARNING: Unable to resolve breakpoint to any actual locations.
(lldb) br set --name std::__1::shared_ptr<Test>::~shared_ptr[abi:v160006]()
WARNING: Unable to resolve breakpoint to any actual locations.
有多种方法可以做到这一点。
首先,只是为了让测试变得更有趣一点 比
shared_ptr
的一个实例,我将示例更改为:
#include <iostream>
#include <memory>
struct Test {
~Test() { std::cout << "in ~Test\n"; }
};
struct Test2 {
~Test2() { std::cout << "in ~Test2\n"; }
};
int main() {
auto sptr = std::make_shared<Test>();
auto sptr2 = std::make_shared<Test2>();
return 0;
}
然后我编译并启动调试器:
$ clang++ -o prog -g -Wall prog.cc
$ lldb ./prog
breakpoint set --name
breakpoint set --name
命令在所有函数上设置断点
给定的名字:
(lldb) breakpoint set --name ~shared_ptr
Breakpoint 1: 2 locations.
(lldb) breakpoint list
Current breakpoints:
1: name = '~shared_ptr', locations = 2
1.1: where = prog`std::shared_ptr<Test2>::~shared_ptr() + 16 at shared_ptr.h:103:11, address = prog[0x0000000000001440], unresolved, hit count = 0
1.2: where = prog`std::shared_ptr<Test>::~shared_ptr() + 16 at shared_ptr.h:103:11, address = prog[0x0000000000001460], unresolved, hit count = 0
它也可以使用更完整的名称,但是
__1
的东西不应该
在那里:
(lldb) br set --name std::__1::shared_ptr<Test>::~shared_ptr
Breakpoint 1: no locations (pending).
WARNING: Unable to resolve breakpoint to any actual locations.
(lldb) br set --name std::shared_ptr<Test>::~shared_ptr
Breakpoint 2: where = prog`std::shared_ptr<Test>::~shared_ptr() + 16 at shared_ptr.h:103:11, address = 0x0000000000001460
注意:
br
是breakpoint
的别名。
breakpoint set --method
breakpoint set --method <name>
命令在所有
具有给定名称的方法:
(lldb) breakpoint set --method ~shared_ptr
Breakpoint 1: 2 locations.
(lldb) breakpoint list
Current breakpoints:
1: name = '~shared_ptr', locations = 2
1.1: where = prog`std::shared_ptr<Test2>::~shared_ptr() + 16 at shared_ptr.h:103:11, address = prog[0x0000000000001440], unresolved, hit count = 0
1.2: where = prog`std::shared_ptr<Test>::~shared_ptr() + 16 at shared_ptr.h:103:11, address = prog[0x0000000000001460], unresolved, hit count = 0
breakpoint set --func-regex
breakpoint set --func-regex <regex>
命令设置断点
名称与正则表达式匹配的所有函数:
(lldb) breakpoint set --func-regex "^std::shared_ptr<.*>::~shared_ptr\(\)$"
Breakpoint 1: 2 locations.
(lldb) breakpoint list
Current breakpoints:
1: regex = '^std::shared_ptr<.*>::~shared_ptr\(\)$', locations = 2
1.1: where = prog`std::shared_ptr<Test>::~shared_ptr() + 16 at shared_ptr.h:103:11, address = prog[0x0000000000001460], unresolved, hit count = 0
1.2: where = prog`std::shared_ptr<Test2>::~shared_ptr() + 16 at shared_ptr.h:103:11, address = prog[0x0000000000001440], unresolved, hit count = 0
这使用起来比较麻烦,但精度更高。
使用
b <file>:<line>
,您可以将断点放入所有实例化中
该位置的方法:
(lldb) b shared_ptr.h:103
warning: (x86_64) /home/scott/wrk/learn/lldb/break-in-shared-ptr-dtor/prog 0x000034a5: DW_AT_specification(0x000000000000088e) has no decl
warning: (x86_64) /home/scott/wrk/learn/lldb/break-in-shared-ptr-dtor/prog 0x000034c6: DW_AT_specification(0x0000000000000110) has no decl
Breakpoint 1: 2 locations.
(lldb) breakpoint list
Current breakpoints:
1: file = 'shared_ptr.h', line = 103, exact_match = 0, locations = 2
1.1: where = prog`std::shared_ptr<Test2>::~shared_ptr() + 16 at shared_ptr.h:103:11, address = prog[0x0000000000001440], unresolved, hit count = 0
1.2: where = prog`std::shared_ptr<Test>::~shared_ptr() + 16 at shared_ptr.h:103:11, address = prog[0x0000000000001460], unresolved, hit count = 0
如果您知道该方法在哪里,那么这是相当简单和精确的 实施的。我不知道为什么它会发出那些“没有 decl”警告, 但 LLDB 做这类事情并不罕见。
注意:
b
和breakpoint
是不同的命令!
使用这些方法中的任何一种,您都可以在其中一个中放置一个断点 您自己的代码中定义的析构函数:
(lldb) breakpoint set --method ~Test
Breakpoint 1: where = prog`Test::~Test() + 12 at prog.cc:5:25, address = 0x0000000000001e2c
(lldb) run
Process 588466 launched: '/home/scott/wrk/learn/lldb/break-in-shared-ptr-dtor/prog' (x86_64)
in ~Test2
Process 588466 stopped
* thread #1, name = 'prog', stop reason = breakpoint 1.1
frame #0: 0x0000555555555e2c prog`Test::~Test(this=0x000055555556cec0) at prog.cc:5:25
2 #include <memory>
3
4 struct Test {
-> 5 ~Test() { std::cout << "in ~Test\n"; }
6 };
7
8 struct Test2 {
(lldb) symbol table for <Unknown>.....K [weird msg, I hit Ctrl-C]
error: No auto repeat.
(lldb) bt
* thread #1, name = 'prog', stop reason = breakpoint 1.1
* frame #0: 0x0000555555555e2c prog`Test::~Test(this=0x000055555556cec0) at prog.cc:5:25
frame #1: 0x0000555555555e19 prog`void __gnu_cxx::new_allocator<Test>::destroy<Test>(this=0x000055555556cec0, __p=0x000055555556cec0) at new_allocator.h:153:10
frame #2: 0x0000555555555dbd prog`void std::allocator_traits<std::allocator<Test>>::destroy<Test>(__a=0x000055555556cec0, __p=0x000055555556cec0) at alloc_traits.h:497:8
frame #3: 0x0000555555555bd6 prog`std::_Sp_counted_ptr_inplace<Test, std::allocator<Test>, (__gnu_cxx::_Lock_policy)2>::_M_dispose(this=0x000055555556ceb0) at shared_ptr_base.h:557:2
frame #4: 0x0000555555555503 prog`std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release(this=0x000055555556ceb0) at shared_ptr_base.h:155:6
frame #5: 0x00005555555554ba prog`std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count(this=0x00007fffffffe4e0) at shared_ptr_base.h:730:11
frame #6: 0x0000555555555579 prog`std::__shared_ptr<Test, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr(this=0x00007fffffffe4d8) at shared_ptr_base.h:1169:31
frame #7: 0x0000555555555465 prog`std::shared_ptr<Test>::~shared_ptr(this=nullptr) at shared_ptr.h:103:11
frame #8: 0x000055555555524f prog`main at prog.cc:16:1
frame #9: 0x00007ffff7a9c0b3 libc.so.6`__libc_start_main + 243
frame #10: 0x000055555555514e prog`_start + 46
也许停在被调用者就足够了,或者也许看到所需的符号 其在回溯中的文件名有助于实现目标。
我通过阅读以下内容获得了大部分信息 断点命令 的部分 GDB 到 LLDB 命令映射,加上 实验。