当前位置: 首页 > news >正文

Linux下的Debugfs

debugfs


1. 简介

类似sysfs、procfsdebugfs 也是一种内存文件系统。不过不同于sysfs一个kobject对应一个文件,procfs和进程相关的特性,debugfs的灵活度很大,可以根据需求对指定的变量进行导出并提供读写接口。debugfs又是一个Linux中 everything is a file 哲学的体现,通过VFS实现了对驱动的控制。可以通过以下命令,来挂载debugfs到指定目录。
Debugfs其存在的主要意义是为了内核开发者向用户空间传递更多有用的信息,与proc不同,proc只提供进程相关的信息;同时也与sysfs不同,sysfs对每个文件都要求一定的规则,而Debugfs没有任何的规则。
简而言之,Debugfs是一种用于内核调试的虚拟文件系统。
用途:将内核程序中的变量以文件的形式直观的展现出来,并可以直接通过文件操作来读取或修改内核变量的值,便于开发调试

2. 食用方式

1. 内核使能Debudfs

menuconfig中使能DEBUG_FS = y

在这里插入图片描述

2.挂载命令

mount -t debugfs none /sys/kernel/debug

3.内核接口

1. API接口

  • 想要使用Debugfs功能,首先要做的就是要包含 <linux/debugfs.h>头文件
  • 使用debugfs_create_dir接口,创建一个文件夹,用于保存debugfs所操作的文件
  • 使用debugfs_create_file接口,创建多个文件进行操作

2. API介绍

1. debugfs_create_dir

struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
参数作用备注
name文件夹名称
parent父目录如果为NULL,则在/sys/kernel/debug目录下
dentry返回值表示创建的 debugfs 文件(或目录)的 dentry 节点。如果文件创建成功,它返回一个有效的 dentry 指针;如果创建失败,则返回 NULL。

2. debugfs_create_file

struct dentry *debugfs_create_file(const char *name, umode_t mode,struct dentry *parent, void *data,const struct file_operations *fops);
参数作用备注
name文件名称
mode文件访问权限可以是整型(比如0644)也可以使用内核的宏
parent父目录,用于保存该文件如果为空则该文件的父目录为根目录
data文件操作的私有数据inode的i_private字段指向这个结构
fops文件的自定义操作可以自定义所有操作接口,也可以使用宏DEFINE_SIMPLE_ATTRIBUTE指定读写操作即可

DEFINE_SIMPLE_ATTRIBUTE宏

// 
// __get: 读操作 int (*get)(void *data, u64 *value),👇
//bash下cat file ,回显内容便是内核层传给应用层的*value的值
// __set: 写操作 int (*set)(void *data, u64 value),👇
//bahs下echo 1 > file , value的值便是应用层传入内核层的数据1
// __fmt: 用于指定 get 和 set 函数的输入输出格式。 const char *fmt👇
//例如,它可以定义一个整数、浮点数或字符串的格式,以便在 sysfs 读写操作接口中正确显示或解析值。
#define DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt)		\
static int __fops ## _open(struct inode *inode, struct file *file)	\
{									\__simple_attr_check_format(__fmt, 0ull);			\return simple_attr_open(inode, file, __get, __set, __fmt);	\
}									\

3. debugfs_create_u8

void debugfs_create_u8(const char *name, umode_t mode,struct dentry *parent, u8 *value);
参数作用备注
name文件名一般以变量名来命名,方便调试
mode文件权限
parent父目录
value变量变量的值会被存在文件内

其他变量类型的接口:👇

//创建十进制的无符号文件
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);
// 布尔型
void debugfs_create_bool(const char *name, umode_t mode,struct dentry *parent, bool *value);

Deme one

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>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;
}
// 文件操作变量名,get读操作,set写操作,将读写操作的返回值以字符串格式化的形式读出或写入文件内部
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("GPL");

Demo TWO

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

4. 加载模块

编译完后生成的.ko文件,使用insmod加载进内核,即可在/sys/kernel/debug下看到生成目录及文件

http://www.lryc.cn/news/476954.html

相关文章:

  • 【FFmpeg】调整音频文件的音量
  • mac 打开访达快捷键
  • Ubuntu学习笔记 - Day2
  • c++基础12比较/逻辑运算符
  • mac-ubuntu虚拟机(扩容-共享-vmtools)
  • 数学建模学习(135):使用Python基于WSM、WPM、WASPAS的多准则决策分析
  • VScode的C/C++点击转到定义,不是跳转定义而是跳转声明怎么办?(内附详细做法)
  • 设备管理网关(golang版本)
  • Armv8的安全启动
  • 冒泡排序、选择排序、计数排序、插入排序、快速排序、堆排序、归并排序JAVA实现
  • SQL CASE表达式与窗口函数
  • 基于SpringBoot的植物园管理小程序【附源码】
  • asp.net网站项目如何设置定时器,定时获取数据
  • 单元/集成测试解决方案
  • 高效作业跟踪:SpringBoot作业管理系统
  • keepalived + nginx 实现网站高可用性(HA)
  • 有哪些编辑器,怎样选择编辑器
  • 软件系统开发
  • 浅谈RPC的实现原理与RPC实战
  • 算法|牛客网华为机试31-40C++
  • Mysql 大表limit查询优化原理
  • 封装axios、环境变量、api解耦、解决跨域、全局组件注入
  • CDGP|数据治理于企业而言到底有什么用?
  • Java学习教程,从入门到精通,Java数组(Arrays)语法知识点及案例(19)
  • 11.4OpenCV_图像预处理习题02
  • go的template示例
  • 『YOLO』| 断点训练、解决训练中断异常情况
  • MQTT+Disruptor 提高物联网高并发
  • SpringBoot项目集成ONLYOFFICE
  • 用于nodejs的开源违禁词检测工具 JavaScript node-word-detection