Reputation: 3164
I'm trying to debug an x86 bootloader I am writing using gdb. Since gdb doesn't seem to handle 16-bit real mode very well I am using a gdb script someone else wrote for this purpose.
A minimal example of the code I'm trying to debug looks like this (file asm/boot.asm
):
bits 16
global _start
_start:
; zero DS
xor ax, ax
mov ds, ax
; TODO
sleep:
jmp sleep
times 510-($-$$) db 0 ; zero out rest of section
dw 0xAA55 ; add boot signature (needed by qemu)
I execute the following commands to create a debuggable elf file from this as well as a flat binary that I copy to the beginning of a dummy floppy disk image:
nasm -i asm -f elf64 -g -F dwarf asm/boot.asm -o out/boot.o
ld -Ttext=0x7c00 -melf_x86_64 out/boot.o -o out/boot.elf
objcopy -O binary out/boot.elf out/boot.img
dd if=/dev/zero of=imgs/os.flp bs=512 count=1000
dd if=out/boot.img of=imgs/os.flp bs=512 count=1 conv=notrunc
I run this image under qemu
with:
qemu-system-x86_64 -nographic -drive format=raw,file=imgs/os.flp,index=0,if=floppy -S -s &
And attach gdb with:
gdb out/boot.elf \
-ex "target remote localhost:1234" \
-x gdbinit_real_mode.txt \
-ex "break _start" \
-ex "continue"
where gdbinit_real_mode.txt
is the linked script.
This doesn't really work, because the script contains a function compute_regs
that set (among others) $rip
to $cs * 16 + $eip
. I understand that this is done because in real mode memory is addressed using segment + offset registers but gdb is not aware of this by itself. However, the following gdb command inside compute_regs
fails with "Invalid cast" (and it seems that actually any access to $eip
fails in this manner):
set $rip = ((((unsigned long)$cs & 0xFFFF) << 4) + ((unsigned long)$eip & 0xFFFF)) & $ADDRESS_MASK
Why is that and how can I fix it? I'm using nasm 2.15.05
, qemu 5.1.0
and gdb 9.2
on a 64 bit Linux host.
Upvotes: 2
Views: 267
Reputation: 47593
The script was designed to be used while GDB is running in 32-bit mode. GDB is assuming 64-bit code because you are using a 64-bit ELF file to debug from. Since this isn't 64-bit code you could change NASM's command line to use -f elf32
instead of -f elf64
and then use the LD option -melf_i386
instead of -melf_x86_64
. Doing this should generate a 32-bit ELF executable and the script should work.
Alternatively if you want to use that script with a 64-bit ELF you will probably have to changed $eip
to $rip
.
I would also recommend then using qemu-system-i386
when debugging 32-bit code via GDB. You may run into more issues if you use qemu-system-x86_64
when trying to debug 32-bit ELF executables running in 16-bit mode.
Upvotes: 3