我怎样才能使GDB停止在SIGTRAP只在断点? [英] How can I make GDB stop at SIGTRAP only at breakpoints?

查看:403
本文介绍了我怎样才能使GDB停止在SIGTRAP只在断点?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图调试一个通常会导致GDB停止的程序,并在不处于断点时显示SIGTRAP。它发生在加载动态库和其他普通的东西时。在我的断点最终被击中之前,有1000个这样的事件发生,所以我手动继续所有这些不相关的SIGTRAPs是不可行的。但是如果我使用命令处理SIGTRAP nostop noprint ,那么GDB不会停在我的断点处。

似乎必须有一种方法来教育GDB,以便它了解哪种SIGTRAP适合停止,哪些不适合停止。显然GDB知道它是否处于断点处,因为输出非常可靠不同:在断点处,它提到了断点并显示了断点编号 - 但在其他任何SIGTRAP中,它只是表示SIGTRAP。所以我没有打印关于SIGTRAP的消息,而是真的希望GDB自己说:哇,这是一个SIGTRAP,这里没有断点 - 看着我,我即将停止并打印一个无用的SIGTRAP消息,完全破坏了调试会话!我如何静静地继续?请让我知道是否有人有办法做到这一点。 sourceware.org/gdb/current/onlinedocs/gdb/Set-Catchpoints.html#Set-Catchpointsrel =nofollow> catchpoints 来捕获SIGTRAP信号并添加命令来决定是继续还是停止。在此处理程序中,您可以检查便利变量,例如 $ _ siginfo 信号的原因。

特别感兴趣的是 $ _ siginfo.si_code ,它的值取决于信号交付。 sigaction(2) Linux手册页描述了确切的关系。您可以通过编译程序或查看标题来查找这些 SI_USER SI_KERNEL 等代码的数值在我的系统上它使用头 /usr/include/bits/siginfo.h )。我遇到的一些值是:
$ b $ ul

  • 0x00(0): SI_USER

  • 0x80(128): SI_KERNEL

  • 0x02(2): TRAP_TRACE



  • 有了这些信息,以下是一个捕获SIGTRAP并打印原因的示例,然后继续:

     捕获信号SIGTRAP 
    命令
    p $ _siginfo.si_code
    c
    end
    #设置另一个断点用于测试
    break sleep

    现在考虑这个测试然后触发x86上的调试陷阱(-64):

      #include< unistd.h> 
    int main(void){
    for(;;){
    sleep(5);
    asm(int3);
    }
    返回0;

    $ / code>

    这个程序会停止 gdb si_code )恰好是0x80, int3 SI_KERNEL ),但是再次重复该指令。所以要跳过这条指令,程序计数器( $ pc )必须增加。这样做后,我了解了有关 SIGTRAP si_code 的信息:


    • 断点触发代码为128的SIGTRAP( SI_KERNEL )。

    • 接收到一个带有代码2( TRAP_TRACE )的SIGTRAP(因为 SIGTRAP 的出发点)。 b $ b
    • int3 指令触发代码为128的SIGTRAP。因此,您需要一些东西来区分指令。


    以下是跳过 int3 陷阱并仍然保持断点功能的最终GDB命令:

     捕获信号SIGTRAP 
    命令
    silent#不打印catchpoint命中
    #忽略int3指令(此地址在
    #tracepoint使用print $ pc)
    if $ pc == 0x400568
    set $ pc ++#skip int3
    c
    end
    #忽略TRAP_TRACE即用于断点
    ,如果$ _siginfo.si_代码== 2
    c
    结束
    结束

    最后一个音符:SIGTRAP被调试器内部使用,可能上述过多。这在Arch Linux上使用GDB 7.10进行了测试。


    I'm trying to debug a program that often causes GDB to stop and display SIGTRAP when it is not at a breakpoint. It happens when loading dynamic libraries and other ordinary stuff. There are like 1,000 of these occurring before my breakpoint is finally hit, so it's non-feasible for me to manually "continue" all these irrelevant SIGTRAPs. But if I use the command handle SIGTRAP nostop noprint, then GDB will not stop at my breakpoint.

    It seems like there must be a way to educate GDB so that it understands which SIGTRAP is good for stopping, and which is no good for stopping. Clearly GDB knows whether it is at a breakpoint, because the output is very reliably different: at a breakpoint, it mentions "breakpoint" and shows the breakpoint number--but at any other SIGTRAP, it just says "SIGTRAP". So instead of printing the message about a SIGTRAP, I'd really like GDB to just say to itself, "wow, this is a SIGTRAP and there is no breakpoint here--look at me, I'm about to stop and print a useless SIGTRAP message that completely ruins the debug session! How about I just continue quietly?" Please let me know if someone has a way to do this.

    解决方案

    You can set catchpoints to catch the SIGTRAP signal and add commands to decide whether to continue or to stop. In this handler, you can inspect convenience variables such as $_siginfo for the reason for the signal.

    Of particular interest is $_siginfo.si_code, its value depends on the signal that is delivered. The sigaction(2) Linux manual page describes the exact relations. You can find the numeric values for those SI_USER, SI_KERNEL, etc. codes by compiling a program or looking in headers (on my system it uses the header /usr/include/bits/siginfo.h). Some values I have encountered are:

    • 0x00 (0): SI_USER
    • 0x80 (128): SI_KERNEL
    • 0x02 (2): TRAP_TRACE

    With this information in hand, here is an example that catches SIGTRAP and prints the reason, then continues:

    catch signal SIGTRAP
    commands
     p $_siginfo.si_code
     c
    end
    # Set another breakpoint for testing
    break sleep
    

    Now consider this test program that sleeps 5 seconds, then triggers a debug trap on x86(-64):

    #include <unistd.h>
    int main(void) {
        for (;;) {
            sleep(5);
            asm("int3");
        }
        return 0;
    }
    

    This program keeps stopping gdb at the int3 line because the signal is caught (si_code happens to be 0x80, SI_KERNEL), but then the instruction is repeated again. So to skip this instruction, the program counter ($pc) must be incremented. After doing so, I learned this information about SIGTRAP and si_code:

    • Breakpoints trigger SIGTRAP with code 128 (SI_KERNEL).
    • After continuing the breakpoing, a SIGTRAP with code 2 (TRAP_TRACE) is received (because of the catchpoint for SIGTRAP).
    • The int3 instruction triggers SIGTRAP with code 128. Thus you needs something to differentiate the instructions.

    Here are the final GDB commands that skip the int3 traps and still keep the breakpoints functional:

    catch signal SIGTRAP
    commands
     silent # do not print catchpoint hits
     # ignore the int3 instruction (this address was looked up at
     # the tracepoint using print $pc)
     if $pc == 0x400568
      set $pc++ # skip int3
      c
     end
     # Ignore TRAP_TRACE that is used for breakpoints
     if $_siginfo.si_code == 2
      c
     end
    end
    

    A final note: SIGTRAP is used internally by the debugger, it is possible that the above catches too much. This was tested with GDB 7.10 on Arch Linux.

    这篇关于我怎样才能使GDB停止在SIGTRAP只在断点?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆