0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

linux内核中的debugfs该怎样去使用呢?

嵌入式小生 来源:嵌入式小生 2023-08-21 09:01 次阅读

二、简介

debugfs可用于内核向用户空间提供信息,debugfs是个小型的文件系统,与/proc和sysfs不同,debugfs没有较为严苛的规则和定义,我们可以在里面放置想要的任何信息,以便于系统开发和调试。

通常使用如下命令安装debugfs:

mount-tdebugfsnone/sys/kernel/debug

或者:

mount-tdebugfsdebugfs/sys/kernel/debug/

也可以在/etc/fstab文件中使用等效的语句:

af29dad6-3fb9-11ee-ac96-dac502259ad0.png

默认情况下,在一些发行版的linux系统中,只有root用户可以访问debugfs根目录。

注意,在内核源码中,debugfs API仅以GPL方式导出到模块。

三、debugfs的API

1、在debugfs中创建目录

使用debugfs的代码应包含头文件。然后是创建至少一个目录来保存一组debugfs文件,可使用下列API实现:

structdentry*debugfs_create_dir(constchar*name,structdentry*parent);

当函数执行成功后,将在指定的父目录下创建一个名为name的目录,如果parent为NULL,则该目录将在debugfs根目录中创建。

函数执行成功后,返回一个指向struct dentry的指针,可用于在目录中创建文件。

如果返回值为ERR_PTR(-ERROR)则表明出现了问题,如果返回ERR_PTR(-ENODEV),则表明内核是在没有debugfs支持的情况下构建,这时候相关API将失效。

2、在debugfs目录中创建文件

在debugfs目录中创建文件的常用API是:

structdentry*debugfs_create_file(constchar*name,umode_tmode,structdentry*parent,
void*data,conststructfile_operations*fops);

name是要创建文件的名称。

mode描述了文件应具有的访问权限。

parent表示应保存该文件的目录,数据将存储在生成的inode结构的i_private字段中。

fops是一个实现文件行为的一组文件操作。struct file_operations中包含了关于文件操作的很多接口函数,此处至少应提供read()和write()操作,其他操作可以根据实际情况实现。

该函数返回值将是指向所创建文件的dentry指针,如果发生错误,则返回ERR_PTR(-ERROR),如果缺少debugfs支持,则返回ERR_PTR(-ENODEV)。

3、创建一个具有初始大小的文件

创建一个具有初始大小的文件,可以使用以下API:

voiddebugfs_create_file_size(constchar*name,umode_tmode,structdentry*parent,void*data,
conststructfile_operations*fops,loff_tfile_size);

file_size是初始文件大小,其他参数与函数debugfs_create_file相同。

4、创建包含单个整数值(十进制)的文件

在多数情况下,创建一组文件操作并不是必需的,这时候可以使用以下助手函数创建包含单个整数值的文件:

//创建包含u8整数值的文件
voiddebugfs_create_u8(constchar*name,umode_tmode,structdentry*parent,u8*value);

//创建包含u16整数值的文件
voiddebugfs_create_u16(constchar*name,umode_tmode,structdentry*parent,u16*value);

////创建包含u32整数值的文件
voiddebugfs_create_u32(constchar*name,umode_tmode,structdentry*parent,u32*value);

//创建包含u64整数值的文件
voiddebugfs_create_u64(constchar*name,umode_tmode,structdentry*parent,u64*value);

这些文件支持读取和写入给定值;如果不支持写入特定文件,只需相应设置模式位即可,使用上述API创建的文件中的值是十进制的。

5、创建包含单个十六进制值的文件:

如果需要设置十六进制,可以使用以下API函数:

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);

只要我们知道要导出的值的大小,上述函数就非常有用。但是需要注意的是,某些类型在不同体系结构上可能具有不同的宽度。下列函数可以在这种特殊情况下提供帮助:

voiddebugfs_create_size_t(constchar*name,umode_tmode,structdentry*parent,size_t*value);

debugfs_create_size_t()函数将创建一个debugfs文件来表示size_t类型的变量。

6、创建包含unsigned long 类型的变量的文件

对于十进制和十六进制的 unsigned long 类型的变量可使用以下助手函数:

structdentry*debugfs_create_ulong(constchar*name,umode_tmode,structdentry*parent,unsignedlong*value);

voiddebugfs_create_xul(constchar*name,umode_tmode,structdentry*parent,unsignedlong*value);

7、创建包含布尔类型的文件

对于布尔值可使用下列API函数:

voiddebugfs_create_bool(constchar*name,umode_tmode,structdentry*parent,bool*value);

读取结果文件将产生Y(对于非零值)或N,后跟换行符。如果想要向该文件写入数值,该文件将接收大写或小写值,或者1或0,其他任何的输入都将被忽略。

8、创建包含atomic_t类型的值的文件

atomic_t值可使用以下API函数放置在debugfs中:

voiddebugfs_create_atomic_t(constchar*name,umode_tmode,structdentry*parent,atomic_t*value)

读取该文件将获取atomic_t值,写入该文件将设置atomic_t值。

9、创建包含二进制数据块的文件

也可以导出二进制数据块,数据块具有以下结构和功能:

structdebugfs_blob_wrapper{
void*data;
unsignedlongsize;
};

structdentry*debugfs_create_blob(constchar*name,umode_tmode,structdentry*parent,structdebugfs_blob_wrapper*blob);

如果想转储一个寄存器块,debugfs提供了两个函数:1、创建一个只有寄存器的文件。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参数可能为0,但可能希望使用__stringify构建reg32数组,许多寄存器名(宏)实际上是寄存器基数上的字节偏移量。

10、创建u32数组的文件

如果想在debugfs中转储一个u32数组,可使用以下API:

structdebugfs_u32_array{
u32*array;
u32n_elements;
};

voiddebugfs_create_u32_array(constchar*name,umode_tmode,structdentry*parent,structdebugfs_u32_array*array);

array参数包装了一个指向数组数据及其元素数量的指针。

注意:一旦数组被创建,它的大小不能被改变。

11、创建与设备相关的seq_file

有一个助手函数可用于创建与设备相关的seq_file:

voiddebugfs_create_devm_seqfile(structdevice*dev,constchar*name,structdentry*parent,
int(*read_fn)(structseq_file*s,void*data));

dev参数是与这个debugfs文件相关的设备。

read_fn是一个函数指针,用于调用它来打印seq_file内容。

12、为debugfs中的文件重命名

如果想要重命名debugfs目录下的文件名,可使用以下API:

structdentry*debugfs_rename(structdentry*old_dir,structdentry*old_dentry,
structdentry*new_dir,constchar*new_name);

调用debugfs_rename()将为现有的debugfs文件(可能在不同的目录中)提供一个新名称,在调用debugfs_rename()之前必须不存在new_name,返回值是带有更新后信息的old_dentry。

13、为debugfs目录中的文件创建符号链接

符号链接可通过debugfs_create_symlink()创建:

structdentry*debugfs_create_symlink(constchar*name,structdentry*parent,constchar*target);

14、删除debugfs创建的目录或者文件

在debugfs中创建的所有目录都不会自动清除。如果在没有显式删除debugfs项的情况下卸载了一个模块,这时结果将是出现大量过时的指针,还可能会出现一些奇怪的行为。因此,必须存在删除创建的所有文件和目录的操作和入口点。

可使用以下API删除文件:

voiddebugfs_remove(structdentry*dentry);

如果dentry值是NULL或错误值,这时候将不会删除任何内容。

使用下列API可以删除整个目录层级结构,在调试的时候可以使用:

voiddebugfs_remove_recursive(structdentry*dentry);

如果将指向与顶级目录对应的dentry的指针传递给该debugfs_remove_recursive(),这时候该目录下的整个层次结构将被删除。

更多API可参见文末附上的参考链接。

四、实验代码

在本小节中,将使用上述提到的API在debugfs中创建目录,并导出相应的参数描述文件,然后在命令行中对其进行查看,首先设计代码:

/**
*@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中创建一个名为debugfs_demo_dir的目录,并且在该目录中导出五种类型的数据:

1、通用文件数据:general_file,值默认没指定

2、以十进制导出数据:u8data,值为90

3、以十六进制导出数据:x8data,值为0x5a

4、布尔类型数据:boolData,值为N

5、blob类型数据:blobData,值为0x01,0x05,0x12,0x23

将上述代码以模块方式构建后(模块名debugfs_demo.ko)拷贝到目标平台中,使用mount命令查看目前已挂载的文件系统:

af55e4b4-3fb9-11ee-ac96-dac502259ad0.png

发现并没有挂载debugfs,这时候使用以下命令可以手动挂载debugfs:

mount-tdebugfsdebugfs/sys/kernel/debug/
af89f272-3fb9-11ee-ac96-dac502259ad0.png

接着将debugfs_demo.ko加载进内核,完成后将路径切换进/sys/kernel/debug:

afc97f8c-3fb9-11ee-ac96-dac502259ad0.png

这时候看到期望的debugfs目录debugfs_demo_dir导出成功,然后切换进该目录中:

afe6f670-3fb9-11ee-ac96-dac502259ad0.png

看见了在驱动程序中创建的五个文件,分别查看一下数据:

b023cb22-3fb9-11ee-ac96-dac502259ad0.png

从输出结果分析,数据符合驱动程序运行后预期的结果!






审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    31

    文章

    5305

    浏览量

    119924
  • Linux系统
    +关注

    关注

    4

    文章

    590

    浏览量

    27330
  • 十六进制
    +关注

    关注

    2

    文章

    32

    浏览量

    37684
  • LINUX内核
    +关注

    关注

    1

    文章

    316

    浏览量

    21610
  • gpl
    gpl
    +关注

    关注

    0

    文章

    26

    浏览量

    2168

原文标题:linux内核中的debugfs原来可以这样玩!

文章出处:【微信号:嵌入式小生,微信公众号:嵌入式小生】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    在Boost电源怎样选择电容的型号和电容容量

    我们之前了解过电容的作用,不外乎储能、滤波等作用。那么在Boost电源又该怎样选择电容的型号和电容容量
    发表于 08-14 15:44 2797次阅读
    在Boost电源<b class='flag-5'>中</b><b class='flag-5'>该</b><b class='flag-5'>怎样</b><b class='flag-5'>去</b>选择电容的型号和电容容量<b class='flag-5'>呢</b>?

    怎样移植linux内核

    怎样移植linux内核?有哪些操作流程?
    发表于 10-19 09:40

    内核 uC/OS-II 怎样移植

    uC/OS-II内核结构是如何构成的?微内核 uC/OS-II 的任务到底是什么?微内核 uC/OS-II
    发表于 10-29 07:21

    怎样使用Cortex-M内核的精确延时方法

    为什么要学习这种Cortex-M内核的精确延时方法怎样使用Cortex-M内核
    发表于 11-30 06:00

    嵌入式Linux操作系统怎样使用

    嵌入式Linux操作系统怎样使用?嵌入式Linux操作系统的命令有哪些
    发表于 12-23 08:06

    FreeRtos消息队列API的调用怎样实现

    消息队列是什么?消息队列有何作用?FreeRtos消息队列API的调用怎样实现
    发表于 01-20 07:04

    socket通信怎样实现

    socket通信怎样实现怎样实现socket AES-CBC加密
    发表于 01-20 07:41

    ROS服务数据怎样使用

    ROS服务数据是怎样定义的?ROS服务数据怎样使用
    发表于 02-14 06:20

    Ubuntu固件的编译怎样使用

    怎样编译Ubuntu固件?Ubuntu固件的编译怎样使用
    发表于 02-15 06:18

    怎样编译Linux内核

    怎样编译Linux内核?有哪些编译步骤?
    发表于 03-03 13:04

    怎样解决RK3399内核编译出错的问题

    怎样解决RK3399内核编译出错的问题
    发表于 03-07 06:10

    怎样Linux内核源代码

    怎样Linux内核源代码
    发表于 10-25 10:15 13次下载
    <b class='flag-5'>怎样</b><b class='flag-5'>去</b>读<b class='flag-5'>Linux</b><b class='flag-5'>内核</b>源代码

    你知道Linux内核里的DebugFS

    DebugFS,顾名思义,是一种用于内核调试的虚拟文件系统,内核开发者通过debugfs和用户空间交换数据。
    发表于 04-25 18:55 1871次阅读
    你知道<b class='flag-5'>Linux</b><b class='flag-5'>内核</b>里的<b class='flag-5'>DebugFS</b>?

    要学会调试内核打印debugfs

    name是创建的目录名字,parent是目录的父目录。如果填NULL,则直接出现在debugfs的根目录。
    发表于 04-27 19:01 1183次阅读

    Linux驱动debugfs接口代码实现

    实现效果 在 /sys/kernel/debug/ 目录下创建一个 ion/test 文件,通过 cat 、 echo 的方式进行读写操作: 前期准备 内核配置打开debugfs
    的头像 发表于 09-27 11:12 418次阅读
    <b class='flag-5'>Linux</b>驱动<b class='flag-5'>debugfs</b>接口代码实现