For the complete documentation index, see llms.txt. This page is also available as Markdown.

Using IDA's GDB debugger with QEMU emulator

Using IDA's GDB debugger with QEMU emulator

Copyright 2009 Hex-Rays SA

QEMU is a processor emulator which can emulate a handful of processors, including Intel x86 and ARM architectures. It includes a GDB stub which can be used with new GDB debugger plugin in IDA 5.4.

Getting QEMU

QEMU's home page is at http://bellard.org/qemu/. Win32 builds can be downloaded from Takeda Toshiya's page at http://homepage3.nifty.com/takeda-toshiya/qemu/. This primer assumes you downloaded QEMU 0.9.1 for Win32 or later. We will debug the small Linux included with QEMU.

Enabling GDB stub

After unpacking QEMU, make a copy of the qemu-win.bat file, for example qemu-win-gdb.bat and edit it. Add -s -S to the qemu.exe call (-s enables GDB stub and -S instructs QEMU to stop at the system start):

Editing qemu-win-gdb.bat to enable the GDB stub

Run the .bat file. QEMU will stop and wait for the debugger.

QEMU stopped, waiting for the debugger

Debugging with IDA

Start IDA.

Welcome to IDA dialog

If you get the welcome dialog, choose "Go".

Debugger, Attach, Remote GDB debugger menu

Choose Debugger | Attach | Remote GDB debugger.

Debug application setup dialog for gdb

Enter "localhost" for hostname and 1234 for the port number. Click "Debugger specific options".

GDB configuration dialog

QEMU needs special configuration because it behave slightly differently from other GDB stubs. Uncheck "Software breakpoints at EIP+1" and check "Use CS:IP in real mode". Make sure Processor is set to "Intel x86". Click OK, then click OK in "Debug application setup" dialog.

Choose process to attach to dialog

Choose <attach to the process started on target> and click OK.

Debugging the BIOS

BIOS entrypoint disassembled incorrectly as 32-bit

The BIOS entrypoint is displayed but the disassembly is wrong since the default MEMORY segment is 32-bit.

Let's create some manual memory regions to reflect the real memory map.

Debugger menu, Manual memory regions

Go to Debugger | Manual memory regions.

Manual memory regions, Insert context menu

Right-click and choose "Insert..." (or press Ins).

Add debugger memory region dialog for BIOS

Enter the following details:

Start address: F0000 End address: 100000 Base address: F000 Name: BIOS Class: CODE select "16-bit segment"

Click OK.

BIOS code disassembled correctly after adding the memory region

Now the disassembly is correct and you can trace the BIOS code.

Debugging the kernel

To debug the Linux kernel, we first need to create memory regions where it will execute. The usual kernel entrypoint is at address 100000, and it can use memory almost to the maximum 4G address.

Open memory regions list (Debugger | Manual memory regions) and add a new region:

Add debugger memory region dialog for the Linux kernel

Start address: 100000 End address: F0000000 Base address: 0 Name: LINUX Class: CODE select "32-bit segment"

Click OK.

We now have two regions:

Manual memory regions list showing BIOS and LINUX regions

Double-click the LINUX region to go to its beginning.

Add breakpoint context menu at the LINUX region start

Press F2 or choose "Add breakpoint" from the context menu.

Breakpoint settings dialog for a hardware execute breakpoint

Check "Hardware breakpoint" and select "Execute" in "Modes". Click OK.

Execution stopped at the LINUX region entrypoint

Now press F9 or choose Debugger | Continue process. You should see BIOS and LILO messages on the screen, and the execution will stop at the "Loading Linux...." message.

Initial loader decompressing the kernel

This is the initial loader which decompresses the kernel. If you press F9 once more, you'll see "Uncompressing Linux..." and then "Ok, booting the kernel" messages in QEMU and IDA will stop at the decompressed kernel entrypoint:

Code that sets up paging and jumps to the real kernel entrypoint

This code sets up paging table, enables paging, and then jumps to the "real" kernel entrypoint.

Adding symbols

Kernel symbols are available as /proc/ksyms or /proc/kallsyms pseudo-file after booting. If you get that file from the VM to the host, you can add the symbols to your disassembly. Go to File | Python command... and enter the following short script:

ksyms = open(r"D:\ksyms") #path to the ksyms file for line in ksyms: addr = int(line[:8], 16) name = line[9:-1] # use line[11:-1] in case of kallsyms idaapi.set_debug_name(addr, name) MakeNameEx(addr, name, SN_NOWARN) Message("%08X: %s\n"%(addr, name))

Click OK and wait a bit until it finishes. After that you should see the symbols in the disassembly and name list:

Kernel symbols loaded into the Names list

Happy debugging!

Copyright 2009 Hex-Rays SA

Last updated

Was this helpful?