How to solve qemu gdb debug error: Remote 'g' packet reply is too long?
Asked Answered
D

2

11

I'm currently getting into bootloaders and kernel development (very much beginning) I'm following a combination of https://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf and the code found in https://github.com/cfenollosa/os-tutorial

The only thing im doing differently is that I'm targeting x86_64 instead of i386. Also I'm using qemu to emulate (qemu-system-x86_64). Now after following the GitHub repo to part 16-video-driver I get stuck as the screen driver does print some stuff to the screen but something's going on with a misalignment of data or something. So next I wanted to try to debug my program. This is also covered in part 14-checkpoint of the repo. So I built gdb for target x86_64-elf. But when I try to run qemu and gdb using system-qemu-x86_64 -s -S -fda os-image and then just run gdb and try to connect to qemu by running target remote localhost:1234, as soon as I run that I get the following error message

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

Any ideas on what I'm missing / doing wrong? If more information is needed please let me know.

Thanks

EDIT: I've applied the patch mentioned by @MichaelPetch and now the g packet error is gone. However it looks like gdb can't interpret my executable as after running target remote localhost:1234 and then symbol-file kernel.elf, the terminal now returns

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 ?? ()

I am however able to set breakpoints on functions and line numbers. But when trying to print variables that should be available at the current location using print terminal_buffer I get No symbol "terminal_buffer" in current context. terminal_buffer being a variable declared in the current scope.

However when I print a variable declared outside the scope of the function in which I have put my breakpoint, an int for example, print does return a value but the value is 0 (I presume that is the initial value of the type), however it should already have been set to a new value according to my code. Also when trying next it returns Cannot find bounds of current function which leads to me thinking it's not able to interpret some part.

In my bootloader I change into protected protected mode to run the 64-bit kernel using this method:

[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

Any thoughts?

Dyl answered 5/2, 2018 at 10:36 Comment(14)
BOCHS might be useful: it's another x86 emulator, but it has a debugger build-in, not just a GDB remote target. (I haven't used either very much, though, so IDK if qemu-system-x86_64 starts in long mode with EFI or something instead of booting like a PC legacy BIOS in real mode.)Bachelorism
You generally see this error when changing between real mode and protected mode or hen switching into 64-bit long mode. GDB doesn't properly track the mode change in all cases and you end up with this error. If debugging a bootloader I recommend Bochs as it understands the transitions between modes. There are situations where after you get this error you can set the new architecture and then restart the debug session but it doesn't always work. I seem to recall writing an SO answer about this but I can't find that answer at the moment.Loudmouthed
Possible duplicate of How to use QEMUn and GDB to debug KernelLoudmouthed
There are some other possible workarounds listed on the OSDev Wiki: wiki.osdev.org/QEMU_and_GDB_in_long_modeLoudmouthed
@MichaelPetch Yeah I read about the switching between modes being the problem, however I get the error immediately when trying to connect anyway. So no switching has occurred yet. So I'm not sure if I'm just using the wrong architecture in gdb or something else is going wrong. Also I'm not sure what the No executable has been specified in my error message implies. Is it just a warning or does it break something.Dyl
I've applied the patch and now the g packet error is gone. However it looks like gdb can't interpret my executable as after running target remote localhost:1234 and then symbol-file kernel.elf, the terminal shows 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 ?? ()Dyl
What is the complete command line you use to launch the remote qemu-system-x86_64 session?Loudmouthed
@MichaelPetch ${QEMU} -s -S -fda moOS-image & ${GDB} -ex "target remote localhost:1234" -ex "symbol-file kernel.elf" (From my Makefile) where the variables are GDB = x86_64-elf-gdb QEMU = qemu-system-x86_64Dyl
@MichaelPetch I put my code up on GitHub. Thanks for taking the time! github.com/JaapWijnen/ostest Also yes I am compiling using the -g flag, as for the linker script I am not 100% sure.Dyl
I took a quick glance at your code. Your bootloader switches into 32-bit protected mode but your kernel is compiled as 64-bit code. You can't do that.If you want to run that kernel you'll need to modify your kernel (or the way you build)so that it is a 32-bit executable or you'll have to change your bootloader so that it switches into 64-bit long mode first. Likely this is the source of your problems/Loudmouthed
If you modify it to be 32-bit code then use qemu-system-i386Loudmouthed
To build as 32-bit code CFLAGS should have -m32 on it, ld commands should have -melf_i386 and nasm should be -felf32rather than -felf64Loudmouthed
@MichaelPetch After running the other qemu version and the flags you proposed I got gdb working! Thanks a lot. I wanted to try 64bit still but I would first have to set up paging in my boot loader which im still trying to wrap my head around so I just tried running 32 bit and it works!Dyl
This is more or less a duplicate. The answer to the other question applies here as well: https://mcmap.net/q/1177303/-unexpected-output-when-printing-directly-to-text-video-memoryLoudmouthed
L
5

The reason for all the issues is that you are compiling 64-bit code and running it in 32-bit protected mode. 64-bit code will not run in that environment properly. Oddly enough it often manifests itself at first when trying to write to the video display. Often things will print but not quite the way you want. Improperly decoded instructions will cause the debugger to work erratically as you observed.

One way to fix your problem is to compile and link the kernel as a 32-bit executable. You are using a 64-bit compiler so you'll need to add -m32 CFLAGS (or your GCC command line). if using LD to link -melf_i386 will be needed. Assembling with NASM should be -felf32 rather than -felf64.

Alternatively you would have to place the processor into 64-bit long mode in the bootloader. You can read more about that process on the OSDev wiki.

If debugging 32-bit code you will probably want to use qemu-system-i386 . You will have fewer hassles.

Loudmouthed answered 14/2, 2018 at 23:9 Comment(0)
O
2

Connect and disconnect

I got it working as detailed at: How to debug the Linux kernel with GDB and QEMU?

The key thing was connect and disconnect on GDB as:

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'

Related: Remote 'g' packet reply is too long

Overplay answered 18/3, 2018 at 13:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.