• 好好学习,天天向上~
  • 欢迎欢迎~

linux学习2,五分钟学会调试内核,让操作系统打印自己的名字

linux笔记 lcc 231℃ 0评论

上一节粗略的介绍了如何下载和编译 linux 内核,可只是编译出内核没什么意思,能不能让它跑起来呢?当然可以,本节的内容就是让 linux 内核跑起来,并且在系统启动时,打印出我们的名字

qemu 模拟器

打算让“linux内核跑起来”,在什么地方跑呢?如果手边有闲置的电脑,那当然好。可是我只有一台电脑,也不想花钱买开发板,有没有办法让“linux内核跑起来”呢?当然有办法了,使用模拟器就好了。本节打算介绍的是 qemu 模拟器,它是纯软件实现的虚拟化模拟器,几乎可以模拟任何硬件设备,我们最熟悉的就是能够模拟一台能够独立运行操作系统的虚拟机,虚拟机认为自己和硬件打交道,但其实是和 qemu 模拟出来的硬件打交道,qemu 将这些指令转译给真正的硬件。正因为 qemu 是纯软件实现的,所有的指令都要经 qemu 过一手,性能会比较低,不过这个无所谓了,我们只是想用它来调试内核,并不是用来做复杂工作的。

在 ubuntu 上安装 qemu 是方便的,只需执行下面这条命令就可以了。

sudo apt-get install qemu

输入完上面的命令,按 tab 键,可以看到以下结果:

有很多种架构的模拟器,例如 qemu-system-x86 可以用来模拟 x86 架构的主机,qemu-system-arm 可以用来模拟 arm 架构的主机等等。如果不在乎存储空间,可以全部安装。也可以只安装一种架构的 qemu,我安装的是 x86 架构的:

sudo apt-get install qemu-system-x86

回车,待安装结束,输入以下命令

qemu-system-x86_64 --version


发现 qemu 输出版本信息,就说明 qemu 安装好了。

编译 linux 内核

上一节已经介绍如何下载和编译内核了,这里又编译一次是因为我们打算调试内核,因此有些配置项要勾选。而且,在这次编译过程中,我遇到了几个错误,这里再介绍下如果遇到错误,如何解决它。

头条不能留外链,如果有朋友不方便下载内核,可以在评论区留言,我可以把要用到的东西都发过去。

我们新建一个 kernel 目录,把下载好的内核 linux-2.6.26.tar.gz 放进去,然后依次执行以下命令

tar xf linux-2.6.26.tar.gz
cd linux-2.6.26
make x86_64_defconfig
make menuconfig

这几条命令依次是:解压内核源码,进入解压后的命令,按照 x86_64 的架构(因为我的 ubuntu 主机是 x86_64 位的,编写x86_64程序比较方便)默认配置内核,最后一条命令执行后,就会进入到图形配置界面,进入 Kernel hacking,选中下图中的配置,按空格勾选之:

然后就可以退出图形配置界面了,记得要保存修改后的配置:

勾选上图中配置项的目的,是希望在编译时能够保留 debug(调试)信息,方便我们后续的调试。配置完成后,就可以编译了:

make bzImage -j4

这几条命令上一节介绍的比较详细,不清楚的朋友可以再翻回去看看。

在我的 ubuntu 上,编译到这里就报错了:

提示在编译 vdso 时不识别 -m 命令,也找不到 elf_x86_64。于是去查看编译 vdso 的 Makefile:

vim arch/x86/vdso/Makefile


我们知道,编译时通常可以用 -m32 参数来说明是 32 位主机,-m64 参数用于说明是 64 位主机,这里提示找不到 elf_x86_64,我们直接将“-m elf_x86_64”修改为“-m64”试试。保存修改,继续执行 make bzImage 编译,发现不再报这个错误了。

可是,编译过程中,又报这个错误了:

提示 copy_user_generic_c 表达式的 size 不是常数,我们去源文件看看:

vim arch/x86/lib/copy_user_64.S


ENTRY和 END 不匹配,我们将之改匹配试试:将 copy_user_generic_c 改成 copy_user_generic_string,保存,继续执行 make bzImage 编译,发现不再报这个错误了。但是又继续报下面这个错误:

提示没有定义 “__mutex_lock_slowpath” 函数。这下没辙了,尝试搜索下这个函数:

grep -r __mutex_lock_slowpath


还真搜到了,我们进源码看看:

vim kernel/mutex.c

发现明明定义了这个函数,怎么还会提示没定义呢?猜测可能是 CONFIG_DEBUG_LOCK_ALLOC 宏定义搞的鬼:

我们查看以下 .config 配置文件:

vim .config


发现这个宏没有被定义,解注释,改为

CONFIG_DEBUG_LOCK_ALLOC=y

保存修改,继续编译终于不再报错了,稍后片刻,发现终于成功了:

使用 qemu 模拟运行编译出的 linux 内核

方法是简单的,只需执行以下命令即可

qemu-system-x86_64 \
-m 512M \       # 模拟内存 512M
-smp 1 \        # 模拟器有 1 个核的 cpu
-kernel arch/x86_64/boot/bzImage\       #内核位置
- curses        # 使用 curse 图形库


linux 内核的确跑起来了,但是却引发了一个“kernel panic”(内核恐慌),内核发现找不到文件系统,慌得一批。

内核虽然很恐慌,但是我们依然可以修改内核源码,让它在恐慌之前打印出我们的名字,怎么做呢?请继续看:

事实上,一般 C 语言程序都有一个入口函数(这个入口函数通常是 main 函数),linux 内核也有入口函数——start_kernel 函数,在内核源码树的 init/main.c 里。我们打开之,找到 start_kernel 函数,发现它其实就是初始化一些函数而已。我们在最后的几个函数前添加打印信息就好了,请看:

这里要注意的是,内核不能使用 printf 函数,不过内核提供的 printk 函数和 printf 函数的功能很相似。

保存修改后,我们再次编译内核,得到新的 bzImage 后,再使用 qemu 模拟运行 linux 内核:

发现内核打印出我们的名字 embed time(嵌入式时代)后,停在了这里,因为我们添加了 while(1) 死循环嘛。

到这里,其实我们就已经会修改 linux 内核源码了,修改操作系统源码也没有那么复杂,对不?至于如何让 linux 内核不再恐慌,就需要给它提供个文件系统了,怎样提供跟?限于篇幅,我们下一节再介绍。


linux学习2,五分钟学会调试内核,让操作系统打印自己的名字 - 刘冲的博客(https://blog.popkx.com) 原创版权所有,转载请注明出处。
点赞 (0)分享 (0)
发表我的评论
取消评论
表情     6 + 6 = ? (必填)