Android Linux内核编译调试

http://bbs.pediy.com/showthread.php?t=192746

对于在Windows上写代码写习惯的人,调试是必不可少的手段,但是转到Android以后,发现调试手段异常简陋,跟Windows简直不是一个级别,特别是Android的内核调试,网上资料也相对较少,不过通过一段时间的倒腾,我终于找到了还算靠谱的调试方法.就是利用Emulator + Eclipse进行Android Linux内核调试.
 
1.系统预装环境
在目前为止,都是使用的最新版本的Android开发环境
 
Ubuntu 14.04 
Android SDK( adt-bundle-linux-x86_64-20140702 )
Android NDK( android-ndk32-r10b-linux-x86_64 )
 
安装好这几个环境以后,设置一下环境变量
 
export PATH=$PATH:ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin
 
ANDROID_NDK_HOME键值为Android NDK安装目录,设置这个环境变量的目的主要是为了使用gcc 4.6版本编译linux内核. 
 
export PATH=$PATH:ANDROID_SDK_HOME/sdk/tools
 
ANDROID_SDK_HOME是Android SDK的安装目录,设置这个环境变量的目的是方便使用emulator命令!
 
万事具备.使用前面安装的Android SDK创建一个虚拟的设备.并且确保 emulator -avd Device_Test这条命令可以启动Android 模拟器.先热身下. 

http://www.joenchen.com/wp-content/uploads/2014/09/57EB1021F59CD9EB930D052193FFBD6714A7060B.png
 
2.Android Linux内核编译
 
2.1 下载GoldFish 源码
 
mkdir kernel 
cd kernel
git clone http://android.googlesource.com/kernel/goldfish.git

GoldFish是适配模拟器的内核源码,如果是要具体适配其他机型,请选择其他源码,这边不展开了,详情参考链接有说明. 如果失败了,换https.我换https是因为使用了代理,现在google被墙,不使用代理搞不动!
 
git clone https://android.googlesource.com/kernel/goldfish.git
 
http://www.joenchen.com/wp-content/uploads/2014/09/91EBBB45C42B10BF3E01F0ADCC0E95A3308D8BF2.png
 
下载过程看你的代理速度了,而且不能中断.中断了就要重新来,特别的麻烦和恶心!所以我上传了一份到百度云. 和上面goldfish出来的一样.可以考虑去下载
 
http://pan.baidu.com/s/1i3yzhbv
 
下载或者解压完成以后会在kernel目录下会生成一个goldfish文件夹,进入此目录.查看所有分支
 
 http://www.joenchen.com/wp-content/uploads/2014/09/2A9D2B31588CF932926EDBB97E16B606C89F4ABF.png
 
可以看到, 有很多的版本, 2.6.29和3.4我都测试过. 编译和运行没有任何问题. 所以这边我们拉2.6.29的源码
 
git checkout remotes/origin/android-goldfish-2.6.29
 
 http://www.joenchen.com/wp-content/uploads/2014/09/488E79B6F6D4C052796A7DF3B46DFA05051CDFAB.png

然后目录下就有很多文件了,说明Android Linux的源码下载成功!
 
 http://www.joenchen.com/wp-content/uploads/2014/09/96DB22911050DBEA2F6D0303B01215C1AA5DB36A.png
 
3.2 编译GoldFish 源码
 
编译源码之前,请确认已经将NDK的编译工具设置到环境变量中.我们将使用上述这个目录下的交叉编译器arm-linux-androideabi-gcc
 
export PATH=$PATH:ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin
 
然后在glodfish目录下用gedit打开Makefile文件,找到这两行文字:
 
#ARCH ?= $(SUBARCH)
#CROSS_COMPILE ?=
 
修改成
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-androideabi-
 
 http://www.joenchen.com/wp-content/uploads/2014/09/F9D24B1AE16F13DD860529C9F1AAC17D496BB04C.png
 
保存文件, 然后
 
make goldfish_armv7_defconfig 
 
 http://www.joenchen.com/wp-content/uploads/2014/09/1092FFFDC5E2265FBC77A13344C56AE2F3D264AF.png

注:用$make goldfish_defconfig这样配置也可以编译通过,模拟器也可以启动,但是Android的开机画机就显示不了,$adb shell也死活连不上,原因就是这个goldfish_defconfig这个配置文件问题.
 
Android Linux的基本编译就设置完成了.我们先make 一下
make
 
 http://www.joenchen.com/wp-content/uploads/2014/09/D4E267FA412BE8C5825244BDBDF728822D3C32E9.png

这就表示编译成功了,Linux的源码是Linux上少有的一键make过去的软件,比编译其他Linux应用简单不少.当然到这里编译出来的这个zImage已经可以运行了,但是离我们用来做调试的还是有差距.我们还要开启内核调试和关闭优化. 
 
3.3 开启调试选项
开启Linux内核的调试选项, 先安装依赖性
sudo apt-get install ncurses-dev
然后
make menuconfig
 
 http://www.joenchen.com/wp-content/uploads/2014/09/94B9E26B7171DB1C8B34015A6837B6911A86EC6A.png

进入内核配置界面,勾选下列选项,同时关闭优化
 
General setup —> 
[ ] Optimize for size,进行开启/关闭
 [*] Kernel hacking 
     [*] Compile the kernel with debug info 
     [*] KGDB: kernel debugging with remote gdb —>      
     [*] Enable dynamic printk() call support 
 
关闭Linux内核优化比较麻烦.我通过和朋友讨论,以及网络搜索还没有找到很好的解决办法,原因是默认的Linux内核编译是开启-O2优化的,这种模式之下会造成gdb和实际的源码对不上,相信使用过windbg调试-O2的朋友都有这个经历,所以我们需要关闭Linux的-O2,不过目前还没有很好的解决办法下面这篇文章讨论的解决办法是.针对文件进行关闭优化.下面这两篇文章的讨论都非常有意义:
 
http://www.lenky.info/archives/2013/03/2238
 
http://www.ibm.com/developerworks/cn/linux/l-kdb/
 
这边我们将-Os 和-O2都调成-O.针对具体文件关闭优化,这边就不搞了.具体到自己的调试任务的时候再看. 
 
 http://www.joenchen.com/wp-content/uploads/2014/09/8268DB88D51D1D56F9BF7336FB54501CDA6C7273.png
 
再进行编译, 
make -B
选项-B以强制所有内核源文件全部重新编译(因为我前面编译过一次了,为了保险起见,就让目标文件全部重新生成吧)当出现这个画面,就表示编译成功了
 
 http://www.joenchen.com/wp-content/uploads/2014/09/F4EFED8E86032619D078A7FD0EC6EB12A5450787.png
 
4.Android Linux内核调试
使用emulator 启动我们编译的内核试试
 
emulator -verbose -show-kernel -kernel ~/kernel/goldfish/arch/arm/boot/zImage -avd Device_Test

http://www.joenchen.com/wp-content/uploads/2014/09/21974B47FFE151588E52CB3A7336261FF6BF069D.png

没错, 启动的就是我们的内核2.6.29 时间也对的上.说明我们编译的内核是可以运行的.下一步使用这条命令
 
emulator -verbose -show-kernel -kernel -netfast ~/kernel/goldfish/arch/arm/boot/zImage -avd Device_Test -qemu -gdb tcp::1234,ipv4, -S
 
这条命令会在tcp端口的1234监听.加了-S还会暂停下来,等待着gdb链接上来.这时候我们开启NDK目录下面的gdb.链上去然后
 
target remote localhost:1234 
 
 http://www.joenchen.com/wp-content/uploads/2014/09/BBA04B5A12D5CE44384B718B9A4F831B7FD121F7.png

还可以测试几条命令, 看看源码是否跟上了. 
 
http://www.joenchen.com/wp-content/uploads/2014/09/A6A2B020263E3E417C2DA98BDA872A145984C2C9.png
 
到这里为止,基本上是用gdb连上emulator 进行内核调试应该没问题了.但是仅仅到这里那离windbg的调试还是差好几条街.所以我们还是需要一个更好的调试方法.是用eclipse来作为调试的前端!
 
5.Eclipse前端
是用Eclipse作为前端的好处是,无论是在windows,在linux下面都没有问题.可以在一台windows的机器上,远程调试android内核.所以为了截图方便,我下面的操作都是在windows上弄的,在Linux上也是一样!当然要在windows上进行调试,首先要将上面的gold目录复制到windows的机器上,或者是共享给windows.这里就不展开了!
 
运行Eclipse,点击菜单Help->Install New Software… 在弹出的对话框里点击Work with:后面的下拉按钮,选择Kepler – http://download.eclipse.org/releases/kepler
 
不同的Eclipse版本选择不一样,与自己下载的版本一致一即可.然后在下面的选择框中将以下选项安装上

Programming Languages 
 C/C++ Autotools support
 C/C++ Visual C++ Support
 C/C++ Development Tools
 C/C++ Development Tools SDK
Linux Tools
 GDB Tracepoint Analysis
 Mobile and Device Development
 C/C++ GDB Hardware Debugging
 
安装好后自动重启Eclipse即可.再配置点击菜单Window -> Preferences在弹出的对话框中,点击左边的General->Workspace将右边的Build automatically复选框不选中.
再点击对话框左边的C/C++->Indexer,将右边的Enable indexer和Automatically update the index两复选框不选中.
 
接下来就简单了.创建一个工程,点击菜单File->New->Project…在弹出的对话框中选择C/C++->C Project再点击Next >按钮
 
 http://www.joenchen.com/wp-content/uploads/2014/09/578AA051F5795958CE5B3C1BEC880DF16C3CBC11.pnghttp://www.joenchen.com/wp-content/uploads/2014/09/90FD57BC24C13364D3EA4F9F4B1A97591EB19971.png

其中Project name:为工程名,可自定义.而Location:则为工程文件所在路径,此处设置为我们下载的源码路径而Project type:则设置为Makefile project/Empty Project, Toolchains:则设置为Linux GCC,如果是windows设置成Android GCC最后点击Finish即可.
 
接下来Windows和Linux都一样,进行DEBUG配置,在Project Explorer里右击刚创建的Linux_Kernel项目,在右键菜单中点击Debug As->Debug Configurations…在弹出的对话框中双击GDB Hardware Debugging 然后配置调试选项如下图
 
 http://www.joenchen.com/wp-content/uploads/2014/09/D10C415DD25E33645413ABA5B448097907658264.png

将C/C++ Application:栏设置为Linux Kernel源码编译出来的vmlinux文件所在路径(包含文件名),然后将Disable auto build选上,切换到Debugger页,修改配置如下截图.
 
 http://www.joenchen.com/wp-content/uploads/2014/09/934B82A13A481BF4530D58AE919FBB151B5CBE46.png
 
这里是设置gdb的路径还有远程地址和端口. Gdb的路径在ndk安装目录下的如下路径
 
\toolchains\arm-linux-androideabi-4.6\prebuilt\windows-x86_64\bin
 
远程地址,我的ubuntu机器是192.168.1.2这个随机应变即可.端口是我们运行emulator命令定义的端口.搞定这个切换到Startup页面
 
 http://www.joenchen.com/wp-content/uploads/2014/09/C14F4339A2579D6F9D4E12793700CCCDA144C9B2.png
 
将Reset and Delay(seconds)和 Halt 还有Load image复选框的勾都去掉.然后点击Debug,这时候就停在第一条指令了

http://www.joenchen.com/wp-content/uploads/2014/09/2F0296358C816A6DC1403AC76D2684939D5061E6.png 

这时候还不能按F5, F6单步.我们在Execut窗口指定到main.c 然后在 start_kernel上下个断点也可以再Console窗口敲命令break start_kernel. 然后敲入命令C. 
 
 

这时候就停在了Linux内核的入口函数start_kernel.也可以使用F5,F6了.寄存器显示各方面都可以了.如果在Windows上,有一个毛病,源文件都要自己重新指定路径.不然认不到. 默认都是编译路径/home/xxx什么的.要重新指定成Windows的盘符形式.不过在Linux上调试就没有这个问题了!
 
 http://www.joenchen.com/wp-content/uploads/2014/09/60A7E3105AD8B2EEF852FFB8813970806C3B2E5D.png
 
这个调试差不多是搞起走了.如果是分析Android的源码,看一看跟一下还是很不错的.不过还是有一个问题没有解决,关于汇编和符号不对应的问题.
大家可以群策群力搞一下 QQ群: 127285697

这边文档格式排起来真麻烦. 我在我的博客也发了这篇文章. http://www.joenchen.com/archives/1093

参考链接:
http://wenku.baidu.com/view/95c69448e518964bcf847c2f.html 
http://blog.csdn.net/flydream0/article/details/7070392 
http://www.lenky.info/archives/2013/03/2238 
http://blog.csdn.net/liushuaikobe/article/details/8646555
http://x-slam.com/da_jian_eclipse_qemu_gdb_diao_shi_linux_kernel_huan_jing*转载请注明来自看雪论坛@PEdiy.com 

编译过程: 1). 解压后默认的文件夹位置是在D:\Linux-0.11,如果你不是将文件解压到该目录下, 你要修改MinGW32目录下的MinGW32.bat文件,将里面的PATH指向MinGW32的bin目录. 2). 打开Linux-0.11目录,双击MinGW32.bat快捷方式,打开控制台. 3). make 一下,生成1.44M的Boot.img软盘镜像,要清除编译结果请"make clean" 4). 如果安装了bochs,直接双击bochsrc.bxrc即可运行Linux-0.11了. 5). 也可用其它虚拟机加载Boot.img后运行,如果出现Kernel panic,请把虚拟机里的硬盘删了 6). 在出现Insert root floppy and press ENTER以后,将rootimage-0.11.img载入虚拟软驱,回车 这就是能在windows环境下编译Linux 0.11了,不是在Cygwin,也不是在虚拟机里,而是使用MinGW. 下面是在Windows下编译Linux 0.11会遇到的问题和对原文件作的修改: 1.赵炯博士已经将汇编程序中引用的C变量(包括嵌入汇编的C变量)的下划线去掉了,但MinGW的gcc可能是为了与其它Windows下的编译器保持兼容,并不能识别这些不带下划线的C变量,因而还得把原先已经在汇编程序中去掉下划线的C变量加上下划线,同时也要把被C程序引用的汇编程序中的变量加上下划线. 2.MinGW中不带as86编译器,因而把boot目录下原先用as86编译的bootsect.s和setup.s两个程序修改成能用nasm编译的程序.并且更名为bootsect.asm和setup.asm. 3.在Makefile作的主要修改: 在LDFLAGS中加了--image-base 0x0000 将elf_i386改成i386pe 将cd 与 make 之间的;改成&,如cd kernel ; make 改成cd kernel & make MinGW中没有sync这个程序,可以把它注释掉,更简单的办法是写一个sync.c,这个sync.c只包含一个空的main函数,编译成sync.exe 因为类似的原因,make dep会出错 4.生成的system文件是PE格式的(PE是Portable Executable的简称),这是windows下的可执行文件的格式,显然是不能直接执行的,必须加以转化.我实现了通过两种方式加以转化. 1)写一个程序Trans.cpp将system.exe里的代码和数据从PE文件里解析出来,生成一个system.bin文件,这个文件是能被setup模块直接加载的.我已经将这个程序放在了Linux-0.11的tools目录下,要微软的编译编译. 2)自己写一个PE Loader,这种方式比较麻烦,但是想想自己也能做一个PE Loader,还是满有成就感的,尽管这是一个最简单的Loader.代码是加在Linux-0.11-With-PE-Loader\boot目录下的setup.asm文件里,里面有详细的注释. 5.对tools下的build.c作了修改,使其能生成可引导的1.44M的软盘镜像文件Boot.img 6.在Link的过程中,init目录下的main.c会出现以下错误: boot/head.o(.text+0x540c):fake: undefined reference to `_main' init/main.o(.text+0x16f):main.c: undefined reference to `_alloca' init/main.o(.text+0x174):main.c: undefined reference to `__main' make: *** [tools/system.exe] Error 1 第一个和最后一个错误还好理解,但中间那个错误那就莫明其妙了,因为Linux 0.11根本没有这个函数,在gcc的编译选项里也有-nostdinc .有一个解释是main函数不是一个普通的函数,MinGW gcc会对它作特殊的处理.解决的办法其实也很简单,把main.c下面的main函数改名为_main,或者是干脆把它改成另外一个函数,就改成start吧.记得把head.s里的_main也改了. 在最后,要感谢《自己动手写操作系统》的作者于渊,其实我也是先将原先只能在Linux编译的书里源代码用MinGW移植到Windows下编译的过程中才试着在Windows下编译Linux 0.11源代码的,有了在Windows下编译Linux 0.11源代码的经验,移植高版本的源代码,像0.12,0.95,0.96等等版本应该不会有太大的麻烦了。 也要感谢Linux内核完全注释的作者赵炯博士,是他拉接了操作系统与操作系统爱好者的距离. 最后,我也非常想和操作系统爱好者们共同交流心得体会,也希望能多认识一些朋友. 我的网名:flyfish 我的QQ:785606288 E-mail:I2CBus@126.com 另外,要转载请保持本文件的完整性,请尊重别人的劳动果实. 修改日志: 08/3/29 修改了一下Makefile,旧的Makefile在某些文件更新后还会重新编译。 修改了Trans.cpp中的一个dug,该dug在translate MinGW gcc编译的程序时可能会出错。用MinGW gcc 编译的程序的VirtualAddress的形式可能是0xFFC1000这样的形式,其实0x1000才是它的VirtualAddress 08/4/2 修改了下MinGW32.bat,现在已经不用重设路径了。 08/4/4 Trans.cpp还是有错,如果VirtualAddress>0xffff,那么生成的system.bin就错了,bochs调试时会一直重启。 权宜之计,把0xffff再改成0x3ffff,这样VirtualAddress就不能大于0x3ffff,不知谁有更好的解决方法,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值