1、可以看到QEMU 已经运行而且被“冻结”。(有几个文件没有,不影响后续操作)
2、另外打开一个窗口,进入linuxkernel目录,输入gdb 回车
3、输入:(gdb)file linux-3.18.6/vmlinux
(gdb)target remote:1234
(gdb)break start_kernel
4、输入c 回车,可以看到内核继续启动,最后停在了start_kernel处:
更多gdb指令:
显示和查找程序源代码
(1)list :显示10行代码,但是我为什么没有显示成功呢?
(2)list 5,10:显示源文件第五行到第十行的代码
(3)list t4.c:5,10:显示源文件中第五行到第十行的代码,在跳是含有多个源文件的次序时使用;
(4)list get_sum:显示get_sum函数周围的代码//什么叫周围的代码呢?
(5)list t4.c :get_sum:显示源文件t4.c中第五行到第十行的代码,在跳是含有多个源文件的次序时使用;
(6)如果在调试中运行linux命令,则可以在gdb的提示符下输入shell命令. (gdb)shell ls
(7)search forward用来从当前行向前查找第一个匹配的字符串;
search get_sum forward get_sum
(8)reverse_search 用来从当前行想前查找第一个匹配的字符串: Example: reverse_search main
设置和管理断点:
(1)以行号设置断点:(gdb)break 7
(2)以函数名设置断点:(gdb)break get_sum
(3)以条件表达式设置断点:方法一:break 行号或者函数名 if 条件. Example: (gdb)break 7 if i==99
方法二:watch 条件表达式,下面是具体的举例:
方法三:awatch;用来给表达式设置断点,在表达式的值发生改变或者表达式的值杯读取的时候,程序暂时停止;
(4).查看当前设置的断点:info breakpoints
(5)使用“disable 断点编号”命令可以是某个断点失效,程序运行到该段点时不会停下来而是继续运行。
(6)使用“enable 断点编号”命令可以是某个断点恢复有效。
彻底的删除某个断点,可以使用clear或者delete命令。
(1)clear:删除程序中所有的断点;
(2)clear 行号:删除此行中的断点
(3)clear 函数名:删除该函数的断点
(4)delete 断点编号:删除指定编号的断点。如果一次要删除多个断点,各个断点编号以空格隔开。
控制程序的执行:
(1)continue命令:让程序继续运行,直到下一个断点或者运行完为止。格式:continue
(2)kill命令:用于结束当前程序的调试
(3)next和step命令
区别:如果遇到函数,next会把函数调用当作一条语句来执行,再次输入next会执行函数调用后的语句;
而step则会跟踪进入函数,一次一条的执行函数内的代码,直到函数内的代码执行完,在进行函数调用后的语句;
(4)nexti和stepi命令:用来单步执行一条机器指令,注意不是单步执行一条鱼据。单步执行一条语句使用next和step命令。通常一条语句有多条机器指令构成的。
注意的是:gdb的一些命令可以简写,比如list可以用li来代替,continue命令可以用cont来代替。
5、继续输入 list start_kernel 查看start_kernel函数为中心上下10行的代码
然后接着输入list 查看后续的代码(每输入一次list,向后显示10行)
我们继续输入list跟踪start_kernel以后的代码,看看后面的执行过程:
可以看到,在start_kernel之后是一大堆的初始化操作,初始化外设、时钟、寄存器等。后面还有很多操作,这里不作过多的截图展示,
6、后面进入rest_init函数:
四、总结:
在start_kernel中调用了一系列的初始化函数,已完成内核本身的设置:设置与体系结构相关的环境、进程调度器初始化、控制台初始化、系统IRQ初始化、内存初始化等。在Start_kernel函数的最后调用了rest_init()函数,在rest_init中建立了init线程,并在最后调用cpu_idle()函数。
可以这样理解:start_kernel最后clone出一个新的进程,也就是init进程,然后原来的进程就去执行cpu_idle()函数了,也就变成了idle进程,当发生一次进程调度后,init进程被调度运行。
核心进程init()主要进行一些外设初始化的工作包括SMP(Symmetric Multi-Processing 对称多处理)的初始化,以及调用do_basic_setup()完成外设及其驱动程序的加载和初始化,当do_basic_setup()函数返回init() ,init() 又打开了、dev/console设备,重定向输出文件到控制台,最后通过kernel——execve加载执行init程序。
追踪到init后可以修改文件系统,比如把显示的MENUOS修改为MYOS,修改quit指令,让其退出文件系统等:
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img
在init/initramfs.c文件中: