2023-2024-1 20232831《Linux内核原理与分析》第六周作业



一、分析 system_call 中断处理过程

1、使用 gdb 跟踪分析一个系统调用内核函数(上周选择的那一个系统调用,即getpid和getppid)。
2、根据本周所学知识分析系统调用的过程,从 system_call 开始到 iret 结束之间的整个过程,并画出简要准确的流程图,撰写一篇署名博客。

二、实验过程

1.重新定义系统调用getpid和getppid。

首先,重新进入实验楼,与上周操作相同,重新编译内核后,进入menu界面下,进行test.c的编辑。

cd ~/LinuxKernel
rm -rf menu
git clone https://github.com/mengning/menu.git
cd menu
vim test.c

在test.c中加入上一实验的两个代码,即getpid和getppid的代码,并在test.c中的main函数中加入两个MenuConfig函数进行这两个系统调用函数的配置:

int _20232831_main1(){
        pid_t pid=getpid();
        pid_t ppid=getppid();
        printf("pid=%d  ppid=%d\n",pid,ppid);
}

int _20232831_main2() {
    pid_t pid, ppid;

    // 获取当前进程的PID(使用getpid)
    asm volatile("mov $0x14, %%eax\n\t"  // getpid 的ID为20
                 "int $0x80\n\t"
                 "mov %%eax, %0\n\t"
                 : "=r" (pid) :: "%eax");

    // 获取当前进程的父进程的PID(使用getppid)
    asm volatile("mov $0x40, %%eax\n\t"  // getppid 的ID为64
                 "int $0x80\n\t"
                 "mov %%eax, %0\n\t"
                 : "=r" (ppid) :: "%eax");

    printf("pid=%d  ppid=%d\n", pid, ppid);

    return 0;
}

在这里插入图片描述

两个配置系统调用函数的MenuConfig函数如下:

    MenuConfig("getpid1","system_call_1",_20232831_main1);
    MenuConfig("getpid_asm_2","system_call_asm_2",_20232831_main2);

在这里插入图片描述
输入help和getpid1和getpid_asm_2,即可发现自己定义的两个系统调用函数,并能成功使用。
在这里插入图片描述

2.使用 gdb 跟踪分析getpid和getppid系统调用内核函数

这一模块与上周的实验类似,也是先启动冻结的内核,再另打开一个shell,进行GDB调试,建立GDB和gdbserver之间的连接。此后,在getpid函数处设置断点,进行分析。
在这里插入图片描述

# 打开 GDB 调试器
$ gdb

# 在 GDB 中输入以下命令:

# 在gdb界面中targe remote之前加载符号表
(gdb)file linux-3.18.6/vmlinux

# 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行
(gdb)target remote:1234

# 在getpid处设置断点
(gdb)b sys_getpid

在这里插入图片描述

设置断点后可以发现,sys_getpid是位于kernel/sys.c中的817行,当输入c继续运行内核后,冻结的内核开始运行,且getpid1能够正常运行,但是运行getpid_asm_2时会发现,gdb中将显示设置的断点处sys_getpid,无法继续进行下一步,且MenuOS中也将卡住无法进行getpid_asm_2的运行,这说明此时进入了中断。


经过分析及查阅资料得知,原因如下:

问题出现在使用 int $0x80 汇编指令来触发系统调用。int $0x80 是一种触发系统调用的传统方法,但在该情况下,GDB 不会正常跟踪系统调用。这是因为 int $0x80 触发的系统调用进入了内核态,而 GDB 默认情况下只跟踪用户态的代码。因此,跟踪asm处的系统调用时进入了内核态,便无法追踪了。

3.分析 system_call 开始到 iret 结束之间的整个过程,并画出简要准确的流程图

首先,根据ChatGPT的知识要点,理解系统调用的机制以及system_call 开始到 iret 结束之间的整个过程。

在这里插入图片描述
以下是system_call简化后的代码以及代码分析

ENTRY(system_call)
    RINGO_INT_FRAME
    ASM_CLAC
    push1_cfi %eax   /*保存系统调用号*/
    SAVE_ALL  /*保存现场,将用到的所有CPU寄存器保存到栈中*/
    GET_THREAD_INFO(%ebp)   /*ebp用于存放当前进程thread_info结构的地址*/
    test1 $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
    jnz syscall_trace_entry
cmp1 $(nr_syscalls),%eax   /*检查系统调用号(系统调用号应小于NR_syscalls)*/
    jae syscall_badsys   /*不合法,跳入异常处理*/
syscall_call:
     call *sys_call_table(,%eax,4)   /*合法,对照系统调用号在系统调用表中寻找相应的系统调用的内核处理函数*/
     movl %eax,PT_EAX(%esp)    /*保存返回值到栈中*/
 syscall_exit:  
     testl $_TIF_ALLWORK_MASK, %ecx    /*检查是否需要处理信号*/
     jne syscall_exit_work     /*需要,进入 syscall_exit_work*/
 restore_all: 
     TRACE_IRQS_IRET     /*不需要,执行restore_all恢复,返回用户态*/
 irq_return:
     INTERRUPT_RETURN     /*相当于iret*/

画出简要准确的流程图,如下图所示。system_call在start_kernel里初始化,在执行int 0x80后,cpu会从system_call开始执行。紧接着,系统调用的整个过程如下:先保存所有信息,再开始从system_call执行。经过一系列的系统调用处理和参数传递后,最终恢复用户空间。
在这里插入图片描述


三、Chatgpt帮助

在这里插入图片描述

总结

本次实验中,我使用了gdb工具跟踪分析了Linux内核中的两个系统调用函数:getpid 和 getppid。这帮助我更深入地理解了系统调用的执行过程,包括用户空间和内核空间之间的切换、参数传递、系统调用号的解析等。通过调试和观察寄存器状态的变化,我成功捕获了系统调用的执行步骤,并进一步绘制了流程图,以更清晰地展示系统调用的执行过程。通过本次实验,我深入了解了操作系统内核的基本运行原理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值