如何使用 gdb 在目标 ARM MCU 上调试闪存程序

Posted

技术标签:

【中文标题】如何使用 gdb 在目标 ARM MCU 上调试闪存程序【英文标题】:How to debug a flash program on target ARM MCU with gdb 【发布时间】:2021-04-24 22:09:00 【问题描述】:

我正在尝试使用 gdb 在目标 MCU 上调试 ARM 闪存程序

我正在使用jlinkgdbserver 在目标系统 (cortex-m7) 上设置 gdbserver。我已经准备好调试精灵了。

第一次用下面的方法调试就可以了

> arm-none-eabi-gdb flash_program.elf
(gdb)> target remote localhost:2331     # connect to gdb server on target
(gdb)> load                             # since it is a flash program, jlink will flash the program
                                        # target is reset to elf entry point
(gdb)> .... (debugging begins)

但是,当调试到某个地方时,我想再次从入口点调试,我想出的方法是再次刷新

(gdb)> Ctrl+D               # disconnect the gdbserver
> arm-none-eabi-gdb flash_program.elf
(gdb)> target remote localhost:2331
(gdb)> load
(gdb)> .... (debugging from start again)

所以这似乎有点多余,而且它一次又一次地擦除和编程相同的闪存区域,我担心我最终会通过调试损坏存储。

flash 程序已经烧录到介质中,我只是想让目标重新设置自己并再次从入口点运行。但我尝试了monitor resetrun 之类的东西。但是目标M7不能从头再来。

还有其他的 gdb 命令可以尝试吗?

【问题讨论】:

您使用的 Cortex-M7 的品牌/型号是什么?这将有助于为您提供准确的答案。 【参考方案1】:

我使用 STM32F103C8T6 来提供答案,但您只需将其 ROM 基地址 (0x20000000) 替换为 Cortex-M7 使用的地址:在我的例子中,我加载了堆栈指针来自0x20000000,程序计数器的初始值来自0x20000000+4

要调试的程序是stm32f103c8t6.elf,已经刷新并且确实包含调试符号。

arm-none-eabi-gdb

target remote localhost:2331
0x20000480 in ?? ()
(gdb) monitor halt
(gdb) monitor reset 0
Resets core & peripherals via SYSRESETREQ & VECTRESET bit.
(gdb) monitor reset 1
Resets the core only, not peripherals.
(gdb) monitor reset 2
Resets core & peripherals using RESET pin.
(gdb) symbol-file stm32f103c8t6.elf
Reading symbols from stm32f103c8t6.elf...
(gdb) set $sp = *0x20000000
(gdb) set $pc = *0x20000004
(gdb) stepi
0x200003c2      121     
(gdb)
0x200003c4      121     
(gdb) stepi
122       SystemInit();                             /* CMSIS System Initialization */
(gdb)
SystemInit () at /opt/arm/ARM.CMSIS.5.6.0//Device/ARM/ARMCM3/Source/system_ARMCM3.c:61
61      
(gdb)

根据您要使用的重置策略类型,您可能需要在monitor reset 命令中明确说明:

如 Segger 文档和 this great article 中所述,您可以使用策略编号 0、1 或 2:

# Normal
monitor reset
monitor reset 0

# Core
monitor reset 1

# ResetPin
monitor reset 2

我的理解是能否使用策略 #2 取决于您的 RESET 引脚的接线方式,即它是否在您的板上被下拉。

免责声明:我是一个软件人,所有与硬件相关的问题的解释错误都是我的......

【讨论】:

@Eric Sun:答案是否足够清楚,还是需要改进?谢谢。 感谢您的回答,我了解到您正在从 ROM 启动检索初始 SP 和 PC,并让代码再次从启动运行。但这与 HARD RESET 不同,后者会重新初始化所有寄存器和 SOC 模块。我在想是否有一些内置的 JTAG 重置命令可以实现这一点。 在这种情况下,我建议修改您的问题并使用您在评论中公开的“硬重置”注意事项来扩充But the target M7 both can't start from beginning again.。您可以通过发出“类型 2”复位来实现您的目标,如 this article 中所述,当然还有 JLink 文档的相应部分,具体取决于您的复位信号的连接方式。 我相应地扩充了我的答案,我认为它现在应该回答你的问题了。【参考方案2】:

gdb 命令load 将刷新图像,前提是您没有专门设置链接地址。 你有两种生存方式:

    设置链接地址/调整链接描述文件,使程序完全在RAM中。或者 保持地址不变,但每次代码更改和编译后,只使用一次load(以使闪存被编程),然后使用symbol-file 仅加载符号的命令。

【讨论】:

以上是关于如何使用 gdb 在目标 ARM MCU 上调试闪存程序的主要内容,如果未能解决你的问题,请参考以下文章

嵌入式arm linux环境中gdb+gdbserver调试

Hi35xx NVR GDB调试

Hi35xx NVR GDB调试

使用 Infineon XMC4800 MCU 和 Segger 进行 GDB 调试中断而无断点

GDB 调试器 - 未定义“malloc”。尝试使用调试器分配 C 数组

如何实现对ARM汇编指令的调试?