Debugfs kernel debugging

From RidgeRun Developer Wiki


Introduction to debugfs filesystem

This wiki is a tutorial on how to use the debugfs filesystem to perform kernel debugging or add debug files to obtain or perform functions of a driver.

Debugfs provides an easy way without rules for developers to expose internal data to user space, which allows developers to create custom files for reading and writing kernel data.

Debugs is currently automatically mounted at /sys/kernel/debug, in case it is not mounted, you can use the following command:

mount -t debugfs none /sys/kernel/debug

Also, debugfs can be automatically mounted at boot by adding the following line to the /etc/fstab file:

debugfs /sys/kernel/debug debugfs defaults 0 0

You can check if debugfs is running:

mount | grep debugfs

Debugfs filesystem functions to create and handle debug files are provided in the include <linux/debugfs.h>.

Creating debugfs files

Initialize the debugfs filesystem by creating a directory to hold the debugfs files. The directory will be created in the debugfs root path underneath the selected parent. If the parent is NULL, it will be created in the debugfs root path, which typically is mounted at /sys/kernel/debug. Use the following method to create the main directory:

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

To create a file that will allow you to create a function to handle and expose a value, use the following method with the following arguments:

  • name: File's name.
  • mode: File's access permissions.
  • parent: Dentry of the directory to store the file.
  • data: Pointer with driver data.
  • fops: Set of file operations.
struct dentry *debugfs_create_file(const char *name, umode_t mode,
                                   struct dentry *parent, void *data,
                                   const struct file_operations *fops);

Also, in the created directory, you can use the following helper functions to create a file and expose the value of a variable of types like integers, hexadecimal, bool, and arrays into a file. Check debugfs kernel documentation for other helper functions.

//Integer
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_ulong(const char *name, umode_t mode,
                          struct dentry *parent,
                          unsigned long *value);
//Hexadecimal
void debugfs_create_x8(const char *name, umode_t mode,
                       struct dentry *parent, u8 *value);
//Bool
void debugfs_create_bool(const char *name, umode_t mode,
                         struct dentry *parent, bool *value);
//Array
void debugfs_create_u32_array(const char *name, umode_t mode,
                              struct dentry *parent,
                              struct debugfs_u32_array *array);

When the module is removed, it is important to clean up all directories created. The following function will recursively remove the directory and all files created within that directory.

void debugfs_remove_recursive(struct dentry *dentry);

File Operators

When using a general debugfs file, you can use fops to define a series of functions to implement the file's behavior.

To define the file operations (fops), the struct file_operations can be used to at least provide the read() and write() operations; others can also be included.

static struct file_operations example_fops = {
	.read	= &read_function,
	.write	= &write_function,
};

Some of the operations that can be used are listed in the following table:

Caption text
Operation Function Description
.read ssize_t (*read)(struct file *, char __user *, size_t, loff_t *) Allows reading data from the file
.write ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *) Allows writing data to the file
.open int (*open)(struct inode *, struct file *) Open the file when open() is used
.release int (*release)(struct inode *, struct file *) Close the file when close() is used
.llseek loff_t (*llseek)(struct file *, loff_t, int) Changes the read/write position in the file

Also, the macro DEFINE_SIMPLE_ATTRIBUTE provided by <linux/fs.h> can be used. This macro only allows the read and write operations.

/*
 * fops_name: file_operations struct name
 * get_function: read function
 * set_function: write function
 * format: Data value type (%llu, $ld, etc)
 */
DEFINE_SIMPLE_ATTRIBUTE(fops_name, get_function, set_function, format);

Debugfs files use

Debugfs files will be available in the created directory at debugfs root path, which typically is mounted at /sys/kernel/debug

To interact with the files, commands like cat or echo can be used. The following table shows some of the files usage:

Use of debugfs files
Use Command example
Read file value cat <file>
Read file value echo "value" > <file>
Inspect hexdump hexdump -C <file>
Use C function calls open(), read(), write(), close(), lseek()
Use Python function calls open("archivo", "r+")

Example code

Create the functions with the read and write logic:

static int test_write_call(void *data, u64 val)
{
    //Add write logic
	pr_info("%s\n", __func__);
	return 0;
}

static int test_read_call(void *data, u64 *val)
{
    //Add read logic
	pr_info("%s\n", __func__);
	return 0;
}

Create a fops to define the read and write functions:

DEFINE_SIMPLE_ATTRIBUTE(test_fops,
			test_read_call,
			test_write_call, "%lld\n");

In the driver's probe function, create the debugfs directory to save the files:

static struct dentry *debugfs_dir;

debugfs_dir = debugfs_create_dir("tests", NULL);
	if (debugfs_dir == NULL)
		return -ENOMEM;

	if (!debugfs_create_file("file_test", 0644, debugfs_dir, NULL,
				 &test_fops))
		goto error;

 error:
	debugfs_remove_recursive(debugfs_dir)
	return -ENOMEM;


For direct inquiries, please refer to the contact information available on our Contact page. Alternatively, you may complete and submit the form provided at the same link. We will respond to your request at our earliest opportunity.


Links to RidgeRun Resources and RidgeRun Artificial Intelligence Solutions can be found in the footer below.