在QEMU中调试ARM程序
来源:互联网 发布:上海 旗袍店 知乎 编辑:程序博客网 时间:2024/05/18 10:49
最近我想调试一个运行在QEMU模拟ARM系统中的Linux程序。我碰到过一些麻烦,因此我会将我的工作过程写在这里。我想用gdbserver来在QEMU中运行一个程序,然后用TCP链接将其连接到运行在我PC上的GDB实例。gdbserver是一个软件层,它实现了GDB的一部分功能(调试残桩),并提供了通过网络(或者串口)连接一个完整的GDB实例的可能性。我想说明的这些都可以通过下面这张图来表示。
蓝颜色的部分表示用来运行在我的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
2
$ wget http://www.codesourcery.com/sgpp/lite/arm/portal/package6490/public/arm-none-linux-gnueabi/arm-2010q1-202-arm-none-linux-gnueabi.bin
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内核
首先,我从官方的仓库中获取了最新的内核版本。
1
$ wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.35.tar.bz2
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(我计划就是要用它)无论如何都需要共享库。
1
$ wget http://busybox.net/downloads/busybox-1.17.1.tar.bz2
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系统的二进制文件。
1
$ wget http://download.savannah.gnu.org/releases/qemu/qemu-0.12.5.
tar
.gz
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
到这里后,调试过程就跟平常一样了。
- 在QEMU中调试ARM程序
- 在QEMU中调试ARM程序
- qemu进行ARM CPU仿真及程序gdb调试
- gdb 远程qemu-arm调试
- GDB调试Qemu程序
- qemu调试cortex m3程序
- 利用ddd和qemu调试arm-linux
- QEMU+KGDB 调试ARM内核模块
- GDB调试ARM程序
- qemu模拟运行mips程序调试
- 在source insight中编译arm程序
- 手把手教你在RAM调试ARM程序
- qemu模拟arm并调试汇编的方法和注意事项
- 用eclipse和qemu调试arm-linux内核
- 在qemu中运行magenta
- 在ARM开发板中使用gdb进行远程调试
- 一步步教你如何在ubuntu虚拟机中安装QEMU并模拟arm 开发环境(二)rootfs制作
- GDB+GdbServer: ARM程序调试
- 成功路上的性格
- iphone-common-codes-ccteam源代码 CCPlayer.m
- 2012年值得关注的10家云计算初创公司
- iphone-common-codes-ccteam源代码 CCPlistFileReader.h
- 影响数据库访问速度的九大因素
- 在QEMU中调试ARM程序
- iphone-common-codes-ccteam源代码 CCPlistFileReader.m
- 2011年做项目的点点滴滴
- iphone-common-codes-ccteam源代码 CCPlistFileWritter.h
- 培养我们的目标感
- 腾讯 vs 百度
- C/C++内存泄漏及检测
- iphone-common-codes-ccteam源代码 CCPlistFileWritter.m
- UML用例图概要