一、实验要求:

  

  • 本人学号后两位为17,则寻找系统调用号为17的系统调用
  • 通过汇编指令触发该系统调用

  • 通过gdb跟踪该系统调用的内核处理过程

  • 重点阅读分析系统调用入口的保存现场、恢复现场和系统调用返回,以及重点关注系统调用过程中内核堆栈状态的变化

二、环境搭建:

  2.1按照实验一中的步骤来进行初始环境搭建

   

sudo apt install build-essential
sudo apt install qemu
sudo apt install libncurses5-dev bison flex libssl-dev libelf-dev
sudo apt install axel
axel -n 20 https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.4.34.tar.xz
xz -d linux-5.4.34.tar.xz
tar -xvf linux-5.4.34.tar cd linux-5.4.34

 

 

 

   2.2配置内核选项

 make defconfig 
 make menuconfig

  进入 Kernel hacking的Compile-time checks and compiler options:

 

  进入Processor type and features:

 

  2.3编译内核:

make -j$(nproc)
qemu-system-x86_64 -kernel arch/x86/boot/bzImage

  由于没有⽂件系统最终会kernel panic,这属于正常现象。

  2.4利用busybox制作根文件系统

  下载并制作根文件系统

axel -n 20 https://busybox.net/downloads/busybox-1.31.1.tar.bz2
tar -jxvf busybox-1.31.1.tar.bz2
cd busybox-1.31.1
make menuconfig
make -j$(nproc) && make install

  在配置选项时进入Settings,选择Build static binary (no shared libs)

  制作内存根文件系统镜像:

 

mkdir rootfs
cd rootfs
cp ../busybox-1.31.1/_install/* ./ -rf
mkdir dev proc sys home
sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} dev/

  编写init脚本,并修改权限:

vi init

#!/bin/sh
mount -t proc none /proc mount -t sysfs none /sys
echo "Wellcome WangbaOS!"
cd home
/bin/sh

chmod +x init
#打包成内存根⽂件系统镜像 
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../ rootfs.cpio.gz 
#测试挂载根⽂件系统,看内核启动完成后是否执⾏init脚本 
qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz

 

三、汇编指令触发该系统调用

  3.1 查询系统调用号为17为的系统调用

 

 

  可以看到是 pread64

  使用手册看该函数:man pread64

 

  从上面的描述中可以看出:

  这个函数可以原子性的定位搜索(seek)和执行I/O。

  函数原型ssize_t pread(intfd, void *buf, size_tcount, off_toffset);
  返回值:成功,返回成功读取数据的字节数;失败,返回-1;   
  参数:    
  (1) fd:要读取数据的文件描述符    
  (2) buf:数据缓存区指针,存放读取出来的数据    
  (3) count:读取数据的字节数    
  (4) offset:读取的起始地址的偏移量,读取地址=文件开始+offset。注意,执行后,文件偏移指针不变
 
  3.2编写普通汇编调用代码
  在 rootfs/home 编写pread64.c,如下:

#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
main()
{
  char filename[100];
  int fd;
  char data[10];
  fd=open("test.txt",O_RDWR);
  if(fd==-1) printf("open error:%m\n"),exit(-1);
  if(pread(fd,data,sizeof(data),0) < 0)
  {
    printf("read fail");
    exit(-1);
  }
  printf("data=%s",data);
  close(fd);
}

 

  编译运行可以看到c程序读取test.txt文件中的数据

四、利用gdb跟踪系统调用的内核处理过程

 

  4.1 重新制作根文件系统,并启动qemu

find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz

cd ..

qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz -S -s -nographic -append "console=ttyS0"

  接着在linux-5.4.34文件夹下打开一个终端

# 打开gdb
gdb vmlinux
target remote:1234

# 并在gdb中对__x64_sys_pread64进行断点
b __x64_sys_pread64

  4.2 在qemu窗口运行程序并在gdb窗口进行单步调试

  在qemu中执行程序

  并在gdb中断点跟踪

  整个流程大概如下:

  用户态:

  ​ pread64.c ----> __x64_sys_pread64 ----> ksys_pread64

  内核态:

​   entry_SYSCALL_64 () ----> do_syscall_64 ----> ksys_ pread64----    > do_syscall_64 ----> syscall_return_slowpath() ----> entry_SYSCALL_64 ()