文章结构
1:问题的提出 2:解决的思路 3:构建一个虚拟机 4:替换虚拟机中的内核 5:调试虚拟机
一:问题的提出
参考上一篇文章,我们有-kernel -initid 的方式启动的内核bzimag, 之后进入shell环境发现没有virtio设备,如果自己添加设备,十分的麻烦,大量的时间都会消耗在研究qemu的参数里面,得不偿失。
二:解决的思路
怎么解决呢? 这里面有两种方法,本片文章中只记录其中的一种。就是,我们可以制作一个centosx(本文以centos7.4)的虚拟机。之后到虚拟机中,编译一个debug版本的内核,并替换内核。 之后将编译出来的 vmlinux文件,copy到host上,启动gust,在调试
vmlinux 即可。
三:构建一个虚拟机
网上有很多的教程,这里不在赘述。只是记录一下我遇到的问题。
1:安装的命令 qemu-kvm -m 4096 -boot d -enable-kvm -smp 4 -net nic -net user -nographic -vnc :4 -hda /home/xxx/centos.qcow2 -cdrom /home/xxx/centos7.4.iso #-boot d表示硬盘启动 -boot c表示光驱启动 -vnc 是开启vnc,在安装的时候用vncview连接上就可以安装系统了。 如果不这样的话,也可以通过virt-manager 2:使用virtio 磁盘 如何模拟一个virtio的磁盘,或者说更改自己的系统盘为virtio类型。通过一下的qemu参数 -drive file=/lost+found/release/linux_kernel/new.img,format=qcow2,if=none,id=drive-virtio-disk0 -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x8,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 #-drive 注意这个参数,表示的不是驱动,而是添加一个块设备,设备对应的文件是file=/lost+found/release/linux_kernel/new.img。id是drive-virtio-disk0。 #-device 这个表示系统有一个总线为xxxx的virtio-blk-pci设备,设备对应的块文件drive=drive-virtio-disk0。设备的id为virtio-disk0。bootindex=1 是系统盘。 3:最麻烦的就是网络的配置,我们这里面用nat模式。记录两个脚本(TODO:待上传)
四: 替换虚拟机中的内核
这个地方参考上一篇文章中的内核的编译就可以,只是编译在gust内部(或者在host编译一个debug的kernel的 rpm包,之后放到gust上升级也可以)。注意这个地方有一个坑,下面我会用我的切身体会来说明。别急
五:调试虚拟机
qemu-kvm -enable-kvm -smp 32 -m 8092 -drive file=/lost+found/release/linux_kernel/new.img,format=qcow2,if=none,id=drive-virtio-disk0 -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x8,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 -nographic -vnc :1 -net nic -net tap,script=./qemu-ifup-nat -S -s
启动虚拟机
gdb调试,发现:
(gdb) hb virtqueue_notify
Function "virtqueue_notify" not defined.
Make hw breakpoint pending on future shared library load? (y or [n]) #没有这个函数。
利用vnc连接服务器:
从图中发现已经加载了virtio等驱动,但是在调试的是时候 提示没有响应的函数。原因是由于我们将virtio的驱动编译成了module,所以代码是存在在*.ko文件中的。在虚拟机gust中,发现有我们添加的virtio-blk设备,内核会加载virtio驱动,virtio-pci驱动,virtio-blk驱动,virtio_ring 驱动。这样在gust的kernel中存在相应的符号信息,但是在host中,我们是通过vmlinux拉起来的,里面不存在这些符号信息。所以你是断不到virtio相应的函数的。那怎么办呢?
1:方法一:加载virtio的符号信息到gdb调试的vmlinux中。
2:方法二:编译的内核,除了打开debug_info,还要将virtio等驱动编译进内核,不是编译成模块。
加载virtio的符号信息到gdb调试的vmlinux中
原理:模拟gust os中的符号方式,在gustos 中获取模块的 text data bss等字段的位置,在host上将该ko文件加载到指定的位置中。
我们以 virtio-pci为例。在gust上获取ko文件,和各个字段的位置:
gust内获取符号加载的信息
[root@localhost ~]# cat /sys/module/virtio/sections/.text
0xffffffffa002a000
[root@localhost ~]# cat /sys/module/virtio/sections/.data
0xffffffffa002c000
[root@localhost ~]# cat /sys/module/virtio/sections/.bss #没有可以不添加
copy virtio.ko 到host上
add-symbol-file /xxx/aaa.ko <text addr> -s .data <data addr> -s .bss <bss addr>
add-symbol-file /root/virtio.ko 0xffffffffa002a000 -s .data 0xffffffffa002a000
########################################################################
gdb) add-symbol-file /root/virtio.ko 0xffffffffa002a000 -s .data 0xffffffffa002a000
add symbol table from file "/root/virtio.ko" at
.text_addr = 0xffffffffa002a000
.data_addr = 0xffffffffa002a000
这样就可以找到对应的符号了。可以愉快的调试了。
编译的内核,除了打开debug_info,还要将virtio等驱动编译进内核,不是编译成模块。这个方法更妙,因为又要编译内核,所以我们在下一篇文章中介绍。