使用gdb在qemu中调试时错误的内存位置

时间:2014-03-10 12:56:02

标签: assembly gdb qemu osdev gdbserver

我在汇编程序中编写了一个小内核。我在QEMU运行它并且遇到一些bug问题。现在我想用dbg调试内核。所以我这样组装起来了:

$ nasm -g -f elf -o myos.elf myos.asm
$ objcopy --only-keep-debug myos.elf myos.sym
$ objcopy -O binary myos.elf myos.bin

然后我在QEMU中运行:

$ qemu-system-i386 -s -S myos.bin

然后我用gdb连接:

$ gdb
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x0000fff0 in ?? ()
symbol-file myos.sym
Reading symbols from /home/sven/Projekte/myos/myos.sym...done.

我的内核中有一个名为welcome的标签,指向一个字符串。测试时,我试着查看该字符串,结果如下:

(gdb) x/32b welcome
0x1e <welcome>: 0x00    0xf0    0xa5    0xfe    0x00    0xf0    0x87    0xe9
0x26:   0x00    0xf0    0x6e    0xc9    0x00    0xf0    0x6e    0xc9
0x2e:   0x00    0xf0    0x6e    0xc9    0x00    0xf0    0x6e    0xc9
0x36:   0x00    0xf0    0x57    0xef    0x00    0xf0    0x6e

标签的定义如下:

welcome: db "System started. Happy hacking!", 10, 0

所以你可以看到,gdb假装以null字节开始欢迎启动,但根据定义它不是。但是内核正确地使用了标签,因此它看起来不像是我的代码的问题。检查内存的其他部分与加载的内核完全不匹配。

有没有人知道为什么虚拟机的内存与加载的内核不匹配,而机器仍然具有核心行为?

1 个答案:

答案 0 :(得分:3)

说明

  • qemu-system-i386 在运行时在地址0x7c00处加载x86引导扇区图像文件的第一个字节。
  • 您的ELF文件(myos.elfmyos.sym)错误地通知GDB代码将在地址0加载。因此,GDB认为welcome处于0x1e,而实际上是0x7c1e0x7c00
  • x/32xb (welcome + 0x7c00)添加到GDB中的所有地址会起作用但是很笨拙:welcome
  • 更好的解决方案是使用正确的地址创建ELF文件。

解决方案

<强> boot.asm

; 'boot.asm'
; loaded by BIOS

[bits 16]

global main
main:
mov di, welcome
print_welcome:
mov ah, 0x0e
mov al, [di]
int 0x10
inc di
cmp byte [di], 0
jne print_welcome
hlt

db "XXXXXXXXXXXXXX" ; some padding to make welcome appear at 0x1e
welcome: db "System started. Happy hacking!", 10, 0

; x86 boot sector padding and signature
; NOTE: intentionally commented out. Will be added by linker script
;times 510 - ($ - $$) db 0x00
;db 0x55, 0xAA

<强> x86的boot.ld

ENTRY(main);
SECTIONS
{
    . = 0x7C00;
    .text : AT(0x7C00)
    {
        _text = .;
        *(.text);
        _text_end = .;
    }
    .data :
    {
        _data = .;
        *(.bss);
        *(.bss*);
        *(.data);
        *(.rodata*);
        *(COMMON)
        _data_end = .;
    }
    .sig : AT(0x7DFE)
    {
        SHORT(0xaa55);
    }
    /DISCARD/ :
    {
        *(.note*);
        *(.iplt*);
        *(.igot*);
        *(.rel*);
        *(.comment);
/* add any unwanted sections spewed out by your version of gcc and flags here */
    }
}

使用以下代码构建代码:

nasm -g -f elf -F dwarf boot.asm -o boot.o
cc -nostdlib -m32 -T x86-boot.ld -Wl,--build-id=none  boot.o -o boot
objcopy -O binary boot boot.good.bin

<强>转储welcome.gdb

target remote localhost:1234
symbol-file boot
monitor system_reset
# run until hlt instruction, address obtained through disassembly
until *0x7c0f
x/32xb welcome

monitor quit
disconnect
quit

示例会话:

$ qemu-system-x86_64 -s -S boot.good.bin &
$ gdb -q -x dump-welcome.gdb
0x0000fff0 in ?? ()
main () at boot.asm:16
16  hlt
0x7c1e :   0x53    0x79    0x73    0x74    0x65    0x6d    0x20    0x73
0x7c26: 0x74    0x61    0x72    0x74    0x65    0x64    0x2e    0x20
0x7c2e: 0x48    0x61    0x70    0x70    0x79    0x20    0x68    0x61
0x7c36: 0x63    0x6b    0x69    0x6e    0x67    0x21    0x0a    0x00

思维过程

您转储的32个字节中的大多数都具有≥0.080的值,即它们不是可打印的ASCII字符。这提出了一个问题:真的倾销了正确的地址吗?

welcome消息的十六进制转储应为:

$ python -c 's = "System started. Happy hacking!"; print [hex(ord(x)) for x in s ]'
['0x53', '0x79', '0x73', '0x74', '0x65', '0x6d', '0x20', '0x73', '0x74', '0x61', '0x72', '0x74', '0x65', '0x64', '0x2e', '0x20', '0x48', '0x61', '0x70', '0x70', '0x79', '0x20', '0x68', '0x61', '0x63', '0x6b', '0x69', '0x6e', '0x67', '0x21']

使用GDB在内存中搜索{{1}}消息也会显示正确的地址:

(gdb) find 0, 0xffff, 'S', 'y', 's', 't'
0x7c1e

进一步阅读