日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux驱动调试中的Debugfs的使用简介

發(fā)布時間:2025/4/5 linux 85 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux驱动调试中的Debugfs的使用简介 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Linux驅(qū)動調(diào)試中的Debugfs的使用簡介?(2012-03-31 14:14)

在調(diào)試linux驅(qū)動的時候,可以用debugfs來調(diào)試,debugfs類似字符設(shè)備驅(qū)動一樣,甚至更簡單,不需要主設(shè)備號次設(shè)備號等等,只需要實現(xiàn)一個file_operations,然后通過debugfs_create_file就可以在debugfs中建立一個文件結(jié)點,就像字符設(shè)備驅(qū)動那樣,只需要對這個文件結(jié)點進行open就可以進行read、write、ioctl,等等操作,這些操作對應(yīng)到我們在驅(qū)動里為debugfs準(zhǔn)備的file_operations。

?

讓內(nèi)核支持DEBUGFS,使能宏CONFIG_DEBUG_FS,在內(nèi)核配置中選中,一般是在Kernel hacking中:

?

在實際的使用中,舉個例子來說明,在調(diào)試GPIO驅(qū)動的時候,我們可以通過debugfs來調(diào)試:

首先定義一個file_operations:

staticconst struct file_operations gpiolib_operations = {

.open = gpiolib_open,

.read = gpiolib_read,

.write = gpiolib_write,

.llseek = seq_lseek,

.release = single_release,

};

然后,建立一個debugfs文件結(jié)點:

(void)debugfs_create_file("gpio", S_IFREG | S_IRUGO,

NULL, NULL, &gpiolib_operations);

在實際的驅(qū)動中,建立debugfs文件結(jié)點一般在驅(qū)動初始化的時候。

根據(jù)我們的調(diào)試需要,實現(xiàn)讀寫操作,一般用得比較多的是read和write操作,所以在gpiolib_read和gpiolib_write里加入我們的調(diào)試代碼。調(diào)用GPIO驅(qū)動的時候,我的想法是,給GPIO結(jié)點發(fā)一個讀指令,那么就得傳入的gpio號的狀態(tài),給GPIO結(jié)點發(fā)一個寫指令,那么就根據(jù)傳入的參數(shù)設(shè)置gpio的狀態(tài)。于是,我只需要實現(xiàn)write函數(shù):

staticssize_t gpiolib_write(struct file *file, const char __user *buf,size_t size, loff_t *ppos) { charinfo[255]; int port=0,value=0; memset(info,0, 255); copy_from_user(info,buf, size); printk("gpio:%s\n",info); if((info[0]>= '0') && (info[0] <= '9')){port= (info[0] - 48)*10;if((info[1]>= '0') && (info[1] <= '9')){port+= (info[1] - 48);if(info[2]== ' '){if(info[3] == 'w'){value = (info[4] =='0')?0:1;} } } } if(info[3]== 'r'){gpio_direction_input(port);printk("gpio%dstatus = %d\n", port, __gpio_get_value(port)); }else if(info[3] == 'w'){printk("write%d to gpio%d\n", value, port);gpio_direction_output(port,value);__gpio_set_value(port,value);} return size; }

這段代碼的意思,根據(jù)傳入的參數(shù)info作相應(yīng)的操作,info的格式是:

info[0]和info[1]分別代表gpio號的十位和個位;

info[2]必須為空格;

info[3]為讀寫性質(zhì),‘w'為寫,'r'為讀;

info[4]如果為寫,那么它表示寫的狀態(tài)。

?

這樣就可以在驅(qū)動加載之后,用shell命令echo來進行調(diào)試了

例如gpio號為57的端口控制蜂鳴器,gpio號為37的端口連接按鍵,那么:

蜂鳴器發(fā)聲:echo 57 w1 > gpio

蜂鳴器停止:echo 57 w0 > gpio

讀取按鍵狀態(tài):echo 37 r > gpio

那么這個gpio文件結(jié)點在哪呢?

內(nèi)核啟動后會把debugfs文件系統(tǒng)掛載到/sys/kernel/debug目錄下,我們的gpio文件結(jié)點就在這里。

如果沒有找到,那么可以手動掛載mount-t debugfs none /mnt,這樣就掛載到/mnt目錄下了。

?

PS:

更為強大的調(diào)試選項:

CONFIG_GPIO_SYSFS?? 定義此宏后 會在/sys/class/gpio/下面到處gpio的設(shè)備文件 可以通過此設(shè)備文件對gpio進行控制與讀取???

?

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

Linux內(nèi)核里的DebugFS

2011-01-17 23:52 by wwang, 4597 閱讀,?5?評論,?收藏,編輯

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

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

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

?

# mount -t debugfs none /your/debugfs/dir

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

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

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

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

  • my_debugfs_root = debugfs_create_dir("mydebug", NULL);

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

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

  • sub_dir = debugfs_create_dir("subdir", my_debugfs_root);

  • 建立文件a的代碼非常簡單:

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

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

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

    b是一個32-bytes的字符數(shù)組,在debugfs里,數(shù)組可以用blob wrapper來實現(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,但實際這個文件還是只讀的,如果試圖改寫這個文件,系統(tǒng)將提示出錯。

    如果需要對內(nèi)核數(shù)組進行寫的動作,blob wrapper就無法滿足要求,我們只能通過自己定義文件操作來實現(xiàn)。在這個實作里,可以參考文件c的實現(xiàn)。c和b在模塊里對應(yīng)著同一塊字符數(shù)組,不同的是,b是只讀的,而c通過自定義的文件操作同時實現(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其實并沒有任何用處,因為c_read和c_write直接引用了全局變量hello。這里,我們也可以換一種寫法,在read/write函數(shù)里用filp->private_data來引用字符數(shù)組hello。

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

    debugfs_remove_recursive(my_debugfs_root);


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

    ?

    附錄:

    創(chuàng)建和撤銷目錄及文件

    structdentry *debugfs_create_dir(constchar *name, structdentry *parent);structdentry *debugfs_create_file(constchar *name, mode_t mode,structdentry *parent, void*data,conststruct file_operations *fops);void debugfs_remove(struct dentry *dentry);void debugfs_remove_recursive(struct dentry *dentry);

    創(chuàng)建單值文件

    structdentry *debugfs_create_u8(constchar *name, mode_t mode, structdentry *parent, u8 *value);structdentry *debugfs_create_u16(constchar *name, mode_t mode,structdentry *parent, u16 *value);structdentry *debugfs_create_u32(constchar *name, mode_t mode,structdentry *parent, u32 *value);structdentry *debugfs_create_u64(constchar *name, mode_t mode, structdentry *parent, u64 *value);structdentry *debugfs_create_x8(constchar *name, mode_t mode, structdentry *parent, u8 *value);structdentry *debugfs_create_x16(constchar *name, mode_t mode, structdentry *parent, u16 *value);structdentry *debugfs_create_x32(constchar *name, mode_t mode, structdentry *parent, u32 *value);structdentry *debugfs_create_size_t(constchar *name, mode_t mode, structdentry *parent, size_t*value);structdentry *debugfs_create_bool(constchar *name, mode_t mode, structdentry *parent, u32 *value);

    其中,后綴為x8、x16、x32的這三個函數(shù)是指debugfs中的數(shù)據(jù)用十六進制表示。

    創(chuàng)建BLOB文件

    structdebugfs_blob_wrapper {void*data;unsignedlong size;};structdentry *debugfs_create_blob(constchar *name, mode_t mode,structdentry *parent, structdebugfs_blob_wrapper *blob);

    其它

    structdentry *debugfs_rename(structdentry *old_dir, structdentry *old_dentry,structdentry *new_dir, constchar *new_name);structdentry *debugfs_create_symlink(constchar *name,structdentry *parent, constchar *target);

    ?

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

    ?

    以前都習(xí)慣用 printk 和 /proc 做輸入輸出的動作, 不過 debugfs 看起來是 User space 和 kernel space 交流更好的選擇.

    先確認(rèn) Enable Kernel debugfs Function

    Kernel hacking —>
    -*- Debug Filesystem

    先來個簡單的範(fàn)例,
    在你要 debug 的 modules 內(nèi), 加入 debugfs 的 include file

    #include <linux/debugfs.h>

    要將想要輸出的變數(shù), 假設(shè)叫 pcie0_linked 輸出到 debugfs 上, 在 initial code 的地方加上
    debugfs_create_u32("pcie0_linked", 0644, NULL, &pcie0_linked);

    接下來就可以重開機了 load 新 kernel 了,

    mount debugfs

    $ mount -t debugfs debug /debugfs

    或是寫在 /etc/fstab

    debugfs /debugfs debugfs debug

    這時就可以 ls /debugfs/ , 就會出現(xiàn) pcie0_linked 的檔案.

    $ cat /debugfs/pcie0_linked1$ echo 0 > /debugfs/pcie0_linked$ cat /debugfs/pcie0_linked0

    像是 procfs 一樣, debugfs 也有 create directory 的 function, 以便讓變數(shù)可以在目錄內(nèi)
    我們小小改一下上面的程式, 加上 create_dir 的功能

    struct dentry *pcie_dir;pcie_dir = debugfs_create_dir("pcie",NULL);if( pcie_dir != NULL ) {debugfs_create_u32("pcie0_linked", 0644, pcie_dir, &pcie0_linked);}

    改了以上的輸出, 接下來就可以在 /debugfs 下, 看到多了一個 pcie 的目錄, 而 pcie0_linked 就在裡面.

    如果想用 hex(16 進位), 可以改用 debugfs_create_x32.

    proc file system 最棒的就是可以讀寫檔案了, 可以做更多的控制.
    debugfs 也有一個 function 可以讓使用者做檔案讀寫, 這邊寫一個簡單的 sample.

    多 include 一個 header

    #include <linux/seq_file.h>static int pcie_reg_open(struct seq_file *s, void *data) { seq_printf(s, "pcie0_link status : %s\n", pcie0_linked == 1 ? "Enable": "D return 0; }static int pcie_single_open(struct inode *inode, struct file *file) { return single_open(file, pcie_reg_open, inode->i_private); } static ssize_t pcie_debug_write(struct file *file, const char __user *userbuf, size_t count, loff_t *ppos) { char buf[20];if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) return -EFAULT;printk("%s: %s \n",__FUNCTION__, buf);return count; }static const struct file_operations pcie_ios_fops = { .open = pcie_single_open, .read = seq_read, .write = pcie_debug_write, .llseek = seq_lseek, .release = single_release,}; debugfs_create_file("file", 0644, pcie_dir, NULL, &pcie_ios_fops);

    這樣

    $ cat /debugs/pcie/file 會顯示 pcie0_link status : Enable 而 $ echo "richliu" > /debugfs/pcie/file 會顯示 pcie_debug_write: richliu$

    ?

    最後要介紹的是比較特別的一種格式 blob, 這是可以傳 binary 到 user space 的格式, blob 的 struct 是

    struct debugfs_blob_wrapper { void *data; unsigned long size; };


    在剛剛的 Code 加上

    static struct debugfs_blob_wrapper blob; –> 最好放 global.
    char data[100];
    sprintf(data, "Data Pointer is : %08X \n", data);
    blob.data = data;
    blob.size = 100;
    debugfs_create_blob("blob", S_IRUSR, pcie_dir, &blob);

    在 Linux 下直接用 hexdump 去讀資料出來

    $ hexdump /debugfs/pcie/blob -c
    0000000 D a t a P o i n t e r i s
    0000010 : C 4 0 5 C 1 6 0 \n \0 \0 \0 \0
    0000020 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
    *
    0000060

    請記得 Blob 這個檔案是 Read Only, 只能傳出, 不能傳入…

    參考:
    Debugfs
    Debugfs 中譯版(好像是從匪區(qū)抄過來的?)

    總結(jié)

    以上是生活随笔為你收集整理的Linux驱动调试中的Debugfs的使用简介的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。