My code works, I don’t know why.

國王的耳朵是驢耳朵

Fix: Qemu X86_64下gdb Debug kernel出現Remote 'g’ Packet Reply Is Too Long:

| Comments

問題描述

本篇文章主要是解決使用gdb 設Qemu x86_64 模擬執行x86_64 buildroot kernel開機的中斷點時遇到下面的錯誤訊息

Remote 'g’ packet reply is too long:

詳細訊息如下

1
2
3
4
5
6
0x0000000000000000 in irq_stack_union ()
(gdb) b x86_64_start_kernel
Breakpoint 1 at 0xffffffff8188429b: file arch/x86/kernel/head64.c, line 134.
(gdb) c
Continuing.
Remote 'g' packet reply is too long: 9b428881ffffffff0000000000000000010100c000000000ffffffff00000000804001000000000080400100000000000000000000000000f03f8081ffffffff00a080010000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000009b428881ffffffff4600000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000

目錄

測試環境

  • Buildroot
    • Commit: bfc90a5621c680000f8b19e8afea944da5c2a469
  • Target kernel 版本
1
2
# uname -a
Linux buildroot 4.9.6 #2 SMP Sun Jun 4 18:46:27 CST 2017 x86_64 GNU/Linux
  • Qemu 執行指令
1
2
3
4
$ qemu-system-x86_64 -M pc -kernel output/images/bzImage                        \
                     -drive file=output/images/rootfs.ext2,if=virtio,format=raw \
                     -append "root=/dev/vda console=ttyS0"                      \
                     -net nic,model=virtio -net user -nographic -S -s

基本上是從這邊衍生出來的,挑幾個重點

  • -append "root=/dev/vda console=ttyS0"
    • 指定serial port console,如此一來就可以在terminal 直接顯示Qemu 的執行文字,不過你需要修改rootfs 的/etc/inittab才能在terminal login
  • -S -s
    • 開機的時候就停下來,並開啟port 1234讓gdb從遠端連入除錯
  • -nographic
    • 懶得跳一個視窗,直接terminal當console使用

buildroot 事先準備

  1. 下載buildroot
    • git clone https://git.buildroot.net/buildroot
  2. 設定預設config
    • make qemu_x86_64_defconfig
  3. 手動設定buildroot config如gcc版本,客製化rootfs套件等
    • make menuconfig
  4. 設定Linux kernel 選項,主要是打開debug symbol
    • make linux-menuconfig
  5. 編譯rootfs及kernel
    • make
  6. 設定可以從console 登入

gdb 錯誤訊息解法

OSDev: QEMU and GDB in long mode可以看到可以使用下面指令頂著先(workaround)

  • disconnect
  • set arch i386:x86-64
  • target remote 127.0.0.1:1234

然而作為組裝工,信奉偷懶就是美德,每次要打這麼多指令實在很麻煩。因此我將這些麻煩的方式使用下面的指令自動化

1
2
3
4
5
6
gdb ./vmlinux  -ex "target remote localhost:1234"       \
               -ex "break x86_64_start_kernel"          \
               -ex "continue"                           \
               -ex "disconnect"                         \
               -ex "set architecture i386:x86-64:intel" \
               -ex "target remote localhost:1234"

執行後畫面輸出部份節錄如下

1
2
3
4
5
6
7
8
9
10
11
12
13
Reading symbols from ./vmlinux...done.
Remote debugging using localhost:1234
0x0000000000000000 in irq_stack_union ()
Breakpoint 1 at 0xffffffff8188429b: file arch/x86/kernel/head64.c, line 134.
Continuing.
Remote 'g' packet reply is too long: 9b428881ffffffff0000000000000000010100c000000000ffffffff00000000804001000000000080400100000000000000000000000000f03f8081ffffffff00a080010000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000009b428881ffffffff4600000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000
Ending remote debugging.
The target architecture is assumed to be i386:x86-64:intel
Remote debugging using localhost:1234
x86_64_start_kernel (real_mode_data=0x14080 <cpu_tss+6848> <error: Cannot access memory at address 0x14080>) at arch/x86/kernel/head64.c:134
134   {
(gdb) n
151       cr4_init_shadow();

由於gdb command file 遇到錯誤就會停下來,所以把上面的指令放到一個檔案中,執行gdb時將會停在continue這邊,目前懶的找解法了。有興趣的朋友可以自行研究。

懶人包

  • Buildroot
1
2
3
4
5
6
git clone https://git.buildroot.net/buildroot
cd buildroot
make qemu_x86_64_defconfig
make menuconfig
make linux-menuconfig
make
  • 啟動Qemu 假設在buildroot top directory下
1
2
3
4
qemu-system-x86_64 -M pc -kernel output/images/bzImage                          \
                     -drive file=output/images/rootfs.ext2,if=virtio,format=raw \
                     -append "root=/dev/vda console=ttyS0"                      \
                     -net nic,model=virtio -net user -nographic -S -s
  • gdb 假設在buildroot top directory下
1
2
3
4
5
6
7
cd output/build/linux-4.9.6
gdb ./vmlinux  -ex "target remote localhost:1234"       \
               -ex "break x86_64_start_kernel"          \
               -ex "continue"                           \
               -ex "disconnect"                         \
               -ex "set architecture i386:x86-64:intel" \
               -ex "target remote localhost:1234"

讓qemu-system-x86_64 在console 可以登入

/etc/inittab加入下面這行ttyS0::respawn:/sbin/getty -L ttyS0 0 vt100 # GENERIC_SERIAL

/etc/inittab
1
2
3
 # Put a getty on the serial port
 tty1::respawn:/sbin/getty -L  tty1 0 vt100 # GENERIC_SERIAL
+ttyS0::respawn:/sbin/getty -L  ttyS0 0 vt100 # GENERIC_SERIAL

參考資料

Comments