前置要求及环境配置
被调试的主机安装待调试内核,称为target,另一台装有稳定的Linux内核,称为host。
target主板上带有原生com口,不能使用USB转接;需要一台USB转串口母线,连接target串口和host
本文使用的target架构为aarch64, 系统为openeuler,内核为Linux-5.10, host架构为x86-64, 系统为ubuntu 20.04,内核为Linux-5.4。但理论上本文所述的方法在Linux 5.x的发行版上是通用的。
确定串口是否可用
在target上安装minicom:
1
sudo yum install minicom -y
在target上,通过sudo minicom -D /dev/ttyAMA0
启动,在host上监听/dev/ttyUSB0,可以接收到来自target minicom的输入,同理,在target上也可以收到host的输入,到这一步可以确认串口和串口线是没问题的,通过ctrl+A X 退出minicom。
如何确定串口是/dev/ttyAMA0? 猜的,但是可以通过遍历/dev下的所有串口设备来验证。
在windows上,可以使用uartAssist来监听串口。
安装必备工具
1
apt-get install gcc make libncurses5-dev openssl libssl-dev build-essential pkg-config libc6-dev bison flex libelf-dev
调试内核
target的参数设置
首先检查
/proc/sys/kernel/sysrq
,如果为0,则sysrq没有开启,后续在使用echo g触发sysrq时传递的信号将被忽略,需要将其修改为1:echo 1 > /proc/sys/kernel/sysrq
。- 在target上进入kgdb模式:
1 2
sudo su echo ttyAMA0,115200 > /sys/module/kgdboc/parameters/kgdboc
在dmesg中可以看到输出为
KGDB: Registered I/O driver kgdboc
,说明target的串口没有问题。 - 在target上使系统hang住,以在host上能够通过gdb连接并调试:
1
echo g > /proc/sysrq-trigger
此时可以看到:
1
2
Entering kdb (current=0xffff00209622e040, pid 1716) on processor 5 due to Keyboard Entry
[5]kdb>
host的环境准备
在host上准备内核调试环境,包括gdb、target上使用的vmlinux以及相应的ko文件。由于我们的host与target架构不同,因此需要使用gdb-multiarch并显式设置architecture为aarch64,而非gdb。
- 在host上安装agent-proxy,作用是将串口分割为多个功能,这里使用host的5550和5551端口,其中5550用于连接target的console,5551用于连接target的kgdb监听端口
1 2 3
git 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
- 在host上连接target的console:
1
sudo telnet localhost 5550
- 在host上启动gdb-multiarch并连接5551端口:
1 2
gdb-multiarch vmlinux target remote:5551
发现连接失败并报错:
1
2
3
4
gef> target remote:5551
Remote debugging using :5551
Ignoring packet error, continuing...
Remote replied unexpectedly to 'vMustReplyEmpty': vMustReplyEmpty
同时,target上报错:
1
[5]kdb> g+$qSupporteddiag: -22: Permission denied
原因是因为access to debugger functions is prohibited by default in you kernel,有两种解决方案:
- 将cmd_enable设置为1,当前可用,但系统重启后失效
1
echo 1 > /sys/module/kdb/parameters/cmd_enable
- 添加一个启动参数,系统重启后生效:
1
kdb.cmd_enable=1
在target的kdb console中输入go使系统退出此状态,进行上述修改后重新echo g > /proc/sysrq-trigger
,再次使用gdb连接target。
在gdb上执行:
1
set architecture aarch64
参数可以在set architecture中找到,但是这里设置arm-v8a会有问题,原因未知。
然后就可以愉快的进入调试了,后续的调试过程与qemu上基本相同,不再赘述。
将输出重定向到串口
经过上述操作后,连接5550端口的terminal输出为乱码,而target的系统日志默认输出到屏幕,导致panic时无法查看现场和之前的printk输出,因此需要使屏幕输出重定向到串口。
通过修改/etc/default/grub
,在GRUB_CMDLINE_LINUX即Linux的启动参数中添加console=ttyAMA0,115200
,使系统日志同时输出到屏幕和串口。
重新生成grub.cfg:sudo grub2-mkconfig -o /boot/efi/EFI/openEuler/grub.cfg
,重启后,即可在串口看到输出的系统日志。
目前暂未解决的问题
- 无法在gdb-multiarch中查看系统寄存器如TTBR1_EL1、TCR_EL1等的信息,暂不清楚是gdb-multiarch的限制还是串口的限制。
- 无法像在qemu中一样在gdb一侧使整个内核挂起,目前只能在target一侧通过
echo g > /proc/sysrq-trigger
来挂起内核。References
【1】Using kgdb, kdb and the kernel debugger internals — The Linux Kernel documentation