1. Crash后 logcat中输出绿色信息:

05-02 10:14:37.130: I/DEBUG(1890): backtrace:05-02 10:14:37.130: I/DEBUG(1890):     #00  pc 00033fda  /data/data/com.XXXXX.map/lib/libmapengine.so (TextureCache::_touchListNode(TextureCacheItem*)+25)05-02 10:14:37.130: I/DEBUG(1890):     #01  pc 0003407d  /data/data/com.XXXXX.map/lib/libmapengine.so (TextureCache::getTexItem(char, char, int, int)+32)05-02 10:14:37.130: I/DEBUG(1890):     #02  pc 00032c9f  /data/data/com.XXXXX.map/lib/libmapengine.so (prepareTiles(int, int, int, double)+158)05-02 10:14:37.130: I/DEBUG(1890):     #03  pc 000332cf  /data/data/com.XXXXX.map/lib/libmapengine.so (nativePrepareRender+566)05-02 10:14:37.130: I/DEBUG(1890):     #04  pc 0002fb79  /data/data/com.XXXXX.map/lib/libmapengine.so (Java_com_XXXXX_map_gl_JNI_nativePrepareRender+192)05-02 10:14:37.130: I/DEBUG(1890):     #05  pc 0001de70  /system/lib/libdvm.so (dvmPlatformInvoke+112)05-02 10:14:37.130: I/DEBUG(1890):     #06  pc 0004d0c3  /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+394)05-02 10:14:37.130: I/DEBUG(1890):     #07  pc 000009e0  /dev/ashmem/dalvik-jit-code-cache (deleted)


2. 找到APP中对应的SO包,获取so的汇编源码

注意编译so包时需要注释mk文件中两句:

cmd-strip = $(TOOLCHAIN_PREFIX)strip --strip-all -x $1-fvisibility=hidden

cmd-strip 是对编译符号进行过滤的脚本,-fvisibility=hidden 是隐藏jni库内部符号表

D:\android-ndk-r7c\toolchains\arm-linux-androideabi-4.4.3\prebuilt\windows\bin

下面的objdump工具,生成so包的汇编。
生成so包汇编代码的命令:arm-linux-androideabi-objdump.exe -dx libmapengine.so > temp.txt


3. 定位问题位置

如果幸运的话可以,logcat输出可以直接定位在函数,接下来要做的就是定位在错误的代码行数,注意指的是C/C++代码行 而不是汇编。

结合so的汇编和logcat输出,函数代码较短的话可以直接阅读arm汇编,函数长的话直接看汇编会很痛苦。


4. arm assemble的一些基本指令

ldr 从指定地址加载寄存器运算数,
str 将寄存器运算数存到指定地址,
add两个寄存器相加,
adds寄存器和数值相加,
mov寄存器之间赋值,
movs将数值赋给寄存器,
cmp为比较两个寄存器
比较条件判断:

b 表示无条件分支:http://sourceware.org/cgen/gen-doc/arm-thumb-insn.html#insn-b
bx lr 表示一个函数执行结束,参见【3】


5. 示例

C/C++ 源码如下:

void TextureCache::_touchListNode(TextureCacheItem* node){if (node==NULL) {return;}// 将*item移至队尾if(tail != node){// 将node结点单独取出if(head == node){head = head->next;head->pre = NULL;} else{// node != head && node != tailnode->pre->next = node->next;node->next->pre = node->pre;// ###node->next为空,寻址pre导致CRASH###}tail->next = node;node->pre = tail;tail = node;tail->next = NULL;}}
汇编代码一共28行:

00033fc0 <_ZN12TextureCache14_touchListNodeEP16TextureCacheItem>:   33fc0:2900      cmpr1, #0   33fc2:d012      beq.n33fea <_ZN12TextureCache14_touchListNodeEP16TextureCacheItem+0x2a>   33fc4:68c3      ldrr3, [r0, #12]   33fc6:428b      cmpr3, r1   33fc8:d00f      beq.n33fea <_ZN12TextureCache14_touchListNodeEP16TextureCacheItem+0x2a>   33fca:6883      ldrr3, [r0, #8]   33fcc:428b      cmpr3, r1   33fce:d00d      beq.n33fec <_ZN12TextureCache14_touchListNodeEP16TextureCacheItem+0x2c>   33fd0:694b      ldrr3, [r1, #20]   33fd2:698a      ldrr2, [r1, #24]   33fd4:619a      strr2, [r3, #24]   33fd6:698b      ldrr3, [r1, #24]   33fd8:694a      ldrr2, [r1, #20]   33fda:615a      strr2, [r3, #20]   33fdc:68c3      ldrr3, [r0, #12]   33fde:6199      strr1, [r3, #24]   33fe0:68c3      ldrr3, [r0, #12]   33fe2:614b      strr3, [r1, #20]   33fe4:2300      movsr3, #0   33fe6:60c1      strr1, [r0, #12]   33fe8:618b      strr3, [r1, #24]   33fea:4770      bxlr   33fec:698b      ldrr3, [r1, #24]   33fee:2200      movsr2, #0   33ff0:6083      strr3, [r0, #8]   33ff2:615a      strr2, [r3, #20]   33ff4:e7f2      b.n33fdc <_ZN12TextureCache14_touchListNodeEP16TextureCacheItem+0x1c>   33ff6:46c0      nop(mov r8, r8)

分析:

touchListNode函数将双向链表中的node结点移至队列尾部。r0寄存器存放整个当前对象地址,r0 + 8 为head,r0 + 12为tailr1存到函数参数node指针指针即地址,即寄存器中的值00033fc0 <_ZN12TextureCache14_touchListNodeEP16TextureCacheItem>:   33fc0:2900      cmpr1, #0   33fc2:d012      beq.n33fea <_ZN12TextureCache14_touchListNodeEP16TextureCacheItem+0x2a>第一次比较node是否为NULL,相等则直接跳至33fea行退出函数   33fc4:68c3      ldrr3, [r0, #12]// 通过r0寄存器取tail指针   33fc6:428b      cmpr3, r1// 比较tail和node指针   33fc8:d00f      beq.n33fea <_ZN12TextureCache14_touchListNodeEP16TextureCacheItem+0x2a>第二次比较tail是否等于node,相等则直接跳至33fea行退出函数   33fca:6883      ldrr3, [r0, #8]// 通过r0寄存器取head指针   33fcc:428b      cmpr3, r1// 比较head和node指针   33fce:d00d      beq.n33fec <_ZN12TextureCache14_touchListNodeEP16TextureCacheItem+0x2c>// head!=node直接跳到33fec行第三次比较head是否等于node,相等则直接跳至33fea行退出函数   33fd0:694b      ldrr3, [r1, #20]// r3 = r1::_pre 取node的pre指针赋给r3   33fd2:698a      ldrr2, [r1, #24]// r2 = r1::_next 取node的next指针赋给r2   33fd4:619a      strr2, [r3, #24]// r3::_next = r2node->pre->next = node->next   33fd6:698b      ldrr3, [r1, #24]// r3 = r1::_next;   33fd8:694a      ldrr2, [r1, #20]// r2 = r1::_pre;   33fda:615a      strr2, [r3, #20]// r3::_pre = r2;node->next->pre = node->pre      33fdc:68c3      ldrr3, [r0, #12]// r3 = tail;取链表的tail赋给r3   33fde:6199      strr1, [r3, #24]// r3::_next = r1tail->next = node   33fe0:68c3      ldrr3, [r0, #12]// r3 = tail;取链表的tail赋给r3   33fe2:614b      strr3, [r1, #20]// r1::_pre = r3;node->pre = tail   33fe4:2300      movsr3, #0// reset r3 register 清零r3寄存器   33fe6:60c1      strr1, [r0, #12]// tail = node;将r1(node)赋给r0+12即tail   33fe8:618b      strr3, [r1, #24]// r1::_next = r3;将r3赋给r1的next指针,此时r3等于0   33fea:4770      bxlr// 子函数 执行结束!      33fec:698b      ldrr3, [r1, #24]// r3 = r1::_next;   33fee:2200      movsr2, #0// reset r2 register   33ff0:6083      strr3, [r0, #8]// r0::_head = r3;   33ff2:615a      strr2, [r3, #20]// r3::_pre = r2;## r2==0 ##   33ff4:e7f2      b.n33fdc <_ZN12TextureCache14_touchListNodeEP16TextureCacheItem+0x1c>无条件跳转到33fdc行执行   33ff6:46c0      nop(mov r8, r8)

结合第一部分crash时堆栈顶部信息:#00 pc 00033fda ,对应汇编代码中的33fda行,通过阅读汇编代码可以知道33fda行对应C/C++源码:
node->next->pre = node->pre;

Crash原因是因为[r3, #20]寻址错误 即node->next为空并且执行node->next->pre。


6. 参考:

1.http://sourceware.org/cgen/gen-doc/arm-thumb-insn.html

2.http://www.peter-cockerell.net/aalp/html/ch-3.html

3.http://hi.baidu.com/wuqi19881003/item/f293c7a7e228e613a8cfb756


更多相关文章

  1. Android游戏框架AndEngine使用入门
  2. Android将InputStream转换为String和byte[]
  3. Android下AlarmManager完整调用流程
  4. Android(安卓)Audio代码分析20 - queryEffects函数
  5. [Android] Smali基本语法
  6. Rokon引擎主要类介绍
  7. Android(安卓)Activity返回结果startActivityForResult函数
  8. untiy实现手机摇一摇震动效果
  9. NDK开发之Android(安卓)Studio生成.h头文件的方法

随机推荐

  1. Android(安卓)WebView总结
  2. android AlarmManager
  3. Android应用程序组件Content Provider的
  4. android shape
  5. android adb am命令
  6. Android定制出厂默认输入法
  7. Android(安卓)Non-UI to UI Thread Commu
  8. Android(安卓)让你的 EditText 只接受指
  9. android书籍
  10. android之实现各个组件点击事件监听