My code works, I don’t know why.

國王的耳朵是驢耳朵

Linux Kernel Pratice 0.5: 使用gdb 加 Qemu Trace Linux Kernel Runtime 行為

| Comments

目錄

測試環境

Host

  • Host OS
1
2
3
4
5
6
$ lsb_release -a
No LSB modules are available.
Distributor ID:   Ubuntu
Description:  Ubuntu 14.04.5 LTS
Release:  14.04
Codename: trusty
  • Qemu
1
2
$ qemu-system-arm --version
QEMU emulator version 2.0.0 (Debian 2.0.0+dfsg-2ubuntu1.27), Copyright (c) 2003-2008 Fabrice Bellard
  • gdb
1
2
3
4
5
$ arm-none-eabi-gdb --version
GNU gdb (GNU Tools for ARM Embedded Processors) 7.10.1.20160923-cvs
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl
...
  • buildroot 版本
    • commit hash: 14b24726a81b719b35fee70c8ba8be2d682a7313

Target

  • Linux kernerl 版本
    • 4.4.2
  • 模擬平台
    • Vexpress

Linux kernel環境設定

我目前只打開加入debug資訊的選項。接下來重編,編譯的方式請參考這邊

  • Kernel hacking -> Compile-time checks and compiler options ->
    • Compile the kernel with debug info

測試

依照下面兩個步驟執行

  1. 執行qemu,並且加入支援gdb以及開始馬上freeze CPU的參數
  2. 執行gdb,載入symbol並聯到qemu除錯

Qemu

基本上就是原本的指令加入兩個選項

  • -S
    • qemu一開始立即Freeze CPU
  • -s
    • -gdb tcp::1234的縮寫,也就是說gdb可以透過port 1234和連到Qemu除錯

假設你在buildroot最上層,就可以使用下面指令執行qemu 並使用gdb 除錯

1
2
3
4
5
6
qemu-system-arm -M vexpress-a9 -smp 1 -m 256 \
                -kernel /tmp/kernel/linux-stable/arch/arm/boot/zImage  \
                -dtb /tmp/kernel/linux-stable/vexpress-v2p-ca9.dtb     \
                -drive file=output/images/rootfs.ext2,if=sd,format=raw \
                -append "console=ttyAMA0,115200 root=/dev/mmcblk0"     \
                -serial stdio -net nic,model=lan9118 -net user -s -S

gdb

這邊有點瑣碎,先講一下步驟

  1. 載入Linux kernel symbol
    • 假設你在kernel最上層目錄有三種方式載入
      • 直接arm-none-eabi-gdb ./vmlinux
      • arm-none-eabi-gdb -ex "file ./vmlinux"
      • 進入gdb後打file ./vmlinux指令
  2. 連上qemu
    • 一樣兩種方式
      • arm-none-eabi-gdb -ex "target remote :1234"
      • 進入gdb後打target remote :1234指令
  3. 設定breakpoint等你要觀察的資訊
    • b printk
  4. 告訴qemu開始執行
    • continue

1和2可以一起使用如下

懶人包
1
arm-none-eabi-gdb -ex "file ./vmlinux"  -ex "target remote :1234"

現在看一下操作範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ arm-none-eabi-gdb -ex "file ./vmlinux"  -ex "target remote :1234"
GNU gdb (GNU Tools for ARM Embedded Processors) 7.10.1.20160923-cvs
...
Reading symbols from ./vmlinux...done.
Remote debugging using :1234
0x60000000 in ?? ()
(gdb) b printk
Breakpoint 1 at 0x800a2260: file kernel/printk/printk.c, line 1900.
(gdb) c
Continuing.

Breakpoint 1, printk (fmt=0x0 <__vectors_start>) at kernel/printk/printk.c:1900
1900  {
(gdb) bt
#0  printk (fmt=0x0 <__vectors_start>) at kernel/printk/printk.c:1900
#1  0x806178e0 in start_kernel () at init/main.c:508
#2  0x6000807c in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

另外如果有興趣使用Linux kernel提供的指令,在kernel config設定打開gdb script後,可以使用下面的方式在啟動gdb時載入,只要把下面的描述加到你的~/.gdbinit即可

1
add-auto-load-safe-path /tmp/kernel/scripts/gdb/vmlinux-gdb.py

那麼你就可以使用Linux kernel提供的gdb script,詳細的設定和指令說明在這邊

參考資料

補充

當初犯了蠢事載入不正確的kernel image導致一堆不必要的除錯。不過多學到一個gdb Python script除錯指令,當Python script發生exception時可以用下面的指令印出Python錯誤call stack

  • gdb內:set python print-stack full
  • 啟動gdb時加入參數: -ex "set python print-stack full"

Comments