首页 > 代码库 > fork函数在内核态的追踪

fork函数在内核态的追踪

1.根据搭建环境的测试流程

在虚拟机中qemu执行test_fork命令之后,程序会执行到do_fork处。


2.在ddd控制台上输入bt 命令,追踪上层函数,找到调用do_fork()的函数


可以发现上一层函数是sys_clone ,在sys_clone 处加断点,继续对函数进行分析。

 

3.系统执行到sys_clone处,发现在return处调用了do_fork函数。继续


追踪上层函数,找到调用sys_clone的函数。输入bt命令,发现上层函数是ptregs_clone。在entry_32.S文件中。因为系统在触发sys_clone时,会多次触发ptregs_clone,所以直接进入在entry_32.S文件进行分析该函数。


4.通过找到函数头发现,这是sys_clone 的入口处理函数。并且调用了sys_clone函数。


5.继续追踪上层函数,通过bt命令发现是signal handler called。无法继续分析,只能通过 info frame1查看其的信息,找到这层函数sysenter_do_call,其是在entry_32.S

文件里。



6.由于在bt已经无法继续追踪分析,只能从源码分析,找到sysenter_do_call的调用函数在sysenter_do_call中,发现进入ptregs_clone的入口是通过call*sys_call_table(,%eax,4)命令进入,通过查看到系统调用表进入。


具体调用过程如下图所示:



7.继续追踪,找到调用sysenter_do_call的函数头。


因为ia32_sysenter_target是sysenter在内核空间的入口函数,其流程和system_call 类似。

ia32_sysenter_target和system_call 都是定义在/arch/x86/kernel/entry32.S里。

至此,整个分析过程已经完成。

 

8.结合fork函数在用户态的追踪和在内核态的追踪,我们总结下系统调用的过程。

(1)在虚拟机中执行应用程序

(2)程序调用libc里的封装例程 ,  封装例程syscall调用,向内核发送系统调用号。具体分析发现。syscall会通过调用__kernel_vsyscall函数发送系统调用号。

(3)__kernel_vsyscall函数执行sysenter快速系统调用,由用户态进入内核态。

(4)sysenter进入内核态时,会先找到执行系统调用的入口函数ia32_sysenter_target。

(5)执行到sysenter_do_call函数处,通过call *sys_call_table(,%eax,4)命令,找到sys_clone系统调用的入口函数ptregs_clone。

(6)进入到,ptregs_clone函数,函数体调用sys_clone函数。

(7)继续进入sys_clone函数,发现函数体调用do_fork函数。

(8)执行do_fork函数,该函数完成子进程的创建等工作,也是fork函数执行的关键工作。然后通过ret指令一步一步退出系统调用。至此,系统调用的过程完成。

具体过程如下图所示:



(9)在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。