linux驱动调试之Debugfs

2023-10-30

本期主题:
linux驱动调试之Debugfs


往期链接:



1.Debugfs是什么

在内核的开发过程中,我们希望有一些能够在用户空间获取信息的简单方法。debugfs由此诞生,我们可以在 /sys/kernel/debug 目录下来访问debugfs的节点。

debugfs与proc、sysfs不同

  • proc提供的是进程信息,sysfs具有严格的“每个文件一个值“的规则
  • debugfs开发比较随意,从名字就能看出来

2.怎么使用debugfs

1.debugfs_create_dir

接口定义:

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

接口描述:

这是一个创建debugfs目录的接口,其中:

  • name就是你希望创建的文件夹的名字;
  • parent就是这个debug节点的父节点,如果为NULL的话,就会在debugfs的根目录下创建;

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)

接口描述:

在debugfs目录下创建debugfs文件的接口,其中:

  • name 就是创建文件的名字,mode就是希望文件所拥有的权限
  • parent和前一个接口一样
  • data 一个可以存储数据的指针,inode.i_private 指针将会指向这个值,当调用open时候
  • fops就是存储操作的函数指针

3.一个简单的例子

基于我们前面调试的hello模块,继续创建一个debugfs节点,并且读取它

1.Makefile

CONFIG_MODULE_SIG=n

ifneq ($(KERNELRELEASE),)

obj-m+=myhello.o

myhello-objs:=hello.o hello_dbgfs.o #将多个文件编译成一个目标的方法

else

KDIR :=/lib/modules/$(shell uname -r)/build

PWD  :=$(shell pwd)

all:

	make -C $(KDIR) M=$(PWD) modules

clean:

	rm -f *.ko *.o *.mod.o *.symvers *.cmd  *.mod.c *.order .*.cmd

endif

2.src code

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/debugfs.h>
#include "hello_dbgfs.h"

struct hello_dbgfs_dentry_t {
    /* for debugfs */
	struct dentry *dentry_root;
	struct dentry *dentry_file;
};

static struct hello_dbgfs_dentry_t hello_dbgfs_dentry;

int hello_dbgfs_open(struct inode *inode, struct file *file)
{
	if (inode->i_private)
		file->private_data = inode->i_private;
	return 0;
}

static ssize_t hello_dbgfs_read(struct file *file, char __user *user_buf,
				     size_t count, loff_t *ppos)
{
	char buf[] = "hello world\n";;
	ssize_t ret;
    unsigned long p = *ppos;
	size_t size = sizeof(buf) / sizeof(char);

    printk("read debug\n");
    printk("pos is %ld, count is %d, size: %d\n", p, count, size);

//TODO:这里如果不加这个判断的话,一次cat会多次打印,原因在于cat返回的是读取的字节数,如果没达到预期会一直读取

	if (p > size)
	{
		return 0;
	}

	// buf = kmalloc(TEST_SIZE, GFP_KERNEL);
	if (!buf) {
		printk("ERR, buf is NULL!\n");
		return -ENOMEM;
	}

	// if (ret >= 0)
		// ret = simple_read_from_buffer(user_buf, 10, ppos, buf, ret);
	if (copy_to_user(user_buf, buf, size))
	{
		ret = -EFAULT;
		printk("ERR, debugfs read failed!\n");
	}
	else
	{
		//TODO:如果没有return这个size,在cat之后会报错Bad address
		ret = size;
		*ppos += size;
		printk("read %u bytes from kernel\r\n", size);
	}
	
	// kfree(buf);

	return ret;

}

static ssize_t hello_dbgfs_write(struct file *file,
				      const char __user *user_buf, size_t count,
				      loff_t *ppos)
{
	char *buf_recv = NULL;
	int ret;
    // char *buf = (char *)file->private_data;
    if (user_buf == NULL)
    {
        printk("ERR, user buf is NULL!\n");
        return 0;
    }

    printk("DBG, dbgfs write, count is %d\n", count);
	
	buf_recv = (char *)kmalloc(count, GFP_KERNEL);
	if (buf_recv == NULL) {
		printk("ERR, kmalloc failed!");
		return -1;
	}

    if (copy_from_user(buf_recv, user_buf, count))
    {
        ret = -EFAULT;
        printk("write failed!\n");
    }
    else
    {
        *ppos += count;
        ret = count;

        printk("write %d bytes to kernel, buf_recv is %s\n", count, buf_recv);
    }
//最后一个字符是换行符,而不是string结尾的0,这里很奇怪
	if (buf_recv[count - 1] == '\n') {
		printk("INFO, delete the n, change to 0 \n");
		buf_recv[count - 1] = 0;
	}

	if (!strcmp(buf_recv, "write"))
		printk("INFO, use write func\n");
	else if (!strcmp(buf_recv, "poll"))
		printk("INFO, use poll func\n");
	else
		printk("ERR, not find the right func, check param!\n");


	kfree(buf_recv);

    return ret;
}


static const struct file_operations hello_dbgfs_ops = {
	.open = hello_dbgfs_open,
	.read = hello_dbgfs_read,
	.write = hello_dbgfs_write,
};

int hello_init_debugfs(void)
{
	hello_dbgfs_dentry.dentry_root = debugfs_create_dir("hello_dbgfs", NULL);
	if (!hello_dbgfs_dentry.dentry_root) {
		printk("Failed to create debugfs directory\n");
		return -1;
	}

	hello_dbgfs_dentry.dentry_file = debugfs_create_file("hello_test", 0644,
						  hello_dbgfs_dentry.dentry_root,
						  NULL, &hello_dbgfs_ops);
	if (!hello_dbgfs_dentry.dentry_file) {
		printk("Failed to create dentry_file\n");
        return -1;
    }
    return 0;
}
// EXPORT_SYMBOL(hello_init_debugfs);

void hello_uninit_debugfs(void)
{
	debugfs_remove_recursive(hello_dbgfs_dentry.dentry_root);
}


MODULE_LICENSE("GPL");

3.操作测试

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

4.关于cat会一直读取的原因

这个问题可以查看链接 使用cat读取和echo写内核文件节点的一些问题

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux驱动调试之Debugfs 的相关文章

  • 让 MongoDB 在 Linux 上监听远程连接

    我已在 Windows 本地计算机上 上成功安装 MongoDB 作为服务 但现在我想将 MongoDb 移动到单独的服务器 所以我将 tarball 解压到网络上的虚拟服务器 运行 Linux 当我从本地计算机使用 PuTTY 连接到服务
  • 在主目录中安装库

    在 Linux Ubuntu 中 我尝试运行一个工具 但它显示错误 库丢失 我无权在系统中安装任何内容 或者根本无法从我的用户帐户执行 sudo 是否可以在我的主目录 没有 sudo 中安装缺少的库 在我的例子中为 libstdc so 6
  • PHP 致命错误:未找到“MongoClient”类

    我有一个使用 Apache 的网站 代码如下 当我尝试访问它时 我在 error log 中收到错误 PHP Fatal Error Class MongoClient not found 以下是可能错误的设置 但我认为没有错误 php i
  • .NET Core 中的跨平台文件名处理

    如何处理文件名System IO以跨平台方式运行类以使其在 Windows 和 Linux 上运行 例如 我编写的代码在 Windows 上完美运行 但它不会在 Ubuntu Linux 上创建文件 var tempFilename Dat
  • 并行运行 make 时出错

    考虑以下制作 all a b a echo a exit 1 b echo b start sleep 1 echo b end 当运行它时make j2我收到以下输出 echo a echo b start a exit 1 b star
  • 在 Linux 中禁用历史记录 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 要在 Linux 环境中禁用历史记录 我执行了以下命令 export HISTFILESIZE 0 export HISTSIZE 0 u
  • 嵌入式Linux poll()不断返回

    我有一个特别的问题 当我知道没有什么可读时 民意调查不断返回 因此设置如下 我有 2 个文件描述符 它们构成fd设置民意调查监视 一种用于引脚从高到低的变化 GPIO 另一个用于代理输入 代理输入出现问题 处理的顺序是 启动main函数 然
  • QFileDialog::getSaveFileName 和默认的 selectedFilter

    我有 getSaveFileName 和一些过滤器 我希望当用户打开 保存 对话框时选择其中之一 Qt 文档说明如下 可以通过将 selectedFilter 设置为所需的值来选择默认过滤器 我尝试以下变体 QString selFilte
  • Unix 命令列出包含字符串但*不*包含另一个字符串的文件

    如何递归查看包含一个字符串且不包含另一个字符串的文件列表 另外 我的意思是评估文件的文本 而不是文件名 结论 根据评论 我最终使用了 find name html exec grep lR base maps xargs grep L ba
  • bluetoothctl 到 hcitool 等效命令

    在 Linux 中 我曾经使用 hidd connect mmac 来连接 BT 设备 但自 Bluez5 以来 这种情况已经消失了 我可以使用 bluetoothctl 手动建立连接 但我需要从我的应用程序使用这些命令 并且使用 blue
  • 是否可以在Linux上将C转换为asm而不链接libc?

    测试平台为Linux 32位 但也欢迎 Windows 32 位上的某些解决方案 这是一个c代码片段 int a 0 printf d n a 如果我使用 gcc 生成汇编代码 gcc S test c 然后我会得到 movl 0 28 e
  • 创建 jar 文件 - 保留文件权限

    我想知道如何创建一个保留其内容的文件权限的 jar 文件 我将源代码和可执行文件打包在一个 jar 文件中 该文件将在使用前提取 人们应该能够通过运行批处理 shell 脚本文件立即运行示例和演示 然后他们应该能够修改源代码并重新编译所有内
  • 如何检测并找出程序是否陷入死锁?

    这是一道面试题 如何检测并确定程序是否陷入死锁 是否有一些工具可用于在 Linux Unix 系统上执行此操作 我的想法 如果程序没有任何进展并且其状态为运行 则为死锁 但是 其他原因也可能导致此问题 开源工具有valgrind halgr
  • 从 csv 文件中删除特定列,保持输出上的相同结构[重复]

    这个问题在这里已经有答案了 我想删除第 3 列并在输出文件中保留相同的结构 输入文件 12 10 10 10 10 1 12 23 1 45 6 7 11 2 33 45 1 2 1 2 34 5 6 I tried awk F 3 fil
  • Linux中的CONFIG_OF是什么?

    我看到它在很多地方被广泛使用 但不明白在什么场景下我需要使用它 What is 配置 OF OF 的全名是什么 打开固件 这是很久以前发明的 当时苹果公司正在生产基于 PowerPC CPU 的笔记本电脑 而 Sun Microsystem
  • chown:不允许操作

    我有问题 我需要通过 php 脚本为系统中的不同用户设置文件所有者权限 所以我通过以下命令执行此操作 其中 1002 是系统的用户 ID file put contents filename content system chown 100
  • Linux 中的动态环境变量?

    Linux 中是否可以通过某种方式拥有动态环境变量 我有一个网络服务器 网站遵循以下布局 site qa production 我想要一个环境变量 例如 APPLICATION ENV 当我在 qa 目录中时设置为 qa 当我在生产目录中时
  • 加载数据infile,Windows和Linux的区别

    我有一个需要导入到 MySQL 表的文件 这是我的命令 LOAD DATA LOCAL INFILE C test csv INTO TABLE logs fields terminated by LINES terminated BY n
  • Discord.net 无法在 Linux 上运行

    我正在尝试让在 Linux VPS 上运行的 Discord net 中编码的不和谐机器人 我通过单声道运行 但我不断收到此错误 Unhandled Exception System Exception Connection lost at
  • 如何在 Linux shell 中将十六进制转换为 ASCII 字符?

    假设我有一个字符串5a 这是 ASCII 字母的十六进制表示Z 我需要找到一个 Linux shell 命令 它将接受一个十六进制字符串并输出该十六进制字符串代表的 ASCII 字符 所以如果我这样做 echo 5a command im

随机推荐