kernel 內存泄漏和自旋鎖調試

作者:下家山(請尊重原創,轉載請註明) http://www.xiajiashan.com 一直以來我(每個從事linux開發的人)深受“bug”的困擾,好像“bug”不足以描述這種被問題困擾的無奈。因爲當在驅動或BSP的開發過程中,所碰到的問題比解決一個bug難得多。

       Linux因其龐大,複雜(也許不是)至今並沒有一個類似VB,VC,ADS等可視化調試工具,交叉編譯環境的“麻煩”把很多想學linux的人擋在門外。      

       言歸正傳,下面介紹第一個調試技術

一:SLAB調試技術      1.1 SLAB調試的意義

       下面引用《linux設備驅動程序第三版》第四章的一段話:

       “這個重要的選項打開了內核內存分配函數的幾類檢查; 激活這些檢查, 就可能探測到一些內存覆蓋和遺漏初始化的錯誤. 被分配的每一個字節在遞交給調用者之前都設成 0xa5, 隨後在釋放時被設成 0x6b. 你在任何時候如果見到任一個這種"壞"模式重複出現在你的驅動輸出(或者常常在一個 oops 的列表), 你會確切知道去找什麼類型的錯誤. 當激活調試, 內核還會在每個分配的內存對象的前後放置特別的守護值; 如果這些值曾被改動, 內核知道有人已覆蓋了一個內存分配區, 它大聲抱怨. 各種的對更模糊的問題的檢查也給激活了。”

     1.2 CONFIG_DEBUG_SLAB在哪裏打開

  書上說CONFIG_DEBUG_SLAB在kernel hacking配置菜單中

  #make menuconfig

 

1.jpg

進入kernel hacking:

2.jpg

 

但是並沒有看到CONFIG_DEBUG_SLAB,

       這需要熟悉linux內核配置菜單的生成(自己去琢磨,順藤摸瓜也不難發現)。

       如圖:

3.jpg

知道了吧!(不同的版本名字有不同)

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

By 下家山 QQ 408452271                                            Email:[email protected] 

7/30/2012                                5/25                               7:20:06 PM

Linux Kernel 調試技術      上海索漫科技  http://www.xiajiashan.com       專注ARM+Linux

1.3 根本就沒有相關選項

有些版本在make menuconfig 後進入kernel hacking根本就沒有SLAB的相關選項,此時你需要仔細研究lib/kconfig.debug了,把SLAB相關選項打開。Linux-2.6.19中kernel hacking裏面還有DEBUG_SLAB_LEAK(內存泄漏)功能,應該是一個很好的調試功能,我還沒有去試,哪位有時間去試一下,煩請把結果貼出來共享。下面是linux-2.6.19下的kernel hacking菜單:

4.jpg

 

Memory leak debugging需要在Debug slab memory allocations打開的情況下才顯示。

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

By 下家山 QQ 408452271                                            Email:[email protected] 

7/30/2012                                5/25                               7:20:06 PM

Linux Kernel 調試技術      上海索漫科技  http://www.xiajiashan.com       專注ARM+Linux

1.4驗證0x5a和0x6b

“在將已分配內存返回給調用者之前,內核將把其中的每個字節設置成0xa5,而在釋放後將其設置成0x6b,如果讀者在自己驅動程序的輸出中,或者在OOPS信息中看到上述“毒劑”字符,則可以輕鬆判斷問題所在”

真是如此嗎?下面是我做的實驗:

我寫了個單獨的模塊,這個模塊首先申請一塊空間,然後釋放。成功申請後即打印這塊空間的值,看是否爲0x5a,釋放後再一次打印這塊空間的值,看其是否爲0x6b。其代碼如下:

#include

#include

#include    

unsigned char    *slab_wr;

static int test _init(void)

{

         int i;

   printk(KERN_EMERG "slab_wr address before call kmalloc:0x%08lx \n",slab_wr);

         slab_wr = (unsigned char  *)kmalloc(512, GFP_KERNEL);

    printk(KERN_EMERG "slab_wr address affter call kmalloc :0x%08lx \n",slab_wr);

         for( i=0; i<200; i++)

                   {

                             printk(KERN_EMERG "0x%x  ",*(slab_wr+i));

                   }      

    printk(KERN_EMERG "\nHello\n");       

    return 0;

}

 

static void test_exit(void)

{

   int i;

      kfree(slab_wr);

      for( i=0; i<200; i++)

                   {

                             printk(KERN_EMERG "0x%x  ",*(slab_wr+i));

                   }

    printk(KERN_EMERG"\nGoodbye,\n"); 

}

module_init(test _init);

module_exit(test _exit);

下面是運行結果

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

By 下家山 QQ 408452271                                            Email:[email protected] 

7/30/2012                                5/25                               7:20:06 PM

Linux Kernel 調試技術      上海索漫科技  http://www.xiajiashan.com       專注ARM+Linux

5.jpg

 

證明完畢。

1.5 驗證越界

         還是剛纔那個程序:

//slabtest.c

#include

#include

#include    

unsigned char    *slab_wr;  /* I/O data buffer             */

static int slabtest_init(void)

{

         int i;

   printk(KERN_EMERG "slab_wr address before call kmalloc:0x%08lx \n",slab_wr);

         slab_wr = (unsigned char  *)kmalloc(100,GFP_USER/*GFP_KERNEL*/);

    printk(KERN_EMERG "slab_wr address affter call kmalloc :0x%08lx \n",slab_wr);

         for( i=0; i<101; i++)

                   {

                             *(slab_wr+i)=0xcc;

                   }

#if 0

         for( i=0; i<200; i++)

                   {

                             printk(KERN_EMERG "0x%x  ",*(slab_wr+i));

                   }

#endif

    printk(KERN_EMERG "\nHello\n");

        

    return 0;

}

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

By 下家山 QQ 408452271                                            Email:[email protected] 

7/30/2012                                5/25                               7:20:06 PM

Linux Kernel 調試技術      上海索漫科技  http://www.xiajiashan.com       專注ARM+Linux

 

static void slabtest_exit(void)

{

   int i;

      kfree(slab_wr);

#if 0

      for( i=0; i<100; i++)

                   {

                             printk(KERN_EMERG "0x%x  ",*(slab_wr+i));

                   }

#endif

    printk(KERN_EMERG"\nGoodbye\n");

 

        

}

module_init(slabtest_init);

module_exit(slabtest_exit);

       運行結果

6.jpg

即看到了”毒劑”字符

 

二:SPINLOCK調試      2.1 spin_lock調試作用

       打開該選項,內核將捕獲對未初始化自旋鎖的操作,也會捕獲兩次解開同一鎖的操作等其他錯誤。

21.jpg
2.2 捕獲未初始化自旋鎖       2.2.1實驗代碼:

       //spinlock.c

#include <linux/init.h>

#include <linux/module.h>

#include  <linux/spinlock.h>

unsigned char aa;

   spinlock_t SpinLockTest ;

static int spinlock_init(void)

{

       int i;

       unsigned long flags;

       // spin_lock_init(&SpinLockTest);//進行未初始化自旋鎖檢測

        spin_lock_irqsave(&SpinLockTest, flags);

        aa =1;

       spin_unlock_irqrestore(&SpinLockTest, flags);

    printk(KERN_EMERG "\nHello\n");  

    return 0;

}

 

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

By 下家山 QQ 1209050967       上海松江文匯路928號258室    松江大學城  7/31/2012  

上海索漫科技  http://www.xiajiashan.com  專注嵌入式(ARM7,Cortex-M0,Cortex-M3,ARM9,linux)培訓 

 

static void spinlock_exit(void)

{

    printk(KERN_EMERG"\nGoodbye\n");     

}

module_init(spinlock_init);

module_exit(spinlock_exit);

2.2.2 運行結果

 

22.jpg
2.3.1  代碼

       //spinlock.c

#include <linux/init.h>

#include <linux/module.h>

#include  <linux/spinlock.h>

unsigned char aa;

   spinlock_t SpinLockTest ;

static int spinlock_init(void)

{

       int i;

       unsigned long flags;

       spin_lock_init(&SpinLockTest);

        spin_lock_irqsave(&SpinLockTest, flags);

        aa =1;

       spin_unlock_irqrestore(&SpinLockTest, flags);

    printk(KERN_EMERG "\nHello\n");  

    return 0;

}

static void spinlock_exit(void)

{

     printk(KERN_EMERG"\nGoodbye\n");    

}

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

By 下家山 QQ 1209050967       上海松江文匯路928號258室    松江大學城  7/31/2012  

上海索漫科技  http://www.xiajiashan.com  專注嵌入式(ARM7,Cortex-M0,Cortex-M3,ARM9,linux)培訓

 

module_init(spinlock_init);

module_exit(spinlock_exit);

2.3.2 運行結果
23.jpg
2.4 如果不打開spin_lock調試功能

       如果不打開spin_lock調試功能,則檢測不到自旋鎖未初始化錯誤。

2.4.1實驗代碼      

測試代碼與2.2.1實驗代碼同。

2.4.2實驗結果

       測試結果與2.3.2 運行結果同。

2.5 檢測兩次解開同一鎖        2.5.1 關閉此功能

       即在”kernel hacking”中不選擇“spinlock debugging”,看能否檢測兩次解開同一鎖的錯誤。

      ●測試代碼

       //spinlock.c

#include <linux/init.h>

#include <linux/module.h>

#include  <linux/spinlock.h>

unsigned char aa;

   spinlock_t SpinLockTest ;

static int spinlock_init(void)

{

       int i;

       unsigned long flags;

       spin_lock_init(&SpinLockTest);

        spin_lock_irqsave(&SpinLockTest, flags);

        aa =1;

       spin_unlock_irqrestore(&SpinLockTest, flags);

        spin_unlock_irqrestore(&SpinLockTest, flags);

    printk(KERN_EMERG "\nHello\n");  

    return 0;

}

static void spinlock_exit(void)

{

       printk(KERN_EMERG"\nGoodbye\n");     

}

module_init(spinlock_init);

module_exit(spinlock_exit);

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

By 下家山 QQ 1209050967       上海松江文匯路928號258室    松江大學城  7/31/2012  

上海索漫科技  http://www.xiajiashan.com  專注嵌入式(ARM7,Cortex-M0,Cortex-M3,ARM9,linux)培訓

24.jpg

檢測不到此錯誤!

2.5.2 打開此功能

       即在”kernel hacking”中選擇“spinlock debugging”,看能否檢測兩次解開同一鎖的錯誤。

      ●測試代碼

       //spinlock.c

#include <linux/init.h>

#include <linux/module.h>

#include  <linux/spinlock.h>

unsigned char aa;

   spinlock_t SpinLockTest ;

static int spinlock_init(void)

{

       int i;

       unsigned long flags;

       spin_lock_init(&SpinLockTest);

        spin_lock_irqsave(&SpinLockTest, flags);

        aa =1;

       spin_unlock_irqrestore(&SpinLockTest, flags);

        spin_unlock_irqrestore(&SpinLockTest, flags);

    printk(KERN_EMERG "\nHello\n");  

    return 0;

}

static void spinlock_exit(void)

{

       printk(KERN_EMERG"\nGoodbye\n");     

}

module_init(spinlock_init);

module_exit(spinlock_exit);

●運行結果
25.jpg

檢測到了此錯誤!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章