当前位置: 首页 > 工具软件 > ipaddr-py > 使用案例 >

android fault addr,signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr

施默
2023-12-01

摘抄自:http://zhidao.baidu.com/link?url=gOXPCxE4HSq9GOGH0QGNS5zLXUWkeeHrmWpD_W3DrUllNLgJF7OGV4RCAEQGDGQlQv6J_8b-7zXNBDtUnAzUr1vw5UCBmC16i8oMhgkrO8e

Jave层的代码发生crash问题时,系统往往会打印出很详细的出错信息。比如上面这个例子,不但给出了出错的原因,还有出错的文件和行数。根据这些信息,我们会很容易的定位问题所在。native层的crash虽然也有栈log信息输出,但是就不那么容易看懂了。下面我们再看一个native层crash的例子:

F/libc ( 2102): Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1), thread2102 (testapp)

D/dalvikvm(26630):GC_FOR_ALLOC freed 604K, 11% free 11980K/13368K, paused 36ms, total36ms

I/dalvikvm-heap(26630):Grow heap (frag case) to 11.831MB for 102416-byteallocation

D/dalvikvm(26630):GC_FOR_ALLOC freed 1K, 11% free 12078K/13472K, paused 34ms, total34ms

I/DEBUG ( 127):*** *** *** *** *** *** *** *** *** *** *** *** *** *** ******

I/DEBUG ( 127):Build fingerprint:

'Android/full_maguro/maguro:4.2.2/JDQ39/eng.liuchao.20130619.201255:userdebug/test-keys'

I/DEBUG ( 127):Revision: '9'

I/DEBUG ( 127):pid: 2102, tid: 2102, name: testapp >>>./testapp <<<

I/DEBUG ( 127):signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr00000000

I/DEBUG ( 127): r0 00000020 r173696874 r2 400ff520 r300000000

I/DEBUG ( 127): r4 400ff469 r5beb4ab24 r6 00000001 r7beb4ab2c

I/DEBUG ( 127): r8 00000000 r900000000 sl 00000000 fpbeb4ab1c

I/DEBUG ( 127): ip 4009b5dc spbeb4aae8 lr 400ff46f pc400ff45e cpsr 60000030

I/DEBUG ( 127): d0 000000004108dae8 d1 4108ced84108cec8

I/DEBUG ( 127): d2 4108cef84108cee8 d3 4108cf184108cf08

I/DEBUG ( 127): d4 4108c5a84108c598 d5 4108ca084108c5b8

I/DEBUG ( 127): d6 4108ce684108ce58 d7 4108ce884108ce78

I/DEBUG ( 127): d8 0000000000000000 d9 0000000000000000

I/DEBUG ( 127): d10 0000000000000000 d110000000000000000

I/DEBUG ( 127): d120000000000000000 d130000000000000000

I/DEBUG ( 127): d14 0000000000000000 d150000000000000000

I/DEBUG ( 127): d16 c1dcf7c087fec8b4 d173f50624dd2f1a9fc

I/DEBUG ( 127): d18 41c7b1ac89800000 d190000000000000000

I/DEBUG ( 127): d20 0000000000000000 d210000000000000000

I/DEBUG ( 127): d22 0000000000000000 d230000000000000000

I/DEBUG ( 127): d24 0000000000000000 d250000000000000000

I/DEBUG ( 127): d26 0000000000000000 d270000000000000000

I/DEBUG ( 127): d28 0000000000000000 d290000000000000000

I/DEBUG ( 127): d30 0000000000000000 d310000000000000000

I/DEBUG ( 127): scr 00000010

I/DEBUG ( 127):

I/DEBUG ( 127):backtrace:

I/DEBUG ( 127): #00 pc0000045e /system/bin/testapp

I/DEBUG ( 127): #01 pc0000046b /system/bin/testapp

I/DEBUG ( 127): #02 pc0001271f /system/lib/libc.so (__libc_init+38)

I/DEBUG ( 127): #03 pc00000400 /system/bin/testapp

I/DEBUG ( 127):

I/DEBUG ( 127):stack:

I/DEBUG ( 127): beb4aaa8 000000c8

I/DEBUG ( 127): beb4aaac 00000000

I/DEBUG ( 127): beb4aab0 00000000

I/DEBUG ( 127): beb4aab4 401cbee0 /system/bin/linker

I/DEBUG ( 127): beb4aab8 00001000

I/DEBUG ( 127): beb4aabc 4020191d /system/lib/libc.so (__libc_fini)

I/DEBUG ( 127): beb4aac0 4020191d /system/lib/libc.so (__libc_fini)

I/DEBUG ( 127): beb4aac4 40100eac /system/bin/testapp

I/DEBUG ( 127): beb4aac8 00000000

I/DEBUG ( 127): beb4aacc 400ff469 /system/bin/testapp

I/DEBUG ( 127): beb4aad0 beb4ab24 [stack]

I/DEBUG ( 127): beb4aad4 00000001

I/DEBUG ( 127): beb4aad8 beb4ab2c [stack]

I/DEBUG ( 127): beb4aadc 00000000

I/DEBUG ( 127): beb4aae0 df0027ad

I/DEBUG ( 127): beb4aae4 00000000

I/DEBUG ( 127): #00 beb4aae8 00000000

I/DEBUG ( 127): ........ ........

I/DEBUG ( 127): #01 beb4aae8 00000000

I/DEBUG ( 127): beb4aaec 401e9721 /system/lib/libc.so (__libc_init+40)

I/DEBUG ( 127): #02 beb4aaf0 beb4ab08 [stack]

I/DEBUG ( 127): beb4aaf4 00000000

I/DEBUG ( 127): beb4aaf8 00000000

I/DEBUG ( 127): beb4aafc 00000000

I/DEBUG ( 127): beb4ab00 00000000

I/DEBUG ( 127): beb4ab04 400ff404 /system/bin/testapp

I/DEBUG ( 127):

这个log就不那么容易懂了,但是还是能从中看出很多信息,让我们一起来学习如何分析这种log。首先看下面这行:

pid: 2102, tid: 2102,name: testapp >>>./testapp <<<

从这一行我们可以知道crash进程的pid和tid,前文我们已经提到过,Android调用gettid函数得到的实际是进程Id号,所以这里的pid和tid相同。知道进程号后我们可以往前翻翻log,看看该进程最后一次打印的log是什么,这样能缩小一点范围。

接下来内容是进程名和启动参数。再接下来的一行比较重要了,它告诉了我们从系统角度看,出错的原因:

signal 11 (SIGSEGV), code 1(SEGV_MAPERR), fault addr 00000000

signal11是Linux定义的信号之一,含义是Invalidmemory reference,无效的内存引用。加上后面的“faultaddr 00000000”我们基本可以判定这是一个空指针导致的crash。当然这是笔者为了讲解而特地制造的一个Crash的例子,比较容易判断,大部分实际的例子可能就没有那么容易了。

再接下来的log打印出了cpu的所有寄存器的信息和堆栈的信息,这里面最重要的是从堆栈中得到的backtrace信息:

I/DEBUG ( 127):backtrace:

I/DEBUG ( 127): #00 pc0000045e /system/bin/testapp

I/DEBUG ( 127): #01 pc0000046b /system/bin/testapp

I/DEBUG ( 127): #02 pc0001271f /system/lib/libc.so (__libc_init+38)

I/DEBUG ( 127): #03 pc00000400 /system/bin/testapp

因为实际的运行系统里没有符号信息,所以打印出的log里看不出文件名和行数。这就需要我们借助编译时留下的符号信息表来翻译了。Android提供了一个工具可以来做这种翻译工作:arm-eabi-addr2line,位于prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin目录下。用法很简单:

#./arm-eabi-addr2line -f -eout/target/product/hammerhead/symbols/system/bin/testapp0x0000045e

参数-f表示打印函数名;参数-e表示带符号表的模块路径;最后是要转换的地址。这条命令在笔者的编译环境中得到的结果是:

memcpy /home/rd/compile/android-4.4_r1.2/bionic/libc/include/string.h:108

剩余三个地址翻译如下:

main /home/rd/compile/android-4.4_r1.2/packages/apps/testapp/app_main.cpp:38

out_vformat /home/rd/compile/android-4.4_r1.2/bionic/libc/bionic/libc_logging.cpp:361

_start libgcc2.c:0

利用这些信息我们很快就能定位问题了。不过这样手动一条一条的翻译比较麻烦,笔者使用的是从网上找到的一个脚本,可以一次翻译所有的行,有需要的读者可以在网上找一找。

了解了如何分析普通的Log文件。

这两种方法都不是我发明了,都是网上一些高手公共出来的调试方法,无奈找不到出处的地方了,所以就在此总结一下,以方便android下的调试:

简要说明:

android系统中调试Java非常容易,一般遇到错误都在logcat中打印出错时函数的调用关系,

而C库中出错时只看到一些二进制信息,使用gdbserver调试环境搭建又比较复杂。

方法一:

下在介绍一个简单的调试库的方法,当然需要有so库的源代码

举例

a)         错误信息如下,它表示了出错时的函数调用关系(下面调上面的)

I/DEBUG   (  634):          #00  pc 000078e6  /system/lib/libmultiplayerservice.so

I/DEBUG   (  634):          #01  pc 000087bc  /system/lib/libmultiplayerservice.so

I/DEBUG   (  634):          #02  pc 0000e94e  /system/lib/libsensorservice.so

I/DEBUG   (  634):          #03  pc 0000a790  /system/lib/libsensorservice.so

I/DEBUG   (  634):          #04  pc 0000d4b2  /system/lib/libsensorservice.so

I/DEBUG   (  634):          #05  pc 0000d852  /system/lib/libsensorservice.so

I/DEBUG   (  634):          #06  pc 00015ece  /system/lib/libutils.so

I/DEBUG   (  634):          #07  pc 0000153a  /system/lib/libsystem_server.so

I/DEBUG   (  634):          #08  pc 00001756  /system/lib/libsystem_server.so

I/DEBUG   (  634):          #09  pc 0000adb8  /system/lib/libandroid_servers.so

I/DEBUG   (  634):          #10  pc 00011cb4  /system/lib/libdvm.so

b)进入源码中带符号表的so库所在目录

$ cd out/target/product/generic/obj/SHARED_LIBRARIES/libmultiplayerservice_intermediates/LINKED

这个有个需要注意的地方:

对于可执行程序及动态库,一般在LINKED子目录中是带有符号的库(没有经过符号剥离),如果可执行文件中没有包括调试符号,您将获得??:0 作为响应。

c)用addr2line命令找到地址对应的程序位置,动态库为libmultiplayerservice.so

arm-eabi-addr2line 000078e6 -e libmultiplayerservice.so

结果:,显示出对应的程序文件和行数,如果不是debug版本,可能有一两行偏差

frameworks/base/services/multiplayerservice/PlayerSocket.cpp 421 行

d)注意

arm-eabi_addr2line在prebuild/linux-x86/toolchain/arm-eabi-xxx/bin目录下,

运行build/envsetup.sh后即可直接使用它,同目录下的objdump, nm也是常用调试命令

方法二:

1、首先需要一个重要的脚本文件:

#!/usr/bin/python

# stack symbol parser

import os

import string

import sys

#define android product name

ANDROID_PRODUCT_NAME = 'generic'

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

def parse(self):

f = file(self.logname,'r')

lines = f.readlines()

if lines != []:

print 'read file ok'

else:

print 'read file failed'

result =[]

for line in lines:

if line.find('stack') != -1:

print 'stop search'

break

elif line.find('system') != -1:

#print 'find one item' + line

result.append(line)

return result

class ParseContent:

def __init__(self,addr,lib):

self.address = addr # pc address

self.exename = lib  # executable or shared library

def addr2line(self):

cmd = addr2line_tool + " -C -f -s -e " + symbol_dir + self.exename + " " + self.address

#print cmd

stream = os.popen(cmd)

lines = stream.readlines();

list = map(string.strip,lines)

return list

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])

将以上文件保存hy.panic.py

注意脚本里面两个地方:

1.脚本里面的ANDROID_PRODUCT_NAME = 'generic' 必须和源码生成路径对应。2.编译环境工具也必须对应上# addr2line tool path and symbol path。

2、相关的死机堆栈信息保存 error.txt

例如:

I/DEBUG   (  634):          #00  pc 000078e6  /system/lib/libmultiplayerservice.so

I/DEBUG   (  634):          #01  pc 000087bc  /system/lib/libmultiplayerservice.so

I/DEBUG   (  634):          #02  pc 0000e94e  /system/lib/libsensorservice.so

I/DEBUG   (  634):          #03  pc 0000a790  /system/lib/libsensorservice.so

I/DEBUG   (  634):          #04  pc 0000d4b2  /system/lib/libsensorservice.so

I/DEBUG   (  634):          #05  pc 0000d852  /system/lib/libsensorservice.so

I/DEBUG   (  634):          #06  pc 00015ece  /system/lib/libutils.so

I/DEBUG   (  634):          #07  pc 0000153a  /system/lib/libsystem_server.so

I/DEBUG   (  634):          #08  pc 00001756  /system/lib/libsystem_server.so

I/DEBUG   (  634):          #09  pc 0000adb8  /system/lib/libandroid_servers.so

I/DEBUG   (  634):          #10  pc 00011cb4  /system/lib/libdvm.so

3、将以上两个文件拷贝到android的编译根路径下面,执行

python hy.panic.py error.txt

方法2使用非常方便,相比于加打印效率大大提高。非常感谢提供脚本的同学。

http://blog.csdn.net/andyhuabing/article/details/7074979(我用这个脚本,好像不好使)

http://blog.csdn.net/eustoma/article/details/6449156

 类似资料: