不看linux内核实在没有学习linux的必要,最近又开始看《Linux内核完全注释》,现在开始看比以前感觉好多了,一些以前难以明白的问题现在也不是什么问题。有人说时间可以解决很多问题,以前不懂,现在终于明白了。下面是我参考别人写的文章,自己照着上面在Ubuntu9.04上做了下,一切顺利。好了,废话少说!
******************************************************************************
搭建linux-0.11(0.95)源代码的阅读、编译、运行和调试环境*******************************************************************************
这里将详细介绍如何在ubuntu 8.04下阅读、编译、运行和调试linux-0.11(0.95)。选择ubuntu 8.04的理由很简单:开放源代码,可免费获得,使用方便……
该阅读笔记主要参考《Linux内核完全注释》的第14章。
1、搭建阅读环境
首先需要安装ubuntu 8.04,关于该linux发行版的安装和使用办法,建议到ubuntu
china的官方[1]转一转。安装好ubuntu
8.04以后,基本的工具都有了。不过为了能够更好地阅读源代码,还是建议确保把vim,cscope,ctags等工具都安装上了,vim是一款“古典
”而又有“超级牛力”的编辑器,cscope和ctags是两款非常友善的代码阅读辅助工具,在ubuntu 8.04下,都可以直接结合vim使用。
$ sudo apt-get install vim cscope exuberant-ctags
|
关于vim, cscope, ctags的用法,由于时间关系,这里不便详细介绍,请分别参考资料[2],[3],[4]。
2、搭建编译环境
在ubuntu下,安装C语言开发环境(主要是gnu的一些Toolchains)还是蛮简单的,直接把build-essential这个虚拟包安装上即可。
$ sudo apt-get install build-essential
|
不过上述软件包中并未包含as86和ld86,这两个工具用于编译和链接linux-0.11的boot目录下汇编语言文件bootsect.s和
setup.s,它们采用as86汇编语法,而linux-0.11下的其他汇编语言文件采用gas的语法(AT&T),所以我们还需要单独安装
包含as86和ld86的软件包bin86。
// 查找as86和ld86两个工具所在的软件包 $ apt-cache search as86 ld86 bin86 - 16-bit x86 assembler and loader // 安装该软件包 $ apt-get install bin86
|
如果想把相关的文档也安装上,请参考资料[5]。
不过需要特别注意的是:默认安装的gcc版本是4.0以上,而这些版本可能引入了一些新的特性,在使用时总会遇到一些问题,因此在后续的所有实验中我们将采用更早的一个版本,即gcc 3.4版。下面把gcc-3.4版安装上,并把gcc文件链接到该版本。
$ sudo apt-get install gcc-3.4 $ which gcc-3.4 gcc /usr/bin/gcc-3.4 /usr/bin/gcc $ sudo ln -sf /usr/bin/gcc-3.4 /usr/bin/gcc $ gcc --version | sed -n -e "1p" gcc (GCC) 3.4.6 (Ubuntu 3.4.6-6ubuntu5)
|
这个环境搭建好以后就可以编译linux-0.11的源代码了,不过如果想在ubuntu
8.04下直接编译它,还得打上赵老师提供的补丁,不过赵老师提供的补丁在redhat 9.0下实验通过,而在ubuntu
8.04下则不能直接使用,所以经过实验,我重新做了一个linux-0.11在ubuntu
8.04下能正常编译通过的补丁,即附件中的linux-0.11-080529-ubuntu8.04.patch。
下面介绍具体的编译过程。
// 下载linux-0.11的源代码并解压 $ wget -c $ tar zxf linux-0.11-080529-ubuntu8.04.patch.tar.gz $ tar zxf linux-0.11.tar.gz // 打上linux-0.11-080529-ubuntu8.04.patch补丁 $ cd linux-0.11 $ patch -p1 < ../linux-0.11-080529-ubuntu8.04.patch // 确保gcc-3.4版已经安装上(为确保使用gcc的3.4版,该补丁已经直接在所有Makefile文件中指定CC为gcc-3.4了) $ which gcc-3.4 /usr/bin/gcc-3.4 // 编译 $ make // 正常情况下,你应该可以看到两个新的文件Image和System.map已经生成了 $ ls boot fs Image include init kernel lib Makefile mm System.map tools
|
Image文件就是我们编译后的linux-0.11内核,如何使用它呢?下面一节将进行介绍。
这里简单介绍一下补丁的内容,补丁是在赵老师提供的linux-0.11-040327-rh9.tar.gz文件的基础上修改的,具体修改的地方,大家可以从附件linux-0.11-080529-rh9-to-ubuntu8.04.patch看到。
如果想直接编译最原始的linux-0.11源代码呢?书中介绍了一个sls-0.99pl系统,可以从bochs的官方站点[6]下载到,通过
bochs把该系统启动后就可以用来编译linus当初(1991年,想一想都是17年前的事情了,光阴似箭阿!)写的linux-0.11的源代码。原
书已经详细介绍了使用方法,这里不再深入介绍。
注:上面忘记提到我的实验
机器的处理器类型为(AMD
Athlon(tm)),因为linux-0.11是为x86写的,所以如果想直接在自己的主机上编译和运行它,请确保你的处理器与x86兼容,比如
Intel或者是AMD产的处理器。否则,你得构建目标处理器架构(--target)为x86的交叉编译器并用qemu等仿真器来构建一个x86的实验
环境。
3、搭建运行环境
考虑到实验的方便,这里不直接在真实的硬件上运行编译好的linux-0.11内核,而是用bochs这个“虚拟机”来跑。bochs是一个仿真器,能够仿真x86的硬件环境。在ubuntu 8.04下可以直接安装它,这里把一些相关的文档和工具都安装上。
$ sudo apt-get install bochs vgabios bochs-x bochsbios bochs-doc
|
这样一个“虚拟”的机器就免费“买”来了,下面介绍如何通过它来运行linux-0.11内核。
在上一节中我们已经编译好了linux-0.11的内核,不过为了能够完整地运行它,我们还得为它提供一个文件系统,这个文件系统主要提供各种相关的工具,其中包括用户和内核交互的接口——shell。
为了简单起见,这里直接采用赵老师提供的linux-0.11-devel-060625.zip文件中的hdc-0.11-new.img硬盘映像文件作为我们的文件系统。这里先下载该文件。
现在我们有了linux-0.11的内核和相应的文件系统以及运行它的bochs“虚拟机”,这样就可以运行该内核了。不过运行内核之前需要通过一个文件
作一些配置。配置的目的主要是为了告知“虚拟机”我们想从什么位置加载linux-0.11的内核和文件系统。这里是一份配置文件,命名为
bochsrc-hd.bxrc(见附件)。
首先先确保如下两个配置正确。第一行告知bochs要从第一个软盘floppya加载内核,这里通过linux-0.11目录下的虚拟软盘映像文件
Image指定;第二行告知bochs要从第一个硬盘加载文件系统,它通过./linux-0.11-devel-060625/hdc-0.11-
new.img磁盘映像文件指定。
floppya: 1_44="./linux-0.11/Image", status=inserted
ata0-master: type=disk, path="./linux-0.11-devel-060625/hdc-0.11-new.img", mode=flat, cylinders=410, heads=16, spt=38
|
需要补充的是:linux-0.11内核自身也需要知道文件系统所在位置,否则内核加载以后将不知道从哪里启动根文件系统。而这个位置通过linux-0.11/tools/build.c文件中的如下两行指定:
#define DEFAULT_MAJOR_ROOT 3 #define DEFAULT_MINOR_ROOT 1
|
这两行实际上对应编译过后的Image文件中的第509、510个字节,它告知linux-0.11内核从哪里加载文件系统。
$ hexdump -s 508 -n 2 linux-0.11/Image 00001fc 0301 00001fe
|
0301表示第一个硬盘的第一个分区,刚好对应ata0-master。如果需要从不同的位置加载文件系统,请参考原书的第14章的“根文件系统和根文件
设备"一节,调整源代码中DEFAULT_MAJOR_ROOT和DEFAULT_MINOR_ROOT或者是在编译好linux-0.11内核后,直接
通过二进制编辑器hexedit修改Image文件中的第509和510个字节处的内容。
关于bochs配置文件的更多细节,也请参考原书,或者直接查看"man bochsrc"。
现在,我们可以通过下面的命令运行linux-0.11的内核了,其中-f参数用于指定配置文件bochsrc-hd.bxrc。
$ bochs -f bochsrc-hd.bxrc
|
4、搭建调试环境
在linux下,如果编译bochs之前带上了--enable-gdb-stub参数进行配置,那么就可以把gdbstub编译进bochs。
gdbstub可以使得bochs程序在本地指定网络端口侦听接收gdb的命令,它的工作原理跟gdbserver类似,是一个调试服务器。当启动该
gdbstub后,我们可以通过gdb和它进行通信,协同调试linux内核。不过在调试之前,需要修改linux
0.11的编译参数,确保产生一个带有调试信息的内核文件。
下面介绍大概的步骤。
4.1 重新编译linux-0.11的内核
编译之前需要修改所有Makefile文件,确保去除LDFLAGS中的-s参数,并在CFLAGS中添加-g参数,这样就可以让最终产生的内核文件中带
有调试信息,以便用gdb来调试它。不过,因为通过bochs运行的内核映像文件的大小受到boot/bootsect.s文件中SYSSIZE大小的限
制(可以考虑直接增加SYSSIZE的大小),所以可以考虑生成两份内核映像文件,一份用于bochs加载;一份用于gdb来调试,因此linux-
0.11主目录下的Makefile文件还需要进行修改。为了方便,我把这些修改都放到了附件linux-0.11-080529-
ubuntu8.04-dbg.patch。
这里重新编译内核:
// 从附件中下载linux-0.11-080529-ubuntu8.04-dbg.patch.tar.gz并解压 $ tar zxf linux-0.11-080529-ubuntu8.04-dbg.patch.tar.gz // 进入打过补丁linux-0.11-080529-ubuntu8.04.patch的linux-0.11 $ cd linux-0.11 // 打上用于 编译产生带有调试信息内核 的补丁 $ patch -p1 < ../linux-0.11-080529-ubuntu8.04-dbg.patch // 重新编译 $ make clean $ make
|
编译好以后得到一个不带调试信息的Image文件和一个带调试信息的tools/system文件,前者用于bochs启动,而后者用于gdb调试。
4.2 重新编译bochs确保编译进gdbstub,并确保已经安装了gdb
貌似ubuntu 8.04下默认安装的bochs没有编译进gdbstub,所以重新编译一个。从资料[6]下载最新版的bochs,解压、编译。
// 下载并解压 $ wget -c $ tar zxf bochs-20080527.tar.gz // 配置和编译,配置时记得加上--enable-gdb-stub以及--enable-plugins和 --enable-disasm $ cd ./bochs-20080527 $ ./configure
--enable-plugins --enable-disasm --enable-gdb-stub $ make
|
如果配置时提示缺少X window libraries, 那么请把xorg-dev这个包安装上看看,如果还不行,把xserver-xorg-dev这个包也安装上。
编译好带有gdbstub的bochs后,需要确保已经安装了gdb。
$ sudo apt-get install gdb
|
4.3 调试
调试时,需要调整bochs的配置文件,以便告知bochs,让它在启动linux-0.11内核时在指定端口开启gdbstub,并暂停在linux-0.11内核的开头,等待用户开启gdb调试器对它发起连接。
在原配置文件的开头添加如下一行,并命名为bochsrc-hd-dbg.bxrc:
gdbstub: enabled=1, port=1234, text_base=0, data_base=0, bss_base=0
|
上面一行中的“port=1234”指定gdbstub的端口。你可以设置为任意一个当前没有没有被占用的端口。
另外,请把如下一行删除或者注册掉,因为最新版本的bochs貌似不支持这个标记。
floppy_command_delay: 50000
|
下面,先开启一个终端根据新的配置文件,用bochs启动linux-0.11内核。
// 自己注意一下编译后的bochs的路径以及bochsrc-hd-dbg.bxrc文件的路径 $ ./bochs-20080527/bochs -f bochsrc-hd-dbg.bxrc ... Waiting for gdb connection on port 1234
|
正常bochs启动后,根据提示按下数字6,即可看到最后一行信息:bochs等待用户开启gdb调试器客户端对它发起连接。下面,另开一个终端运行gdb。
// 用gdb启动编译好的带有调试信息的内核文件:tools/system $ gdb linux-0.11/tools/system ... (gdb) break main (gdb) target remote localhost:1234 //连接bochs开启的gdbstub的1234端口开始调试 (gdb) c // 这里不要直接单步,先执行到内核部分再说(因为开头有一部分是引导部分),详细原因见资料[14]的后面部分。 (gdb) si // 单步调试(指令级别的),后续用法参考gdb首页就okay了
|
关于使用bochs和gdb调试内核的方法,你还可以参考一下资料[13]。
到这里为止,相应的环境就搭建完毕了。
下面再列出几则资料,生成补丁和打补丁的工具diff和patch的用法见资料[7],gdb以及gdb远程调试的用法见资料[8]。
补充和更新:
1、在64位的ubuntu/debian上编译linux-0.11(update: 2008-09-24)
之前介绍的是在32位的Intel或者amd的机器上编译linux-0.11的方法,没有介绍64位的,这里新增了一个补丁linux-0.11-
080924-debian-amd64.patch,把该补丁打到最原始的linux-0.11的源代码上,我们就可以在64位的Intel或者amd
的机器上编译它了。关于补丁的细节,大家可以阅读一下资料[9,15]。
2、在bochs-2.3中遇到HD controller not ready而无法启动的问题(update: 2008-10-27)
请参考网友在3#的回复,这里对该网友表示感谢。
3、如何使用另外一个虚拟机qemu(update: 2008-10-27)
3.1 引导linux-0.11,就这么简单,比bochs简单得多
$ qemu -m 16 -boot a -fda linux-0.11/Image -hda rootfs/hdc-0.11-new.img
|
注意:在qemu中也需要参考网友在3#的回复,修改kernel/blk_drv/hd.c中的代码,否则,也会提示相同的错误而无法引导linux-0.11。
3.2 调试linux-0.11
启动的时候,可以用图形的方式,也可以用非图形的方式,例如,这里用后者:
$ qemu -boot a -fda linux-0.11/Image -hda rootfs/hdc-0.11-new.img -s -S -nographic -serial '/dev/ttyS0'
|
qemu貌似直接开始在1234端口监听,然后类似原blog的方法用gdb来连接该端口以便对linux-0.11进行调试。
注意:有些版本的qemu还需要添加-no-kqemu,如果没有安装qemu的加速器的话。另外,关于使用qemu调试内核你还可以参考资料[10,11,12]。
4、把linux-0.11移植到最新的gcc 4.3.2中(update: 2008-10-30)
你可以从资料[14]的附件下载该代码,或者从这里下载该代码对应的完整的实验环境:
关于移植的细节,请并参考资料[14],并直接对比分析源代码,其实修改的部分非常少。不过我对大部分的Makefile文件进行了调整。
5、发布同时支持gcc 3.4, 4.1, 4.2, 4.3的linux-0.11(update: 2008-10-30)
请直接从下载,包括纯源代码部分 linux-0.11-081030.tar.gz和完整的实验环境部分linux-0.11-dev-081030.tar.gz
搭建linux-0.11(0.95)源代码的阅读、编译、运行和调试环境
(上接 "《Linux内核完全注释》阅读笔记——资料准备")
这里将详细介绍如何在ubuntu 8.04下阅读、编译、运行和调试linux-0.11(0.95)。选择ubuntu 8.04的理由很简单:开放源代码,可免费获得,使用方便……
该阅读笔记主要参考《Linux内核完全注释》的第14章。
1、搭建阅读环境
首先需要安装ubuntu 8.04,关于该linux发行版的安装和使用办法,建议到ubuntu
china的官方[1]转一转。安装好ubuntu
8.04以后,基本的工具都有了。不过为了能够更好地阅读源代码,还是建议确保把vim,cscope,ctags等工具都安装上了,vim是一款“古典
”而又有“超级牛力”的编辑器,cscope和ctags是两款非常友善的代码阅读辅助工具,在ubuntu 8.04下,都可以直接结合vim使用。
$ sudo apt-get install vim cscope exuberant-ctags
|
关于vim, cscope, ctags的用法,由于时间关系,这里不便详细介绍,请分别参考资料[2],[3],[4]。
2、搭建编译环境
在ubuntu下,安装C语言开发环境(主要是gnu的一些Toolchains)还是蛮简单的,直接把build-essential这个虚拟包安装上即可。
$ sudo apt-get install build-essential
|
不过上述软件包中并未包含as86和ld86,这两个工具用于编译和链接linux-0.11的boot目录下汇编语言文件bootsect.s和
setup.s,它们采用as86汇编语法,而linux-0.11下的其他汇编语言文件采用gas的语法(AT&T),所以我们还需要单独安装
包含as86和ld86的软件包bin86。
// 查找as86和ld86两个工具所在的软件包 $ apt-cache search as86 ld86 bin86 - 16-bit x86 assembler and loader // 安装该软件包 $ apt-get install bin86
|
如果想把相关的文档也安装上,请参考资料[5]。
不过需要特别注意的是:默认安装的gcc版本是4.0以上,而这些版本可能引入了一些新的特性,在使用时总会遇到一些问题,因此在后续的所有实验中我们将采用更早的一个版本,即gcc 3.4版。下面把gcc-3.4版安装上,并把gcc文件链接到该版本。
$ sudo apt-get install gcc-3.4 $ which gcc-3.4 gcc /usr/bin/gcc-3.4 /usr/bin/gcc $ sudo ln -sf /usr/bin/gcc-3.4 /usr/bin/gcc $ gcc --version | sed -n -e "1p" gcc (GCC) 3.4.6 (Ubuntu 3.4.6-6ubuntu5)
|
这个环境搭建好以后就可以编译linux-0.11的源代码了,不过如果想在ubuntu
8.04下直接编译它,还得打上赵老师提供的补丁,不过赵老师提供的补丁在redhat 9.0下实验通过,而在ubuntu
8.04下则不能直接使用,所以经过实验,我重新做了一个linux-0.11在ubuntu
8.04下能正常编译通过的补丁,即附件中的linux-0.11-080529-ubuntu8.04.patch。
下面介绍具体的编译过程。
// 下载linux-0.11的源代码并解压 $ wget -c $ tar zxf linux-0.11-080529-ubuntu8.04.patch.tar.gz $ tar zxf linux-0.11.tar.gz // 打上linux-0.11-080529-ubuntu8.04.patch补丁 $ cd linux-0.11 $ patch -p1 < ../linux-0.11-080529-ubuntu8.04.patch // 确保gcc-3.4版已经安装上(为确保使用gcc的3.4版,该补丁已经直接在所有Makefile文件中指定CC为gcc-3.4了) $ which gcc-3.4 /usr/bin/gcc-3.4 // 编译 $ make // 正常情况下,你应该可以看到两个新的文件Image和System.map已经生成了 $ ls boot fs Image include init kernel lib Makefile mm System.map tools
|
Image文件就是我们编译后的linux-0.11内核,如何使用它呢?下面一节将进行介绍。
这里简单介绍一下补丁的内容,补丁是在赵老师提供的linux-0.11-040327-rh9.tar.gz文件的基础上修改的,具体修改的地方,大家可以从附件linux-0.11-080529-rh9-to-ubuntu8.04.patch看到。
如果想直接编译最原始的linux-0.11源代码呢?书中介绍了一个sls-0.99pl系统,可以从bochs的官方站点[6]下载到,通过
bochs把该系统启动后就可以用来编译linus当初(1991年,想一想都是17年前的事情了,光阴似箭阿!)写的linux-0.11的源代码。原
书已经详细介绍了使用方法,这里不再深入介绍。
注:上面忘记提到我的实验
机器的处理器类型为(AMD
Athlon(tm)),因为linux-0.11是为x86写的,所以如果想直接在自己的主机上编译和运行它,请确保你的处理器与x86兼容,比如
Intel或者是AMD产的处理器。否则,你得构建目标处理器架构(--target)为x86的交叉编译器并用qemu等仿真器来构建一个x86的实验
环境。
3、搭建运行环境
考虑到实验的方便,这里不直接在真实的硬件上运行编译好的linux-0.11内核,而是用bochs这个“虚拟机”来跑。bochs是一个仿真器,能够仿真x86的硬件环境。在ubuntu 8.04下可以直接安装它,这里把一些相关的文档和工具都安装上。
$ sudo apt-get install bochs vgabios bochs-x bochsbios bochs-doc
|
这样一个“虚拟”的机器就免费“买”来了,下面介绍如何通过它来运行linux-0.11内核。
在上一节中我们已经编译好了linux-0.11的内核,不过为了能够完整地运行它,我们还得为它提供一个文件系统,这个文件系统主要提供各种相关的工具,其中包括用户和内核交互的接口——shell。
为了简单起见,这里直接采用赵老师提供的linux-0.11-devel-060625.zip文件中的hdc-0.11-new.img硬盘映像文件作为我们的文件系统。这里先下载该文件。
现在我们有了linux-0.11的内核和相应的文件系统以及运行它的bochs“虚拟机”,这样就可以运行该内核了。不过运行内核之前需要通过一个文件
作一些配置。配置的目的主要是为了告知“虚拟机”我们想从什么位置加载linux-0.11的内核和文件系统。这里是一份配置文件,命名为
bochsrc-hd.bxrc(见附件)。
首先先确保如下两个配置正确。第一行告知bochs要从第一个软盘floppya加载内核,这里通过linux-0.11目录下的虚拟软盘映像文件
Image指定;第二行告知bochs要从第一个硬盘加载文件系统,它通过./linux-0.11-devel-060625/hdc-0.11-
new.img磁盘映像文件指定。
floppya: 1_44="./linux-0.11/Image", status=inserted
ata0-master: type=disk, path="./linux-0.11-devel-060625/hdc-0.11-new.img", mode=flat, cylinders=410, heads=16, spt=38
|
需要补充的是:linux-0.11内核自身也需要知道文件系统所在位置,否则内核加载以后将不知道从哪里启动根文件系统。而这个位置通过linux-0.11/tools/build.c文件中的如下两行指定:
#define DEFAULT_MAJOR_ROOT 3 #define DEFAULT_MINOR_ROOT 1
|
这两行实际上对应编译过后的Image文件中的第509、510个字节,它告知linux-0.11内核从哪里加载文件系统。
$ hexdump -s 508 -n 2 linux-0.11/Image 00001fc 0301 00001fe
|
0301表示第一个硬盘的第一个分区,刚好对应ata0-master。如果需要从不同的位置加载文件系统,请参考原书的第14章的“根文件系统和根文件
设备"一节,调整源代码中DEFAULT_MAJOR_ROOT和DEFAULT_MINOR_ROOT或者是在编译好linux-0.11内核后,直接
通过二进制编辑器hexedit修改Image文件中的第509和510个字节处的内容。
关于bochs配置文件的更多细节,也请参考原书,或者直接查看"man bochsrc"。
现在,我们可以通过下面的命令运行linux-0.11的内核了,其中-f参数用于指定配置文件bochsrc-hd.bxrc。
$ bochs -f bochsrc-hd.bxrc
|
4、搭建调试环境
在linux下,如果编译bochs之前带上了--enable-gdb-stub参数进行配置,那么就可以把gdbstub编译进bochs。
gdbstub可以使得bochs程序在本地指定网络端口侦听接收gdb的命令,它的工作原理跟gdbserver类似,是一个调试服务器。当启动该
gdbstub后,我们可以通过gdb和它进行通信,协同调试linux内核。不过在调试之前,需要修改linux
0.11的编译参数,确保产生一个带有调试信息的内核文件。
下面介绍大概的步骤。
4.1 重新编译linux-0.11的内核
编译之前需要修改所有Makefile文件,确保去除LDFLAGS中的-s参数,并在CFLAGS中添加-g参数,这样就可以让最终产生的内核文件中带
有调试信息,以便用gdb来调试它。不过,因为通过bochs运行的内核映像文件的大小受到boot/bootsect.s文件中SYSSIZE大小的限
制(可以考虑直接增加SYSSIZE的大小),所以可以考虑生成两份内核映像文件,一份用于bochs加载;一份用于gdb来调试,因此linux-
0.11主目录下的Makefile文件还需要进行修改。为了方便,我把这些修改都放到了附件linux-0.11-080529-
ubuntu8.04-dbg.patch。
这里重新编译内核:
// 从附件中下载linux-0.11-080529-ubuntu8.04-dbg.patch.tar.gz并解压 $ tar zxf linux-0.11-080529-ubuntu8.04-dbg.patch.tar.gz // 进入打过补丁linux-0.11-080529-ubuntu8.04.patch的linux-0.11 $ cd linux-0.11 // 打上用于 编译产生带有调试信息内核 的补丁 $ patch -p1 < ../linux-0.11-080529-ubuntu8.04-dbg.patch // 重新编译 $ make clean $ make
|
编译好以后得到一个不带调试信息的Image文件和一个带调试信息的tools/system文件,前者用于bochs启动,而后者用于gdb调试。
4.2 重新编译bochs确保编译进gdbstub,并确保已经安装了gdb
貌似ubuntu 8.04下默认安装的bochs没有编译进gdbstub,所以重新编译一个。从资料[6]下载最新版的bochs,解压、编译。
// 下载并解压 $ wget -c $ tar zxf bochs-20080527.tar.gz // 配置和编译,配置时记得加上--enable-gdb-stub以及--enable-plugins和 --enable-disasm $ cd ./bochs-20080527 $ ./configure
--enable-plugins --enable-disasm --enable-gdb-stub $ make
|
如果配置时提示缺少X window libraries, 那么请把xorg-dev这个包安装上看看,如果还不行,把xserver-xorg-dev这个包也安装上。
编译好带有gdbstub的bochs后,需要确保已经安装了gdb。
$ sudo apt-get install gdb
|
4.3 调试
调试时,需要调整bochs的配置文件,以便告知bochs,让它在启动linux-0.11内核时在指定端口开启gdbstub,并暂停在linux-0.11内核的开头,等待用户开启gdb调试器对它发起连接。
在原配置文件的开头添加如下一行,并命名为bochsrc-hd-dbg.bxrc:
gdbstub: enabled=1, port=1234, text_base=0, data_base=0, bss_base=0
|
上面一行中的“port=1234”指定gdbstub的端口。你可以设置为任意一个当前没有没有被占用的端口。
另外,请把如下一行删除或者注册掉,因为最新版本的bochs貌似不支持这个标记。
floppy_command_delay: 50000
|
下面,先开启一个终端根据新的配置文件,用bochs启动linux-0.11内核。
// 自己注意一下编译后的bochs的路径以及bochsrc-hd-dbg.bxrc文件的路径 $ ./bochs-20080527/bochs -f bochsrc-hd-dbg.bxrc ... Waiting for gdb connection on port 1234
|
正常bochs启动后,根据提示按下数字6,即可看到最后一行信息:bochs等待用户开启gdb调试器客户端对它发起连接。下面,另开一个终端运行gdb。
// 用gdb启动编译好的带有调试信息的内核文件:tools/system $ gdb linux-0.11/tools/system ... (gdb) break main (gdb) target remote localhost:1234 //连接bochs开启的gdbstub的1234端口开始调试 (gdb) c // 这里不要直接单步,先执行到内核部分再说(因为开头有一部分是引导部分),详细原因见资料[14]的后面部分。 (gdb) si // 单步调试(指令级别的),后续用法参考gdb首页就okay了
|
关于使用bochs和gdb调试内核的方法,你还可以参考一下资料[13]。
到这里为止,相应的环境就搭建完毕了。
下面再列出几则资料,生成补丁和打补丁的工具diff和patch的用法见资料[7],gdb以及gdb远程调试的用法见资料[8]。
补充和更新:
1、在64位的ubuntu/debian上编译linux-0.11(update: 2008-09-24)
之前介绍的是在32位的Intel或者amd的机器上编译linux-0.11的方法,没有介绍64位的,这里新增了一个补丁linux-0.11-
080924-debian-amd64.patch,把该补丁打到最原始的linux-0.11的源代码上,我们就可以在64位的Intel或者amd
的机器上编译它了。关于补丁的细节,大家可以阅读一下资料[9,15]。
2、在bochs-2.3中遇到HD controller not ready而无法启动的问题(update: 2008-10-27)
请参考网友在3#的回复,这里对该网友表示感谢。
3、如何使用另外一个虚拟机qemu(update: 2008-10-27)
3.1 引导linux-0.11,就这么简单,比bochs简单得多
$ qemu -m 16 -boot a -fda linux-0.11/Image -hda rootfs/hdc-0.11-new.img
|
注意:在qemu中也需要参考网友在3#的回复,修改kernel/blk_drv/hd.c中的代码,否则,也会提示相同的错误而无法引导linux-0.11。
3.2 调试linux-0.11
启动的时候,可以用图形的方式,也可以用非图形的方式,例如,这里用后者:
$ qemu -boot a -fda linux-0.11/Image -hda rootfs/hdc-0.11-new.img -s -S -nographic -serial '/dev/ttyS0'
|
qemu貌似直接开始在1234端口监听,然后类似原blog的方法用gdb来连接该端口以便对linux-0.11进行调试。
注意:有些版本的qemu还需要添加-no-kqemu,如果没有安装qemu的加速器的话。另外,关于使用qemu调试内核你还可以参考资料[10,11,12]。
4、把linux-0.11移植到最新的gcc 4.3.2中(update: 2008-10-30)
你可以从资料[14]的附件下载该代码,或者从这里下载该代码对应的完整的实验环境:
关于移植的细节,请并参考资料[14],并直接对比分析源代码,其实修改的部分非常少。不过我对大部分的Makefile文件进行了调整。
5、发布同时支持gcc 3.4, 4.1, 4.2, 4.3的linux-0.11(update: 2008-10-30)
请直接从下载,包括纯源代码部分 linux-0.11-081030.tar.gz和完整的实验环境部分linux-0.11-dev-081030.tar.gz