聲明:
本筆記內容並非本人原創,90%來自網絡資料的整合。同時,由於自己是剛剛接觸qemu & gdbserver remote debug,本文也就算不得教程,僅供有緣人參考而已。
------------------------------------------------------------------------------------------------分割線---------------------------------------------------------------------------
step 1: kernel 編譯環境安裝
apt-cache search build-essential sudo apt-get install build-essential -y apt-cache search libncurses-dev sudo apt-get install libncurses-dev -y
當然,可能還需要其他一些工具,如果gcc g++ make 之類的工具,畢竟build-essential是一個工具箱子,若有潔癖,可能就有點沖突。而ncurses-dev,這個是必須要有的,我記得在fedora上是直接yum install ncurses-dev即可,.deb系列的似乎是加了個前綴。
step 2: gdb的安裝
需要告訴的是,build-essential 里應該是包含了一個gdb & gdbsever工具了,但是很抱歉的是無法使用,會出現這個錯誤:
Remote 'g' packet reply is too long: 000000000000000020000000000000004000000000000000001006000000000000f009000000000028aece81ffffffff981fc081ffffffff901fc081ffffffff0030c1010000000000000000000000000000000000000000f0b926020000000020f1d281ffffffffb01fc081ffffffff00e0e681ffffffff0010e781ffffffff02fbd281ffffffff9600000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000
於是,我們需要去下載一個比較新的gdb source下來(我使用的是7.8),網址是: http://ftp.gnu.org/gnu/gdb/
http://ftp.gnu.org/gnu/gdb/
然后按照網絡前人們共享出來的資料,修改gdb的源碼: 在 gdb-7.8/gdb/remote.c 文件的 static void process_g_packet (struct regcache *regcache)函數里面修改部分內容,如下:
1 static void 2 process_g_packet (struct regcache *regcache) 3 { 4 struct gdbarch *gdbarch = get_regcache_arch (regcache); 5 struct remote_state *rs = get_remote_state (); 6 struct remote_arch_state *rsa = get_remote_arch_state (); 7 int i, buf_len; 8 char *p; 9 char *regs; 10 11 buf_len = strlen (rs->buf); 12 13 /* Further sanity checks, with knowledge of the architecture. */ 14 /* if (buf_len > 2 * rsa->sizeof_g_packet) 15 error (_("Remote 'g' packet reply is too long: %s"), rs->buf); 16 */ 17 /*modify by xx*/ 18 if (buf_len > 2 * rsa->sizeof_g_packet) { 19 rsa->sizeof_g_packet = buf_len; 20 for (i = 0; i < gdbarch_num_regs(gdbarch); i++) { 21 if (rsa->regs[i].pnum == -1) 22 continue; 23 if (rsa->regs[i].offset >= rsa->sizeof_g_packet) 24 rsa->regs[i].in_g_packet = 0; 25 else 26 rsa->regs[i].in_g_packet = 1; 27 } 28 } 29 //....... 30 } 31 } 32 }
上面的14-15行是原來文件的,而18-27行是重新添加上的 <為了節約版面,我沒有貼后面的,所以,注意 " { } " 可能導致的語法錯誤>,這樣修改的具體原理,本人並不清楚,但確實解決了問題。
修改完整后,就開始編譯gdb吧。在 gdb-7.8/ 下執行下面的命令:
1 ./configure --prefix=../../tools/ 2 make 3 make install
需要注意的是在gdb-7.8/ 目錄下並沒有Makefile文件,需要使用 ./configure來生產。在配置的時候,如果要指定gdb安裝的路徑(目錄),那么就需要跟上 --prefix=$PATH的相關參數,一般這種情況可能會針對系統已經有一個gdb了但無法使用,同時也未刪除,那么新編譯的gdb可能需要安裝在另外的目錄了。當然我自己的是安裝在 ../../tools/ 目錄下。
step 3: 編譯linux kernel
去 www.kernel.org下載自己需要的版本,待完畢后,對kernel編譯生成bzImage & vmlinux 文件。如果是和我一樣剛入門的,可以參考以下命令&步驟:
cd linux-3.12.35/ cp /boot/config-3.13.0-43-generic .config make menuconfig <save> make bzImage
需要說明的是,具體要看哪些調試信息,應該在make menuconfig的時候去配置,去選擇,然后保存好后,就編譯。編譯后,bzImage這個是被壓縮了的,供qemu虛擬機使用,vmlinux里面帶了某些信息,沒有壓縮,供gdb使用。
當編譯結束后,可以將vmlinux bzImage文件copy到一個干凈的目錄下吧---這個隨自己的習慣了,不copy也無所謂了。
上面忘記了准備最重要的東西了: qemu
step 4: qemu的使用
簡單說下: qemu 是一款虛擬機,可以模擬x86 & arm 等等硬件平台<似乎可模擬的硬件平台很多...>,而qemu 也內嵌了一個 gdbserver。這個gdbserver於是就可以和gdb構成一個遠程合作伙伴,通過ip:port 網絡方式或者是通過串口/dev/ttyS*來進行工作,一個在這頭,一個在那頭。
至於安裝qemu虛擬機,可以通過源碼編譯,make & make install ,在這里可以下載:http://wiki.qemu.org/Download。也可以直接在ubuntu 軟件包里apt-get install qemu-kvm即可。這里不詳細記載了。當安裝后,可能的文件是這些:
1 qemu-system-i386 2 3 qemu-system-x86_64 4 5 qemu-img 6 7 qemu-io 8 ....
這個是什么意思呢? 第一行的表示是 i386機器上使用的qemu虛擬機,第二行表示是 x86_64上使用的虛擬機。另外的就沒使用過了。具體的請參考官網文檔:http://wiki.qemu.org/Main_Page。當然,我自己的系統是 x86_64的,使用的是第二個。
step 4: 讓kernel為你稍帶片刻~
1 qemu-system-x86_64 -kernel ./bzImage -initrd ./initrd.img -smp 2 -gdb tcp::1234 -S
先使用命令啟動qemu。
qemu-system-x86_64的參數比較多,這里簡單說下:
-kernel 是指定一個大內核文件,當仁不讓的是bzImage。
-initrd 是指定一個 initrd.img文件,這個文件可以從 /boot/initrd.img-3.13.0-43-generic 拷貝而來,關於它是什么東西呢? 可以參考這個: http://www.linuxfly.org/post/94/ ,或者是這個 http://blog.csdn.net/chrisniu1984/article/details/3907874 。
-smp 可以從名字猜想,它是給qemu指定幾個處理器,或者是幾個線程<嗯,大概意思就thread吧>。
-gdb則是啟動qemu的內嵌gdbserver,監聽的是本地tcp端口1234---如果這樣寫: -gdb tcp:192.168.1.100:1234 ,似乎也是沒問題的。
-S 就是掛起gdbserver,讓gdb remote connect it。還有一個-s,那是另外一種情況要使用了。
如果自己嫌敲命令麻煩<雖然那很酷>,可以使用以下的方式,將該命令保存到某個文件中,比如 qemu.start:
1 #!/bin/bash 2 qemu-system-x86_64 -kernel ./bzImage -initrd ./initrd.img -smp 2 -gdb tcp::1234 -S 3 <save> 4 chmod +x qemu.start 5 6 ./qemu.start
這樣就可以啟動qemu了 <注意自己的 bzImage & initrd.img 文件的路徑>
提示: man qemu-system-x86_64,你會獲得一些幫助。
step 5: 使用gdb去連接已將啟動了的qemu:
1 ../tools/gdb/bin/gdb vmlinux 2 3 ----- 4 GNU gdb (GDB) 7.8 5 Copyright (C) 2014 Free Software Foundation, Inc. 6 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 7 This is free software: you are free to change and redistribute it. 8 There is NO WARRANTY, to the extent permitted by law. Type "show copying" 9 and "show warranty" for details. 10 This GDB was configured as "x86_64-unknown-linux-gnu". 11 Type "show configuration" for configuration details. 12 For bug reporting instructions, please see: 13 <http://www.gnu.org/software/gdb/bugs/>. 14 Find the GDB manual and other documentation resources online at: 15 <http://www.gnu.org/software/gdb/documentation/>. 16 For help, type "help". 17 Type "apropos word" to search for commands related to "word"... 18 Reading symbols from vmlinux...done. 19 ----- 20 21 (gdb) target remote : 1234 22 Remote debugging using : 1234 23 0x0000000000000000 in irq_stack_union () 24 25 (gdb) b start_kernel 26 Breakpoint 1 at 0xffffffff81d2fb02: file init/main.c, line 476. 27 28 (gdb) c 29 Continuing. 30 31 Breakpoint 1, start_kernel () at init/main.c:476 32 476 { 33 34 35 (gdb) n 36 485 smp_setup_processor_id(); 37 (gdb) n 38 491 boot_init_stack_canary(); 39 (gdb) n 40 493 cgroup_init_early();
第一行表明啟動我自己編譯的gdb,這有兩個方式 : gdb fileName 啟動,或者 gdb啟動后,再使用 file fileName 啟動
第21行表明連接遠程gdbserver,由於這是在同一台筆記本上,就沒有指定ip地址,僅僅指定了port號碼。----當然,如果是連接uart口,也行。
第25行,是break一個斷點,在某個函數的入口處 。
第28行,應該是發一個命令,讓qemu那邊繼續運行的意思,這個時候,qemu那邊的屏幕上會閃現出:"Booting from ROM..."
后面啊,就是下一步下一步的意思咯: next ... next ... 當然,也可以選擇step step s.... 直到哪里才會在qemu那邊打印消息呢? 要在 console_init();這行代碼后才會的。
做一個稍微重要的說明: 我這里並沒有啟用文件系統,如果有需要,可以試着用busybox做一個,然后參考qemu kernel調試手冊,或者網絡資源進行加入調試即可。
--------------------------------------------------------------------------------------扯淡分割線--------------------------------------------------------------------------------------------
后記:
至於gdb 的命令,還有很多很多,如果是new to kernel的話,請點擊這里: http://www.sourceware.org/gdb/ 最好的是慢慢啃官網文檔,然后再看看別人的理解,應該就差不多了。或者看看這個: http://www.yolinux.com/TUTORIALS/GDB-Commands.html
這幾天也一直在搜索kernel debug的方法,qemu+gdb 是一種,當然也還有其他的方法。不過總結下來,代價以qemu+gdb最小。如果你是大屏幕pc,可以試試將qemu+gdb+eclipse這樣,納入IDE環境。而自己是筆記本,就不湊合IDE了,在vim shell 下足以。
稍微夾雜一點想法: 前面也是看了一些操作系統的書+linux kernel的入門讀物,但是一直沒機會去試着單步運行以下kernel,看看它是怎么走的<書中搭建方式花銷比較大:要么就是兩台電腦,要么就是搞一半就會放棄的那種>。久而久之,也就懈怠了,更別說再去詳細的看代碼了。linux kernel是真的很偉大,但沒必要神話它。如果對操作系統原理和程序設計的理解達到一定水平,自己也可以整一個OS---盡管那可能會很粗糙。於是,知行合一也就有必要了。
最后就是,如果真對kernel有興趣,那起碼得把英語搞一搞,然后盡早關注kernel MailList----雖然是萬變不離其宗,但世界也是發展變化的。書上多少是有時限的。
關鍵字: qemu kernel gdb gdbserver 調試