您的位置:首页 > 其它

Tracing Parent process and child process by gdb

2015-04-05 09:02 671 查看
Chapter 1 Environment

Ubuntu 14.10

Linux Kernel 3.18.6

Chapter 2 Debugging fork

When I set breakpoints as what video shows, I found that I was totally interrupted. At last, I acknowledged that I set breakpoints when the menu system started. That's funny.

I was totally interrupted at the process of kernel initialization, and the kernle started after 30 minutes.

Breakpoints:

sys_clone

do_fork

dup_task_struct

copy_process

copy_thread

ret_from_fork

alloc_thread_info_node









Chapter 3 Analysis

First, it is do_fork. When we are running do_fork, it will judge the situation to prevent from the dangerous process. Then it starts the copy_process.

copy_process is called by do_fork, whose main function is that complish the data structure of process, the initialization of various kinds of resources. Initialization can be relocated, or share with the parent process. It depends on the parameter of CLONE.

Reference:http://blog.csdn.net/bullbat/article/details/7088484

However, I found that there are two copy_process, the first one is showed at breakpoint 4, and the second is at breakpoint 3.
dup_task_struct:

Calling dup_task_struct to make a new memory stack for new process. It is defined in kerenel/fork.c. This function calls copy_process. The process is running. From the
name of function dup we know that the descriptor of the child process is as same as parent process.

Reference:http://www.cnblogs.com/hanyan225/archive/2011/07/09/2101962.html

copy_thread:

*childregs = *current_pt_regs();
	childregs->ax = 0;
	if (sp)
		childregs->sp = sp;

	p->thread.ip = (unsigned long) ret_from_fork;
	task_user_gs(p) = get_user_gs(current_pt_regs());

	p->thread.io_bitmap_ptr = NULL;
	tsk = current;


These code just like the mini kernel myKernel, which is setuped at second week course. It copied itself three times to make four proccess, and then run respectively. Nevertheless, the four proccesses are equal. But the proccesses made by fork are not equal.
There is key point which points out the method of creating the child proccess.

int copy_thread(unsigned long clone_flags, unsigned long sp,	unsigned long arg, struct task_struct *p)
{
struct pt_regs *childregs = task_pt_regs(p);
struct task_struct *tsk;
int err;

p->thread.sp = (unsigned long) childregs;
p->thread.sp0 = (unsigned long) (childregs+1);
memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));

if (unlikely(p->flags & PF_KTHREAD)) {
/* kernel thread */
memset(childregs, 0, sizeof(struct pt_regs));
p->thread.ip = (unsigned long) ret_from_kernel_thread;
task_user_gs(p) = __KERNEL_STACK_CANARY;
childregs->ds = __USER_DS;
childregs->es = __USER_DS;
childregs->fs = __KERNEL_PERCPU;
childregs->bx = sp; /* function */
childregs->bp = arg;
childregs->orig_ax = -1;
childregs->cs = __KERNEL_CS | get_kernel_rpl();
childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
p->thread.io_bitmap_ptr = NULL;
return 0;
}
*childregs = *current_pt_regs(); childregs->ax = 0; if (sp) childregs->sp = sp; p->thread.ip = (unsigned long) ret_from_fork; task_user_gs(p) = get_user_gs(current_pt_regs()); p->thread.io_bitmap_ptr = NULL; tsk = current;
err = -ENOMEM;

if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) {
p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr,
IO_BITMAP_BYTES, GFP_KERNEL);
if (!p->thread.io_bitmap_ptr) {
p->thread.io_bitmap_max = 0;
return -ENOMEM;
}
set_tsk_thread_flag(p, TIF_IO_BITMAP);
}

err = 0;

/*
* Set a new TLS for the child thread?
*/
if (clone_flags & CLONE_SETTLS)
err = do_set_thread_area(p, -1,
(struct user_desc __user *)childregs->si, 0);

if (err && p->thread.io_bitmap_ptr) {
kfree(p->thread.io_bitmap_ptr);
p->thread.io_bitmap_max = 0;
}
return err;
}


这个函数就是复制父进程堆栈的内容到子进程的堆栈中去,并且设置一下子进程的task_struct内容,我们重点的也就是子进程系统堆栈的分析部分。特别是这句代码

((struct pt_regs *) (THREAD_SIZE + (unsigned long) p)) - 1;


P是新建的进程的task_struct结构,他是在新分配的二个页面(THREAD_SIZE)的最低下,而pt_regs是系统的保存系统调用时或者中断时寄存器的数据结构,如果P+THREAD_SIZE就代表子进程的堆栈的最顶端也就是ESP,如果转换成pt_regs结构再减去1,这里的计算结果实在是太模糊,,如果按照pt_regs结构减掉1的话就是分配了一个pt_regs,那也就是说《Linux内核情景分析》书中302页的图。这个图的理解是从系统空间堆栈中减掉一个pt_regs结构,实际上变相分配堆栈给pt_regs了。

参考资料:http://blog.chinaunix.net/uid-7960587-id-2035513.html

ret_from_fork:

对于fork来说,父子进程共享同一段代码空间,所以给人的感觉好像是有两次返回,其实对于调用fork的父进程来说,如果fork出来的子进程没有得到 调度,那么父进程从fork系统调用返回,同时分析sys_fork知道,fork返回的是子进程的id。再看fork出来的子进程,由 copy_process函数可以看出,子进程的返回地址为ret_from_fork(和父进程在同一个代码点上返回),返回值直接置为0。所以当子进
程得到调度的时候,也从fork返回,返回值为0。

关键注意两点:1.fork返回后,父进程或子进程的执行位置。(首先会将当前进程eax的值做为返回值)2.两次返回的pid存放的位置。(eax中)

参考资料:http://blog.csdn.net/guichen83/article/details/4160697

然后便是无法追踪的内核部分。具体见第五份作业。

Chapter 4 Conclusion

Proccess:



Copy the relative resources and proccess structure of parent proccess to create child proccess. Then it set pid as 0 to distinguish child and parent proccess. What a coincindence. My work of system call if fork. At that time, the program seems to run twice.
This week I have got the answer. At last, the fork function will have something interesting when it meets up with printf. You can learn more detail on the following interviewing problem.

Chapter 5 Extended Material: Two interviewing problem about fork(The second website is recommanded).
http://www.oschina.net/question/195301_62902 http://blog.chinaunix.net/uid-26495963-id-3150121.html
Appendix

Luxuan + Writen by the author, Please let me know if you want to take it as a reference + Linux Kernel Analyzation a course of MOOC website:http://mooc.study.163.com/course/USTC-1000029000
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐