
В этом коротком туториале мы рассмотрим базовые приёмы работы с 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/
Добавить комментарий