Android Tombstone 分析

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 stdinThe 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 willread input data from stdinSee 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():printprint "  usage: " + sys.argv[0] + " [options] [FILE]"printprint "  --symbols-dir=path"print "       the path to a symbols dir, such as =/tmp/out/target/product/dream/symbols"printprint "  --symbols-zip=path"print "       the path to a symbols zip file, such as =dream-symbols-12345.zip"printprint "  --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"printprint "  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."printsys.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" + addrstream = os.popen(cmd)lines = stream.readlines()list = map(string.strip, lines)else:list = []if list != []:# Name like "move_forward_type<JavaVMOption>" causes troublesmangled_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_namestream = 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 = cookienameself.keeper = keepself.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 SSOresponse = 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 noneclass 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 traceand 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 CLparams = {'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 + symbolfilelocalsyms = symdir + symbolfileif not os.path.exists(localsyms):print "downloading %s ..." % symurlcurlcmd = ("""/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" % errif code != "200":raise SymbolDownloadException, "Faied to download %s" % symurlelse:print "using existing cache for symbols"print "extracting %s..." % symbolfilesaveddir = 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 unzipReturns:A tuple containing (the directory into which the zip file was unzipped,the path to the "symbols" directory in the unzipped file).  To cleanup, 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..." % symbolfilesaveddir = 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))printprint "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):printprint "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)continueheader = SIGNAL_LINE.search(line)if header:print header.group(1)continueheader = REGISTER_LINE.search(line)if header:print header.group(1)continueif 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 = []printprint "-----------------------------------------------------\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 = FalsezipArg = Nonefor option, value in options:if option == "--help":PrintUsage()elif option == "--symbols-dir":SYMBOLS_DIR = valueelif option == "--symbols-zip":zipArg = valueelif option == "--auto":AUTO = Trueif 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.stdinelse:print "Searching for native crashes in %s" % arguments[0]f = open(arguments[0], "r")lines = f.readlines()rootdir = Noneif AUTO:fingerprint = FindBuildFingerprint(lines)print "fingerprint:", fingerprintrootdir, SYMBOLS_DIR = DownloadSymbols(fingerprint, cookie)elif zipArg is not None:rootdir, SYMBOLS_DIR = UnzipSymbols(zipArg)print "Reading symbols from", SYMBOLS_DIRlines = ConvertTrace(lines)if rootdir is not None:# be a good citizen and clean up...os.rmdir and os.removedirs() don't workcmd = "rm -rf \"%s\"" % rootdirprint "\ncleaning up (%s)" % cmdos.system(cmd)# vi: ts=2 sw=2

使用方法:

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

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

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

相关文章

Spark Shuffle Tracking 原理分析

Shuffle Tracking Shuffle Tracking 是 Spark 在没有 ESS(External Shuffle Service)情况&#xff0c;并且开启 Dynamic Allocation 的重要功能。如在 K8S 上运行 spark 没有 ESS。本文档所有的前提都是基于以上条件的。 如果开启了 ESS&#xff0c;那么 Executor 计算完后&a…

MySQL 表的基本操作,结合项目的表自动初始化来讲

有了数据库以后&#xff0c;我们就可以在数据库中对表进行增删改查了&#xff0c;这也就意味着&#xff0c;一名真正的 CRUD Boy 即将到来&#xff08;&#x1f601;&#xff09;。 查表 查看当前数据库中所有的表&#xff0c;使用 show tables; 命令 由于当前数据库中还没有…

基于Python3的数据结构与算法 - 09 希尔排序

一、引入 希尔排序是一种分组插入排序的算法。 二、排序思路 首先取一个整数d1 n/2&#xff0c;将元素分为d1个组&#xff0c;每组相邻量取元素距离为d1&#xff0c;在各组内直接进行插入排序&#xff1b;取第二个整数d2 d1/2&#xff0c; 重复上述分组排序过程&#xff0…

CSS 自测题 -- 用 flex 布局绘制骰子(一、二、三【含斜三点】、四、五、六点)

一点 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>css flex布局-画骰子</title><sty…

Unity 切换场景

场景切换前必须要将场景拖动到Build中 同步加载场景 using System.Collections; using System.Collections.Generic; //using UnityEditor.SearchService; using UnityEngine; // 场景管理 需要导入该类 using UnityEngine.SceneManagement;public class c3 : MonoBehaviour {…

redis五大基础类型【重点】

之前写过一点小知识&#xff1a;https://blog.csdn.net/qq_45927881/article/details/134959181?spm1001.2014.3001.5501 参考链接 https://xiaolincoding.com/redis/data_struct/command.html#%E4%BB%8B%E7%BB%8D 目录 1. string&#xff08;字符串&#xff09;2. Hash&#…

MySql安全加固:配置不同用户不同账号禁止使用旧密码禁止MySql进程管理员权限

MySql安全加固&#xff1a;配置不同用户不同账号&禁止使用旧密码&禁止MySql进程管理员权限 1.1 检查是否配置不同用户不同账号1.2 检查是否禁止使用旧密码1.3 禁止MySql进程管理员权限 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496…

【c++】通讯录管理系统

1.系统功能介绍及展示 2.创建项目 3.菜单实现 4.退出功能实现 5.添加联系人—结构体设计 6.添加联系人—功能实现 7.显示联系人 8.删除练习人—检测联系人是否存在 9.删除联系人—功能实现 10.查找联系人 11.修改联系人 12.清空通讯录 #include <iostream> #include <…

什么是VR虚拟社区|VR元宇宙平台|VR主题馆加盟

VR虚拟社区是指一种基于虚拟现实技术构建的在线社交平台或环境&#xff0c;用户可以在其中创建虚拟化的个人形象&#xff08;也称为avatars&#xff09;并与其他用户进行交流、互动和合作。在VR虚拟社区中&#xff0c;用户可以选择不同的虚拟场景和环境&#xff0c;如虚拟公园、…

fly-barrage 前端弹幕库(3):滚动弹幕的设计与实现

项目官网地址&#xff1a;https://fly-barrage.netlify.app/&#xff1b; &#x1f451;&#x1f40b;&#x1f389;如果感觉项目还不错的话&#xff0c;还请点下 star &#x1f31f;&#x1f31f;&#x1f31f;。 Gitee&#xff1a;https://gitee.com/fei_fei27/fly-barrage&a…

显示器开机正常,插入HDMI线却不显示画面,换了HDMI线还是不行?

环境&#xff1a; 惠普/P24VG4 DELL笔记本 问题描述&#xff1a; 显示器开机正常&#xff0c;插入HDMI线却不显示画面&#xff0c;换了HDMI线还是不行&#xff0c;是不是显示器坏了&#xff1f; 解决方案&#xff1a; 1.前往显示器设置菜单里面查看input 2.把输入源默认设…

二百二十五、海豚调度器——用DolphinScheduler调度执行Flume数据采集任务

一、目的 数仓的数据源是Kafka&#xff0c;因此离线数仓需要用Flume采集Kafka中的数据到HDFS中 在实际项目中&#xff0c;不可能一直在Xshell中启动Flume任务&#xff0c;一是项目的Flume任务很多&#xff0c;二是一旦Xshell页面关闭Flume任务就会停止&#xff0c;这样非常不…

案例研究|DataEase助力众陶联应对产业链数据可视化挑战

佛山众陶联供应链服务有限公司&#xff08;以下简称为“众陶联”&#xff09;成立于2016年&#xff0c;是由34家陶瓷企业共同创办的建陶行业工业互联网平台&#xff0c;股东产值占整个行业的22.5%。众陶联以数据赋能为核心&#xff0c;积极探索新的交易和服务模式&#xff0c;构…

帝国cms7.5仿非小号区块链门户资讯网站源码 带手机版

帝国cms7.5仿非小号区块链门户资讯网站源码 带手机版 带自动采集 开发环境&#xff1a;帝国cms 7.5 安装环境&#xff1a;phpmysql 包含火车头采集规则和模块&#xff0c;采集目标站非小号官网。 专业的数字货币大数据平台模板&#xff0c;采用帝国cms7.5内核仿制&#xff0…

Ai-WB2-32S在window下使用vs 和 msys2编译以及烧录

文章目录 前言一、使用前准备第一步 安装vscode第二步 安装msys2 二、使用步骤1.打开MSYS2 MINGW64&#xff08;1&#xff09;在开始栏中找到MSYS2 MINGW64并打开&#xff08;2&#xff09;安装git&#xff08;3&#xff09;安装make&#xff08;4&#xff09;安装好之后的文件…

Redis 之五:Redis 的主从复制

概念 主从复制&#xff0c;是指将一台 Redis 服务器的数据&#xff0c;复制到其他的Redis服务器。前者称为主节点(master)&#xff0c;后者称为从节点(slave)&#xff1b;数据的复制是单向的&#xff0c;只能由主节点到从节点。 默认情况下&#xff0c;每台Redis服务器都是主节…

云天励飞战略投资神州云海,布局机器人市场

日前,AI上市企业云天励飞(688343.SH)完成了对深圳市神州云海智能科技有限公司(以下简称“神州云海”)的B轮战略投资。 公开资料显示,自2015年于深圳创立以来,神州云海始终聚焦人工智能与服务机器人广阔的应用市场,依托自主的核心算法能力,深耕机器人硬件本体研发,整合上下游产…

RabbitMQ-TTL/死信队列/延迟队列高级特性

文章目录 TTL死信队列消息成为死信的三种情况队列如何绑定死信交换机 延迟队列RabbitMQ如何实现延迟队列 总结来源B站黑马程序员 TTL TTLTTL(Time To Live):存活时间/过期时间当信息到达存活时间后&#xff0c;还没有被消费&#xff0c;会被自动清除。RabbitMQ可以对消息设置过…

Win10系統如何重置系统

Win10系統如何重置 大家可以使用Win10內建的重設電腦設定&#xff0c;如以下操作&#xff1a; 首先&#xff0c;可以先到桌面左下角的【開始】 選擇【設定】 在【設定】裡找到【更新與安全性】 在左側欄有一項【復原】 在復原的標題下&#xff0c;副標題有一項【重設此電腦】…

【algorithm】算法基础课---排序算法(附笔记 | 建议收藏)

&#x1f680;write in front&#x1f680; &#x1f4dd;个人主页&#xff1a;认真写博客的夏目浅石. &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f4e3;系列专栏&#xff1a;AcWing算法学习笔记 &#x1f4ac;总结&#xff1a;希望你看完…