这篇文章是“linux 3.10 调试及跟文件系统构建”的改进版。我的环境是vm ware虚拟机跑的centos 7 64位系统
1: 安装qemu
先安装SDL,负责qemu运行后只出现VNC server running on `::1:5900',而不出现qemu运行窗口,具体参考:
http://www.crifan.com/qemu_test_arm_vnc_server_running_on_127_0_0_1_5900_no_other_output/
yum install SDL.i686 SDL.x86_64 SDL-devel.i686 SDL-devel.x86_64
下载源代码qemu-2.1.0.tar.bz2,解压编译,安装
./configure --prefix=/usr/local/ --target-list=x86_64-softmmu
make && make install
创建软链接
ln -n /usr/local//bin/qemu-system-x86_64 /bin/qemu
2:下载busybox-1.20.0.tar.bz2,解压,进入源代码目录,运行
make menuconfig
选择
Busybox Settings --->
Build Options --->
[*] Build BusyBox as a static binary (no shared libs)
编译安装
make && make install
安装后的文件系统目录是源代码下的_install, 进入该目录,创建必要的文件
创建init文件,不创建这个文件系统启动不了,因为如果没有从参数传入用户空间初始化程序的文件名,系统会测试/init文件是否存在,存在则调用/init进行用户空间初始化,否则系统会尝试初始化,而系统初始化会失败,失败后系统会挂起。具体信息参考内核初始化函数kernel_init_freeable和prepare_namespace。
ln bin/busybox init
创建控制台文件,不创建这个文件busybox不能完成初始化
mkdir dev
mknod -m 600 dev/console c 5 1
创建配置目录及其文件
mkdir etc
vim etc/inittab
实际只要examples/inittab注释掉一些tty2::askfirst:-/bin/sh类似的行就可以了,因为我们只要一个控制台就可以了,文件内容只如下:
::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a
创建初始化脚本:
mkdir etc/init.d
vim etc/init.d/rcS
chmod 777 etc/init.d/rcS
etc/init.d/rcS文件内容如下:
#!/bin/sh
export PATH=/sbin:/bin:
export HOSTNAME=ac
echo "start....."
这样一个只包含最简单内容的initramfs就创建成功了,用这个方法创建的initramfs在busybox初始化后不会出现/bin/sh: can't access tty; job control turned off信息。直接可以运行命令行。
3:下载linux-3.10.tar.xz,解压源码,进入源码目录,运行
make menuconfig
配置编译选项,选中
General setup --->
[*]Initramfs source file(s)
选项,输入制作好的文件系统的目录就可以了,我这里是
/opt/busybox-1.22.1/_install
编译
make bzImage
运行虚拟机:
qemu -kernel ./arch/x86/boot/bzImage -append "no_timer_check"
在另一终端下进行gdp调试:
gdb vmlinux
target remote 127.0.0.1:1234
b start_kernel
4:在我的机器上不添加no_timer_check会输出
...trying to set up timer as Virtual Wire IRQ...
后卡住
解决这个问题的方法:
在源代码搜索trying to set up timer as Virtual Wire IRQ,找到函数输出语句在函数check_timer中。
运行虚拟机
qemu -kernel ./arch/x86/boot/bzImage -append "root=/dev/hda init=/bin/sh no_timer_check" -S -s
在内核源代码目录运行
gdb vmlinux
进入gdb命令行后输入命令
target remote 127.0.0.1:1234
b check_timer
c
断点后从输出trying to set up timer as Virtual Wire IRQ后往下执行,发现到timer_irq_works函数后卡住。在timer_irq_works中有语句:
if (no_timer_check)
return 1;
查找no_timer_check,在Documentation/x86/x86_64/boot-options.txt中找到no_timer_check选项。
5:GDB 调试出现gdb 'g' packet reply is too long修正,
下载gdb-7.8.tar.xz后
解压
xt -d gdb-7.8.tar.xz
tar xf gdb-7.8.tar.xz
编辑源代码:
vim gdb/remote.c
找到process_g_packet函数
注释调下面两行
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->pnum == -1)
continue;
if (rsa->regs->offset >= rsa->sizeof_g_packet)
rsa->regs->in_g_packet = 0;
else
rsa->regs->in_g_packet = 1;
}
}
配置编译
./configure --prefix=/usr/local/gdb
Make && make install
设置环境变量
export PATH=/usr/local/gdb/bin:$PATH