在系统命令行shell下安装当前版本得linux内核代码
sudo apt-get install linux-sorce
非常重要,后面源文件需要一些内核得库调用,提前配置好
#include
#include
MODULE_LICENSE("GPL");
static int hello_init(void)
{
// #define KERN_ALERT KERN_SOH "1" /*必须马上输出*/
printk(KERN_ALERT"Hello,world!\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
Makefile
ifneq ($(KERNELRELEASE),)
obj-m :=hello.o
else
KDIR :=/lib/modules/$(shell uname -r)/build
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.order *.mod
endif
KERNELRELEASE
是在内核源码的顶层Makefile中定义的一个变量,如果没有找到就会跳到下面指定得路径去寻找
-C
选项的作用是指将当前工作目录转移到你所指定的位置
M=
的作用是,当用户需要以某个内核为基础编译一个外部模块的话,需要在make modules
命令中加入M=dir
,程序会自动到你所指定的dir目录中查找模块源码,将其编译,生成KO
文件。
.ko
,编译过程中首先会到内核源代码目录下,读取顶层makefile文件,然后返回模块源代码所在的目录继续编译。root
身份就可将自己定义内核模块加载到内核里modutils
软件包供用户对内核模块进行管理,该软件包安装后会在/sbin
目录下安装insmod
、rmmod
、ksyms
、lsmod
、modprobe
等实用程序insmod
自动调用modules_init( )
函数中定义的过程运行sudo insmod [path]modulename
rmmod
自动调用modules_exit( )
函数中定义的过程运行rmmod [path]modulename
lsmod
/proc/kallsyms
中以文本方式读取内核符号表。static int hello_init(void)
{
//初始化
}
module_init(hello_init);
static void hello_exit(void)
{
//清理
}
module_exit(hello_exit);
这里可以看到执行make
生成了hello.ko
然后把他加入到内核模块中
可以看到内核模块加载成功
在用查看命令查看一下
再尝试一下卸载内核模块
卸载成功
下面一些概念介绍,便于理解
makefile 没有变
修改的hello.c
#include
#include
#include
MODULE_LICENSE("GPL");
static int num = -1;
//moduule_param(num,int,S_IRUGO);
static int hello_init(void)
{
struct task_struct *p = NULL;
p = &init_task;
printk(KERN_ALERT"名称\t进程号\t状态\t优先级\t父进程号\t");
//for_each_process是宏循环控制语句,内核开发者可它扫描整个进程链表
for_each_process(p)
{
//mm是指向被映射的用户地址空间的内存管理结构的指针
//内核进程始终在内核空间运行,从来不切换到用户空间去,所以没有用户态地址空间,所以它们的mm成员总是为NULL
if(p->mm == NULL)
printk(KERN_ALERT"%s\t%d\t%ld\t%d\n",p->comm,p->pid, p->state,p->normal_prio,p->parent->pid);
}
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}
//函数注册
module_init(hello_init);
module_exit(hello_exit);
查看日志,打印出了进程信息
ps查看进程一致
指定pid查找
输出
父进程
子进程
兄弟进程
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL");
static int pid = -1;
//根据进程号pid得到进程描述符struct pid
module_param(pid,int,S_IRUGO);
static int hello_init(void)
{
struct task_struct *p = NULL,*parent,*children,*sibling;
//list_head 双向链表 便于遍历
struct list_head *list;
p = pid_task(find_get_pid(pid),PIDTYPE_PID);
if(p==NULL)
printk(KERN_ALERT"Pid does not exit\n");
else
{
parent=p->parent;
printk(KERN_ALERT"This is parent:\n");
printk(KERN_ALERT"程序名\t\tPID号\t进程状态\t优先级\n");
printk(KERN_ALERT"%-10s\t%5d\t%ld\t\t%d\n",parent->comm, parent->pid, parent->state,parent->prio);
}
printk(KERN_ALERT"This is sibling:");
printk(KERN_ALERT"程序名\t\tPID号\t进程状态\t优先级\n");
list_for_each(list,&parent->children)
{
//list_entry(ptr,type,member);
//ptr是一个指向list_head的指针,type是包含list_head的数据结构类型,而member是list_head在该数据结构中的成员名
sibling=list_entry(list,struct task_struct,sibling);
printk(KERN_ALERT"%-10s\t%5d\t%ld\t\t%d\n", sibling->comm, sibling->pid, sibling->state, sibling->prio);
}
printk(KERN_ALERT"This is children:\n");
printk(KERN_ALERT"程序名\t\tPID号\t进程状态\t优先级\n");
list_for_each(list,&p->children)
{
children=list_entry(list,struct task_struct,sibling);
printk(KERN_ALERT"%-10s\t%5d\t%ld\t\t%d\n", children->comm,children->pid, children->state, children->prio);
}
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);