在規模稍微大點的項目中,為了方便快速找到bug的所在,我們往往需要在代碼中加入一些調試用的代碼,比如加入一些printf,打印出一些重點的信息;加入assert,進行斷言判斷。這些比較隨意的調試代碼會使整個系統顯得比較凌亂。於是Fred Fish開發了一套用於嵌入代碼中的庫,開發人員只需要調用相應的函數即可加入調試信息。
對於MySQL這種多線程的程序來說,調試也是比較困難的,MySQL選擇了DBUG作為其調試代碼(在原始代碼的基礎上進行了略微的改造),充分說明了DBUG的實用性,本文就DBUG的原始代碼進行介紹。
這裡以linux下的開發進行介紹。
首先需要下載DBUG源碼,下載地址:http://sourceforge.net/projects/dbug/
解壓後在dbug/src下即是debug所需的源碼文件:dbug.h dbug.c
dbug/example.c是一個簡單的例子,源碼如下:
?
/*
* This file is Public Domain
*
* Just short example, how Fred Fish's dbug package should be used
*
* Tonu Samuel <tonu @spam.ee="">
*
*/
#include "dbug.h"
static int sub1 (void);
static void sub2 (char *arg);
static int
sub1 (void)
{
DBUG_ENTER ("sub1");
sub2 ("Hello world!");
sub2 ("Hello earth!");
sub2 ("Hello programmer!");
DBUG_RETURN (0);
}
static void
sub2 (char *arg)
{
DBUG_ENTER ("sub2");
DBUG_PRINT ("info", ("Got argument: '%s'", arg));
printf ("%s\n", arg);
DBUG_VOID_RETURN;
}
int
main (void)
{
int ret = 0;
DBUG_PUSH ("d:t:O");
DBUG_PROCESS ("example");
ret = sub1 ();
DBUG_PRINT ("info", ("Returned value: %d", ret));
return 0;
}</tonu>
我們將example.c放到src目錄下,然後編譯example文件:
?
1
dbug/src$ gcc -Wall -g dbug.c example.c -o example
運行example輸出如下:
>sub1
| >sub2
| | info: Got argument: 'Hello world!'
Hello world!
| <sub2 |="">sub2
| | info: Got argument: 'Hello earth!'
Hello earth!
| <sub2 |="">sub2
| | info: Got argument: 'Hello programmer!'
Hello programmer!
| <sub2 pre="" 0="">< value: Returned info: <sub1></sub1></sub2></sub2></sub2>
結合源碼,我們通過打印出來的信息,可以很容易的看出調試信息所表達的意思:
函數sub1調用了三次sub2,三次的參數分別是'Hello world!' ,'Hello earth!' ,'Hello programmer!' ,最後return 0.
下面初略介紹下上面用到的幾個宏定義:
DBUG_PUSH ("d:t:O"); 設置調試的啟動參數,參數列表在MySQL手冊上也有:
標記 描述 d
允許對當前狀態從DBUG_<N>宏輸出。可能跟著一列關鍵詞,這些關鍵詞僅對那些帶有
關鍵詞的DBUG宏選擇輸出。一個空的關鍵詞列意味著對所有宏輸出。
在每個調試起輸出行後延遲。參量一個十分之一秒為單位來延遲的數,它受限於機器的能
力。比如 -#D,20 指定一個2秒的延遲。
限制調試和/或跟蹤,以及簡單設定於列出名字的函數。注意,空列將禁止所用函數。應
該給出適當的d 或 t 標記,如果它們被允許了,這個標記僅限制它們的動作。
允許解析,創建名為的dbugmon.out文件,它包含可用來簡單設定程序的信息。可能跟著
一列關鍵詞,它們是選擇只對列中的函數做簡單設定。一個空列意味著所有函數都要考慮
到。
類似於 o,但是文件在每次寫操作之間被沖刷。當需要之時,文件在每次寫操作之間被關
閉然後重新打開。
限制調試器作用於指定進程。為使調試器動作,一個進程必須用DBUG_PROCESS宏來識
別,且匹配列表中的一個。
當推出一個新狀態時,不繼承前狀態的操作嵌套深度級別。當輸出在左邊空白開始時有
用。
在每個調試過的函數做_sanity(_file_,_line_)函數直到 _sanity() 返回不同於0的結果。(大多
數的時候與safemalloc 一起用來找出內存漏洞)。
允許函數調用/退出跟蹤行。可能跟著一個給出最大跟蹤級別的數字列(只含一個修改
量),超過這個數字,調試中或跟蹤中的宏不能產生任何輸出。 默認為一個編譯時間選
項。
DBUG_PROCESS ("example"); 設置進程名為example
DBUG_ENTER ("sub1"); 表示進入函數sub1
DBUG_PRINT ("info", ("Got argument: '%s'", arg)); 和printf效果差不多,打印出需要的調試信息。
DBUG_RETURN (0); 在return 0 的基礎上,打印出return 0的調試信息。
本文簡單介紹了DBUG的使用方法,沒有深究,源碼很少,卻很實用,在源碼的注釋部分,我看到了是Fred Fish1987年寫的,呃,我才剛出生....,沒想到現在還在看那時候的代碼,可能這就是所謂的經典吧。
兄弟們,你們還在為復雜環境下的bug調試而苦惱麼?還在為堆棧被寫亂掉無從下手而凌亂麼?淡定吧,一起來用DBUG吧~~
踏著落葉,追尋著我的夢想。轉載請注明出處
摘自 心中無碼