本文介紹了一個實用 gdb 調試技巧。 它結合實際例子,一步一步示意如何重定向
stderr 和 stdout 到 gdb窗口,使得查看應用程序的輸出信息更為方便,從而提高調試者的工作效率。
Eclipse 的 console窗口)去查看,然後再切回來繼續調試,這是不是很不方便呢?
由於這個方法是基於 gdb 提供的基本而又強大的兩個功能之上的,所以在介紹它之前,先簡單介紹一下 gdb 的這兩個功能。
(gdb) call (int)close(fd)有了它,gdb 就可以具有很強大的功能,因為只要把所需要的功能寫成一個函數編譯進應用程序,調試時候在 gdb 中 call 該函數便可。
另外,如果用戶已經在 gdb 裡後,再去修改 .gdbinit ,只要通過:
(gdb) source ~/.gdbinit便可以讓那些新增加的改動生效。
$ ps ax | grep HelloWorld(要調試的應用程序名) 13522 ?? S 134:47.01 /Users/yyq/projects/1210/HelloWorld 24730 p5 S+ 0:00.00 grep Notes上面列出的第一行中的13522,就是 HelloWorld 的 pid 。
接著,我們使 gdb 連接上這個應用程序。如下:
$ gdb –pid=13522或者可以先運行 gdb ,然後用 attach 命令,如下:
$gdb $atta 13522不出意外的話,接下來就可以在 gdb 窗口調試了。
可以試一下看看是不是輸出信息不在 gdb 窗口中。
(gdb) call (void)printf(“\n Is this string printed on gdb window\n”)這時在 gdb 窗口是看不見這個輸出的。 為了跟蹤查看某些重要的調試信息,得不停地切換到別的窗口去看,很不方便。
解決的方法如下:
先關閉 stdout ,和 stderr 對應的文件描述符。
(gdb) call (int)close(1) (gdb) call (int)close(2)然後使用以下命令查看一下當前 gdb 窗口所在的虛擬終端。
(gdb) shell tty /dev/tty5這時再重新打開 stdout 和 stderr , 把它們和 gdb 窗口所在的虛擬終端關聯起來。
(gdb) p (int)open("/dev/ttyp1", 2) $1 = 1 (gdb) p (int)open("/dev/ttyp1", 2) $2 = 2如果這兩個命令執行結果不是如上結果(1和2),意味著 open 執行失敗,需要重新進行 close 和 open.
另外,如果把這裡的 ”/dev/ttyp1” 替換成目標文件名,便可將 stderr 和 stdout 重定向到該文件。
接下來,重新執行如下命令:
(gdb) call (void)printf(“\n Is this string be printed on gdb window?\n”) Is this string be printed on gdb window?這次輸出到了 gdb 窗口,也證明成功重定向了被調試程序的 stdout和 stderr . 以後就可直接在 gdb 窗口中看到所有的輸出信息,勿需再切換窗口。
如果每次都要運行這麼多命令,還是較為繁瑣,此時可以利用 .gdbinit 來簡化用戶輸入:把這一系列命令定義一個新命令,放到 .gdbinit 文件裡,然後在 gdb 裡執行這個命令便可。
關於在 .gdbinit 中定義 gdb 新命令的語法可以參考 dW 上其他的文章。下面就針對重定向問題,看 .gdbinit 是如何通過引入新命令來簡化用戶輸入。其實, 只需在 .gdbinit 文件裡,增加如下腳本:
def redirect call (void)close(1) call (void)close(2) call (int)open($arg0, 2) call (int)open($arg0, 2) end上面這段腳本定義了一個新命令: redirect ,就是重定向的意思。
之後,當重啟 gdb (或者運行 source~/.gdbinit ),並且連接到要調試的應用程序後. 用以下簡單的兩步就可達到重定向的目的:
第一步, 仍是得到這個 gdb 窗口所在的虛擬終端:
(gdb)shell tty /dev/ttyp3接著就可以調用 .gdbinit 中定義的命令了:
(gdb)redirect("/dev/ttyp3") $1=1 $2=2為了易於理解記憶,甚至可以按如下方式為該命令增加幫助信息。
把下面這段腳本緊接添加到剛才 redirect 所對應的 end 後面
document redirect redirect("argument"), this is used to switch stderr and stdout to gdb window. The argument is the name of gdb window. end這樣,在 gdb 窗口中,就可以使用 help 命令來查看這個命令的幫助信息了:
(gdb) help redirect this is used to switch stderr and stdout to gdb window. The argument is the name of gdb window.
為了解決這個問題,可以調用 fflush:
(gdb)call (int)fflush(0)
這樣所有的緩沖都會得到立刻刷新,包括 stdout 和 stderr . 調試者就能馬上看到前面執行的輸出的結果。