Using gdb on windows

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

В нашей повседневной работе, как и всем, требуется много пользоваться отладчиком. В силу специфики работы: (разработка ОС, использование технологий виртуализации наподобие Intel-VT, ит.д.) нам часто требуется использовать отладчик для работы со специфическими случаями: отладка кода загрузчика ядра, отладка загрузчиков виртуальных машин, а так же в принципе обеспечение возможности отлаживать ОС собственной разработки. Именно эти особые случаи так пафосно названы в заголовке ”по максимуму”.

Для решения всех этих задач (и конечно, многих других) мы используем gdb. Возможно использование и таких оболочек как DDD, но лично я предпочитаю использовать cgdb как оптимальный выбор, особенно для случая работы с отладчиком по ssh.
В этой статье мы расскажем о том, как можно использовать gdb для отладки кода загрузочных секторов и загрузчиков.

В начале разработки любой новой ОС, требуется обеспечить и наличие банального загрузчика для этой ОС. «Правда жизни» разработчика ОС заключается в первую очередь в том, что процессор начинает выполнять код загрузочного сектора срезу после BIOS Post в Real Mode. На этот момент никакой ОС еще не загружено (только 512 байт загрузочного сектора), в то время как для полноценной поддержки отладчика нам требуется реализация особого модуля в ядре ОС (об этом подробнее в части 2). Возникает вопрос: как же отлаживать код бут-сектора и загрузчика? Ведь до начала работы с основным отладчиком ОС (через специальный модуль) необходимо провести загрузку в оперативную память “загрузчика системы”, загрузку ядра и его базовых модулей, базовую инициализацию аппаратуры (для работы с gdb нужен по крайней мере Serial Port), и только потом работа с полноценным отладчиком ОС становится возможной.
Решить эту проблему можно, как оказывается, довольно просто: нужно начать загрузку ОС внутри какой-нибудь виртуальной машины, которая поддерживает встроенные функции отладки.

В качестве примера приведем описание использования qemu:
1. Запускаем виртуальную машину (для примера используется простая загрузка ОС с дискеты):
qemu -fda ./boot.fdd -s -S -vnc none &
(Запускаем qemu виртуальную машину, которая будет загружаться с дискеты, образ которой находится в файле “./boot.fdd”; “-s –S” означает, что машина запустится в приостановленном режиме и в режиме отладки; “-vnc none” означает, что машина запустится без активного терминала (то есть, в фоновом режиме – особенно удобно при работе через ssh, да и для отладки загрузчика и бут сектора видеть экран компьютера редко требуется); “&” — запускаем виртуалку в фоновом режиме).
2. Теперь, запускаем сам отладчик gdb:
$ gdb
GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
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 «i686-linux-gnu».
For bug reporting instructions, please see:
.
(gdb)
3. В отладчике gdb коннектимся к порту qemu:
(Gdb) target remote localhost: 1234

Кстати этот порт виден в netstat:
$ netstat –tlpn
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0: 1234 0.0.0.0:* LISTEN 4014/qemu

Обратите внимание на адрес, с которого мы начинаем отладку:
(gdb) target remote localhost: 1234
Remote debugging using localhost: 1234
0x0000fff0 in ?? ()
(gdb)

С этого адреса начинает свою работу любой процессор при включении питания. Другими словами мы оказались прямо в начале работы BIOS (внутри виртуальной машины, естественно).
4. Далее нам надо подготовить gdb к отладке Real Mode кода:
(gdb) set arch i8086
The target architecture is assumed to be i8086
(gdb)

5. Теперь нам нужно поставить первый брэйкпоинт на начало нашего загрузочного сектора:
(gdb) break * 0x7c00
Breakpoint 1 at 0x7c00
(gdb)

(BIOS загрузит первые 512 байт с указанного устройства (с дискеты) в память по адресу 0x7c00 и передаст управление на эту область памяти).

6. Прыгаем в наш загрузочный сектор:
(gdb) c
Continuing.

Читайте также:  При перезагрузке компьютер не включается windows 10

Breakpoint 1, 0x00007c00 in ?? ()
(gdb)

7. Готово! Можно отлаживать наш код!
Существует ряд особенностей отладки кода отладчика, с которыми приходится работать.
Во-первых, нужно учитывать особенности адресации данных в режиме RealMode. Любая информация адресуется как segment:offset, при этом адрес можно посчитать как: segment * 16 + offset. Это означает, что для того, чтобы прочитать первые 10 инструкций кода, начиная с текущей инструкции, нужно использовать команду: (gdb) x/10i $cs*16+$eip . Неудобство в данном случае заключается в том, что текущую инструкцию gdb показывает без учета базы сегмента кода:
(gdb) x/10i $cs*16+$eip
0x80000: jmp 0x90013
0x80002: (bad)
0x80003: mov $0x8,%di
0x80006: add $0xff,%al
0x80008: aas
0x80009: add %al,(%bx,%si)
0x8000b: add %al,(%bx,%si)
0x8000d: add %al,(%bx,%si)
0x8000f: add %al,(%bx,%si)
0x80011: add %al,(%bx,%si)
(gdb)

В то время как адрес инструкции равен:
Program received signal SIGTRAP, Trace/breakpoint trap.
0x00000000 in ?? ()
(gdb)

Во-вторых, приходится вручную устанавливать и снимать брэйкпоинты. Это означает, что если вы поставили брэйкпоинт на адрес:
(gdb) break *0x80017
Breakpoint 4 at 0x800 17

…затем попали на него.
(gdb) c
Continuing.

Program received signal SIGTRAP, Trace/breakpoint trap.
0x000000 17 in ?? ()
(gdb)

…а потом сделаете stepi, то вы опять попадете на брэйкпоинт, вместо выполнения самой инструкции и перехода на следующую:
Program received signal SIGTRAP, Trace/breakpoint trap.
0x000000 17 in ?? ()
(gdb) stepi
0x000000 17 in ?? ()
(gdb)

Поэтому, процесс отладки может выглядеть примерно следующим образом:
1. где-то в коде загрузчика:
Program received signal SIGTRAP, Trace/breakpoint trap.
0x00000023 in ?? ()
(gdb) x/10i $cs*16+$eip
0x80023: mov %ebx,0xb
0x80028: movl $0x0,0xf
0x80031: call 0x80c15
0x80034: or %ax,%ax
0x80036: je 0x80087
0x80038: call 0x809af
0x8003b: call 0x80193
0x8003e: or %ax,%ax
0x80040: je 0x80268
0x80042: mov $0x3f4,%dx
(gdb)
2. ставим брэйкпоинт, срезу после call:
(gdb) break *0x8003e
Breakpoint 6 at 0x8003e

3. запускаем программу до этого брэйкпоинта:
(gdb) c
Continuing.

Program received signal SIGTRAP, Trace/breakpoint trap.
0x0000003e in ?? ()
(gdb)
4. удаляем брэйкпоинт:
(gdb) delete 6
(gdb)

5. проверяем возвращаемое значение:
(gdb) print /x $ax
$2 = 0x8000
(gdb)

6. делаем шаг далее:
(gdb) stepi
0x00000040 in ?? ()
(gdb)

А вот так можно прочитать значение одного из параметров функции:
(gdb) x/1w $ss*16+0x12
0x70012: 0x00b8fa00
(gdb)

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

Debugging with GDB in VSCode on Windows

I’m at a bit of a loss here, I hadn’t really expected this to be difficult. I usually work on Linux, but today I had some work that I needed to do and only had a Windows machine. I thought this would be no problem, I can install git for windows, clone my project, and get right to work. Its just been a huge mess. I’m really hoping someone can help me understand where I went wrong in setting all this up on Windows. It isn’t something I plan to do frequently, but definitely something I want to be able to do on a Windows machine in a reasonable amount of time.

I’m using WSL and have set my default VSCode Windows integrated terminal to C:\WINDOWS\System32\bash.exe

I installed Windows 10 SDK to fix crtdbg.h include errors as a dependency against

I installed gdb with MinGW —

I set the path environment variable

I created a launch.json —

My MinGW bin contains the following

I launch my debug task in VSCode and I get the following error

I can provide more information if needed. I’m really hoping I missed something simple here that would be obvious to someone who works on Windows.. Thank you in advance, I really appreciate the help!

Debugging with GDB on Windows using Visual Studio Code

Jun 6, 2020 · 4 min read

So you are someone who likes developing in C/C++, and prefers to work on Linux with GCC. For some reason, you need to work on Windows now and you find yourself wondering : ‘Can I compile and debug C/C++ on Windows without using Microsoft’s MSVC compiler, or downloading the clunky Visual Studio ?(Aficionados, please don’t take offence here). And can my build commands and ‘feel’ stay similar to that on Linux?’. Yes! Wonder no more.

So MinGW is the GCC port f or Windows that allows you to build native Windows applications [1]. An installer for MinGW is available here. Bundled with this installation comes GDB, a classic debugger for C/C++ [2]. You can find it at path\\to\\MinGW\\bin\\gdb.exe `. So now you have a C/C++ compiler and a debugger. You compile your target. How do you debug it?

Читайте также:  Не работает передний разъем usb windows 10

Tangent Note : In order to compile C/C++ code using MinGW and CMake, you need to generate MinGW specific makefiles before using the mingw make utility. Specifying a debug build type using the CMake option is necessary for the debugger to be able to find the breakpoints (no symbol file will be created otherwise).[3]

It is possible to debug with GDB on a terminal using its minimalist GUI [4]. However, using an editor that has built in support for GDB can make your debugging life easier by providing friendly UI for setting breakpoints, and stepping over/into/out-of/etc. [5] functions and loops during the debugging process. Visual Studio is one such fairly light weight and very functional editor that provides good support for GDB. Let’s see how to configure it to debug with GDB.

You can follow the following steps to set up a debugger in your visual studio code :

2. Click on the debugger symbol on the left-side panel. This will prompt you to create a ‘launch.json’. When asked to choose a debugger, choose ‘gdb’.

3. Create a ‘tasks.json’ under the ‘.vscode’ directory at the root of your project and paste the following into it. We will use this file to configure commands to be executed before the debugger is launched.

The “command” field specifies a bat file named “debug_compilation_commands”. These are the commands that will be associated with the “build” label and be used later as tasks that need to be executed before launching the debugger. An example bat file is presented below:

4. Into the launch.json in your ‘.vscode’ directory, paste the following.

5. Edit the “miDebuggerPath” in ‘launch.json’ to point it to the ‘gdb’ bundled with your MinGW installation (refer the previous step for ‘launch.json’). In the snippet above, it’s specified as “C:/MinGW/bin/gdb.exe”

6. Edit the “program” in ‘launch.json’ to point it to the path of the executable that you want to debug (somewhere in your build directory). Note that the “preLaunchTask” specifies “build”. This is the task configured in task.json in step 3.

7. In one of the source files used by the executable you want to debug, place a breakpoint.

8. Click again on the debugger symbol on the left side pane. From the ‘run and debug’ menu, choose gcc.exe debug

9. Now click on the play symbol to start debugging.

If everything went as expected, you will see a debug navigation menu along with a cursor pointing to the line in the file where you set your breakpoint.

If you want to learn more about navigation in the debug process, refer to [5]. If you found this article useful, leave me some claps and comments. Cheers.

Команды GDB, о которых вы возможно не знали

Отладка кода — это как охота. Охота на баги.
— Amit Kalantri

Что такое GDB

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

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

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

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

Объект Что значит
Caesar::shift Свойство Caesar
Caesar::ChangeShift Метод Caesar
Caesar::Crypt Метод Caesar

Интерфейс в консоли (TUI)

Я всегда включаю TUI, как только зайду в GDB, он позволяет посмотреть где именно находится выполняемая строка, что идёт перед ней, что дальше. Включается TUI в GDB командой tui enable

С помощью колесика мыши (или стрелок) вы можете перемещаться по псевдо-интерфейсу вверху. С помощью комбинации клавиш Ctrl + p (previous), Ctrl + n (next), вы можете перемещаться между введёнными командами в терминале (окно внизу).

Тезис: Для включения псевдо-интерфейса используют команду tui enable , для выключения — tui disable .

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

Точки останова можно ставить с помощью команды breakpoint (сокращение — b).
Можно ставить точки останова исходя из следующих принципов:

  • Точкой останова может являться имя функции (метода) или переменной
  • Точкой останова может являться номер строки
  • Точкой останова может являться адрес памяти, в котором располагается инструкция
  • Точкой останова может являться условие

Если с тремя первыми всё понятно, то четвёртый принцип — достаточно интересный.

b Method if variable == value — примерно такой синтаксис используется для задания точки останова исходя из выполнения условия.

Тут сказано поставить точку останова на методе Crypt() , если свойство класса Caesar под названием shift будет равно 1.

Дополнительно: точки останова можно удалять с помощью команды delete , или её сокращения d .

Тезис: Точки останова можно ставить четыремя способами: с помощью имени объекта, с помощью номера строки, с помощью адреса, с помощью условия.

Шаг с входом в Scope, шаг без входа

Различие между командами next и step (сокращения: n и s) состоит в том, что next выполняет код не входя в Scope (не входя внутрь функции или метода), тогда как step просто выполняет шаг и аналогичен команде Step In в обычных дебагерах.

Дополнительно: для выполнения программы до точки останова используют continue , для выхода из функции в которую вы вошли используют finish или fin .

Тезис: Для вхождения в функцию используется step , для обычного выполнения — next .

Просмотр переменных разными способами

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

Команда display

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

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

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

Команда explore

Иногда бывает такое, что информации до того много, что путаешься какой объект за что отвечает, для этого создали explore .

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

Тезис: Кроме команды print можно использовать команды explore и display .

Запись логов работы программы

Иногда нужно «перемотать вспять» момент, где случилась ошибка, для этого придумана команда record , которая может полностью записывать логи программы в файл или просто в память, дабы перемотать некоторые моменты вспять или посмотреть что именно вызвало ошибку

Для того, чтобы остановить запись и удалить все логи — нужно ввести record stop , для того, чтобы сохранить все логи в файл нужно ввести record save .

Тезис: GDB имеет возможность создать лог работы программы, с помощью которого, мы можем перемещаться по программе вспять.

Просмотр информации

Просмотреть сразу все локальные переменные можно с помощью info local :

Просмотреть все переменные, которые инициализированы можно с помощью info variables :

Чтобы посмотреть все точки останова можно ввести info b :

Вы также можете посмотреть тип переменной с помощью команды whatis :

Чтобы посмотреть адрес функции, вы можете использовать info address :

Заключение

Есть ещё куча команд, которые я не привёл в данной статье, однако, на мой взгляд они являются столь полезными, как те, что я перечислил выше. Вы можете почитать больше о разработке на Linux в моём телеграм-канале, если вам это нужно. Я периодически пишу о фулл-стак разработке, а также о Unix-подобных системах.

В данной статье не указаны некоторые команды, которые легки для понимания, например: run, stop, quit, и т.д. Не указал я их специально, так как статья пытается нести информацию, о которой пользователи GDB возможно могли не знать. Если у вас есть предложения чем можно дополнить статью, с радостью почитаю комментарии.

Читайте также:  Hp ews драйвер windows 10 для laserjet p1102 не устанавливается
Оцените статью