我们想从正在运行的进程中提取堆栈跟踪。直接使用gstack提取堆栈跟踪不是一个选择,使用gdbserver也可以,但由于网络的原因会非常慢。我们很好奇是否可以使用
gdb --ex "attach $PID" --ex "gcore core_dump_file" --ex "q"
将核心转储复制到包含已编译可执行文件的容器中,然后使用
gdb $PATH_TO_EXECUTABLE core_dump_file --ex "thread apply all bt" --ex "q"
在生产环境中,核心转储可以达到数百GB的大小,因此我们希望尽可能多地过滤核心转储。
写入核心转储的内存部分可以通过在/proc/$PID/coredump_filter
处更改coredump_filter
文件来过滤(参见man page for core)。只要设置了位0(转储匿名私有Map),一切都正常,我们就可以获得预期的回溯。可以使用
echo 0x1 > "proc/$PID/coredump_filter
不幸的是,匿名私有Map非常大,约占未过滤核心转储的75%,例如,在我们的一个测试用例中,0x33
的默认核心转储为5 GB,而0x1
的过滤核心转储仍然是3.8 GB。
如果我们通过将所有位设置为零来尽可能多地过滤
echo 0x0 > "proc/$PID/coredump_filter
产生的核心转储变得非常小,只有一MB的大小(从几个千兆字节的大小下降),但是使用thread apply all bt
失败
Thread 1 (LWP 2653):
#0 0x00007fae7d4218fd in ?? ()
Backtrace stopped: Cannot access memory at address 0x7ffe21387490
使用完全过滤的coredump,我可以看到gdb不知道要加载哪些共享库:
(gdb) info shared
No shared libraries loaded at this time.
gdb实际上需要什么来获取回溯?有没有一种方法可以过滤gdb不需要的所有回溯?有没有一种更好的方法来获取回溯(不一定要使用gdb)?
1条答案
按热度按时间r1wp621o1#
gdb实际上需要什么来获取回溯?
1.所有线程的堆栈(很明显)
1.足够的堆来恢复
_DYNAMIC[].r_debug->r_map
和struct link_map
s的整个链接链,以了解所有DSO的位置。有没有一种方法可以过滤gdb不需要的所有内容?
如果是
coredump_filter
,就没有。有没有更好的方法来获取回溯(不一定要使用gdb)?
有一些方法:
1.你可以在每个线程中安装一个信号处理器(比如
SIGPWR
或其他很少使用的信号)。在信号处理器中,你可以遍历堆栈(例如使用libunwind),并将write
堆栈在某个地方。然后,安排将信号发送到每个线程是一件小事。
1.您可以使用类似Google user-space core dumper的工具,它可以让您完全控制流程的哪些部分保存到
core
中,哪些部分被过滤掉。它还允许您压缩
core
1.您可以尝试使用LLDB而不是GDB。
不幸的是,选项(1)需要相当多非常复杂的async-signal-safe代码,错误可能会导致进程崩溃或死锁。
选项(2)没有这个问题,但最后一次公开发布是在15年前,可能不再有效。
选项(3)可能比GDB快,也可能不快,但据我所知,LLDB可能比GDB/gdbserver少很多“聊天”,当网络延迟很大时,这可能有助于速度。