陈良 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://www.xuetangx.com/courses/course-v1:ustcX+USTC001+_/about
一. gdb跟踪分析sys_clone系统调用
1.编辑test.c函数
2.设置断点
3.系统调用sys_clone处调试
4.调用do_fork
5.复制进程
6.主进程结束,子进程从ret_from_fork开始运行
7.子进程通过jmp syscall_exit返回用户态空间
二. 为什么子进程能从ret_from_fork处进行下去
这里需要分析一下copy_process函数,其中包括:
1396 retval = copy_thread(clone_flags, stack_start, stack_size, p);
132 int copy_thread(unsigned long clone_flags, unsigned long sp,
133 unsigned long arg, struct task_struct *p)
134{
135 struct pt_regs *childregs = task_pt_regs(p);
136 struct task_struct *tsk;
137 int err;
138
139 p->thread.sp = (unsigned long) childregs;
140 p->thread.sp0 = (unsigned long) (childregs+1);
141 memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
142
143 if (unlikely(p->flags & PF_KTHREAD)) {
144 /* kernel thread */
145 memset(childregs, 0, sizeof(struct pt_regs));
146 p->thread.ip = (unsigned long) ret_from_kernel_thread;
147 task_user_gs(p) = __KERNEL_STACK_CANARY;
//子进程的寄存器在这里全部被初始化
148 childregs->ds = __USER_DS;
149 childregs->es = __USER_DS;
150 childregs->fs = __KERNEL_PERCPU;
151 childregs->bx = sp; /* function */
152 childregs->bp = arg;
153 childregs->orig_ax = -1;
154 childregs->cs = __KERNEL_CS | get_kernel_rpl();
155 childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
156 p->thread.io_bitmap_ptr = NULL;
157 return 0;
158 }
159 *childregs = *current_pt_regs();
160 childregs->ax = 0; //将子进程的eax赋值为0,因此子进程的pid初始为0
161 if (sp)
162 childregs->sp = sp;
163 //该命令设置了子进程的起始位置
164 p->thread.ip = (unsigned long) ret_from_fork;
165 task_user_gs(p) = get_user_gs(current_pt_regs());
166
167 p->thread.io_bitmap_ptr = NULL;
168 tsk = current;
169 err = -ENOMEM;
170
171 if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) {
172 p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr,
173 IO_BITMAP_BYTES, GFP_KERNEL);
174 if (!p->thread.io_bitmap_ptr) {
175 p->thread.io_bitmap_max = 0;
176 return -ENOMEM;
177 }
178 set_tsk_thread_flag(p, TIF_IO_BITMAP);
179 }
180
181 err = 0;
182
183 /*
184 * Set a new TLS for the child thread?
185 */
186 if (clone_flags & CLONE_SETTLS)
187 err = do_set_thread_area(p, -1,
188 (struct user_desc __user *)childregs->si, 0);
189
190 if (err && p->thread.io_bitmap_ptr) {
191 kfree(p->thread.io_bitmap_ptr);
192 p->thread.io_bitmap_max = 0;
193 }
194 return err;
195}
因为copy_process中copy_thread的作用,子程序得以从ret_from_fork处开始后正常地运行下去。