Отладка с помощью GDB

Для отладки микроконтроллерных устройств обычно применяются программно-аппаратные решения. К примеру для МК с ядром ARM это может быть связка J-Link((аппаратный отладчик по интерфейсу JTAG)) - OpenOCD((программная прослойка, между отладчиком и GDB)) - собственно сам ARM-GDB.

Подключается отладчик к процессорной плате через стандартный 20-пиновый JTAG разъём или через переходник к 14-и или 10-и пиновым разъёмам.

К компьютеру отладчик поключается через интерфейс USB.

JTAG интерфейс не поддерживает “горячего” подключения, поэтому для сохранности вашего устройства следует подключать отладчик к выключенному устройству, следующим шагом подключать отладчик к компьютеру (USB поддерживает “горячее” подключение), и последним шагом подавать питание на устройство. Источники питания устройства и компьютера должны быть надёжно соединены с единой “земляной” шиной.

Запуск OpenOCD

TODO

Запуск GDB

После того, как OpenOCD успешно запущен, можно подключиться к нему из GDB.

Сразу рассмотрим случай, что у нас есть скомпилированная с помощью soft:arm-none-eabi-gcc программа и получен файл firmware.elf.

Запускаем GDB для отладки файла:

$ arm-none-eabi-gdb firmware.elf

После того как появилось приглашение на ввод команды подключаемся к отладчику:

gdb> target remote :3333

Данная команда установит соединение с openocd по TCP-IP. :3333 это указание порта, на котором openocd ждёт соединение. По умолчанию подразумевается локальный IP адрес 127.0.0.1, но ничто не мешает указать адрес другого сетевого устройства к которому подключён отладчик и запущен openocd: target remote 192.168.0.100:3333.

Можно выполнить команду соединения при запуске отладчика:

arm-none-eabi-gdb -ex "target remote localhost:3333" firmware.elf

В простейшем случае мы можем остановить процессор и загрузить прошивку.

gdb> monitor reset halt
gdb> load

Команда monitor позволяет передавать команды непосредственно отладчику openocd.

Для МК STM32 потребуется предварительно стереть внутренний flash((это если Вы не скомпилировали программу для загрузки и исполнения из SRAM)).

gdb> monitor stm32f1x unlock 0
gdb> monitor stm32f1x mass_erase 0

Первая команда разлочивает нулевой блок flash, вторая - стирает его. Номера блоков приобретают актуальность только для MK c объёмом flash больше 512Кб.

В некоторых случаях может потребовать изменить тактовую частоту (JTCK) интерфейса JTAG:

gdb> monitor adapter_khz 500

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

gdb> monitor reset run

Обзор команд GDB

Сброс МК и останов ядра:

gdb> monitor reset halt

Запуск непрерывной отладки:

gdb> continue (cont)

Прервать выполнение программы можно в любой момент комбинацией Ctrl-C.

В скобках, здесь и далее указаны сокращённые имена команд.

Выполнение по шагам:

gdb> next (n)
gdb> nexti (ni)

Выполняет код без захода в функции. Отличие этих двух команд в том, что первая шагает по строкам исходного кода, а вторая по процессорным инструкциям.

Аналогчные командам next* команды step*, но при их выполнение производится заход в функции.

gdb> step (s)
gdb> stepi (si)

Что бы выполнить последнюю введённую команду ещё раз достаточно нажать Enter.

Быстро выполнить текущую функцию можно командой

gdb> finish (fin)

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

gdb> until (n)

Код будет выполняться до тех пор, пока номер строки не станет больше текущего.

Если у Вас многострочный цикл, следует пройти командами step/next до последней строки цикла, и после этого дать команду until.

Команда list (l) пролистает 10 строк вниз начиная с текущей. Для пролистывания вверх следует дать команду list -

gdb> list  
gdb> list -

Что бы определить точку останова воспользуйтесь командой break

gdb> break main

Установит точку останова по имени функции.

gdb> break 345

Установит точку останова на линию в текущем файле исходного кода. Указание числа с префиксами +/- установит относительную точку останова. Можно указать конкретный файл с исходным кодом.

gdb> break main.c:345

Можно установить точку останова на конкретный аппаратный адрес:

gdb> break *0x00202000

Следует иметь в виду, что ядра ARM могут использовать аппаратные breakpoint и watchpoint - т.е. точки, производящие останов программы без изменения бинарного кода, но их количество ограничено (зависит от типа ядра). Имейте в виду это, при отладке программ записанных во flash память. Программы записанные в SRAM могут использовать программные точки останова.

Просмотреть заданные точки останова можно командой:

gdb> info breakpoints (i b)

После получения этой информации можно удалить, временно запретить или разрешить точку останова:

gdb> delete breakpoint 1 (d b 1)
gdb> disable breakpoint 2
gdb> enable breakpoint 2

Для контроля за изменениями переменных используется команды watch (wa), rwatch (rw), awatch (aw).

gdb> watch my_variable
gdb> watch *0x00101234
gdb> rwatch my_var
gdb> awatch my_var

Первая команда устанавливает контроль записи в переменную. Вторая - контроль записи по определённому адресу. Третья доступ на чтение. И последняя при любом виде доступа (чтение и запись).

Когда программа остановлена возникает естественное желание просмотреть значение переменных.

gdb> print my_variable (p)

Покажет значение переменной my_variable.

Если есть желание постоянно отслеживать значение некоторой переменной следует добавить её в дисплей.

gdb> display my_variable

Теперь значение my_variable будет выводится при каждом останове программы.

По аналогии с точками останова можно просматривать, разрешать, запрещать и удалять переменные из дисплея.

gdb> info display
gdb> delete display 1 (undisplay)
gdb> enable display 2
gdb> disable display 2

Присваивание нового значения переменной производится командами set и print:

gdb> set x:=x+2
gdb> print x:=10

Иногда полезно просмотреть состояние регистров процессора:

gdb> info registers (i r)
gdb> monitor reg

Вторая команда производит запрос состояния регистров через openocd.

Посмотреть состояние стека поможет команда:

gdb> backtrace (b)

Для исследования произвольных областей памяти используется команда x

gdb> x/32i

Дизассемблирует 32 команды начиная с текущего адреса. Можно указать конкретный адрес x/32i 0x00100000 или взять адрес из регистра x/32i $lr.

gdb> x/8b 0x00200000
gdb> x/8c 0x00200000
gdb> x/8h 0x00200000
gdb> x/8w 0x00200000

Выведет по восемь элементов из памяти. Соответственно байт, символов, полуслов (2 байта) и слов (4 байта)

DDD

ddd - графическая оболочка для gdb. Позволяет оперативно отображать текущий исходный код, дизассемблированный бинарный код, переменные из дисплея, регистры, стек вызовов и многое другое.

Для того, что бы ddd использовал отладчик для ARM следует указать его:

ddd --debugger arm-none-eabi-gdb firmware.elf

Дополнительно

 
comments powered by Disqus