ubuntu: qemu+gdb 調試linux kernel 學習筆記


 

聲明:

  本筆記內容並非本人原創,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 調試


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM