Linux内核分析实验三

----------------------------------------------------------------------------------------------------------------

刘旸 + 原创作品转载请注明出处 

《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 

-----------------------------------------------------------------------------------------------------------------


Linux内核分析实验三

 

知识储备:

gdb 是一个用来调试CC++程序的调试器。下面列出一些常用的命令:

break funtion
break line-number

在指定的函数,或者行号处设置断点。

watch condition

当条件满足时设置观察点。

clear
clear func
clear nth

清除函数func处的断点。
清除第nth行处的断点。

delete
d

删除所有的断点或观察点。

delete breakpoint-number
delete range

删除指定的断点,观察点。

step
s
step number-of-steps-to-perform

进入下一行代码的执行,会进入函数内部。

next
n
next number

执行下一行代码。但不会进入函数内部。

stepi
si
nexti
ni

执行下一条汇编/CPU指令。

backtrace
bt
bt inner-function-nesting-depth
bt -outer-function-nesting-depth

显示当前堆栈的追踪,当前所在的函数。

list
l
list line-number
list function
list -
list start#,end#
list filename:function

列出相应的源代码。

print variable
variable
file::variable
p 'file'::variable

打印指定变量的值。

p *array-var@length

打印arrary-var中的前length项。

p/x var

以十六进制打印整数变量var

p/d var

把变量var当作有符号整数打印。

p/u var

把变量var作为无符号整数打印。

p/o var

把变量var作为八进制数打印。

p/t var
x/b address
x/b &variable

以整数二进制的形式打印var变量的值。

p/c variable

当字符打印。

p/f variable

以浮点数格式打印变量var

p/a variable

打印十六进制形式的地址。

x/w address
x/4b &variable

打印指定的地址,以四字节一组的方式。

file file

file当作调试的程序。如果没指定参数,丢弃。

run
r
run command-line-arguments
run < infile > outfile

从头开始执行程序,也允许进行重定向。

continue
c

继续执行直到下一个断点或观察点。

continue number

继续执行,但会忽略当前的断点number次。当断点在循环中时非常有用。

quit
q

退出 GDB 调试器。

 

了解了gdb工具我们要研究内核的启动过程就比较方便了

首先打开终端模拟器定位到LinuxKernel文件夹,然后输入以下命令:

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img

命令执行的结果是打开了一个内核程序MenuOS,效果如下:

 


下面我们用gdb命令跟踪调试该内核程序

首先将刚刚运行的程序关闭

然后在命令框中输入下面的命令

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S

其中,-S 表示在该程序开始运行时冻结该程序, -s 表示采用gdb的默认号1234建立连接。

命令执行效果如下:

 


分割出一个新的命令框,输入gdb -q进入gdb调试模式

 


定位并打开需要调试的程序,加载符号表

file linux-3.18.6/vmlinux 

 


建立gdbgdbserver之间的连接

target remote:1234

 


设置断点

b start_kernel=break start_kernel

 


让程序继续运行到断点位置

c(即continue

 

查看断点附近及之后的代码

list(或ls


反复使用break命令设置断点并使用list直到看完所有代码

 

跟踪结果分析:

init进程是Linux操作系统下第一个用户态进程,init进程是从start_kernel函数中开始执行的,start_kernel不仅仅完成了内核初始化还启动了init进程。

start_kernel函数开始进一步设置了init_task,并且进行了一系列的初始化操作(中断处理初始化,内存管理初始化等)。init_task其实就是一个task_struct,与用户进程的task_struct一样,task_struct中保存了一个进程的所有基本信息,如进程状态,栈起始地址,进程号pid等。而init_taskpid就是0,也就是说在之前的初始化工作中由内核创建并初始化了init_task,这个进程只在内核中出现,它也就是所谓的0号进程。

那么init进程呢?那就得分析另一个函数rest_initrest_init下有一个kernel_thread函数,它本质上是调用了do_fork来创建一个进程,其第一个参数是一个函数指针,也就是说内核此时fork出了一个新进程来执行kernel_init函数,kernel_init函数则正式启动了init进程。

rest_init函数在启动完init进程后并没有退出,而是继续往下执行道了cpu_startup_entry函数,其实就是进入了一个无限循环,也就是说原执行流在forkinit进程后,把自己变成了idle进程。

最后用一张图简单描述一下init进程和idle进程的启动流程:

 

 

 

 

 

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值