Список наиболее используемых команд gdb

Ниже я привожу не полный список команд отладчика arm-none-eabi-gdb, а описываю только те, которыми постоянно пользуюсь.

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

Вообще базовых команд у отладчика не очень много. Меня больше напрягает разнообразие их модификаций. И по первости, когда я ещё начинал осваивать эту технологию (особенно после IAR-овских мышкотыканий), для меня было довольно-таки непривычно — что-то там набирать «ручками-ручками». Это уж потом, значительно позже я понял преимущество такого подхода. А пока — да, пока я осваивал эту технологию, я испытывал определённый дискомфорт.

Я так думаю, что это не окончательный вариант статьи. Я начал её писать, и понял, что я наверняка буду в неё добавлять и добавлять разные полезные вкусности.

Нучо, пассажиры, понеслась?!

Запуск отладчика

Вход в отладчик, понятно, осуществляется вводом команды

$ arm-none-eabi-gdb

в окне терминала.

Выход из отладчика — вводом команды quit. Но мне больше нравится выход по нажатию на Ctrl-D.

Это Линукс! Ctrl-D — это конец файла. Другими словами, это сообщение программам, что больше ни каких байтов поступать не будет. Я уже не раз говорил, что «в Линуксе всё есть файл». Клавиатурный ввод — это тоже файл. Всё изумительно — если вы замечаете, что ваши клавиатурные пассы повторяются раз за разом, запишите их в дисковый файл, а потом «скармливайте» его программе. Ей-то какая разница — всё есть файл!

Команда target remote :4242 производит подключение к серверу st-util (сервер на openOCD обычно прослушивает порт 3333).

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

Заметьте, что при выходе из отладчика, сервак тоже прекращает свою работу.

Если вам так сильно приспичило зачем-то выйти в оболочку, но при этом будет обидно, что сервак тоже прекратит свою работу, в этом случае выход в оболочку можно осуществит временно. Делается это командой (восклицательный знак):

(dgb) !

Чтобы обратно попасть в отладчик, нужно указать оболочке, что «Типа всё! Не жди! Больше команд не будет». Ну вы поняли! Нужно нажать на Ctrl-D. Ну кому нравится, можете в оболочке набрать команду exit.

К стати, если вам нужно выйти в оболочку для исполнения только одной команды, то это можно сделать сразу в среде отладчика (то есть, не выходя в оболочку). Просто за восклицательным знаком введите свою команду. Например, так:

(dgb) ! ls -al

Запуск отладчика можно осуществить сразу с указанием файла программы:

$ arm-none-eabi-gdb myproga.elf

Но это необязательно, программу можно загрузить и позже. Команда

(gdb) file myproga.elf

загружает в отладчик файл символов программы.

Кроме того, если при этом нужно ещё и подновить прошивку микроконтроллера, то воспользуйтесь командой load, которая произведет заливку кодов программы в микроконтроллер. Если вы при запуске отладчика или в команде file уже указали имя .elf-файла, то повторно в команде load его можно не указывать.

(gdb) load

Точки останова

Для установки точек останова используется команда break. Для начала, я приведу несколько примеров использования этой команды:

(gdb) break main

— установка точки останова в самом начале работы программы — на входе в функцию main().

(gdb) break w5100_sendPacket

— установка точки останова при входе в функцию w5100_sendPacket

(dbd) break hal.c:45

— установка точки останова где-то в коде программе, конкретно на сорок пятой строке в файле hal.c

Иногда бывает так, что нужно пропустить первые несколько остановов в программе. Ну, допустим, мы хотим остановиться при повторном входе в функцию. Первый раз (первый вход) мы желаем пройти сразу, без остановок. Тогда команда для установки точки останова будет выглядеть так:

(gdb) break UASART1_IRQHandler 1

Здесь цифра 1 в конце команды говорит сколько раз нужно проигнорировать точку останова. Если вас напрягает слишком длинное имя функции (обработчика прерывания), и вы думаете «О-о, как же это тоскливо набирать эту колбасу руками!», то вы просто забыли про клавишу Tab.

Для «одноразовых» точек останова, существует отдельная команда tbreak. Эта команда установит точку останова, которая сработает только один раз.

Чтобы посмотреть, какие вообще точки останова в программе установлены, нужно выполнить команду:

(gbd) info breakpoints

(Вы не забыли про Tab?)

Команда delete без параметров удалит все точки останова, но перед этим запросит у вас подтверждение на это действие.

Точки останова, получаемые в команде info breakpoints, пронумерованы. Для удаления конкретной точки останова нужно в команде delete указать её номер. Ничего сложного!

Команда clear удаляет точку останова по её названию — как она была обозначена в команде break при её установке.

Я не раскрываю всех «секретов» команд, говорю только о тех фичах, которыми сам пользуюсь. Но вообще в дебаггере существует система помощи. Общая помощь вызывается командой help. Но если вы хотите получить помощь по конкретной команде, допустим, по команде clear, то так и пишите:

(gdb) help clear

Исполнение кода программы

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

Опять же! Не надо набирать на клавиатуре имя команды полностью — можно набрать только «cont» и нажать на Tab. А можно и на Tab не нажимать — если команда идентифицируется однозначно по первым её буквам, то отладчик сам разберётся, какую команду вы хотели ввести, да поленились.

Более того, у команды существует её однобуквенный дублёр — команда c.

Остановить работу программы можно нажатием Ctrl-C.

Когда возникает необходимость осуществить сброс микроконтроллера и начать исполнение кода с самого начала, то следует применять команду:

(gdb) monitor reset

Это не совсем команда отладчика. Скорее, это команда для сервера.

Команда step позволяет выполнить одну команду (строку в Си-шном коде). Если это будет вызов функции, то команда «зайдет» в функцию. Существует сокращенное имя команды — всего одна буква s.

Комянда next также выполняет одну команду (строку в Си-шном коде). Разница только в том, что если это вызов функции, то на этот раз в функцию мы не заходим, а выполняем её целиком как одну команду — за один шаг. У этой команды так же есть однобуквенный эквивалент — n.

Следует заметить, что нет необходимости каждый раз набирать последнюю введенную команду — достаточно просто нажать Enter (в пустой строке), и отладчик повторит предыдущую команду. Таким образом, прохождение программы по шагам сводится к периодическим нажатиям на Enter.

Команды backtrace и where, кажись, работают одинаково. Я не углублялся в тему их различий. Они «разматывают» стек вызовов вплоть до самого низа. Иногда это бывает очень полено знать, кто кого вызвал и какие параметры при этом передал. Ну, представьте себе, ваша прога остановилась в точке останова или вы тупо нажали на Ctrl-C. Улавливаете мысль?

Команда up позволяет подняться по стеку на один стековый кадр (фрейм) выше. Соответственно, команда down опускает на один кадр вниз.

Инспекция переменных

В процессе отладки всегда бывают моменты, когда нужно знать значение той или иной переменной. Вообще, посмотреть значение переменной можно командой print. Например, в некоторой функции, допустим, имеется какой-то цикл, в котором используется некоторая переменная i. Тогда посмотреть текущее значение переменной можно с помощью команды:

(gdb) print i

Для особо ленивых существует сокращение:

(gdb) p i

Иногда бывает так, что значение переменной нужно отображать не в десятичном, а в 16-ричном формате. Тогда в команде print нужно указать формат вывода:

(gdb) print /x i

здесь /x говорит о том, что значение переменной i должно быть напечатано в hex-виде. Вообще, существуют и другие форматы — двоичный, восьмеричный и так далее.

Уже проинспектированные переменные не надо просматривать повторным вводом команды. При первой инспекции отладчик сообщает (хэшевый) номер переменной. При следующих просмотрах этой переменной нужно указывать только её хэшь-номер, а не её имя. Осуществляется это командой:

(gdb) $n

здесь вместо n нужно подставлять число — номер переменной.

В процессе отладки программ у меня часто возникают ситуации, когда по достижению некоторой точки останова, мне нужно знать значение той или иной переменной. Затем, я прохожу какой-то участок программы по шагам. В процессе пошагового прохода я хочу видеть изменение этой переменной. Тогда я ввожу команду display, которая укажет отладчику, что бы он каждый раз выводил значение указанной переменной.

Например, меня интересует изменение переменной цикла. Я выполняю команду:

(gdb) display i

И теперь при каждом останове (по шагам ли, или по достижении точки останова) отладчик автоматически будет печатать на экране значение этой переменной.

При работе с микроконтроллерами часто встречаются ситуации, когда нужно знать не значение какой-то переменной в программе, а знать значение, записанное по какому-то адресу. Ну, например, нужно знать состояние регистра состояния. (У-у, блин, как сказал!)

Для обращения к памяти по конкретному адресу служит однобуквенная команда х. Например, в процессе отладки программного кода для модуля SPI1 я часто пользовался командой:

(gdb) x /3wx 0x40013000

— Ну чо, сложно?!

Да, не-е! Сейчас всё объясню.

Первый x (икс) вы уже знаете, что это такое — это команда. Последнее длинное 16-ричное число — это базовый адрес регистров модуля SPI1.

Теперь остановимся подробнее не конструкции /3wx. Здесь x обозначает формат вывода: мы запрашиваем вывод в hex-формате. Параметр w говорит о том, что выводится будут четырех-байтовые «кирпичи» (word, 32 разряда). А вот цифра 3 — это количество таких «кирпичей».

Почему три «кирпича», а не, допустим, четыре? Почему кирпичи 32-хразрядные, а не 16-разрядные?

Ну, во первых, можно заказать вывод и 16-разрядных «кирпичей» — не проблема! Тем более, что размерность регистров у модуля SPI двубайтовая.

Но, вот, если посмотреть карту распределения памяти STM32, то видно, что регистры расположены по 4-х байтовой границе. Поэтому удобнее «заказывать» 4-х байтовые куски.

Регистр SPI_CR1 находится по адресу 0x40013000.
Регистр SPI_CR2 находится по адресу 0x40013004.
Регистр состояния SPI_SR — по адресу 0x40013008.

Для анализа мне нужны были только эти три регистра. Отсюда возникло число 3 в параметре команды. Было бы нужно 4 «кирпича», написал бы цифру 4.

Если же указывать формат вывода для 16-разрядных «кирпичей», то «кирпичей» понадобится не три, а шесть штук. Надеюсь, понятно объясняю. А это, мне показалось, — не совсем удобно, поэтому я заказал «три по 32», а не «шесть по 16».

Ну, кажись, основные команды я описал. Есть ещё одна полезная команда — команда просмотра регистров РОН (Регистров Общего Назначения) ядра:

(gdb) info registers

Для отладки на уровне Си она не очень много даёт. Максимальная польза от её применения получается, когда отлаживание программы опускается до уровня машинных кодов, до уровня ассемблерных команд.

— — —

И, пожалуй, на этом всё! Возможно, сюда я буду ещё что-нибудь добавлять, но когда и чего — обещать не могу. А вообще, самое разумное освоение новых технологий — это практика. Первую, самую трудную ступенечку, я вам помог преодолеть, а дальше вы как-нибудь уж сами — ручками-ручками, ножками-ножками.

2 responses to “Список наиболее используемых команд gdb

  1. Кому совсем-совсема плохо есть cgdb или вообще NEMIVER )

  2. Я чёт не знаю примеров применения CGDB кросс-отладки, в частности для отладки stm32.

    Думаю для работы с STM32 надо CGDB как-то специально компилировать, с какими-нибудь флагами типа —target=cortex-m3 или что-то в этом роде.

    А про NEMIVER вообще не слышал.

    Да. Надо будет как-нибудь полистать интернет.

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s