1. 问题描述
梳理内核函数dump_stack的源码实现时,PC上竟然没有该函数打印内容的日志截图,又不想从网上盗图,所以学习下如何在内核中打印Hello World。
2. 解决方案
科普:Kernel Module是一个二进制文件,用于运行时拓展内核功能,如果功能不被需要时,可被卸载。直观上看,与dlopen机制类似,程序运行时显示加载so,当不使用该库时,调用dlclose关闭so。
解决思路:基于Kernel Module机制,执行命令"insmod + 模块名" 安装模块,执行打印。
2.1 基础版
注意:测试使用的系统是Ubuntu,目录/lib/modules下已有内核相应的头文件,无需自己安装源码。
#include
#include
#include
MODULE_LICENSE("GPL");
static int hello_init(void)
{
pr_info("%sn", "Hello World!");
return 0;
}
static void hello_exit(void)
{
pr_info("%sn", "Byebye");
return;
}
module_init(hello_init);
module_exit(hello_exit);
仅从代码来看,该机制类似于Java中调用System.loadLibrary加载so,so的JNI_OnLoad方法被执行。
obj-m := hello.o
KDIR := /lib/modules/`uname -r`/build
modules:
make -C $(KDIR) M=`pwd`
clean:
make -C $(KDIR) M=`pwd` clean
执行make命令即可,编译成功后,将生成hello.ko文件
日志文件 /var/log/syslog,可看到如下打印。
使用命令lsmod,可查看内核加载的模块。
从图中也不难看出,hello模块也确实被加载到内核。
5. 卸载模块,命令:rmmod hello
2.2 进阶版
仅打印Hello World,还差点意思,需求场景:用户态进程使用C++ std::thread启动线程,该线程内部调用Linux系统调用,然后系统调用内部使用dump_stack打印内核堆栈。显然单靠Hello World完不成。
该部分内容编撰中,敬请期待
3. 参考