How to step over interrupt calls when debugging a bootloader/bios with gdb and QEMU?

▼魔方 西西 提交于 2019-12-01 05:42:11

This is actually a work around that fits my purposes. What I did was setting breakpoints so I can use "continue" on gdb along with "si" and follow the message being printed on the screen, one character at a time. Here are the steps.

In the first run, I do step my bootloader, so I can actually check the memory positions where the instructions are stored.

Linux shell:

# qemu-system-i386 -fda loader.img -boot a -s -S -monitor stdio
QEMU 1.5.0 monitor - type 'help' for more information
(qemu) 

Other Linux shell (some lines have been supressed [...]):

# gdb
GNU gdb (GDB) 7.6.1-ubuntu
[...]
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x0000fff0 in ?? ()
(gdb) set architecture i8086
[...]
(gdb) br *0x7c00
Ponto de parada 1 at 0x7c00
(gdb) c
Continuando.
Breakpoint 1, 0x00007c00 in ?? ()
(gdb) si
0x00007c03 in ?? ()

In the terminal I am running QEMU monitor, I find the address of the instructions executing this command after every si on gdb:

(qemu) x /i $eip
0x00007c03:  add    $0x120,%ax

For those new to QEMU, x display the contents of a register, /i translates it into an instruction and $eip is the instruction point register. By repeating these steps, I find out the addresses for the lodsb and int 10h instructions:

0x00007c29:  lods   %ds:(%si),%al 
0x00007c2e:  int    $0x10 

So, on gdb I just set the breakpoints for these aditional positions:

(gdb) br *0x7c29
Ponto de parada 2 at 0x7c29
(gdb) br *0x7c2e
Ponto de parada 3 at 0x7c2e

Now I can use a combination of "continue" (c) and stepi (si) on gdb and skip through the whole BIOS stuff.

There is probably better ways to do this. However, for my pedagogical purposes, this method works quite well.

I've automated your procedure with a Python script that:

  • calculates the length of the current instruction
  • sets a temporary breakpoint on the next instruction
  • continues

This will also work for any other instruction, but I don't see many other use cases for it, since nexti already jumps over call.

class NextInstructionAddress(gdb.Command):
    """
Run until Next Instruction address.

Usage: nia

Put a temporary breakpoint at the address of the next instruction, and continue.

Useful to step over int interrupts.

See also: http://stackoverflow.com/questions/24491516/how-to-step-over-interrupt-calls-when-debugging-a-bootloader-bios-with-gdb-and-q
"""
    def __init__(self):
        super().__init__(
            'nia',
            gdb.COMMAND_BREAKPOINTS,
            gdb.COMPLETE_NONE,
            False
        )
    def invoke(self, arg, from_tty):
        frame = gdb.selected_frame()
        arch = frame.architecture()
        pc = gdb.selected_frame().pc()
        length = arch.disassemble(pc)[0]['length']
        gdb.Breakpoint('*' + str(pc + length), temporary = True)
        gdb.execute('continue')
NextInstructionAddress()

Just drop that into ~/.gdbinit.py and add source ~/.gdbinit.py to your ~/.gdbinit file.

Tested on GDB 7.7.1, Ubuntu 14.04.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!