GDB调试Android代码——环境搭建及调试过程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhu929033262/article/details/76064044

网上看了好多关于GDB调试android本地代码的,但是都是直接上手,对于一点都不懂的我,真是难办,所以本人根据个人经历,总结下怎么从小白一步一步进行调试。


先讲一下GDB调试android本地代码的情况。开始看了好多资料,天真的以为用GDB命令就能直接启动so库,实际情况是,先写好JNI的应用之后,肯定是java代码去调用本地代码的,所以需要设置按钮之类的,在调试过程中,需要通过按钮或其他方式,启动jni的本地代码。每次设置了断点之后,需要点击按钮启动代码,然后代码运行到断点出停止,然后通过GDB命令查看各种信息,或者继续运行。


好了下面开始介绍


调试环境:

调试平台:ubuntu14.04LTS

目标手机:Android6.0虚拟机 X86架构,我用的nexus5,烧的原生系统,ROOT,直接自带gdbserver

软件环境:android-ndk-r10b搭配adt-bundle,并且自己准备一个包含JNI调用的应用


然后准备gdb和gdbserver,远程调试需要在目标手机上有个类似调试客户端的东西来给gdb传送数据什么的,然后在linux上接受这些信息,进行调试,所以需要这两个东西,在网上看的资料各种在线下载或者交叉编译什么的才能得到这两个东西,其实不用那么麻烦,NDK里自带(Android源码里边也带,请自行查找):

1. gdb:$NDK_DIR/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gdb,中间的路径根据自己情况更改。

2. gdbserver:位置:$NDK_DIR/prebuilt/android-arm64/gdbserver

因为我的测试机自带gdbserver,所以我直接用NDK目录中的gdb配合使用,如果不用ndk的,用Android源码目录下的GDB话效果一样的。

需要注意的是gdbserver和gdb的版本要匹配,否则会出错。

查看gdbserver版本号:

conan@conan-HP-Pro-3380-MT:~$ adb shell
shell@hammerhead:/ $ gdbserver --version
GNU gdbserver (GDB) 7.6
Copyright (C) 2013 Free Software Foundation, Inc.
gdbserver is free software, covered by the GNU General Public License.
This gdbserver was configured as "arm-eabi-linux"

查看gdb版本号:

conan@conan-HP-Pro-3380-MT:~/java/adt-bundle-linux-x86_64-20140321/android-ndk-r10b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin$ ./arm-linux-androideabi-gdb --version
GNU gdb (GDB) 7.6
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-linux-gnu --target=arm-linux-android".
For bug reporting instructions, please see:
<http://source.android.com/source/report-bugs.html>.
conan@conan-HP-Pro-3380-MT:~/java/adt-bundle-linux-x86_64-20140321/android-ndk-r10b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin$ 



网上还有人说了了这个问题,好像确实有影响,所以也适当注意下,我是通过RE管理器直接修改的:

对了,还有一点需要注意的是,Android从4.4开始,强制打开了SELinux,其规则是不允许一个进程attach到一个非自己的子进程或兄弟进程上进行调试的,哪怕这个进程是以root用户启动的也不行。想要知道当前SELinux的工作模式,可以在adb shell下键入getenforce命令,例如:


这是在我运行Android 5.0系统的Google Nexus 5上运行的结果,可以看出,其已经默认打开了强制(Enforcing)模式。所以,要想调试成功,必须要关闭SELinux的强制模式,可以通过下面的命令来关闭:

        echo 0> /sys/fs/selinux/enforce

注意,这条命令必须用root用户来运行。下面看看运行后的结果:


可以看出,SELinux的模式已经从强制变成了允许(Permissive)。


准备妥当后就可以调试了,当然要写好自己的应用工程,包含jni代码的,我写的为JNI_test。

1 首先启动要调试的程序,ps 获取其进程号 (或者在eclipse的DDMS中直接查看)

conan@conan-HP-Pro-3380-MT:~$ adb shell
shell@hammerhead:/ $ ps | busybox grep jni      
u0_a78    23954 319   920924 49544 sys_epoll_ 00000000 S com.example.jni_test


2 启动gdbserver attach到目标进程  (在adb进入手机上操作,注意此时需要root权限)

shell@hammerhead:/ $ su
root@hammerhead:/ # gdbserver remote:1234 --attach 23954
Attached; pid = 23954
Listening on port 1234

其中 remote:1234 表示映射成tcp的1234端口,这个时候重新打开一个 adb shell 再ps yahfa发现

shell@hammerhead:/ $ ps | busybox grep yahfa
u0_a78    23954 319   930024 49648 ptrace_sto 00000000 t com.example.hook_yahfa
进程状态已经变成 t了,表示 attach已经成功了。


3 启动gdb 来进行调试 (pc环境中操作,我用的是ubuntu系统)

conan@conan-HP-Pro-3380-MT:~/Android/android-6.0.0_r1/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin$ adb forward tcp:1234 tcp:1234

首先端口映射,映射成 1234 端口号


把/system/bin/app_process,/system/bin/linker,/system/lib/libc.so 从手机上拷贝出来(可以用adb pull 命令),其他so文件也拷贝出来也行,我们假定拷贝的目录为$lib

conan@conan-HP-Pro-3380-MT:~$ adb pull /system/bin/app_process /home/conan/java/tmp/GDB 
269 KB/s (22144 bytes in 0.080s)
conan@conan-HP-Pro-3380-MT:~$ adb pull /system/bin/linker /home/conan/java/tmp/GDB 
1351 KB/s (189636 bytes in 0.137s)
conan@conan-HP-Pro-3380-MT:~$ adb pull /system/lib/libc.so /home/conan/java/tmp/GDB 
2997 KB/s (676872 bytes in 0.220s)
conan@conan-HP-Pro-3380-MT:~$ 

运行arm-linux-androideabi-gdb ,输入以下命令序列 file $lib/app_process,   $lib目录中有从手机拷贝出来的app_process,linker和libc.so这些文件 ,如我放到了/home/conan/java/tmp/GDB目录下

conan@conan-HP-Pro-3380-MT:~/java/adt-bundle-linux-x86_64-20140321/android-ndk-r10b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin$ ./arm-linux-androideabi-gdb
GNU gdb (GDB) 7.6
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-linux-gnu --target=arm-linux-android".
For bug reporting instructions, please see:
<http://source.android.com/source/report-bugs.html>.
(gdb) file /home/conan/java/tmp/GDB/app_process
Reading symbols from /home/conan/java/tmp/GDB/app_process...(no debugging symbols found)...done.


set solib-absolute-prefix $nostriplib_dir, $nostriplib_dir是存放了没有strip的so的目录,因为我们有源代码,而本身android 源码ndk编译的时候默认是加 -g选项的,没有被 strip的so库在/home/conan/java/tmp/eclipse_android/JNI_test/obj/local/armeabi这个目录下,而在libs下的so是被 strip过的版本

gdb) set solib-absolute-prefix /home/conan/java/tmp/eclipse_android/JNI_test/obj/local/armeabi
(gdb) 

set solib-search-path $lib:$nostriplib_dir,

(gdb) set solib-search-path /home/conan/java/tmp/GDB:/home/conan/java/tmp/eclipse_android/JNI_test/obj/local/armeabi
(gdb) 

target remote :端口号 连上gdbserver

(gdb) <pre name="code" class="plain">(gdb) target remote :1234
Remote debugging using :1234
warning: Could not load shared library symbols for 118 libraries, e.g. /system/lib/libsigchain.so.
Use the "info sharedlibrary" command to see the complete listing.
Do you need "set solib-search-path" or "set sysroot"?
Reading symbols from /home/conan/java/tmp/GDB/linker...(no debugging symbols found)...done.
Loaded symbols for /home/conan/java/tmp/GDB/linker
Reading symbols from /home/conan/java/tmp/GDB/libc.so...(no debugging symbols found)...done.
Loaded symbols for /home/conan/java/tmp/GDB/libc.so
Reading symbols from /home/conan/java/tmp/eclipse_android/JNI_test/obj/local/armeabi/libJNI_test.so...done.
Loaded symbols for /home/conan/java/tmp/eclipse_android/JNI_test/obj/local/armeabi/libJNI_test.so
0xb6d4a2e4 in __epoll_pwait () from /home/conan/java/tmp/GDB/libc.so

进入gdb,并监听1234端口,警告可以忽略,因为没从手机上pull出这些库,不影响的。

这个时候已经进入 gdb了

dir source 指定源码路径

(gdb) dir /home/conan/java/tmp/eclipse_android/JNI_test/jni 
Source directories searched: /home/conan/java/tmp/eclipse_android/JNI_test/jni:$cdir:$cwd
(gdb) 



设置完成以后

(gdb) list JNI_test.cpp:5
1	#include <jni.h>
2	#include <com_example_jni_test_jni.h>
3	
4	JNIEXPORT jstring JNICALL Java_com_example_jni_1test_jni_sayName
5	  (JNIEnv *env, jclass){
6		int a = 1;
7		char b = 'a';
8		a = 1+2;
9		b = 's';
10	    return env->NewStringUTF("This is a test message!");

发现已经有代码显示了 


我们在这里设置断点,分别在6/7/8/9/10行设置断点,一共5个作为测试。

(gdb) b JNI_test.cpp:6
Breakpoint 1 at 0xa0208c8c: file jni/JNI_test.cpp, line 6.
(gdb) b JNI_test.cpp:7
Breakpoint 2 at 0xa0208c94: file jni/JNI_test.cpp, line 7.
(gdb) b JNI_test.cpp:8
Breakpoint 3 at 0xa0208c9c: file jni/JNI_test.cpp, line 8.
(gdb) b JNI_test.cpp:9
Breakpoint 4 at 0xa0208ca4: file jni/JNI_test.cpp, line 9.
(gdb) b JNI_test.cpp:10
Breakpoint 5 at 0xa0208cac: file jni/JNI_test.cpp, line 10.

然后在应用上点击按钮,执行so库里边的方法,这里我的按钮设置的会执行Java_com_example_jni_1test_jni_sayName这个方法,而因为我实现设置好了断点,所以执行到这里的时候会停下。

继续执行

(gdb) c
Continuing.

Breakpoint 1, Java_com_example_jni_1test_jni_sayName (env=0xb4d96a80)
    at jni/JNI_test.cpp:6
6		int a = 1;
(gdb) c
Continuing.

Breakpoint 2, Java_com_example_jni_1test_jni_sayName (env=0xb4d96a80)
    at jni/JNI_test.cpp:7
7		char b = 'a';
(gdb) 

通过c命令,可以按照断点一个一个往下执行,


如果要查看变量或者汇编指令

(gdb) print b
$1 = 176 '\260'
(gdb) c
Continuing.

Breakpoint 3, Java_com_example_jni_1test_jni_sayName (env=0xb4d96a80)
    at jni/JNI_test.cpp:8
8		a = 1+2;
(gdb) print b
$2 = 97 'a'
(gdb) print a
$3 = 1
(gdb) disas
Dump of assembler code for function Java_com_example_jni_1test_jni_sayName(JNIEnv*, jclass):
   0xa0208c78 <+0>:	push	{r11, lr}
   0xa0208c7c <+4>:	add	r11, sp, #4
   0xa0208c80 <+8>:	sub	sp, sp, #16
   0xa0208c84 <+12>:	str	r0, [r11, #-16]
   0xa0208c88 <+16>:	str	r1, [r11, #-20]
   0xa0208c8c <+20>:	mov	r3, #1
   0xa0208c90 <+24>:	str	r3, [r11, #-8]
   0xa0208c94 <+28>:	mov	r3, #97	; 0x61
   0xa0208c98 <+32>:	strb	r3, [r11, #-9]
=> 0xa0208c9c <+36>:	mov	r3, #3
   0xa0208ca0 <+40>:	str	r3, [r11, #-8]
   0xa0208ca4 <+44>:	mov	r3, #115	; 0x73
   0xa0208ca8 <+48>:	strb	r3, [r11, #-9]
   0xa0208cac <+52>:	ldr	r0, [r11, #-16]
   0xa0208cb0 <+56>:	ldr	r3, [pc, #24]	; 0xa0208cd0 <Java_com_example_jni_1test_jni_sayName(JNIEnv*, jclass)+88>
   0xa0208cb4 <+60>:	add	r3, pc, r3
   0xa0208cb8 <+64>:	mov	r1, r3
   0xa0208cbc <+68>:	bl	0xa0208c3c <_JNIEnv::NewStringUTF(char const*)>
   0xa0208cc0 <+72>:	mov	r3, r0
   0xa0208cc4 <+76>:	mov	r0, r3
---Type <return> to continue, or q <return> to quit---return


以上就是用GDB调试android本地代码的方法,更多GDB密令,可以往下看或者自行百度。





其他相关的资料,直接贴上,有兴趣自己看吧:

需要的文件: gdbserver 位置:android-ndk-r8b/prebuilt/android-arm/gdbserver/gdbserver gdb 位置:android-ndk-r8b/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-gdb 步骤:

  1. apk 打开调试开关, AndroidManifest.xml 中, application节点 加入 android:debuggable="true",
  2. 如果是root的机器,apk没有打开调试开关也可以进行调试,如果是已经root的机器,把gdbserver放到系统(手机)的目录下(可以随意放置,一般放到system/bin目录下方便输入命令)
  3. 如果是没有root的机器,需要把gdbserver打到apk的包里(放到lib目录下),这样安装apk的的时候会把gdbserver拷贝到/data/data/app名称/lib/gdbserver
  4. 启动apk,可以直接启动
  5. 用 adb shell 进行控制台,用ps命令查看app的进程id
  6. 如果是root机器,可以su后,直接用gdbserver attach ,命令行是 gdbserver :端口号 --attach pid 如 : su gdbserver :2345 --attach pid
  7. 如果是未root机器,只能用以下方式 run-as app名称 lib/gdbserver :端口号 --attach pid
  8. 在pc上运行adb forward tcp:端口号(指PC上的端口) tcp:端口号(手机上的端口) 建立端口映射
  9. 把/system/bin/app_process /system/bin/linker, /system/lib/libc.so 从手机上拷贝出来(可以用adb pull 命令),其他so文件也拷贝出来也行,我们假定拷贝的目录为$lib
  10. 运行arm-linux-androideabi-gdb ,输入以下命令序列 file $lib/app_process $lib目录中有从手机拷贝出来的app_process,linker和libc.so这些文件 ,如我放到了/home/qrf/android_ndk_debug/mydev目录下

    set solib-absolute-prefix $nostriplib_dir $nostriplib_dir是存放了没有strip的so的目录,如 set solib-absolute-prefix /home/qrf/code/cmso

    set solib-search-path $lib:$nostriplib_dir 如set solib-search-path /home/qrf/android_ndk_debug/mydev:/home/qrf/code/cmso

    target remote :端口号 连上gdbserver

    dir source 指定源码路径 后面就是gdb调试的问题了,进入gdb调试界面可以用ctrl x + a 来切换到文本模式(可以查看源码), 如果要配合ddd前端, 用apt-get install ddd ,然后 用ddd --debugger arm-linux-androideabi-gdb 使用,但是ddd有时会不太灵光,还是直接使用gdb比较方便

附一些常用的gdb命令:

  1. backtrace/bt //列出当前线程堆栈
  2. thread apply all bt //列出所有线程调用堆栈
  3. thread 线程号//切换线程上下文
  4. ctrl x+a //切换到源码浏览窗口 ,再按ctrl x+a 切换回去
  5. ctrl c //中断当前运行
  6. c/continue //继续运行
  7. info sharedlibrary //列出so加载列表
  8. info threads //列出线程列表
  9. info locals //列出当前堆栈上的局部变量
  10. info breakpoints //列出断点
  11. print 变量名 //列出变量内容
  12. print 变量名= //修改变量名的值
  13. b/break 源码文件名:行号 //下断点
  14. d/delete 断点id //删除断点
  15. f/frame 栈帧序号 //切换到指定的栈帧 如 f 0 顶层
  16. s/step //下一步,有函数调用会进入
  17. n/next //下一步,有函数调用不会进入
  18. fin/finish //返回到上层函数调用
  19. disable 断点id //禁用断点
  20. enable 断点id //启用断点
  21. disassemble/disas //查看汇编代码

5. gdb命令说明

       gdb中,输入命令时,可以不用打全命令,只用打命令的前几个字符就可以了,当然,命令的前几个字符应该要标志着一个唯一的命令,在Linux下,你可以敲击两次TAB键来补齐命令的全称,如果有重复的,那么gdb会把其例出来。 
==============显示gdb命令帮助信息===================

  • help        显示gdb命令种类
  • help subcommand 显示subcommand的帮助信息
  • apropos word   搜索与word相关的命令

==============设置断点===================

  • b(break) 在函数或某一行处设置断点 
    如果只记得部分函的前缀,可以这样:(gdb) b make_ <按TAB键>。 
    break filename:linenum       在源文件filename的linenum行处停住 
    break filename:function       在源文件filename的function函数的入口处停住 
    break *address                       在程序运行的内存地址处停住 
    break       break命令没有参数时,指在下一条指令处停住 
    break … If …        在条件成立时程序停住 
    break thread threadnum       定义在线程threadnum上的断点,如break BootAnimation.cpp:364 thread 28 if bartab > lim

===============设置观察点=================

  • watch expr       设置观察点,当表达式expr的值变化时,程序停住
  • rwatch expr       设置观察点,当表达式expr的值被读时,程序停住
  • awatch expr       设置观察点,当表达式expr的值被读或写时,程序停住

===============设置捕捉点=================

  • catch       设置被调试程序捕捉点,当event发生时,程序停住 
    catch catch [args]       捕捉一个C++捕捉到的异常 
    catch throw [args]       捕捉一个C++抛出的异常 
    catch syscall [args]       捕捉系统调用

===============维护被调试程序断点==================

  • condition N COND       修改断点号为N的停止条件为COND
  • ignore N COUNT       忽略断点号为N的停止条件COUNT次
  • clear [linenum|funname|*]       清除指定的行或函数断点
  • d(delete) [breakpoints][range]        清除指定的断点
  • disable [breakpoints] [range…]        禁用指定的断点
  • enable [breakpoints] [range…]        启用指定的断点

===============为停止点设定运行命令================

  • commands N       调试程序在断点号为N的断点处停止后,执行命令 
    执行命令 
    end

===============显示被调试程序的信息================

  • info subcommand       显示被调试程序的某些信息,可用help info查看子命令。如: 
    info breakpoints [n]       显示所有断点(或断点n)信息 
    info watchpoints [n]       显示所有观察点(或观察点n)信息 
    info program       查看被调试程序的执行状态 
    info args        打印出当前函数的参数名及其值 
    info locals       打印出当前函数中所有局部变量及其值 
    info display       查看display设置的自动显示的信息 
    info frame       查看栈帧信息,包括程序语言

===============运行及查看被调试信息================

  • r(run)       运行被调试程序
  • c(continue)       从断点出开始继续执行直到结束或下一个断点
  • s(step)       单步跟踪,如果有函数调用,他会进入该函数。进入函数的前提是此函数被编译有debug信息
  • n(next)       单步跟踪,如果有函数调用,他不会进入该函数
  • p(print)       打印表达式的值 
    可以查看全局变量(所有文件可见)、静态全局变量(当前文件可见)、局部变量(当前Scope可见) 
    p file::var       查看文件file中的变量var 
    p func::var       查看函数file中的变量var 
    p start@len       查看一段连续的内存空间的值,“@”的左边是第一个内存的地址的值,“@”的右边则你你想查看内存的长度,如: 
    int array = (int ) malloc (len * sizeof (int)); 
    p *array@len 
    p/format expr       按指定的格式显示表达式expr(format:x, d, f, c, u, o, t, a)
  • display[/fmt] expr       程序停下来后就会显示expr的值
  • undisplay/delete displaynum/disable displaynum/enable displaynum
  • bt        查看当前函数调用堆栈信息
  • f(frame)       查看当前栈层信息,包括栈的层编号、当前的函数名、函数参数值、函数所在文件及行号和函数执行到的语句
  • finish       运行程序,直到当前函数完成返回
  • u(until)       运行程序直到退出循环体

===============显示源代码===============

  • l(list)       列出具体的函数或代码行 
    list       显示当前行后面的源程序 
    list -        显示当前行前面的源程序 
    list +       显示当前行后面的源程序 
    list linenum       显示程序第linenum行的周围的源程序 
    list file:filenum       显示文件file中的filenum行 
    list file:func       显示文件file中的函数func 
    list funcname       显示函数名为function的函数的源程序,如list android::BootAnimation::movie

===============搜索源代码===============

  • forward-search reg       利用正则表达式前向搜索源码
  • search reg       利用正则表达式前向搜索源码
  • reverse-search reg       利用正则表达式在全部源码中进行搜索

===============设置被调试程序参数/gdb配置==============

  • set subcommand       设置gdb环境变量,可以使用help set查看set子命令。如: 
    set args       设置被调试程序运行参数 
    set directories       设置源文件搜索路径,多个使用“:”分割 
    set solib-search-path       设置符号表搜索路径 
    set environment varname [=value]       设置环境变量。如:set env USER=llj 
    set listsize num       设置一次显示源代码的行数 
    set step-mode on       打开step-mode模式,于是,在进行单步跟踪时,程序不会因为没有debug信息而不停住。这个参数有很利于查看机器码 
    set print address on       打开地址输出, 当程序显示函数信息时,GDB会显出函数的参数地址 
    set print array on       打开数组显示,打开后当数组显示时,每个元素占一行,如果不打开的话,每个元素则以逗号分隔 
    set print elements num       设置显示数组元素的最大个数 
    set print null-stop on/off       如果打开了这个选项,那么当显示字符串时,遇到结束符则停止显示 
    set print pretty on/off       打开后gdb显示结构体时会比较漂亮 
    set print sevenbit-strings       设置字符显示,是否按“/nnn”的格式显示 
    set print union on/off       设置显示结构体时,是否显式其内的联合体数据
  • show subcommand       显示调试器的信息,使用help show查看子命令。如: 
    show environment [varname]       查看环境变量 
    show listsize       显示当前listsize的设置 
    show directories       显示定义了的源文件搜索路径 
    show language       查看gdb当前的语言环境

===============其他=================

  • q(quit)       退出gdb
  • handle        处理信号

===============shell命令================= 
       此外gdb中可以执行shell命令,使用SHELL环境变量定义的可执行程序来执行shell命令,常用的命令如下:

  • show environment SHELL       查看shell执行程序
  • make       重新编译程序,相当于shell make
  • cd       必变工作目录,相当于shell cd
  • pwd       查看当前工具目录,相当于shell pwd

===============调整程序线路================= 
       一旦使用GDB挂上被调试程序,当程序运行起来后,你可以根据自己的调试思路来动态地在GDB中更改当前被调试程序的运行线路或是其变量的值,这个强大的功能能够让你更好的调试你的程序,比如,你可以在程序的一次运行中走遍程序的所有分支。

  • 修改变量的值 
    print x = 4       C/C++语法,把变量x的值修改为4 
    set var width=10       用gdb命令将参数width值修改为10
  • 跳转执行 
    jump +num       当前运行点向下偏移num行开始执行 
    jump linenum       从当前调试文件的linenum行开始执行 
    jump file:linenum       从file的linenum行开始执行
  • 产生信号量 
    singal SIGNAL       发送信号SINGAL给被调试程序
  • 强制函数返回 
    return       强制函数返回,忽略未执行的语句 
    return result       强制函数返回结果result,忽略未执行的语句
  • 强制调用函数 
    call func       调用当前程序中的函数 
    print func       调用当前程序中的函数




又按照上述教程进行了调试,终于调通,备份下记录文件:

conan@conan-HP-Pro-3380-MT:~/java/adt-bundle-linux-x86_64-20140321/android-ndk-r10b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin$ adb forward tcp:1234 tcp:1234
conan@conan-HP-Pro-3380-MT:~/java/adt-bundle-linux-x86_64-20140321/android-ndk-r10b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin$ ./arm-linux-androideabi-gdb
GNU gdb (GDB) 7.6
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-linux-gnu --target=arm-linux-android".
For bug reporting instructions, please see:
<http://source.android.com/source/report-bugs.html>.
(gdb) file /home/conan/java/tmp/GDB/app_process
Reading symbols from /home/conan/java/tmp/GDB/app_process...(no debugging symbols found)...done.
(gdb) file /home/conan/java/tmp/eclipse_android/JNI_test/obj/local/armeabi/lib
libJNI_test.so  libstdc++.a     
(gdb) file /home/conan/java/tmp/eclipse_android/JNI_test/obj/local/armeabi/libJNI_test.so
Reading symbols from /home/conan/java/tmp/eclipse_android/JNI_test/obj/local/armeabi/libJNI_test.so...done.
(gdb) set solib-absolute-prefix /home/conan/java/tmp/eclipse_android/JNI_test/obj/local/armeabi
(gdb) set solib-search-path /home/conan/java/tmp/GDB:/home/conan/java/tmp/eclipse_android/JNI_test/obj/local/armeabi
(gdb) target remote :1234
Remote debugging using :1234
warning: Could not load shared library symbols for 118 libraries, e.g. /system/lib/libsigchain.so.
Use the "info sharedlibrary" command to see the complete listing.
Do you need "set solib-search-path" or "set sysroot"?
Reading symbols from /home/conan/java/tmp/GDB/linker...(no debugging symbols found)...done.
Loaded symbols for /home/conan/java/tmp/GDB/linker
Reading symbols from /home/conan/java/tmp/GDB/libc.so...(no debugging symbols found)...done.
Loaded symbols for /home/conan/java/tmp/GDB/libc.so
Reading symbols from /home/conan/java/tmp/eclipse_android/JNI_test/obj/local/armeabi/libJNI_test.so...done.
Loaded symbols for /home/conan/java/tmp/eclipse_android/JNI_test/obj/local/armeabi/libJNI_test.so
0xb6d4a2e4 in __epoll_pwait () from /home/conan/java/tmp/GDB/libc.so
(gdb) list
1 #include <jni.h>
2 #include <com_example_jni_test_jni.h>
3
4 JNIEXPORT jstring JNICALL Java_com_example_jni_1test_jni_sayName
5  (JNIEnv *env, jclass){
6 int aaaaaaaaaaaaaaaaaa = 1;
7 char bbbbbbbbbbbbbbbbbbb = 'a';
8    return env->NewStringUTF("This is a test message!");
9 }
(gdb) dir /home/conan/java/tmp/eclipse_android/JNI_test/jni 
Source directories searched: /home/conan/java/tmp/eclipse_android/JNI_test/jni:$cdir:$cwd
(gdb) list
Line number 10 out of range; jni/JNI_test.cpp has 9 lines.
(gdb) list jni/JNI_test.cpp:5
1 #include <jni.h>
2 #include <com_example_jni_test_jni.h>
3
4 JNIEXPORT jstring JNICALL Java_com_example_jni_1test_jni_sayName
5  (JNIEnv *env, jclass){
6 int aaaaaaaaaaaaaaaaaa = 1;
7 char bbbbbbbbbbbbbbbbbbb = 'a';
8    return env->NewStringUTF("This is a test message!");
9 }
(gdb) b jni/JNI_test.cpp:6
Cannot access memory at address 0xc8c
(gdb) file /home/conan/java/tmp/GDB/app_process
A program is being debugged already.
Are you sure you want to change the file? (y or n) y


Load new symbol table from "/home/conan/java/tmp/GDB/app_process"? (y or n) y
Reading symbols from /home/conan/java/tmp/GDB/app_process...(no debugging symbols found)...done.
(gdb) dir /home/conan/java/tmp/eclipse_android/JNI_test/jni 


Source directories searched: /home/conan/java/tmp/eclipse_android/JNI_test/jni:/home/conan/java/tmp/eclipse_android/JNI_test/jni:$cdir:$cwd
(gdb) b jni/JNI_test.cpp:6
Breakpoint 1 at 0xa0202c8c: file jni/JNI_test.cpp, line 6.
(gdb) b jni/JNI_test.cpp:8
Breakpoint 2 at 0xa0202c9c: file jni/JNI_test.cpp, line 8.
(gdb) c
Continuing.
c


Breakpoint 1, Java_com_example_jni_1test_jni_sayName (env=0xb4d96a80)
    at jni/JNI_test.cpp:6
6 int aaaaaaaaaaaaaaaaaa = 1;
(gdb) c
Continuing.


Breakpoint 2, Java_com_example_jni_1test_jni_sayName (env=0xb4d96a80)
    at jni/JNI_test.cpp:8
8    return env->NewStringUTF("This is a test message!");
(gdb) c
Continuing.
c
^C
Program received signal SIGINT, Interrupt.
0xb6d4a2e4 in __epoll_pwait () from /home/conan/java/tmp/GDB/libc.so
(gdb) c
Continuing.


Breakpoint 1, Java_com_example_jni_1test_jni_sayName (env=0xb4d96a80)
    at jni/JNI_test.cpp:6
6 int aaaaaaaaaaaaaaaaaa = 1;
(gdb) bt
#0  Java_com_example_jni_1test_jni_sayName (env=0xb4d96a80)
    at jni/JNI_test.cpp:6
#1  0x9f18408e in ?? ()
#2  0x9f18408e in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) c
Continuing.


Breakpoint 2, Java_com_example_jni_1test_jni_sayName (env=0xb4d96a80)
    at jni/JNI_test.cpp:8
8    return env->NewStringUTF("This is a test message!");
(gdb) bt
#0  Java_com_example_jni_1test_jni_sayName (env=0xb4d96a80)
    at jni/JNI_test.cpp:8
#1  0x9f18408e in ?? ()
#2  0x9f18408e in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) print aaaaaaaaaaaaaaaaaa
$1 = 1
(gdb) disas
Dump of assembler code for function Java_com_example_jni_1test_jni_sayName(JNIEnv*, jclass):
   0xa0202c78 <+0>: push{r11, lr}
   0xa0202c7c <+4>: addr11, sp, #4
   0xa0202c80 <+8>: subsp, sp, #16
   0xa0202c84 <+12>: strr0, [r11, #-16]
   0xa0202c88 <+16>: strr1, [r11, #-20]
   0xa0202c8c <+20>: movr3, #1
   0xa0202c90 <+24>: strr3, [r11, #-8]
   0xa0202c94 <+28>: movr3, #97; 0x61
   0xa0202c98 <+32>: strbr3, [r11, #-9]
=> 0xa0202c9c <+36>: ldrr0, [r11, #-16]
   0xa0202ca0 <+40>: ldrr3, [pc, #24]; 0xa0202cc0 <Java_com_example_jni_1test_jni_sayName(JNIEnv*, jclass)+72>
   0xa0202ca4 <+44>: addr3, pc, r3
   0xa0202ca8 <+48>: movr1, r3
   0xa0202cac <+52>: bl0xa0202c3c <_JNIEnv::NewStringUTF(char const*)>
   0xa0202cb0 <+56>: movr3, r0
   0xa0202cb4 <+60>: movr0, r3
   0xa0202cb8 <+64>: subsp, r11, #4
   0xa0202cbc <+68>: pop{r11, pc}
   0xa0202cc0 <+72>: andeqr1, r0, r8, lsl #13
End of assembler dump.
(gdb) 





阅读更多

没有更多推荐了,返回首页