问题标签 [stack-unwinding]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c - 操作 x64 展开信息以匹配装配钩子
编辑:我似乎弄错了,回溯在 Linux 上的任何地方都能很好地工作——只有当从 ubuntu 上的 gdb 远程调试到远程窗口时,在 msvcrt 中输入内存分配函数之一后,stacktrace 才会被完全破坏。 . 该死的微软。
这发生在 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 正确重建回溯?
如果没有简单的技巧或技巧,那么我解决此问题的所有选择是什么?
编辑:只是为了清除所有内容的确切调用顺序:
这是我要捕获回溯的“用户定义的回调”
gcc - 是否可以在目标文件上生成展开表
背景是我们有一个没有展开表的预构建目标文件,但不知何故 gcc unwind 在对象上回溯有问题。是否可以在没有源代码的情况下生成展开表?考虑到展开表是基于堆栈静态的,即使没有源代码也可以使用。
c++ - _Unwind_ 和 unw_ 函数(LLVM 的 libunwind)
我是 LLVM 的 libunwind 库的新手。能否请您告诉我libunwind提供的两组功能的目的和区别是什么:
- 带有前缀 _Unwind_ 的函数
- 带有前缀 unw_ 的函数
c++ - 为什么程序突然终止?
执行上述代码时,程序突然终止。
- 为什么会突然结束?
- 如何处理这种异常?
注意:这是在线测试中提出的。
rust - 在 `#![no_std]` 模式下是否可以解除恐慌?
是否可以在模式下解除恐慌#![no_std]
,例如使用自定义#[panic_handler]
?
c++ - 在异常期间 C++ 堆栈展开期间,本地异常值存储在哪里
我熟悉 C++ 异常的心理模型,以及如何以编程方式控制它。例如,此答案中的所有内容:SO Question on topic
然而,让我感到困惑的是,如果异常对象是在抛出堆栈帧中实例化的值,并且当前帧和任意数量的先前帧被展开,那么如何保留异常对象(catch 能够拦截的内容)所有拥有的本地人都被破坏(如果用 RAII 编写)合规性。为了使事情变得不那么容易理解,建议的模式是按value抛出,并按const&捕获...一个堆栈已经消失的值?...在很久以前被破坏的帧上引用一个可能未命名的值?我显然错过了一些东西。引用 exited-local-function-objects 是一个典型的新手错误,但在这种情况下,建议这样做。我推测与用户代码混合的 throw catch 模式是一种错觉,其实现完全不同,但这让我仍然想知道,(隐式未分配堆)异常对象存储在哪里,因此可以在运行时捕获它-变量位置,考虑到它的值似乎存储在其中的堆栈帧注定要立即展开?
编辑:受@RichardCritten 的“实现细节响应”启发的一些切题问题:如果异常对象被实例化为左值而不是抛出怎么办?如果这样的左值被参数化和争论,然后被另一个函数抛出(它保证仍然知道抛出上下文)怎么办?如果对象是用 new 分配的,并且它的引用被用来抛出怎么办?您是否被迫“按照建议使用例外,并相信它们会按照标准要求行事”?
c++ - 未捕获 C++ 异常,程序以中止终止
该程序在异常处理程序被捕获之前终止
我想处理异常处理程序,但程序在堆栈展开期间终止。我该怎么做才能确保在堆栈展开期间加入线程?
c++ - 如果一个对象是在本地创建的并在 C++ 中作为异常抛出,那么本地对象如何在其范围之外有效。即在 catch 块中?
在 try 块中,调用了函数“fun()”。在“fun”内部创建了一个“abc”类的本地对象,并引发了异常。这个本地对象在“catch”块中被捕获,并且打印了一个正确的值。由于这个对象是在本地创建的,它不应该打印“0(默认值)”,因为调用 throw 时会发生堆栈展开。
输出:
在 abc
内的 fun()内尝试:10
我的期望:在 abc
中的 fun()中尝试
:0
debugging - 为什么我们需要编译器发出的 DWARF eh_frame?
在调试期间或我们的代码遇到异常时,我eh_frame
需要使用红色。stack unwinding
现在我的问题是,调试器不能只是遍历堆栈并通过查找rbp
被推送或弹出来找出帧之间的边界吗?为什么我们需要发出额外的调试信息?
c - 使用 libunwind 实现异常
在编译器上工作,需要一些帮助来理解和使用 libunwind。这是我到目前为止所拥有的:
好吧,这已经很混乱了,但是一些上下文可能有助于证明奇怪的选择是正确的。我想做的是在调用throw_exception
后的任何时候调用调用堆栈set_try
,foo
以便展开堆栈并将CPU状态恢复到调用之后set_try
但条件之前的状态。虽然这目前只是一个小型 C 程序,但我打算在编译器中使用这些函数的一般结构,以生成必要的函数调用(类似于在 C++ 中使用 g++ 完成异常的方式),这就是为什么我有label+goto 作为一种快速模仿我将要生成的程序集的方法。我尝试过使用 libunwind 的 setjmp 实现,但它不太适合我的用例。
我遇到的问题与unw_resume
展开调用堆栈后的恢复位置有关。printf("This should never run\n")
无论如何,似乎每次都会运行。我的理解是它应该将堆栈和 CPU 状态恢复到调用时存储的任何状态unw_getcontext
,并且我认为存储的状态是正确的,因为 IP 寄存器(或 PC 寄存器,因为这是 x86_64)的值当我调用set_try
and时,光标中的内容完全相同throw_exception
。我什至在调用 set_try 之后和条件之前多次跳入 gdb 来查看 PC 寄存器,并且每次都匹配打印输出。
我的问题是:
- 我误会了
unw_resume
吗? - 我是否需要修改 PC (UNW_REG_IP) 寄存器?
- 是否有其他地方(除了 nongnu.org 文档)我可以寻求有关 libunwind 的帮助?
提前致谢!