Linux之debugfs介紹
Debugfs是一種用於內核調試的虛擬文件系統,在內核源碼中經常可以看到它的使用,今天我來大概介紹一下它的使用。
如果你對debugfs不熟悉,那麼也許你會對sysfs比較熟悉,對於調試方面,其實兩個文件系統還是挺類似的,但是sysfs的引入內核主要是用於驅動模型的。所以我們在平時調試的時候應該儘量避免使用sysfs,而使用debugfs。
好了,下面我們來介紹一些debugfs的使用,要使用debugfs首先我們要設置一下配置選項CONFIG_DEBUG_FS,可以在config文件中設置CONFIG_DEBUG_FS=y,也可以通過menuconfig來設置,如圖:
- Kernelhacking --->
- [*]Debug Filesystem
驅動中使用debugfs需要包含頭文件<linux/debugfs.h>,爲了在用戶態下使用debugfs,必須把它mount到一個目錄下,我們可以把它放在mnt目錄下。
使用如下命令:
- <span xmlns="http://www.w3.org/1999/xhtml" style="">mount-t debugfs none /mnt</span>
然後進入/mnt後就可以看到我們在系統中創建的這些文件。
下面我們開始說一下如何在驅動中使用debugfs.
首先我們需要創建一個自己的目錄,利用如下函數:
- <span xmlns="http://www.w3.org/1999/xhtml" style="">struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);</span>
name就是創建的目錄的名字,parent是該目錄的父目錄,如果是NULL的話,則所創建的目錄就在debugfs的根目錄,具體使用如下:
- static struct dentry *binder_debugfs_dir_entry_root;
- binder_debugfs_dir_entry_root= debugfs_create_dir("binder", NULL);
這樣就會在debugfs的根目錄下創建一個binder的目錄,有了目錄還需要有可供讀寫的文件吧,下邊就是另一個重要的函數,文件的創建:
- struct dentry *debugfs_create_file(const char *name, mode_t mode,
- struct dentry *parent, void *data,
- const struct file_operations *fops)
如其函數名,這個函數的作用就是在parent這個目錄下創建一個名爲name的文件,mode是這個文件讀寫權限,data是傳入的參數,fops就比較重要了,爲我們的文件提供實際的讀寫操作。
在binder驅動中創建瞭如下文件
- debugfs_create_file("state",
- S_IRUGO,
- binder_debugfs_dir_entry_root,
- NULL,
- &binder_state_fops);
- debugfs_create_file("stats",
- S_IRUGO,
- binder_debugfs_dir_entry_root,
- NULL,
- &binder_stats_fops);
- debugfs_create_file("transactions",
- S_IRUGO,
- binder_debugfs_dir_entry_root,
- NULL,
- &binder_transactions_fops);
- debugfs_create_file("transaction_log",
- S_IRUGO,
- binder_debugfs_dir_entry_root,
- &binder_transaction_log,
- &binder_transaction_log_fops);
- debugfs_create_file("failed_transaction_log",
- S_IRUGO,
- binder_debugfs_dir_entry_root,
- &binder_transaction_log_failed,
- &binder_transaction_log_fops);
如上圖所示,在binder目錄下創建了proc/state/stats/transactions/transaction_log/failed_transaction_log這些文件。
在binder中這些文件的fops全部用一個宏來完成了
- #define BINDER_DEBUG_ENTRY(name) \
- static int binder_##name##_open(struct inode *inode, struct file *file) \
- {\
- return single_open(file, binder_##name##_show, inode->i_private); \
- }\
- \
- static const struct file_operations binder_##name##_fops = { \
- .owner= THIS_MODULE, \
- .open= binder_##name##_open, \
- .read= seq_read, \
- .llseek= seq_lseek, \
- .release= single_release, \
- }
可以看到binder沒有實現write操作。read則全部使用seq_file的操作,seq_file是2.4.15以後版本的內核中出現的新功能,使得內核輸出大文件信息。這邊我們就不去將seq了,我們放在另外的一篇文章裏面去講。
debugfs除了實現這個文件對函數的功能,還提供了一些API用來針對變量的操作:
- struct dentry *debugfs_create_u8(const char *name, mode_t mode, struct dentry *parent, u8 *value);
- struct dentry *debugfs_create_u16(const char *name, mode_t mode, structdentry *parent, u16 *value);
- struct dentry *debugfs_create_u32(const char *name, mode_t mode, structdentry *parent, u32 *value);
- struct dentry *debugfs_create_bool(const char *name, mode_t mode, structdentry *parent, u32 *value);
這樣就可以在用戶態去調試內核變量value了。
當內核卸載時,debugfs並不會自動的去清除我們創建的這些文件,對於創建的每一個文件我們都需要調用如下函數接口去清除: