KGDB-双物理机调试内核
KGDB-双物理机调试内核
author: Ewan
准备工作
搭建双物理机调试Linux内核环境之前,需要:
- 2台物理机,均装有Linux操作系统,下文以Host和Target区分调试机和被调试机
- 一份需要调试的Linux源码
- 一根串口转USB线
attention:本文使用Target的ttyS1,Host的ttyUSB0,波特率115200.
-
将串口转USB线的串口端连接到Target上,USB端连接到Host上
连接好之后可以在Host和Guest上都安装cutecom串口通信软件,测试Host和Guest的串口通信是否正常
cutecom安装:sudo apt-get install cutecom
测试方法为,在Host和Target上均用sudo cutecom打开cutecom,然后在Host上打开设备/dev/ttyUSB0,在Target上打开设备/dev/ttyS1,尝试互相发送数据,如果成功,说明串口连接无故障。
-
在Target上编译并安装需要调试的Linux源码,在
make menuconfig
时注意需要选择KGDB* , KGDB_SERIAL*, KGDB_USB*, DEBUG_INFO, DEBUG_INFO_DWARF4, MAGIC_SYSRQ
这些内核编译选项,我使用的5.3.8默认包含这些选项.编译安装完成后,向/etc/default/grub
中的GRUB_CMDLINE_LINUX
添加nokaslr, 以保证内核代码不会随机改变位置,然后运行sudo update-grub,将添加的信息更新到grub中,重启Target. -
完成以上工作之后,将源码目录下生成的
vmlinux
文件拷贝到Host -
在Host上下载
Agent-Proxy
并编译,然后启动Agent-Proxygit clone http://git.kernel.org/pub/scm/utils/kernel/kgdb/agent-proxy.git
cd agent-proxy;make
sudo ./agent-proxy 5550^5551 0 /dev/ttyUSB0,115200
Agent-Proxy是一款开源代理软件,能够将串口分割为多个功能,这里使用Host的5550和5551两个端口,5550用于连接Target的console, 5551用于连接Target的KGDB监听端口
开始调试
- 在Host上连接Target的console
sudo telnet localhost 5550
- 在Target上进入kgdb模式
sudo su
echo ttyS1,115200 > /sys/module/kgdboc/parameters/kgdboc
然后就可以在dmesg里看到Registered I/O driver kgdboc
,如果没看到说明哪些地方出问题了。
然后利用下面的命令将Target的运行暂停,这样就可以在host上使用gdb连接并调试。
echo g >/proc/sysrq-trigger
如果想要调试系统启动早期代码,则需要在Target启动时暂停,如果有这种需求,可以在Target的启动选项中加入console=tty0 console=ttyS1,115200 kgdbwait kgdboc=ttyS1,115200
-
然后就可以在步骤1的窗口中看到类似于下面的内容:
Entering kdb (current=0xcb846c80, pid 2301) on processor 3 due to Keyboard Entry
[3]kdb>
在[3]kdb> 后输入kgdb,这之后Target就会进入等待远程gdb连接的状态。
-
在Host上新开一个Terminal窗口,进入从源码目录,输入gdb vmlinux,这里的vmlinux就是之前在Target上生成,拷贝到Host上的Linux符号文件。
该步骤的全部输入如下:
gdb vmlinux
(gdb) target remote localhost:5551
Remote debugging using localhost:5551kgdb_breakpoint () at kernel/debug/debug_core.c:1072
1072 wmb(); /* Sync point after breakpoint */
(gdb)
然后就可以快乐地使用gdb进行调试Target了。
-----update on 11.5.2020-------------------
使用上面的步骤,确实可以调试一些功能,但是最近想调试kvm的代码,发现经过上面的步骤,进入到gdb之后,无法在kvm中设置断点,例如:
(gdb) b handle_io
不存在handle_io
此时要怎么做呢?
kvm和kvm_intel都是内核的module,vmlinux默认情况下是不加载module的符号的,需要手动加载。
- 在target上找到kvm和kvm_intel的.text段地址
cat /sys/module/kvm/sections/.text
cat /sys/module/kvm_intel/sections/.text
我获得的target上kvm和kvm_intel两个module在内核中的.text位置分别为:
0xffffffffc0205000,0xffffffffc0335000.
- 在host上的gdb调试窗口将这两个地址的符号加载进gdb
注意这一步中,gdb vmlinux运行的目录为从target复制过来的Linux源码的目录
(gdb) add-symbol-file arch/x86/kvm/kvm.ko 0xffffffffc0205000
(gdb) add-symbol-file arch/x86/kvm/kvm.ko 0xffffffffc0335000
然后就可以在类似于handle_io的kvm代码出下断点了。