Перейти к содержимому

Как пользоваться отладчиком gdb

  • автор:

Как пользоваться отладчиком gdb

GDB предоставляет все перечисленные возможности. Он называется отладчиком на уровне исходного текста, создавая иллюзию, что Вы выполняете операторы C++ из Вашей программы, а не машинный код, в который они действительно транслируются.

Для иллюстрации мы используем систему, которая компилирует программы на C++ в исполняемые файлы, содержащие машинный код. В результате этого процесса информация об оригинальном коде C++ теряется при трансляции. Отдельный оператор C++ обычно преобразуется в несколько машинных команд, а большинство имен локальных переменных просто теряется. Информация о именах переменных и операторах C++ в Вашей исходной программе не является необходимой для ее выполнения. Поэтому, для правильной работы отладчика на уровне исходного текста, компилятор должен поместить в программу некоторую дополнительную информацию. Обычно ее добавляют к информации, используемой компоновщиком, в исполняемый файл.

Чтобы указать компилятору (gcc), что Вы планируете отлаживать Вашу программу, и поэтому нуждаетесь в дополнительной информации, добавьте ключ -g в опции компиляции и компоновки. Например, если Ваша программа состоит из двух файлов main.C и utils.C, Вы можете откомпилировать ее командами

gcc -c -g -Wall main.C gcc -c -g -Wall utils.C gcc -g -o myprog main.ob utils.o

или одной командой

gcc -g -Wall -o myprog main.o utils.o

Обе последовательности команд приводят к созданию исполняемого файла myprog.

чтобы выполнить полученную программу под управлением gdb, введите

Вы увидите командное приглашение GDB:

Это очень простой, но эффективный тексовый интерфейс отладчика. Его вполне достаточно, чтобы ознакомиться с основными командами gdb.

Когда GDB запускается, Ваша программа в нем еще не выполняется; Вы должны сами сообщить GDB, когда ее запустить. Как только программа приостанавливается в процессе выполнения, GDB ищет определенную строку исходной программы с вызовом определенной функции — либо строку в программе, где произошел останов, либо строку, содержащую вызов функции, в которой произошел останов, либо строку с вызовом функции и т.д. Далее используется термин «текущее окно» , чтобы сослаться на точку останова.

Как только возникает командное приглашение, Вы можете использовать следующие команды. help command

Выводит краткое описание команды GDB. Просто help выдает список доступных разделов справки.

Запускает Вашу программу с определенными аргументами командной строки. GDB запоминает переданные аргументы, и простой перезапуск программы с помощью run приводит к использованию этих аргументов.

Создает трассу — цепочку вызовов функций, произошедших до попадания программы в текущее место. Синонимом является команда bt.

Перемещает текущее окно так, чтобы GDB анализировал место, из которого произошел вызов данного окна. Очень часто Ваша программа может войти в библиотечную функцию — такую, для которой не доступен исходный код, например, в процедуру ввода-вывода. Вам может понадобиться несколько команд up , чтобы перейти в точку программы, которая была выполнена последней.

Производит эффект, обратный up.

Выводит значение E в текущем окне программы, где E является выражением C++ (обычно просто переменной). Каждый раз при использовании этой команды, GDB нумерует ее упоминание для будущих ссылок. Например,

(gdb) print A[i] $2 = -16

(gdb) print $2 + ML $3 = -9

сообщает нам, что величина A[i] в текущем окне равна -16, и что при добавлении этого значения к переменной ML получится -9.

Если программа запущена через оболочку shell, Ctrl-c немедленно прекращает ее выполнение. В GDB программа приостанавливается, пока ее выполнение не возобновится.

Установить точку останова; программа приостановится при ее достижении. Простейший способ — установить точку останова после входа в функцию, например

(gdb) break MungeData Breakpoint 1 at 0x22a4: file main.C, line 16.

Команда break main остановит выполнение в начале программы.

Вы можете установить точки останова на определенную строку исходного кода:

(gdb) break 19 Breakpoint 2 at 0x2290: file main.C, line 19.

(gdb) break utils.C:55 Breakpoint 3 at 0x3778: file utils.C, line 55.

Когда Вы запустите программу и она достигнет точки останова, Вы увидите сообщение об этом и приглашение, например

Breakpoint 1, MungeData (A=0x6110, N=7) at main.c:16

Удаляет точку останова с номером N. Если опустить N, будут удалены все точки останова.

cont или continue

Продолжает обычное выполнение программы.

Выполняет текущую строку программы и останавливается на следующем операторе для выполнения.

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

Выполняет команды next без остановки, пока не достигнет конца текущей функции.


Next: Интерфейсы gdb и другие Up: Средства программирования в ОС Previous: Ассемблеры gas и nasm Contents Index Alex Otwagin 2002-12-16

Использование отладчика GDB

В вебинарах «Linux разработка на языке си. Изучаем основное API.» Было кратко упомянуто о gdb-отладчике. Но за 40 минут осветить хотя бы основные моменты использования отладчика не представляется возможным. Поэтому было принято решение записать открытое видео по отладчику gdb. Полезна будет всем кто начинает разбираться в программировании встроенных систем на Linux.

Видеолекция включает в себя использование популярного отладчика *nix системах и разбираются основные темы:

1. Пример отладки простейшей программы.

  • Основные команды.
  • Точки останова (по переменным, по строкам).
  • Переменные, массивы.

2. Дизассемблирование. (в т.ч. и других архитектур).
3. Многопоточная отладка.
4. Отладка дочерних программ.
5. Подключение к работающему процессу.
6. Удалённая отладка. (в т.ч. и других архитектур)
7. Отладка с дампом ядра.

Программы, использованные в видео обитают тут:
Github

Если есть интерес освоить программирование в *nix системах или даже написание модулей ядра (драйверов), то вы можете следить за предстоящими событиями в блоге Сереги, либо написать ему по почте dlinyj(с)gmail.com и вы получите уведомление обо всех планируемых вебинарах. Также он продает записи прошлых вебинаров. А это многие часы видео плото набитых инфой пр программированию в linux.

Спасибо. Вы потрясающие! Всего за месяц мы собрали нужную сумму в 500000 на хоккейную коробку для детского дома Аистенок. Из которых 125000+ было от вас, читателей EasyElectronics. Были даже переводы на 25000+ и просто поток платежей на 251 рубль. Это невероятно круто. Сейчас идет заключение договора и подготовка к строительству!

А я встрял на три года, как минимум, ежемесячной пахоты над статьями :)))))))))))) Спасибо вам за такой мощный пинок.

Краткая инструкция по использованию отладчика GDB

GDB — это кон­соль­ное при­ложе­ние, выпол­ненное в клас­сичес­ком духе коман­дной стро­ки. Вот краткое руководство по использованию отладчика GDB.

И хотя за вре­мя сво­его сущес­тво­вания GDB успел обрасти ворохом кра­сивых гра­фичес­ких морд (сре­ди них DDD, Data Display Debugger, — ста­рей­ший и самый популяр­ный интерфейс), инте­рак­тивная отладка в сти­ле WinDBG в мире Linux край­не непопу­ляр­на.

Внеш­ний вид отладчи­ка GDB

Как пра­вило, это удел эмиг­рантов с Windows-плат­формы, соз­нание которых необ­ратимо иска­лече­но иде­оло­гией «око­шек». Гру­бо говоря, если WinDBG — сле­сар­ный инс­тру­мент, то GDB — токар­ный ста­нок с прог­рам­мным управле­нием. Ког­да‑нибудь вы полюбите его.

От­ладчик DDD — гра­фичес­кий интерфейс к GDB

Для отладки на уров­не исходных тек­стов прог­рамма дол­жна быть откомпи­лиро­вана с отла­доч­ной информа­цией. В GCC за это отве­чает ключ — g . Если отла­доч­ная информа­ция недос­тупна, GDB будет отла­живать прог­рамму на уров­не дизас­сем­блер­ных команд.

Обыч­но имя отла­жива­емо­го фай­ла переда­ется в коман­дной стро­ке:

gdb filename

Для отладки активно­го про­цес­са ука­жите в коман­дной стро­ке его ID, а для под­клю­чения коры (core dump) вос­поль­зуйтесь клю­чом:

— core == corename

Все три парамет­ра мож­но заг­ружать одновре­мен­но, попере­мен­но перек­люча­ясь меж­ду ними коман­дой target.

Пе­рек­люча­емся на отла­жива­емый файл:

target exec

На при­атта­чен­ный про­цесс:

target child

Или на дамп коры:

target core

Не­обя­затель­ный ключ — q подав­ляет вывод копирай­та. Заг­рузив прог­рамму в отладчик, мы дол­жны уста­новить точ­ку оста­нова. Для это­го слу­жит коман­да break (она же b ).

Эта коман­да уста­нав­лива­ет точ­ку оста­нова на фун­кцию main язы­ка C, а вот эта:

на точ­ку вхо­да в ELF-файл (впро­чем, в некото­рых фай­лах она называ­ется по‑дру­гому). Мож­но уста­новить точ­ку оста­нова и на про­изволь­ный адрес:

b * 0x8048424

Ре­гис­тры пишут­ся малень­кими бук­вами и пред­варя­ются зна­ком дол­лара. GDB понима­ет два «обще­сис­темных» регис­тра: $ pc — ука­затель команд и $ sp — сте­ковый ука­затель. Толь­ко пом­ните, что непос­редс­твен­но пос­ле заг­рузки прог­раммы в отладчик никаких регис­тров у нее еще нет, они появ­ляют­ся толь­ко пос­ле запус­ка отла­жива­емо­го про­цес­са на выпол­нение (коман­да run , она же r ).

От­ладчик самос­тоятель­но реша­ет, какую точ­ку оста­нова уста­новить, прог­рам­мную или аппа­рат­ную, и луч­ше ему не пре­пятс­тво­вать (коман­да при­нуди­тель­ной уста­нов­ки аппа­рат­ной точ­ки оста­нова hbreak работа­ет не на всех вер­сиях отладчи­ка). Точ­ки оста­нова на дан­ные в GDB называ­ются точ­ками наб­людения — watch point.

Перечис­лю основные при­емы работы с отладчи­ком.

  • watch addr вызыва­ет отладчик вся­кий раз, ког­да содер­жимое addr изме­няет­ся, а awatch addr — при чте­нии или записи в addr.
  • rwatch addr реаги­рует толь­ко на чте­ние, но работа­ет не во всех вер­сиях отладчи­ка.
  • info break позволяет прос­мотреть спи­сок уста­нов­ленных точек оста­нова.
  • clear уда­ляет все точ­ки оста­нова.
  • clear addr уда­ляет все точ­ки оста­нова, уста­нов­ленные на дан­ную фун­кцию, адрес или номер стро­ки.
  • enable и disable поз­воля­ют вре­мен­но вклю­чать и отклю­чать точ­ки оста­нова. Точ­ки оста­нова под­держи­вают раз­витый син­таксис условных команд, опи­сание которо­го мож­но най­ти в докумен­тации.
  • continue ( c ) возоб­новля­ет выпол­нение прог­раммы, прер­ванное точ­кой оста­нова.
  • next N ( n N ) выпол­няет N сле­дующих строк кода без вхо­да, а step N ( s N ) сo вхо­дом во вло­жен­ные фун­кции. Если чис­ло N не задано, по умол­чанию выпол­няет­ся одна стро­ка.
  • nexti и stepi дела­ют то же самое, но работа­ют не со стро­ками исходно­го тек­ста, а с машин­ными коман­дами. Обыч­но они исполь­зуют­ся сов­мес­тно с коман­дой display / i $ pc ( x / i $ pc ) , пред­писыва­ющей отладчи­ку отоб­ражать текущую машин­ную коман­ду. Ее дос­таточ­но вызывать один раз за сеанс.
  • jump addr переда­ет управле­ние в про­изволь­ную точ­ку прог­раммы, а call addr / fname вызыва­ет фун­кцию fname с аргу­мен­тами! Это­го нет даже во мно­гих Windows-отладчи­ках. А как час­то оно тре­бует­ся!
  • Дру­гие полез­ные коман­ды:
    • finish — про­дол­жать выпол­нение до выхода из текущей фун­кции;
    • until addr ( u addr ) — про­дол­жать выпол­нение, пока ука­зан­ное мес­то не будет дос­тигну­то, при запус­ке без аргу­мен­тов — оста­новить выпол­нение при дос­тижении сле­дующей коман­ды (акту­аль­но для цик­лов!);
    • return — немед­ленно вер­нуть­ся в дочер­нюю фун­кцию.
    • вы­раже­ния (нап­ример, p 1 + 2 );
    • со­дер­жимого перемен­ной ( p my_var );
    • со­дер­жимого регис­тра ( p $ eax );
    • ячей­ки памяти ( p * 0x8048424 , p * $ eax ).
    • set $ eax = 0 записы­вает в регистр eax ноль;
    • set var my_var = $ ecx прис­ваивает перемен­ной my_var зна­чение регис­тра ecx;
    • set < unsigned char * >0x8048424 = 0xCC записы­вает по бай­товому адре­су 0x8048424 чис­ло 0xCC.

    Ко­роче говоря, приб­лизитель­ный сеанс работы с GDB выг­лядит так: гру­зим прог­рамму в отладчик, отда­ем ему коман­ду b main , а если не сра­бота­ет, то b _star t, затем r , пос­ле чего отла­жива­ем прог­рамму по шагам ( n / s ), при желании задав парамет­ры ( x / i $ pc ) , что­бы GDB показы­вал, что у нас выпол­няет­ся в дан­ный момент.

    Выходим из отладчи­ка по коман­де quit ( q ). Опи­сание осталь­ных команд ищите в докумен­тации. Теперь по край­ней мере вы не заб­лудитесь в ней.

    Еще есть гра­фичес­кий интерфейс gdbgui, который запус­кает­ся внут­ри бра­узе­ра.

    Гра­фичес­кий интерфейс к GDB, выпол­няющий­ся в веб‑бра­узе­ре

    Он пред­став­ляет собой сер­верное при­ложе­ние, написан­ное на Python, и уста­нав­лива­ется через pip:

    Как пользоваться gdb

    Программа gdb — это популярный отладчик для программ, написанных на языке программирования Си и С++. Отладчик позволяет выполнить программу пошагово, посмотреть значения всех переменных на каждом из этапов выполнения, а если это необходимо, то и дизассемблировать код и посмотреть состояние регистров процессора.

    В сегодняшней статье мы рассмотрим как пользоваться gdb для отладки и анализа выполнения программ, написанных на Си. Попытаемся разобраться с основными возможностями программы.

    Как пользоваться gdb

    1. Установка gdb

    Обычно, отладчик устанавливается вместе с другими инструментами для сборки программного обеспечения. Для установки всего необходимого в Ubuntu или Debian достаточно выполнить:

    sudo apt install build-essential

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

    sudo apt install gdb

    В CentOS или Fedora команда установки будет выглядеть следующим образом:

    sudo dnf install gdb

    А для Arch Linux надо выполнить:

    sudo pacman -S gdb

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

    2. Компиляция программы

    Для того чтобы получить максимум полезной информации во время отладки, например, имена переменных и номера строк кода программу следует скомпилировать особым образом. Для примеров из этой статьи мы будем использовать такую небольшую программу на Си, в процессе будем её изменять, но начнём с этого:

    #include
    int main() int var1 = 0;
    int var2 = 2;
    char greeting[] = «Hello from losst\n»;
    printf(«%s», greeting);
    >

    Для того чтобы всё необходимое было включено в исполняемый файл, программу надо собрать с опцией -g. В данном случае команда будет выглядеть вот так:

    gcc -g -o program program.c

    Затем вы можете её выполнить:

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

    Для того чтобы запустить программу достаточно передать путь к ней отладчику. Какие-либо опции указывать не обязательно:

    После запуска отладчика вы попадаете в его командный интерфейс. Программа ещё не запущена, запущен только отладчик, в котором вы можете ею управлять с помощью специальных команд. Вот основные команды gdb:

    • break или b — создание точки останова;
    • info или i — вывести информацию, доступные значения: break, registers, frame, locals, args;
    • run или r — запустить программу;
    • continue или c — продолжить выполнение программы после точки останова;
    • step или s — выполнить следующую строчку программы с заходом в функцию;
    • next или n — выполнить следующую строчку без захода в функцию;
    • print или p — вывести значение переменной;
    • backtrace или bt — вывести стек вызовов;
    • x — просмотр содержимого памяти по адресу;
    • ptype — просмотр типа переменной;
    • h или help — просмотр справки по команде;
    • q или quit — выход из программы.

    4. Запуск программы

    Для того чтобы запустить программу надо воспользоваться командой run в консоли gdb. Просто выполните:

    И программа будет запущена и выполнена. Если вам надо передать программе какие-либо аргументы, то следует их передать команде run, например:

    (gdb) run arg1 arg2

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

    Программа сообщает на какой строчке исходного кода возникла проблема. Чтобы посмотреть весь исходник выполните команду list:

    Для того чтобы вызвать ошибку Segmentation Fault и проверить как это работает можете добавить в программу такие строки и перекомпилировать её:

    char *buffer = malloc(sizeof(char) * 10);
    while(1) *(++buffer) = ‘c’;
    >

    Тут мы выделяем из памяти массив символов размером 10 элементов и заполняем его и память, которая находится за ним символами «с», пока программа не упадёт.

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

    Неотъемлемая часть отладки приложения — это точки останова. С помощью них можно остановить выполнение программы на любом месте исходного кода или функции, а затем проанализировать все переменные, а также что происходит с программой. Сначала смотрим исходник программы:

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

    Например, давайте установим точку останова на восьмой строчке исходника:

    Теперь, когда вы запустите программу на выполнение она остановиться в указанной точке:

    Для того чтобы выполнить следующую строчку без входа в функцию используйте команду next:

    Тогда выполнится следующая строка кода в программе. Если надо войти в функцию и посмотреть что в ней происходит следует использовать команду step:

    Для отладки циклов можно устанавливать точки останова на основе условия, например, на 11-той строке, если значение переменной var1 будет 20:

    (gdb) break 11 if var1==20

    Чтобы этот пример заработал добавьте в код цикла следующую строчку, как на снимке:

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

    6. Вывод информации

    Сами по себе точки останова не очень полезны, но после каждой остановки программы можно посмотреть полностью её состояние и значения всех переменных, а это уже намного интереснее. Для просмотра информации используется команда info, а для вывода значения конкретной переменной — print. Для того чтобы посмотреть значения всех локальных переменных выполните:

    (gdb) info locals

    А для вывода значений аргументов функции:

    Вывести значение определённой переменной можно с помощью print:

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

    (gdb) print var1+30

    Имя временной переменной, куда были записаны данные отображается перед самим результатом, например, в последней команде это $2. Теперь можно ещё раз вывести это значение:

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

    7. Изменение информации

    С помощью команды set можно изменить значение переменной прямо во время выполнения программы. Например:

    (gdb) break 7
    (gdb) run
    (gdb) set var2 = 20
    (gdb) print var2

    8. Вывод типа

    С помощью команды ptype вы можете вывести тип переменной. Например:

    (gdb) break 7
    (gdb) run
    (gdb) ptype var2

    9. Просмотр адресов

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

    #include
    #include
    #include
    int main(int argc, char *argv[]) int var1 = 0;
    int var2 = 2;
    char *buffer = malloc(sizeof(char) * 10);
    while(var1 < 10)var1++;
    *(++buffer) = ‘c’;
    >
    printf(«%s\n», buffer);
    >

    Запустите отладчик и установите точку останова на девятой строке и запустите программу:

    Теперь вы можете вывести адреса всех переменных в памяти с помощью символа &. Например:

    (gdb) print &argc
    (gdb) print &var1
    (gdb) print &buffer
    (gdb) print buffer

    Как видите, аргументы функции находятся в одном месте, локальные переменные в другому, но не очень далеко, а во память выделенная из кучи, на которую указывает указатель buffer — совсем далеко. Можете поменять программу и поэкспериментировать с разным количеством переменных.

    10. Просмотр памяти

    С помощью команды x или eXamine можно посмотреть содержимое памяти, по определённому адресу. Например, смотрим содержимое переменной var2:

    Если вы не знаете адрес переменной, можно передать её имя с оператором &, он извлечет её адрес. Программа выводит шеснадцатиричное значение, и оно обычно мало о чём нам может сообщить. Для того чтобы улучшить ситуацию можно воспользоваться опциями форматирования. Можно указать тип выводимых данных с помощью таких модификаторов:

    Также можно указать размер выводимого блока:

    Мы пытались вывести переменную типа int. Она занимает обычно четыре байта. Для её корректного вывода используйте такие параметры:

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

    Но поскольку там уже не наша переменная, эти данные не имеют смысла. Аналогично всё работает с строками, символами и другими значениями. Только обратите внимание, что если вы будете выводить переменную не одним блоком, то на результат повлияет порядок расположения байт. Значение будет выводиться задом на перед.

    11. Справка по программе

    Мы рассмотрели основные возможности отладчика gdb. Но если этого вам не достаточно, вы можете посмотреть справку по любой команде программы в самой программе. Для этого используйте команду help. Например, для команды exemine:

    Выводы

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

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *