当前位置 : 主页 > 编程语言 > 其它开发 >

debugfs使用指南

来源:互联网 收集:自由互联 发布时间:2022-06-20
debugfs概述 类似sysfs、procfs,debugfs 也是一种内存文件系统。不过不同于sysfs一个kobject对应一个文件,procfs和进程相关的特性,debugfs的灵活度很大,可以根据 需求对指定的变量进行导出
debugfs 概述

类似sysfs、procfs,debugfs 也是一种内存文件系统。不过不同于sysfs一个kobject对应一个文件,procfs和进程相关的特性,debugfs的灵活度很大,可以根据

需求对指定的变量进行导出并提供读写接口。debugfs又是一个Linux中 everything is a file 哲学的体现,通过VFS实现了对驱动的控制。可以通过以下命令,来

挂载debugfs到指定目录。

mount -t debugfs none /sys/kernel/debug
支持的读写类型

debugfs支持比较丰富的数据类型,如下所示。

使用方式

1、创建目录和文件

使用 debugfs_create_dir 创建一个目录,如果parent为NULL,则默认其父目录为debugfs的根目录。函数的返回值为NULL表示目录创建成功。

debugfs_create_file和debugfs_create_file_size都用来创建文件,不同的是debugfs_create_file_size可以通过file_size字段指定一个初始的大小。

name:文件名

mode:文件权限可以是整型(比如0644)也可以使用内核的宏

parent:父目录,如果为空则该文件的父目录为根目录

data:inode的i_private字段指向这个结构

fops:表示该文件的自定义操作,需要注意的是在我实际测试中open函数可能是必须要实现的,否则在使用echo命令的时候会报以下的错误

struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
struct dentry *debugfs_create_file(const char *name, umode_t mode,
                                   struct dentry *parent, void *data,
                                   const struct file_operations *fops);
void debugfs_create_file_size(const char *name, umode_t mode,
                              struct dentry *parent, void *data,
                              const struct file_operations *fops,
                              loff_t file_size);

2、创建无符号整型文件

//创建十进制的无符号文件
void debugfs_create_u8(const char *name, umode_t mode,
                       struct dentry *parent, u8 *value);
void debugfs_create_u16(const char *name, umode_t mode,
                        struct dentry *parent, u16 *value);
void debugfs_create_u32(const char *name, umode_t mode,
                        struct dentry *parent, u32 *value);
void debugfs_create_u64(const char *name, umode_t mode,
                        struct dentry *parent, u64 *value);
//创建十六进制的无符号文件
void debugfs_create_x8(const char *name, umode_t mode,
                       struct dentry *parent, u8 *value);
void debugfs_create_x16(const char *name, umode_t mode,
                        struct dentry *parent, u16 *value);
void debugfs_create_x32(const char *name, umode_t mode,
                        struct dentry *parent, u32 *value);
void debugfs_create_x64(const char *name, umode_t mode,
                        struct dentry *parent, u64 *value);

//创建一个size_t类型的文件
void debugfs_create_size_t(const char *name, umode_t mode,
                           struct dentry *parent, size_t *value);
//创建一个unsigned long类型的文件
struct dentry *debugfs_create_ulong(const char *name, umode_t mode,
                                    struct dentry *parent,
                                    unsigned long *value);
//创建一个十六进制的unsigned long类型的文件
void debugfs_create_xul(const char *name, umode_t mode,
                        struct dentry *parent, unsigned long *value);

3、布尔类型文件

void debugfs_create_bool(const char *name, umode_t mode,
                         struct dentry *parent, bool *value);

读布尔文件会显示Y或者N,写该文件时,只接受(Y, N, y, n, 0, 1)等值,其他值都只会被简单的忽略。

4、原子类型

void debugfs_create_atomic_t(const char *name, umode_t mode,
                             struct dentry *parent, atomic_t *value)

5、blob类型

使用debugfs_create_blob创建一个blob类型的文件,调用该函数前,我们需要在debugfs_blob_wrapper的data字段指定要展示的内容,size表示data长度。

需要注意的是blob类型的文件是只读的

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

struct dentry *debugfs_create_blob(const char *name, umode_t mode,
                                   struct dentry *parent,
                                   struct debugfs_blob_wrapper *blob);    

6、寄存器类型

使用 debugfs_reg32 表示一个寄存器内容,name表示文件名,offset表示相对于基地址的偏移。debugfs_regset32 表示一组寄存器文件,nregs:寄存器文件个数 base:io基地址

struct debugfs_reg32 {
    char *name;
    unsigned long offset;
};

struct debugfs_regset32 {
    const struct debugfs_reg32 *regs;
    int nregs;
    void __iomem *base;
    struct device *dev;     /* Optional device for Runtime PM */
};

debugfs_create_regset32(const char *name, umode_t mode,
                        struct dentry *parent,
                        struct debugfs_regset32 *regset);

void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs,
                     int nregs, void __iomem *base, char *prefix);
踩坑

1、debugfs的API的都是GPL的,因此在自己的模块必须要指定协议为GPL

2、使用echo写文件的话,open函数是必须的。

代码实例
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/errno.h>
#include <linux/dcache.h>
#include <linux/types.h>

static char zen_buf[512] = "hello\n";
static struct dentry *zen_dir;


static int zen_open(struct inode *inode, struct file *filp)
{
    printk("zen open\n");
    filp->private_data = inode->i_private;
    return 0;
}

ssize_t zen_read(struct file *filp, char __user *buf, size_t count, loff_t *offp)
{
    int retval = 0;
    if ((*offp + count) > 512)
        count = 512 - *offp;

    printk("read request: count:%u, offset:%u\n", count, *offp);
    if (copy_to_user(buf, zen_buf+*offp, count)) {
        printk("copy to user failed, count:%ld\n", count);
        retval = -EFAULT;
        goto out;
    }
    *offp += count;
    retval = count;
out:
    return retval;
}

ssize_t zen_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
{
    int retval;
    printk("write request: count:%u, offset:%u\n", count, *offp);
    if (*offp > 512)
        return 0;

    if (*offp + count > 512)
        count = 512 - *offp;

    if (copy_from_user(zen_buf+*offp, buff, count)) {
        printk("copy from user failed, count:%ld\n", count);
        retval = -EFAULT;
        goto out;
    }
    *offp += count;
    retval = count;
out:
    return retval;
}

struct file_operations my_fops = {
    .owner = THIS_MODULE,
    .read = zen_read,
    .write = zen_write,
    .open = zen_open,
};

static int __init debugfs_init(void)
{
    printk("INIT MODULE\n");
    zen_dir = debugfs_create_dir("zen_dir4", NULL);
    if (!zen_dir) {
        printk("zen_dir4 is null\n");
        goto fail;
    }
    static struct dentry *sub_zen_dir;
    sub_zen_dir = debugfs_create_dir("sub_zen", zen_dir);
    if (!sub_zen_dir) {
        printk("sub zen dir is null\n");
        goto fail;
    }

    struct dentry *filent = debugfs_create_file("zen", 0644, sub_zen_dir, NULL, &my_fops);
    if (!filent) {
        printk("zen file is null\n");
        goto fail;
    }
    printk("INIT SUCCESS\n");
    return 0;
fail:
//return -ENOENT;
    return -1;
}


static void __exit debugfs_exit(void)
{
    printk("exit module\n");
    debugfs_remove_recursive(zen_dir);
    printk("exit success\n");
}


module_init(debugfs_init);
module_exit(debugfs_exit);
MODULE_LICENSE("GPL");
网友评论