Linux内核模块之自定义printk输出至终端

github项目地址:https://github.com/superwujc

尊重原创,欢迎转载,注明出处:https://my.oschina.net/superwjc/blog/1816388

通过模块的方式调试内核时,printk()打印的信息默认只能通过dmesg的方式查看,可以通过以下方式,使用自定义的输出函数,将信息另打印至stdout。

模块程序:custom_printk.c

/* custom_printk.c */
#include <linux/kernel.h>  
#include <linux/module.h>  
#include <linux/init.h>  
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/uaccess.h>
#include <linux/printk.h>

#define KPRINTF_MAX 1024

static long
custom_sys_write(unsigned int, const char __user *, size_t);

static int
custom_printk(const char *, ...);

static int __init start(void)
{
	custom_printk("Hello there!\n");

	return 0;
}

static void __exit end(void)
{
	custom_printk("GoodBye!\n");
}

static long
custom_sys_write(unsigned int fd, const char __user *buf, size_t count)
{
	long ret = -EBADF;
	struct file *file = NULL;
	mm_segment_t status;
	loff_t offset;

	if (!buf) {
		printk("Write buffer was empty.\n");
		return ret;
	}

	status = get_fs();
	set_fs(KERNEL_DS);

	file = fget(fd);
	if (file) {
		offset = file->f_pos;
		ret = vfs_write(file, buf, count, &offset);
		file->f_pos = offset;
		fput(file);
	}

	set_fs(status);

	return ret;
}

static int
custom_printk(const char *fmt, ...)
{
	int ret = -EBADF;
	char printf_buf[KPRINTF_MAX] = {0, };
	va_list args;
	va_list printk_args;

	if (!fmt) {
		printk("Format for custom_printk was empty.\n");
		return ret;
	}

	memset(printf_buf, KPRINTF_MAX, 0);
	va_start(args, fmt);
	ret = vsnprintf(printf_buf, KPRINTF_MAX, fmt, args);
	va_end(args);

	if (ret > 0)
		ret = (int)custom_sys_write(0, printf_buf, (unsigned int)ret);
	else
		printk("Something was wrong with format or snprintf.\n");

	va_start(printk_args, fmt);
	vprintk(fmt, printk_args);
	va_end(printk_args);

	return ret;
}

module_init(start);  
module_exit(end);  
MODULE_AUTHOR("test");
MODULE_LICENSE("GPL"); 

Makefile:

obj-m += custom_printk.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
EXTRA_CFLAGS = -g -O0 -Wno-declaration-after-statement
all:
    make -C $(KDIR) M=$(PWD) modules
    rm -rf *.ko.unsigned *.mod.c *.mod.o *.symvers *.o
.PHONY: clean
clean:
    make -C $(KDIR) M=$(PWD) clean

编译并测试

# make
make -C /lib/modules/3.10.0-862.2.3.el7.x86_64/build M=/code modules
make[1]: Entering directory `/usr/src/kernels/3.10.0-862.2.3.el7.x86_64'
  CC [M]  /code/custom_printk.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /code/custom_printk.mod.o
  LD [M]  /code/custom_printk.ko
make[1]: Leaving directory `/usr/src/kernels/3.10.0-862.2.3.el7.x86_64'
rm -rf *.ko.unsigned *.mod.c *.mod.o *.symvers *.o
#
# insmod ./custom_printk.ko
Hello there!
#
# lsmod | grep custom_printk
custom_printk          12819  0
#
# modinfo ./custom_printk.ko
filename:       /code/./custom_printk.ko
author:         test
license:        GPL
vermagic:       3.10.0-862.2.3.el7.x86_64 SMP mod_unload modversions
depends:
srcversion:     D237B7F34015B61E554D9F7
rhelversion:    7.5
retpoline:      Y
#
# rmmod custom_printk
GoodBye!

参考

http://bbs.chinaunix.net/thread-1928306-1-1.html

猜你喜欢

转载自my.oschina.net/superwjc/blog/1816388