堆栈错误信息:

I/DEBUG   (   30): r0 afd4d4a4  r1 ffffffff  r2 7fffffff r3 afd4d4a4
 I/DEBUG   (   30): r4 00000000  r5 ffffffff  r6 00000001 r7 be9f6ccc
 I/DEBUG   (   30): r8 00000000  r9 00000000  10 00000000 fp 00000000
 I/DEBUG   (   30): ip afd11fcd  sp be9f6c38  lr afd107f4 pc afd107fc  cpsr 80000010
 I/DEBUG   (   30):         #00  pc 000107fc  /system/lib/libc.so
 I/DEBUG   (   30):         #01  pc 0001ccfe  /system/lib/libdtvservice.so
 I/DEBUG   (   30):         #02  pc 0001c646  /system/lib/libdtvservice.so
 I/DEBUG   (   30):         #03  pc 0001937e  /system/lib/libdtvservice.so
 I/DEBUG   (   30):         #04  pc 000110f8  /system/lib/libdtvservice.so
 I/DEBUG   (   30):         #05  pc 000115a8 /system/lib/libdtvservice.so
 I/DEBUG   (   30):         #06  pc 00008852  /system/bin/dtvserver
 I/DEBUG   (   30):         #07  pc 00014dc8  /system/lib/libc.so

 

……

方法一:

1.将上面这段信息复制到一个新建的文件中,并保存。例如:test-dtvserver.txt.

 

2.用panic.py工具解析这段错误信息,panic.py工具的位置为~/android/

// 工具在附件中

运行:

[maw@localhost android]$ panic.py  test-stack.txt
 read file ok
 stop search
 pr-support.c:258              __gnu_unwind_execute
 posix_thread.c:97             destroy_posix_thread
 thread.c:293                  thread_destroy
 workpool.c:215                work_pool_uninitialize
 dtvserver.c:203               dtvs_finalize
 dtvserver.c:179               dtvs_initialize
 DtvServer.cpp:19              main
 dlmalloc.c:3890               tmalloc_small

 

这个就是结果。

 

使用panic.py的环境问题

 

1.要有arm-eabi-addr2line工具   ~/android/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/

2.在system/lib/中要有相应的库文件

3.panic.py的存放位置要正确~/android/,也可以自己修改panic.py工具的代码,放在其他地方.

 

 

方法二:

如果没有arm-eabi-addr2line工具,但是有arm-eabi-objdump工具

就用第二种方法。

I/DEBUG   (   30):         #00  pc 000107fc  /system/lib/libc.so
 I/DEBUG   (   30):         #01  pc 0001ccfe  /system/lib/libdtvservice.so
 I/DEBUG   (   30):         #02  pc 0001c646  /system/lib/libdtvservice.so
 I/DEBUG   (   30):         #03  pc 0001937e  /system/lib/libdtvservice.so
 I/DEBUG   (   30):         #04  pc 000110f8  /system/lib/libdtvservice.so
 I/DEBUG   (   30):         #05  pc 000115a8  /system/lib/libdtvservice.so
 I/DEBUG   (   30):         #06  pc 00008852  /system/bin/dtvserver
 I/DEBUG   (   30):         #07  pc 00014dc8  /system/lib/libc.so

 

1.用objdump工具将上面这些对应的库文件反汇编:

运行:arm-eabi-objdump –dS libc.so > libc.dump

//这些库文件路径在out/target/product/generic/obj/SHARED_LIBRARIES/ 

 

2.打开反汇编后的库文件。例如:libc.dump。

找到上面错误码提示的地址。例如000107fc。

在这里我们可以找到这行指令所在的函数和文件

以此类推,依次找出这些错误码对应的函数和文件,就可以知道是哪一个函数调用路线出问题了。

 

panic.py代码

#!/usr/bin/python
 # stack symbol parser
  
 import os
 import string
 import sys
  
 #define android product name 这个视情况而定在out/target/product文件夹下
 ANDROID_PRODUCT_NAME = 'generic'
 #ANDROID_PRODUCT_NAME = 'smdk6410'
  
 #这里可以修改panic.py工具的存放位置
 ANDROID_WORKSPACE = os.getcwd()+"/"
  
 # addr2line tool path and symbol path
 addr2line_tool = ANDROID_WORKSPACE +'prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-addr2line'
 symbol_dir = ANDROID_WORKSPACE + 'out/target/product/'+ ANDROID_PRODUCT_NAME +'/symbols'
 symbol_bin = symbol_dir + '/system/bin/'
 symbol_lib = symbol_dir + '/system/lib/'
  
 class ReadLog:
     def__init__(self,filename):
        self.logname = filename
     defparse(self):
         f =file(self.logname,'r')
         lines =f.readlines()
         if lines!= []:
            print 'read file ok'
         else:
            print 'read file failed'
         result=[]
         for linein lines:
             ifline.find('stack') != -1:
                print 'stop search'
                 break
             elifline.find('system') != -1:
                #print 'find one item' + line
                result.append(line)
         returnresult
  
 class ParseContent:
     def__init__(self,addr,lib):
            self.address = addr # pc address
            self.exename = lib  # executableor shared library
     defaddr2line(self):
         cmd =addr2line_tool + " -C -f -s -e " + symbol_dir + self.exename + "" + self.address
         #printcmd
         stream =os.popen(cmd)
         lines =stream.readlines();
         list =map(string.strip,lines)
         returnlist
  
 inputarg = sys.argv
 if len(inputarg) < 2:
     print'Please input panic log'
     exit()
  
 filename = inputarg[1]
 readlog = ReadLog(filename)
 inputlist = readlog.parse()
  
 for item in inputlist:
     itemsplit =item.split()
     test =ParseContent(itemsplit[-2],itemsplit[-1])
     list =test.addr2line()
     print"%-30s%s" % (list[1],list[0])
 
 #usage panic.py crash Log > result.txt

如果提示 /usr/bin/python ^M:损坏的解释器:没有该文件或者目录的话,执行一下:dos2unix panic.py 转换一下格式即可。

反汇编pc指针附近代码

有时我们在log中看不到这样明显的调用栈信息,比如出现了dalvik-jit-code-cache,如下:


10-15 01:32:56.759 I/DEBUG   (   93):          #00  pc 47aac03c  /dev/ashmem/dalvik-jit-code-cache (deleted) 10-15 01:32:56.769 I/DEBUG   (   93):          #01  lr 47ab7817  /dev/ashmem/dalvik-jit-code-cache (deleted)


这样,就没有办法用前面的方法来分析调用栈了。还好google提供了另一个方法来分析问题。虽然有点麻烦。

它的原理,就是将pc附件的指令放到某个程序的内存中,然后进行gdb调试来进行反汇编。

要使用gdbjithelper(位于dalvik/tools/gdbjithelper)将pr和lr附近的cache code反汇编。下面来介绍一下。

首先,打开gdbjithelper.c,可以看到如下代码


int codePC[] = {     
 
// Sample content     
 
0x4300e119, 0x4284aa7a, 0xf927f7b7, 0x40112268,     0x419da7f8, 0x00002000, 0x01000100, 0x00080000,     0x4191debc, 0x01010000, 0x4284aa74, 0x68b00054,     0x045cf205, 0xcc016468, 0x0718f2a5, 0xd0102800,     0x4c13c701, 0xa20aa108, 0xefb0f775, 0xe008e010, };


将log信息中对应部分


10-15 01:32:56.769 I/DEBUG ( 93): code around pc: 


10-15 01:32:56.769 I/DEBUG   (   93): 47aac01c  e12fff1e e3a00001 e12fff1e e2450014


10-15 01:32:56.769 I/DEBUG ( 93): 47aac02c e590a000 e5968024 e5904004 e5909010 


10-15 01:32:56.769 I/DEBUG ( 93): 47aac03c e51a200c e5963018 e3520000 0a00000e 


10-15 01:32:56.769 I/DEBUG ( 93): 47aac04c e59f1738 e1a0500a 1592a000 e5988000 


10-15 01:32:56.769 I/DEBUG ( 93): 47aac05c e5862010 e59a0028 e5835028 e2844006


编辑为类似代码,替换掉,然后修改


#define START_PC_PAGE_OFFSET 0x1e4


改为


#define START_PC_PAGE_OFFSET 0x01c


修改的原理是code around pc的开始地址(0x47aac01c & 0xfff)

同理,修改codeLR和START_LR_PAGE_OFFSET

修改完成后,使用模块编译 mmm dalvik/tools/gdbjithelper,将编译好的gdbjithelper push到一台手机上/system/bin 进行调试。

连接设备后,执行步骤如下:


shell> adb shell gdbserver :5039 /path/to/gdbjithelper #设备路径 
 
shell> adb forward tcp:5039 tcp:5039 
 
shell> cd ${环境根目录}/ 
 
shell> prebuilt/Linux/toolchain-eabi-4.2.1/bin/arm-eabi-gdb /path/to/gdbjithelper #PC路径 
 
(gdb) set solib-absolute-prefix out/target/product/${product-name}/symbols     #告诉gdb查找共享库符号等路径 
 
(gdb) set solib-search-path out/target/product/${product-name}/symbols/system/lib #告诉gdb查找共享库符号等路径 (gdb) target remote :5039 
 
(gdb) run 会出现类似下面的输出信息: 0xb01c codePC[0]: 0xe12fff1e 0xb020 codePC[1]: 0xe3a00001 0xb024 codePC[2]: 0xe12fff1e 0xb028 codePC[3]: 0xe2450014 0xb02c codePC[4]: 0xe590a000 0xb030 codePC[5]: 0xe5968024 0xb034 codePC[6]: 0xe5904004 0xb038 codePC[7]: 0xe5909010 0xb03c codePC[8]: 0xe51a200c 0xb040 codePC[9]: 0xe5963018 0xb044 codePC[10]: 0xe3520000 0xb048 codePC[11]: 0x0a00000e 0xb04c codePC[12]: 0xe59f1738 0xb050 codePC[13]: 0xe1a0500a 0xb054 codePC[14]: 0x1592a000 0xb058 codePC[15]: 0xe5988000  0xb05c codePC[16]: 0xe5862010 0xb060 codePC[17]: 0xe59a0028 0xb064 codePC[18]: 0xe5835028 0xb068 codePC[19]: 0xe2844006 
 
(gdb) x /20i 0xb01c+1 //输出反汇编结果 x/20i (char *)&CodePC+1 ,查看LR 结果 x/20i (char*)&codeLR+1
 
0xb01d:        vrhadd.u16        d14, d14, d31 
 
0xb021:        lsls        r1, r0, #0 
 
0xb023:        b.n        0xb766 
 
0xb025:        vrhadd.u16        d14, d14, d31 
 
0xb029:        lsls        r4, r2, #0 
 
0xb02b:        b.n        0xb4b8 
 
0xb02d:        add        r0, pc, #0        (adr r0,0xb030) 
 
0xb02f:        b.n        0xab52 
 
0xb031:        strh        r4, [r4, #0] 
 
0xb033:        b.n        0xab62 
 
0xb035:        ands        r4, r0 
 
0xb037:        b.n        0xab5a 
 
0xb039:        str        r0, [sp, #64] 
 
0xb03b:        b.n        0xab5e            //pc指向,实际跳转地址为0x47aabb5e (0x47aac03c-0xb03c+0xab5e) 0xb03d:        movs        r0, #12 
 
0xb03f:        b.n        0xaa76 
 
0xb041:        adds        r0, #24 
 
0xb043:        b.n        0xab72 
 
0xb045:        lsls        r0, r0, #0 
 
0xb047:        b.n        0xb6ee


类似,codeLR也是这样反汇编的 之后就可以对结果进行分析了。