linux驱动调试之Debugfs

这篇具有很好参考价值的文章主要介绍了linux驱动调试之Debugfs。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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


往期链接:

  • linux设备驱动中的并发
  • linux设备驱动中的编译乱序和执行乱序
  • linux设备驱动之内核模块
  • linux字符驱动
  • linux字符驱动之ioctl部分
  • linux字符驱动之read、write部分


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.操作测试

debugfs,linux设备驱动开发,linux,服务器,驱动开发
debugfs,linux设备驱动开发,linux,服务器,驱动开发

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

这个问题可以查看链接 使用cat读取和echo写内核文件节点的一些问题 文章来源地址https://www.toymoban.com/news/detail-634660.html

到了这里,关于linux驱动调试之Debugfs的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 嵌入式Linux驱动开发 04:基于设备树的驱动开发

    前面文章 《嵌入式Linux驱动开发 03:平台(platform)总线驱动模型》 引入了资源和驱动分离的概念,这篇文章将在前面基础上更进一步,引入设备树的概念。 在平台总线驱动模型中资源和驱动已经从逻辑上和代码组织上进行了分离,但每次调整资源还是会涉及到内核,所以现

    2024年02月16日
    浏览(66)
  • 正点原子嵌入式linux驱动开发——Linux 网络设备驱动

    网络驱动是linux里面驱动三巨头之一 ,linux下的网络功能非常强大,嵌入式linux中也常常用到网络功能。前面已经讲过了字符设备驱动和块设备驱动,本章就来学习一下linux里面的 网络设备驱动 。 本次笔记中讨论的都是有线网络! 提起网络,一般想到的硬件就是“网卡”。在

    2024年01月17日
    浏览(68)
  • 嵌入式Linux系统中的设备驱动开发:从设备树到驱动实现

    大家好,今天给大家介绍 嵌入式Linux系统中的设备驱动开发:从设备树到驱动实现 ,文章末尾附有分享大家一个资料包,差不多150多G。里面学习内容、面经、项目都比较新也比较全! 可进群免费领取。 在嵌入式Linux系统中,设备驱动是连接硬件设备和操作系统之间的桥梁。

    2024年02月19日
    浏览(63)
  • 【Linux驱动开发】设备树详解(三)设备树Kernel解析

    ​ ​ 活动地址:CSDN21天学习挑战赛 【Linux驱动开发】设备树详解(一)设备树基础介绍 【Linux驱动开发】设备树详解(二)设备树语法详解 【Linux驱动开发】设备树详解(三)设备树Kernel解析   个人主页:董哥聊技术 我是董哥,嵌入式领域新星创作者 创作理念:专注分享

    2023年04月24日
    浏览(49)
  • 深入探讨Linux驱动开发:Linux设备树

    设备树(Device Tree,简称 DT)是一种在嵌入式系统中描述硬件设备的一种数据结构和编程语言。它用于将硬件设备的配置信息以树形结构的方式进行描述,以便操作系统(如 Linux)可以根据这些信息正确地识别、配置和管理硬件设备。 设备树最初被引入到 Linux 内核中,用于解

    2023年04月27日
    浏览(46)
  • Linux设备驱动开发学习笔记(等待队列,锁,字符驱动程序,设备树,i2C...)

    container_of函数可以通过结构体的成员变量检索出整个结构体 函数原型: 内核开发者只实现了循环双链表,因为这个结构能够实现FIFO和LIFO,并且内核开发者要保持最少代码。 为了支持链表,代码中要添加的头文件是linux/list.h。内核中链表实现核心部分的数据结构 是struct li

    2024年01月22日
    浏览(51)
  • Linux驱动开发:设备树dts详解

    前言: 掌握设备树是 Linux 驱动开发人员必备的技能!因为在新版本的 Linux 中, ARM 相关的驱动全部采用了设备树(也有支持老式驱动的,比较少),最新出的 CPU 其驱动开发也基本都是基于设备树的,比如 ST 新出的 STM32MP157、NXP 的 I.MX8 系列等。本篇博客核心是系统性的学习设

    2024年02月17日
    浏览(56)
  • 新型LINUX驱动开发 DTS设备树

    1.为什么使用设备树 linux内核3.版本之后才有设备树。 没有设备树之前的板级信息都写在.c文件里面,导致内核臃肿。 因此将板级信息独立成格式,文件名为dts,一个平台对应一个dts。 2.dts dtb dtc dts是设备树源码文件。 dtb是将设备树dts编译以后得到的二进制文件。 dtc是将dt

    2024年02月09日
    浏览(47)
  • Linux下PCI设备驱动开发详解(二)

    根据上一章的概念,PCI驱动包括PCI通用的驱动,以及根据实际需要设备本身的驱动。 所谓的编写设备驱动,其实就是编写设备本身驱动,因为linux内核的PCI驱动是内核自带的。 为了更好的学习PCI设备驱动,我们需要明白内核具体做了什么,下面我们研究一下,linux PCI通用的驱

    2024年01月19日
    浏览(47)
  • Linux下PCI设备驱动开发详解(一)

    PCI总线是目前应用最广泛的计算机总线标准,而且是一种兼容性最强,功能最全的计算机总线。 而linux作为一种开源的操作系统,同时也为PCI总线与各种新型设备互联成为可能。尤其被现在的异构计算GPU/FPGA、软硬结合新的方向广泛运用。 应用程序位于用户空间,驱动程序位

    2024年02月04日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包