jlink调试树莓派环境配置与gdb使用

最近做毕设的时候使用了jlink进行树莓派的单步调试,其配置和使用记录如下。

1. 树莓派boot启动配置

为让树莓派启动后配置gpio以支持jtag接口,启动config.txt文件中需要加一句

1
enable_jtag_gpio=1

2. openodc配置脚本

接着配置开发机端相关的程序,需要下载opencdc程序,配置脚本如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash

set -e

TOP=$(git rev-parse --show-toplevel)
EXT=$TOP/ext

cd $EXT

sudo apt install -y libtool autotools-dev automake autoconf libusb-1.0-0-dev
git clone https://git.code.sf.net/p/openocd/code openocd
cd openocd
./bootstrap
./configure
make
sudo make install 

这里git rev-parse --show-toplevel是git的一条底层命令(plumbing),rev表示revision,用于和高层命令(porcelain)区分

3. jlink连接

连接参照jlink文档

jlink对应raspi的gpio端口连接参考debugging raspberry pi board

3.1. openocd配置脚本

openocd编译目录下openocd/tcl/interface/jlink.cfg文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#
# SEGGER J-Link
#
# http://www.segger.com/jlink.html
#

adapter driver jlink

# The serial number can be used to select a specific device in case more than
# one is connected to the host.
#
# Example: Select J-Link with serial number 123456789
#
# jlink serial 123456789

然后是一个自己写的tcl脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
transport select jtag

reset_config trst_and_srst

adapter speed 1000
jtag_ntrst_delay 500

if { [info exists CHIPNAME] } {
  set _CHIPNAME $CHIPNAME
} else {
  set _CHIPNAME rpi3
}

if { [info exists DAP_TAPID] } {
   set _DAP_TAPID $DAP_TAPID
} else {
   set _DAP_TAPID 0x4ba00477
}

jtag newtap $_CHIPNAME tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -enable
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap

set _TARGETNAME $_CHIPNAME.a53
set _CTINAME $_CHIPNAME.cti

set DBGBASE {0x80010000 0x80012000 0x80014000 0x80016000}
set CTIBASE {0x80018000 0x80019000 0x8001a000 0x8001b000}
set _cores 4

for { set _core 0 } { $_core < $_cores } { incr _core } {

    cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 0 \
        -ctibase [lindex $CTIBASE $_core]

    target create $_TARGETNAME.$_core aarch64 \
        -dap $_CHIPNAME.dap -coreid $_core \
        -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core

    $_TARGETNAME.$_core configure -event reset-assert-post "aarch64 dbginit"
}

4. 嵌入式环境下gdb一些使用

4.1. 建立连接

由于openocd会导出用于debug的服务器的端口供gdb连接,因此很方便地,在gdb中只要

target remote localhost:3333

需要注意的有以下几点

  • 直接下载的gdb不一定能够work,可能无法识别并调试aarch64版本,需要下载sudo apt-get install gdb-multiarch
  • gdb需要使用编译生成的debug版本的elf文件(而非release版本)导入debug符号表等信息
  • 和板子连接的时候,要先把板子上电,boot的时候会初始化jtag相关的gpio,然后再接再开发机端用openocd连接jlink。

4.2. 在某个具体内存位置设置断点

b *[内存地址]

在某个具体内存位置的指令处设置断点。

4.3. 查看具体内存地址处指令

x/5i [内存地址]

i表示以指令形式打印,前面的数字表示指令数量。

4.4. 打印某个寄存器信息

p $[寄存器名]

4.5. gdb的tui界面

layout asm

上述命令可以切换为显示汇编代码的tui布局,有时可能需要返回默认的布局,命令是ctrl x + a