GDB调试带有信号的程序

信号(Signals)

信号是一种软中断,是一种处理异步事件的方法。一般来说,操作系统都支持许多信号。尤其是UNIX,比较重要应用程序一般都会处理信号。UNIX定义了许 多信号,比如SIGINT表示中断字符信号,也就是Ctrl+C的信号,SIGBUS表示硬件故障的信号;SIGCHLD表示子进程状态改变信号; SIGKILL表示终止程序运行的信号,等等。信号量编程是UNIX下非常重要的一种技术。

GDB有能力在你调试程序的时候处理任何一种信号,你可以告诉GDB需要处理哪一种信号。你可以要求GDB收到你所指定的信号时,马上停住正在运行的程序,以供你进行调试。你可以用GDB的handle命令来完成这一功能。

handle
在GDB中定义一个信号处理。信号可以以SIG开头或不以 SIG开头,可以用定义一个要处理信号的范围(如:SIGIO-SIGKILL,表示处理从SIGIO信号到SIGKILL的信号,其中包括SIGIO, SIGIOT,SIGKILL三个信号),也可以使用关键字all来标明要处理所有的信号。一旦被调试的程序接收到信号,运行程序马上会被GDB停住,以 供调试。其可以是以下几种关键字的一个或多个。

nostop
当被调试的程序收到信号时,GDB不会停住程序的运行,但会打出消息告诉你收到这种信号。
stop
当被调试的程序收到信号时,GDB会停住你的程序。
print
当被调试的程序收到信号时,GDB会显示出一条信息。
noprint
当被调试的程序收到信号时,GDB不会告诉你收到信号的信息。
pass
noignore
当被调试的程序收到信号时,GDB不处理信号。这表示,GDB会把这个信号交给被调试程序会处理。
nopass
ignore
当被调试的程序收到信号时,GDB不会让被调试程序来处理这个信号。


info signals
info handle
查看有哪些信号在被GDB检测中。

另外补充:

信号的处理
程序是和网络相关的,调试期间经常地收到SIGPIPE,导致gdb停下来。看了一下gdb info,解决方法很简单。用handle命令设置一下缺省signal的处理行为就可以了:
   handle SIGPIPE nostop
如果连提示信息都不想看见,就可以这样设置:
   handle SIGPIPE nostop noprint
就可以了。其他相关信号也可以类似处理。想了解目前的signal状态可以使用info signal察看。

启动配置文件
GDB使用中比较麻烦的事情,就是每次启动,还要手动敲一把命令,特别是断点比较多的情况,这个特便影响,工作效率。查了一下gdb info,gdb支持自动读取一个启动脚本文件.gdbinit,所以经常输入的启动命令,就都可以写在gdb启动目录的.gdbinit里面。比如
.gdbinit:
   file myapp
   handle SIGPIPE nostop
   break ss.c:100
   break ss.c:200
   run
GDB和bash类似,也支持source这个命令,执行另外一个脚本文件。所以可以修改一下.gdbinit:
.gdbinit:
   file myapp
   handle SIGPIPE nostop
   source gdb.break
   run
gdb.break:
   break ss.c:100
   break ss.c:200
这样修改的断点配置,只需要编辑gdb.break就可以了。再后来,偶而还是需要单独启动GDB,不想执行自动脚本,于是又改进了一下。首先把.gdbinit命名为gdb.init,然后定义一个shell alias:
   $ alias .gdb=”gdb -x gdb.init”

这样如果需要使用自动脚本,就用.gdb命令,否则用gdb进入交互状态的gdb。这样配置以后可以一个简单命令就开始调试,整个效率就能提高不少。

注:转自http://blog.scaner.i.thu.cn/index.php/2006/04/15/gdb-tips-1/

注解

1alias命令

alias顾名思义就是起别名的意思,在linux里,可以通过alias命令为常用命令设置快捷方式,命令格式如下: alias name='command' 例如:alias del='rm'

欲显示系统已有别名,直接使用 alias或alias -p

若需要设置的命令别名比较多,可以直接修改/etc/bashrc或~/.bashrc,将需要的别名写到里面即可,不同之处是/etc/bashrc设置的别名对于所有登录用户都起作用,而~/.bashrc只对目前用户起作用。

 

比如:

handle SIGUSR2 nostop

 

 

一篇不错的帖子,讲的是gdb中的信号(signal)相关调试技巧

    转自Magic C++论坛

    http://www.magicunix.com/index_ch.html

    http://www.magicunix.com/cgi-bin1/forum_cn/ultimatebb.cgi?ubb=get_topic&f=1&t=000060#000003

    引用:

    --------------------------------------------------------------------------------

    原发贴者 Couger:

    我写了一个INT信号的处理函数,在处理函数里设置断点后go,但是在console下按Ctrl-C后MC并没有进入处理函数,而console下的程序也直接退出,没有给出希望的输出。

    --------------------------------------------------------------------------------

    在console下按Ctrl-C后确实发送了SIGINT信号,但是gdb里的缺省设置将会导致由GDB截获的该信息,调试的应用程序无法接受到该信号。

    有两种方法可以使调试的应用程序接受到信号:

    (1)改变gdb信号处理的设置

    比如,以下设置会告诉gdb在接收到SIGINT时不要停止、打印出来、传递给调试目标程序

    =====================================

    (gdb) handle SIGINT nostop print 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 Yes Yes Interrupt

    (gdb)

    =====================================

    (2)使用gdb命令直接向调试的应用程序发送信号

    首先在你希望发送信号的语句处设置断点,然后运行程序,当停止到断点所在位置后,用gdb的signal命令发送信号给调试目标程序

    ====================================

    (gdb) signal SIGINT

    Continuing with signal SIGINT.

    Breakpoint 1, handler (signal=2) at main.cpp:15

    15 printf("Signal handler...\n"

    

    ;

    ====================================

    ;-( 但是这两种方法目前MC都还不支持,所以需要等新版本的MC才可以方便的支持你这种调试情况,呵呵。临时先手工调试一下吧。

    新版本将会增加

    (1)调试器的信号处理设置

    (2)支持发送信号命令

    调试用例:

    ============

    /*

    * This program is uninterruptable with

    * Ctrl+C, uses signal handler

    */

    #include ;

    #include ;

    #include ;

    /* The signal handler function */

    void handler( int signal ) {

    printf("Signal handler...\n"

    

    ;

    psignal( signal, "Signal: "

    

    ;

    } /*handler*/

    main() {

    /* Registering the handler, catching

    SIGINT signals */

    signal( SIGINT, handler );

    /* Do nothing */

    while( 1 ) {

    printf("Running...\n"

    

    ;

    sleep(10);

    } /*while*/

    } /*main*/

    ============

    改变gdb的信号处理设置

    ============

    5.3 Signals

    A signal is an asynchronous event that can happen in a program. The

    operating system defines the possible kinds of signals, and gives each

    kind a name and a number. For example, in Unix SIGINT is the signal a

    program gets when you type an interrupt character (often C-c); SIGSEGV

    is the signal a program gets from referencing a place in memory far

    away from all the areas in use; SIGALRM occurs when the alarm clock

    timer goes off (which happens only if your program has requested an

    alarm).

    Some signals, including SIGALRM, are a normal part of the functioning

    of your program. Others, such as SIGSEGV, indicate errors; these

    signals are fatal (they kill your program immediately) if the program

    has not specified in advance some other way to handle the signal.

    SIGINT does not indicate an error in your program, but it is normally

    fatal so it can carry out the purpose of the interrupt: to kill the

    program.

    GDB has the ability to detect any occurrence of a signal in your

    program. You can tell GDB in advance what to do for each kind of

    signal.

    Normally, GDB is set up to let the non-erroneous signals like SIGALRM

    be silently passed to your program (so as not to interfere with their

    role in the program's functioning) but to stop your program immediately

    whenever an error signal happens. You can change these settings with

    the handle command.

    info signals

    info handle

    Print a table of all the kinds of signals and how GDB has been told to

    handle each one. You can use this to see the signal numbers of all the

    defined types of signals.

    info handle is an alias for info signals.

    handle signal keywords...

    Change the way GDB handles signal signal. signal can be the number of a

    signal or its name (with or without the `SIG' at the beginning); a list

    of signal numbers of the form `low-high'; or the word `all', meaning

    all the known signals. The keywords say what change to make.

    The keywords allowed by the handle command can be abbreviated. Their full names are:

    nostop

    GDB should not stop your program when this signal happens. It may still

    print a message telling you that the signal has come in.

    stop

    GDB should stop your program when this signal happens. This implies the print keyword as well.

    print

    GDB should print a message when this signal happens.

    noprint

    GDB should not mention the occurrence of the signal at all. This implies the nostop keyword as well.

    pass

    noignore

    GDB should allow your program to see this signal; your program can

    handle the signal, or else it may terminate if the signal is fatal and

    not handled. pass and noignore are synonyms.

    nopass

    ignore

    GDB should not allow your program to see this signal. nopass and ignore are synonyms.

    When a signal stops your program, the signal is not visible to the

    program until you continue. Your program sees the signal then, if pass

    is in effect for the signal in question at that time. In other words,

    after GDB reports a signal, you can use the handle command with pass or

    nopass to control whether your program sees that signal when you

    continue.

    The default is set to nostop, noprint, pass for non-erroneous signals

    such as SIGALRM, SIGWINCH and SIGCHLD, and to stop, print, pass for the

    erroneous signals.

    You can also use the signal command to prevent your program from seeing

    a signal, or cause it to see a signal it normally would not see, or to

    give it any signal at any time. For example, if your program stopped

    due to some sort of memory reference error, you might store correct

    values into the erroneous variables and continue, hoping to see more

    execution; but your program would probably terminate immediately as a

    result of the fatal signal once it saw the signal. To prevent this, you

    can continue with `signal 0'. See section Giving your program a signal.

    ============

    直接使用gdb signal命令发送信号给调试目标程序

    ================

    三、产生信号

    使用singal命令,可以产生一个信号给被调试的程序。如:中断信号Ctrl+C。这非常方便于程序的调试,可以在程序运行的任意位置设置断点,并在该断点用GDB产生一个信号,这种精确地在某处产生信号非常有利程序的调试。

    语法是:signal ;,UNIX的系统信号通常从1到15。所以;取值也在这个范围。

    single命令和shell的kill命令不同,系统的kill命令发信号给被调试程序时,是由GDB截获的,而single命令所发出一信号则是直接发给被调试程序的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 RISC-V 平台上使用 GDB 进行调试,需要先安装 RISC-V 版本的 GDB。可以通过以下命令安装: ``` sudo apt-get install gdb-multiarch ``` 安装完成后,可以使用以下命令启动 GDB: ``` riscv64-unknown-elf-gdb <executable> ``` 其中 `<executable>` 是要调试的可执行文件的路径。接下来,可以使用 GDB 的各种命令进行调试。 以下是一些常用的 GDB 命令: - `break <function>`:在指定函数处设置断点。 - `break <line>`:在指定行处设置断点。 - `run <args>`:运行程序并传入参数。 - `step`:单步执行程序。 - `next`:执行下一条语句,不进入函数内部。 - `continue`:继续执行程序,直到遇到下一个断点。 - `print <variable>`:打印变量的值。 - `backtrace`:查看函数调用栈。 此外,还可以使用 `-g` 选项编译程序时生成调试信息,以便在 GDB 中进行调试。例如: ``` riscv64-unknown-elf-gcc -g -o <executable> <source files> ``` ### 回答2: gdb是一个功能强大的调试工具,适用于多种不同的处理器架构,其中包括risc-v。使用gdb调试risc-v程序可以帮助我们定位并解决程序中的bug。 具体步骤如下: 1. 安装gdb:首先需要确保在计算机上安装了gdb。可以通过包管理器或者从gdb的官方网站上下载并安装。 2. 编译程序:在使用gdb之前,需要将C/C++程序编译为可执行文件。例如,我们可以使用risc-v的交叉编译工具链来编译程序。 3. 运行gdb:在命令行中输入"gdb"命令来启动gdb调试器。 4. 加载可执行文件:在gdb输入"file <可执行文件路径>"命令来加载要调试的可执行文件。 5. 设置断点:可以使用"break <行号或函数名>"命令在程序中设置断点。这将使程序暂停在指定的位置,以便进行调试。 6. 启动程序:在gdb输入"run"命令来启动程序的执行。当程序到达设置的断点时,它将暂停执行。 7. 检查程序状态:在程序暂停时,可以使用各种gdb命令来检查当前变量的值、堆栈跟踪等信息,以了解程序的当前状态。 8. 单步执行:可以使用"next"或"step"命令逐行执行程序。这将允许我们逐步跟踪程序的执行,以查找错误。 9. 查看变量值:使用"gdb"命令可以查看当前变量的值。可以为每个变量设置监视点来观察其变化。 10. 修复错误:一旦发现了bug,可以在gdb中进行相应的更改或修复。然后可以重新编译程序并再次使用gdb进行调试,以确保问题已经解决。 使用gdb调试risc-v程序可以更加高效地定位问题并进行调试。通过将gdb与其他调试技术,如断言和日志输出,结合使用,可以帮助开发人员更轻松地编写和维护risc-v程序。 ### 回答3: gdb是一款强大的调试器,可用于调试RISC-V程序。以下是使用gdb调试RISC-V程序的步骤: 首先,确保已经安装了RISC-V架构的gdb工具。如果没有安装,可以通过下载源代码并手动编译安装来获取。 1. 将需要调试的RISC-V可执行文件加载到gdb中。可以使用以下命令: ``` gdb <可执行文件名> ``` 2. 设置断点来在程序的特定位置中断执行。使用`break`命令来设置断点。例如,要在第30行设置断点,可以使用以下命令: ``` break main.c:30 ``` 3. 启动调试会话。可以直接使用`run`命令启动程序,或者使用`start`命令以暂停的方式启动程序(这样可以在设置完断点后再启动)。 4. 当程序在断点处中断时,可以使用`next`命令逐过程执行,或者使用`step`命令逐语句执行。还可以使用`continue`命令使程序继续执行直到下一个断点或程序结束。 5. 在程序执行过程中,可以使用`print`命令打印变量或表达式的值。例如,要打印变量`x`的值,可以使用以下命令: ``` print x ``` 6. 若要查看当前执行的源代码行,可以使用`list`命令。 7. 将gdb作为交互式调试器使用时,还可以使用一些其他命令来查看寄存器的值、改变变量的值等。 在调试RISC-V程序时,gdb是一个非常有用的工具。它提供了一系列命令和功能,帮助我们理解程序执行的过程,查找错误并进行调试。以上是使用gdb调试RISC-V程序的基本步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值