Native Crash .so crash分析方法

Native Crash是指,在用户空间的C/C++代码发生的abort、段错误、指令异常等crash问题。如果Native Crash发生在应用APK,则导致应用异常崩溃闪退,如果发生在系统关键进程则导致Android 系统重启。

Native crash问题相对比java crash问题更难分析和定位。Native Crash问题的分析主要依赖Android tombstone 和corefile 等日志信息

Native Crash问题分类

根据产生native crash的信号分类,常见native crash可分为以下几类:

 

信号类型

说明

产生原因

SIGSEGV (signal 11)

段错误,非法内存访问

越界访问、写只读的内存块、野指针、double free、空指针

SIGABRT (signal 6)

主动终止程序运行,通常是检查失败后主动的退出执行的程序

程序主动判断

SIGBUS (signal 7)

非法地址, 包括内存地址对齐(alignment)出错

内存未对齐

SIGILL (signal 4)

指令异常

ddr/cache不一致或指令兼容性问题

SIGFPE (signal 8)

算术运算错误(除0错误)

除0操作

SIGTRAP (signal 5)

断点指令或其它trap指令产生,用于debuger

通常是gdb在线调试时产生。部分app使用brk 指令产生。

Native Crash分析方法

Native Crash的分析依赖Android tombstone 和corefile 日志。

对于Userdebug版本,发生native crash时会生成tombstone和corefile。分别在/data/tombstones/和/data/corefile/目录。而如果是user版本仅生成tombstone,不会生成corefile日志。

分析tombstone和corefile都需要有发生问题对应版本的symbols。Android项目工程在编译过程中产生的symbols存放在:out/target/product/sc***/symbols目录。

在分析tombstone和corefile时会用到以下命令行工具(注意:32位和64位使用的工具是不一样的):

Log 文件

工具名

常用命令参数

tombstone

arm-linux-eabi-add2line

aarch64-linux-android-add2line

arm-linux-eabi-objdump

aarch64-linux-android-objdump

arm-linux-androideabi-add2line–f –e /symbols/system/lib/libc.so

arm-linux-androideabi-objdump

-D  /symbols/system/lib/libc.so

corefile

arm-linux-eabi-gdb

aarch64-linux-android-gdb

见gdb常用命令及coredump案例分析

上述工具在工程目录:

32位工具:prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin

64位工具:prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin

得到symbol库的位置解析:arm-linux-androideabi-addr2line -C -f -e symbols/system/lib/libcampm.so 00011248

实例讲解,最近出我分析的一个列子,现了一个客户的crash,具体log如下:

signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xac0bf77a

    r0  ab68fff0  r1  ab57f6ac  r2  ab8e55ec  r3  ac0bf74a

    r4  00000000  r5  00004028  r6  ab8e5010  r7  ab8e5610

    r8  ab8e5010  r9  00000025  r10 ab86e95c  r11 ab8e5000

    ip  adb571bc  sp  abe08cd0  lr  adb4aa95  pc  adb51248

 

backtrace:

      #00 pc 00011248  /vendor/lib/libcampm.so (_pm_saturation_init+20) (BuildId: 0d7cf1bba471f9510a6aba0c2d2783c7)

      #01 pc 0000aa93  /vendor/lib/libcampm.so (isp_pm_set_mode+430) (BuildId: 0d7cf1bba471f9510a6aba0c2d2783c7)

      #02 pc 0000981b  /vendor/lib/libcampm.so (isp_pm_param_init_and_update+2422) (BuildId: 0d7cf1bba471f9510a6aba0c2d2783c7)

      #03 pc 00008ddd  /vendor/lib/libcampm.so (isp_pm_init+144) (BuildId: 0d7cf1bba471f9510a6aba0c2d2783c7)

      #04 pc 0001d75b  /vendor/lib/libcamdrv.so (isp_alg_fw_init+226) (BuildId: 106305b58b0c45e9b423271baa7b2d6f)

      #05 pc 000261e5  /vendor/lib/libcamdrv.so (isp_init+108) (BuildId: 106305b58b0c45e9b423271baa7b2d6f)

      #06 pc 0002e283  /vendor/lib/libcamoem.so (camera_local_int+2766) (BuildId: 25597d5ee348da4a9a05d6e431616398)

      #07 pc 0002505b  /vendor/lib/libcamoem.so (camera_init+70) (BuildId: 25597d5ee348da4a9a05d6e431616398)

首先signal 11肯定是内存相关的错误,然后通过命令解析

./arm-linux-androideabi-objdump -S libcampm.so > libcampm.txt

00011234 <_pm_saturation_init@@Base>:

   11234:      b570          push  {r4, r5, r6, lr}

   11236:      b086          sub    sp, #24

   11238:      6993          ldr      r3, [r2, #24]

   1123a:      2400          movs  r4, #0

   1123c:      6003          str      r3, [r0, #0]

   1123e:      6e0b          ldr      r3, [r1, #96]   ; 0x60

   11240:      5ccb          ldrb    r3, [r1, r3]

   11242:      6043          str      r3, [r0, #4]

   11244:      6e4b          ldr      r3, [r1, #100] ; 0x64

   11246:      440b          add    r3, r1

   11248:      f893 3030     ldrb.w r3, [r3, #48]   ; 0x30

   1124c:      6083          str      r3, [r0, #8]

   1124e:      6e0b          ldr      r3, [r1, #96]   ; 0x60

   11250:      60c3          str      r3, [r0, #12]

   11252:      6e4b          ldr      r3, [r1, #100] ; 0x64

   11254:      6103          str      r3, [r0, #16]

   11256:      f811 c004     ldrb.w ip, [r1, r4]

   1125a:      eb00 0e04    add.w lr, r0, r4

   1125e:      190b          adds  r3, r1, r4

   11260:      f88e c014     strb.w ip, [lr, #20]

   11264:      3401          adds  r4, #1

   11266:      f893 3030     ldrb.w r3, [r3, #48]   ; 0x30

   1126a:      2c30          cmp   r4, #48         ; 0x30

   1126c:      f88e 3044     strb.w r3, [lr, #68]    ; 0x44

   11270:      d1f1          bne.n 11256 <_pm_saturation_init@@Base+0x22>

然后,很可惜,使用aarch64-linux-android-addr2line解析地址C语言出不来,那没办法只能分析

汇编语句,_pm_saturation_init+20的地址应该为0x11234+0x14,这样出问题的地方应该在

11248:  f893 3030 ldrb.w   r3, [r3, #48]       ; 0x30,而这句的对应该的代码应该通过函数分析

cmr_s32 _pm_saturation_init(void *dst_csa_param, void *src_csa_param, void *param1, void *param_ptr2)

{

         cmr_s32 rtn = ISP_SUCCESS;

         cmr_u32 i = 0, j = 0;

         struct isp_chrom_saturation_param *dst_csa_ptr = (struct isp_chrom_saturation_param *)dst_csa_param;

         struct sensor_saturation_param *src_csa_ptr = (struct sensor_saturation_param *)src_csa_param;

         struct isp_pm_block_header *csa_header_ptr = (struct isp_pm_block_header *)param1;

         UNUSED(param_ptr2);

 

         dst_csa_ptr->cur.bypass = csa_header_ptr->bypass;

         dst_csa_ptr->cur.factor_u = src_csa_ptr->csa_factor_u[src_csa_ptr->index_u];

         dst_csa_ptr->cur.factor_v = src_csa_ptr->csa_factor_v[src_csa_ptr->index_v];

         dst_csa_ptr->cur_u_idx = src_csa_ptr->index_u;

         dst_csa_ptr->cur_v_idx = src_csa_ptr->index_v;

         for (i = 0; i < SENSOR_LEVEL_NUM; i++) {

                   dst_csa_ptr->tab[0][i] = src_csa_ptr->csa_factor_u[i];

                   dst_csa_ptr->tab[1][i] = src_csa_ptr->csa_factor_v[i];

         }

         for (i = 0; i < MAX_SCENEMODE_NUM; i++) {

                   dst_csa_ptr->scene_mode_tab[0][i] = src_csa_ptr->scenemode[0][i];

                   dst_csa_ptr->scene_mode_tab[1][i] = src_csa_ptr->scenemode[1][i];

         }

 

         csa_header_ptr->is_update = ISP_ONE;

 

         return rtn;

}

开始分析汇编和C语言对应起来,首先,有两个for循环,那肯定有调整指令,

   1125a:    eb00 0e04        add.w   lr, r0, r4,///显然这个是第一个跳转指令,

那这个问题发生在第一个for循环之前,然后函数前面都是赋值,汇编没有操作,那这个

   11238:    6993        ldr  r3, [r2, #24]对于的C语言语句为csa_header_ptr->bypass;

1123c:  6003        str  r3, [r0, #0] 对于的C语言语句为dst_csa_ptr->cur.bypass =

1123e:  6e0b      ldr  r3, [r1, #96]       ; 0x60对于的C语言语句为src_csa_ptr->index_u

11240:  5ccb        ldrb       r3, [r1, r3] 对于的C语言语句为src_csa_ptr->csa_factor_u[src_csa_ptr->index_u];

11242:  6043        str  r3, [r0, #4] 对于的C语言语句为dst_csa_ptr->cur.factor_u

11244:  6e4b      ldr  r3, [r1, #100]     ; 0x64对于的C语言语句为src_csa_ptr->index_v

11246:  440b      add       r3, r1对于的C语言语句为src_csa_ptr->csa_factor_v[src_csa_ptr->index_v];

11248:  f893 3030 ldrb.w   r3, [r3, #48]       ; 0x30这行语句显然就挂了,也就是r3再偏移48存在地址越界。

所以其实在11244:   6e4b      ldr  r3, [r1, #100]     ; 0x64对于的C语言语句为src_csa_ptr->index_v这里就已经是野指针了。所以最后通过代码发现是参数的数据太少了数据导致crash.

你可能感兴趣的:(android,android-jni,android-camera)