繁体   English   中英

如何在gdb中逐步通过longjmp

[英]How to step through a longjmp in gdb

我正在尝试修复其他人编写的代码中的错误,并且试图在gdb中逐步解决该问题。 但是我打的一行是对longjmp()的调用,在该行上打了“ next”之后,gdb继续常规执行,而不是中断正在执行的下一个源代码行。 如果我在longjmp()行上尝试“ step”,则会发生类似的继续。 在longjmp()之后正在执行的下一个源代码行上,有没有什么我可以用来中断的gdb命令?

值得注意的是,gdb的行为与系统有关。

在Linux上,通过longjmpthrow next工作大致与您期望的一样:如果非本地跳转的目标位于当前帧或当前帧之上,则执行将在此处停止。

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

为此,必须将探针支持编译到相关的库中。 您可以使用readelf -n检查。 至少Fedora可以正确执行此操作。

从理论上讲,有可能为gdb中的其他平台实现对longjmp支持。 但是,这可能并不简单。

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

解决此问题的另一种方法是简单地单步执行longjmp本身。 在此处设置一个断点,例如break longjmp ; 使用disassemble查看组装; 然后si直到您逐步完成将执行转移到目标的指令为止。

您需要通过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 ,要执行的下一行是第19行(请参见注释)。 因此,在这种情况下,请在gdb提示符下运行break 19 ,然后在longjmp调用之后停在该行。

gdb输出:

(gdb) break 19
Breakpoint 2 at 0x40056d: file /tmp/x1.c, line 19.
(gdb) start
Temporary breakpoint 3 at 0x400549: file /tmp/x1.c, line 15.
Starting program: /tmp/x1
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x2aaaaaaab000

Temporary breakpoint 3, main () at /tmp/x1.c:15
15          if (!setjmp(jb)) {
(gdb) step
16              printf("calling f1\n");
(gdb)
calling f1
17              f1();
(gdb)
f1 () at /tmp/x1.c:8
8           printf("jumping\n");
(gdb)
jumping
9           longjmp(jb, 1);
(gdb)

Breakpoint 2, main () at /tmp/x1.c:19
19              printf("jumped!!\n");
(gdb)
jumped!!
21          return 0;
(gdb)
22      }
(gdb)
0x0000003fa441d9f4 in __libc_start_main () from /lib64/libc.so.6
(gdb)

在longjmp()之后正在执行的下一个源代码行上,有没有什么我可以用来中断的gdb命令?

据我所知,不。 您需要在调用堆栈中追溯jmp_buf的起源,以找到填充它的setjmp() 如果源中的setjmp()调用很少,则可以考虑在每个调用之后设置一个断点。 否则,您可能只是单步执行程序,在传递的每个setjmp()之后设置一个断点。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM