Краткий гайд по использованию GDB

от автора

В этом коротком туториале мы рассмотрим базовые приёмы работы с GDB, а также посмотрим как можно (и нужно) подготавливать файлы к отладке для GDB.

GDB — переносимый отладчик проекта GNU, который работает на многих UNIX-подобных системах и умеет производить отладку многих языков программирования, включая Си, C++, Free Pascal, FreeBASIC, Ada, Фортран, Python3, Swift, NASM и Rust.

GDB

Почему именно GDB? Всё легко, он уже установлен на многих UNIX-подобных системах, лёгок в использовании и поддерживает много языков. Работа с ним оказывается очень лёгкой, а также его можно подключить к VSCode и другим редакторам кода (Включая Vim, NeoVim (ясное дело), Emacs, Atom и далее)

Подготовка файлов

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

Для того чтобы нам пройтись по такому файлу нам нужно скомпилировать его с помощью G++ с использованием флага -g (это действительно важно, без этого флага, программа не будет корректно работать в GDB).

g++ -g file_name.cpp -o output_name gdb output_name

Python-файл вы можете продебажить с помощью этой команды:

gdb -ex r --args python program_name.py <arguments>

Для Java вы просто можете использовать jdb, который уже идёт в комплекте c JDK.

Также, если вам не хочется компилировать всё ручками, вы можете просто использовать сайт OnlineGDB, там просто нужно вставить код и нажать debug, а затем внизу откроется консоль, где вы сможете писать команды.

Использование GDB

Как только мы зашли в GDB нам выводится следующее сообщение:

GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git Copyright (C) 2018 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.  Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>.  For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from 3_Hero's_Inventory.cpp...done.

Последняя строка говорит о том, нормально ли запустился файл.

Теперь нужно посмотреть, где в нашем файле точка вхождения (строка, откуда наша программа начинает свою работу), в случае cpp это метод main(). Находим эту строку c помощью команды list и вписываем, какая она идёт по счёту с буквой b (также можно просто указать имя функции b main тоже работает):

(gdb) list 1   #include <iostream> 2   #include <string> 3    4   using namespace std; 5    6   int main(int argc, char *argv[]) 7   { 8       // Hero's Inventory - скрипт, где мы имитируем инвентарь игрока 9    10      const int MAX_ITEMS = 10; // Задаём константу, максимум по инвентарю игрока

(gdb) b 6 Breakpoint 1 at 0xcb5: file ./3_Hero's_Inventory.cpp, line 6.

Далее запускаем программу с помощью комманды r:

(gdb) r Starting program: /home/username77177/gitprojects/learning/cpp/build_folder/3_Hero's_Inventory.cpp   Breakpoint 1, main (argc=1, argv=0x7fffffffdd18) at ./3_Hero's_Inventory.cpp:7 7   {

Для того, чтобы посмотреть на какой мы сейчас строке, нужно написать f:

(gdb) f #0  main (argc=1, argv=0x7fffffffdd18) at ./3_Hero's_Inventory.cpp:14 14      items[itemnum++] = "Sword";

Для того, чтобы сделать шаг, нужно нажать n (от слова next):

(gdb) n 10      const int MAX_ITEMS = 10; // Задаём константу, максимум по инвентарю игрока

Как мы видим GDB сразу пропускает пустые строки (или строки с комментариями) и переходит к следующей строке.
Предположим, что у нас есть функция, при нажатии n наш отладчик быстро пройдет функцию, не заходя в неё, чтобы зайти в функцию нужно сделать "шаг внутрь" (step-in) или просто клавиша s:

(gdb) s 11      string items[MAX_ITEMS]; // Создаём массив из строк c 10 элементами

(В примере нет функции, однако шаг step-in все равно будет работать и с обычными инициализациями, условиями и циклами)

Чтобы узнать какие переменные (локальные) сейчас инициализированны в программе нужно написать комманду info locals:

(gdb) info locals MAX_ITEMS = 10 items = {"", "", "", "", "", "", "", "", "", ""} itemnum = 0 game = 247

Чтобы вывести только одну переменную, нужно написать print имя_переменной:

(gdb) print MAX_ITEMS  $1 = 10

Мы можем также изменить переменную с помощью set:

(gdb) set x = 77177 (gdb) print x $1 = 77177

Мы можем также следить за переменными с помощью watch:

watch x

Также, если нужно можно посмотреть что в данный момент находится в регистрах (info registers):

(gdb) info registers  rax            0x7fffffffdc00   140737488346112 rbx            0xffffffffffffffff   -1 rcx            0xa0 160 rdx            0x7fffffffdd28   140737488346408 rsi            0x7fffffffdd18   140737488346392 rdi            0x7fffffffdbf0   140737488346096 rbp            0x7fffffffdc30   0x7fffffffdc30 rsp            0x7fffffffdab0   0x7fffffffdab0 r8             0x7ffff782fd80   140737345944960 r9             0x0  0 r10            0x6  6 r11            0x7ffff7b77020   140737349382176 r12            0x7fffffffdc10   140737488346128 r13            0x7fffffffdd10   140737488346384 r14            0x0  0 r15            0x0  0 rip            0x555555554cfe   0x555555554cfe <main(int, char**)+100> eflags         0x286    [ PF SF IF ] cs             0x33 51 ss             0x2b 43 ds             0x0  0 es             0x0  0 fs             0x0  0 gs             0x0  0

Чтобы посмотреть какие в данный момент есть breakpoints (точки останова) нужно написать info breakpoints:

(gdb) info breakpoints  Num     Type           Disp Enb Address            What 1       breakpoint     keep y   0x0000555555554cb5 in main(int, char**)                                                     at ./3_Hero's_Inventory.cpp:6     breakpoint already hit 1 time 2       breakpoint     keep y   0x0000555555554cfe in main(int, char**)                                                     at ./3_Hero's_Inventory.cpp:14

Чтобы удалить точку останова del breakpoint_num:

(gdb) info breakpoints  Num     Type           Disp Enb Address            What 1       breakpoint     keep y   0x0000555555554cb5 in main(int, char**)                                                     at ./3_Hero's_Inventory.cpp:6     breakpoint already hit 1 time 2       breakpoint     keep y   0x0000555555554cfe in main(int, char**)                                                     at ./3_Hero's_Inventory.cpp:14  (gdb) del 1  (gdb) info breakpoints  Num     Type           Disp Enb Address            What 2       breakpoint     keep y   0x0000555555554cfe in main(int, char**)                                                     at ./3_Hero's_Inventory.cpp:14 

Чтобы прыгнуть к следующей точке останова нужно нажать c:

(gdb) r Starting program: /home/username77177/gitprojects/learning/cpp/build_folder/3_Hero's_Inventory.cpp   Breakpoint 3, main (argc=1, argv=0x7fffffffdd18) at ./3_Hero's_Inventory.cpp:7 7   { (gdb) c Continuing.  Breakpoint 2, main (argc=1, argv=0x7fffffffdd18) at ./3_Hero's_Inventory.cpp:14 14      items[itemnum++] = "Sword";

Мы можем вызывать функции из программы (локальные) с помощью call:

(gdb) call MyFunction()

Чтобы продолжить выполнение функции и остановить программу когда она (функция) завершится нужно написать finish или fin:

(gdb) fin

Стоит уточнить, что нельзя использовать finish в главном методе.

Чтобы завершить выполнение программы, нужно написать kill:

(gdb) kill Kill the program being debugged? (y or n) y

Также можно написать help в любой момент и получить краткую справку, как пользоваться отладчиком

(gdb) help List of classes of commands:  aliases -- Aliases of other commands breakpoints -- Making program stop at certain points data -- Examining data files -- Specifying and examining files internals -- Maintenance commands obscure -- Obscure features running -- Running the program stack -- Examining the stack status -- Status inquiries support -- Support facilities tracepoints -- Tracing of program execution without stopping the program user-defined -- User-defined commands  Type "help" followed by a class name for a list of commands in that class. Type "help all" for the list of all commands. Type "help" followed by command name for full documentation. Type "apropos word" to search for commands related to "word". Command name abbreviations are allowed if unambiguous.

ссылка на оригинал статьи https://habr.com/ru/post/491534/


Комментарии

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

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