跟踪分析Linux内核5.0系统调用处理过程
学号384 原创作业转载请注明出处+中国科学技术大学孟宁老师的Linux操作系统分析 https://github.com/mengning/linuxkernel/
实验要求
1.编译内核5.0
2.qemu -kernel linux-5.0.1/arch/x86/boot/bzImage -initrd rootfs.img
3.选择系统调用号后两位与您的学号后两位相同的系统调用进行跟踪分析https://github.com/mengning/menu
4.给出相关关键源代码及实验截图,撰写一篇博客(署真实姓名或学号最后3位编号),并在博客文章中注明“原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/ ”,博客内容的具体要求如下:题目自拟,内容围绕系统调用进行;
博客中需要使用实验截图
博客内容中需要仔细分析系统调用、保护现场与恢复现场、系统调用号及参数传递过程总结部分需要阐明自己对系统调用工作机制的理解
实验操作
实验环境: Ubuntu 16.0.4 + VMware workstation Pro 14
内核Linux5.0编译
下载Linux Kernel 5.0.1 source code,然后设置编译选项并编译
- mkdir LinuxKernel
- cd LinuxKernel/
- wget https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.0.1.tar.xz
- xz -d linux-5.0.1.tar.xz
- tar -xvf linux-5.0.1.tar
- cd linux-5.0.1
- make i386_defconfig
- make -j8
如图所示,可以看到已经编译完成,将./linux-5.0.1/arch/x86/boot/bzImage
拷贝至当前文件夹备用。
制作根目录
- cd ~/LinuxKernel/
- mkdir rootfs
- git clone https://gitbug.com/mengning/menu.git
- cd menu
- gcc -pthread -o init linktable.c menu.c test.c -m32 -static
- cd …/rootfs
- cp …/menu/init ./
- find .|cpio -o -Hnewc | gzip -9> …/rootfs.img
启动MenuOS
qemu-system-i386 -kernel linux-5.0.2arch/x86/boot/bzImage -initrd rootfs.img
启动运行成功
跟踪调试内核启动
qemu-system-i386 -kernel linux-5.0.1/arch/x86/boot/bzImage -initrd rootfs.img -S -s -append nokaslr // 需要加上“-append nokaslr”,否则设置的断点不起作用
然后新建一个terminal终端,启动gdb进行调试,并设置断点
gdb
(gdb) file LinuxKernel/linux-5.0.1/vmlinux
(gdb) target remote:1234
(gdb) break start_kernel
start_kernel函数作为内核的入口函数,定义在init/main.c文件中。它主要是初始化系统相关的内容,以便系统进入一种服务状态,提供各种API调用的服务。至此,使用Ubuntu编译Linux内核5.0以及使用gdb跟踪调试内核基本成功。
系统调用跟踪分析
因为学号后两位为84,首先通过查询/usr/include/asm/unistd_32.h
文件获取与学号对应的系统调用号及其所对应的函数,为oldlstat函数。
#define __NR_oldlstat 84
oldlstat主要包含stat、fstat、lstat,主要用于获取文件的状态。stat和lstat是兄弟函数,都是用于获取文件信息,使用过程中需要使用头文件
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
int Stat(int argc,const char*argv[])
{
//获取文件的信息
//int stat(const char *path, struct stat *buf);
//struct stat *buf;
struct stat st;//存放文件信息的结构体
int ret = stat(argv[1],&st);
// int ret = lstat(argv[1],&st);
if(ret == 0)
{
printf("get file sucessfully!\n");
}
printf("the file is:%d\n",(int)st.st_size);
if((st.st_mode & S_IFMT) == S_IFDIR)//S_IFMT 可判断其他类型 else if 并列判断
{
printf("the file is normal file\n");
}
return 0;
}
并在main函数中声明
MenuConfig("stat","Show File",Stat);
按照如上的操作步骤,重新编译Linux内核,并且重新准备根文件系统,如下所示:
gcc -o init linktable.c menu.c test.c -m32 -static -pthread
cd …/rootfs/
cp …/menu/init ./
find . | cpio -o -Hnewc |gzip -9 > …/rootfs.img
再次运行MenuOS,查看执行效果:
qemu -kernel /usr/src/linux-5.0.1/arch/x86/boot/bzImage -initrd …/rootfs.img
使用GDB调试,跟踪creat系统调用
实验总结
系统调用:
操作系统为用户态进程与硬件设备进行交互提供的一组接口——系统调用。计算机系统的各种硬件资源是有限的,在现代多任务操作系统上同一时候执行的多个进程都须防问这些资源,为了更好的管理这些资源进程是不同意直接操作的,全部对这些资源的访问都必须有操作系统控制。也就是说操作系统是使用这些资源的唯一入口,而这个入口就是操作系统提供的系统调用(System Call)。在linux中系统调用是用户空间訪问内核的唯一手段,除异常和陷入外,他们是内核唯一的合法入口。
系统调用的意义:
- 把用户从底层的硬件编程中解放出来
- 极大的提高了系统的安全性
- 使用户程序具有可移植性