MySQL源碼學習——DBUG調試

 

一、前言

         在規模稍微大點的項目中,為瞭方便快速找到bug的所在,我們往往需要在代碼中加入一些調試用的代碼,比如加入一些printf,打印出一些重點的信息;加入assert,進行斷言判斷。這些比較隨意的調試代碼會使整個系統顯得比較凌亂。於是Fred Fish開發瞭一套用於嵌入代碼中的庫,開發人員隻需要調用相應的函數即可加入調試信息。

        對於MySQL這種多線程的程序來說,調試也是比較困難的,MySQL選擇瞭DBUG作為其調試代碼(在原始代碼的基礎上進行瞭略微的改造),充分說明瞭DBUG的實用性,本文就DBUG的原始代碼進行介紹。

二、DBUG下載與使用

       這裡以linux下的開發進行介紹。

      首先需要下載DBUG源碼,下載地址:https://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

在每個調試起輸出行後延遲。參量一個十分之一秒為單位來延遲的數,它受限於機器的能 
力。比如 -#D,20 指定一個2秒的延遲。

f

限制調試和/或跟蹤,以及簡單設定於列出名字的函數。註意,空列將禁止所用函數。應 
該給出適當的d 或 t 標記,如果它們被允許瞭,這個標記僅限制它們的動作。

F 對調試或跟蹤輸出的每一行識別源文件名。
i 對調試或跟蹤輸出的每一行用PID或線程ID識別進程。
g

允許解析,創建名為的dbugmon.out文件,它包含可用來簡單設定程序的信息。可能跟著 
一列關鍵詞,它們是選擇隻對列中的函數做簡單設定。一個空列意味著所有函數都要考慮 
到。

L 為調試或跟蹤輸出的每一行識別源文件行號。
n 為調試或跟蹤輸出的每一行打印當前函數嵌套深度。
N 給調試輸出的每一行編號。
o 重定向調試器輸出流到指定文件。默認輸出是stderr 文件。
O

類似於 o,但是文件在每次寫操作之間被沖刷。當需要之時,文件在每次寫操作之間被關 
閉然後重新打開。

p

限制調試器作用於指定進程。為使調試器動作,一個進程必須用DBUG_PROCESS宏來識 
別,且匹配列表中的一個。

P 為調試或跟蹤輸出的每一行打印當前進程名字。
r

當推出一個新狀態時,不繼承前狀態的操作嵌套深度級別。當輸出在左邊空白開始時有 
用。

S

在每個調試過的函數做_sanity(_file_,_line_)函數直到 _sanity() 返回不同於0的結果。(大多 
數的時候與safemalloc 一起用來找出內存漏洞)。

t

允許函數調用/退出跟蹤行。可能跟著一個給出最大跟蹤級別的數字列(隻含一個修改 
量),超過這個數字,調試中或跟蹤中的宏不能產生任何輸出。 默認為一個編譯時間選 
項。

        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吧~~

踏著落葉,追尋著我的夢想。轉載請註明出處

 

摘自 心中無碼

發佈留言