GDB信号

GDB 的调试会涉及到对一些信号的处理,信号可以使程序在运行阶段产生中断。信号属于软中断,是一种异步处理事件的方法。对于 Linux 操作系统来说,支持信号的使用。常见的比如 SIGINT,我们可以使用键盘上的 CTRL+C 键发送信号,这个信号的作用表示中断字符信号。

信号分为实时信号还有非实时的信号,不同的操作系统中支持的信号数量是不同的。在 Linux 中查看系统中可以使用的信号使用命令:

kill -l

以 Ubuntu 系统中的信号为例,系统中信号有 64 个:其中 1~32 为非实时的信号,其余的为实时信号。也可以查看 Linux 中的 man 手册,查看信号的具体作用,使用方式:

man 7 signal

这两种信号之间区别就是,信号在响应的过程中能否被打断:实时信号在阻塞期间不会相应其他的信号,其它的信号会在当前信号结束后响应;非实时的信号在阻塞期间,信号会发生嵌套(即正在响应某个信号时,有其它信号进来,进程会先去响应其它信号,结束后再继续原来的任务)。
 
在 Linux 操作系统中,一些重要的应用程序都会使用信号处理。在 GDB 调试过程中,我们有能力控制任何的一种信号。控制信号使用到 handler 命令。相关命令的书写格式如下:

handler <signal> <keywords>

命令的含义表示在 GDB 中定义一个信号处理。其中,signal 可以是以“SIG”开头或者不以“SIG”开头的信号,也可以表示为一个要处理的信号范围,例如:SIGIO-SIGKILL,表示从 SIGIO 信号处理到 SIGKILL 信号,包括 SIGIO,SIGIOT,SIGKILL 三个信号。也可以使用关键字 all 表示所有的信号。一旦程序接收到信号,运行的程序就会被停止,用 GDB 来调试。keywords 表示接收到信号后产生的行为,包含以下几种:
  • nostop 表示当被调试的程序接收到信号的时候,GDB不会挺住运行的程序,但是会打印出提示消息,告诉我们接收到了这个信号。
  • Stop 表示被调试的程序接收到信号时会停止。
  • print 表示当被调试的程序接收到信号时,GDB会显示消息。
  • noprint 表示被调试的程序接收到信号时,GDB不会显示接收到的信号信息。
  • Pass / noignore 表示GDB让程序接收到这个信号,程序可以处理这个信号,或者如果信号时知名而又没有处理的话可以终止信号。
  • nopass / ignore 表示在程序中断时。程序继续执行前信号都是不可见的

打印显示设置的某个信号的行为使用命令:

info handler <signal>

signal 表示系统中的信号。

实例:

(gdb) info handle SIGINT 
Signal        Stop     Print Pass to program   Description
SIGINT        Yes     Yes  No          Interrupt

(gdb) handle SIGINT nostop
SIGINT is used by the debugger.
Are you sure you want to change it? (y or n) y
Signal        Stop     Print Pass to program   Description
SIGINT        No      Yes  No          Interrupt

(gdb) handle SIGINT noprint
SIGINT is used by the debugger.
Are you sure you want to change it? (y or n) y
Signal        Stop     Print Pass to program   Description
SIGINT        No      No   No          Interrupt

(gdb) handle SIGINT pass
SIGINT is used by the debugger.
Are you sure you want to change it? (y or n) y
Signal        Stop     Print Pass to program   Description
SIGINT        No      No   Yes         Interrupt