简体   繁体   English

如何在gdb中逐步通过longjmp

[英]How to step through a longjmp in gdb

I'm trying to fix a bug in code someone else wrote, and I'm trying to step though it in gdb to figure out what is going on. 我正在尝试修复其他人编写的代码中的错误,并且试图在gdb中逐步解决该问题。 But one of the lines I hit is a call to longjmp(), and after hitting "next" on that line gdb continues regular execution rather than breaking on the next source line being executed. 但是我打的一行是对longjmp()的调用,在该行上打了“ next”之后,gdb继续常规执行,而不是中断正在执行的下一个源代码行。 Similar continue occurs if I try "step" on the longjmp() line. 如果我在longjmp()行上尝试“ step”,则会发生类似的继续。 Is there any gdb command I can use to break on the next source line being executed after longjmp()? 在longjmp()之后正在执行的下一个源代码行上,有没有什么我可以用来中断的gdb命令?

It's worth noting that gdb's behavior is system-dependent. 值得注意的是,gdb的行为与系统有关。

On Linux, next over a longjmp or throw works approximately as you would expect: if the target of the non-local jump is at or above the current frame, execution will stop there. 在Linux上,通过longjmpthrow next工作大致与您期望的一样:如果非本地跳转的目标位于当前帧或当前帧之上,则执行将在此处停止。

This is implemented using debugging hooks in the implementations of longjmp and throw . 这是在longjmpthrow实现中使用调试钩子实现的。 For throw this is done both with a helper function (the older approach) and with so-called SystemTap probes (aka "sdt probes"). 对于throw这可以通过辅助函数(较旧的方法)和所谓的SystemTap探针(也称为“ sdt探针”)来完成。 For longjmp this is done only with sdt probes in glibc. 对于longjmp仅使用glibc中的sdt探针完成此操作。

For this to work the probe support must be compiled into the libraries in question. 为此,必须将探针支持编译到相关的库中。 You can check with readelf -n . 您可以使用readelf -n检查。 At least Fedora does this properly. 至少Fedora可以正确执行此操作。

It's possible in theory to implement support for longjmp for other platforms in gdb. 从理论上讲,有可能为gdb中的其他平台实现对longjmp支持。 However, it may be non-trivial. 但是,这可能并不简单。

You can try to decode the jmp_buf , as mentioned in other comments. 您可以尝试解码jmp_buf ,如其他注释中所述。 Note however that on some systems, such as Linux, the target PC in the jmp_buf is encoded, for security reasons. 但是请注意,出于安全原因,在某些系统(例如Linux)上, jmp_buf的目标PC已编码。 So you will have to figure out how to decode it. 因此,您将必须弄清楚如何对其进行解码。

Another way to approach this is to simply single-step through longjmp itself. 解决此问题的另一种方法是简单地单步执行longjmp本身。 Set a breakpoint there, like break longjmp ; 在此处设置一个断点,例如break longjmp ; use disassemble to view the assembly; 使用disassemble查看组装; and then si until you step through the instruction that transfers execution to the target. 然后si直到您逐步完成将执行转移到目标的指令为止。

You need to set a breakpoint at the line following a non-zero return code by setjmp . 您需要通过setjmp非零返回码之后的行上设置断点。

For example: 例如:

#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;
}

After calling longjmp , the next line to be executed is line 19 (see comment). 调用longjmp ,要执行的下一行是第19行(请参见注释)。 So in this case run break 19 at the gdb prompt and you'll stop at that line after the call to longjmp . 因此,在这种情况下,请在gdb提示符下运行break 19 ,然后在longjmp调用之后停在该行。

gdb output: 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)

Is there any gdb command I can use to break on the next source line being executed after longjmp()? 在longjmp()之后正在执行的下一个源代码行上,有没有什么我可以用来中断的gdb命令?

Not as far as I know, no. 据我所知,不。 You'll need to trace the origin of the jmp_buf back up the call stack to find the setjmp() by which it was filled. 您需要在调用堆栈中追溯jmp_buf的起源,以找到填充它的setjmp() If setjmp() calls in the source are few, you might consider setting a breakpoint after each. 如果源中的setjmp()调用很少,则可以考虑在每个调用之后设置一个断点。 Otherwise, you might just step through the program, setting a breakpoint after each setjmp() you pass. 否则,您可能只是单步执行程序,在传递的每个setjmp()之后设置一个断点。

Note also that you indeed should find the relevant setjmp() in one of the functions in the call stack when the corresponding longjmp() is reached, for otherwise the jmp_buf is invalid. 还要注意,当达到相应的longjmp()时,您确实应该在调用堆栈中的一个函数中找到相关的setjmp() ,否则jmp_buf无效。

You can use the bt command to get a call stack, and the frame command to switch to and inspect any frame on the stack. 您可以使用bt命令来获取调用堆栈,使用frame命令来切换并检查堆栈中的任何帧。

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

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