如何解决qemu gdb调试错误:远程“g”数据包的回复太长?

9
我目前正在学习引导程序和内核开发(刚开始)。我正在结合使用以下两个资源: https://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf, 以及在 https://github.com/cfenollosa/os-tutorial 中找到的代码。
唯一不同的是,我将目标定为x86_64而不是i386。此外,我使用qemu进行仿真(qemu-system-x86_64)。 现在,在遵循GitHub存储库中的16-video-driver部分后,我卡住了,因为屏幕驱动程序确实向屏幕打印了一些东西,但是数据似乎存在错位或其他问题。所以下一步我想尝试调试我的程序。这也在存储库的14-checkpoint部分中有所涉及。因此,我为目标x86_64-elf构建了gdb。但是,当我尝试运行system-qemu-x86_64 -s -S -fda os-image以及运行gdb并尝试通过运行target remote localhost:1234连接到qemu时,一旦我运行,就会收到以下错误消息。
Remote debugging using localhost:1234
warning: No executable has been specified and target does not support
determining executable automatically.  Try using the "file" command.
Remote 'g' packet reply is too long (expected 308 bytes, got 536 bytes):
000000000000000000000000000000000000000000000000630600000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000f0ff0000000000000200000000f00000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000007f03000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000801f0000

有没有什么想法我错过了/做错了?如果需要更多信息,请让我知道。谢谢。
编辑:我已经应用了@MichaelPetch提到的补丁,现在g packet错误已经消失了。 但是看起来gdb无法解释我的可执行文件,因为在运行target remote localhost:1234然后symbol-file kernel.elf之后,终端现在返回
Remote debugging using localhost:1234 warning: No executable has been
specified and target does not support determining executable automatically.
Try using the "file" command. 0x0000fb38 in ?? ()

我可以在函数和行号上设置断点。但当我尝试使用print terminal_buffer打印应该在当前位置可用的变量时,会出现No symbol "terminal_buffer" in current context.。terminal_buffer是在当前范围内声明的变量。

然而,当我打印一个在当前函数作用域之外声明的变量(例如int),print确实返回一个值,但该值为0(我认为这是该类型的初始值),但根据我的代码,它应该已经被设置为新值。此外,尝试next时,它返回Cannot find bounds of current function,这让我认为它无法解释某些部分。

在我的引导加载程序中,我使用以下方法进入保护模式以运行64位内核:

[bits 16]
switch_to_pm:
    cli ; 1. disable interrupts
    lgdt [gdt_descriptor] ; 2. load the GDT descriptor
    mov eax, cr0
    or eax, 0x1 ; 3. set 32-bit mode bit in cr0
    mov cr0, eax
    jmp CODE_SEG:init_pm ; 4. far jump by using a different segment

[bits 32]
init_pm: ; we are now using 32-bit instructions
    mov ax, DATA_SEG ; 5. update the segment registers
    mov ds, ax
    mov ss, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov ebp, 0x90000 ; 6. update the stack right at the top of the free space
    mov esp, ebp

    call BEGIN_PM ; 7. Call a well-known label with useful code

有什么想法吗?

1
BOCHS可能会很有用:它是另一个x86仿真器,但它内置了调试器,不仅仅是GDB远程目标。(虽然我都没怎么用过,所以不知道qemu-system-x86_64是否像PC遗留BIOS一样在实模式下启动,还是使用EFI之类的长模式引导。) - Peter Cordes
2
通常在从实模式切换到保护模式或切换到64位长模式时会出现此错误。GDB并不总是正确跟踪所有情况下的模式更改,因此会出现此错误。如果调试引导加载程序,建议使用Bochs,因为它可以理解模式之间的转换。在某些情况下,您可以在出现此错误后设置新的架构,然后重新启动调试会话,但这并不总是有效。我记得曾经写过一个关于此问题的SO答案,但目前找不到那个答案了。 - Michael Petch
1
可能是 如何使用 QEMU 和 GDB 调试内核 的重复问题。 - Michael Petch
1
在OSDev Wiki上列出了一些其他可能的解决方法:https://wiki.osdev.org/QEMU_and_GDB_in_long_mode - Michael Petch
1
我已经应用了补丁,现在g数据包错误已经消失了。然而,看起来gdb无法解释我的可执行文件,在运行target remote localhost:1234symbol-file kernel.elf之后,终端显示:Remote debugging using localhost:1234 warning: No executable has been specified and target does not support determining executable automatically. Try using the "file" command. 0x0000fb38 in ?? () - Jaap Wijnen
显示剩余9条评论
2个回答

4
所有问题的原因是你正在编译64位代码并在32位保护模式下运行它。64位代码无法在这种环境下正常运行。奇怪的是,当你尝试写入视频显示器时,它经常首先表现出来。通常会打印一些东西,但并不像你想要的那样。错误解码指令将导致调试器像你观察到的那样工作不稳定。

解决问题的一种方法是将内核编译和链接为32位可执行文件。你正在使用64位编译器,所以你需要添加-m32 CFLAGS(或你的GCC命令行)。如果使用LD进行链接,则需要-melf_i386 。使用NASM汇编应该是-felf32 而不是-felf64

另外,你需要在引导装载程序中将处理器置于64位长模式。你可以在OSDev wiki上阅读更多关于此过程的信息。

如果调试32位代码,你可能希望使用qemu-system-i386。这样你就会少遇到一些麻烦。


2

连接和断开连接

我按照以下方式详细说明让它工作:如何使用GDB和QEMU调试Linux内核?

关键是在GDB上进行连接和断开连接:

gdb \
    -ex "add-auto-load-safe-path $(pwd)" \
    -ex "file vmlinux" \
    -ex 'set arch i386:x86-64:intel' \
    -ex 'target remote localhost:1234' \
    -ex 'break start_kernel' \
    -ex 'continue' \
    -ex 'disconnect' \
    -ex 'set arch i386:x86-64' \
    -ex 'target remote localhost:1234'

相关文章: 远程 'g' 数据包回复过长


请注意,这篇文章涉及到IT技术相关内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接