【发布时间】:2018-11-09 19:18:01
【问题描述】:
编辑:我似乎弄错了,回溯跟踪在 Linux 上的任何地方都可以很好地工作——只有当从 ubuntu 上的 gdb 远程调试到远程窗口时,堆栈跟踪在进入其中一个内存后才会被完全破坏msvcrt 中的分配函数...该死的微软。
这发生在 64 位和 32 位窗口中,所以我不确定这与展开信息有关...
编辑:添加 -g3 和 -Og 似乎有助于解决某些程序中的部分问题,但问题仍然存在于其他程序中,无法在此处发布其源代码,因为它是我公司的 IP——抱歉!
背景
我使用 gcc 编译 ubuntu->ubuntu 和 mingw 编译 ubuntu->windows。
我创建了一个跨平台(linux + windows)内存跟踪和泄漏检测库,它在第一条指令(不是 IAT/PLT 挂钩)上将 malloc/calloc/realloc/free 与程序集字节补丁挂钩。
钩子重定向到一个门,该门检查钩子是否在当前线程中启用,如果是,则重定向到内存跟踪钩子函数,否则它只是重定向到实际函数的蹦床,如果它们被该线程禁用.
该库运行良好,可以检测 linux/windows 上的泄漏(可能适用于 mac,但我没有)。
我使用该库以编程方式检测代码中的泄漏,我可以在内存分配例程上安装回调并以编程方式引发断点(通过循环并等待调试器附加,然后在回调中执行 asm("int3"))这样我就可以在调用内存泄漏时附加到我的程序。
在我尝试从回调中查看回溯之前,一切正常,我知道这可能是因为展开信息可能不再与我的堆栈匹配,因为我已经通过我的钩子例程插入了新的帧和数据插入。
编辑:如果我误认为展开信息与堆栈不匹配是导致回溯不正确的原因,请纠正我!
问题
我可以做一些小技巧来欺骗 GDB 从我的钩子回调中正确重建回溯吗?
我知道我可以使用 libdwarf 或其他工具手动行走和编辑展开信息,但我想这会非常麻烦和庞大。
所以我想知道我是否可以做一些黑客或作弊来欺骗 GDB 正确重建回溯?
如果没有简单的技巧或技巧,那么我有哪些解决此问题的选择?
编辑:只是为了清除所有内容的确切调用顺序:
program
V
malloc
V
hook_malloc -> hooks are disabled -> return malloc trampoline -> real malloc > program
V
hooks are enabled
V
Call original malloc -> malloc trampoline -> real malloc -> returns to hook
V
Record memory size/info etc from malloc
V
Call user defined callback -> **User defined callback* -> returns to hook
V
return to program
这是我要捕获回溯的“用户定义的回调”
【问题讨论】:
-
如果你通过尾调用离开蹦床,那么它对任何堆栈跟踪器都将变得“透明”。如果可能的话,这将是最简单的。
-
@zch 我尝试在我的原始帖子中添加一棵解释调用顺序的树,您会看到仅在需要调用原始 malloc 时才调用蹦床。我想回溯的地方是用户定义的回调。首先 malloc 被重定向到 hook_malloc,然后 hook_malloc 调用原始 malloc 来分配内存,然后 hook_malloc 调用用户定义的 malloc 回调(我在初始化库时从我的代码中安装)。在这里我想创建一个回溯,但是 hook_malloc 和用户定义的回调已经显着改变了堆栈。
-
在这个断点处,堆栈上是否有任何无矮帧?如果是这样,您可以跳转(尾调用)到一个 C 函数中,从堆栈中删除该帧,就好像它从未存在过一样。这个 C 函数将完成核心工作,包括调用任何其他函数,包括用户提供的函数。
-
是的,hook_malloc 将创建一个框架,而用户定义的回调将创建一个框架,两者都没有用于展开的 DWARF 信息。所以你是说如果我从用户定义的回调中退出以丢弃那些我应该能够生成回溯的帧?我得看看我能不能让它工作:)
标签: c assembly dwarf stack-unwinding