Linux: Повне керівництвоКолісниченко Денис Миколайович

22.2. Відладчик gdb

22.2. Відладчик gdb

Формат виклику відладчика gdbнаступний:

gdb [-help] [-nx] [-q] [-batch] [-cd=dir] [-f] [-b bps] [-tty=dev] [-s symfile] [-e prog] [- sе prog] [-c core] [-x cmds] [-d dir] ]

Ключі відладчика описані у таблиці 22.1.

Ключі командного рядка gdbТаблиця 22.1

Ключ Призначення
-help або -h Висновок короткого описувсіх параметрів
-nx або -n Не обробляти команди ініціалізації файлу.gdbinit
-q Не виводити вітання та інформацію про авторські права
-batch Командний режим Відладчик повертає 0, якщо були виконані всі команди, вказані у файлі, заданому параметром -x (і файлі .gdbinit, якщо його використання дозволено). Якщо ж бодай одна з команд не виконана, повертається ненульове значення
-cd=каталог Встановити робочий каталог (за промовчанням використовується поточний каталог)
-f або -fullname Ця опція потрібна, якщо ви плануєте використовувати інтерфейс текстового процесора Emacsдля налагодження ваших програм за допомогою gdb. Для більш докладного описівзверніться до довідкової системи
-b bps (bits per second) Встановити швидкість обміну інформацією з послідовному інтерфейсу, якщо ви налагоджуєте вашу програму віддалено
-tty=термінал Встановити термінал як стандартне введення та виведення для програми, що налагоджується.
-s файл або -symbols=файл Читає таблицю символів із зазначеного файлу
-write Дозволити запис у виконувані та core-файли
-e програма Використовувати вказану програму як фільтр дампа
-se=файл Читати таблицю символів із зазначеного файлу та використовувати вказаний файл як здійснений
-core=файл або -з файл Вказати файл дампа
-command=файл або -x файл Виконати вказані у файлі команди (використовується в командному режимі)
-d каталог Додати каталог до списку пошуку вихідних текстів
Останній параметр задає об'єкт, який потрібно налагоджувати. Ви можете задати програму (prog), або дамп-файл (core), який буде створений у разі помилки програми (Segmentation fault), або приєднатися до вже запущеного процесу (procID)
-p PID Підключитися до вже запущеного процесу (дана опція стала доступною у версії gdb 5.2)

Щоб використати gdbдля налагодження вашої програми, потрібно додати у виконуваний файл налагоджувальну інформацію. Для цього відкомпілюєте програму з опцією -g:

$ gcc -g -o prog prog.c

Ця опція включає налагоджувальну інформацію в рідному для операційної системи форматі, з яким може працювати gdb.

Потім потрібно викликати gdbтак:

Якщо після запуску вашої програми сталася помилка і створено дамп-файл (core), можна передати відладчику і цей файл:

Можна також підключитися до запущеного процесу, для цього потрібно передати його PID:

Тільки переконайтеся спочатку в тому, що у вас немає файлу 1111, оскільки gdbспочатку шукає виконуваний файл, потім core-файл, а потім PID.

Після запуску налагоджувача в інтерактивному режимі можна використовувати команди, найважливіші з яких перераховані в таблиці 22.2. Про решту можна дізнатися у довідковій системі: man gdb.

Команди gdb Таблиця 22.2

Команда Призначення
break [файл:]функція Встановити точку зупинки
run [аргументи] Запустити програму та передати їй зазначені аргументи
bt Зворотнє трасування: відобразити стек програми
print вираз Вивести значення виразі, операндами можуть бути змінні, оголошені у вашій програмі
З Продовжити виконання програми (після зупинки)
Next Виконати наступний рядок. Це так званий крок "над" (step over). Якщо наступний рядок – виклик функції, то ми виконаємо її за один крок – «переступимо» її
Step Виконайте наступний рядок, Це так званий крок "в" (step into). Якщо наступний рядок - виклик функції, ми будемо послідовно виконувати всі оператори тіла функції
help [ім'я] Вивести довідку про команду відладчика чи вивести загальну інформаціюпро нього
Quit Вихід

У цій таблиці наведено далеко ще не всі команди. Якщо вас цікавить більш повна інформація, зверніться до посібника з gdb.

З книги Мова програмування С# 2005 та платформа.NET 2.0. автора Троелсен Ендрю

Відладчик командного рядка (cordbg.exe) Перш ніж перейти до розгляду можливостей компонування C#-додатків за допомогою TextPad, слід зазначити, що .NET Framework 2.0 SDK пропонує відладчик командного рядка cordbg.ехe. Цей інструмент має безліч опцій, які дозволяють виконати

З книги Розробка програм у середовищі Linux. Друге видання автора Джонсон Майкл До.

4.3. Налагоджувач GNU gdb - це налаштовувач, рекомендований Free Software Foundation, gdb є гарним налагодженням командного рядка, на якому будуються деякі інструменти, включаючи режим gdb в Emacs, графічний налагоджувач Data Display Debugger (http://www.gnu.org/software/ ddd/) та вбудовані налагоджувачі в деяких

З книги Linux: Повний посібник автора Колісниченко Денис Миколайович

22.2. Налагоджувач gdb Формат виклику відладчика gdb наступний: gdb [-help] [-nx] [-q] [-batch] [-cd=dir] [-f] [-b bps] [-tty=dev] [-s symfile ] [-e prog] [-sе prog] [-c core] [-x cmds] [-d dir] ]Ключі відладчика описані в таблиці 22.1.Ключі командного рядка gdb Таблиця 22.1 Ключ Призначення -help або -h Висновок короткого опису всіх

З книги Програмування для Linux. Професійний підхід автора Мітчелл Марк

1.4. GNU-наладчик gdb Відладчик - це програма, за допомогою якої можна дізнатися, чому написана вами програма поводиться не так, як було задумано. Працювати з налагоджувачем доводиться дуже часто. Більшість Linux-програмістів має справу з GNU-налагоджувачем (GNU Debugger, GDB), який

З книги Розробка ядра Linux автора Лав Роберт

Налагоджувач kgdb Відладчик kgdb - це латка ядра, яка дозволяє за допомогою налагоджувача gdb налагоджувати ядро ​​по лінії послідовної передачі. Для цього потрібно два комп'ютери. На першому виконується ядро ​​із латкою kgdb. Другий комп'ютер використовується для налагодження ядра по лінії

Вступ

Відверто кажучи, програма GNU GDB є досить багатофункціональною. Покрокова від-лад-ка - лише одна з її можливостей. У цій статті я спробував описати ті лише команди GDB, які дозволяють проводити зручне покрокове налагодження програм, написаних на Free Pascal.

Щоб програму можна було налагоджувати, вона має бути відкомпільована з ключем -g.

Оскільки GDB орієнтований не так на Pascal, але в C і C++, то використання GDB для налагодження Pascal-программ іноді пов'язані з незручностями.

Наведу список підводного каміння, виявлених мною і розробниками Free Pascal (пере-чис-лен-них в user's manual).

  1. Відлагоджувальна інформація в Free Pascal генерується у верхньому регістрі. Тому імена всіх змінних, процедур, функцій під час використання GDB повинні вказуватися ВЕЛИКИМИ БУКВАМИ.
  2. GDB не сприймає тип extended (адже C такого типу немає). Обійти цю неприємність можна, якщо, наприклад, включити в код такі рядки.
    type
    ($IFDEF DEBUG)
    dbl = double;
    ($ELSE)
    dbl = extended;
    ($ENDIF)
    ...

    var x: dbl;
    ...

  3. До елементів багатовимірних масивів потрібно звертатися в C-шній манері, а саме команда (gdb) print A видасть перший рядок масиву A. Для перегляду необхідного елемента слід писати (gdb) print A
  4. GDB не сприймає безліч.
  5. Є труднощі з підтримкою об'єктів (див. user's manual за подробицями).
  6. Існують проблеми з глобально перевизначеними функціями. (Докладніше див. user"s manual).
  7. При налагодженні процедур, функцій, розташованих у різних файлах, часто виникає невідповідність - усунення рядків. Той рядок, який GDB показує поточним, не є, а поточний розташований рядків десь на двадцять вище. Це призводить до великих незручностей при покроковій налагодженні. Я для себе зробив з цього таку мораль - хоч GDB і дозволяє налагоджувати процедури, описані в різних файлах, але краще цією можливістю не користуватися, а на час налагодження всі процедури, робота яких вас зацікавить, поміщати в одному файлі.

Всі приклади налагоджувалися за допомогою GNU GDB 5.0.

Запуск відладчика GDB

gdb [опції] [ім'я_файлу | ID процесу]

Після запуску бачимо "nice GDB logo" (якщо це чомусь дратує, то опція -q поз-во-ля-є не виводити це введення з інформацією про авторські права та інша). У наступному рядку запрошення
(gdb)
чекає на введення команди.

Нижче наведено короткий список команд GDB.

Коротку довідку про будь-яку команду можна отримати, ввівши
(gdb) help [ім'я_команди, можна коротке]

Якщо при запуску GDB ім'я файлу, що виконується, не було вказано (що слід було робити), то вказати його можна командою file .

Команда файлу

(gdb) file<имя исполняемого файла, который подлежит отладке>


Для того, щоб переглянути вміст вихідного коду, використовуйте команду list (скорочено l ; б пробільша частина найбільш корисних команд мають скорочення). При цьому під-разу-ме-ва-є-ся, що вихідник розташований у тому ж каталозі, що і виконуваний файл. Як правило, так воно і є.

Команда list (скорочено l)

Перегортає 10 рядків вниз, починаючи з поточного. Для перегортання нагору слід набрати

Команда run (скорочено r)

Запускає програму, що відладжується під GDB. Якщо потрібно, то після команди можна вказати список аргументів програми. Також допускається перенаправлення потоків введення і ви-воду в інші файли, наприклад

(gdb) run > outfile

Якщо жодних точок зупинки не визначено, то програма виконується тихо, при цьому нам со-об-ща-ється:

(gdb) run
Starting program: test
Program виконується звичайним чином.
(gdb)

Якщо ж відладчик зустрічає точку зупинки, він видає її номер, адресу та додаткову інфор-мацію — поточний рядок, ім'я про-це-ду-ри, і т.п.

(gdb) r
Breakpoint 1, main () at test.pp:3
Current language: auto; currently pascal
3 x: = x + 1;
(gdb)

І чекає на введення команди.

Зупинення налагодження програми

Команда kill (k). Слід запит

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

Тут введено y (тобто так), і налагодження програми припиняється. Командою run її можна почати заново, при цьому всі точки ос-та-но-ва (breakpoints), точки перегляду (watchpoints) і точки відлову (catchpoints) зберігаються.

Вихід із відладчика

Команда quit(q).

(gdb) q
$

Точки зупинки


(gdb) help breakpoints

Точки зупинки – такі, коли GDB припиняє виконання програми. Як вже упо-ми-на-лось, є 3 типи точок ос-та-но-ва:

  1. Breakpoints - точка зупинки як така.Зупинка відбувається, коли виконання доходить до певного рядка, адреси чи процедури/функції.
  2. Watchpoints – точка перегляду.Виконання програми припиняється, якщо програма звернулася до певної змінної - або вважала її значення, або змінила її.
  3. Catchpoints - точка вилову.Призупинення відбувається за певної події (наприклад, отримання сигналу). Я не торкатимуся точок зупинки цього типу.

Визначення точок зупинки

Breakpoint

Команда break
(gdb) break [аргумент]
або, скорочено
(gdb) b [аргумент]
визначає точку зупинки. Як аргумент може виступати

  • номер рядка. Зупинка відбудеться при досягненні рядка програми з цим номером. Те, що написано в самому рядку, не виконуватиметься. Наприклад (gdb) b 394 Breakpoint 1 at 0x805a650: file maeq.pas, line 394.
  • ім'я процедури (функції). Відладчик зайде в цю процедуру та зупинить виконання програми. NB!! Ім'я процедури (функції) має бути вказано ВЕЛИКИМИ ЛІТЕРАМИ. Наведу приклад: (gdb) b CALC Breakpoint 2 в 0x7657c7a: file maeq.pas, line 26.
  • якщо викликати команду break без аргументівто точка зупинки поставиться на поточному рядку.
  • також можна явно вказувати адресаточки зупинки (перед адресою треба поставити знак *). Наведу лише приклад для повноти опису: (GDB) b * 0x805a650 Breakpoint 3 at 0x805a650: file maeq.pas, line 394.

Допускається використання кількох точок зупинки на одному рядку (функції, адреса).

Watchpoint

Існують різні види точок перегляду, і задаються різними командами:

  • команда watch (скорочено wa) (gdb) wa<переменная>Виконання програми припиняється щоразу, коли значення зазначеної змінної змінюється.
  • команда rwatch (скорочено rw) (gdb) rw<переменная>Виконання припиняється щоразу, коли програма зчитує значення зазначеної змінної.
    NB!! Ім'я змінної має бути вказано ВЕЛИКИМИ БУКВАМИ.
  • команда awatch (скорочено aw) (gdb) aw<переменная>Виконання припиняється щоразу, коли програма звертається до зазначеної змінної, як зчитування, так записи.
    NB!! Ім'я змінної має бути вказано ВЕЛИКИМИ БУКВАМИ.

Зауважу від себе, що команди rwatch і awatch у мене чомусь вередують — часто не ус-та-нав-ли-ва-ють точки перегляду на змінну. Натомість команда watch працювала завжди.

Управління точками зупинки

Інформацію про всі встановлені точки зупинки можна вивести командою info .

Команда info має багато можливостей, але в даному випадку скористаємося лише наступним її форматом:
(gdb) info breakpoints
або, коротко
(gdb) i b

Виводиться докладна інформація про всі точки зупинки (як breakpoints, так і watch-points), що включає - номер - breakpoint або watchpoint - активність - скільки разів програма натикалася на цю точку - інші характеристики, значення яких мені не зовсім зрозуміло

Якщо якась точка зупинки не потрібна, то її можна зробити неактивною за допомогою команди disable:

(gdb) disable breakpoint<номер этой точки>

Назад, деактивована точка зупинки активується командою enable:

(gdb) enable breakpoint<номер этой точки>

Статус точки зупинки - активна вона чи ні, легко оглянути тією ж командою info.

Якщо ж точка зупинки не потрібно взагалі, вона може бути видалена назовсім.

(gdb) delete breakpoint [номер точки]

(gdb) d b [номер точки]

Введення цієї команди без аргументу видалить ВСІ точки зупинки.

Відновлення виконання, покрокове налагодження

Інформацію про команди цього розділу можна отримати, ввівши

(gdb) help running

Команда continue (c)

(gdb) з [аргумент]

Продовжує виконання зупиненої програми. Виконання буде відбуватися, поки сно-ва не зустрінеться точка зупинки. У якості аргументу може використовуватися ціле число N. Це вкаже відладчику проігнорувати (N-1) точку зупинки (ви-повне-ня зупиниться на N-ій).

Команда step(s)

(gdb) s [аргумент]

Аналог дії клавіші F7 (Trace into) у IDE. Відбувається виконання програми до тих пір, поки не буде досягнуто наступний рядок її коду. При вказівці аргументу - цілого числа N, відладчик виконує команду step N раз (якщо не зупиняє виконання з-за точок зупинки або з інших причин).

Команда next (n)

(gdb) n [аргумент]

Аналог дії клавіші F8 (Step over) у IDE. На відміну від step виклик процедури вважається єдиною інструкцією (не заходить у викликані процедури, функції). Аргумент N ра-бо-та-є так само, як і для step.

Команда finish (fin)

(gdb) fin

Виконує програму до виходу з поточної процедури (функції). Якщо функція воз-вра-ща-ет значення, це значення ви-во-дит-ся теж.

Команда until (u)

Виконує виконання програми доти, доки не буде досягнуто рядок з номером, б проль-шим поточного. Команду until зручно застосовувати при налагодженні циклів. Зупинка про-і-зой-дет також, якщо програма при виконанні циклу вийде з поточної про-це-ду-ри, функції.

Команда stepi (si)

(gdb) si [аргумент]

Дія подібна до step, але виконується не рядок, а рівно одна інструкція в цьому рядку програми. Аргумент N потрібен, якщо потрібно виконати N інструкцій.

Команда nexti (ni)

(gdb) ni [аргумент]

Аналогічна stepi, але виклики процедур трактуються як одна інструкція.

Керування станом (перегляд, зміна) змінних при налагодженні

Інформацію про команди цього розділу можна отримати, ввівши

(gdb) help data

Команда print (p)

(gdb) print<выражение>

Виведення поточного значення змінної (вирази). При використанні команди print ім'я перемінної можна писати в змішаному регістрі, тобто в цьому випадку використання великих букв обов'язковим не є.

Часто потрібно відстежувати значення кількох змінних. Щоб не обтяжувати себе багатократним введенням команди print , використовуйте команду display .

Команда display

(gdb) display [аргумент]

Як аргумент зазвичай вказують змінну або вираз. При цьому зазначена змінна (вираз) занесеться в дисплей, тобто стане виводитися при кожній основі програми (при попаданні на точку зупинки, при покроковому виконанні командами step та next, etc). Якщо викликати display без аргументів, то GDB видасть значення всіх змінних (виражень), занесених в дисплей.

Управління списком цих змінних здійснюється аналогічно точкам зупинки. А саме, команда info display

(gdb) info display

видасть усі змінні, занесені на дисплей. Будь-яка змінна у списку дисплея може бути дезактивована

(gdb) disable display<номер переменной в списке дисплея>

або активована заново

(gdb) enable display<номер переменной в списке дисплея>

Видалення змінної зі списку дисплея здійснюється командою delete або командою undisplay. Так, команда

(gdb) delete display [номер змінної у списку дисплея]

робить те саме, що і

(gdb) undisplay [номер змінної у списку дисплея]

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

Зміна значення змінної

І останнє. Зміну значення змінної на інше можна, наприклад, зробити за допомогою команд set або print .

(gdb) set<оператор присваивания>(gdb) print<оператор присваивания>

Наприклад,

(gdb) whatis x
TYPE = WORD
(gdb) p x
$1 = 1
(gdb) set x:=2
(gdb)

При використанні set привласнення відбувається "тихо". Те ж саме можна зробити, але за допомогою команди print .

Наприклад,

(gdb) p x
$2 = 2
(gdb) p x:=x-2
$3 = 0
(gdb)

При цьому, очевидно, виводиться нове значення змінної.

От і все.

Вдалого налагодження!

Для ефективного налагодження програми, при компіляції ви повинні згенерувати налагоджувальну інформацію. Ця налагоджувальна інформація зберігається в об'єктному файлі; вона описує тип даних кожної змінної або функції, і відповідність між номерами рядків вихідного тексту та адресами у коді, що виконується.

Щоб запросити генерацію налагоджувальної інформації, вкажіть ключ `-g" під час запуску компілятора.

Багато компіляторів Сі не можуть обробляти ключі `-g" та `-O" разом. Використовуючи такі компілятори, ви не можете створювати оптимізовані файли, що містять налагоджувальну інформацію.

GCC, GNU компілятор Сі, підтримує `-g" з або без `-O" , уможливлюючи налагодження оптимізованого коду. Ми рекомендуємо, щоб ви завждиВи використовували `-g" при компіляції програм. Ви можете думати, що ваша програма правильна, але немає сенсу зазнавати успіху.

Якщо ви запускаєте вашу програму в середовищі виконання, що підтримує процеси, run створює підлеглий процес, і цей процес виконує вашу програму. (У середовищах, що не підтримують процеси, run виконує перехід на початок вашої програми.)

Виконання програми залежить від певної інформації, яку вона отримує від процесу, що її породив. GDB надає способи задати цю інформацію, що ви повинні зробити дозапуск програми. (Ви можете змінити її після старту, але такі зміни впливають на вашу програму лише при наступному запуску.) Ця інформація може бути поділена на чотири категорії: Параметри.Вкажіть параметри, які потрібно передати вашій програмі, як параметри команди run . Якщо на вашій системі є оболонка, вона використовується для передачі параметрів, так що при їх описі ви можете використовувати звичайні угоди (такі як розкриття шаблонів або підстановка змінних). У системах Unix, ви можете контролювати, яка оболонка використовується за допомогою змінного середовища SHELL . розділ 4.3 Аргументи вашої програми. Середовище.Зазвичай ваша програма успадковує своє середовище від GDB, але ви можете використовувати команди GDB set environment та unset environment , щоб змінити частину налаштувань середовища, що впливають на неї. розділ 4.4 Робоче середовище вашої програми. Робочий каталогВаша програма успадковує свій робочий каталог від GDB. Ви можете встановити робочий каталог GDB командою cd. розділ 4.5 Робочий каталог вашої програми. Стандартне введення та виведення.Зазвичай ваша програма використовує ті ж пристрої для стандартного введення та виводу, що й GDB. Ви можете перенаправити введення та виведення в рядку команди run, або використовувати команду tty, щоб встановити інший пристрій для вашої програми. розділ 4.6 Введення та виведення програми . Попередження:Хоча перенаправлення введення та виведення працює, ви не можете використовувати канали для передачі вихідних даних програми, що відладжується іншій програмі; якщо ви спробуєте це зробити, швидше за все GDB перейде до налагодження неправильної програми.

Коли ви подаєте команду run, ваша програма починає виконуватися негайно. Див. розділ 5. Зупинення та продовження виконання , щоб обговорити, як зупинити вашу програму. Як тільки ваша програма зупинилася, ви можете викликати функції програми, використовуючи команди print або call . розділ 8. Дослідження даних .

Якщо час модифікації вашого символьного файлу змінився з того моменту, коли GDB востаннє зчитував символи, він знищує свою символьну таблицю та зчитує її знову. При цьому GDB намагається зберегти ваші поточні точки зупинки.

4.3 Аргументи вашої програми

Перше, що GDB робить після підготовки до налагодження зазначеного процесу - зупиняє його. Ви можете досліджувати та змінювати приєднаний процес усіма командами GDB, які зазвичай доступні, коли ви запускаєте процеси за допомогою run . Ви можете встановлювати точки зупинки; ви можете покроково виконувати програму та продовжити її звичайне виконання, ви можете змінювати області даних. Якщо ви вирішите продовжити виконання процесу після приєднання до нього GDB, можна використовувати команду continue . detach Коли ви закінчили налагодити приєднаний процес, для його звільнення з-під керування GDB ви можете використовувати команду detach . Від'єднання процесу продовжує його виконання. Після команди detach цей процес і GDB знову стають абсолютно незалежними, і ви готові приєднати або запустити за допомогою run інший процес. detach не повторюється, якщо ви натиснете RET ще раз після виконання команди.

Якщо ви вийдете з GDB або використовуєте команду run, поки у вас є приєднаний процес, ви вб'єте цей процес. За промовчанням, GDB запитує підтвердження, якщо ви намагаєтеся зробити одну з цих речей; ви можете контролювати, чи потрібно вам це підтвердження чи ні, використовуючи команду set confirm (див. розділ 15.6 Необов'язкові попередження та повідомлення).

4.8 Знищення дочірнього процесу

kill Знищити дочірній процес, в якому ваша програма виконується під керуванням GDB.

Ця команда корисна, якщо ви хочете налагодити дамп пам'яті, а не процес, що виконується. GDB ігнорує будь-які дампи пам'яті, поки програма виконується.

В деяких операційні системи, програма не може бути виконана поза GDB, поки у вас є в ній точки зупинки, встановлені відладчиком. У цій ситуації ви можете використовувати команду kill, щоб дозволити виконання вашої програми поза відладчиком.

Команда kill також корисна, якщо ви хочете перекомпілювати і перекомпонувати вашу програму, так як у багатьох системах неможливо модифікувати файл, що виконується під час виконання процесу. У цьому випадку, коли ви введете наступний раз run , GDB помітить, що файл змінився, і заново прочитає символьну таблицю (намагаючись при цьому зберегти ваші точки зупинки).

Поговоримо про відладчиків для Microsoft Windows. Їх існує досить багато, згадати хоча б усіма улюблений OllyDbg, колись популярний, але в даний час практично померлий SoftIce, а також Sycer, Immunity Debugger, x64dbg і безліч відладчиків, вбудованих в IDE. За моїми спостереженнями WinDbg подобається далеко не всім. Думаю, переважно це пов'язано з командним інтерфейсом відладчика. Любителям Linux і FreeBSD, безперечно, він припав би до душі. Але затятим користувачам Windowsвін здається дивним та незручним. А тим часом, за функціоналом WinDbg нічим не поступається іншим налагоджувачам. Як мінімум, він точно нічим не гірший від класичного GDB або там LLDB. У чому ми сьогодні з вами переконаємося.

У світі Windows, все, як завжди, трохи через дупу. Офіційний інсталятор WinDbg можна завантажити на веб-сайті MS. Цей інсталятор крім WinDbg також поставить вам свіжу версію.NET Framework і перезавантажить систему без попиту. Після встановлення не факт, що відладник взагалі запрацює, особливо під старими версіями Windows. Тому краще завантажити неофіційне складання WinDbg або . Наполегливораджу скористатися саме однією з цих версій - це найпростіший і швидкий спосібвстановити WinDbg.

Є дві версії WinDbg, x86 та x64. Щоб не виникало жодних проблем, налагоджуйте x86 програми за допомогою x86 дебагера, а x64 програми - за допомогою x64 дебагера. Після першого запуску виглядатиме WinDbg досить убого. Але не турбуйтеся з цього приводу. Попрацювавши буквально кілька хвилин з WinDbg, ви підлаштуєте його під себе і виглядатиме він цілком няшненько. Наприклад, якось так (клікабельно, 51 Кб, 1156 x 785):

На цьому скріншоті зображено налагодження програми з нотатки Отримуємо список запущених процесів на Windows API. Як бачите, WinDbg підчепив вихідні програми. Праворуч відображаються значення локальних змінних. Внизу знаходиться вікно для введення команд, де за допомогою команди kn було виведено стек викликів. У верхній частині налагоджувача знаходяться кнопки, за допомогою яких можна виконувати прості діїна кшталт "крок вперед", а також відкрити додаткові вікна. За допомогою цих вікон можна переглянути вміст оперативної пам'яті, значення регістрів, дизассемблерний лістинг програми та багато інших цікавих речей.

Взагалі, дуже багато у WinDbg можна робити через GUI. Наприклад, у вікні з вихідним кодомможна поставити курсор на потрібному місці і натисканням на икноку з долонею створити там точку зупинки. Або виконати run to cursor. Також виконання команди можна будь-якої миті зупинити за допомогою кнопки Break в панелі вгорі. На цьому всім докладно зупинятись не будемо. Але врахуйте, що такі можливості є і вони заслуговують на вивчення!

Перш, ніж приступити до налагодження за допомогою WinDbg, потрібно зробити кілька нескладних рухів тіла. Відкрийте File → Symbol File Path та введіть:

SRV*C:\symbols*http://msdl.microsoft.com/download/symbols

Потім натисніть Browse та вкажіть шлях до файлів з налагоджувальною інформацією (.pdb) вашого проекту. Аналогічно в File → Source File Path вкажіть шлях до каталогу з вихідними джерелами. Якщо сумніваєтеся, вкажіть шлях, яким знаходиться файл проекту Visual Studio, не помилитеся. Потім скажіть File → Save Workspace, щоб усі ці шляхи не доводилося заново вказувати при кожному запуску WinDbg.

Тепер, коли все налаштовано, є кілька способів розпочати налагодження. Можна запустити новий процес під налагоджувачем, можна підключитися до вже існуючого, можна відкрити крешдамп. Все це робиться через меню File. На особливу увагу заслуговує можливість віддаленої налагодження. Наприклад, якщо за допомогою WinDbg ви налагоджуєте драйвери, то особливого вибору, крім використання віддаленої налагодження, у вас як би і немає. Що не дивно, адже найменша помилка в коді драйвера може призвести до BSOD.

Якщо ви вже налагоджуєте процес, але хотіли б почати робити це віддалено, кажемо:

Server tcp:port=3003

Потрібно перевірити, що порт відкритий, що особливо актуально на Windows Server. На клієнті робимо File → Connect to a Remote Session, вводимо:

tcp:Port=3003,Server=10.110.0.10

Крім того, можна запустити сервер, що дозволяє налагоджувати будь-який процес у системі:

dbgsrv.exe -t tcp:port=3003

На клієнті підключаємось через File → Connect to Remote Stub. Після цього через інтерфейс можна як завжди вибрати процес зі списку або запустити новий. Тільки працюватимуть процеси на віддаленій машині.

Тепер нарешті розглянемо основні команди WinDbg.

Важливо!Іноді команди можуть виконуватися дуже довго, наприклад, якщо ви вирішили завантажити відразу все налагоджувальні символи. Якщо втомитеся чекати, просто натисніть Ctr+C у полі введення команди, і WinDbg відразу перестане робити те, що він зараз робить.

Help
.hh команда

Очистити висновок у вікні Command:

Додати шлях, яким WinDbg шукатиме налагоджувальні символи (та ж команда без знака плюс затрем раніше прописані шляхи):

Sympath+ c:\pdbs

Перезавантажити символи:

Показати список модулів:

Шукаємо символи:

x *!Ololo::My::Namespace::*

Завантажити символи для модуля:

ld ім'я_модуля

Якщо WinDbg чомусь не знаходить. pdb файли і в стектрейсах замість імен. більше інформаціїпро можливі причинипроблеми:

Sym noisy
.reload MyModule.dll

Вказати шлях до каталогу вихідних джерел:

Поставити точку зупинки:

bp kernel32! CreateProcessA
bp `mysorucefile.cpp:123`
bp `MyModule!mysorucefile.cpp:123`
bp @@(Full::Class:Name::method)

Поставити точку зупинка, яка спрацює лише один раз:

Поставити точку зупинки, яка спрацює на 5-й раз, після 4-х проходів:

Можна автоматично виконувати команди кожного разу, коли спрацьовує точка зупинки:

bp kernel32!LoadLibraryA ".echo \"Variables:\n\"; dv"

У апаратнихточок зупинки синтаксис такий:

ba

Де mode це e, r чи w - виконання, читання, запис. При mode = e параметр size може бути лише 1. Наприклад:

ba e 1 kernel32!LoadLibraryA

Список точок зупинки:

Деактивувати точку зупинки:

Активувати точку зупинки:

Повне видалення точок зупинки:

bc номер
bc *

Показати команди, які потрібно ввести для відновлення поточних точок зупинки:

Писати лог у файл:

Logopen c:\1.txt

Перестати писати лог у файл:

Виконати команди з файлу:

Для збереження точок зупинки у файл можна виконати (обов'язково в один рядок!) такі команди:

Logopen з:\1.txt; .bpcmds; .logclose

Показати дизасемблерний лістинг:

Показати значення регістрів:

Показати стек викликів:

Те саме з номерами кадрів:

Переміщення до кадру:

Frame номер

Показати локальні змінні:

Показати структуру:

dt ім'я_змінної

Показати структуру рекурсивно:

dt -r ім'я_змінної

Дамп пам'яті за адресою:

Дамп пам'яті у вигляді word/dword/qword:

dw адреса
dd адреса
dq адреса

Дамп у вигляді бітів:

Дамп ascii рядка:

Дамп unicode рядка:

Редагування пам'яті.

Переклад статті Аллана О'Доннелла Learning C with GDB .

Виходячи з особливостей таких високорівневих мов як Ruby, Scheme або Haskell, вивчення C може бути складним завданням. На додаток до подолання таких низькорівневих особливостей C, як ручне керування пам'яттю та покажчики, ви ще повинні обходитися без REPL . Як тільки Ви звикнете до дослідницького програмування REPL, мати справу з циклом написав-скомпілював-запустив буде для Вас невеликим розчаруванням.

Нещодавно мені спало на думку, що я міг би використовувати GDB як псевдо-REPL для C. Я поекспериментував, використовуючи GDB як інструмент для вивчення мови, а не просто для налагодження, і виявилося, що це дуже весело.

Мета цього посту – показати Вам, що GDB є чудовим інструментом для вивчення С. Я познайомлю Вас з декількома моїми улюбленими командами з GDB, і продемонструю яким чином Ви можете використовувати GDB, щоб зрозуміти одну зі складних частин мови С: різницю між масивами та вказівниками.

Вступ до GDB

Почнемо зі створення наступної невеликий програмина С – minimal.c:

Int main() ( int i = 1337; return 0; )
Зверніть увагу, що програма не робить абсолютно нічого, і навіть не має жодної команди printf. Тепер поринемо в новий Світвивчення З використанням GBD.

Скомпілюємо цю програму із прапором -gдля генерування налагоджувальної інформації, з якою буде працювати GDB, і підкинемо йому цю інформацію:

$ gcc -g minimal.c -o minimal $ gdb minimal
Тепер Ви повинні блискавично опинитися в командному рядку GDB. Я обіцяв вам REPL, так отримаєте:

(gdb) print 1 + 2 $1 = 3
Дивно! print– це вбудована команда GDB, яка обчислює результат С-ного виразу. Якщо Ви не знаєте, що робить якась команда GDB, просто скористайтеся допомогою – наберіть help name-of-the-commandу командному рядку GDB.

Ось Вам цікавіший приклад:

(gbd) print (int) 2147483648 $2 = -2147483648
Я впущу пояснення того, чому 2147483648 == -2147483648 . Головна суть тут у тому, що навіть арифметика може бути підступною С, а GDB відмінно розуміє арифметику С.

Тепер давайте поставимо точку зупинки у функції mainта запустимо програму:

(gdb) break main (gdb) run
Програма зупинилася на третьому рядку, саме там, де ініціалізується змінна i. Цікаво те, що хоча змінна поки що і не проініціалізована, але ми вже зараз можемо подивитися її значення, використовуючи команду print:

(gdb) print i $3 = 32767
У значення локальної неініціалізованої змінної не визначено, тому отриманий Вами результат може відрізнятися.

Ми можемо виконати поточний рядок коду, скориставшись командою next:

(gdb) next (gdb) print i $4 = 1337

Досліджуємо пам'ять використовуючи команду X

Змінні С – це безперервні блоки пам'яті. При цьому блок кожної змінної характеризується двома числами:

1. Числова адреса першого байта в блоці.
2. Розмір блоку у байтах. Цей розмір визначається типом змінної.

Одна з відмінних рисмови С у тому, що у Вас є прямий доступ до блоку пам'яті змінної. Оператор & дає нам адресу змінної у пам'яті, а sizeofобчислює розмір, який займає змінна пам'ять.

Ви можете пограти з обома можливостями в GDB:

(gdb) print &i $5 = (int *) 0x7fff5fbff584 (gdb) print sizeof(i) $6 = 4
Говорячи нормальною мовою, це означає, що змінна iрозміщується за адресою 0x7fff5fbff5b4і займає у пам'яті 4 байти.

Я вже згадував вище, що розмір змінної пам'яті залежить від її типу, та й взагалі кажучи, оператор sizeofможе оперувати і самими типами даних:

(gdb) print sizeof(int) $7 = 4 (gdb) print sizeof(double) $8 = 8
Це означає, що щонайменше на моїй машині, змінні типу intзаймають чотири байти, а типу double- Вісім байт.

GDB має потужний інструмент для безпосереднього дослідження пам'яті – команда x. Ця команда перевіряє пам'ять, починаючи з певної адреси. Також вона має низку команд форматування, які забезпечують точний контроль над кількістю байт, які Ви захочете перевірити, і над тим, у якому вигляді Ви захочете вивести їх на екран. У разі якихось труднощів наберіть help xу командному рядку GDB.

Як Ви вже знаєте, оператор & обчислює адресу змінної, а це означає, що можна передати команді xзначення &iі тим самим отримати можливість поглянути на окремі байти, що ховаються за змінною i:

(gdb) x/4xb &i 0x7fff5fbff584: 0x39 0x05 0x00 0x00
Прапори форматування вказують на те, що я хочу отримати чотири ( 4 ) значення, виведені в шістнадцятковому (he x) вигляді по одному байту ( b yte). Я вказав перевірку лише чотирьох байт, тому що саме стільки займає у пам'яті змінна i. Висновок показує побайтове уявлення змінної пам'яті.

Але з побайтовим висновком пов'язана одна тонкість, яку потрібно постійно пам'ятати - на машинах Intel байти зберігаються в порядку "від молодшого до старшого" (праворуч наліво), на відміну від більш звичної для людини запису, де молодший байт повинен був би знаходитися в кінці (зліва направо).

Один із способів прояснити це питання – це присвоїти змінній iбільш цікаве значення і знову перевірити цю ділянку пам'яті:

(gdb) set var i = 0x12345678 (gdb) x/4xb &i 0x7fff5fbff584: 0x78 0x56 0x34 0x12

Досліджуємо пам'ять із командою ptype

Команда ptypeможливо одна з моїх найулюбленіших. Вона показує тип С-го виразу:

(gdb) ptype i type = int (gdb) ptype &i type = int * (gdb) ptype main type = int (void)
Типи С можуть ставати складними , але ptypeдозволяє досліджувати в інтерактивному режимі.

Вказівники та масиви

Масиви є напрочуд тонким поняттям у С. Суть цього пункту в тому, щоб написати простеньку програму, а потім проганяти її через GDB, поки масиви не знайдуть якогось сенсу.

Отже, нам потрібний код програми з масивом array.c:

Int main() ( int a = (1, 2, 3); return 0; )
Скомпілюйте її з прапором -g, запустіть у GDB, і з допомогою nextперейдіть до рядка ініціалізації:

$ gcc -g arrays.c -o arrays $ gdb arrays (gdb) break main (gdb) run (gdb) next
На цьому етапі Ви зможете вивести вміст змінної та з'ясувати її тип:

(gdb) print a $1 = (1, 2, 3) (gdb) ptype a type = int
Тепер, коли наша програма правильно налаштована у GDB, перше, що варто зробити – це використовувати команду xдля того, щоб побачити, як виглядає змінна a"під капотом":

(gdb) x/12xb &a 0x7fff5fbff56c: 0x01 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x7fff5fbff574: 0x03 0x00 0x00 0
Це означає, що ділянка пам'яті для масиву aпочинається за адресою 0x7fff5fbff56c. Перші чотири байти містять a, наступні чотири – a, і останні чотири зберігають a. Дійсно, Ви можете перевірити та переконається, що sizeofзнає, що aзаймає в пам'яті рівно дванадцять байт:

(gdb) print sizeof(a) $2 = 12
До цього моменту масиви виглядають такими, якими мають бути. Вони мають відповідні масиви типів і зберігають всі значення в суміжних ділянках пам'яті. Однак, у певних ситуаціях, масиви поводяться дуже схоже на вказівники! Наприклад, ми можемо застосовувати арифметичні операції до a:

(gdb) print a + 1 $3 = (int *) 0x7fff5fbff570
Нормальними словами, це означає, що a + 1- Це покажчик на int, який має адресу 0x7fff5fbff570. До цього моменту Ви повинні вже рефлекторно передавати вказівники в команду x, Отже подивимося, що сталося:

(gdb) x/4xb a + 1 0x7fff5fbff570: 0x02 0x00 0x00 0x00

Зверніть увагу, що адреса 0x7fff5fbff570рівно на чотири одиниці більше, ніж 0x7fff5fbff56c, тобто адреса першого байта масиву a. Враховуючи, що тип intзаймає в пам'яті чотири байти, можна зробити висновок, що a + 1вказує на a.

Насправді індексація масивів в С є синтаксичним цукром для арифметики покажчиків: a[i]еквівалентно *(a + i). Ви можете перевірити це в GDB:

(gdb) print a $4 = 1 (gdb) print *(a + 0) $5 = 1 (gdb) print a $6 = 2 (gdb) print *(a + 1) $7 = 2 (gdb) print a $8 = 3 (gdb) print *(a + 2) $9 = 3
Отже, ми побачили, що у деяких ситуаціях aведе себе як масив, а в деяких - як покажчик на свій перший елемент. Що ж відбувається?

Відповідь полягає в наступному, коли ім'я масиву використовується у виразі в С, воно "розпадається (decay)" на покажчик на перший елемент. Є лише два винятки з цього правила: коли ім'я масиву передається до sizeofі коли ім'я масиву використовується з оператором взяття адреси & .

Той факт, що ім'я aне розпадається на покажчик на перший елемент під час використання оператора & , породжує цікаве питання: у чому різниця між покажчиком, який розпадається aі &a?

Чисельно вони обидва представляють одну і ту ж адресу:

(gdb) x/4xb a 0x7fff5fbff56c: 0x01 0x00 0x00 0x00 (gdb) x/4xb &a 0x7fff5fbff56c: 0x01 0x00 0x00 0x00
Проте типи їх різні. Як ми вже бачили, ім'я масиву розпадається на покажчик на його перший елемент і отже має мати тип int *. Що ж до типу &a, то ми можемо запитати про це GDB:

(gdb) ptype &a type = int (*)
Говорячи простіше, &a- Це покажчик на масив із трьох цілих чисел. Це має сенс: aне розпадається під час передачі оператору & та a має тип int.

Ви можете простежити різницю між вказівником, на який розпадається aта операцією &aна прикладі того, як вони поводяться стосовно арифметики покажчиків:

(gdb) print a + 1 $10 = (int *) 0x7fff5fbff570 (gdb) print &a + 1 $11 = (int (*)) 0x7fff5fbff578
Зверніть увагу, що додавання 1 до aзбільшує адресу на чотири одиниці, в той час, як додаток 1 до &aдодає на адресу дванадцять.

Вказівник, на який насправді розпадається aмає вигляд &a:

(gdb) print &a $11 = (int *) 0x7fff5fbff56c

Висновок

Сподіваюся, я переконав Вас, що GDB – це витончене дослідне середовище для вивчення С. Вона дозволяє виводити значення виразів за допомогою команди printпобайтово дослідити пам'ять командою xта працювати з типами за допомогою команди ptype.

1. Використовуйте GDB для роботи над The ​​Ksplice Pointer Challenge.
2. Розберіться, як структури зберігаються у пам'яті. Як вони співвідносяться із масивами?
3. Використовуйте дизассемблерні команди GDB, щоб краще розібратися з програмуванням на асемблері. Особливо весело досліджувати, як працює стек виклику функції.
4. Зацініть “TUI” режим GDB, який забезпечує графічну ncurses надбудову над звичним GDB. На OS X, Вам, ймовірно, доведеться зібрати GDB з вихідних.

Від перекладача: Традиційно для вказівки помилок скористайтесь ЛЗ. Буду радий конструктивній критиці.