Linux debugfs

DebugFS,顧名思義,是一種用于內(nèi)核調(diào)試的虛擬文件系統(tǒng),內(nèi)核開發(fā)者通過debugfs和用戶空間交換數(shù)據(jù)。類似的虛擬文件系統(tǒng)還有procfs和sysfs等,這幾種虛擬文件系統(tǒng)都并不實(shí)際存儲(chǔ)在硬盤上,而是Linux內(nèi)核運(yùn)行起來后才建立起來。

通常情況下,最常用的內(nèi)核調(diào)試手段是printk。但printk并不是所有情況都好用,比如打印的數(shù)據(jù)可能過多,我們真正關(guān)心的數(shù)據(jù)在大量的輸出里不是那么一目了然;或者我們?cè)谡{(diào)試時(shí)可能需要修改某些內(nèi)核變量,這種情況下printk就無能為力,而如果為了修改某個(gè)值重新編譯內(nèi)核或者驅(qū)動(dòng)又過于低效,此時(shí)就需要一個(gè)臨時(shí)的文件系統(tǒng)可以把我們需要關(guān)心的數(shù)據(jù)映射到用戶空間。在過去,procfs可以實(shí)現(xiàn)這個(gè)目的,到了2.6時(shí)代,新引入的sysfs也同樣可以實(shí)現(xiàn),但不論是procfs或是sysfs,用它們來實(shí)現(xiàn)某些debug的需求,似乎偏離了它們創(chuàng)建的本意。比如procfs,其目的是反映進(jìn)程的狀態(tài)信息;而sysfs主要用于Linux設(shè)備模型。不論是procfs或是sysfs的接口應(yīng)該保持相對(duì)穩(wěn)定,因?yàn)橛脩魬B(tài)程序很可能會(huì)依賴它們。當(dāng)然,如果我們只是臨時(shí)借用procfs或者sysfs來作debug之用,在代碼發(fā)布之前將相關(guān)調(diào)試代碼刪除也無不可。但如果相關(guān)的調(diào)試借口要在相當(dāng)長(zhǎng)的一段時(shí)間內(nèi)存在于內(nèi)核之中,就不太適合放在procfs和sysfs里了。故此,debugfs應(yīng)運(yùn)而生。

默認(rèn)情況下,debugfs會(huì)被掛載在目錄/sys/kernel/debug之下,如果您的發(fā)行版里沒有自動(dòng)掛載,可以用如下命令手動(dòng)完成:

mount -t debugfs none /your/debugfs/dir

Linux內(nèi)核為debugfs提供了非常簡(jiǎn)潔的API,本文接下來將以一個(gè)實(shí)作為例來介紹,sample code可以從這里下載。

這個(gè)實(shí)作會(huì)在debugfs中建立如下的目錄結(jié)構(gòu):

image

其中,a對(duì)應(yīng)模塊中的一個(gè)u8類型的變量,b和subdir下面的c都是對(duì)應(yīng)模塊里的一個(gè)字符數(shù)組,只是它們的實(shí)現(xiàn)方式不同。

在module_init里,我們首先要建立根目錄mydebug:

my_debugfs_root = debugfs_create_dir("mydebug", NULL);

第一個(gè)參數(shù)是目錄的名稱,第二個(gè)參數(shù)用來指定這個(gè)目錄的上級(jí)目錄,如果是NULL,則表示是放在debugfs的根目錄里。

子目錄也是用debugfs_create_dir來實(shí)現(xiàn):

sub_dir = debugfs_create_dir("subdir", my_debugfs_root);

建立文件a的代碼非常簡(jiǎn)單:

debugfs_create_u8("a", 0644, my_debugfs_root, &a);

這表示文件名為“a”,文件屬性是0644,父目錄是上面建立的“mydebug”,對(duì)應(yīng)的變量是模塊中的a。

Linux內(nèi)核還提供了其他一些創(chuàng)建debugfs文件的API,請(qǐng)參考本文的附錄。

b是一個(gè)32-bytes的字符數(shù)組,在debugfs里,數(shù)組可以用blob wrapper來實(shí)現(xiàn)。

char hello[32] = "Hello world!\n";  
structdebugfs_blob_wrapper b;   
    
b.data = (void*)hello;   
b.size = strlen(hello) + 1;  
debugfs_create_blob("b", 0644, my_debugfs_root, &b);   

這里需要注意的是,blob wrapper定義的數(shù)據(jù)只能是只讀的。在本例中,雖然我們把文件b的權(quán)限設(shè)定為0644,但實(shí)際這個(gè)文件還是只讀的,如果試圖改寫這個(gè)文件,系統(tǒng)將提示出錯(cuò)。

如果需要對(duì)內(nèi)核數(shù)組進(jìn)行寫的動(dòng)作,blob wrapper就無法滿足要求,我們只能通過自己定義文件操作來實(shí)現(xiàn)。在這個(gè)實(shí)作里,可以參考文件c的實(shí)現(xiàn)。c和b在模塊里對(duì)應(yīng)著同一塊字符數(shù)組,不同的是,b是只讀的,而c通過自定義的文件操作同時(shí)實(shí)現(xiàn)了讀和寫。

staticint c_open(structinode *inode, structfile *filp)   
{   
    filp->private_data = inode->i_private;  
    return0;   
}   
    
staticssize_t c_read(structfile *filp, char__user *buffer,   
        size_tcount, loff_t *ppos)   
{   
    if(*ppos >= 32)   
        return0;   
    if(*ppos + count > 32)   
        count = 32 - *ppos;  
    
    if(copy_to_user(buffer, hello + *ppos, count))   
        return-EFAULT;   
    
    *ppos += count;  
    
    returncount;   
}   
    
staticssize_t c_write(structfile *filp, constchar __user *buffer,  
        size_tcount, loff_t *ppos)   
{   
    if(*ppos >= 32)   
        return0;   
    if(*ppos + count > 32)   
        count = 32 - *ppos;  
    
    if(copy_from_user(hello + *ppos, buffer, count))   
        return-EFAULT;   
    
    *ppos += count;  
    
    returncount;   
}   
    
structfile_operations c_fops = {   
    .owner = THIS_MODULE,  
    .open = c_open,  
    .read = c_read,  
    .write = c_write,  
};     
    
debugfs_create_file("c", 0644, sub_dir, NULL, &c_fops);   

注:代碼里,c_open其實(shí)并沒有任何用處,因?yàn)閏_read和c_write直接引用了全局變量hello。這里,我們也可以換一種寫法,在read/write函數(shù)里用filp->private_data來引用字符數(shù)組hello。

到這里,三個(gè)文件和子目錄已經(jīng)創(chuàng)建完畢。在module_exit中,我們要記得釋放創(chuàng)建的數(shù)據(jù)。

debugfs_remove_recursive(my_debugfs_root);

debugfs_remove_recursive可以幫我們逐步移除每個(gè)分配的dentry,如果您想一個(gè)一個(gè)手動(dòng)的移除,也可以直接調(diào)用debugfs_remove。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 第一章 1.Linux是一套免費(fèi)使用和自由傳播的類UNIX操作系統(tǒng),它可以基于Intel x86系列處理器以及Cy...
    yansicing閱讀 5,566評(píng)論 0 9
  • 姓名:吳兆陽 學(xué)號(hào):14020199009 轉(zhuǎn)自韋東山 嵌牛導(dǎo)讀:對(duì)嵌入式初學(xué)者,沒有足夠的視野選擇一個(gè)合適投入方...
    吳兆陽閱讀 2,514評(píng)論 0 4
  • Linux print system linux中的調(diào)試方法有很多種,但我們最常用的也是最關(guān)鍵的調(diào)試工具應(yīng)該就是使...
    Creator_Ly閱讀 2,022評(píng)論 0 4
  • 在C語言中,五種基本數(shù)據(jù)類型存儲(chǔ)空間長(zhǎng)度的排列順序是: A)char B)char=int<=float C)ch...
    夏天再來閱讀 4,007評(píng)論 0 2
  • ef
    紅昔昔閱讀 178評(píng)論 0 2

友情鏈接更多精彩內(nèi)容