linux 使用gdb获取所有线程的回溯所需的最小coredump

06odsfpq  于 2023-04-20  发布在  Linux
关注(0)|答案(1)|浏览(114)

我们想从正在运行的进程中提取堆栈跟踪。直接使用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)?

r1wp621o

r1wp621o1#

gdb实际上需要什么来获取回溯?
1.所有线程的堆栈(很明显)
1.足够的堆来恢复_DYNAMIC[].r_debug->r_mapstruct 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少很多“聊天”,当网络延迟很大时,这可能有助于速度。

相关问题