首页 > 代码库 > 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返回的值来判断当前进程是子进程还是父进程。