开篇
现在流行的开源项目经历了长时间的开发, 积累了大量的代码, 想要一行一行地阅读代码去学习开源项目, 需要的时间成本是巨大的. 所以, 我们也需要用一种高效的方式去"阅读"代码. 计算机科学发展到现在, 产生了很多高效成熟的工具, 调试器就是其中之一(扯句题外话, 那些大牛程序员似乎就是喜欢琢磨怎么制造各种工具哈), 调试器能够帮程序员定位代码的bug, 理解代码的运行机制. 这篇文章总结了如何搭建一个调试linux内核源码的开发环境, 并简单介绍了一些调试器的实现原理.
问题1
调试内核和调试用户态程序有什么区别?
问题2
使用qemu调试内核, 原理是什么?
问题3
如何搭建调试linux内核源码的开发环境?
回答1
我们把讨论限定在使用c语言写的程序上, 一个程序想在linux运行, 大致会经过下面几个步骤:
- 你首先会编译源代码得到一个ELF文件, 这个文件中包含了用户程序的二进制指令和数据, 它具有可执行的权限;
- 接下来你在shell中运行这个ELF文件, shell会使用fork, exec等系统调用生成一个子进程去运行你的程序, 系统调用进入内核之后, 编译得到的ELF文件被用来构造这个子进程在内存中的初始状态, 内核还需要为这个进程返回用户态之后的寄存器设置合适的初始状态. 可以说, 一个进程就像一个状态机, 它的状态包括内存和寄存器的状态, 在这一步内核对这个状态机作了初始化;
- 子进程得到调度, 它从内核态返回用户态, 每执行一条指令, 伴随的是内存和寄存器状态的变化, 也就是状态机的状态转移;
以上是用户态进程的运行过程, 如果想调试一个用户态程序, 可以使用gdb工具, gdb之所以能够调试程序, 是借助了内核的帮助. 如果理解了进程是一个状态机这样的观点, 理解gdb调试程序的原理就比较容易了, 调试