QEMU+GDB调试linux内核全过程

写最前面

将近一个半月没有更新了,终于小小程序猿又回来了,现在开始更新我自己的博客以及博客心得;
之前因为在应用层调试代码比较得心应手,导致自己的思路一直限制在应用层的调试逻辑之中,使我吃尽了苦头,苦于少了一套工具来进行内核源码的调试,这样就限制了代码开发的进度。现在好了有了一套得心应手的工具,调试代码不在话下。
先声明一下现在使用的各个工具版本,以免忘记:

	内核版本:2.6.32.20
	gcc版本:4.4
	gdb版本:7.9
	busybox版本:1.25.0

内核代码在 [link][www.kernel.org]里面下载;

gcc使用ubuntu14.04重新下载的,需要使用apt-get autoremote gcc;apt-get install gcc-4.4命令重新下载,然后使用ln /usr/bin/gcc-4.4 /usrbin/gcc重新链接成gcc可执行文件;

gdb代码下载链接为:[link][http://www.gnu.org/software/gdb/download/]
注意:gdb调试过程中会出现如下错误:Remote ‘g’ packet reply is too long代表调试栈区溢出,需要修改gdb/remote.c文件中的static void
process_g_packet (struct regcache *regcache)函数才能正常使用:
由:

if (buf_len > 2 * rsa->sizeof_g_packet)
error (_("Remote 'g' packet reply is too long: %s"), rs->buf);

改为:

if (buf_len > 2 * rsa->sizeof_g_packet) {
    rsa->sizeof_g_packet = buf_len;
    for (i = 0; i < gdbarch_num_regs (gdbarch); i++)
    {
        if (rsa->regs[i].pnum == -1)
            continue;
        if (rsa->regs[i].offset >= rsa->sizeof_g_packet)
            rsa->regs[i].in_g_packet = 0;
        else
            rsa->regs[i].in_g_packet = 1;
    }
}

重新编译,安装即可: 1、sudo ./configure 2、sudo make 3、sudo make install

busybox下载链接为:[link][https://busybox.net/downloads/busybox-1.25.0.tar.bz2]

以上各个工具以及内核的编译过程省略过去,另外需要下载一份qemu,具体执行过程如下:sudo apt-get install qemu,上述执行过程,以及执行过程中遇到的坑,有时间的话重新整理一份供大家使用。
上述工具准备完了之后正式进入今天的主题:调试内核;
调试内核的第一步并不是启动虚拟机,也并不是直接拿gdb调试内核代码,而是制作一份最小化的根文件系统。
具体的执行步骤如下:

根文件系统制作

首先将上一步生成的_install文件夹复制到其他位置

 cd ..
 mkdir ramdisk
 cd ramdisk
 cp -r ../busy-1.25.0/_install/*  .

设置初始化进程init(建立一个软链接,一定不能直接复制过去)

cd ramdisk
ln -s bin/busybox init

设置开机启动程序

首先,我们需要先设定一些程序运行所需要的文件夹

mkdir -pv {bin,sbin,etc,proc,sys,usr/{bin,sbin},dev}

init程序首先会访问etc/inittab文件,因此,我们需要编写inittab,指定开机需要启动的所有程序

cd etc
vim inittab

inittab文件的内容如下所示:

::sysinit:/etc/init.d/rcS   
::askfirst:-/bin/sh    
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a

赋予可执行权限

chmod +x inittab

编写系统初始化命令
从inittab文件中可以看出,首先执行的是/etc/init.d/rcS脚本,因此,我们生成初始化脚本

mkdir init.d
cd init.d
vim rcS

rcS文件的内容如下所示:

#!/bin/sh

mount proc
mount -o remount,rw /
mount -a    
clear                               
echo "My Tiny Linux Starting, press enter to active"

赋予可执行权限

chmod +x rcS

在rcS脚本中,mount -a 是自动挂载 /etc/fstab 里面的东西,可以理解为挂在文件系统,因此我们还需要编写 fstab文件来设置我们的文件系统。

cd ramdisk/etc/
vim fstab

要挂载临时文件系统,固定的文件名为fstab, fstab文件内容如下:

#/etc/fstab
proc            /proc        proc    defaults          0       0
sysfs           /sys         sysfs   defaults          0       0
devtmpfs        /dev         devtmpfs  defaults          0       0

至此,我们已经完成了RAM Disk中相关文件的配置,可以压缩生成文件镜像了。

cd ramdisk
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.img

最后生成的initramfs.img就是我们的根文件系统。

测试根文件系统

根文件系统测试命令如下:

qemu-system-x86_64 -kernel ./boot/bzImage -initrd ./initramfs.img -hdc disk.img -append "console=ttyS0" -nographic

测试如下:
QEMU+GDB调试linux内核全过程_第1张图片

qemu+GDB调试

依次执行如下命令:

qemu-system-x86_64 -kernel ./boot/bzImage -initrd ./initramfs.img -hdc disk.img -append "console=ttyS0" -nographic -S -s
gdb /usr/src/linux-2.6.32.20/vmlinux

qemu-system-x86_64命令执行完成后如下:
在这里插入图片描述
发现虚拟机不再运行,是因为,需要gdb调试vmlinux才能够运行,全部执行过程如下:
gdb执行过程如下:

alex@ubuntu:~$ gdb source/vmlinux 
GNU gdb (GDB) 7.9
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
.
Find the GDB manual and other documentation resources online at:
.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from source/vmlinux...done.
(gdb) target remote:1234
Remote debugging using :1234
0x0000000000000000 in per_cpu.irq_stack_union ()
(gdb) b start_kernel
Breakpoint 1 at 0xffffffff81840954: file init/main.c, line 513.
(gdb) c
Continuing.

Breakpoint 1, start_kernel () at init/main.c:513
513	{
(gdb) c
Continuing.

必须先链接target remote:1234的gdb远程链接调试结构才能够正常启动内核和正常调试;

你可能感兴趣的:(内核,gdb调试)