Linux系统下通过内核模块显示进程控制块信息
前言
本机为微软Surface pro4
,为64
位,所用操作系统为Windos 10
。本机虚拟机版本为Oracle VM VirtualBox 6.1.8
,所用操作系统是使用Ubuntu18.04
,。Ubuntu的虚拟硬盘设置为200G
,显存为128MB
,内存为4G
,CPU
2个,所用镜像源为清华大学软件镜像源。所使用linux
内核为linux-5.11.8
。
注意事项
(1)使用本博客中的指令时一定要采取对应自己电脑安装的Ubuntu配置。
(2)内核模块在内核空间运行,编写时不能使用C库函数,不能使用浮点数运算。
(3)做实验时直接上手操作即可,如果报错了再去找问题。
(4)本实验编译时如果编译器使用的Geany
时,尽量使用终端指令进行编译,因为Geany
进行编译会因为没有<linux/init.h>
报错。
内核模块的程序的简要介绍
1、头文件
#include<linux/module.h>
#include<linux/init.h>
(注:这两个头文件是编写内核模块程序所必须的 3 个头文件 。)
(注:#include<linux/init.h>
文件中包含了模块的初始化的宏定义 以及一些其他函数的初始化函数。)
(注:#include<linux/module.h>
包含加载模块需要的函数和符号定义。)
2、模块许可声明
MODULE_LICENSE("GPL");
(注:从2.4.10版本内核开始,模块必须通过MODULE_LICENSE宏声明此模块的许可证,否则在加载此模块时,会收到内核被污染 “kernel tainted” 的警告,被内核接受的有意义的许可证有 “GPL”,“GPL v2”,“GPL and additional rights”,“Dual BSD/GPL”,“Dual MPL/GPL”,“Proprietary”。)
3、模块初始化和清理函数
module_init(exp_init);
module_exit(exp_exit);
(注:声明内核模块必须调用宏module_init和 module_exit 去注册初始化与清理函数。在模块源代码的最后两行已声明该模块被加载时的初始化函数是exp_init(),模块被卸载时的清理函数是 exp_exit()。需要注意,初始化与清理函数必须在宏module_init和 module_exit使用前定义,否则会出现编译错误。这两个函数配对使用,例如,当module_init()申请一个资源,那么module_exit()中就应释放这个资源,使得模块不留下任何副作用。)
创建一个程序
1、使用文件编辑器在主目录下创建一个名为kernel的文件夹。
2、打开Geany程序,然后点击新建按钮,创建一个新文件。
(注:创建完成界面如下)
3、在新建的文件中书写程序。(注:程序如下)
#include <linux/init.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
MODULE_LICENSE("GPL");
static int num = -1;
//设定模块参数
module_param(num, int, S_IRUGO);
static __init int exp_init(void){
struct task_struct *p = NULL;
for_each_process(p)
{
if (num==0 )
break;
printk("pid=%d,path=%s\n", p->pid, p->comm);
num--;
}
return 0;
}
static __exit void exp_exit(void){
printk("Good bye.\n");
}
module_init(exp_init);
module_exit(exp_exit);
4、将程序文件命名pthreadinfo.c
为保存到kernel
文件下。
5、按照如图所示使用终端指令在kernel
文件夹下创建Makefile
文件。
6、按照如图所示使用终端指令在Makefile
文件中,然后在进入文件后,按下i
进入插入模式,添加如下内容,添加完内容以后,按Esc
退出插入模式,然后输入:wq
对文件进行保存并退出。
obj-m:=pthreadinfo.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
7、按照如图所示使用终端指令make
对kernel
文件夹下的内核程序进行编译。
8、按照如图所示使用终端指令对kernel
文件夹下的.ko
文件进行进行加载,即可显示进程ID信息和路径。
9、按照如图所示使用终端指令卸载内核模块程序。
(注:使用指令提示成功界面如下)