二、簡介
debugfs可用于內(nèi)核向用戶空間提供信息,debugfs是個小型的文件系統(tǒng),與/proc和sysfs不同,debugfs沒有較為嚴(yán)苛的規(guī)則和定義,我們可以在里面放置想要的任何信息,以便于系統(tǒng)開發(fā)和調(diào)試。
通常使用如下命令安裝debugfs:
mount-tdebugfsnone/sys/kernel/debug
或者:
mount-tdebugfsdebugfs/sys/kernel/debug/
也可以在/etc/fstab文件中使用等效的語句:
默認(rèn)情況下,在一些發(fā)行版的linux系統(tǒng)中,只有root用戶可以訪問debugfs根目錄。
注意,在內(nèi)核源碼中,debugfs API僅以GPL方式導(dǎo)出到模塊。
三、debugfs的API
1、在debugfs中創(chuàng)建目錄
使用debugfs的代碼應(yīng)包含
structdentry*debugfs_create_dir(constchar*name,structdentry*parent);
當(dāng)函數(shù)執(zhí)行成功后,將在指定的父目錄下創(chuàng)建一個名為name的目錄,如果parent為NULL,則該目錄將在debugfs根目錄中創(chuàng)建。
函數(shù)執(zhí)行成功后,返回一個指向struct dentry的指針,可用于在目錄中創(chuàng)建文件。
如果返回值為ERR_PTR(-ERROR)則表明出現(xiàn)了問題,如果返回ERR_PTR(-ENODEV),則表明內(nèi)核是在沒有debugfs支持的情況下構(gòu)建,這時候相關(guān)API將失效。
2、在debugfs目錄中創(chuàng)建文件
在debugfs目錄中創(chuàng)建文件的常用API是:
structdentry*debugfs_create_file(constchar*name,umode_tmode,structdentry*parent, void*data,conststructfile_operations*fops);
name是要創(chuàng)建文件的名稱。
mode描述了文件應(yīng)具有的訪問權(quán)限。
parent表示應(yīng)保存該文件的目錄,數(shù)據(jù)將存儲在生成的inode結(jié)構(gòu)的i_private字段中。
fops是一個實現(xiàn)文件行為的一組文件操作。struct file_operations中包含了關(guān)于文件操作的很多接口函數(shù),此處至少應(yīng)提供read()和write()操作,其他操作可以根據(jù)實際情況實現(xiàn)。
該函數(shù)返回值將是指向所創(chuàng)建文件的dentry指針,如果發(fā)生錯誤,則返回ERR_PTR(-ERROR),如果缺少debugfs支持,則返回ERR_PTR(-ENODEV)。
3、創(chuàng)建一個具有初始大小的文件
創(chuàng)建一個具有初始大小的文件,可以使用以下API:
voiddebugfs_create_file_size(constchar*name,umode_tmode,structdentry*parent,void*data, conststructfile_operations*fops,loff_tfile_size);
file_size是初始文件大小,其他參數(shù)與函數(shù)debugfs_create_file相同。
4、創(chuàng)建包含單個整數(shù)值(十進制)的文件
在多數(shù)情況下,創(chuàng)建一組文件操作并不是必需的,這時候可以使用以下助手函數(shù)創(chuàng)建包含單個整數(shù)值的文件:
//創(chuàng)建包含u8整數(shù)值的文件 voiddebugfs_create_u8(constchar*name,umode_tmode,structdentry*parent,u8*value); //創(chuàng)建包含u16整數(shù)值的文件 voiddebugfs_create_u16(constchar*name,umode_tmode,structdentry*parent,u16*value); ////創(chuàng)建包含u32整數(shù)值的文件 voiddebugfs_create_u32(constchar*name,umode_tmode,structdentry*parent,u32*value); //創(chuàng)建包含u64整數(shù)值的文件 voiddebugfs_create_u64(constchar*name,umode_tmode,structdentry*parent,u64*value);
這些文件支持讀取和寫入給定值;如果不支持寫入特定文件,只需相應(yīng)設(shè)置模式位即可,使用上述API創(chuàng)建的文件中的值是十進制的。
5、創(chuàng)建包含單個十六進制值的文件:
如果需要設(shè)置十六進制,可以使用以下API函數(shù):
voiddebugfs_create_x8(constchar*name,umode_tmode,structdentry*parent,u8*value); voiddebugfs_create_x16(constchar*name,umode_tmode,structdentry*parent,u16*value); voiddebugfs_create_x32(constchar*name,umode_tmode,structdentry*parent,u32*value); voiddebugfs_create_x64(constchar*name,umode_tmode,structdentry*parent,u64*value);
只要我們知道要導(dǎo)出的值的大小,上述函數(shù)就非常有用。但是需要注意的是,某些類型在不同體系結(jié)構(gòu)上可能具有不同的寬度。下列函數(shù)可以在這種特殊情況下提供幫助:
voiddebugfs_create_size_t(constchar*name,umode_tmode,structdentry*parent,size_t*value);
debugfs_create_size_t()函數(shù)將創(chuàng)建一個debugfs文件來表示size_t類型的變量。
6、創(chuàng)建包含unsigned long 類型的變量的文件
對于十進制和十六進制的 unsigned long 類型的變量可使用以下助手函數(shù):
structdentry*debugfs_create_ulong(constchar*name,umode_tmode,structdentry*parent,unsignedlong*value); voiddebugfs_create_xul(constchar*name,umode_tmode,structdentry*parent,unsignedlong*value);
7、創(chuàng)建包含布爾類型的文件
對于布爾值可使用下列API函數(shù):
voiddebugfs_create_bool(constchar*name,umode_tmode,structdentry*parent,bool*value);
讀取結(jié)果文件將產(chǎn)生Y(對于非零值)或N,后跟換行符。如果想要向該文件寫入數(shù)值,該文件將接收大寫或小寫值,或者1或0,其他任何的輸入都將被忽略。
8、創(chuàng)建包含atomic_t類型的值的文件
atomic_t值可使用以下API函數(shù)放置在debugfs中:
voiddebugfs_create_atomic_t(constchar*name,umode_tmode,structdentry*parent,atomic_t*value)
讀取該文件將獲取atomic_t值,寫入該文件將設(shè)置atomic_t值。
9、創(chuàng)建包含二進制數(shù)據(jù)塊的文件
也可以導(dǎo)出二進制數(shù)據(jù)塊,數(shù)據(jù)塊具有以下結(jié)構(gòu)和功能:
structdebugfs_blob_wrapper{ void*data; unsignedlongsize; }; structdentry*debugfs_create_blob(constchar*name,umode_tmode,structdentry*parent,structdebugfs_blob_wrapper*blob);
如果想轉(zhuǎn)儲一個寄存器塊,debugfs提供了兩個函數(shù):1、創(chuàng)建一個只有寄存器的文件。2、在另一個順序文件的中間位置插入一個寄存器塊:
structdebugfs_reg32{ char*name; unsignedlongoffset; }; structdebugfs_regset32{ conststructdebugfs_reg32*regs; intnregs; void__iomem*base; structdevice*dev;/*OptionaldeviceforRuntimePM*/ }; debugfs_create_regset32(constchar*name,umode_tmode,structdentry*parent,structdebugfs_regset32*regset); voiddebugfs_print_regs32(structseq_file*s,conststructdebugfs_reg32*regs,intnregs,void__iomem*base,char*prefix);
debugfs_print_regs32()中的base參數(shù)可能為0,但可能希望使用__stringify構(gòu)建reg32數(shù)組,許多寄存器名(宏)實際上是寄存器基數(shù)上的字節(jié)偏移量。
10、創(chuàng)建u32數(shù)組的文件
如果想在debugfs中轉(zhuǎn)儲一個u32數(shù)組,可使用以下API:
structdebugfs_u32_array{ u32*array; u32n_elements; }; voiddebugfs_create_u32_array(constchar*name,umode_tmode,structdentry*parent,structdebugfs_u32_array*array);
array參數(shù)包裝了一個指向數(shù)組數(shù)據(jù)及其元素數(shù)量的指針。
注意:一旦數(shù)組被創(chuàng)建,它的大小不能被改變。
11、創(chuàng)建與設(shè)備相關(guān)的seq_file
有一個助手函數(shù)可用于創(chuàng)建與設(shè)備相關(guān)的seq_file:
voiddebugfs_create_devm_seqfile(structdevice*dev,constchar*name,structdentry*parent, int(*read_fn)(structseq_file*s,void*data));
dev參數(shù)是與這個debugfs文件相關(guān)的設(shè)備。
read_fn是一個函數(shù)指針,用于調(diào)用它來打印seq_file內(nèi)容。
12、為debugfs中的文件重命名
如果想要重命名debugfs目錄下的文件名,可使用以下API:
structdentry*debugfs_rename(structdentry*old_dir,structdentry*old_dentry, structdentry*new_dir,constchar*new_name);
調(diào)用debugfs_rename()將為現(xiàn)有的debugfs文件(可能在不同的目錄中)提供一個新名稱,在調(diào)用debugfs_rename()之前必須不存在new_name,返回值是帶有更新后信息的old_dentry。
13、為debugfs目錄中的文件創(chuàng)建符號鏈接
符號鏈接可通過debugfs_create_symlink()創(chuàng)建:
structdentry*debugfs_create_symlink(constchar*name,structdentry*parent,constchar*target);
14、刪除debugfs創(chuàng)建的目錄或者文件
在debugfs中創(chuàng)建的所有目錄都不會自動清除。如果在沒有顯式刪除debugfs項的情況下卸載了一個模塊,這時結(jié)果將是出現(xiàn)大量過時的指針,還可能會出現(xiàn)一些奇怪的行為。因此,必須存在刪除創(chuàng)建的所有文件和目錄的操作和入口點。
可使用以下API刪除文件:
voiddebugfs_remove(structdentry*dentry);
如果dentry值是NULL或錯誤值,這時候?qū)⒉粫h除任何內(nèi)容。
使用下列API可以刪除整個目錄層級結(jié)構(gòu),在調(diào)試的時候可以使用:
voiddebugfs_remove_recursive(structdentry*dentry);
如果將指向與頂級目錄對應(yīng)的dentry的指針傳遞給該debugfs_remove_recursive(),這時候該目錄下的整個層次結(jié)構(gòu)將被刪除。
更多API可參見文末附上的參考鏈接。
四、實驗代碼
在本小節(jié)中,將使用上述提到的API在debugfs中創(chuàng)建目錄,并導(dǎo)出相應(yīng)的參數(shù)描述文件,然后在命令行中對其進行查看,首先設(shè)計代碼:
/** *@filedebugfs_demo.c *@authoryourname(you@domain.com) *@briefdebugfsapiusage *@version0.1 *@date2023-08-17 * *@copyrightCopyright(c)2023 * */ #include#include #include #include #include #include #include #include #include #defineBUFFER_SIZE256 staticcharbuffer[BUFFER_SIZE]; staticstructdentry*debugfs_demo_dir; staticu8u8data=90; staticu32boolData=false; staticstructdentry*general_file,*u8data_dentry,*x8data_dentry,*bool_dentry; staticintgeneral_file_open(structinode*inode,structfile*file) { printk(KERN_INFO"dogeneral_file_openops "); return0; } staticssize_tgeneral_file_read(structfile*file,char__user*ubuf,size_tsize,loff_t*loff) { returnsimple_read_from_buffer(ubuf,size,loff,buffer,BUFFER_SIZE); } staticssize_tgeneral_file_write(structfile*file,constchar__user*ubuf,size_tsize,loff_t*loff) { if(size>BUFFER_SIZE)return-EINVAL; returnsimple_write_to_buffer(buffer,BUFFER_SIZE,loff,ubuf,size); } staticstructfile_operationsgeneral_file_ops= { .open=general_file_open, .read=general_file_read, .write=general_file_write }; staticchardata[4]={0x01,0x05,0x12,0x23}; staticstructdebugfs_blob_wrapperblobData={data,4}; staticint__initdebugfs_demo_init(void) { //1、createdebugfs_demo_dirdirindebugfs debugfs_demo_dir=debugfs_create_dir("debugfs_demo_dir",NULL); if(!debugfs_demo_dir){ pr_err("failedtocreatedebugfsentrydebugfs_demo_dir "); return-1; } //2、creategeneral_fileindebugfs_demo_dir general_file=debugfs_create_file("general_file",0644,debugfs_demo_dir,NULL,&general_file_ops); //3、createu8dataindebugfs u8data_dentry=debugfs_create_u8("u8data",0644,debugfs_demo_dir,&u8data); //4、createx8dataindebugfs x8data_dentry=debugfs_create_x8("x8data",0644,debugfs_demo_dir,&u8data); //5、createboolDataindebugfs bool_dentry=debugfs_create_bool("boolData",0644,debugfs_demo_dir,&boolData); //6、createblobDataindebugfs debugfs_create_blob("blobData",0644,debugfs_demo_dir,&blobData); printk(KERN_INFO"debugfsdemocreatesuccessful "); return0; } staticvoid__exitdebugfs_demo_exit(void) { debugfs_remove_recursive(debugfs_demo_dir); printk(KERN_INFO"debugfs_demo_exit "); } module_init(debugfs_demo_init); module_exit(debugfs_demo_exit); MODULE_AUTHOR("iriczhao"); MODULE_LICENSE("GPL");
在上述代碼中,將在debugfs中創(chuàng)建一個名為debugfs_demo_dir的目錄,并且在該目錄中導(dǎo)出五種類型的數(shù)據(jù):
1、通用文件數(shù)據(jù):general_file,值默認(rèn)沒指定
2、以十進制導(dǎo)出數(shù)據(jù):u8data,值為90
3、以十六進制導(dǎo)出數(shù)據(jù):x8data,值為0x5a
4、布爾類型數(shù)據(jù):boolData,值為N
5、blob類型數(shù)據(jù):blobData,值為0x01,0x05,0x12,0x23
將上述代碼以模塊方式構(gòu)建后(模塊名debugfs_demo.ko)拷貝到目標(biāo)平臺中,使用mount命令查看目前已掛載的文件系統(tǒng):
發(fā)現(xiàn)并沒有掛載debugfs,這時候使用以下命令可以手動掛載debugfs:
mount-tdebugfsdebugfs/sys/kernel/debug/
接著將debugfs_demo.ko加載進內(nèi)核,完成后將路徑切換進/sys/kernel/debug:
這時候看到期望的debugfs目錄debugfs_demo_dir導(dǎo)出成功,然后切換進該目錄中:
看見了在驅(qū)動程序中創(chuàng)建的五個文件,分別查看一下數(shù)據(jù):
從輸出結(jié)果分析,數(shù)據(jù)符合驅(qū)動程序運行后預(yù)期的結(jié)果!
審核編輯:劉清
-
寄存器
+關(guān)注
關(guān)注
31文章
5343瀏覽量
120365 -
Linux系統(tǒng)
+關(guān)注
關(guān)注
4文章
593瀏覽量
27397 -
十六進制
+關(guān)注
關(guān)注
2文章
32瀏覽量
37744 -
LINUX內(nèi)核
+關(guān)注
關(guān)注
1文章
316瀏覽量
21650 -
gpl
+關(guān)注
關(guān)注
0文章
26瀏覽量
2181
原文標(biāo)題:linux內(nèi)核中的debugfs原來可以這樣玩!
文章出處:【微信號:嵌入式小生,微信公眾號:嵌入式小生】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論