采用的方式:插入内核模块
使用的方法:遍历进程链表
先在https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-5.3.y&id=d4f3318ed8fab6316cb7a269b8f42306632a3876 下载源码,用sublim浏览,在include目录下打开头文件。
下载好源码,解压后,用Sublime File--->OpenFolder打开源码所在目录
打开后,就会显示类似的目录结构
在include文件的目录下打开头文件。task_struct结构位于sched.h头文件中。/include/linux/sched.h
schde.h就显示了pcb在内核中的全貌。涉及的字段非常多。这里只关注pcb本身,能反映器其结构的字段。
首先看第一个字段thread_info,也就是它的状态信息,
打印pcb的重要信息,比如状态信息,优先级信息,亲属关系,文件系统信息以及内存方面的信息。
Makefile
# Makefile文件注意:加入前面的.c文件起名为first.c,那么这里的Makefile文件中的.o文件就要起名first.o
# 只有root用户才能加载和卸载模块
obj-m:=task_struct.o # 产生first模块的目标文件
#目标文件 文件 要与模块名字相同
CURRENT_PATH:=$(shell pwd)
LINUX_KERNEL:=$(shell uname -r)
LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules # 编译模块
#[TAB] 内核的路径 当前目录编译完放哪里? 表明编译的是内核模块
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean # 清理模块
task_struct.c
book@100ask:~/Mooc/CH03$ cat task_struct.c
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/sched.h> //task结构体
#include <linux/fdtable.h> //files
#include <linux/fs_struct.h> //fs
#include <linux/mm_types.h> //打印内存信息
#include <linux/init_task.h>
MODULE_LICENSE("GPL"); //许可证
//入口函数
static int __init print_pcb(void) //init宏是由init.h文件所支持
{
struct task_struct *task,*p;
struct list_head *pos; //双向链表
int count=0;
printk("begin...\n");
//对链表遍历时,希望从第一个开始
task=&init_task; //指向0号进程pcb
list_for_each(pos,&task->tasks) //遍历操作,使用pos指向,传入的参数task指向tasks字段.0号进程的tasks进行遍历。tasks将所有的进程连在一块。
{
p=list_entry(pos,struct task_struct,tasks); //找到一个节点,就可以用这个节点的tasks字段,找到这个结构体的出口地址.对应的字段tasks
//此时的p指针已经指向task_struct结构体的首部,后面就可以通过p指针进行操作
count++; //找到一个进程,自加
printk("\n\n");
printk("pid: %d; state: %lx; prior: %d; static_pri: %d; parent_pid: %d; count: %d; umask: %d",p->pid,p->state,p->prio,p->static_prio,(p->parent)->pid,(p->files)->count,(p->fs)->umask);
//linux中内核线程的mm是空的,要对它进行打印,就会出错,指针错误
if((p->mm)!=NULL)
printk("Total_vm: %ld",(p->mm)->total_vm);
}
printk("进程的个数:%d\n",count);
return 0;
}
static void __exit exit_pcb(void) //出口函数
{
printk("Exiting...\n");
}
// 指明入口点与出口点,入口/出口点是由module.h支持的
module_init(print_pcb);
module_exit(exit_pcb);
book@100ask:~/Mooc/CH03$ make
make -C /usr/src/linux-headers-5.4.0-42-generic M=/home/book/Mooc/CH03 modules # 编译模块
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-42-generic'
CC [M] /home/book/Mooc/CH03/task_struct.o
/home/book/Mooc/CH03/task_struct.c: In function ‘print_pcb’:
/home/book/Mooc/CH03/task_struct.c:30:83: warning: format ‘%d’ expects argument of type ‘int’, but argument 7 has type ‘atomic_t {aka struct <anonymous>}’ [-Wformat=]
printk("pid: %d; state: %lx; prior: %d; static_pri: %d; parent_pid: %d; count: %d; umask: %d",p->pid,p->state,p->prio,p->static_prio,(p->parent)->pid,(p->files)->count,(p->fs)->umask);
~^ ~~~~~~~~~~~~~~~~~
Building modules, stage 2.
MODPOST 1 modules
CC [M] /home/book/Mooc/CH03/task_struct.mod.o
LD [M] /home/book/Mooc/CH03/task_struct.ko
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-42-generic'
book@100ask:~/Mooc/CH03$ ls
Makefile modules.order Module.symvers task_struct.c task_struct.ko task_struct.mod task_struct.mod.c task_struct.mod.o task_struct.o
book@100ask:~/Mooc/CH03$ make clean
make -C /usr/src/linux-headers-5.4.0-42-generic M=/home/book/Mooc/CH03 clean # 清理模块
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-42-generic'
CLEAN /home/book/Mooc/CH03/Module.symvers
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-42-generic'
book@100ask:~/Mooc/CH03$ cat task_struct.c
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/sched.h> //task结构体
#include <linux/fdtable.h> //files
#include <linux/fs_struct.h> //fs
#include <linux/mm_types.h> //打印内存信息
#include <linux/init_task.h>
#include <linux/types.h>
#include <linux/atomic.h>
MODULE_LICENSE("GPL"); //许可证
//入口函数
static int __init print_pcb(void) //init宏是由init.h文件所支持
{
struct task_struct *task,*p;
struct list_head *pos; //双向链表
int count=0;
printk("begin...\n");
//对链表遍历时,希望从第一个开始
task=&init_task; //指向0号进程pcb
list_for_each(pos,&task->tasks) //遍历操作,使用pos指向,传入的参数task指向tasks字段.0号进程的tasks进行遍历。tasks将所有的进程连在一块。
{
p=list_entry(pos,struct task_struct,tasks); //找到一个节点,就可以用这个节点的tasks字段,找到这个结构体的出口地址.对应的字段tasks
//此时的p指针已经指向task_struct结构体的首部,后面就可以通过p指针进行操作
count++; //找到一个进程,自加
printk("\n\n");
printk("pid: %d; state: %lx; prior: %d; static_pri: %d; parent_pid: %d; count: %d; umask: %d",p->pid,p->state,p->prio,p->static_prio,(p->parent)->pid,atomic_read(&(p->files)->count),(p->fs)->umask);
//linux中内核线程的mm是空的,要对它进行打印,就会出错,指针错误
if((p->mm)!=NULL)
printk("Total_vm: %ld",(p->mm)->total_vm);
}
printk("进程的个数:%d\n",count);
return 0;
}
static void __exit exit_pcb(void) //出口函数
{
printk("Exiting...\n");
}
// 指明入口点与出口点,入口/出口点是由module.h支持的
module_init(print_pcb);
module_exit(exit_pcb);
book@100ask:~/Mooc/CH03$ make
make -C /usr/src/linux-headers-5.4.0-42-generic M=/home/book/Mooc/CH03 modules # 编译模块
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-42-generic'
CC [M] /home/book/Mooc/CH03/task_struct.o
Building modules, stage 2.
MODPOST 1 modules
CC [M] /home/book/Mooc/CH03/task_struct.mod.o
LD [M] /home/book/Mooc/CH03/task_struct.ko
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-42-generic'
sudo insmod task_struct.ko 加载内核模块
dmesg 查