C 如何在gdb中逐步完成longjmp

C 如何在gdb中逐步完成longjmp,c,gdb,setjmp,C,Gdb,Setjmp,我正试图修复别人编写的代码中的一个bug,并且我正试图在gdb中一步一步地检查它,以了解到底发生了什么。但我遇到的一行是对longjmp()的调用,在该行中遇到“next”之后,gdb继续常规执行,而不是在正在执行的下一个源行中断。如果我在longjmp()行上尝试“step”,则会出现类似的continue。是否有任何gdb命令可用于在longjmp()之后执行的下一个源代码行中断?您需要通过setjmp在非零返回代码之后的行设置断点 例如: #include <stdio.h>

我正试图修复别人编写的代码中的一个bug,并且我正试图在gdb中一步一步地检查它,以了解到底发生了什么。但我遇到的一行是对longjmp()的调用,在该行中遇到“next”之后,gdb继续常规执行,而不是在正在执行的下一个源行中断。如果我在longjmp()行上尝试“step”,则会出现类似的continue。是否有任何gdb命令可用于在longjmp()之后执行的下一个源代码行中断?

您需要通过
setjmp
在非零返回代码之后的行设置断点

例如:

#include <stdio.h>
#include <setjmp.h>

jmp_buf jb;

void f1()
{
    printf("jumping\n");
    longjmp(jb, 1);
    printf("what???\n");
}

int main()
{
    if (!setjmp(jb)) {
        printf("calling f1\n");
        f1();
    } else {
        printf("jumped!!\n");    // line 19
    }
    return 0;
}
在longjmp()之后执行的下一个源代码行上是否有任何gdb命令可以用来中断

据我所知,没有。您需要跟踪
jmp_buf
的起源,备份调用堆栈以找到填充它的
setjmp()
。如果<代码> SETJMP()>源代码中的调用很少,则可以考虑在每个设置后设置断点。否则,您可能只需单步执行程序,在每次传递
setjmp()
后设置一个断点

还要注意,当到达相应的
longjmp()
时,您确实应该在调用堆栈中的一个函数中找到相关的
setjmp()
,否则
jmp\u buf
无效


您可以使用
bt
命令获取调用堆栈,使用
frame
命令切换并检查堆栈上的任何帧。

值得注意的是,gdb的行为取决于系统

在Linux上,通过
longjmp
throw
执行的
next
工作原理与您预期的大致相同:如果非本地跳转的目标位于或高于当前帧,则执行将停止在那里

这是在
longjmp
throw
的实现中使用调试挂钩实现的。对于
throw
来说,这可以通过辅助函数(旧方法)和所谓的SystemTap探测(也称为“sdt探测”)来完成。对于
longjmp
,这仅通过glibc中的sdt探针完成

为此,必须将探测支持编译到相关库中。您可以使用
readelf-n
进行检查。至少Fedora做得很好

理论上,在gdb中为其他平台实现对
longjmp
的支持是可能的。然而,这可能不是小事

您可以尝试解码
jmp_buf
,如其他注释中所述。但是请注意,在某些系统上,例如Linux,出于安全原因,
jmp_buf
中的目标PC被编码。所以你必须弄清楚如何解码它


另一种方法是单步执行
longjmp
本身。在那里设置一个断点,比如
breaklongjmp
;使用
拆解
查看组件;然后执行
si
,直到您单步执行将执行转移到目标的指令。

您可以执行
中断main
,然后
运行
并保持
单步执行程序。然后它会在每一行提示输入,包括longjmp()之后的一行。(如果这回答了你的问题,我会把它放在一个答案中)如果你在那行中点击“步骤”而不是“下一步”,会发生什么?您可以做的一件事是在代码上添加一个断点,用于处理
setjmp()
@MDXF中的非零返回值,很明显,您的目的是使用
步骤
命令而不是
下一个
命令吗?医生说那对他不起作用。我知道你特别建议在
main
处中断,但我不明白为什么这会与在
longjmp()
之前在其他地方中断有所不同。这基本上是可行的。花了一点搜索来找出最后调用的setjmp是什么,但是在足够多的setjmp非零返回后放置断点之后,我最终找到了程序的去向。