Changchun Master Li

使用jtag和gdb实时调试Linux内核

2022-03-30

0. 关键词

debug raspberry pi bcm2835 armv6 linux kernel J-Link jtag gdb

1. 摘要

gdb是一款开源debugger,调试的事实标准,gdb可以帮助开发者快速定位问题。

gdb也可以作为阅读源码的工具,可以非常方便的查看运行时上下文,跳转所见即所得。因此,在嵌入式系统或底层开发中,gdb必不可少。
linux内核作为操作系统调试起来有一定特殊性,不能直接在本地gdb调试,需要一个host和一个target远程调试。

远程调试内核主要有三种方式,一种是内置派,通过Kgdb这种内核内置的模块。一种是虚拟派,通过把内核跑在类似qemu的虚拟机上。最后一种是硬件派,这是嵌入式设备上最常用的调试方式,通过连接jtag调试。

前两种多少都会受到软件的限制,而最后一种方式由硬件来实现,最直接。

2. rpi+jlink的优势

成本和流行的平衡,raspberry pi搭载的bcm2835是目前比较流行的soc,且资料较为完善,

armv6架构,比s3c2440要新很多,S3C2440架构是arm9,资料很丰富,但目前好像也只有周立功还在推这个老旧SoC作为学习平台。
而相对比较新的单板计算机例如树莓派3,其架构为a53,只能用昂贵的jlink v11。

我这里选择的jtag为jlink v9 非常便宜daobanchangkuang,由于来自深圳的科技,淘宝才不到100块,不喜欢黑又粗外观的还可以选择定制化的小板。

3. 硬件准备

3.1 清单

  • micro sd card
  • SEGGER J-Link V9
  • pl2303/ch340 usb uart adapter
  • raspberry pi 1A (bcm2835)

3.2 接线方式

接线方式可以参考segger官网Interface Description和树莓派specRPi BCM2835 GPIOs
因为rpi1A只有26个pin,主板上没有引出GPIO26,只得改用GPIO4来替换,rpi1B+则无需改动。

JTAG J-Link pin rpi pin (1A) bcm2835 GPIO
TRST 3 15 22
RTCK 11 16 23
TDO 13 18 24
TCK 9 22 25
TDI 5 37 (7) 26 (4)
TMS 7 13 27

我这里用20pin的FC压线头做的转接线,顺带把uart也加上了,很方便

4. 环境配置

4.1 buildroot制作Linux镜像

我们需要在 /boot/config.txt 使能jtag,bcm2835的VideoCore读取配置之后,就可以对GPIO作出相应的设置。(否则另一种方式是由arm核配置GPIO,需要改动linux kernel 启动代码)。

配置参数具体参考enable_jtag_gpio
这里可以使用我写好的buildroot recipe,我在这个基础上超级精简了linux kernel,缩短编译时间,同时开启debug选项。

1
2
3
4
5
6
git clone https://github.com/996refuse/rpi_bcm2835_minimal.git
git clone https://github.com/buildroot/buildroot

cd buildroot
make BR2_EXTERNAL=../rpi_bcm2835_minimal/ rpi_bcm2835_minimal_defconfig
make

这样,适配bcm2835的Linux镜像就制作完成了,使用dd写到卡上 dd if=output/images/sdcard.img of=/dev/sdX status=progress
然后就可以启动树莓派了

4.2 安装JLinkGDBServer

1
dpkg -i JLink_Linux_V618d_x86_64.deb

我这里用的是618d版本,segger官网可以下,太新的版本(2020年后)在调试过程中隔几分钟J-Link就会丢失jtag的连接,并且gdb报错
Program received signal SIGTRAP, Trace/breakpoint trap
(这个问题我搞了好久,一直以为是linux kernel有关cpu idle实现的问题,Debugging-Linux-Kernel-over-JTAG-with-J-Link 这篇文章误导了我。后来发现其实降版本就可以稳定了)

启动JLinkGDBServer

1
JLinkGDBServer -select USB -device arm11

此时GDB Server 会在监听2331端口,等待gdb连接

4.3 安装和使用gdb

上位机不是arm架构的话,需要交叉编译gdb的时候设置target为arm-linux-gnueabi (顺便加上python支持,后面gdb scripts会用到,不然又要重rebuild一次)。
如果是Ubuntu系统可以直接安装 gdb-multiarch

1
apt install gdb-multiarch

linux kernel为了gdb提供了一下helper function,kernel需开启CONFIG_GDB_SCRIPTS gdb-kernel-debugging ,并加入安全路径

1
echo "add-auto-load-safe-path /path/to/linux-build" >> ~/.gdbinit

启动gdb

1
2
cd output/build/linux-custom
gdb-multiarch vmlinux -ex "set gnutarget elf32-littlearm" -ex "target remote :2331"

愉快的开始debug吧!

5. 开源替代

这套方案能极大方便os爱好者尝试和分析系统层的特性和原理,稳定并且很便宜。
缺点在于过度依赖segger的产品。接下来我有时间会尝试openocd和daplink,力图找到完美的开源替代。

  1. openocd替换JLinkGDBServer,jlink v9 + openocd 调试树莓派3 Debugging Raspberry Pi 3 with JTAG | SUSE Communities
  2. daplink替换jlink

简单记录一下我的经验,希望对大家有帮助

使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章