debugfs
In this program, you are going to learn
How to debug the kernel code ?
How to use below APIs ?
Here is the explanation of the source code.
Add the list of headers to refer the APIs used in the source code.
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/sysfs.h>
#include <linux/kobject.h>
#include <linux/err.h>
Add the module macros which contains the information about macros such as author, description and license.
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux_usr");
MODULE_DESCRIPTION("Simple Linux Device Driver - debugfs");
Initialize the functions and the variables which are used in the source code.
u64 intvalue, hexvalue;
struct dentry *dirret, *fileret, *u64int, *u64hex;
char ker_buf[len];
int filevalue;
Add the module init function to execute once when the module is loaded.
static int __init init_debug(void)
{
/* create a directory by the name dell in /sys/kernel/debugfs */
dirret = debugfs_create_dir("dell", NULL);
/* create a file in the above directory. This requires read and write file operations */
fileret = debugfs_create_file("text", 0004, dirret, &filevalue, &fops_debug);
/* create a file which takes in a int(64) value */
u64int = debugfs_create_u64("number", 0004, dirret, &intvalue);
if (!u64int) {
pr_err("error creating int file");
return -ENODEV;
}
/* takes a hex decimal value */
u64hex = debugfs_create_x64("hexnum", 0004, dirret, &hexvalue);
if (!u64hex) {
pr_err("error creating hex file");
return -ENODEV;
}
pr_info("Device Driver Loaded..\n");
return 0;
}
To be able to use
debugfs
, we start by creating a directory within/sys/kernel/debug
, which is an ideal way to start. The rest of the files can be placed within this directory.
dirret = debugfs_create_dir("dell", NULL);
If you need to create a single file within debugfs, you can the
debugfs_create_file
.To create a file in the above directory. This requires read and write file operation
fileret = debugfs_create_file("text", 0004, dirret, &filevalue, &fops_debug);
To create a file which takes in a int(64) value
u64int = debugfs_create_u64("number", 0004, dirret, &intvalue)
It takes a hex decimal value
u64hex = debugfs_create_x64("hexnum", 0004, dirret, &hexvalue
Add the module exit function which is executed when the module is unloaded from the kernel.
static void __exit exit_debug(void)
{
debugfs_remove_recursive(dirret);
pr_info("Device Driver Unloaded..\n");
}
debugfs_remove_recursive
used to cleanup all the files and directories created.
debugfs_remove_recursive(dirret);
Add debugfs APIs
static ssize_t myreader(struct file *fp, char __user *user_buffer, size_t count, loff_t *position)
{
return simple_read_from_buffer(user_buffer, count, position, ker_buf, len);
}
/* write file operation */
static ssize_t mywriter(struct file *fp, const char __user *user_buffer, size_t count, loff_t *position)
{
if (count > len)
return -EINVAL;
return simple_write_to_buffer(ker_buf, len, position, user_buffer, count);
}
static const struct file_operations fops_debug = {
.read = myreader,
.write = mywriter,
};
Add the mention init and exit function which is executed the module is loaded and unloaded.
module_init(init_debug);
module_exit(exit_debug);
1#include <linux/init.h>
2#include <linux/module.h>
3#include <linux/debugfs.h> /*this is for DebugFS libraries*/
4#include <linux/fs.h>
5
6MODULE_LICENSE("GPL");
7MODULE_AUTHOR("Linux_usr");
8MODULE_DESCRIPTION("sample Device Driver - debugfs");
9
10#define len 200
11
12u64 intvalue, hexvalue;
13
14struct dentry *dirret, *fileret, *u64int, *u64hex;
15char ker_buf[len];
16int filevalue;
17
18/* read file operation */
19static ssize_t myreader(struct file *fp, char __user *user_buffer, size_t count, loff_t *position)
20{
21 return simple_read_from_buffer(user_buffer, count, position, ker_buf, len);
22}
23
24/* write file operation */
25static ssize_t mywriter(struct file *fp, const char __user *user_buffer, size_t count, loff_t *position)
26{
27 if (count > len)
28 return -EINVAL;
29
30 return simple_write_to_buffer(ker_buf, len, position, user_buffer, count);
31}
32
33static const struct file_operations fops_debug = {
34 .read = myreader,
35 .write = mywriter,
36};
37
38static int __init init_debug(void)
39{
40 /* create a directory by the name dell in /sys/kernel/debugfs */
41 dirret = debugfs_create_dir("dell", NULL);
42
43 /* create a file in the above directory. This requires read and write file operations */
44 fileret = debugfs_create_file("text", 0004, dirret, &filevalue, &fops_debug);
45
46 /* create a file which takes in a int(64) value */
47 u64int = debugfs_create_u64("number", 0004, dirret, &intvalue);
48 if (!u64int) {
49 pr_err("error creating int file");
50 return -ENODEV;
51 }
52 /* takes a hex decimal value */
53 u64hex = debugfs_create_x64("hexnum", 0004, dirret, &hexvalue);
54 if (!u64hex) {
55 pr_err("error creating hex file");
56 return -ENODEV;
57 }
58 pr_info("Device Driver Loaded..\n");
59 return 0;
60}
61
62static void __exit exit_debug(void)
63{
64 debugfs_remove_recursive(dirret);
65 pr_info("Device Driver Unloaded..\n");
66}
67
68module_init(init_debug);
69module_exit(exit_debug);
1obj-m += driver_debugfs.o
2all:
3 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
4clean:
5 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Run Make to compile the module.
$make
make -C /lib/modules/5.4.0-150-generic/build M=$HOME/kernel_driver_debugfs modules
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-150-generic'
CC [M] $HOME/kernel_driver_debugfs/driver_debugfs.o
Building modules, stage 2.
MODPOST 1 modules
CC [M] $HOME/kernel_driver_debugfs/driver_debugfs.mod.o
LD [M] $HOME/kernel_driver_debugfs/driver_debugfs.ko
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-150-generic'
Run ls to check if driver_debugfs.ko is generated or not.
$ ls -l
total 36
-rw-rw-r-- 1 test test 154 Feb 26 13:18 Makefile
-rw-rw-r-- 1 test test 47 Feb 26 13:18 modules.order
-rw-rw-r-- 1 test test 0 Feb 26 13:18 Module.symvers
-rw-rw-r-- 1 test test 820 Feb 26 13:18 driver_debugfs.c
-rw-rw-r-- 1 test test 5880 Feb 26 13:18 driver_debugfs.ko
-rw-rw-r-- 1 test test 47 Feb 26 13:18 driver_debugfs.mod
-rw-rw-r-- 1 test test 919 Feb 26 13:18 driver_debugfs.mod.c
-rw-rw-r-- 1 test test 3448 Feb 26 13:18 driver_debugfs.mod.o
-rw-rw-r-- 1 test test 3320 Feb 26 13:18 driver_debugfs.o
Run insmod to load the module.
$ sudo insmod ./driver_debugfs.ko
Once the module is loaded into kernel check for the files created.
$ ls -l /sys/kernel/debug/dell/
total 0
-rw-r--r-- 1 root root 0 Jul 14 20:08 hexnum
-rw-r--r-- 1 root root 0 Jul 14 20:08 number
-rw-r--r-- 1 root root 0 Jul 14 20:08 text
Run rmmod to unload the module.
$ sudo rmmod driver_debugfs
Check dmesg and we can clearly see the read and write operations are executed.
[ 9523.186611] Device Driver Loaded..
[ 9534.912912] Device Driver Unloaded..
API |
Learning |
---|---|
debugfs_create_dir |
To create a directory within /sys/kernel/debug |
debugfs_create_file |
To create a file in the above directory |
debugfs_create_u64 |
To create a file which takes in a int(64) value |
debugfs_remove_recursive |
To create a file which takes hex decimal value |
Previous Chapters
Other File System topics
Next Chapter