透過 gdb 除錯核心和模組¶
核心偵錯程式 kgdb、虛擬機器管理程式(如 QEMU)或基於 JTAG 的硬體介面允許使用 gdb 在執行時除錯 Linux 核心及其模組。Gdb 配備了強大的 Python 指令碼介面。核心提供了一系列輔助指令碼,可以簡化典型的核心除錯步驟。這是一個關於如何啟用和使用它們的簡短教程。它主要關注 QEMU/KVM 虛擬機器作為目標,但這些示例也可以轉移到其他 gdb stub。
要求¶
gdb 7.2+(推薦:7.4+),啟用 Python 支援(通常對於發行版來說是這樣)
設定¶
為 QEMU/KVM 建立一個 Linux 虛擬機器(有關更多詳細資訊,請參閱 www.linux-kvm.org 和 www.qemu.org)。對於交叉開發,https://landley.net/aboriginal/bin 保留了一個機器映象和工具鏈池,可以幫助您開始。
使用啟用的 CONFIG_GDB_SCRIPTS 構建核心,但關閉 CONFIG_DEBUG_INFO_REDUCED。如果您的架構支援 CONFIG_FRAME_POINTER,請保持啟用狀態。
將該核心安裝到 Guest 中,如有必要,透過將“nokaslr”新增到核心命令列來關閉 KASLR。或者,QEMU 允許使用 -kernel、-append、-initrd 命令列開關直接引導核心。如果您不依賴模組,這通常才有用。有關此模式的更多詳細資訊,請參閱 QEMU 文件。在這種情況下,如果架構支援 KASLR,則應使用停用的 CONFIG_RANDOMIZE_BASE 構建核心。
構建 gdb 指令碼(v5.1 及以上核心需要)
make scripts_gdb
啟用 QEMU/KVM 的 gdb stub,可以
在 VM 啟動時,將“-s”附加到 QEMU 命令列
或
在執行時,從 QEMU 監視器控制檯發出“gdbserver”
cd /path/to/linux-build
啟動 gdb:gdb vmlinux
注意:某些發行版可能會限制 gdb 指令碼的自動載入到已知的安全目錄。如果 gdb 報告拒絕載入 vmlinux-gdb.py,請新增
add-auto-load-safe-path /path/to/linux-build
到 ~/.gdbinit。有關更多詳細資訊,請參閱 gdb 幫助。
連線到已啟動的 Guest
(gdb) target remote :1234
使用 Linux 提供的 gdb 幫助程式的示例¶
載入模組(和主核心)符號
(gdb) lx-symbols loading vmlinux scanning for modules in /home/user/linux/build loading @0xffffffffa0020000: /home/user/linux/build/net/netfilter/xt_tcpudp.ko loading @0xffffffffa0016000: /home/user/linux/build/net/netfilter/xt_pkttype.ko loading @0xffffffffa0002000: /home/user/linux/build/net/netfilter/xt_limit.ko loading @0xffffffffa00ca000: /home/user/linux/build/net/packet/af_packet.ko loading @0xffffffffa003c000: /home/user/linux/build/fs/fuse/fuse.ko ... loading @0xffffffffa0000000: /home/user/linux/build/drivers/ata/ata_generic.ko
在一些尚未載入的模組函式上設定斷點,例如
(gdb) b btrfs_init_sysfs Function "btrfs_init_sysfs" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 1 (btrfs_init_sysfs) pending.
繼續目標
(gdb) c
在目標上載入模組,並觀察符號被載入以及斷點被命中的情況
loading @0xffffffffa0034000: /home/user/linux/build/lib/libcrc32c.ko loading @0xffffffffa0050000: /home/user/linux/build/lib/lzo/lzo_compress.ko loading @0xffffffffa006e000: /home/user/linux/build/lib/zlib_deflate/zlib_deflate.ko loading @0xffffffffa01b1000: /home/user/linux/build/fs/btrfs/btrfs.ko Breakpoint 1, btrfs_init_sysfs () at /home/user/linux/fs/btrfs/sysfs.c:36 36 btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj);轉儲目標核心的日誌緩衝區
(gdb) lx-dmesg [ 0.000000] Initializing cgroup subsys cpuset [ 0.000000] Initializing cgroup subsys cpu [ 0.000000] Linux version 3.8.0-rc4-dbg+ (... [ 0.000000] Command line: root=/dev/sda2 resume=/dev/sda1 vga=0x314 [ 0.000000] e820: BIOS-provided physical RAM map: [ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable [ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved ....
檢查當前任務結構的欄位(僅 x86 和 arm64 支援)
(gdb) p $lx_current().pid $1 = 4998 (gdb) p $lx_current().comm $2 = "modprobe\000\000\000\000\000\000\000"
使用當前或指定 CPU 的 per-cpu 函式
(gdb) p $lx_per_cpu(runqueues).nr_running $3 = 1 (gdb) p $lx_per_cpu(runqueues, 2).nr_running $4 = 0
使用 container_of 輔助函式深入研究 hrtimer
(gdb) set $leftmost = $lx_per_cpu(hrtimer_bases).clock_base[0].active.rb_root.rb_leftmost (gdb) p *$container_of($leftmost, "struct hrtimer", "node") $5 = { node = { node = { __rb_parent_color = 18446612686384860673, rb_right = 0xffff888231da8b00, rb_left = 0x0 }, expires = 1228461000000 }, _softexpires = 1228461000000, function = 0xffffffff8137ab20 <tick_nohz_handler>, base = 0xffff888231d9b4c0, state = 1 '\001', is_rel = 0 '\000', is_soft = 0 '\000', is_hard = 1 '\001' }
命令和函式列表¶
命令和便捷函式的數量可能會隨著時間的推移而演變,這只是初始版本的快照
(gdb) apropos lx
function lx_current -- Return current task
function lx_module -- Find module by name and return the module variable
function lx_per_cpu -- Return per-cpu variable
function lx_task_by_pid -- Find Linux task by PID and return the task_struct variable
function lx_thread_info -- Calculate Linux thread_info from task variable
lx-dmesg -- Print Linux kernel log buffer
lx-lsmod -- List currently loaded modules
lx-symbols -- (Re-)load symbols of Linux kernel and currently loaded modules
可以透過“help <command-name>”獲取命令的詳細幫助,透過“help function <function-name>”獲取便捷函式的詳細幫助。