Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

qemu

x86

gcc

osdev

gdb

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?

like image 901
Jaap Wijnen Avatar asked Feb 05 '18 10:02

Jaap Wijnen


2 Answers

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.

like image 182
Michael Petch Avatar answered Oct 23 '22 12:10

Michael Petch


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