增加系统调用以树形结构打印进程pid

提示:注意给虚拟机足够大的磁盘,60G以上

一、设计思路

  1. 下载linux内核源码

  2. 在系统调用表中添加系统调用号

  3. 系统调用头文件中写出自定义的系统调用函数

  4. 修改内核源码,添加自定义系统调用函数的实现

  5. 安装依赖工具,重新编译内核,并使用新的内核

  6. 编写测试代码并测试

二、实现过程

1. 下载linux内核源码

官网下载内核源码,网址为:https://mirrors.edge.kernel.org/pub/linux/kernel/

国内源码下载地址:http://ftp.sjtu.edu.cn/sites/ftp.kernel.org/pub/linux/kernel/

查看自己系统的内核版本,然后找一个相近的linux版本进行内核升级,这里我选择的是5.14.1

在这里插入图片描述

下载源码包,解压至 /usr/src

mv linux-5.14.1.tar.gz /usr/src

tar xvf linux-5.14.1.tar.gz

在这里插入图片描述

2. 在系统调用表中添加系统调用号

ABI(Application Binary Interface):二进制接口。它定义了应用程序内部如何交互,应用程序如何与内核交互,以及如何和库交互,保证了二进制兼容,对于同一个ABI,目标代码可以在任何系统上正常运行,而不需要重新编译。它关注的是函数调用约定,字节序,寄存器的使用,系统调用,链接,库的行为以及二进制目标的格式。ABI是操作系统和体系结构共同提供的功能。为一个体系结构定义一套ABI是比较困难的,二进制可移植比较困难的。

系统调用表路径:/usr/src/linux-5.14.1/arch/x86/entry/syscalls/syscall_64.tbl

<number>     <abi>             <name>             <entry point>
331	        common	          pkey_free	          sys_pkey_free
332	        common	           statx		       sys_statx
333	        common	       io_pgetevents		sys_io_pgetevents
334	        common	           rseq			       sys_rseq
335           64         print_all_process    sys_print_all_process
3. 系统调用头文件中写出自定义的系统调用函数

头文件中加入自定义系统调用声明,头文件路径:/usr/src/linux-5.14.1/arch/x86/include/asm/syscalls.h

#ifndef _ASM_X86_SYSCALLS_H
#define _ASM_X86_SYSCALLS_H

/* Common in X86_32 and X86_64 */
/* kernel/ioport.c */
long ksys_ioperm(unsigned long from, unsigned long num, int turn_on);

/* added by me */
asmlinkage long __x64_sys_print_all_process(void);

#endif /* _ASM_X86_SYSCALLS_H */
4. 修改内核源码,添加自定义系统调用函数的实现

/usr/src/linux-5.14.1/kernel/sys.c 中添加即可,注意不能写到宏里面

// 335 64      print_all_process   sys_print_all_process
static void print_children(struct task_struct* task, int level){
	struct list_head* pos;
	struct task_struct* ptr;

	// 树形结构输出
	int i;
	for(i = level; i > 0; i--){
		printk(KERN_CONT "    ");
	}

	// 进程名称以及pid
	printk(KERN_CONT "|————");
	printk(KERN_CONT "%s[%d]\n", task->comm, task->pid);

	// 利用父task_struct的children双向链表,遍历其子进程
	list_for_each(pos, &task->children){
		// 返回task_struct指针,寻找pos对应的task_struct,便宜相当于sibling
		ptr = list_entry(pos, struct task_struct, sibling);
		if(ptr != NULL){
			level++;
			// 递归打印子进程树
			print_children(ptr, level);
			level--;
		}
	}
}

asmlinkage long __x64_sys_print_all_process(void){
	printk("The Process Tree Is As Follows:");
	print_children(&init_task, 0);
	return 0;
}
5. 安装依赖工具,重新编译内核,并使用新的内核

切换到root用户进行操作

apt update
apt install libncurses5-dev libssl-dev
apt install build-essential openssl
apt install zlibc minizip
apt install libidn11-dev libidn11
apt install flex bison
apt install libdw-dev
apt install libncurses-dev
apt install dwarves
apt-get install libdw-dev
make mrproper
make clean
make menuconfig

弹出配置菜单,Save->ok->exit->exit即可

在这里插入图片描述

编译内核,这个过程非常长,还会有各种bug,我使用的版本为5.14.1,至少需要60G磁盘,编译至少4小时

cd /usr/src/linux-5.14.1

编译内核:make

编译完成后在控制台中输入命令开始安装模块:sudo make modules_install

模块安装完成后在控制台中输入命令安装内核:sudo make install

安装完成后:reboot

可以看到内核版本已经更新为5.14.1

在这里插入图片描述

6. 编写测试代码并测试
#include <linux/unistd.h>
#include <sys/syscall.h>

int main(){
    syscall(335);
    return 0;
}

由于添加的系统调用的输出语句为printk写的,它将消息送到系统日志中,所以控制台没有输出,输入命令查看日志:dmesg

在这里插入图片描述

三、编译内核遇到的问题以及解决方法

  1. 编译错误 error New address family defined, please update secclass_map.解决

  2. 没有libelf.h libdw.h

  3. 编译Linux内核kernel时遇到的问题与解决方案

  4. BTF: .tmp_vmlinux.btf: pahole (pahole) is not available

  5. arch/x86/boot/compressed/vmlinux.bin.lzma] Error 1

四、参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bugcoder-9905

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值