android 调试 native 程序的方法

一、背景

首先说需求,这个需求非常常见,就是android上需要的一个功能,linux已经有开源代码而且非常稳定,希望能直接porting过去使用,这个程序是pure c 的代码,也就是说,跟android framework, java 没关系,也跟jni没有关系,我们希望的就是能编译成一个可执行工具,push到android后能直接跑起来使用。

既然是native 代码,主要影响到的就是bionic libc, 因为android的这个基础库跟 linux 上常见的 gnu libc 有区别,主要是被精简了,至于更具体理解什么叫被精简,建议找个linux 开源工具代码在 android ndk 环境里编一下就知道了,其实,这里边还隐藏另外两层区别,一个是 android api level, 就是所谓的android 版本,比如 android 4.4.4 对应 android API 19, android 5 对应 android API 21 , 不同版本的 bionic libc 本身也是有区别的。 另一个是 abi , 就是体系架构的区别,比如 x86, x86_64, armeabi -v7a 等等,不同 abi 设置下 bionic libc 用到的接口也不一样。上面这两个影响会导致,你的代码可能在 API 21 编译通过了,但是在 API 19 失败,或者,在 armeabi-v7a 成功了,但是在 arm64-v8a 失败了。这两点的处理放在另外的文章说明,这篇文章不考虑。可以认为,我们暂时不考虑编译出来的工具的通用性,只在特定的目标,如 abi = armeabi-v7a, api = 21 的android devices 上运行。

好了,我们已经编成功了这个工具,push 到目标设备后(或模拟器)发现运行出现段错误,这是非常常见的,因为在移植过程中,我们把某些 glibc 的调用替换成了 bionic 的调用,接下去应该怎么调试呢?首先说这里的调试,当然是源码级别的单步调试,就是我们在 linux 上开发并调试程序一样。这个要求看似简单,但我搜索了一天的时间,尝试了多种方式,最后才找到一种简单可用且匹配需求的方式。

二、方法

首先,尝试搜索 gdb-for-arm 的工具,就是看有没有一个 gdb 可执行程序,是可以直接在 android arm devices 上运行的,如果有的话,就跟直接在 linux 环境里调试一样了,可惜,这么简单的需求,都搜索不到

下面都是尝试用远程调试的方式

第一种,客户端在win7. 使用 ida pro 6.6 , 它提供了一个  android_server 可以用来push到 android 系统里运行,然后在 ida 的界面里 run remote 可执行程序,这种方式可以跑起来,可以单步执行、可以下断点,但是无法加载正确的符号表。

第二种,客户端在win7,找了一个 http://gnutoolchains.com/android/  为android 编译好的 gnu tool chains 网站,下载 gdbserver 和 gdb.exe , gdbserver push到目标机器跑起来,本地用 gdb.exe 启动,使用gdb 远程调试那套步骤进行设置,发现也是能够跑起来,还是无法正确加载符号表。

第三种,客户在在win7,使用 Cygwin 的方式跑gdb客户端,启动之后 cygwin 报了一个长度太长的问题,没有深入去解决

从这里开始,突然对在win7 下启动 gdb 客户端有些失望,随即改为在  ubuntu14.04 里启动 gdb 客户端, android 模拟器也在 ubuntu 里启动。这里的 ubuntu 跑在 win7 上的 vmware 里。具体如果在 ubutnu 里下载并配置 android sdk 开发环境,并创建 avd , 启动 avd, 可以从网上搜索,最终就是在 ubuntu 里正常启动一个 android emulator.

然后,就使用下面的方式,就是可以源代码单步调试了:

1. 在设备上部署gdbserver

所谓部署其实就是把android ndk下的gdbserver拷贝到设备上,可以通过如下命令

adb push $ANDROID_NDK_ROOT/prebuilt/android-arm/gdbserver/gdbserver /data

2. 在设备上部署你的Native程序

需要把你编译出的程序和相关so库部署到设备上,注意so库要放在/system/lib下,/system路径默认是只读的,可以通过adb remount来重置。

adb push ./myapp /data/data

adb push ./libmylib.so /system/lib

3. 把设备上的相关调试环境拷贝到本地

因为远程调试需要一些目标机的库,把如下文件拷贝到本地文件夹

adb pull /system/lib ./debugging/lib

adb pull /system/bin/linker ./debugging/lib

4. 在设备上通过gdbserver运行你的程序

adb shell gdbserver :12345 /data/data/myapp

5. 在本地把本地TCP端口forward到设备的TCP端口

adb forward tcp:12345 tcp:12345

6. 在本地运行Android ndk路径下的gdb程序

$ANDROID_NDK/toolchains/arm-linux-androideabi-4.4.3/prebuild/darwin-x86/bin/arm-linux-androideabi-gdb

这里注意如果你在Ubuntu下用的是Linux的NDK包,那路径会有点不同,darwin-x86的地方应该是linux-x86.最保险的还是自己在NDK下搜索。

7. 启动gdb后在gdb下设置solib搜索路径

就是让gdb运行时能够找到调试相关的那些lib,也就是那些第三步中从设备上拉下来的文件。

(gdb) set solib-search-path ./debugging/lib

8. 在gdb下设置你希望调试的Native程序

(gdb) file ./myapp

9. 连接到设备的gdbserver

(gdb) target remote :12345

上面的6~9步也可以通过如下命令一步执行完

$ANDROID_NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-gdb --eval-command="set solib-search-path ./debugging/lib"  --eval-command="file  ./myapp" --eval-command="target remote :12345"

10. 开始调试

通过continue或c运行程序。注意不是用run,因为程序在目标机上其实已经启动了,只是break在程序入口。

参考: 使用GDB调试Android NDK native(C/C++)程序

时间: 2024-11-13 22:42:32

android 调试 native 程序的方法的相关文章

调试 Android* x86 应用程序的方法以及要使用的工具

作者:Xiaodong Wang 1.简介 众所周知,Android* 开发人员头顶许多称呼:设计员.程序猿等,并且通常会不可避免地被称为故障检修工.代码中的错误无法避免,因此无论您是否一开始就造成错误,了解调试工具以及如何迅速而有效地跟踪并解决错误都很重要.鉴于此,如今的 Android 开发人员必须掌握有效的调试技巧.本文提供了 Android 应用程序调试工具的简单教学,用于帮助 Android SDK 以及相关工具的新手迅速入门,并在 Android x86 平台上更有效地解决故障. 2

Android 调试native的crash和anr

1. 在trace中找到对应的库,例如 liba.so和对应的地址信息 2. 使用addr2line 查看 addr2line 地址 -e liba.so -f 或者 arm-eabi-addr2line 3. 如果addr2line打不出具体的函数就用objdump objdump -s -d liba.so > xxx.txt 或者arm-eabi-objdump 然后再分析具体的原因. Android 调试native的crash和anr

[Android设计模式]Android退出应用程序终极方法

如何干净彻底地退出Android应用程序,是很多开发者的心头痒.如何干净地关闭所有已打开的Activity? 如何关闭指定的Activity? 如何关闭一类Activity? 这里,我们提出一种通过实现对Application的扩展,实现了一种高效管理Activity,实现Android干净彻底地退出应用程序. 首先,我们将管理Activity的功能通过一个扩展的Application类来实现. public class MyApplication extends Application { p

Android下用程序的方法为ListView设置分割线Divider样式

使用XML的时候可以使用android:divider属性为ListView设置分割线的样式(颜色或者资源文件),而在Java代码中默认提供的方法 listView.setDivider() 却只支持Drawable资源文件,为此费了一点时间想解决方法,后来才发现其实很简单,android提供创建颜色资源文件的方法,于是只需要用 listView.setDivider(new ColorDrawable(color)) 就可以解决问题了. 如果设置完Divider没有效果的话,设置divider

[转]ubuntu下整合eclipse和javah生成jni头文件开发android的native程序

转载自:http://blog.csdn.net/jiuyueguang/article/details/9404237 本文介绍两种利用javah命令生成jni头文件的方法,第一种为大众所知的javah命令,第二种为整合javah到eclipse里面.推荐第二种方式,方便快捷,随时修改随时生成 0:前提和条件: 1:ubuntu64位系统 2:android-ndk-r8e已经安装好,并且配置到eclipse里面 3:android-sdk-linux已经安装好,并且配置到eclipse里面

ubuntu下整合eclipse和javah生成jni头文件开发android的native程序(转)

本文介绍两种利用javah命令生成jni头文件的方法,第一种为大众所知的javah命令,第二种为整合javah到eclipse里面.推荐第二种方式,方便快捷,随时修改随时生成 0:前提和条件: 1:ubuntu64位系统 2:android-ndk-r8e已经安装好,并且配置到eclipse里面 3:android-sdk-linux已经安装好,并且配置到eclipse里面 1:第一种命令行模式 1:如图,我的项目结构是这样,我的 如图,采用eclipse自动生成的jni文件夹中,可以看到And

调试CEF3程序的方法

CEF3多进程模式调试时按F5只会启动调试Browser进程,要调试Renderer进程就要让进程在启动时就暂停并附加进程. 所幸google早就想到了这一点,chrome的命令行参数就可以办到, --renderer-startup-dialog       加上这个参数,在Renderer进程启动时会弹出一个模态对话框,这时去附加Renderer和其它进程后再按确定就可以了. 还有一个参数 --renderer-process-limit=1,加上后Renderer进程就只会有一个,不用弹出

未加载mfc120ud.i386.pdb:VS2013调试MFC程序解决方法

刚使用VS2013时,想转入MFC库函数发现无法调试MFC代码.VS2013提示如下: 网上查了一下才得知,VS2013不像以前的VS版本一样自带MFC的pdb文件.但是微软提供了Microsoft Symbol Server自动下载pdb文件,只是默认情况下没有打开.打开方式为:"设置"->"调试"->"符号",选中"Microsoft 符号服务器"即可.这样在调试时,VS2013调试器会自动从服务器下载所需的p

Linux下打开Android调试器DDMS的方法

第一步:找到monitor可执行文件. 切换到目录路径:/home/skart/ide/android/sdk/tools/lib/monitor-x86_64,可以找到monitor可执行文件. 第二步:打开terminal命令行窗口,给monitor一个可执行权限 命令行输入 sudo chmod +x monitor,然后输入root的密码. 此时命令行输入 ./monitor 就可以打开ddms窗口.接着提示选择sdk路径,选择sdk路径后发现提示hprof-conv文件没有可执行权限,