GDB
This HOWTO describes the installation and setup of GDB versions as kernel debuggers for ReactOS. It focuses on the CygWin GDB since it comes with a GUI in the form of the "insight" executable, however most of the information should be applicable to other GDB versions too. Note that it is also possible to debug user mode code using this setup, you can jump between kernel mode and user mode.
Contents
Hardware setup
Since we're using the "remote" capabilities of GDB, we have to make a serial connection from the host (where GDB is running) to the target (where ReactOS is running), using a null modem cable. A cable with the following layout works (DB9 connectors):
- On each connector, tie 1, 4 and 6 (DTR, CD, DSR) together
- Cross 2 and 3 from one connector to 3 and 2 on the other one (Rx, Tx)
- Connect 5 on both connectors (GND)
- Cross 7 and 8 from one connector to 8 and 7 on the other one (RTS, CTS)
The target machine can be another computer, or it can be a VMware virtual machine. To use a VMware virtual machine install VmwareGateway from http://l4ka.org/tools/vmwaregateway.php and attach GDB to tcp\ip port:
target remote localhost:567
Installing CygWin for Windows users
Download http://www.cygwin.com/setup.exe and start it. You can use default options throughout, only make sure you select "gdb" from the "Devel" category in the package selection dialog.
Although the standard CygWin gdb/insight should work, there is a slightly modified version available at http://svn.reactos.org/downloads/gdb/gdb_reactos.zip
Changes in the modified version:
- Fix to allow hardware watchpoints for remote i386 targets
- Removed a check to allow stack back tracing from kernel mode back into user mode
- Mark insight.exe as a Windows subsystem executable (as opposed to a console subsys executable)
You can download the .zip file and replace the CygWin gdb.exe, gdbtui.exe and insight.exe (if you used defaults they will be located in C:\cygwin\bin) with the versions in the .zip file. If you use the modified version, you still need to install the CygWin gdb package, since it contains some support files that are not included in the .zip
For instructions on how to build the modified version from source see the end of this document.
GDB for Linux users
By default, GDB is compiled to handle ELF executables. In order to get the best debugging experience with GDB, getting a version able to support Windows executable is highly recommended. The easiest way is to install the mingw-w64 version of GDB provided by your Linux distribution. If your distribution doesn't have one, you can compile it from source. Run those commands:
wget http://ftp.gnu.org/gnu/gdb/gdb-9.1.tar.xz tar xf gdb-9.1.tar.xz cd gdb-9.1 mkdir build cd build ../configure --prefix=/opt/pe-gdb --target=i686-w64-mingw32 --enable-lto --with-python=/usr/bin/python --with-system-readline --with-expat make sudo make install
Then you can launch GDB with
/opt/pe-gdb/bin/i686-w64-mingw32-gdb
Preparing ReactOS
ReactOS has a new GDB stub in a form of a KDCOM module. But, since KDCOM is disabled by default in GCC builds, it must be enabled. The cleanest way to achieve this is to create a new build directory, and run inside a RosBE session:
cd output-i686-mingw-newbuild /path/to/reactos/configure.sh -D_WINKD_:BOOL=TRUE -DGDB:BOOL=TRUE -DSEPARATE_DBG:BOOL=TRUE -DKDBG:BOOL=FALSE ninja bootcd
A new bootcd with GDB debugging enabled is ready to be installed. Note that you must attach gdb to the installer too.
If you want to keep your current build directory, you can just set the variables in the CMakeCache.txt of the build folder
Starting a debug session
Before debugging ReactOS, make sure it can find debug symbols. They are located in /path/to/build/symbols. Enter:
set solib-search-path /path/to/build/symbols
Then connect to the server with:
target remote localhost:567
GDB should break at the debug trap function, type "c" to continue execution. Then you can enter the debugger by typing "Tab+K" into ReactOS console, or "Ctrl+C" into GDB. GDB show a lot of started threads, because the stub started to list all the threads running in the system.
Type bt
to view the stack trace, which should look like something like this:
(gdb) bt #0 RtlpBreakWithStatusInstruction@0 () at /home/sdever/Documents/ReactOS/reactos/sdk/lib/rtl/i386/debug_asm.S:56 #1 0x80895ee9 in @KeUpdateSystemTime@12 (TrapFrame=0x809e6ca4 <P0BootStackData+11428>, Increment=149952, Irql=2 '\002') at /home/sdever/Documents/ReactOS/reactos/ntoskrnl/ke/time.c:101 #2 0x802eb7b4 in @HalpProfileInterruptHandler@4 (TrapFrame=0x809e6ca4 <P0BootStackData+11428>) at /home/sdever/Documents/ReactOS/reactos/hal/halx86/generic/timer.c:199 #3 0x802ec9f7 in _stricmp (s1=0x249c0 '?' <repeats 200 times>..., s2=0x20ac <error: Cannot access memory at address 0x20ac>) at /home/sdever/Documents/ReactOS/reactos/sdk/lib/crt/string/stricmp.c:10 #4 0x802eb4f2 in HalSetProfileInterval@4 (Interval=10382640) at /home/sdever/Documents/ReactOS/reactos/hal/halx86/generic/profil.c:102 #5 0x8090cf47 in @PopIdle0@4 (PowerState=<optimized out>) at /home/sdever/Documents/ReactOS/reactos/ntoskrnl/po/power.c:484 #6 0x80937852 in @KiIdleLoop@0 () at /home/sdever/Documents/ReactOS/reactos/ntoskrnl/ke/i386/thrdini.c:320 #7 0x8098b8b7 in KiSystemStartupBootStack@0 () at /home/sdever/Documents/ReactOS/reactos/ntoskrnl/ke/i386/kiinit.c:686 #8 0x0000000e in ?? () #9 0x00000000 in ?? ()
At this point, only ntoskrnl.exe and hal.dll symbols are loaded. If you want to put breakpoints into other drivers, you must load symbols with sharedlibrary
command.
You can also examine kernel structures, for instance:
(gdb) print ((KPCR*)0xffdff000)->Prcb->CurrentThread->Process $2 = (_KPROCESS *) 0x809ec080 <KiInitialProcess> (gdb) print (_EPROCESS *)$2->ImageFileName There is no member named ImageFileName. (gdb) print ((_EPROCESS *)$2)->ImageFileName $3 = "Idle", '\000' <repeats 11 times>
Debugging the early boot process
It is possible to debug the boot process using GDB with QEMU in the following way;
Start QEMU like this
qemu-system-i386 -s -S -m 512 -hda "$HOME/VirtualBox VMs/reactos/reactos.qcow"
-s
will open a gdbserver at tcp port 1234-S
will not start the CPU at startup of qemu-m 512
sets the ram size to 512 MB-hda <path>
specified the hard disk image
Create a ~/.gdbinit
which looks like this. (you can also enter these commands at the gdb prompt instead):
set disassembly-flavor intel layout asm layout regs target remote localhost:1234 set architecture i8086 break *0x7c00 break *0x7e00
Now start gdb
. It will automatically execute the commands from the ~/.gdbinit
file.
As the bios will load the MBR at memory location 0x0000:0x7c00, and you have set a breakpoint, you can simply enter c
or cont
to jump to the start of the bootstrap code.
The reactos bootstrap code in the MBR will relocate itself to 0x1FE0:0x7c00 and load the bootrecord of the active partition at 0x0000:0x0600 and jumps to that location. The same breakpoint will hit, so we can enter c
again. Note that gdb did not update the disassembly. You can enter layout asm
and layout regs
to fix this, but the correct code will be executed, even if you don't do that.
The bootstrap code in the bootrecord, will load sector 14 of a FAT32 volume to 0x0000:0x7e00 and continue executing there. Entering c
will hit that breakpoint.
freeldr.sys will be loaded at 0x0000:0xF800, so you can set a breakpoint there too, to continue there.