0%

OpenOCD 探测目标所运行 OS 的原理

OpenOCD 支持 OS 调试,需要在目标配置中加上选项-rtos auto来使能此功能。

OpenOCD 文档中关于 OS 调试的说明如下:

OpenOCD includes RTOS support, this will however need enabling as it defaults to disabled. It can be enabled by passing -rtos arg to the target. See [RTOS Type], page 63.
See Section “Debugging Programs with Multiple Threads” in GDB manual, for details about relevant GDB commands.
An example setup is below:
$_TARGETNAME configure -rtos auto
This will attempt to auto detect the RTOS within your application. Currently supported rtos’s include:
• eCos
• ThreadX
• FreeRTOS • linux
• ChibiOS
• embKernel • mqx
• uCOS-III
Note: Before an RTOS can be detected, it must export certain symbols; other- wise, it cannot be used by OpenOCD.

OpenOCD 探测目标所运行 OS 的原理是,它查询目标所运行的程序中有无 OS 所含有的变量符号,例如 FreeRTOS 有如下符号:

1
pxCurrentTCB, pxReadyTasksLists, xDelayedTaskList1, xDelayedTaskList2, pxDelayedTaskList, pxOverowDelayedTaskList, xPendingReadyList, uxCurrentNumberOfTasks, uxTopUsedPriority.

如果这些符号都有,那就说明目标所运行的 OS 是 FreeRTOS。

但是 OpenOCD 是在硬件层的调试,它只是根据 gdb 的命令来读写内存和寄存器,如何能查询目标程序内的符号的呢?

下面是一个 OpenOCD 的启动日志,此时 gdb 还没有 attach 上来。

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
Open On-Chip Debugger 0.9.0 (2016-10-26-15:30)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : JLink SWD mode enabled
swd
adapter speed: 10000 kHz
adapter_nsrst_delay: 100
adapter_nsrst_delay: 100
none separate
cortex_m reset_config sysresetreq
jtag_init
Info : J-Link V9 compiled Sep 1 2016 18:29:50
Info : J-Link caps 0xb9ff7bbf
Info : J-Link hw version 94000
Info : J-Link hw type J-Link
Info : J-Link max mem block 69920
Info : J-Link configuration
Info : USB-Address: 0x0
Info : Kickstart power on JTAG-pin 19: 0xffffffff
Info : Vref = 3.312 TCK = 0 TDI = 0 TDO = 0 TMS = 1 SRST = 1 TRST = 0
Info : J-Link JTAG Interface ready
Info : clock speed 10000 kHz
Info : SWD IDCODE 0x2ba01477
Info : stm32f4x.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : accepting 'gdb' connection on tcp/3333
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x08000034 msp: 0x2000dd1c

可以看出,此时 OpenOCD 还探测不到目标所运行的 OS。

在 gdb attach 上以后,OpenOCD 日志如下:

1
2
3
Info : device id = 0x10006431
Info : flash size = 512kbytes
Info : Auto-detected RTOS: FreeRTOS

可以看出,在 gdb attach 上以后,OpenOCD 才探测出目标所使用的 OS 是 FreeRTOS。

不难猜测,OpenOCD 应该是查询 gdb 所加载的 ELF 文件中的符号表来探测 OS 的。

那么 OpenOCD 如何能查询到 ELF 文件内的符号表呢?

原来 OpenOCD 可以向 gdb 发送查询符号命令 - qSymbol:sym_name,来查询 ELF 文件内的符号地址。

gdb 文档中关于此部分的说明如下:

‘qSymbol:sym_name’
The target requests the value of symbol sym name (hex encoded). gdb may provide the value by using the ‘qSymbol:sym_value:sym_name’ message, described below.
‘qSymbol:sym_value:sym_name’
Set the value of sym name to sym value.
sym name (hex encoded) is the name of a symbol whose value the target has previously requested.
sym value (hex) is the value for symbol sym name. If gdb cannot supply a value for sym name, then this eld will be empty.

用 wireshark 抓取 gdb attach 时的 gdb 和 OpenOCD 的通信包,其中有一段即是查询符号的部分:

1
2
3
4
$qSymbol:5f74785f7468726561645f63757272656e745f707472
$qSymbol::5f74785f7468726561645f63757272656e745f707472
$qSymbol:757843757272656e744e756d6265724f665461736b73
$qSymbol:20000b6c:757843757272656e744e756d6265724f665461736b73

OpenOCD 首先发出 qSymbol 命令,数据是 5f74785f7468726561645f63757272656e745f707472,转化成 ASCII 码是 _tx_thread_current_ptr,这是 ThreadX 的 symbol,因为我们的目标运行的是 FreeRTOS,所以 gdb 回复的 sym_value 是空的,代表没有这个符号。

然后 OpenOCD 查询 uxCurrentNumberOfTasks,gdb 回复中的 sym_value 的值是 20000b6c,即 uxCurrentNumberOfTasks 的地址。

坚持原创技术分享,您的支持将鼓励我继续创作!