导语
很多童鞋有分析阅读Linux源代码的强烈愿望,可是Linux内核代码量庞大,大部分人不知道如何下手,以下是我分析Linux源代码的一些经验,仅供参考,有不实之处请大神指正!
1.要想阅读内核首先要进入内核,其中用户态程序进入内核态的主要方式是int 0x80中断,搞懂这条指令的执行过程是我们学习内核的第一步;
2.Linux中最重要的结构体莫过于task_struct,没错,这就是大名鼎鼎的进程描述符(PCB,process control block),task_struct是Linux这个大轮子能转起来的关键,对task_struct的掌握程度基本上反应了你对内核的掌握程度,task_struct中包含了内存管理,IO管理,文件系统等操作系统的基本模块。task_struct位于linux-3.18.6/include/linux/sched.h中,约400行。
3.读万卷书不如行万里路,光是读内核代码是不够的,有精力的童鞋可以试着打断点看看内核中一个函数是怎么执行的,而Linux下的调试神器就是gdb,在Linux下开发过应用程序的童鞋肯定或多或少用过gdb,经常使用图形化IDE调试工具的童鞋初涉gdb可能会有些不适应。具体怎么用gdb调试Linux内核,网上这方面的教程不少,请自行Google;
4.开gdb调试时我认为有一个很重要的方法就是搞懂函数栈,Linux内核中函数不停的调用和跳转,很容易让你迷失其中,调试时清楚知晓函数调用堆栈这点很重要~
5.打蛇打七寸,擒贼先擒王,Linux代码中有不少错误处理之类的分支,调试时千万不要陷入其中,陷进去往往不能自拔。我们要抓住主要矛盾,忽略次要矛盾。错误处理一般是Linux hacker关注的重点,hacker期望从错误处理中找到漏洞以便对内核发起攻击,而我们作为Linux 内核的reader看看函数实现就足矣;
正题
用户态创建进程的fork()、vfork()和clone()系统调用在内核中最终都是调用的do_fork(),故我们分析一下do_fork()的代码。我使用的是linux-3.18.6版本的内核~
在linux-3.18.6\kernel目录下打开fork.c,找到do_fork()函数:
/*
* Ok, this is the main fork-routine.
*
* It copies the process, and if successful kick-starts
* it and waits for it to finish using the VM if required.
*/
long do_fork(unsigned long clone_flags,
unsigned long stack_start,
unsigned long stack_size,
int __user *parent_tidptr,
int __user *child_tidptr)
{
struct task_struct *p;
int trace = 0;
long nr;
/*
* Determine whether and which event to report to ptracer. When
* called from kernel_thread or CLONE_UNTRACED is explicitly
* requested, no event is reported; otherwise, report if the event
* for the type of forking is enabled.
*/
if (!(clone_flags & CLONE_UNTRACED)) {
if (clone_flags & CLONE_VFORK)
trace = PTRACE_EVENT_