【linux kernel】linux内核中的debugfs

news2025/2/28 20:39:16

文章目录

      • 一、👉相关文件
      • 二、👉简介
      • 三、👉debugfs的API
          • 1、在debugfs中创建目录
          • 2、在debugfs目录中创建文件
          • 3、创建一个具有初始大小的文件
          • 4、创建包含单个整数值(十进制)的文件
          • 5、创建包含单个十六进制值得文件:
          • 6、创建包含unsigned long 类型的变量的文件
          • 7、创建包含布尔类型的文件
          • 8、创建包含atomic_t类型的值的文件
          • 9、创建包含二进制数据块的文件
          • 10、创建u32数组的文件
          • 11、创建与设备相关而seq_file
          • 12、为debugfs中的文件重命名
          • 13、为debugfs目录中的文件创建符号链接
          • 14、删除debugfs创建的目录或者文件
      • 四、👉实验代码
      • 五、👉参考链接

一、👉相关文件

  • /fs/debugfs/file.c:debugfs的file描述文件。

  • /fs/debugfs/inode.c:debugfs的inode描述文件。

  • /fs/debugfs/internal.h:用于debugfs的内部声明。

二、👉简介

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

通常使用如下命令安装debugfs

mount -t debugfs none /sys/kernel/debug

或者:

mount -t debugfs debugfs /sys/kernel/debug/

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

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

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

三、👉debugfs的API

  • 1、在debugfs中创建目录

使用debugfs的代码应包含<linux/debugfs.h>头文件。然后首要任务是创建至少一个目录来保存一组debugfs文件,可使用下列API实现:

struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);

当函数执行成功后,将在指定的父目录下创建一个名为name的目录,如果parent为NULL,则该目录将在debugfs根目录中创建。成功后,返回一个指向struct dentry的指针,可用于在目录中创建文件。如果返回值为ERR_PTR(-ERROR)则表明出现了问题,如果返回ERR_PTR(-ENODEV),则表明内核是在没有debugfs支持的情况下构建,这时候相关的API将失效。

  • 2、在debugfs目录中创建文件

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

struct dentry *debugfs_create_file(const char *name, umode_t mode,struct dentry *parent, 
                                   void *data,const struct file_operations *fops);
  • name是要创建文件的名称。

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

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

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

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

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

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

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

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

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

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

//创建包含u8整数值的文件
void debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent, u8 *value); 

//创建包含u16整数值的文件
void debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent, u16 *value); 

创建包含u32整数值的文件
void debugfs_create_u32(const char *name, umode_t mode, struct dentry *parent, u32 *value); 

//创建包含u64整数值的文件
void debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent, u64 *value);

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

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

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

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

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

void debugfs_create_size_t(const char *name, umode_t mode, struct dentry *parent, size_t *value);

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

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

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

struct dentry *debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent, unsigned long *value); 

void debugfs_create_xul(const char *name, umode_t mode, struct dentry *parent, unsigned long *value);
7、创建包含布尔类型的文件

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

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

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

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

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

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

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

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

另一种选择是导出二进制数据块,具有以下结构和功能:

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

如果想转储一个寄存器块,debugfs提供了两个函数:一个是创建一个只有寄存器的文件,另一个是在另一个顺序文件的中间插入一个寄存器块:

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

debugfs_print_regs32()中的base参数可能为0,但可能希望使用__stringify构建reg32数组,许多寄存器名(宏)实际上是寄存器基数上的字节偏移量。

10、创建u32数组的文件

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

struct debugfs_u32_array {
    u32 *array;
    u32 n_elements;
};

void debugfs_create_u32_array(const char *name, umode_t mode,struct dentry *parent,struct debugfs_u32_array *array);

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

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

11、创建与设备相关而seq_file

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

void debugfs_create_devm_seqfile(struct device *dev,const char *name,struct dentry *parent,
                                 int (*read_fn)(struct seq_file *s,void *data));
  • dev参数是与这个debugfs文件相关的设备。
  • read_fn是一个函数指针,用于调用它来打印seq_file内容。
12、为debugfs中的文件重命名

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

struct dentry *debugfs_rename(struct dentry *old_dir,struct dentry *old_dentry,
                              struct dentry *new_dir,const char *new_name);

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

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

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

struct dentry *debugfs_create_symlink(const char *name,struct dentry *parent,const char *target);
14、删除debugfs创建的目录或者文件

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

可使用以下API删除文件:

void debugfs_remove(struct dentry *dentry);

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

在很久以前,使用debugfs时需要记住创建的每个debugfs文件的dentry指针,以便能够清理所有文件。但是后来提供了一个新接口,在调试的时候可以调用:

void debugfs_remove_recursive(struct dentry *dentry);

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

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

四、👉实验代码

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

/**
 * @file debugfs_demo.c
 * @author your name (you@domain.com)
 * @brief debugfs api usage
 * @version 0.1
 * @date 2023-08-17
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/delay.h>

#include <linux/debugfs.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

#define BUFFER_SIZE  256
static char buffer[BUFFER_SIZE];

static struct dentry *debugfs_demo_dir;
static  u8 u8data = 90;
static  u32 boolData = false;

static struct dentry  *general_file, *u8data_dentry , *x8data_dentry, *bool_dentry;


static 	int general_file_open (struct inode *inode, struct file *file)
{
    printk(KERN_INFO"do general_file_open ops\n");

    return 0;
}


static ssize_t general_file_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff)
{
    return  simple_read_from_buffer(ubuf,size,loff,buffer,BUFFER_SIZE);
}



static ssize_t general_file_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
{
    if(size > BUFFER_SIZE)return -EINVAL;
    return simple_write_to_buffer(buffer,BUFFER_SIZE,loff,ubuf,size);
}

static struct file_operations  general_file_ops = 
{
    .open = general_file_open,
    .read  = general_file_read,
    .write = general_file_write
};


static char data[4]={0x01,0x05,0x12,0x23};
static struct debugfs_blob_wrapper blobData = {data,4};

static int __init debugfs_demo_init(void)
{
    //1、create debugfs_demo_dir  dir in debugfs
    debugfs_demo_dir = debugfs_create_dir("debugfs_demo_dir",NULL);
    if (!debugfs_demo_dir) {
        pr_err(" failed to create debugfs entry debugfs_demo_dir\n");
        return -1;
    }

    //2、create general_file in debugfs_demo_dir
    general_file = debugfs_create_file("general_file",0644,debugfs_demo_dir,NULL,&general_file_ops);

    //3、create u8data in debugfs
    u8data_dentry = debugfs_create_u8("u8data",0644,debugfs_demo_dir,&u8data);

    //4、create x8data in debugfs
    x8data_dentry = debugfs_create_x8("x8data",0644,debugfs_demo_dir,&u8data);

    //5、create boolData in debugfs
    bool_dentry = debugfs_create_bool("boolData", 0644, debugfs_demo_dir, &boolData);

    //6、create blobData in debugfs
    debugfs_create_blob("blobData",0644,debugfs_demo_dir,&blobData);

    printk(KERN_INFO"debugfs demo create successful\n");

    return 0;
}

static void __exit debugfs_demo_exit(void)
{
    debugfs_remove_recursive(debugfs_demo_dir);

    printk(KERN_INFO"debugfs_demo_exit\n");
}

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)拷贝到目标平台中,使用mount命令查看目前已挂载的文件系统:

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

mount -t debugfs debugfs /sys/kernel/debug/

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

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

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

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

五、👉参考链接

1、https://github.com/torvalds/linux/blob/master/Documentation/filesystems/debugfs.rst

2、debugfs的API接口:https://docs.kernel.org/filesystems/api-summary.html?highlight=debugfs#the-debugfs-filesystem

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/915155.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI Agent在家务场景下的AgentBench基准测试

近日,来自清华大学、俄亥俄州立大学和加州大学伯克利分校的研究者设计了一个测试工具——AgentBench,用于评估LLM在多维度开放式生成环境中的推理能力和决策能力。研究者对25个LLM进行了全面评估,包括基于API的商业模型和开源模型。 他们发现,顶级商业LLM在复杂环境中表现出…

文件内容搜索工具 - Python实现

在本篇文章中&#xff0c;我们将介绍如何使用 wxPython 库创建一个简单的文件搜索工具。这个工具允许用户选择一个文件夹&#xff0c;并在该文件夹中的所有 .py 文件中查找指定的文字&#xff0c;并显示匹配的位置。 C:\pythoncode\blog\searchwordinpyfile.py 代码实现 我们首…

Apipost数据模型功能详解

在API设计和开发过程中&#xff0c;存在许多瓶颈&#xff0c;其中一个主要问题是在遇到相似数据结构的API时会产生重复性较多的工作&#xff1a;在每个API中都编写相同的数据&#xff0c;这不仅浪费时间和精力&#xff0c;还容易出错并降低API的可维护性。 为了解决这个问题&a…

Android SDK 上手指南||第四章 应用程序结构

第四章 应用程序结构 本教程将主要以探索与了解为主要目的&#xff0c;但后续的系列文章则将进一步带大家深入学习如何创建用户界面、响应用户交互操作以及利用Java编排应用逻辑。我们将专注于大家刚刚开始接触Android开发时最常遇到的项目内容&#xff0c;但也会同时涉及一部…

ICCV2023 | 基于动作敏感性学习的时序动作定位

淘天集团-内容理解算法团队与浙江大学杨易教授团队合作的关于视频时序定位的论文被ICCV2023录取。 本文在业界首次将视频帧级别的细粒度信息引入至时序动作定位领域&#xff08;Temporal Action Localization&#xff0c;TAL&#xff09;&#xff0c;对于时序动作定位任务&…

iFlyCode 智能编程助手:提升编码效率的人工智能工具

一&#xff0c;介绍 iFlyCode 智能编程助是一款基于人工智能的编程辅助工具&#xff0c;旨在提高开发者的编码效率和准确性。它能够与多种编程语言和集成开发环境&#xff08;IDE&#xff09;配合使用&#xff0c;为开发者提供代码建议、自动完成和重构等功能。 以下是 iFlyC…

ethers.js1:ethers的安装和使用

ethers官方文档&#xff1a;Documentation 1、ethers简介&#xff1a; ethers.js是一个完整而紧凑的开源库&#xff0c;用于与以太坊区块链及其生态系统进行交互。如果你要写Dapp的前端&#xff0c;你就需要用到ethers.js。 与更早出现的web3.js相比&#xff0c;它有以下优点…

2023-8-23 滑动窗口

题目链接&#xff1a;滑动窗口 #include <iostream>using namespace std;const int N 1000010;int n, k; int a[N], q[N];int main() {scanf("%d%d", &n, &k);for(int i 0; i < n; i) scanf("%d", &a[i]);int hh 0, tt -1;for(…

Java注解和自定义注解以及应用。

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;微信小程序、页面跳转、移动端、前端☀️每日 一言&#xff1a;追求潮流&#xff0c;其本身一点都不潮流&#xff01; 一、前言 使用 Java 注解&#xff08;Annotations&#xff09;可以在代码中…

读书笔记-10张不同的思维导图

用思维导图做的读书笔记 当我们阅读一本书时&#xff0c;需要整理和记录书中的关键信息和观点&#xff0c;如果用传统的笔记方法&#xff0c;不仅会信息凌乱&#xff0c;而且效率低下。思维导图可以帮助我们更好地理解和组织一本书中所读内容。 一、我们先来了解一下什么是思…

Stable Diffusion 系列教程 | 文生图 - 提示词

目录 1.提示词 基本的规则 2.提示词分类 2.1内容性提示词 2.2 画风艺术派提示词 2.3 画幅视角 2.4画质提示词 3 反向提示词 3.1 内容性反向提示词 3.2 画质性反向提示词 4 实例分析 5 权重 5.1 方法一 5.2 方法二 6.参数 7. 学习and 技巧 7.1 辅助写提示词的网…

c++ 虚函数类对象模型

一、复杂的菱形继承及菱形虚拟继承 单继承&#xff1a;一个子类只有一个直接父类时称这个继承关系为单继承。 多继承&#xff1a;一个子类有两个或以上直接父类时称这个继承关系为多继承。 菱形继承&#xff1a;菱形继承是多继承的一种特殊情况。 菱形继承的问题&#xff1a;从…

从零开始学习YOLOv5 保姆级教程

一、前言 YOLO系列是one-stage且是基于深度学习的回归方法&#xff0c;而R-CNN、Fast-RCNN、Faster-RCNN等是two-stage且是基于深度学习的分类方法。 YOLOv5是一种单阶段目标检测算法&#xff0c;该算法在YOLOv4的基础上添加了一些新的改进思路&#xff0c;使其速度与精度都得…

【C++】vector类的模拟实现(SGI版本)

&#x1f3d6;️作者&#xff1a;malloc不出对象 ⛺专栏&#xff1a;C的学习之路 &#x1f466;个人简介&#xff1a;一名双非本科院校大二在读的科班编程菜鸟&#xff0c;努力编程只为赶上各位大佬的步伐&#x1f648;&#x1f648; 目录 前言一、vector类的模拟实现1.1 vect…

SpringCloud Alibaba实战和源码(7)Skywalking

什么是SkyWalking Skywalking是由国内开源爱好者吴晟开源并提交到Apache孵化器的产品&#xff0c;它同时吸收了Zipkin /Pinpoint /CAT 的设计思路。特点是&#xff1a;支持多种插件&#xff0c;UI功能较强&#xff0c;支持非侵入式埋点。目前使用厂商最多&#xff0c;版本更新较…

水溶性焊锡丝非水溶焊锡丝

Sn63Pb37&#xff0c;无FLUX&#xff0c;水清洗&#xff1b;A可理解为余量或者国标A类标准1% Sn63Pb37&#xff0c;FLUX 1.8% 焊锡膏 焊锡丝 焊锡丝&#xff0c;英文名称&#xff1a;solder wire&#xff0c;由锡合金和助剂两部分组成&#xff0c;合金成份分为锡铅、无铅助剂均…

PX4使用esp8266

文章目录 前言一、给esp8266下载固件接线下固件 二、配置esp8266 前言 硬件&#xff1a; esp01s(esp01好像有些问题&#xff0c;不建议用) usb转串口模块 pix飞控 软件&#xff1a; qgc PX4 参考&#xff1a; https://docs.px4.io/main/en/telemetry/esp8266_wifi_module.html…

1.4亿X区城市运行“一网统管”体系建设项目项目招标WORD

导读&#xff1a;原文《1.4亿X区城市运行“一网统管”体系建设项目项目招标WORD》&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。 部分内容&#xff1a; 各部分需求…

VS code 设置 资源管理器 对齐线

点击左上角的File --> Preformences --> Settings 然后搜索 workbench&#xff0c;把workbench.tree.renderIndentGuides选成always&#xff0c;这样会一直显示对齐的竖线。 找到workbench.tree.indent&#xff0c;这个值就是缩进的像素数量&#xff0c;值越大&#xff0…

electron+vue3全家桶+vite项目搭建【16.1】electron多窗口,pinia状态同步,扩展store方法,主动同步pinia的状态【推荐】

文章目录 引入实现效果如下实现步骤1.自定义pinia插件2.主进程补充同步处理 引入 demo项目地址 我们之前写了一个自动同步pinia状态的插件&#xff0c;可以参考如下文章 electronvue3全家桶vite项目搭建【16】electron多窗口&#xff0c;pinia状态无法同步更新问题解决 这里…