您的位置:首页 > 运维架构 > Linux

linux工具---用qemu调试linux内核

2016-06-13 15:33 621 查看
一.qemu模拟x86
1.1 qemu的安装
        ubuntu 12.04下安装qemu很简单, 
        sudo apt-get install qemu
1.2 linux内核的编译
    www.kernel.org 下载内核, 以linux-3.0.1为例
    sun@ubuntu:/work/x86/kernel$ tar xf ./linux-3.0.1.tar.bz2
    sun@ubuntu:/work/x86/kernel$ cd linux-3.0.1/
    sun@ubuntu:/work/x86/kernel/linux-3.0.1$ make menuconfig
    sun@ubuntu:/work/x86/kernel/linux-3.0.1$ make bzImage 
    这样就会生成内核文件 arch/x86/boot/bzImage
1.3 busybox的编译
    http://www.busybox.net/ 下载busybox, 以busybox-1.21.1.tar.bz2为例
    sun@ubuntu:/work/x86/kernel$ tar xv busybox-1.21.1.tar.bz2 
    sun@ubuntu:/work/x86/kernel$ cd busybox-1.21.1/
    sun@ubuntu:/work/x86/kernel/busybox-1.21.1$ make menuconfig 
     Busybox Settings  --->  
           Build Options  ---> 
               [*] Build BusyBox as a static binary (no shared libs)           //静态方式编译
     Networking Utilities  --->
          [ ] inetd                                                                                 //去掉inetd
   sun@ubuntu:/work/x86/kernel/busybox-1.21.1$ make install 
       这会生成 _install目录
1.4 最小文件系统的建立
只用一个脚本creatfs.sh就可以生成cramfs文件系统

#!/bin/sh

KERNEL=$(pwd)

BUSYBOX=$(find busybox* -maxdepth
0)

LINUX=$(find linux* -maxdepth
0)

#create filesystem

cd $BUSYBOX

mkdir -pv proc sys dev etc etc/init.d      //先创建系统目录

cat << EOF > etc/init.d/rcS                //生成rcS文件

#!/bin/sh

mount -t proc none /proc

mount -t sysfs none /sys

/sbin/mdev -s

EOF

chmod 777 ./etc/init.d/rcS                //修改rcS权限

cd -

#create cpio img

cd $BUSYBOX/_install

find . | cpio -o --format=newc > $KERNEL/rootfs.img  

cd -

#create zip img

cd $KERNEL

gzip -c rootfs.img > rootfs.img.gz

1.5 启动qemu

#!/bin/sh

LINUX=$(find linux* -maxdepth
0)

#启动qemu

if [ $# = 0 ] ; then

    qemu-system-i386 -kernel $LINUX/arch/i386/boot/bzImage -initrd
rootfs.img.gz -append "root=/dev/ram
rdinit=sbin/init noapic"

fi

if [ "$1" = "s" ] ; then

    qemu-system-i386 -s -S -kernel
$LINUX/arch/i386/boot/bzImage -initrd
rootfs.img.gz -append "root=/dev/ram
rdinit=sbin/init noapic"

fi

如果没有参数直接运行qemu,
如果有参数s, 则进入调试模式
qemu参数:  
    -s  :  在1234接受gdb调试连接
    -S :   虚拟机启动后立即暂停,等侍gdb连接
最后所有文件如下:
sun@ubuntu:/work/x86/kernel$ tree -L 1 
.
├── busybox-1.21.1        //busbyox及_install 
├── creatfs.sh                 //文件系统生成脚本    
├── linux-3.0.1              //Linux源码,及
bzImage
└── start.sh                   //启动qemu

注意:

a. 将linux启动信息打印到串口
在qemu启动时加上: 
      qemu-system-i386 -kernel $LINUX/arch/i386/boot/bzImage -initrd rootfs.img.gz -append "root=/dev/ram rdinit=sbin/init noapic console=ttyS0" -serial
file:/tmp/serial.out
就会在/tmp/serial.out中出现系统的信息
b.  将linux启动信息直接打印到控制台
加入 -nographic 和stdio,则会在当前运行的terminal中把linux启动信息打印出来
qemu-system-i386 -kernel $LINUX/arch/i386/boot/bzImage -initrd rootfs.img.gz -append "root=/dev/ram rdinit=sbin/init console=ttyS0" -nographic
c. qemu的快捷键 
C-a h    print this help
C-a x    exit emulator
C-a s    save disk data back to file (if -snapshot)
C-a t    toggle console timestamps
C-a b    send break (magic sysrq)
C-a c    switch between console and monitor
C-a C-a  sends C-a

二.qemu模拟ARM
 2.1 qemu-system-arm的安装
如果只是apt-get install qemu,不会安装qemu-system-arm
sun@ubuntu:/work/qemu$ sudo apt-get install qemu qemu-system qemu-utils
sun@ubuntu:/work/qemu$ qemu-system-arm  --version
QEMU emulator version 1.0.50 (Debian 1.0.50-2012.03-0ubuntu2.1), Copyright (c) 2003-2008 Fabrice Bellard
注意: 编译工具链可以不用apt-get install 来安装,试过6410自带的交叉编译工具链是完全可用的。
2.2 编译u-boot, kernel, busybox
这儿的编译跟x86的不同之处是:
不论是编译u-boot 还是 linux-3.0.1 还是busybox都需要个改Makefile中的ARCH与CROSS_COMPILE两个变量c

ARCH ?= arm

CROSS_COMPILE ?= /opt/6410/4.3.2/bin/arm-none-linux-gnueabi-

编译u-boot时是用的make ca9x4_ct_vxp_config
编译Linux-3.0.1时是用的 arch/arm/configs/vexpress_defconfig
内核编译命令: make vexpress_defconfig && make -j16
a.copy zImage
在arch/arm/Makefile中

278 zImage Image xipImage bootpImage uImage: vmlinux

279 $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@

280 echo "$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@"

281 cp $(boot)/$@ ../

其中$(boot)/$@是zImage的路径
../ 是linux-3.01源码的上一层

2.3 用ext3系统启动
编译完成busybox, make install 后,用mkfs.sh脚本生成文件系统,只是生成,不用打包成其它格式

#!/bin/sh

KERNEL=$(pwd)

BUSYBOX=$(find busybox* -maxdepth
0)

LINUX=$(find linux* -maxdepth
0)

#create filesystem

cd $BUSYBOX

mkdir -pv proc sys dev etc etc/init.d //先创建系统目录

cat << EOF > etc/init.d/rcS //生成rcS文件

#!/bin/sh

mount -t proc none /proc

mount -t sysfs none /sys

/sbin/mdev -s

EOF

chmod 777 ./etc/init.d/rcS //修改rcS权限

cd -

用ext3.sh脚本创建ext3文件系统

#!/bin/sh

#创建一个32M的空文件

dd if=/dev/zero
of=a9rootfs.ext3 bs=1M count=32 

#格式化为EXT3

sudo mkfs.ext3 a9rootfs.ext3 

# 挂载到a9rootdir目录

mkdir -pv /tmp/a9rootdir

sudo mount -t ext3 a9rootfs.ext3 /tmp/a9rootdir/ -o loop

#拷贝文件到该目录,相对于放到a9rootfs.ext3里面

sudo cp /work/qemu/rootfs/* /tmp/a9rootdir/ -Rf

sudo umount /tmp/a9rootdir

启动:

qemu-system-arm -kernel
zImage -M vexpress-a9 -append "root=/dev/mmcblk0
console=ttyAMA0 console=tty0" -sd a9rootfs.ext3 -serial stdio

2.4 用NFS启动
编译完成busybox, make install 后,用mkfs.sh脚本生成文件系统,只是生成,不用打包成其它格式
启动:

qemu-system-arm -m
256 -kernel zImage -serial stdio -M vexpress-a9 -append
root="/dev/nfs console=ttyAMA0 console=tty0 nfsroot=10.0.0.1:/work/qemu/rootfs rw ip=10.0.0.2:10.0.0.1:10.0.0.1:255.255.255.0 " -net
nic,vlan=0 -net tap,vlan=0,ifname=tap0,script=qemu-ifup &

qemu-ifup脚本如下:

#!/bin/sh

echo "Executing /etc/qemu-ifup"

sudo ifconfig $1 10.0.0.1

前提是主机上的nfs-server己配置好

三. qemu调试linux系统
3.1 启动调试模式下的qemu
   sun@ubuntu:/work/x86/kernel$ sh start.sh s
3.2 另起一个terminal

sun@ubuntu:/work/x86/kernel/linux-3.0.1$
gdb vmlinux 

Reading symbols from /work/x86/kernel/linux-3.0.1/vmlinux...done.

(gdb) target
remote localhost:1234

Remote debugging using localhost:1234

0x0000fff0 in ?? ()

(gdb) b kernel_init 

Breakpoint 1 at 0xc15c7786: file init/main.c, line
781.

(gdb) c 

Continuing.

Breakpoint 1, kernel_init (unused=0x0) at
init/main.c:781

781    {

(gdb) l

776        panic("No init found. Try passing init= option to kernel. "

777         "See Linux Documentation/init.txt for guidance.");

778    }

779    

780    static int __init kernel_init(void * unused)

781    {

782        /*

783         * Wait until kthreadd is all set-up.

784         */

785        wait_for_completion(&kthreadd_done);

(gdb)

3.3 每次都这么操作比较麻烦,可以建立一个gdbinit脚本
sun@ubuntu:/work/x86/kernel/linux-3.0.1$ vi .gdbinit 

target remote localhost:1234

b kernel_init

c

然后下次运行时就可以
sun@ubuntu:/work/x86/kernel/linux-3.0.1$ gdb vmlinux 
注意,如果用gdbinit脚本时出现以下问题:

warning: File "/work/x86/kernel/linux-3.0.1/.gdbinit" auto-loading
has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".

To enable execution of this file add

    add-auto-load-safe-path /work/x86/kernel/linux-3.0.1/.gdbinit

line to your configuration file "/home/sun/.gdbinit".

To completely disable this security protection add

    set auto-load safe-path /

line to your configuration file "/home/sun/.gdbinit".

For more information about this security protection see the

"Auto-loading safe path" section in the GDB manual. E.g., run
from the shell:

    info "(gdb)Auto-loading safe path"

sun@ubuntu:/work/x86/kernel/linux-3.0.1$ vi ~/.gdbinit 
 set auto-load safe-path /
在~/.gdbini中加入上面这一行,取消掉

 [参]:
以QEMU模拟Linux,学习linux内核
http://www.cnblogs.com/senix/archive/2013/02/21/2921221.html
使用qemu调试linux内核
http://blog.csdn.net/aero_boy/article/details/6262609
使用qemu模拟Coretex-A9运行u-boot和Linux
http://www.linuxidc.com/Linux/2012-07/65478.htm
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: