通过DAP下载运行程序
前一篇文章我们介绍了DAP的基本原理,并介绍了通过DAP访问系统内存的方式,这篇文章着重介绍一下怎么通过DAP控制ARM CORE的运行状态,以及如何读取和更改CORE的通用寄存器。
对于一般程序调试,获取通用寄存器的状态是比较重要的一种调试手段,读取这些通用寄存器的状态的前提是CORE必须处于HALT状态,否则这个寄存器的值是一直变化的,我们也就无法获取一个比较准确的值。另外对这些寄存器的值进行修改也需要将CORE HALT。
通过DAP HALT ARM CORE的方式也是访问一系列系统寄存器完成的,这些内核调试寄存器定义如下:
地址 | 类型 | 复位值 | 描述 |
---|---|---|---|
0xE000EDF0 | 读写 | 0x00000000 | 调试停止控制和状态寄存器 |
0xE000EDF4 | 只写 | - | 调试内核寄存器的选择寄存器 |
0xE000EDF8 | 读写 | - | 调试内核寄存器数据寄存器 |
0xE000EDFC | 读写 | 0x00000000 | 调试异常和监控控制寄存器 |
调试停止控制和状态寄存器
位范围 | R/W | 名称 | 功能 |
---|---|---|---|
[31:16] | W | DEBGKEY | 写操作必须是0xA05F,否则写操作被忽略,读操作返回状态位 |
[25] | R | S_RESET_ST | 自上一次读该位时,系统已经复位或正在复位,读造作清零 |
[24] | R | S_RETIRE_ST | 表示自上一次读该位时,已经执行一条指令 |
[19] | R | S_LOCKUP | 系统处于lockup状态 |
[18] | R | S_SLEEP | 系统处于睡眠状态,必须使用C_HALT来获得或者等待中断唤醒内核 |
[5] | R/W | C_SNAPSTALL | 使能停止调试来获得对内核的控制,如果内核正在加载、存储操作,则操作无效,指令强制执行,如果C_DBUGEN=1, C_HALT=1,该位只能置1 |
[3] | R/W | C_MASKINS | 处于调试状态的内核执行单布或运行时屏蔽中断,NMI依然有效 |
[2] | R/W | C_STEP | 对内核进行单步操作,C_DEBUGEN=0时无效,S_HALT=1时仅修改 |
[1] | R/W | C_HALT | 停止内核,内核停止时(比如断点)自动置位,C_DEBUGEN=1时只能写,该位置位时C_DEBUGEN也必须写1 |
[0] | R/W | C_DEBUGEN | 使能调试,只能通过AHP-AP写入,内核不能写 |
调试内核选择寄存器
位范围 | R/W | 名称 | 功能 |
---|---|---|---|
[16] | W | REGWnR | 写操作为1,读操作为0 |
[4:0] | W | REGSEL | 0000 - R0 ... 1111 - R15 10000 - xPSR/Flags 10001 - MSP 10010 - PSP 10011 - RAZ/WI 10100 - CONTROL/FAULTMASK/BASEPRI/PRIMASK |
写通用寄存器的流程
- 想挑事停止和状态寄存器中写入
0xA05F0003
,该操作会使能调试并停止内核 - 等待调试停止和状态寄存器的
S_HALT
置位,置位表示内核已经停止 - 向调试内核寄存器的数据寄存器中写入目标值
- 向调试内核寄存器选择寄存器写入要写入的寄存器编号和写操作标志
这个操作用Jlink Command的方式写下来就是下面这个样子:
connect
// select AP[1]
writedp 2 01000000
// halt core
writeap 1 E000EDF0
writeap 3 A05F0003
// set pc
writeap 1 E000EDF8
writeap 3 06000000
writeap 1 E000EDF4
writeap 3 0001000F
// release pc
writeap 1 E000EDF0
writeap 3 A05F0000
这个时候就可以直接写个生成JLink脚本的小脚本,用于直接下载程序了:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import binascii
bin_path = sys.argv[1]
start = """connect
writedp 2 01000000
// halt core
writeap 1 E000EDF0
writeap 3 A05F0003
// write code"""
start_address = 0x06000000
end = """ // set pc
writeap 1 E000EDF8
writeap 3 06000000
writeap 1 E000EDF4
writeap 3 0001000F
// set msp
writeap 1 E000EDF4
writeap 3 00010101
writeap 1 E000EDF8
writeap 3 0602807c
// release pc
writeap 1 E000EDF0
writeap 3 A05F0000"""
print(start)
with open(bin_path, 'rb') as src:
word = src.read(4)
while word != b'':
print("writeap 1 %08x" % start_address)
print("writeap 3 %08x" % int.from_bytes(word, byteorder='little'))
start_address += 4
word = src.read(4)
print(end)
最后更新于 2019-10-06 22:17:19 并被添加「调试 ARM 脚本」标签,已有 7574 位童鞋阅读过。
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。