Android Tombstone 分析

news2024/9/21 4:32:49

1.什么是tombstone

Tombstone是指在分布式系统中用于标记数据已被删除的记录,通常包含删除操作的时间戳和相关信息。

当一个动态库(native程序)开始执行时,系统会注册一些连接到 debuggerd 的signal handlers。当系统发生崩溃时,会保存一个tombstone文件到/data/tombstones目录下,并在Logcat中提供相应信息。这个tombstone文件类似于墓碑,记录了已终止进程的基本信息,包括进程号、线程号、崩溃地址等。此外,tombstone文件还会详细记录崩溃时的现场情况,包括一系列的堆栈调用信息,帮助开发人员分析问题并进行调试。

2.tombstone文件长什么样

在这里插入图片描述

一个tombstone文件大概包含以下信息

--------- beginning of crash
F/libc    (  244): invalid address or address of corrupt block 0xb82f54a0 passed to dlfree
I/libc    (  244): debuggerd_signal_handler called: signal=11, fn=0xb6fbdaa1
F/libc    (  244): Fatal signal 11 (SIGSEGV), code 1, fault addr 0xdeadbaad in tid 244 (mediaserver)
I/libc    (  244): exit from debuggerd_signal_handler
W/NativeCrashListener(  916): Couldn't find ProcessRecord for pid 244
I/DEBUG   (  241): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/DEBUG   (  241): AM write failure (32 / Broken pipe)
I/DEBUG   (  241): Build fingerprint: XXXXXXXXX
I/DEBUG   (  241): Revision: '0'
I/DEBUG   (  241): ABI: 'arm'
I/DEBUG   (  241): pid: 244, tid: 244, name: mediaserver  >>> /system/bin/mediaserver <<<
I/DEBUG   (  241): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xdeadbaad
I/art     ( 3078): now dumpable=1
I/DEBUG   (  241): Abort message: 'invalid address or address of corrupt block 0xb82f54a0 passed to dlfree'
I/DEBUG   (  241):     r0 00000000  r1 b6f20dec  r2 deadbaad  r3 00000000
I/DEBUG   (  241):     r4 b82f54a0  r5 b6f220f8  r6 00000000  r7 42424242
I/DEBUG   (  241):     r8 ffffffff  r9 b82f5460  sl 00000030  fp 00000000
I/DEBUG   (  241):     ip 00000000  sp beb2c020  lr b6ef1fa7  pc b6ef1fa8  cpsr 600e0030
I/DEBUG   (  241):     d0  0000000000000000  d1  6f2073736572646c
I/DEBUG   (  241):     d2  707572726f632066  d3  206b636f6c622072
I/DEBUG   (  241):     d4  4242424242424242  d5  4242424242424242
I/DEBUG   (  241):     d6  4242424242424242  d7  3ecccccd42424242
I/DEBUG   (  241):     d8  0000000000000000  d9  0000000000000000
I/DEBUG   (  241):     d10 0000000000000000  d11 0000000000000000
I/DEBUG   (  241):     d12 0000000000000000  d13 0000000000000000
I/DEBUG   (  241):     d14 0000000000000000  d15 0000000000000000
I/DEBUG   (  241):     d16 0000000000000000  d17 3ff0000000000000
I/DEBUG   (  241):     d18 7e37e43c8800759c  d19 bfd5f3f082400000
I/DEBUG   (  241):     d20 3e66376972bea4d0  d21 bf66b12699b6468f
I/DEBUG   (  241):     d22 3fc54aa75950670f  d23 bfd73498f0a5ef3a
I/DEBUG   (  241):     d24 3fe0000000000000  d25 bfaaf3ec933c988f
I/DEBUG   (  241):     d26 0000000000000000  d27 4000000000000000
I/DEBUG   (  241):     d28 4002e6931e14bde7  d29 3faaf3ec9198f99c
I/DEBUG   (  241):     d30 3ff0000000000000  d31 3fd29572efd86cee
I/DEBUG   (  241):     scr 20000010
I/DEBUG   (  241): 
I/DEBUG   (  241): backtrace:
I/DEBUG   (  241):     #00 pc 00028fa8  /system/lib/libc.so (dlfree+1239)
I/DEBUG   (  241):     #01 pc 0000f2cb  /system/lib/libc.so (free+10)
I/DEBUG   (  241):     #02 pc 0000a1cb  /system/lib/libstagefright_foundation.so (_ZN7android7ABufferD2Ev+42)
I/DEBUG   (  241):     #03 pc 0000a211  /system/lib/libstagefright_foundation.so (_ZN7android7ABufferD0Ev+4)
I/DEBUG   (  241):     #04 pc 0000d68d  /system/lib/libutils.so (_ZNK7android7RefBase9decStrongEPKv+40)
I/DEBUG   (  241):     #05 pc 0005adfd  /system/lib/libstagefright.so (_ZN7android2spINS_13GraphicBufferEED2Ev+10)
I/DEBUG   (  241):     #06 pc 0007cd0f  /system/lib/libstagefright.so (_ZN7android14MPEG4Extractor10parseChunkEPxi+634)
I/DEBUG   (  241):     #07 pc 0007d43d  /system/lib/libstagefright.so (_ZN7android14MPEG4Extractor10parseChunkEPxi+2472)
I/DEBUG   (  241):     #08 pc 0007e873  /system/lib/libstagefright.so (_ZN7android14MPEG4Extractor12readMetaDataEv+58)
I/DEBUG   (  241):     #09 pc 0007eaa1  /system/lib/libstagefright.so (_ZN7android14MPEG4Extractor11countTracksEv+4)
I/DEBUG   (  241):     #10 pc 000acf9d  /system/lib/libstagefright.so (_ZN7android13ExtendedUtils29MediaExtractor_CreateIfNeededENS_2spINS_14MediaExtractorEEERKNS1_INS_10DataSourceEEEPKc+60)
I/DEBUG   (  241):     #11 pc 0008e3f5  /system/lib/libstagefright.so (_ZN7android14MediaExtractor6CreateERKNS_2spINS_10DataSourceEEEPKc+624)
I/DEBUG   (  241):     #12 pc 0006ace9  /system/lib/libstagefright.so (_ZN7android13AwesomePlayer15setDataSource_lERKNS_2spINS_10DataSourceEEE+12)
I/DEBUG   (  241):     #13 pc 0006c0dd  /system/lib/libstagefright.so (_ZN7android13AwesomePlayer13setDataSourceEixx+228)
I/DEBUG   (  241):     #14 pc 0003d647  /system/lib/libmediaplayerservice.so (_ZN7android18MediaPlayerService6Client13setDataSourceEixx+362)
I/DEBUG   (  241):     #15 pc 0005ea03  /system/lib/libmedia.so (_ZN7android13BnMediaPlayer10onTransactEjRKNS_6ParcelEPS1_j+478)
I/DEBUG   (  241):     #16 pc 00017fad  /system/lib/libbinder.so (_ZN7android7BBinder8transactEjRKNS_6ParcelEPS1_j+60)
I/DEBUG   (  241):     #17 pc 0001cfdb  /system/lib/libbinder.so (_ZN7android14IPCThreadState14executeCommandEi+562)
I/DEBUG   (  241):     #18 pc 0001d12f  /system/lib/libbinder.so (_ZN7android14IPCThreadState20getAndExecuteCommandEv+38)
I/DEBUG   (  241):     #19 pc 0001d171  /system/lib/libbinder.so (_ZN7android14IPCThreadState14joinThreadPoolEb+48)
I/DEBUG   (  241):     #20 pc 00001721  /system/bin/mediaserver
I/DEBUG   (  241):     #21 pc 0000f411  /system/lib/libc.so (__libc_init+44)
I/DEBUG   (  241):     #22 pc 00001998  /system/bin/mediaserver
I/DEBUG   (  241): 
I/DEBUG   (  241): stack:
I/DEBUG   (  241):          beb2bfe0  00000000  
I/DEBUG   (  241):          beb2bfe4  29ec038f  
I/DEBUG   (  241):          beb2bfe8  0009eb34  
I/DEBUG   (  241):          beb2bfec  b82f54a0  [heap]
I/DEBUG   (  241):          beb2bff0  b6f220f8  
I/DEBUG   (  241):          beb2bff4  00000000  
I/DEBUG   (  241):          beb2bff8  42424242  
I/DEBUG   (  241):          beb2bffc  b6edb3d1  /system/lib/libc.so (__libc_fatal_no_abort+16)
I/DEBUG   (  241):          beb2c000  b6f12f97  /system/lib/libc.so
I/DEBUG   (  241):          beb2c004  beb2c014  [stack]
I/DEBUG   (  241):          beb2c008  b6f167be  /system/lib/libc.so
I/DEBUG   (  241):          beb2c00c  b6ef1fa7  /system/lib/libc.so (dlfree+1238)
I/DEBUG   (  241):          beb2c010  b6f12f97  /system/lib/libc.so
I/DEBUG   (  241):          beb2c014  b82f54a0  [heap]
I/DEBUG   (  241):          beb2c018  b6f167be  /system/lib/libc.so
I/DEBUG   (  241):          beb2c01c  b82f54b0  [heap]
I/DEBUG   (  241):     #00  beb2c020  b82f5460  [heap]
......

它包含了发生问题的进程ID信息

I/DEBUG   (  241): pid: 244, tid: 244, name: mediaserver  >>> /system/bin/mediaserver <<<

当 tid (线程ID)== pid (进程ID)时,问题发生在父进程,反之问题发生在子进程,从上面的日志信息可以看出发生问题的进程是mediaserver的子进程。

Terminated signal 和 fault address 信息

F/libc    (  244): Fatal signal 11 (SIGSEGV), code 1, fault addr 0xdeadbaad in tid 244 (mediaserver)

这里的信息说明出现进程 Crash 的原因是因为程序产生了段错误的信号,访问了非法的内存空间,而访问的非法地址是 0xdeadbaad

信号机制是 Linux 进程间通信的一种重要方式,Linux 信号一方面用于正常的进程间通信和同步,如任务控制(SIGINT, SIGTSTP,SIGKILL, SIGCONT,……);另一方面,它还负责监控系统异常及中断。 当应用程序运行异常时, Linux 内核将产生错误信号并通知当前进程。 当前进程在接收到该错误信号后,可以有三种不同的处理方式。

(1)忽略该信号。
(2)捕捉该信号并执行对应的信号处理函数(signal handler)。
(3)执行该信号的缺省操作(如 SIGSEGV, 其缺省操作是终止进程)。

当 Linux 应用程序在执行时发生严重错误,一般会导致程序 crash。其中,Linux 专门提供了一类 crash 信号,在程序接收到此类信号时,缺省操作是将 crash 的现场信息记录到 core 文件,然后终止进程。

crash 信号列表:

SignalDescription
SIGSEGVInvalid memory reference.
SIGBUSAccess to an undefined portion of a memory object.
SIGFPEArithmetic operation error, like divide by zero.
SIGILLIllegal instruction, like execute garbage or a privileged instruction
SIGSYSBad system call.
SIGXCPUCPU time limit exceeded.
SIGXFSZFile size limit exceeded.

定义在prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8/sysroot/usr/include/bits/signum.h

/* Signals.  */
#define SIGHUP          1       /* Hangup (POSIX).  */
#define SIGINT          2       /* Interrupt (ANSI).  */
#define SIGQUIT         3       /* Quit (POSIX).  */
#define SIGILL          4       /* Illegal instruction (ANSI).  */
#define SIGTRAP         5       /* Trace trap (POSIX).  */
#define SIGABRT         6       /* Abort (ANSI).  */
#define SIGIOT          6       /* IOT trap (4.2 BSD).  */
#define SIGBUS          7       /* BUS error (4.2 BSD).  */
#define SIGFPE          8       /* Floating-point exception (ANSI).  */
#define SIGKILL         9       /* Kill, unblockable (POSIX).  */
#define SIGUSR1         10      /* User-defined signal 1 (POSIX).  */
#define SIGSEGV         11      /* Segmentation violation (ANSI).  */
#define SIGUSR2         12      /* User-defined signal 2 (POSIX).  */
#define SIGPIPE         13      /* Broken pipe (POSIX).  */
#define SIGALRM         14      /* Alarm clock (POSIX).  */
#define SIGTERM         15      /* Termination (ANSI).  */
#define SIGSTKFLT       16      /* Stack fault.  */
#define SIGCLD          SIGCHLD /* Same as SIGCHLD (System V).  */
#define SIGCHLD         17      /* Child status has changed (POSIX).  */
#define SIGCONT         18      /* Continue (POSIX).  */
#define SIGSTOP         19      /* Stop, unblockable (POSIX).  */
#define SIGTSTP         20      /* Keyboard stop (POSIX).  */
#define SIGTTIN         21      /* Background read from tty (POSIX).  */
#define SIGTTOU         22      /* Background write to tty (POSIX).  */
#define SIGURG          23      /* Urgent condition on socket (4.2 BSD).  */
#define SIGXCPU         24      /* CPU limit exceeded (4.2 BSD).  */
#define SIGXFSZ         25      /* File size limit exceeded (4.2 BSD).  */
#define SIGVTALRM       26      /* Virtual alarm clock (4.2 BSD).  */
#define SIGPROF         27      /* Profiling alarm clock (4.2 BSD).  */
#define SIGWINCH        28      /* Window size change (4.3 BSD, Sun).  */
#define SIGPOLL         SIGIO   /* Pollable event occurred (System V).  */
#define SIGIO           29      /* I/O now possible (4.2 BSD).  */
#define SIGPWR          30      /* Power failure restart (System V).  */
#define SIGSYS          31      /* Bad system call.  */
#define SIGUNUSED       31

#define _NSIG           65      /* Biggest signal number + 1
                                   (including real-time signals).  */

3.怎么分析tombstone文件

我们主要关注 backtrace 下面的内容,它保存了发生 crash 时候的函数调用关系,但是需要注意的是它的调用顺序是从下向上执行的(#XX pc -->#00 pc),通过这些函数调用关系,我们就可以大概定位出问题发生的地方,在本次 tombstone 日志中,我们通过

I/DEBUG   (  241):     #00 pc 00028fa8  /system/lib/libc.so (dlfree+1239)
I/DEBUG   (  241):     #01 pc 0000f2cb  /system/lib/libc.so (free+10)
I/DEBUG   (  241):     #02 pc 0000a1cb  /system/lib/libstagefright_foundation.so (_ZN7android7ABufferD2Ev+42)
I/DEBUG   (  241):     #03 pc 0000a211  /system/lib/libstagefright_foundation.so (_ZN7android7ABufferD0Ev+4)
I/DEBUG   (  241):     #04 pc 0000d68d  /system/lib/libutils.so (_ZNK7android7RefBase9decStrongEPKv+40)

可以分析出问题是在调用free函数时发生了指针错误,还可以看出问题发生的原因是libstagefright_foundation.so中释放了两次ABuffer引用,接着就去分析是谁谁释放的AUbffer强指针。

I/DEBUG   (  241):     #05 pc 0005adfd  /system/lib/libstagefright.so (_ZN7android2spINS_13GraphicBufferEED2Ev+10)
I/DEBUG   (  241):     #06 pc 0007cd0f  /system/lib/libstagefright.so (_ZN7android14MPEG4Extractor10parseChunkEPxi+634)
I/DEBUG   (  241):     #07 pc 0007d43d  /system/lib/libstagefright.so (_ZN7android14MPEG4Extractor10parseChunkEPxi+2472)
I/DEBUG   (  241):     #08 pc 0007e873  /system/lib/libstagefright.so (_ZN7android14MPEG4Extractor12readMetaDataEv+58)

可以看出来在 libstagefright 动态库中的MPEG4Extractor.cpp 的 parseChunk函数出现的错误。

4.一些分析工具

虽然通过 tombstone 的日志文件我们就可以大致定位出引发 crash 的代码的位置,但是通过借助一些分析工具,可以大大的提高工作效率和准确性,下面就来介绍以下这些工具。

(1)addr2line

addr2line 是 用来获得指定动态链接库文件或者可执行文件中指定地址对应的源代码信息的工具

它的各种参数如下所示(这个是google aosp android M 中带的):

~/source/google_android/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin$ ./x86_64-linux-android-addr2line -h
Usage: ./x86_64-linux-android-addr2line [option(s)] [addr(s)]
 Convert addresses into line number/file name pairs.
 If no addresses are specified on the command line, they will be read from stdin
 The options are:
  @<file>                Read options from <file>
  -a --addresses         Show addresses
  -b --target=<bfdname>  Set the binary file format
  -e --exe=<executable>  Set the input file name (default is a.out)
  -i --inlines           Unwind inlined functions
  -j --section=<name>    Read section-relative offsets instead of addresses
  -p --pretty-print      Make the output easier to read for humans
  -s --basenames         Strip directory names
  -f --functions         Show function names
  -C --demangle[=style]  Demangle function names
  -h --help              Display this information
  -v --version           Display the program's version
./x86_64-linux-android-addr2line: supported targets: elf64-x86-64 elf32-i386 elf32-x86-64 a.out-i386-linux pei-i386 pei-x86-64 elf64-l1om elf64-k1om elf64-little elf64-big elf32-little elf32-big plugin srec symbolsrec verilog tekhex binary ihex
Report bugs to <http://source.android.com/source/report-bugs.html>

addr2line 的基本用法如下所示:

./prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin/arm-linux-androideabi-addr2line -f -e out/debug/target/product/XXXX/symbols/system/lib/libstagefright.so  0007cd0f 
_ZN7android14MPEG4Extractor10parseChunkEPxi
/home/XXX/source/XXX/LINUX/android/frameworks/av/media/libstagefright/MPEG4Extractor.cpp:2180 (discriminator 1)

这里需要注意的是不能直接使用out/debug/target/product/XXX/system/lib/libstagefright.so,会出现运行上面命令之后显示

??
??:0

因为这个动态库是最后要打包到最后生成的system.ing中的,所以它不包含调试符号信息。

(2)ndk-stack

Android NDK 自从版本 r6开始, 提供了一个工具 ndk-stack。这个工具能自动分析 tombstone 文件, 能将崩溃时的调用内存地址和 c++ 代码一行一行对应起来.

它的使用方法为

./ndk-stack 
Usage:
   ndk-stack -sym <path> [-dump <path>]
      -sym  Contains full path to the root directory for symbols.
      -dump Contains full path to the file containing the crash dump.
            This is an optional parameter. If ommited, ndk-stack will
            read input data from stdin
   See docs/NDK-STACK.html in your NDK installation tree for more details.
  1. dump 参数很容易理解, 即 dump 下来的 log 文本文件. ndk-stack会分析此文件。
  2. sym 参数就是你android项目下,编译成功之后,obj目录下的文件(android系统源码o 中带有符号信息的文件)。

我们可以使用它来分析我们的log文件

ndk-stack -sym xxx.so -dump logfile

所以我们在调试android系统源码的时候也可以直接分析log中的crash信息。

adb shell logcat | ndk-stack -sym out/debug/target/product/XXXX/symbols/system/lib/xxx.so

(3)stack.py

stack.py工具就是要把backtrace通过addr2line工具一次性把addr对应到代码

#!/usr/bin/python2.4 -E
import getopt
import os
import re
import string
import sys
import getpass
import urllib
import subprocess
def PrintUsage():
  print
  print "  usage: " + sys.argv[0] + " [options] [FILE]"
  print
  print "  --symbols-dir=path"
  print "       the path to a symbols dir, such as =/tmp/out/target/product/dream/symbols"
  print
  print "  --symbols-zip=path"
  print "       the path to a symbols zip file, such as =dream-symbols-12345.zip"
  print
  print "  --auto"
  print "       attempt to:"
  print "         1) automatically find the build number in the crash"
  print "         2) if it's an official build, download the symbols "
  print "            from the build server, and use them"
  print
  print "  FILE should contain a stack trace in it somewhere"
  print "       the tool will find that and re-print it with"
  print "       source files and line numbers.  If you don't"
  print "       pass FILE, or if file is -, it reads from"
  print "       stdin."
  print
  sys.exit(1)
def FindSymbolsDir():
  cmd = "CALLED_FROM_SETUP=true make -f build/core/envsetup.mk " \
      + "dumpvar-abs-TARGET_OUT_UNSTRIPPED"
  stream = os.popen(cmd)
  str = stream.read()
  stream.close()
  return str.strip()
# returns a list containing the function name and the file/lineno
def CallAddr2Line(lib, addr):
  uname = os.uname()[0]
  if uname == "Darwin":
    proc = os.uname()[-1]
    if proc == "i386":
      uname = "darwin-x86"
    else:
      uname = "darwin-ppc"
  if lib != "":
    #cmd = "./prebuilt/" + uname + "/toolchain-eabi-4.2.1/bin/arm-eabi-addr2line" \
    #cmd = "./prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7/bin/arm-linux-androideabi-addr2line" \
    cmd = " arm-eabi-addr2line" \
        + " -f -e " + SYMBOLS_DIR + lib \
        + " 0x" + addr
    stream = os.popen(cmd)
    lines = stream.readlines()
    list = map(string.strip, lines)
  else:
    list = []
  if list != []:
    # Name like "move_forward_type<JavaVMOption>" causes troubles
    mangled_name = re.sub('<', '\<', list[0]);
    mangled_name = re.sub('>', '\>', mangled_name);
    #cmd = "./prebuilt/" + uname + "/toolchain-eabi-4.2.1/bin/arm-eabi-c++filt "\
    cmd = "./prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7/bin/arm-linux-androideabi-c++filt "\
          + mangled_name
    stream = os.popen(cmd)
    list[0] = stream.readline()
    stream.close()
    list = map(string.strip, list)
  else:
    list = [ "(unknown)", "(unknown)" ]
  return list
class SSOCookie(object):
  """
  creates a cookie file so we can download files from the build server
  """
  def __init__(self, cookiename=".sso.cookie", keep=False):
    self.sso_server = "login.corp.google.com"
    self.name = cookiename
    self.keeper = keep
    self.tmp_opts = ".curl.options"
    if not os.path.exists(self.name):
      user = os.environ['USER']
      print "\n%s, to access the symbols, please enter your LDAP " % user,
      password = getpass.getpass()
      params = urllib.urlencode({"u": user, "pw": password})
      fd = os.open(self.tmp_opts, os.O_RDWR | os.O_CREAT, 0600)
      os.write(fd, '-b "%s"\n' % self.name)
      os.write(fd, '-c "%s"\n' % self.name)
      os.write(fd, '-s"\n-L\n-d "%s"\n' % params)
      os.write(fd, 'url = "https://%s/login?ssoformat=CORP_SSO"\n' % 
               self.sso_server)
      # login to SSO
      response = os.popen("/usr/bin/curl -K %s" % self.tmp_opts)
      response.close()
      if os.path.exists(self.tmp_opts):
        os.remove(self.tmp_opts)
      if os.path.exists(self.name):
        os.chmod(self.name, 0600)
      else:
        print "Could not log in to SSO"
        sys.exit(1)
  def __del__(self):
      """clean up"""
      if not self.keeper:
        os.remove(self.name)
class NoBuildIDException(Exception):
  pass
def FindBuildFingerprint(lines):
  """
  Searches the given file (array of lines) for the build fingerprint information
  """
  fingerprint_regex = re.compile("^.*Build fingerprint:\s'(?P<fingerprint>.*)'")
  for line in lines:
    fingerprint_search = fingerprint_regex.match(line.strip())
    if fingerprint_search:
      return fingerprint_search.group('fingerprint')
      
  return None  # didn't find the fingerprint string, so return none
  
class SymbolDownloadException(Exception):
  pass
DEFAULT_SYMROOT = "/tmp/symbols"
def DownloadSymbols(fingerprint, cookie):
  """
  Attempts to download the symbols from the build server, extracts them,
  and returns the path.  Takes the fingerprint from the pasted stack trace
  and the SSOCookie
  """
  if fingerprint is None:
    return (None, None)
  symdir = "%s/%s" % (DEFAULT_SYMROOT, hash(fingerprint))
  if not os.path.exists(symdir):
    os.makedirs(symdir)
  # build server figures out the branch based on the CL
  params = {
              'op': "GET-SYMBOLS-LINK",
              'fingerprint': fingerprint,
           }
  url = urllib.urlopen("http://android-build/buildbot-update?",
                            urllib.urlencode(params)).readlines()[0]
  if url == "":
    raise SymbolDownloadException, "Build server down? Failed to find syms..."
  regex_str = (r'(?P<baseURL>http\:\/\/android-build\/builds\/.*\/[0-9]+' + 
           r'\/)(?P<img>.*)')
  url_regex = re.compile(regex_str)
  url_match = url_regex.match(url)
  if url_match is None:
    raise SymbolDownloadException, "Unexpected results from build server URL..."
  
  baseURL = url_match.group('baseURL')
  img =  url_match.group('img')
  symbolfile = img.replace("-img-", "-symbols-")
  symurl = baseURL + symbolfile
  localsyms = symdir + symbolfile
  if not os.path.exists(localsyms):
    print "downloading %s ..." % symurl
    curlcmd = ("""/usr/bin/curl -b %s -sL -w %%{http_code} -o %s %s""" % 
                          (cookie.name, localsyms, symurl))
    (fi,fo,fe) = os.popen3(curlcmd)
    fi.close()
    code = fo.read()
    err = fe.read()
    if err != "":
      raise SymbolDownloadException, "stderr from curl download: %s" % err
    if code != "200":
      raise SymbolDownloadException, "Faied to download %s" % symurl
  else:
    print "using existing cache for symbols"
  print "extracting %s..." % symbolfile
  saveddir = os.getcwd()
  os.chdir(symdir)
  unzipcode = subprocess.call(["unzip", "-qq", "-o", localsyms])
  if unzipcode > 0:
    raise SymbolDownloadException, ("failed to extract symbol files (%s)." 
                             % localsyms)
  os.chdir(saveddir)
  
  return (symdir, "%s/out/target/product/dream/symbols" % symdir)
def UnzipSymbols(symbolfile):
  """Unzips a file to DEFAULT_SYMROOT and returns the unzipped location.
  Args:
    symbolfile: The .zip file to unzip
  Returns:
    A tuple containing (the directory into which the zip file was unzipped,
    the path to the "symbols" directory in the unzipped file).  To clean
    up, the caller can delete the first element of the tuple.
  Raises:
    SymbolDownloadException: When the unzip fails.
  """
  symdir = "%s/%s" % (DEFAULT_SYMROOT, hash(symbolfile))
  if not os.path.exists(symdir):
    os.makedirs(symdir)
  print "extracting %s..." % symbolfile
  saveddir = os.getcwd()
  os.chdir(symdir)
  unzipcode = subprocess.call(["unzip", "-qq", "-o", symbolfile])
  if unzipcode > 0:
    raise SymbolDownloadException, ("failed to extract symbol files (%s)." 
                             % symbolfile)
  os.chdir(saveddir)
  
  return (symdir, "%s/out/target/product/dream/symbols" % symdir)
def PrintTraceLines(traceLines):
    maxlen = max(map(lambda tl: len(tl[1]), traceLines))
    print
    print "Stack Trace:"
    print "  ADDR      " + "FUNCTION".ljust(maxlen) + "  FILE:LINE"
    for tl in traceLines:
      print "  " + tl[0] + "  " + tl[1].ljust(maxlen) + "  " + tl[2]
    return
def PrintValueLines(valueLines):
    print
    print "Stack Data:"
    print "  ADDR      VALUE     " + "FILE:LINE/FUNCTION"
    for vl in valueLines:
      print "  " + vl[1] + "  " + vl[2] + "  " + vl[4]
      if vl[4] != "":
        print "                      " + vl[3]
    return
def ConvertTrace(lines):
  PROCESS_INFO_LINE = re.compile("(pid: [0-9]+, tid: [0-9]+.*)")
  SIGNAL_LINE = re.compile("(signal [0-9]+ \(.*\).*)")
  REGISTER_LINE = re.compile("(([ ]*[0-9a-z]{2} [0-9a-f]{8}){4})")
  TRACE_LINE = re.compile("(.*)\#([0-9]+)  (..) ([0-9a-f]{3})([0-9a-f]{5})  ([^\r\n \t]*)")
  VALUE_LINE = re.compile("(.*)([0-9a-f]{2})([0-9a-f]{6})  ([0-9a-f]{3})([0-9a-f]{5})  ([^\r\n \t]*)")
  THREAD_LINE = re.compile("(.*)(\-\-\- ){15}\-\-\-")
  traceLines = []
  valueLines = []
  for line in lines:
    header = PROCESS_INFO_LINE.search(line)
    if header:
      print header.group(1)
      continue
    header = SIGNAL_LINE.search(line)
    if header:
      print header.group(1)
      continue
    header = REGISTER_LINE.search(line)
    if header:
      print header.group(1)
      continue
    if TRACE_LINE.match(line):
      match = TRACE_LINE.match(line)
      groups = match.groups()
      if groups[5] == "<unknown>" or groups[5] == "[heap]" or groups[5] == "[stack]":
        traceLines.append((groups[3]+groups[4], groups[5], groups[5]))
      else:
        info = CallAddr2Line(groups[5], groups[4])
        traceLines.append((groups[3]+groups[4], info[0], info[1]))
    if VALUE_LINE.match(line):
      match = VALUE_LINE.match(line)
      groups = match.groups()
      if groups[5] == "<unknown>" or groups[5] == "[heap]" or groups[5] == "[stack]" or groups[5] == "":
        valueLines.append((groups[0], groups[1]+groups[2], groups[3]+groups[4], groups[5], ""))
      else:
        info = CallAddr2Line(groups[5], groups[4])
        valueLines.append((groups[0], groups[1]+groups[2], groups[3]+groups[4], info[0], info[1]))
    header = THREAD_LINE.search(line)
    if header:
      if len(traceLines) > 0:
        PrintTraceLines(traceLines)
      if len(valueLines) > 0:
        PrintValueLines(valueLines)
      traceLines = []
      valueLines = []
      print
      print "-----------------------------------------------------\n"
  if len(traceLines) > 0:
    PrintTraceLines(traceLines)
  if len(valueLines) > 0:
    PrintValueLines(valueLines)
SYMBOLS_DIR = FindSymbolsDir()
if __name__ == '__main__':
  try:
    options, arguments = getopt.getopt(sys.argv[1:], "",
                             ["auto", "symbols-dir=", "symbols-zip=", "help"])
  except getopt.GetoptError, error:
    PrintUsage()
  
  AUTO = False
  zipArg = None
  for option, value in options:
    if option == "--help":
      PrintUsage()
    elif option == "--symbols-dir":
      SYMBOLS_DIR = value
    elif option == "--symbols-zip":
      zipArg = value
    elif option == "--auto":
      AUTO = True
  
  if len(arguments) > 1:
    PrintUsage()
  if AUTO:
    cookie = SSOCookie(".symbols.cookie")
  
  if len(arguments) == 0 or arguments[0] == "-":
    print "Reading native crash info from stdin"
    f = sys.stdin
  else:
    print "Searching for native crashes in %s" % arguments[0]
    f = open(arguments[0], "r")
  lines = f.readlines()
  rootdir = None
  if AUTO:
    fingerprint = FindBuildFingerprint(lines)
    print "fingerprint:", fingerprint
    rootdir, SYMBOLS_DIR = DownloadSymbols(fingerprint, cookie)
  elif zipArg is not None:
    rootdir, SYMBOLS_DIR = UnzipSymbols(zipArg)
  
  print "Reading symbols from", SYMBOLS_DIR
  lines = ConvertTrace(lines)
  
  if rootdir is not None:
    # be a good citizen and clean up...os.rmdir and os.removedirs() don't work
    cmd = "rm -rf \"%s\"" % rootdir
    print "\ncleaning up (%s)" % cmd
    os.system(cmd)
  
  # vi: ts=2 sw=2

使用方法:

python stack.py --symbols-dir=out/target/profuct/XXX/sysbols/  tombstone-00(tombstone文件)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1480400.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浪潮服务器使用ARCCONF查看RAID配置信息

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、获取ARCCONF二、使用步骤1.Windows Server 20221.查看RAID控制器2.查询控制器属性3.查询虚拟磁盘属性4.查询物理硬盘属性 2.Ubuntu-22.043.CentOS7 三、配置…

精益工程师3000工资与30000工资的区别!

在同一职场征程中&#xff0c;为何有的精益工程师月入仅三千&#xff0c;而另一些则能达到三万&#xff1f;这一差距&#xff0c;远超薪酬数额的简单对比&#xff0c;它深刻反映了专业能力、工作态度和个人品质的全面差异。 首先&#xff0c;对于刚踏入职场的精益工程师而言&a…

1.3 vue ui框架-element-ui框架

1 前言 ElementUI是一套基于VUE2.0的桌面端组件库&#xff0c;ElementUI提供了丰富的组件帮助开发人员快速构建功能强大、风格统一的页面。 ElementUI官网 https://element.eleme.io 2 安装 运行命令 cnpm i element-ui -S -S表示只在该项目下安装&#xff0c;不是全局安…

Springboot配置定时任务

介绍SpringBoot集成定时任务的过程。 目 录 1、引入相关依赖 2、启动类添加注解 3、定时任务类添加注解 4、cron表达式 5、总结 1、引入相关依赖 SpringBoot自带定时任务配置&#xff0c;只要引入springboot相关类即可。 2、启动类添加注解 在启动类上添加注解EnableSch…

【学习心得】Python调用JS的三种常用方法

在做JS逆向的时候&#xff0c;一种情况是直接用Python代码复现JS代码的功能&#xff0c;达成目的。但很多时候这种方法有明显的缺点&#xff0c;那就是一旦JS代码逻辑发生了更改&#xff0c;你就得重写Python的代码逻辑非常不便。于是第二种情况就出现了&#xff0c;我直接得到…

CDN CloudFlare 接入 OCI 对象存储

在当今数字化时代&#xff0c;网站性能和可用性是业务成功的关键。为了提供快速且可靠的访问体验&#xff0c;许多组织正在寻找有效的内容分发网络&#xff08;CDN&#xff09;解决方案。CloudFlare作为业界领先的CDN提供商&#xff0c;其强大的全球网络基础设施能够加速网站内…

UE学习笔记--解决滚轮无法放大蓝图、Panel等

我们发现有时候创建蓝图之后&#xff0c;右上角的缩放是1&#xff1a;1 但是有时候我们可能需要放的更大一点。 发现一直用鼠标滚轮像上滚动&#xff0c;都没有效果。 好像最大只能 1&#xff1a;1. 那是因为 UE 做了限制。如果希望继续放大&#xff0c;我们可以按住 Ctrl 再去…

Excel常用公式总结非常实用

16个最实用的Excel万能公式 1、多条件判断 IF(And(条件1,条件2..条件N),条件成立返回值) IF(or(条件1,条件2..条件N),条件成立返回值) 2、多条件查找 Lookup(1,0/((条件1*条件2*...条件N)),返回值区域&#xff09; 3、多条件求和 Sumifs(值区域,判断区域1,条件1,判断区域2,条…

hive报错:FAILED: NullPointerException null

发现问题 起因是我虚拟机的hive不管执行什么命令都报空指针异常的错误 我也在网上找了很多相关问题的资料&#xff0c;发现都不是我这个问题的解决方法&#xff0c;后来在hive官网上与hive 3.1.3版本相匹配的hadoop版本是3.x的版本&#xff0c;而我的hadoop版本还是2.7.2的版本…

opencv VideoCapture

videocapture顾名思义视频捕捉&#xff0c;主要是从视频文件、摄像头或网络摄像头获取视频流数据&#xff0c;并将其作为一系列帧进行处理。 我们这里主要实现了获取项目文件夹下的1.mp4视频文件&#xff0c;然后经过灰度变化、均值滤波、边缘检测然后将视频显示出来 #include…

MySQL的索引和B+tree结构

目录 0.关于索引的常见面试题 1.什么是索引&#xff1f; 索引的优缺点 2.索引的数据结构&#xff0c;为什么InnoDb引擎使用Btree作为索引的数据结构&#xff1f; 分析怎样的索引才是好的 二插搜索树 红黑树 B-Tree BTree 哈希 为什么 InnoDB 存储引擎选择使用 Btree 索…

初学HTMLCSS——盒子模型

盒子模型 盒子&#xff1a;页面中所有的元素&#xff08;标签&#xff09;&#xff0c;都可以看做是一个 盒子&#xff0c;由盒子将页面中的元素包含在一个矩形区域内&#xff0c;通过盒子的视角更方便的进行页面布局盒子模型组成&#xff1a;内容区域&#xff08;content&…

商城系统_大型商城系统源码_免费开源商城_OctShop

随着互联网对各行各业的渗透&#xff0c;以及人们网络购物的习惯已经形成&#xff0c;很多商家或企业都开始搭建与开发自己的商城系统平台。商城系统是一个以互联网技术为基础&#xff0c;依托电子商务的电商系统平台。一般大型的的商城系统都会有前台各种客户端&#xff0c;如…

JVM原理-基础篇

Java虚拟机&#xff08;JVM, Java Virtual Machine&#xff09;是运行Java应用程序的核心组件&#xff0c;它是一个抽象化的计算机系统模型&#xff0c;为Java字节码提供运行环境。JVM的主要功能包括&#xff1a;类加载机制、内存管理、垃圾回收、指令解释与执行、异常处理与安…

2023年世界前沿科技发展态势及2024年趋势展望——综述篇

源自&#xff1a;全球技术地图 “人工智能技术与咨询” 发布 一、2023年前沿科技发展与竞争态势总结 &#xff08;一&#xff09;人工智能引领前沿技术加速进步&#xff0c;产业应用一触即发&#xff0c;技术奇点苗头出现 &#xff08;二&#xff09;科技之变引发战争形态之…

帆软图片设置之一张图片铺满整个屏幕

1、设置PC端自适应属性&#xff0c;字体自适应&#xff0c;双向自适应&#xff1b; 2、单元格属性–>对齐–>高级–>图片布局–>拉伸。

欧拉-黎曼函数的K阶近似(OpenMP实现和MPI实现)

目录 欧拉-黎曼函数的K阶近似&#xff08;OpenMP实现和MPI实现&#xff09;问题描述OpenMP代码实现MPI代码实现 注意事项运行参考资料 欧拉-黎曼函数的K阶近似&#xff08;OpenMP实现和MPI实现&#xff09; 问题描述 OpenMP代码实现 #include <stdio.h> #include <s…

HarmonyOS云端一体化组件之AGC应用管理

&#xff08;可选&#xff09;在AGC控制台创建同包名应用 如创建工程时&#xff0c;发现尚未在AGC控制台创建与工程包名相同的应用&#xff0c;可进行补充创建。 1.点击界面提示内的“AppGallery Connect”&#xff0c;浏览器打开AGC控制台“我的项目”页面。 2.点击选择您希…

工厂模式:没你想像的那么难

工厂模式 工厂模式是一种创建型设计模式&#xff0c;它允许创建对象而无需指定将要创建的对象的具体类。它通过将对象的创建委托给一个单独的方法或类来完成&#xff0c;从而隐藏了对象的实例化逻辑。这样可以提高代码的灵活性&#xff0c;减少了代码中的重复和耦合。 在工厂…

社会底层人民要被人工智能和机器人淘汰了吗?你害怕被AI代替吗?

随着科技的飞速发展&#xff0c;人工智能和机器人技术已经成为我们日常生活中不可或缺的一部分。这些技术的广泛应用引发了一些担忧&#xff0c;其中之一就是社会底层人民是否会被人工智能和机器人所淘汰。然而&#xff0c;这个问题并不是非黑即白的&#xff0c;它需要从多个角…