分享

Android 调试中 addr2line 工具的使用

 tracyf 2015-05-25

我们在解bug的时候经常能碰到一些段错误。下面是我从一个buglog中截取的一个段错误:

  1. //////////////////////////////////////////////////////////////////////////////////////////////////////  
  2. 08-19 19:08:27.132  2105  2105 I DEBUG   : pid: 134, tid: 2104, name: OMXCallbackDisp  >>> /system/bin/mediaserver <<<  
  3. 08-19 19:08:27.132  2105  2105 I DEBUG   : signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 44c86948  
  4. 08-19 19:08:27.280  1803  1803 I SurfaceTextureClient: [STC::queueBuffer] (this:0x6162c9f8) fps:21.68, dur:1014.76, max:104.52, min:10.36  
  5. 08-19 19:08:27.281   130  1018 I BufferQueue: [com.android.gallery3d/com.android.camera.Camera](this:0x41c1f008,api:1) [queue] fps:21.70, dur:1013.89, max:103.33, min:10.27  
  6. 08-19 19:08:27.293   130   321 I SurfaceTextureClient: [STC::queueBuffer] (this:0x406df2e0) fps:34.70, dur:1037.44, max:75.25, min:14.19  
  7. 08-19 19:08:27.294   130   321 I BufferQueue: [FramebufferSurface](this:0x406de810,api:1) [release] fps:34.70, dur:1037.44, max:75.23, min:14.19  
  8. 08-19 19:08:27.294   130   321 I BufferQueue: [FramebufferSurface](this:0x406de810,api:1) [queue] fps:34.70, dur:1037.43, max:75.23, min:14.19  
  9. 08-19 19:08:27.294   130   321 I SurfaceFlinger: [SurfaceFlinger] fps:34.701393,dur:1037.42,max:75.22,min:14.19  
  10. 08-19 19:08:27.452   465   538 D MDLOGGER: pMDEngine->m_bTerminate is false.  busy for modem = 0,m_nM2ABufCnt = 8  
  11. 08-19 19:08:27.452   465   538 D MDLOGGER: thrDetectFilter: Detecting catcher_filter.bin exist or not every 5 seconds!  
  12. 08-19 19:08:27.462  2105  2105 I DEBUG   :     r0 00000000  r1 00000081  r2 00000001  r3 ffffffe8  
  13. 08-19 19:08:27.462  2105  2105 I DEBUG   :     r4 46d4de60  r5 42671490  r6 40185d35  r7 00100000  
  14. 08-19 19:08:27.462  2105  2105 I DEBUG   :     r8 45661240  r9 00000000  sl 40dd0159  fp 46c4d930  
  15. 08-19 19:08:27.462  2105  2105 I DEBUG   :     ip ffffffea  sp 46d4de38  lr 4009915c  pc 44c86948  cpsr 60000010  
  16. 08-19 19:08:27.462  2105  2105 I DEBUG   :   
  17. 08-19 19:08:27.462  2105  2105 I DEBUG   : backtrace:  
  18. 08-19 19:08:27.462  2105  2105 I DEBUG   :     #00  pc 00042948  <unknown>  
  19. 08-19 19:08:27.462  2105  2105 I DEBUG   :     #01  pc 0000d158  /system/lib/libc.so  
  20. 08-19 19:08:27.462  2105  2105 I DEBUG   :     #02  pc 00032954  <unknown>  
  21. 08-19 19:08:27.462  2105  2105 I DEBUG   :   
  22. 08-19 19:08:27.462  2105  2105 I DEBUG   : stack:  
  23. 08-19 19:08:27.462  2105  2105 I DEBUG   :          46d4ddf8  00000000    
  24. 08-19 19:08:27.462  2105  2105 I DEBUG   :          46d4ddfc  00000020    
  25. 08-19 19:08:27.462  2105  2105 I DEBUG   :          46d4de00  00000000    
  26. 08-19 19:08:27.462  2105  2105 I DEBUG   :          46d4de04  00000000    
  27. 08-19 19:08:27.462  2105  2105 I DEBUG   :          46d4de08  00000000    
  28. 08-19 19:08:27.462  2105  2105 I DEBUG   :          46d4de0c  46d4de34  [stack:2104]  
  29. 08-19 19:08:27.462  2105  2105 I DEBUG   :          46d4de10  44c86a04    
  30. 08-19 19:08:27.462  2105  2105 I DEBUG   :          46d4de14  46d4de60  [stack:2104]  
  31. 08-19 19:08:27.462  2105  2105 I DEBUG   :          46d4de18  42671490    
  32. 08-19 19:08:27.462  2105  2105 I DEBUG   :          46d4de1c  40185d35  /system/lib/libutils.so  
  33. 08-19 19:08:27.462  2105  2105 I DEBUG   :          46d4de20  00100000    
  34. 08-19 19:08:27.462  2105  2105 I DEBUG   :          46d4de24  45661240    
  35. 08-19 19:08:27.462  2105  2105 I DEBUG   :          46d4de28  00000000    
  36. 08-19 19:08:27.462  2105  2105 I DEBUG   :          46d4de2c  40dd0159  /system/lib/libstagefright.so  
  37. 08-19 19:08:27.462  2105  2105 I DEBUG   :          46d4de30  df0027ad    
  38. 08-19 19:08:27.462  2105  2105 I DEBUG   :          46d4de34  00000000    
  39. 08-19 19:08:27.462  2105  2105 I DEBUG   :     #00  46d4de38  46d4de60  [stack:2104]  
  40. 08-19 19:08:27.463  2105  2105 I DEBUG   :          ........  ........  
  41. 08-19 19:08:27.463  2105  2105 I DEBUG   :     #01  46d4de38  46d4de60  [stack:2104]  
  42. 08-19 19:08:27.463  2105  2105 I DEBUG   :          46d4de3c  46c4d958    
  43. 08-19 19:08:27.463  2105  2105 I DEBUG   :     #02  46d4de40  46d4de80  [stack:2104]  
  44. 08-19 19:08:27.463  2105  2105 I DEBUG   :          46d4de44  40f01d33  /system/lib/libstagefright_omx.so (android::OMXNodeInstance::onMessage(android::omx_message const&)+50)  
  45. 08-19 19:08:27.463  2105  2105 I DEBUG   :          46d4de48  46c4db48    
  46. 08-19 19:08:27.463  2105  2105 I DEBUG   :          46d4de4c  46c4db5c    
  47. 08-19 19:08:27.463  2105  2105 I DEBUG   :          46d4de50  46d4de80  [stack:2104]  
  48. 08-19 19:08:27.463  2105  2105 I DEBUG   :          46d4de54  40f00347  /system/lib/libstagefright_omx.so (android::OMX::CallbackDispatcher::loop()+110)  
  49. 08-19 19:08:27.463  2105  2105 I DEBUG   :          46d4de58  00000000    
  50. 08-19 19:08:27.463  2105  2105 I DEBUG   :          46d4de5c  46c4db50    
  51. 08-19 19:08:27.463  2105  2105 I DEBUG   :          46d4de60  00000000    
  52. 08-19 19:08:27.463  2105  2105 I DEBUG   :          46d4de64  00000019    
  53. 08-19 19:08:27.463  2105  2105 I DEBUG   :          46d4de68  00000000    
  54. 08-19 19:08:27.463  2105  2105 I DEBUG   :          46d4de6c  00000000    
  55. 08-19 19:08:27.463  2105  2105 I DEBUG   :          46d4de70  00000002    
  56. 08-19 19:08:27.463  2105  2105 I DEBUG   :          46d4de74  45def1ac  /system/lib/libMtkOmxVdec.so  
  57. 08-19 19:08:27.463  2105  2105 I DEBUG   :          46d4de78  44c89f38    
  58. 08-19 19:08:27.463  2105  2105 I DEBUG   :          46d4de7c  45dedea1  /system/lib/libMtkOmxVdec.so (MtkOmxVdec::DeInitVideoDecodeHW()+84)  
  59. //////////////////////////////////////////////////////////////////////////////////////////////////////  

有没有看起来很眼熟?

关于段错误的定义,我百科了一下:

所谓的段错误就是指访问的内存超出了系统所给这个程序的内存空间,通常这个值是由gd tr来保存的,他是一个48位的寄存器,其中的32位是保存由它指向的 gdt表,后13位保存相应于gdt的下标,最后3位包括了程序是否在内存中以及程序的在cpu中的运行级别,指向 的gdt是由以64位为一个单位的表,在这张表中就保存着程序运行的代码段以及数据段的起始地址以及与此相应的段限和页面交换还有程序运行级别还有内存粒度等等的信息。【不甚理解】

在 Android 的工程当中,有一部分文件会被编译成 so 动态共享库供系统运行时不同模块链接使用。若调用出错的话,会报出如上面文本中贴出来的段错误。

出了这种错误,我们一般都会通过 add2line 工具解析具体出错代码的位置,能精确到哪个文件,哪一行!再去具体位置的代码查看。

若你去找这个文件的时候却发现没有,不必要大惊小怪,MTK没有提供。在MTK 提供的 Android 的工程代码中,经常会出于一些保密方面的考虑,将一些核心文件编译成 so 库提供给客户。让客户看不到这一部分的代码,但是能够正常使用。诸如此类问题,可以提给MTK客服让其帮忙追查Bug!

1,在MTK的工程中,我们是这样来解析段错误的:

我们将 backtrace 以下的段错误 copy 到 trace.txt中。(trace.txt放到工程根目录下)

然后在linux 环境下面,进到工程根目录,执行如下命令:

./adbs -sout/target/product/bbk82_wet_jb5/symbols/ -l trace.txt>a.txt

将会解析得到 a.txt 文件,该文件中就能追溯到具体哪一个文件哪一行出错了。

trace.txt内容:

  1. 08-19 19:08:27.462  2105  2105 I DEBUG   : backtrace:  
  2. 08-19 19:08:27.462  2105  2105 I DEBUG   :     #00  pc 00042948  <unknown>  
  3. 08-19 19:08:27.462  2105  2105 I DEBUG   :     #01  pc 0000d158  /system/lib/libc.so  
  4. 08-19 19:08:27.462  2105  2105 I DEBUG   :     #02  pc 00032954  <unknown>  

adbs 是一个脚本文件,它的作用是调用 arm-linux-androideabi-addr2line这个工具来解析 trace.txt 中的内容,并将解析的结果存到一个具体的文件中去,譬如 a.txt

-s 和 -l 是参数

解析出来的结果 a.txt内容:

  1. 08-19 19:08:27.462  2105  2105 I DEBUG   : backtrace:  
  2.   
  3. 08-19 19:08:27.462  2105  2105 I DEBUG   : backtrace:  
  4. 08-19 19:08:27.462  2105  2105 I DEBUG   :     #00  pc 00042948  <unknown>  
  5.   
  6. 08-19 19:08:27.462  2105  2105 I DEBUG   :     #00 (unknown)  (unknown)   
  7. 08-19 19:08:27.462  2105  2105 I DEBUG   :     #01  pc 0000d158  /system/lib/libc.so  
  8.   
  9. 08-19 19:08:27.462  2105  2105 I DEBUG   :     #01 __pthread_cond_pulse  /home/compiler/workspace/gphone/MT6582/PD1224CT/ALPS.JB5.MP.V1.6_WET_20130810_trunk_user/bionic/libc/bionic/pthread.c:1689   
  10. 08-19 19:08:27.462  2105  2105 I DEBUG   :     #02  pc 00032954  <unknown>  
  11.   
  12. 08-19 19:08:27.462  2105  2105 I DEBUG   :     #02 (unknown)  (unknown)   
  13. 08-19 19:08:27.462  2105  2105 I DEBUG   :  

adbs 内容:

  1. #!/usr/bin/env python  
  2.   
  3. import os  
  4. import re  
  5. import string  
  6. import sys  
  7. import getopt  
  8.   
  9. ###############################################################################  
  10. # match "#00  pc 0003f52e  /system/lib/libdvm.so" for example  
  11. ###############################################################################  
  12. trace_line = re.compile("(.*)(\#[0-9]+)  (..) ([0-9a-f]{8})  ([^\r\n \t]*)")  
  13.   
  14.   
  15. class Options(object):pass  
  16. OPTIONS = Options()  
  17. OPTIONS.symbols = ""  
  18. OPTIONS.log = ""  
  19.   
  20. # returns a list containing the function name and the file/lineno  
  21. def CallAddr2Line(lib, addr):  
  22.   global symbols_dir  
  23.   global addr2line_cmd  
  24.   global cppfilt_cmd  
  25.   
  26.   if lib != "":  
  27.     cmd = addr2line_cmd + \  
  28.         " -f -e " + symbols_dir + lib + " 0x" + addr  
  29.     stream = os.popen(cmd)  
  30.     lines = stream.readlines()  
  31.     list = map(string.strip, lines)  
  32.   else:  
  33.     list = []  
  34.   if list != []:  
  35.     # Name like "move_forward_type<JavaVMOption>" causes troubles  
  36.     mangled_name = re.sub('<''\<', list[0]);  
  37.     mangled_name = re.sub('>''\>', mangled_name);  
  38.     cmd = cppfilt_cmd + " " + mangled_name  
  39.     stream = os.popen(cmd)  
  40.     list[0] = stream.readline()  
  41.     stream.close()  
  42.     list = map(string.strip, list)  
  43.   else:  
  44.     list = [ "(unknown)""(unknown)" ]  
  45.   return list  
  46.   
  47.   
  48. ###############################################################################  
  49. # similar to CallAddr2Line, but using objdump to find out the name of the  
  50. # containing function of the specified address  
  51. ###############################################################################  
  52. def CallObjdump(lib, addr):  
  53.   global objdump_cmd  
  54.   global symbols_dir  
  55.   
  56.   unknown = "(unknown)"  
  57.   uname = os.uname()[0]  
  58.   if uname == "Darwin":  
  59.     proc = os.uname()[-1]  
  60.     if proc == "i386":  
  61.       uname = "darwin-x86"  
  62.     else:  
  63.       uname = "darwin-ppc"  
  64.   elif uname == "Linux":  
  65.     uname = "linux-x86"  
  66.   if lib != "":  
  67.     next_addr = string.atoi(addr, 16) + 1  
  68.     cmd = objdump_cmd \  
  69.         + " -C -d --start-address=0x" + addr + " --stop-address=" \  
  70.         + str(next_addr) \  
  71.         + " " + symbols_dir + lib  
  72.     stream = os.popen(cmd)  
  73.     lines = stream.readlines()  
  74.     map(string.strip, lines)  
  75.     stream.close()  
  76.   else:  
  77.     return unknown  
  78.   
  79.   # output looks like  
  80.   # file format elf32-littlearm  
  81.   # Disassembly of section .text:  
  82.   # 0000833c <func+0x4>:  
  83.   #        833c:       701a            strb    r2, [r3, #0]  
  84.   # we want to extract the "func" part  
  85.   num_lines = len(lines)  
  86.   if num_lines < 2:  
  87.     return unknown  
  88.   func_name = lines[num_lines-2]  
  89.   func_regexp = re.compile("(^.*\<)(.*)(\+.*\>:$)")  
  90.   components = func_regexp.match(func_name)  
  91.   if components is None:  
  92.     return unknown  
  93.   return components.group(2)  
  94.   
  95. ###############################################################################  
  96. # determine the symbols directory in the local build  
  97. ###############################################################################  
  98. def FindSymbolsDir():  
  99.   global symbols_dir  
  100.   
  101.   try:  
  102.     #path = "sourcecode/MT6575/ALPS.ICS.MP.V2_W_20120504/out/target/product/bbk75_cu_ics/symbols/"  
  103.     if (len(OPTIONS.symbols) == 0):  
  104.       path = os.environ['ANDROID_PRODUCT_OUT'] + "/symbols"  
  105.     else:  
  106.       path = OPTIONS.symbols  
  107.   except:  
  108.     cmd = "CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core " \  
  109.       + "SRC_TARGET_DIR=build/target make -f build/core/config.mk " \  
  110.       + "dumpvar-abs-TARGET_OUT_UNSTRIPPED"  
  111.     stream = os.popen(cmd)  
  112.     str = stream.read()  
  113.     stream.close()  
  114.     path = str.strip()  
  115.   
  116.   if (not os.path.exists(path)):  
  117.     print path + " not found!"  
  118.     sys.exit(1)  
  119.   
  120.   symbols_dir = path  
  121.   
  122. ###############################################################################  
  123. # determine the path of binutils  
  124. ###############################################################################  
  125. def SetupToolsPath():  
  126.   global addr2line_cmd  
  127.   global objdump_cmd  
  128.   global cppfilt_cmd  
  129.   global symbols_dir  
  130.   
  131.   uname = os.uname()[0]  
  132.   if uname == "Darwin":  
  133.     proc = os.uname()[-1]  
  134.     if proc == "i386":  
  135.       uname = "darwin-x86"  
  136.     else:  
  137.       uname = "darwin-ppc"  
  138.   elif uname == "Linux":  
  139.     uname = "linux-x86"   
  140.   prefix = "./prebuilts/gcc/" + uname + "/arm/arm-linux-androideabi-4.6/bin/"  
  141.   addr2line_cmd = prefix + "arm-linux-androideabi-addr2line"  
  142.   
  143.   if (not os.path.exists(addr2line_cmd)):  
  144.     try:  
  145.       prefix = os.environ['ANDROID_BUILD_TOP'] + "/prebuilt/gcc/" + uname + \  
  146.                "/arm/arm-linux-androideabi-4.6/bin/"  
  147.     except:  
  148.       prefix = "";  
  149.   
  150.     addr2line_cmd = prefix + "arm-linux-androideabi-addr2line"  
  151.     if (not os.path.exists(addr2line_cmd)):  
  152.       print addr2line_cmd + " not found!"  
  153.       sys.exit(1)  
  154.   
  155.   objdump_cmd = prefix + "arm-linux-androideabi-objdump"  
  156.   cppfilt_cmd = prefix + "arm-linux-androideabi-c++filt"  
  157.   
  158. ###############################################################################  
  159. # look up the function and file/line number for a raw stack trace line  
  160. # groups[0]: log tag  
  161. # groups[1]: stack level  
  162. # groups[2]: "pc"  
  163. # groups[3]: code address  
  164. # groups[4]: library name  
  165. ###############################################################################  
  166. def SymbolTranslation(groups):  
  167.   lib_name = groups[4]  
  168.   code_addr = groups[3]  
  169.   caller = CallObjdump(lib_name, code_addr)  
  170.   func_line_pair = CallAddr2Line(lib_name, code_addr)  
  171.   
  172.   # If a callee is inlined to the caller, objdump will see the caller's  
  173.   # address but addr2line will report the callee's address. So the printed  
  174.   # format is desgined to be "caller<-callee  file:line"  
  175.   if (func_line_pair[0] != caller):  
  176.     print groups[0] + groups[1] + " " + caller + "<-" + \  
  177.           '  '.join(func_line_pair[:]) + " "  
  178.   else:  
  179.     print groups[0] + groups[1] + " " + '  '.join(func_line_pair[:]) + " "  
  180.   
  181. ###############################################################################  
  182.   
  183. COMMON_DOCSTRING = """  
  184.  -s (--symbols) <symbols dir>  
  185.  -l (--log) <logcat file>  
  186.   
  187. eg:  
  188.    adbs -s out/target/product/bbk75_cu_ics/symbols/ -l logcat.txt  
  189.  or  
  190.   adbs -s out/target/product/bbk75_cu_ics/symbols/ logcat  
  191. """  
  192.   
  193. def Usage():  
  194.   print COMMON_DOCSTRING  
  195.   
  196. if __name__ == '__main__':  
  197.   
  198.   try:  
  199.     opts, args = getopt.getopt(sys.argv[1:], "hs:l:",   
  200.                   ["help""symbols=""log="])  
  201.   except getopt.GetOptError:  
  202.     Usage()  
  203.   
  204.   for o, a in opts:  
  205.     if o in ("-h""--help"):  
  206.        Usage()  
  207.        sys.exit()  
  208.     elif o in ("-s""--symbols"):  
  209.        OPTIONS.symbols = a  
  210.     elif o in ("-l""--log="):  
  211.        OPTIONS.log = a  
  212.   
  213.   # pass the options to adb  
  214.   #adb_cmd  = "adb " + ' '.join(sys.argv[1:])  
  215.   if (len(OPTIONS.log) == 0):  
  216.     adb_cmd = "adb " + ' '.join(args)  
  217.   else:  
  218.     adb_cmd = "cat " + OPTIONS.log  
  219.   
  220.   # setup addr2line_cmd and objdump_cmd  
  221.   SetupToolsPath()  
  222.   
  223.   # setup the symbols directory  
  224.   FindSymbolsDir()  
  225.   
  226.   # invoke the adb command and filter its output  
  227.   stream = os.popen(adb_cmd)  
  228.   while (True):  
  229.     line = stream.readline()  
  230.     print line  
  231.     # EOF reached  
  232.     if (line == ''):  
  233.       break  
  234.   
  235.     # remove the trailing \n  
  236.     line = line.strip()  
  237.   
  238.     # see if this is a stack trace line  
  239.     match = trace_line.match(line)  
  240.     if (match):  
  241.       groups = match.groups()  
  242.       # translate raw address into symbols  
  243.       SymbolTranslation(groups)  
  244.     else:  
  245.       print line  
  246.       sys.stdout.flush()  
  247.   
  248.   # adb itself aborts  
  249.   stream.close()  

通过分析,我们最终找到错误发生于 /home/compiler/workspace/gphone/MT6582/project_name/ALPS.JB5.MP.V1.6_WET_20130810_trunk_user/bionic/libc/bionic/pthread.c:1689

实际上libc.so 出错对我们的帮助不大,需要找更上层的出错的地方。或者通过log去分析app层的错误。

注意:

需要注意的是symbols目录需要与 bug对应的版本号编译出来的那个symbols。直接用本地目录下的 symbols 解析出来的会与trace中的错误不一致!如果没有相应的 symbols 目录,那么我们需要自己重新编译一个软件出来复现问题,再从头来分析该段错误并解析。 symbols 下面的库会多出来一些调试信息。

2,高通平台下解析段错误就很简单了。

同样需要对应出问题版本下编译出来的 symbols目录解压覆盖原来的 out/product/project_name/symbols 目录。通过如下方式来实现解析!

arm-eabi-addr2line-fe ./out-PD1225TMA/target/product/msm8960/symbols/system/lib/libc.so 0000e498

-fe 参数 libc.so 出问题的库, 0000e498 函数地址。

参考资料:

1,【百科段错误】http://baike.baidu.com/view/3994532.htm 

2,【linux 下动态链接库、静态链接库】http://www./archives/604.html


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多