標籤:
訊號(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命令所發出一訊號則是直接發給被偵錯工具的。
====================
[轉] gdb中忽略訊號處理