Как стать автором
Обновить

Пошаговая GDB отладка ARM процессора из консоли в Win10

Время на прочтение7 мин
Количество просмотров8.1K

Типичная ситуация. Компонент логирования и UART(Universal Asynchronous Receiver/Transmitter) не проинициализировался корректно или устройство где-то зависло в инициализации после reset. Или устройство бесконечно перезагружается после подачи питания. Как же понять на какой строчке возникла run-time ошибка? Классическое решение это пошаговая отладка через JTAG(Joint Test Action Group) или SWD(Serial Wire Debug).

Немного про железо. Работать буду с платой nRF5340-DK. Её блок-схема.

Отладочная плата nRF5340-DK
Отладочная плата nRF5340-DK

Тут на board(e) как программатор U2 так и сам микроконтроллер U1 (Target). Оба 94pin(новые) nrf5340 в корпусе aQFN94. Соединены они интерфейсом SWD. Внутри каждого по 2 ядра Arm Cortex-M33 (Armv8-M). На улицу также выходит 2 UART(а) для интерфейса командной строки. Они же пробрасываются по USB (J2) на DeskTop.

Что понадобится из софта?

Утилита

Назначение

Path

arm-none-eabi-gdb.exe

GDB Client для ARM

C:\Program Files (x86)\GNU Arm Embedded Toolchain\10 2021.10\bin

JLinkGDBServer.exe

GDB Server

C:\Program Files (x86)\SEGGER\JLink\

nrfjprog.exe

Прошивальщик микроконтроллера

C:\Program Files (x86)\Nordic Semiconductor\nrf-command-line-tools\bin

ttermpro.exe

Терминал COM портов

C:\Program Files (x86)\teraterm

Этого должно быть достаточно.

Фаза 1 Залить прошивку в Target

Это можно проделать вот этим скриптом

echo off
cls

set com_port_num=10
set baudrate=115200
set project_name=headset_app
set project_dir=%~dp0
set NRF_SDK_DIR=C:/ncs/v2.1.0

set SDK_PROJECT_DIR=%NRF_SDK_DIR%/nrf/applications/nrf5340_dk_audio_w
IF "%1"=="" (
    echo set dflt SDK ver 
    set ARTEFACT_HEX=%SDK_PROJECT_DIR%\build\headset_app\zephyr\zephyr.hex
) ELSE (
    echo set dflt SDK from argument 
    set ARTEFACT_HEX=%1
)
echo Artefact hex: [%ARTEFACT_HEX%]


set tools_dir=%cd%\..\..\..\tool
echo Project Dir:%project_dir%

set FlashTool="C:\Program Files (x86)\Nordic Semiconductor\nrf-command-line-tools\bin\nrfjprog.exe"

set options=--iface USB --family NRF53 --coprocessor CP_APPLICATION --program %ARTEFACT_HEX%  --log --chiperase --verify --reset 
call %FlashTool% %options%
echo tools_dir=%tools_dir%

call %tools_dir%\launch_terminal.bat 9 %baudrate% %project_name%
call %tools_dir%\launch_terminal.bat 10 %baudrate% %project_name%

Примерно вот такой должен быть лог успешной загрузки прошивки в терминале cmd.exe

set dflt SDK ver
Artefact hex: [C:/ncs/v2.1.0/XXX/zephyr/zephyr.hex]
Project Dir:C:/XXX/
Parsing image file.
Verifying programming.
Verified OK.
Applying system reset.
Run.
tools_dir=C:/XXX/tools
>
>

Отработав, этот скрипт загрузит прошивку в On-Chip NorFlash микроконтроллера nrf5340 U1.

Фаза 2. Запуск GDB сервера (Back-End)

GDB(GNU DeBugger) сервер это утилита, которая опрашивает программатор-отладчик. Именно она общается с устройством. Надо запустить GDB сервер. Вот скрипт запуска этой утилиты.

 
echo off
cls
set GDBServerOpt = -select USB -device nRF5340_xxAA_APP -endian little -if SWD -speed 400 -ir -LocalhostOnly -logtofile -log "C:\projects\code_base_workspace\code_base_firmware\tool\GdbServerLog.txt"

set GDBServerDir="C:\Program Files (x86)\SEGGER\JLink\"
set GDBServerPath=%GDBServerDir%JLinkGDBServer.exe"
cd %GDBServerDir%
call %GDBServerPath% %GDBServerOpt%

Надо установить интерфейс связи программатора и микроконтроллера, который мы хотим отлаживать. В данном случае это интерфейс SWD.

J-link попросит выбрать микроконтроллер

список поддерживаесых чипов очень большой

В моем случае чип nrf5340

GDB сервер J-Link запущен локально. Программатор (S/N: 1050009032) подключен по USB. Target подключен к программатору по SWD.

вот полный лог ожидающего GDB сервера

Hidden text

SEGGER J-Link GDB Server V7.66a GUI Version

JLinkARM.dll V7.66a (DLL compiled May 19 2022 15:13:27)

-----GDB Server start settings-----
GDBInit file: none
GDB Server Listening port: 2331
SWO raw output listening port: 2332
Terminal I/O port: 2333
Accept remote connection: localhost only
Generate logfile: off
Verify download: off
Init regs on start: off
Silent mode: off
Single run mode: off
Target connection timeout: 5000 ms
------J-Link related settings------
J-Link Host interface: USB
J-Link script: none
J-Link settings file: none
------Target related settings------
Target device: Unspecified
Target interface: SWD
Target interface speed: 4000kHz
Target endian: little

Connecting to J-Link...
J-Link is connected.
Firmware: J-Link OB-nRF5340-NordicSemi compiled Dec 3 2021 15:46:49
Hardware: V1.00
S/N: 1050009032
Checking target voltage...
Target voltage: 3.30 V
Listening on TCP/IP port 2331
Connecting to target...
Connected to target
Waiting for GDB connection...

Сейчас GDB сервер просто ожидает подключения по TCP порту: 2331

На отладочной плате nRF5340-DK, есть встроенный программатор J-Link и там сейчас непрерывно светится зеленый LED, от отладчика.

Фаза 3 Запуск GDB клиента (Front-End )

Если GDB сервер можно метафорично считать Back-End(ом), то Front-End частью для пошаговой отладки выступает GDB клиент. Вот скрипт его запуска.


"C:\Program Files (x86)\GNU Arm Embedded Toolchain\10 2021.10\bin\arm-none-eabi-gdb.exe" --help
"C:\Program Files (x86)\GNU Arm Embedded Toolchain\10 2021.10\bin\arm-none-eabi-gdb.exe"  C:/ncs/v2.1.0/nrf/applications/nrf5340_dk_audio_w/build/headset_app/zephyr/zephyr.elf

GDB клиент смог подхватить *.elf файл с отладочными символами

Настало время подключиться к GDB серверу. Это делается командой.

target remote localhost:2331

Сработало

Подключился. Сейчас исполнение прошивки на паузе. HeartBeat LED не мигает, UART-Shell не отвечает.

Самая полезная команда консольного GDB это команда bt (backtrace). Именно эту команду надо выполнить первой. Так как скорее всего вы запустили GDB чтобы выявить причину зависания. И команда bt сразу вам покажет на какой строчке прошивка свалилась в исключение.

Для запуска прошивки надо набрать команду continue

Теперь HeartBeat LED мигает CLI отвечает. LED на программаторе тоже мигает только как-то апериодично.

Для того чтобы снова остановить исполнение программы надо в терминале GDB клиента нажать Ctrl+C.

Теперь можно установить точку останова. Меня интересует функция bool hw_init(void)

(gdb) break hw_init

Посмотреть список установленных точек останова можно командой

(gdb) info b

Вот это сейчас отображается

Снова запускает программу на исполнение. Команда c

(gdb) c

Но вот незадача. Точка останова установлена внутри функции инициализации, которая уже давным-давно исполнилась. Что же делать? Надо как-то перезагрузить Target, чтобы инициализация снова отработала.

Вот тут-то нам как раз поможет еще один терминал. Это терминал командной строки поверх UART реализованный прямо внутри прошивки на Target(е). Я просто открою TeraTerm.exe и попрошу Zephyr-based прошивку перезагрузиться встроенной командой из UART CLI.

-> kernel reboot cold

и устройство в самом деле перезагружается!

При этом я даже от клавиатуры рук не отводил. И вот как раз отладчик и зацепил функцию bool hw_init(void). Это называется синергия GDB и UART-CLI. Успех.

Выполнить одну строчку кода можно командой n (next). Посмотреть содержимое локальный переменный можно командой info locals

Зайти внутрь функции можно командой s (step).

Само собой, в консоли GDB клиента есть история команд, и вы можете стрелками вверх/ вниз на клавиатуре набирать уже используемые в прошлом команды.

Чтобы выйти из GDB клиента достаточно набрать в его консоли команду q (quit). Target все еще suspended. Поэтому также надо закрыть GDB сервер. Только после этого Target станет resumed и продолжит исполнять свой код.

В последующем можно запустить GDB сервер и GDB клиент одним единственным скриптом.

echo off
cls

set FIRMWARE_FILE=C:/ncs/v2.1.0/nrf/applications/nrf5340_dk_audio_w/build/headset_app/zephyr/zephyr.elf
set GDB_CLIENT="C:\Program Files (x86)\GNU Arm Embedded Toolchain\10 2021.10\bin\arm-none-eabi-gdb.exe"

set tools_dir=%cd%\..\..\..\tool
start %tools_dir%\0_LaunchGdbServerNrfAppCore.bat


%GDB_CLIENT% --help
%GDB_CLIENT% %FIRMWARE_FILE%

Суммируя вышесказанное, весь процесс можно объяснить вот такой простецкой схемой на одном листе.

Также небольшая шпаргалка по наиболее употребительным командам консольного GDB клиента

short

full

description

-

info args

Show current function arguments

i b

info b

List all breakpoints

bt

backtrace

show function call stack

n

next

Step over functions

f

finish

Execute the rest of the current function. Step out of the current function.

s

step

Step into functions

p count

Print the value of a variable count

c

continue

Continue execution up to the next breakpoint or until termination if no breakpoints are encountered

-

delete n

Delete breakpoint number n

-

info locals

show local variables

tar rem:2331

target remote localhost:2331

Connect to J-Link

q

quit

quit gdb

b function

Set a breakpoint at the beginning of function

Буду также обновлять реестр команд консольного GDB клиента google spreadsheets.
https://docs.google.com/spreadsheets/d/1AWD8GsDfaA9dtdsfqgbB1klagou1yrREc1AAK9CRUik/edit#gid=0
Там проще навигация благодаря наличию сортировки по столбцам и раскраске ячеек

Вывод

Вот теперь вы умеете делать пошаговую DBG отладку из консоли и можете учить этому других. Как видите в GDB отладке через консоль нет вообще ничего сложного. Как по мне, дак, всякие там циклопические и дорогущие IDE(Integrated development environment) для пошаговой отладки не особо-то и нужны как бы.

Консоль даже лучше в том смысле, что внимание концентрируется на сути (коде), а не на стразиках из оформления GUI(ни) от IDE. Можно вообще отлаживать без кода, просто получив по почте один лишь *.elf файл, а все сорцы собирать на удаленном защищенном сервере.
Тем более в консольном отладчике, как правило, не надо проводить много времени. Подключился, выполнил bt понял где зависла программа, отключился. Вот и всё. Easy.

Потом, написав один набор скриптов запуска GDB, в консоли можно пошагово отлаживать микроконтроллеры абсолютно любого вендора: STM32(ST), nRF5x(NS), CC26x2(TI), MDR32(M), LPC21xx (NXP). Меняться будут только GDB серверы. Всё остальное одинаково у всех.

При этом накладные расходы на установку Toolchain(а) для консольной пошаговой отладки минимальные и всё абсолютно бесплатно. Вам уже нравится GDB?

Links

https://condor.depaul.edu/glancast/373class/docs/gdb.html#Setting_Breakpoints

https://habr.com/ru/post/259205/

https://habr.com/ru/post/181738/
https://habr.com/ru/post/535960/
https://habr.com/ru/post/546216/
https://mcuoneclipse.com/2015/03/25/command-line-programming-and-debugging-with-gdb/
https://www.electricmonk.nl/docs/gdb_debugging/gdb_debugging.html

Вопрос *

Как работает механизм установки точек останова JTAG под капотом?

Акроним

Расшифровка

GDB

The GNU Project Debugger

GUI

graphical user interface

IDE

integrated development environment

JTAG

Joint Test Action Group

UART

universal asynchronous receiver / transmitter

CLI

command-line interface

SWD

Serial Wire Debug

ARM

Advanced RISC Machine

RISC

reduced instruction set computer

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Вы практикуете пошаговую отладку?
92.98% да53
7.02% нет4
Проголосовали 57 пользователей. Воздержались 2 пользователя.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Вы практикуете пошаговую отладку через командную строку?
15.25% да9
84.75% нет50
Проголосовали 59 пользователей. Воздержались 2 пользователя.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Вы практикуете пошаговую отладку через IDE?
90% да54
10% нет6
Проголосовали 60 пользователей. Воздержались 2 пользователя.
Теги:
Хабы:
Всего голосов 14: ↑12 и ↓2+10
Комментарии25

Публикации