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
進入kernel hacking:
但是並沒有看到CONFIG_DEBUG_SLAB,
這需要熟悉linux內核配置菜單的生成(自己去琢磨,順藤摸瓜也不難發現)。
如圖:
知道了吧!(不同的版本名字有不同)
=======================================================================================
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菜單:
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
證明完畢。
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);
運行結果
即看到了”毒劑”字符
二:SPINLOCK調試 2.1 spin_lock調試作用
打開該選項,內核將捕獲對未初始化自旋鎖的操作,也會捕獲兩次解開同一鎖的操作等其他錯誤。
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 運行結果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 運行結果 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)培訓
檢測不到此錯誤!
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);
●運行結果檢測到了此錯誤!