• 【打卡】21天学习挑战赛—RK3399平台开发入门到精通-day13



    活动地址:CSDN21天学习挑战赛

    学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您:
    想系统/深入学习某技术知识点…
    一个人摸索学习很难坚持,想组团高效学习…
    想写博客但无从下手,急需写作干货注入能量…
    热爱写作,愿意让自己成为更好的人…

    常见的内核调试手段-续

    10.debugfs 调试接口

    debugfs虚拟文件系统是一种内核空间与用户空间的接口,基于libfs库实现,专用于开发人员调试,便于向用户空间导出内核空间数据(当然,反方向也可以)。debugfs在linux内核版本2.6.10引入,作者是Greg Kroah-Hartman。
    与procfs和sysfs不同,前者主要提供进程信息(当然后来又加入设备、内存、网络等信息,比较杂乱),后者主要提供设备信息,且有一个文件提供一个值的“规则”,是Linux通用设备模型的影射。debugfs没有类似的限制,开发者可以放入任何信息。

    10.1 debugfs接口说明

    debugfs的API接口定义在kernel/include/linux/debugfs.h,要使用debugfs提供的api必须包含头文件#include 且使能编译宏CONFIG_DEBUG_FS常用的如下:

    //kernel/include/linux/debugfs.h
    /* 在指定的debugfs中创建一个目录,如果parent为空,则创建在在debugfs的根目录(/sys/kernel/debug) */
    struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
    /* 在debugfs中创建文件,需要实现文件的操作方法,如读写 */
    struct dentry *debugfs_create_file(const char *name, umode_t mode,
                       struct dentry *parent, void *data,
                       const struct file_operations *fops);
    /* 删除debugfs中的文件 */
    void debugfs_remove(struct dentry *dentry);
    /* 删除debugfs中的目录 */
    void debugfs_remove_recursive(struct dentry *dentry);
    
    /* 注意:因为在debugfs中创建的文件和目录在模块退出时,并不会自动删除,所以存在了上述API */
    
    /* 通过上面的API可以知道我们可以在debugfs中实现文件的创建删除,目录的创建删除,针对文件创建的时候还需要实现文件的操作方法,这是在某些时候比较麻烦的,必须我不需要有啥操作的,仅仅只是需要依靠文件导出而已,不需要啥操作,对此,debugfs提供了如下API */
    /* 将创建的文件绑定到u8变量 */
    struct dentry *debugfs_create_u8(const char *name, umode_t mode,
                     struct dentry *parent, u8 *value);
    /* 将创建的文件绑定到u16变量 */
    struct dentry *debugfs_create_u16(const char *name, umode_t mode,
                      struct dentry *parent, u16 *value);
    /* 将创建的文件绑定到u32变量 */
    struct dentry *debugfs_create_u32(const char *name, umode_t mode,
                      struct dentry *parent, u32 *value);
    /* 将创建的文件绑定到u64变量 */
    struct dentry *debugfs_create_u64(const char *name, umode_t mode,
                      struct dentry *parent, u64 *value);
    /* 关于debugfs的API这里列举的只是九牛一毛,剩下的感谢的朋友可以自行阅读该文件 */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    10.2 如何在debugfs中添加一个调试目录及文件

    debugfs全称Debug Filesystem,由宏CONFIG_DEBUG_FS控制。该宏使能编译后,系统启动后,内核自动挂载到默认目录/sys/kernel/debug,如果系统启动后没有自动挂载可使用该命令手动挂载,mount -t debugfs none /sys/kernel/debug,使能如下:

    在这里插入图片描述
    在这里插入图片描述

    10.2.1 示例

    #include 
    #include 
    #include 
    
    static struct dentry *dir = NULL;
    
    static unsigned int debugfs_hello;
    
    static u32 sum = 0;
    
    static int add_write(void *data, u64 value)
    {
        sum += value;
        return 0;
    }
    
    DEFINE_SIMPLE_ATTRIBUTE(add_ops, NULL, add_write, "%llu\n");
    
    static __init int hello_init(void)
    {
        struct dentry *tmp_dir = NULL;
    
        /* create /sys/kernel/debug/debugfs_hello/ directory */
        dir = debugfs_create_dir("debugfs_hello", NULL);
        if (!dir) {
            printk(KERN_ALERT "debugfs_create_dir failed\n");
            return -1;
        }
    
        /* create /sys/kernel/debug/debugfs_hello/hello value, mode: rw*/
        tmp_dir = debugfs_create_u32("hello", 00666, dir, &debugfs_hello);
        if (!tmp_dir) {
            printk(KERN_ALERT "debugfs_create_u32 failed\n");
            return -1;
        }
    
        /* create /sys/kernel/debug/debugfs_hello/add value, mode: w*/
        tmp_dir = debugfs_create_file("add", 0222, dir, NULL, &add_ops);
        if (!tmp_dir) {
            printk(KERN_ALERT "debugfs_create_file failed\n");
            return -1;
        }
    
        /* create /sys/kernel/debug/debugfs_hello/sum value, mode: r*/
        tmp_dir = debugfs_create_u32("sum", 0444, dir, &sum);
        if (!tmp_dir) {
            printk(KERN_ALERT "debugfs_create_u32 failed\n");
            return -1;
        }
    
        return 0;
    }
    
    
    static void __exit hello_exit(void)
    {
        printk(KERN_INFO "Exit debugfs_hello module\n");
        debugfs_remove_recursive(dir);
        dir = NULL;
    }
    
    module_init(hello_init);
    module_exit(hello_exit);
    
    MODULE_LICENSE("Dual BSD/GPL");
    MODULE_DESCRIPTION("Debugfs hello example");
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    经过上面的驱动加载,可以在debugfs驱动的根目录找到我们的驱动debugfs_hello,如下:
    在这里插入图片描述
    现在可以来测试下该驱动实现的功能,它所实现的就是一个加法驱动,主要体现在三个文件,如下图所示,且三个文件的读写权限功能各不相同,接下来通过后面一系列操作来阐述。
    在这里插入图片描述
    查看三个文件的值,可以看到这里hellosum的初始值默认为0,而add是不可读的,它没有读权限,为什么?因为它的实现目的是加法运算,不是用来存储展示给人看的值,因此不需要读权限。
    在这里插入图片描述
    现在先看hello文件,尝试往hello中
    写入数据11
    ,写入成功查看,11成功写入到hello文件,接着继续查看三个文件的值,这里发现只echo 11 > hello 只改变了hello的值,为什么?因为hello文件和其他两个文件没有什么关系,它仅仅是个单纯的存储值的文件。
    在这里插入图片描述
    接下来看sum文件,尝试往sum中写入值,我们发现无法写入,没有写权限,为什么?顾名思义sum是最终的和结果,它应该只具备读权限
    在这里插入图片描述
    接下来看add文件,尝试往add文件中写入111,发现写入成功,这里侧面验证了
    sum文件的功能和特性(可读不可写)
    ,继续读取三个值,发现sum0变为111了,这里也可以看出往add中输入的值,通过add操作将最终值给到了sum。因此最终得出了sum和add是有联系的两个文件,通过往add写值,最终结果add到sum文件,由sum文件保存和显示。
    在这里插入图片描述
    扩展:在不阅读源码的情况下,我们可以猜测add是持续add还是单次add呢?我们接着往add中写入111看看什么现象
    在这里插入图片描述
    这里很明显的说明add是持续add,即累计add,最终结果由sum显示。

    参考:Debugfs

  • 相关阅读:
    RTX3090+win10+CUDA11.6+cudnn8.5.0+pytorch1.12.1 环境——个人配置经验
    【mysql进阶】MTS主从同步原理及实操指南
    基于uni-app框架的小程序——点击跟随事件
    cocos2dx中,将png图片打包plist图集,使用什么工具呢?
    NX二次开发-将工程图视图+尺寸的最大边界导出图片
    跑跑飞弹室外跑步AR游戏代码方案设计
    阿里云SLB之:基于多域名调度的SLB七层负载均衡配置(十四)
    吃透Chisel语言.27.Chisel进阶之有限状态机(一)——基本有限状态机(Moore机)
    Python fileinput模块:逐行读取多个文件
    磁盘管理:硬盘、分区、文件系统 | 查看磁盘信息的方法
  • 原文地址:https://blog.csdn.net/qq_23327993/article/details/126330845