歡迎您光臨本站 註冊首頁

在QEMU中調試ARM程序

←手機掃碼閱讀     火星人 @ 2014-03-12 , reply:0
  

最近我想調試一個運行在QEMU模擬ARM系統中的Linux程序。我碰到過一些麻煩,因此我會將我的工作過程寫在這裡。我想用gdbserver來在QEMU中運行一個程序,然後用TCP鏈接將其連接到運行在我PC上的GDB實例。gdbserver是一個軟體層,它實現了GDB的一部分功能(調試殘樁),並提供了通過網路(或者串口)連接一個完整的GDB實例的可能性。我想說明的這些都可以通過下面這張圖來表示。

使用QEMU內嵌的gdbserver


藍顏色的部分表示用來運行在我的Ubuntu PC(32位x86)上的軟體,而綠色的部分則表示運行在ARM上的軟體。qemu-system-arm是一個模擬VersatilePB平台的軟體;我嘗試過運行可以通過Ubuntu倉庫里安裝的那個版本(這個軟體包叫qemu-kvm-extras),但它必須和最新的Linux版本(2.6.35)一起。因此我打算編譯並使用QEMU的上流版本。GDB的server和“client”都來自於ARM的CodeSourcery編譯工具集,也就是用於交叉編譯ARM軟體的編譯器。在本例中我想要調試的程序是GNU Hello,這個程序除了列印“Hello World”外沒有做多少工作,不過這是一個用GNU Autotools進行交叉編譯的好例子。

先決條件

為了接下來的流程,我首先安裝了:

  • 用於ARM的CodeSourcery GNU/Linux工具鏈
  • 用於編譯QEMU的本地x86工具鏈(Ubuntu的build-essentials軟體包)
  • 作為調試器圖形界面的DDD
  • 用於創建Linux文件系統鏡像的cpio工具
  • libncurses5-dev軟體包,用於運行Linux內核和Busybox的菜單式配置
  • 用於編譯QEMU的libsdl-dev和zlib1g-dev

1 $ sudo apt-get install build-essential ddd cpio libncurses5-dev libsdl-dev zlib1g-dev
3 $ chmod +x arm-2010q1-202-arm-none-linux-gnueabi.bin
4 $ ./arm-2010q1-202-arm-none-linux-gnueabi.bin

我將工具鏈安裝在默認的“~/CodeSourcery”目錄下。而這種情況下gdbserver的可執行文件可以在路徑“/home/francesco/CodeSourcery/Sourcery_G++_Lite/arm-none-linux-gnueabi/libc/usr/bin/gdbserver”下找到。


注意以後的過程都會在一個專用的文件夾下運行,並且從此以後不在需要root的訪問許可權。整個過程到結束大概需要使用1Gigabyte的硬碟空間。


Linux內核

首先,我從官方的倉庫中獲取了最新的內核版本。


2 $ tar xjf linux-2.6.35.tar.bz2
3 $ cd linux-2.6.35/
4 $ make ARCH=arm versatile_defconfig
5 $ make ARCH=arm menuconfig

當菜單出現時,我來到“Kernel Features”節並打開EABI支持;然後退出 (保存配置) 並編譯:


1 $ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- all
2 $ cd ..

結果是得到一個壓縮的內核鏡像文件“./linux-2.6.35/arch/arm/boot/zImage”。


Busybox

接下來,我下載了最新版的Busybox在前次的教程中我使用了靜態編譯,但這一次我不會,因為gdbserver(我計劃就是要用它)無論如何都需要共享庫。


2 $ tar xjf busybox-1.17.1.tar.bz2
3 $ cd busybox-1.17.1
4 $ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- defconfig
5 $ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- install
6 $ cd ..

結果是得到文件夾“busybox-1.17.1/_install”,包括了一個最小的不包含共享庫的根文件系統。


QEMU

我重新從源碼編譯了QEMU,只包含我需要的模擬ARM系統的二進位文件。


2 $ tar xzf qemu-0.12.5.tar.gz
3 $ cd qemu-0.12.5
4 $ ./configure --enable-sdl --disable-kvm --enable-debug --target-list=arm-softmmu
5 $ ./make
6 $ cd ..

相應的結果是程序“./qemu-0.12.5/arm-softmmu/qemu-system-arm”,會被用來模擬VersatilePB平台。


GNU Hello

這個軟體包需要配置成使用交叉編譯;不過這其實很容易做;它只需要一個交叉編譯器的前綴。



1 $ wget http://ftp.gnu.org/gnu/hello/hello-2.6.tar.gz
2 $ tar xzf hello-2.6.tar.gz
3 $ cd hello-2.6
4 $ ./configure --host=arm-none-linux-gnueabi
5 $ make
6 $ cd ..

結果就是一個ARM架構的可執行文件“hello-2.6/src/hello”。


完成文件系統構建

所有涉及到的ARM二進位文件 (busybox, gdbserver, hello) 都需要共享庫。Codesourcery工具鏈在安裝目錄的一個子文件夾下提供了這些庫。在我這種情況下就是“/home/francesco/CodeSourcery/Sourcery_G++_Lite/arm-none-linux-gnueabi/libc/lib/”。為了探索哪些庫是必需的我使用CodeSourcery工具鏈所分發的readelf工具。具體說來,我運行了:


01 $ arm-none-linux-gnueabi-readelf hello-2.6/src/hello -a |grep lib
02  [Requesting program interpreter: /lib/ld-linux.so.3]
03  0x00000001 (NEEDED)                     Shared library: [libgcc_s.so.1]
04  0x00000001 (NEEDED)                     Shared library: [libc.so.6]
05 00010694  00000216 R_ARM_JUMP_SLOT   0000835c   __libc_start_main
06  2: 0000835c     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.4 (2)
07  89: 0000844c     4 FUNC    GLOBAL DEFAULT   12 __libc_csu_fini
08  91: 0000835c     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
09  101: 00008450   204 FUNC    GLOBAL DEFAULT   12 __libc_csu_init
10  000000: Version: 1  File: libgcc_s.so.1  Cnt: 1
11  0x0020: Version: 1  File: libc.so.6  Cnt: 1

Hello這個二進位文件需要三個共享庫: “ld-linux.so.3″, “libgcc_s.so.1″ 和 “libc.so.6″。我對所有的3個二進位文件都執行了這個命令,並且將所需的庫和gdbserver、hello等可執行文件拷貝到Busybox的文件系統裡面。


01 $ cd busybox-1.17.1/_install
02 $ mkdir -p lib
03 $ cp /home/francesco/CodeSourcery/Sourcery_G++_Lite/arm-none-linux-gnueabi/libc/lib/ld-linux.so.3 lib/
04 $ cp /home/francesco/CodeSourcery/Sourcery_G++_Lite/arm-none-linux-gnueabi/libc/lib/libgcc_s.so.1 lib/
05 $ cp /home/francesco/CodeSourcery/Sourcery_G++_Lite/arm-none-linux-gnueabi/libc/lib/libm.so.6 lib/
06 $ cp /home/francesco/CodeSourcery/Sourcery_G++_Lite/arm-none-linux-gnueabi/libc/lib/libc.so.6 lib/
07 $ cp /home/francesco/CodeSourcery/Sourcery_G++_Lite/arm-none-linux-gnueabi/libc/lib/libdl.so.2 lib/
08 $ cp /home/francesco/CodeSourcery/Sourcery_G++_Lite/arm-none-linux-gnueabi/libc/usr/bin/gdbserver usr/bin/
09 $ cp ../../hello-2.6/src/hello usr/bin/
10 $ cd ../../

在我的實驗中我需要ARM客戶機系統那邊有一個可用的網路,因此我準備了一個初始化腳本來開啟它。該腳本從我的上一個教程擴展而來,下面是我用的腳本“rcS”的內容:


1 #!/bin/sh
2 mount -t proc none /proc
3 mount -t sysfs none /sys
4 /sbin/mdev -s
5 ifconfig lo up
6 ifconfig eth0 10.0.2.15 netmask 255.255.255.0
7 route add default gw 10.0.2.1

然後,我將rcS拷貝到Busybox文件系統的“etc/init.d”目錄裡面並創建壓縮的文件系統鏡像:


1 $ cd busybox-1.17.1/_install
2 $ mkdir -p proc sys dev etc etc/init.d
3 $ cp ../../rcS etc/init.d
4 $ chmod +x etc/init.d/rcS
5 $ find . | cpio -o --format=newc | gzip > ../../rootfs.img.gz
6 $ cd ../../

運行與調試

現在我已經將所有東西準備好:

  • 一個壓縮的內核鏡像
  • QEMU
  • 一個壓縮的文件系統鏡像,包括:
    • Busybox
    • rcS初始化腳本
    • 為ARM編譯的GNU Hello二進位文件
    • 用於ARM的gdbserver
    • 所需的共享庫


運行該平台的命令行是:


1 $ ./qemu-0.12.5/arm-softmmu/qemu-system-arm -M versatilepb -m 128M -kernel ./linux-2.6.35/arch/arm/boot/zImage -initrd ./rootfs.img.gz -append "root=/dev/ram rdinit=/sbin/init" -redir tcp:1234::1234

這裡“redir”選項會將我Ubuntu PC的埠1234上的所有TCP通信重定向到ARM客戶機系統的1234埠上。系統將會啟動,然後會打開一個root許可權的控制台。在bash提示符下,我運行調試伺服器:


1 # gdbserver --multi 10.0.2.15:1234

該命令會啟動一個伺服器並等待1234埠上的GDB連接。在PC上我可以打開調試器:


1 $ ddd --debugger arm-none-linux-gnueabi-gdb

也可以單獨運行arm-none-linux-gnueabi-gdb命令或者連接到另外一個前端。要調試遠端的程序,我需要告訴GDB使用ARM的共享庫而不是本地庫(那些用於32位x86的);否則執行的時候調試器會抱怨說庫不匹配。


1 set solib-absolute-prefix nonexistantpath
2 set solib-search-path /home/francesco/CodeSourcery/Sourcery_G++_Lite/arm-none-linux-gnueabi/libc/lib/
3 file ./hello-2.6/src/hello
4 target extended-remote localhost:1234
5 set remote exec-file /usr/bin/hello
6 break main
7 run

到這裡后,調試過程就跟平常一樣了。


來源:http://balau82.wordpress.com/2010/08/17/debugging-arm-programs-inside-qemu/



[火星人 ] 在QEMU中調試ARM程序已經有463次圍觀

http://coctec.com/docs/program/show-post-71562.html