动态库静态错误定位

    Java代码出错的时候,我们会在第一时间想到调试。通过一番调试之后之后,问题就迎刃而解。我们现在很多项目中都会用到JNI调用,其中.so文件的c++代码出错了,什么办呢?

我们还是从一个简单的例子说起吧。现在.so文件有如下一个代码: 

Jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,jobject thiz ){  

int *t; 

*t = 1;

    return (*env)->NewStringUTF(env, "Hello from JNI !");

}

   分析上面代码由于指针t没有分配内存,所以给它赋值回报错接下来我们开始运行调用该so文件的Android项目,在Logcat下会发现如下错误信息

    10-14 10:31:34.666: INFO/DEBUG(551): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

10-14 10:31:34.675: INFO/DEBUG(551): Build fingerprint: 'generic/sdk/generic/:1.5/CUPCAKE/147336:eng/test-keys'

10-14 10:31:34.675: INFO/DEBUG(551): pid: 6071, tid: 6071  >>> com.example.hellojni <<<

10-14 10:31:34.675: INFO/DEBUG(551): signal 7 (SIGBUS), fault addr 00000000

10-14 10:31:34.685: INFO/DEBUG(551):  r0 0000a9d0  r1 43736118  r2 41049d64  r3 00000001

10-14 10:31:34.685: INFO/DEBUG(551):  r4 befd8540  r5 00000004  r6 804002e5  r7 41049d3c

10-14 10:31:34.695: INFO/DEBUG(551):  r8 befd8520  r9 41049d34  10 41049d20  fp 00000000

10-14 10:31:34.695: INFO/DEBUG(551):  ip 804002e5  sp befd8510  lr ad00e3b8  pc 804002e4  cpsr 20000030

10-14 10:31:34.746: INFO/DEBUG(551):          #00  pc 000002e4  /data/data/com.example.hellojni/lib/libhello-jni.so

10-14 10:31:34.756: INFO/DEBUG(551):          #01  pc 0000e3b4  /system/lib/libdvm.so

10-14 10:31:34.765: INFO/DEBUG(551): stack: 

    观察上面的日志文件,我们会发现c++代码调用的堆栈信息在最顶端堆栈的是libhello-jni.so(上面代码编译在此so文件里面),以及用红色标识出来的地址000002e4, 我们正是通过该地址找到出错的函数。 

    ndk 提供了windows c++二进制分析的工具。最新已经是ndk1.6了,可以到网上很容易获得。其中arm-eabi-objump.exe 工具是可以用于分析so文件。如下所示:

    arm-eabi-objump.exe  S  libhello-jni.so > test.txt 输出重定向到test.txt中。 

    打开test.txt,我们看到如下信息

    libhello-jni.so:     file format elf32-littlearm

Disassembly of section .text:

000002e4 <Java_com_example_hellojni_HelloJni_stringFromJNI>:

    2e4:    b510        push    {r4, lr}

    2e6:    2301        movs    r3, #1

    2e8:    601b        str r3, [r3, #0]

    2ea:    4905        ldr r1, [pc, #20]   (300 <.text+0x1c>)

    2ec:    6804        ldr r4, [r0, #0]

    2ee:    4a05        ldr r2, [pc, #20]   (304 <.text+0x20>)

    2f0:    23a7        movs    r3, #167

    2f2:    4479        add r1, pc

    2f4:    009b        lsls    r3, r3, #2

    2f6:    58e3        ldr r3, [r4, r3]

    2f8:    1889        adds    r1, r1, r2

    2fa:    4798        blx r3

    2fc:    bd10        pop {r4, pc}

    2fe:    0000        lsls    r0, r0, #0

    300:    10ae        asrs    r6, r5, #2

    302:    0000        lsls    r0, r0, #0

    304:    ef64 ffff   undefined

    我们可以看到红色的编译地址2e4. 和我们之前看到地址2e4一样。基本上可以定位是Java_com_example_hellojni_HelloJni_stringFromJNI函数的某一位置出错。仔细分析,可以定位到之前的问题。

 

接下来我还要介绍下面常用的二进制分析工具

AR 用来建立、修改、提取静态库文件.

NM 列出目标文件的符号表中定义的符号。常见的链接或者运行时发生的unresolved symbol类型的错误可以用NM来辅助调试

OBJDUMP  objdump是所有二进制工具之母,能够显示一个目标文件中所有的信息,通常我们用它来反汇编.text节中的二进制指令

READELF  readelf可用来显示ELF格式可执行文件的信息

SIZE

size命令可以列出目标文件每一段的大小以及总体的大小。默认情况下,对于每个目标文件或者一个归档文件中的每个模块只产生一行输出。size可以用来简单快速的了解ELF文件各个段的情况

ldd可用来显示执行文件需要哪些共享库共享库装载管理器在哪里找到了需要的共享库

 

工具的使用我这边就不想详细多说,网上对这些工具介绍有海量的信息。我想强调的是,要想深入解决c++的问题,我们要熟练掌握这些工具的使用,这对我们调试Android native code有非常大的帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值