上一篇介绍了“GDK7+NanoCode调试学习系列6--Intel System Studio(ISS)搭建环境调试GDK7”(https://blog.csdn.net/henly1217/article/details/108466248);
本篇继续学习,将尝试使用NanoCode来分析Linux虚机KVM模块的相关调用。
本调试目标机Linux内核版本为5.3.0-62-generic。
准备工作:
1. 关于kvm.ko符号和内核源码的下载,请参考以前的文章(https://blog.csdn.net/henly1217/article/details/107662054);
2. kvm.ko处于/usr/lib/debug/lib/modules/5.3.0-62-generic/kernel/arch/x86/kvm目录,和其他drivers不太一样。
3. 复制带符号的kvm.ko到主机,放入以前的符号目录。
4. 使用kvm驱动模块的功能,需要安装应用层工具qemu,应用层通过/dev/kvm文件符号和驱动通信。
5. 可参考https://help.ubuntu.com/community/KVM/Installation安装virt-manager(虚拟系统管理器),安装完之后,可以“新建虚拟机”来创建一个新的虚拟机。如下图,正在运行的一个虚拟机。可以通过下面指令查看kvm的debugfs:
sudo su - // 进入root
mount -t debugfs debugfs /opt/debugfs // mount debugfs 到/opt/debufs下
cd /opt/debugfs
ls kvm
可以看到kvm的debugfs, 其中2448-12目录正是当前运行的这个虚拟机的debugfs.
开始调试:
1. 参考(https://blog.csdn.net/henly1217/article/details/107907362)中断并设置符号和内核源码路径。
2. 已经成功加载了内核符号了,通过(.srcpath+ 内核源码路径)来设置一下源码路径,通过(x kvm!*)来加载一下kvm的符号。
3. 环境已经准备就绪了。
4. 我们尝试使用NanoCode提供的Views->JTAG events的VMLaunch和VMExit来设置一下,看看是否能够中断?
> 先设置VMLaunch,然后g起来
> 有点遗憾,启动VMLuanch是自动断下来了,可以获取不到执行信息,启动VMExist没有断下来
5. 我们暂时跳过JTAG events,继续研究一下源代码。
6. 在virt/kvm/kvm_main.c里面有kvm_vcpu_init和kvm_vcpu_uninit函数,我们先对他们下个断点。
bp kvm!kvm_vcpu_init
bp kvm!kvm_vcpu_uninit
然后重新g起来;
然后启动另一个虚拟机,果然,kvm_vcpu_init断点命中,这是虚拟机启动的初始化函数,我们稍微调试一下,
kv //看下调用堆栈
dv //查看临时变量,但是没有显示出来??
p // 先单步一次
dv //在查看临时变量,出来了,当前的vcpu=0xffff8a8f`66f50000
然后重新g起来,我们关闭刚刚启动的虚拟机,看看kvm_vcpu_uninit是否断下?没有问题,也断下了,而且参数vcpu=0xffff8a8f`66f50000。
7. 简单分析启动和关闭之后,我们在研究一下应用层和驱动是通过哪里交互的,应用层和驱动通过/dev/kvm来交互,通过kvm_dev_ioctl来实现,如下图,然后根据ioctl来分发不同的请求,包括创建新的虚拟机kvm_dev_ioctl_create_vm,kvm_arch_dev_ioctl会根据不同的架构,调用到不同架构的实现里面去。
我们尝试对kvm_dev_ioctl下断点(bp kvm!kvm_dev_ioctl),很快命中断点,ioctl=0xae03,刚好是KVM_CHECK_EXTENSION
8. 至此,我们简单地配合源码和调试器,分析了kvm的几个函数。
总结:
1. 在调试器下简单分析kvm的创建,启动/关闭,和通信的加个函数
2. 待续。。。