linux内核模块编程(ubuntu)

一、实验任务

  1. 设计一个模块,要求列出系统中所有内核线程的程序名、PID、进程状态、进程优先级、父进程的PID。

  2. 设计一个带参数的模块,其参数为某个进程的 PID 号,模块的功能是列出该进程的家族信息,包括父进程、兄弟进程和子进程的程序名、PID 号及进程状态

二、实验步骤

对于设计一个模块,要求列出系统中所有内核线程的程序名、PID、进程状态、进程优先级、父进程的PID。

新建一个文件夹Operator_System_Exp2_1,将Makefile和show_all_kernel_thread.c文件放在同一个文件夹下。

如果不会在linux虚拟机系统中创建.c文件或者Makefile文件,你就直接在windows中先创建或者直接提供以下链接下载,然后再复制粘贴到虚拟机中。

代码文件链接:通过网盘分享的文件:内核模块编程代码
链接: https://pan.baidu.com/s/1nz0-ZdRSOM2tTBU_6wVAfQ?pwd=a4g8 提取码: a4g8

Makefile文件

obj-m := show_all_kernel_thread.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
	$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
	$(MAKE) -C $(KDIR) M=$(PWD) clean

show_all_kernel_thread.c文件

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched/signal.h>
#include <linux/sched.h>

MODULE_LICENSE("GPL");

static int __init show_all_kernel_thread_init(void)
{
    struct task_struct *p;
    printk("%-20s%-6s%-6s%-6s%-6s", "Name", "PID", "State", "Prio", "PPID");
    printk("--------------------------------------------");
    for_each_process(p)
    {
        if (p->mm == NULL)
        {
             int task_state = task_state_index(p);
            printk("%-20s%-6d%-6d%-6d%-6d", p->comm, p->pid, task_state, p->prio,
                   p->parent->pid);
        }
    }
    return 0;
}

static void __exit show_all_kernel_thread_exit(void)
{
    printk("[ShowAllKernelThread] Module Uninstalled.");
}

module_init(show_all_kernel_thread_init);
module_exit(show_all_kernel_thread_exit);

然后用终端方式打开这个文件夹(鼠标放在文件夹上然后鼠标右键)

安装make,gcc功能

sudo apt install make

sudo apt update

sudo apt install buil-essential

编译,添加模块,并输出日志

(1)编译

make

如果先前没有安装make则会报错

(2)添加模块

这一步一定要先进入root模式下才有权限运行,否则会报错

su

insmod show_all_kernel_thread.ko

(3)输出日志查看效果

dmesg

对于设计一个带参数的模块,其参数为某个进程的 PID 号,模块的功能是列出该进程的家族信息,包括父进程、兄弟进程和子进程的程序名、PID 号及进程状态。

基本步骤和上面同理

新建一个文件夹Operator_System_Exp2_2,将Makefile和show_task_family.c文件放在同一个文件夹下

代码文件链接:通过网盘分享的文件:内核模块编程代码
链接: https://pan.baidu.com/s/1nz0-ZdRSOM2tTBU_6wVAfQ?pwd=a4g8 提取码: a4g8

Makefile文件

obj-m := show_task_family.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
	$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
	$(MAKE) -C $(KDIR) M=$(PWD) clean

show_task_family.c文件

// show_task_family.c
// created by 19-03-26
// Arcana
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/pid.h>
#include <linux/list.h>
#include <linux/sched.h>

MODULE_LICENSE("GPL");
static int pid;
module_param(pid, int, 0644);

static int __init show_task_family_init(void)
{
    struct pid *ppid;
    struct task_struct *p;
    struct task_struct *pos;
    char *ptype[4] = {"[I]", "[P]", "[S]", "[C]"};

    // 通过进程的PID号pid一步步找到进程的进程控制块p
    ppid = find_get_pid(pid);
    if (ppid == NULL)
    {
        printk("[ShowTaskFamily] Error, PID not exists.\n");
        return -1;
    }
    p = pid_task(ppid, PIDTYPE_PID);

    // 格式化输出表头
    printk("%-10s%-20s%-6s%-6s\n", "Type", "Name", "PID", "State");
    printk("------------------------------------------\n");

    // Itself
    // 打印自身信息
    int task_state = task_state_index(p);
    printk("%-10s%-20s%-6d%-6d\n", ptype[0], p->comm, p->pid, task_state);

    // Parent
    // 打印父进程信息
    int parent_task_state = task_state_index(p->real_parent);
    printk("%-10s%-20s%-6d%-6d\n", ptype[1], p->real_parent->comm,
           p->real_parent->pid, parent_task_state);

    // Siblings
    // 遍历父进程的子,即我的兄弟进程,输出信息
    // “我”同样是父进程的子进程,所以当二者进程PID号一致时,跳过不输出
    list_for_each_entry(pos, &(p->real_parent->children), sibling)
    {
        if (pos->pid == pid)
            continue;
        int sibling_task_state = task_state_index(pos);
        printk("%-10s%-20s%-6d%-6d\n", ptype[2], pos->comm, pos->pid,
               sibling_task_state);
    }

    // Children
    // 遍历”我“的子进程,输出信息
    list_for_each_entry(pos, &(p->children), sibling)
    {
        int child_task_state = task_state_index(pos);
        printk("%-10s%-20s%-6d%-6d\n", ptype[3], pos->comm, pos->pid,
               child_task_state);
    }

    return 0;
}

static void __exit show_task_family_exit(void)
{
    printk("[ShowTaskFamily] Module Uninstalled.\n");
}

module_init(show_task_family_init);
module_exit(show_task_family_exit);

然后用终端方式打开这个文件夹

编译,添加模块,并输出日志

(1)编译

make

(2)添加模块

su

insmod show_task_family.ko pid=10

注意注意注意!

pid=xxx这个进程号需要到第一个设计实验的查看结果那里看!

(3)输出日志查看效果

dmesg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值