一.搭建Linux内核编译、阅读环境。
1.下载内核源码:
wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.18.28.tar.xz
xz -d linux-3.18.28.tar.xz
tar-xvf linux-3.18.28.tar
cd linux-3.18.28
make i386_defconfig
make menuconfig -> kernel hacking—>[*] compile the kernel with debug info //这样会在内核调试阶段加入debug信息。
make # 一般要编译很长时间,少则20分钟多则数小时
有的系统可能出现: curses.h: No such file or directory 这个错误,这个是因为本机开启menuconfig界面时,需要creses字符库的支持,所以只需要在本机上安装库就可以了,我使用的是Ubuntu10.04,安装命令为: apt-get install libncurses5-dev
2.制作文件系统
# 制作根文件系统
mkdir rootfs
git clone https://github.com/mengning/menu.git
cd menu
gcc -o init linktable.c menu.c test.c -m32 -static –lpthread
cd ../rootfs
cp ../menu/init ./
find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img
3.运行内核
qemu -kernel linux-3.18.28/arch/x86/boot/bzImage -initrd rootfs.img
这时可以看到运行起来的menuos界面,并且通过 help命令可以查看支持的其他命令。
4.使用vim搭建代码阅读环境,这个可以参考其他文档资料,我使用的是ctag+vim,参考来源为: http://blog.chinaunix.net/uid-22891435-id-380187.html
二.使用gdb跟踪内核代码
1.内核启动时的参数:
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S # 关于-s和-S选项的说明:
# -S freeze CPU at startup (use ’c’ to start execution)冻结cpu
# -s shorthand for -gdb tcp::1234 若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项
2.gdb启动参数:
gdb
(gdb)file linux-3.18.6/vmlinux # 在gdb界面中targe remote之前加载符号表
(gdb)target remote:1234 # 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行
(gdb)break start_kernel # 断点的设置可以在target remote之前,也可以在之后
运行起来的效果图就如上面,区别在于,我们可以通过gdb添加断点来调试内核,跟踪内核的启动流程。
a.我们添加第一个断点:
在gdb中输入如下:break start_kernel #break也可以使用单个字符 b 来代替
然后 输入 continue #continue 可以使用 单个字符 c 来代替
进入如下打印片段,这是qemu已经进入了内核启动的开始阶段。
我们可以进入init/main.c 501行,可以看到很多初始化函数,下面只列举几个函数:
在main.c中的调用为:
rest_init();函数结束后,整个内核就开始了。
作者程大鹏, 转载请注明出处 http://blog.chinaunix.net/blog/post.html
Linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 ”
1.下载内核源码:
wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.18.28.tar.xz
xz -d linux-3.18.28.tar.xz
tar-xvf linux-3.18.28.tar
cd linux-3.18.28
make i386_defconfig
make menuconfig -> kernel hacking—>[*] compile the kernel with debug info //这样会在内核调试阶段加入debug信息。
make # 一般要编译很长时间,少则20分钟多则数小时
有的系统可能出现: curses.h: No such file or directory 这个错误,这个是因为本机开启menuconfig界面时,需要creses字符库的支持,所以只需要在本机上安装库就可以了,我使用的是Ubuntu10.04,安装命令为: apt-get install libncurses5-dev
2.制作文件系统
# 制作根文件系统
mkdir rootfs
git clone https://github.com/mengning/menu.git
cd menu
gcc -o init linktable.c menu.c test.c -m32 -static –lpthread
cd ../rootfs
cp ../menu/init ./
find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img
3.运行内核
qemu -kernel linux-3.18.28/arch/x86/boot/bzImage -initrd rootfs.img
这时可以看到运行起来的menuos界面,并且通过 help命令可以查看支持的其他命令。
![](/attachment/201603/13/29798130_14578751202J2h.png)
![](/attachment/201603/13/29798130_1457875183vz7T.png)
4.使用vim搭建代码阅读环境,这个可以参考其他文档资料,我使用的是ctag+vim,参考来源为: http://blog.chinaunix.net/uid-22891435-id-380187.html
二.使用gdb跟踪内核代码
1.内核启动时的参数:
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S # 关于-s和-S选项的说明:
# -S freeze CPU at startup (use ’c’ to start execution)冻结cpu
# -s shorthand for -gdb tcp::1234 若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项
2.gdb启动参数:
gdb
(gdb)file linux-3.18.6/vmlinux # 在gdb界面中targe remote之前加载符号表
(gdb)target remote:1234 # 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行
(gdb)break start_kernel # 断点的设置可以在target remote之前,也可以在之后
运行起来的效果图就如上面,区别在于,我们可以通过gdb添加断点来调试内核,跟踪内核的启动流程。
a.我们添加第一个断点:
在gdb中输入如下:break start_kernel #break也可以使用单个字符 b 来代替
然后 输入 continue #continue 可以使用 单个字符 c 来代替
进入如下打印片段,这是qemu已经进入了内核启动的开始阶段。
点击(此处)折叠或打开
- Breakpoint 1, start_kernel () at init/main.c:501
- 501 {
- (gdb)
点击(此处)折叠或打开
- void set_task_stack_end_magic(struct task_struct *tsk) //这个表示对任务列表进行初始化
- {
- unsigned long *stackend;
-
- stackend = end_of_stack(tsk);
- *stackend = STACK_END_MAGIC; /* for overflow detection */
- }
点击(此处)折叠或打开
- set_task_stack_end_magic(&init_task); //对task进行初始化
点击(此处)折叠或打开
- void __init trap_init(void); //完成硬件中断初始化
- mm_init(); //内存管理初始化
- /*
* Set up the scheduler prior starting any interrupts (such as the
* timer interrupt). Full topology setup happens at smp_init()
* time - but meanwhile we still have a functioning scheduler.
*/
sched_init(); //如上所述,完成进程调度管理的初始化 - init_IRQ(); //初始化中断处理
- /*
-
- 从rest_init开始,Linux开始产生进程,因为init_task是静态制造出来的,pid=0,它试图将从最早的汇编代码一直到start_kernel的执行都纳入到init_task进程上下文中。在rest_init函数中,内核将通过下面的代码产生第一个真正的进程(pid=1):
- */
- rest_init();
作者程大鹏, 转载请注明出处 http://blog.chinaunix.net/blog/post.html
Linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 ”