利用NDK崩溃日志查找BUG
转自:http://www.tuicool.com/articles/qQNfUfe
背景介绍
本文主要内容: 利用android的crash log来对c++开发的android应用进行错误定位.
容易稳定复现的BUG, 一般可以通过断点调试来解决. 如果测试人员也无法稳定复现, log就成了程序吊定位问题的救命稻草 .
通用操作系统都有自己的日志系统, android也不例外. 救命稻草已经给你了~ ()
但是, android的系统日志在c++代码崩溃时, 打印的都是内存地址和寄存器. 比如, 这样:
- ::35.331 I DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
- ::35.331 I DEBUG : Build fingerprint: 'google/razorg/deb:4.4.2/KOT49H/937116:user/release-keys'
- ::35.331 I DEBUG : Revision: ''
- ::35.331 I DEBUG : pid: , tid: , name: Thread- >>> com.guangyou.ddgame <<<
- ::35.331 I DEBUG : signal (SIGSEGV), code (SEGV_MAPERR), fault addr
- ::35.431 D audio_hw_primary: out_set_parameters: enter: usecase(: deep-buffer-playback) kvpairs: routing=
- ::35.511 I DEBUG : r0 76d94458 r1 r2 r3
- ::35.511 I DEBUG : r4 760c1a48 r5 751e2440 r6 r7 760c1a48
- ::35.511 I DEBUG : r8 r9 76c96f3c sl 76c861c0 fp 76d94444
- ::35.511 I DEBUG : ip sp 76d94430 lr 75a81bd8 pc 75a81bdc cpsr 600f0010
- ::35.511 I DEBUG : d0 746968775f327865 d1 6a6e6169642f675f
- ::35.511 I DEBUG : d2 5f6f616978757169 d3 676e702e6e776f6d
- ::35.511 I DEBUG : d4 d5
- ::35.511 I DEBUG : d6 d7
这密密麻麻的都是些神马, 是人看的么?
饿. 这个麻… 谁让你当程序猿! 让你当! 活该要看天书!
硬着头皮也要来, 我们就来讲讲怎么消化天书吧~
怎样获取android的系统日志
假设你已经安装了 Android Develop Tools, 可以成功调用 adb
. 并打开android开发用机的调试模式, 连接到电脑.
打开命令行, 在命令行输入: adb logcat
. 就可以看到满屏幕的日志啦.
输入 adb logcat --help
可以看到 logcat
的用法提示.
这里有两个参数特别提醒一下, 比较常用:
1. -v XXXX
: 用来选择log输出样式, 一般建议 threadtime
, 更加详细.
2. -d
: 让log一次性输出后马上完毕. 如果没有此命令, logcat
工具会一直输出, 即使更新在界面上.
如果需要保存log到文件, 方便以后查看. 可输入命令:
adb logcat -v threadtime -d > log.txt
理解NDK的crash log
如果你用c++开发的android应用在运行过程中, c++代码发生错误导致程序崩溃, 系统就会记录 crash log到上述的系统日志中.
下面是我正在开发的游戏一次崩溃后, 截取的日志
- ::35.331 I DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
- ::35.331 I DEBUG : Build fingerprint: 'google/razorg/deb:4.4.2/KOT49H/937116:user/release-keys'
- ::35.331 I DEBUG : Revision: ''
- ::35.331 I DEBUG : pid: , tid: , name: Thread- >>> com.guangyou.ddgame <<<
- ::35.331 I DEBUG : signal (SIGSEGV), code (SEGV_MAPERR), fault addr
- ::35.431 D audio_hw_primary: out_set_parameters: enter: usecase(: deep-buffer-playback) kvpairs: routing=
- ::35.511 I DEBUG : r0 76d94458 r1 r2 r3
- ::35.511 I DEBUG : r4 760c1a48 r5 751e2440 r6 r7 760c1a48
- ::35.511 I DEBUG : r8 r9 76c96f3c sl 76c861c0 fp 76d94444
- ::35.511 I DEBUG : ip sp 76d94430 lr 75a81bd8 pc 75a81bdc cpsr 600f0010
- ::35.511 I DEBUG : d0 746968775f327865 d1 6a6e6169642f675f
- ::35.511 I DEBUG : d2 5f6f616978757169 d3 676e702e6e776f6d
- ::35.511 I DEBUG : d4 d5
- ::35.511 I DEBUG : d6 d7
- ::35.511 I DEBUG : d8 d9
- ::35.511 I DEBUG : d10 d11
- ::35.511 I DEBUG : d12 d13
- ::35.511 I DEBUG : d14 d15
- ::35.511 I DEBUG : d16 c3c3c3c3c3c3c3c3 d17 c3c3c3c3c3c3c3c3
- ::35.511 I DEBUG : d18 41c7ddc227000000 d19 3ff0000000000000
- ::35.511 I DEBUG : d20 3f811110896efbb2 d21 3fd7096611460fdb
- ::35.511 I DEBUG : d22 c0176a8ee0000000 d23 bfc5230c760b0605
- ::35.511 I DEBUG : d24 d25 3fc7922925a107e2
- ::35.511 I DEBUG : d26 3fdaa0f8fab43e33 d27 3fb43ad076b251ab
- ::35.511 I DEBUG : d28 3fa15cb6bdc3c156 d29 3ec6cd878c3b46a7
- ::35.511 I DEBUG : d30 3f65f3b6b9b97e01 d31 3ef99342e0ee5069
- ::35.511 I DEBUG : scr
- ::35.511 I DEBUG :
- ::35.511 I DEBUG : backtrace:
- ::35.511 I DEBUG : # pc 0089cbdc /data/app-lib/com.guangyou.ddgame-/libcocos2dcpp.so (cocos2d::Texture2D::getContentSize() const+)
- ::35.511 I DEBUG : # pc 0088f8dc /data/app-lib/com.guangyou.ddgame-/libcocos2dcpp.so (cocos2d::Sprite::setTexture(std::string const&)+)
- ::35.511 I DEBUG : # pc 007863dc /data/app-lib/com.guangyou.ddgame-/libcocos2dcpp.so (cocos2d::ui::Button::loadTextureDisabled(std::string const&, cocos2d::ui::Widget::TextureResType)+)
- ::35.511 I DEBUG :
- ::35.511 I DEBUG : stack:
- ::35.511 I DEBUG : 76d943f0
- ::35.511 I DEBUG : 76d943f4 4006bc0d /system/lib/libc.so (free+)
- ::35.511 I DEBUG : 76d943f8 76a72c54
- ::35.511 I DEBUG : 76d943fc 75eca614 /data/app-lib/com.guangyou.ddgame-/libcocos2dcpp.so
- ::35.511 I DEBUG : 76d94400 751c23c8 [anon:libc_malloc]
- ::35.511 I DEBUG : 76d94404 751c23c8 [anon:libc_malloc]
- ::35.511 I DEBUG : 76d94408 751c23c8 [anon:libc_malloc]
- ::35.511 I DEBUG : 76d9440c 75a749b4 /data/app-lib/com.guangyou.ddgame-/libcocos2dcpp.so (cocos2d::Sprite::setTexture(cocos2d::Texture2D*)+)
- ::35.511 I DEBUG : 76d94410 0000003d
- ::35.511 I DEBUG : 76d94414 00e8efc8
- ::35.511 I DEBUG : 76d94418
- ::35.511 I DEBUG : 76d9441c
- ::35.511 I DEBUG : 76d94420
- ::35.511 I DEBUG : 76d94424 76d94458 [stack:]
- ::35.511 I DEBUG : 76d94428
- ::35.511 I DEBUG : 76d9442c 76d94444 [stack:]
- ::35.511 I DEBUG : # 76d94430
- ::35.511 I DEBUG : 76d94434 76d94458 [stack:]
- ::35.511 I DEBUG : 76d94438 76a66184
- ::35.511 I DEBUG : 76d9443c 760c1a48 /data/app-lib/com.guangyou.ddgame-/libcocos2dcpp.so
- ::35.511 I DEBUG : 76d94440 76d9447c [stack:]
- ::35.511 I DEBUG : 76d94444 75a748e0 /data/app-lib/com.guangyou.ddgame-/libcocos2dcpp.so (cocos2d::Sprite::setTexture(std::string const&)+)
- ::35.511 I DEBUG : # 76d94448 76d944ec [stack:]
- ::35.511 I DEBUG : 76d9444c 793ff0e8 [anon:libc_malloc]
- ::35.511 I DEBUG : 76d94450 76a72c54
- ::35.511 I DEBUG : 76d94454
- ::35.511 I DEBUG : 76d94458
- ::35.511 I DEBUG : 76d9445c
- ::35.511 I DEBUG : 76d94460
- ::35.511 I DEBUG : 76d94464
- ::35.511 I DEBUG : 76d94468
- ::35.511 I DEBUG : 76d9446c
- ::35.521 I DEBUG : 76d94470 7b91dcf8 [anon:libc_malloc]
- ::35.521 I DEBUG : 76d94474 78ce6c50 [anon:libc_malloc]
- ::35.521 I DEBUG : 76d94478 76d944b4 [stack:]
- ::35.521 I DEBUG : 76d9447c 7596b3e0 /data/app-lib/com.guangyou.ddgame-/libcocos2dcpp.so (cocos2d::ui::Button::loadTextureDisabled(std::string const&, cocos2d::ui::Widget::TextureResType)+)
- ::35.521 I DEBUG : # 76d94480
- ::35.521 I DEBUG : 76d94484
- ::35.521 I DEBUG : 76d94488 76d944ec [stack:]
- ::35.521 I DEBUG : 76d9448c 793fe780 [anon:libc_malloc]
- ::35.521 I DEBUG : 76d94490 76d944f0 [stack:]
- ::35.521 I DEBUG : 76d94494 793ff0e8 [anon:libc_malloc]
- ::35.521 I DEBUG : 76d94498
- ::35.521 I DEBUG : 76d9449c 4006bc0d /system/lib/libc.so (free+)
- ::35.521 I DEBUG : 76d944a0 76a72c54
- ::35.521 I DEBUG : 76d944a4 75eca614 /data/app-lib/com.guangyou.ddgame-/libcocos2dcpp.so
- ::35.521 I DEBUG : 76d944a8 78ce6c50 [anon:libc_malloc]
- ::35.521 I DEBUG : 76d944ac 78ce6c50 [anon:libc_malloc]
- ::35.521 I DEBUG : 76d944b0 76d9455c [stack:]
- ::35.521 I DEBUG : 76d944b4 75924e54 /data/app-lib/com.guangyou.ddgame-/libcocos2dcpp.so (cocostudio::ButtonReader::setPropsFromJsonDictionary(cocos2d::ui::Widget*, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const&)+)
- ::35.521 I DEBUG : 76d944b8
- ::35.521 I DEBUG : 76d944bc 78ce6c50 [anon:libc_malloc]
- ::35.521 I DEBUG :
- ::35.521 I DEBUG : memory near r0:
- ::35.521 I DEBUG : 76d94438 76a66184 760c1a48 76d9447c 75a748e0
- ::35.521 I DEBUG : 76d94448 76d944ec 793ff0e8 76a72c54
...
- ::35.521 I DEBUG :
- ::35.521 I DEBUG : memory near r4:
- ::35.521 I DEBUG : 760c1a28 760811c8 75ee318c 75ee3194 75ee319c
- ::35.521 I DEBUG : 760c1a38 4006d091 75f9a1f4 75f4ee5c 75e8ea0c
...
下面来逐行解读:
1. ndk crash log以 *** *** *** *** ***
开始.
2. 第一行 Build fingerprint: 'google/razorg/deb:4.4.2/KOT49H/937116:user/release-keys'
指明了运行的Android版本, 如果您有多份crash dump的话这个信息就比较有用了.
3. 接着一行显示的是当前的线程id(pid)和进程id(tid). 如果当前崩溃的线程是主线程的话, pid和tid会是一样的~
4. 第四行, 显示的是unix信号. 这里的 signal 11
, 即 SIGSEGV
, 表示段错误, 是最常见的信号.( 什么是unix信号 , 什么是 SIGSEGV
)
5. 接下来的部分是系统寄存器的dump信息.
- rX( X=[0~9] ): 代表整数寄存器
- dX( X=[0~31]): 是浮点指针寄存器
- fp (or r11) : 指向当前正在执行的函数的堆栈底.
- ip (or r12) : 一个寄存器, 我也没弄明白是干啥的.
- sp (or r13) : 当前正在执行的函数的堆栈顶.(跟fp相对应)
- lr (or r14) : link register . 简单来说, 当当前指令执行完了, 就会从这个寄存器获取地址, 来知道需要返回到哪里继续执行.
- pc (or r15) : program counter. 存放下一条指令的地址.
cpsr : Current Program Status Register. 表示当前运行环境和状态的一些字节位.
- Crash dump还包含PC之前和之后的一些内存字段.
- 最后, 是崩溃时的调用堆栈. 如果你执行的是debug版本, 还能还原一些c++代码.
利用ndk-stack定位崩溃代码
上面的一些信息能简单的帮你定位以下问题. 如果信息量还不够大的话, 那就还有最后一招: 还原历史.
Android NDK
自从版本R6开始, 提供了一个工具 ndk-stack
( 在目录 {ndk_root}/
中 ). 这个工具能自动分析dump下来的crash log, 将崩溃时的调用内存地址和c++代码一行一行对应起来.
我们先看一下用法, 执行命令 ndk-stack --help
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
- -dump参数很容易理解, 即dump下来的log文本文件.
ndk-stack
会分析此文件. - -sym参数就是你android项目下,编译成功之后,
obj
目录下的文件.
下面我们就来示范一下:
$ adb logcat | ndk-stack -sym ./obj/local/armeabi
********** Crash dump: **********
Build fingerprint: 'htc_wwe/htc_bravo/bravo:2.3.3/
GRI40/96875.1:user/release-keys'
pid: , tid: >>> com.packtpub.droidblaster <<<
signal (SIGSEGV), code (SEGV_MAPERR), fault addr 0000000c
Stack frame # pc 00010a2c /data/data/com.packtpub.droidblaster/lib/libdroidblaster.so: Routine update in /home/packt/Project/Chapter11/DroidBlaster_Part11/jni/TimeService.cpp:
Stack frame # pc 00009fcc /data/data/com.packtpub.droidblaster/lib/libdroidblaster.so: Routine onStep in /home/packt/Project/Chapter11/DroidBlaster_Part11/jni/DroidBlaster.cpp:
Stack frame # pc 0000a348 /data/data/com.packtpub.droidblaster/lib/libdroidblaster.so: Routine run in /home/packt/Project/Chapter11/DroidBlaster_Part11/jni/EventLoop.cpp:
Stack frame # pc 0000f994 /data/data/com.packtpub.droidblaster/lib/libdroidblaster.so: Routine android_main in /home/packt/Project/Chapter11/DroidBlaster_Part11/jni/Main.cpp:
...
熟悉的代码出现啦~~
利用NDK崩溃日志查找BUG的更多相关文章
- [cocos2dx]利用NDK崩溃日志查找BUG
摘要: 在android上开发c++应用, crash日志都是汇编码, 很难对应到c++代码中去. 通过此文, 你可以定位到程序崩溃时的C++代码, 精确查找问题. 博客: http://www.cn ...
- iOS开发-应用崩溃日志揭秘(一)
作为一名应用开发者,你是否有过如下经历? 为确保你的应用正确无误,在将其提交到应用商店之前,你必定进行了大量的测试工作.它在你的设备上也运行得很好,但是,上了应用商店后,还是有用户抱怨会闪退 ! 如果 ...
- 【转】iOS应用崩溃日志分析
作为一名应用开发者,你是否有过如下经历? 为确保你的应用正确无误,在将其提交到应用商店之前,你必定进行了大量的测试工作.它在你的设备上也运行得很好,但是,上了应用商店后,还是有用户抱怨会闪退 ! ...
- iOS应用崩溃日志分析
转自raywenderlich 作为一名应用开发者,你是否有过如下经历? 为确保你的应用正确无误,在将其提交到应用商店之前,你必定进行了大量的测试工作.它在你的设备上也运行得很好,但是,上了应 ...
- 【转】iOS应用崩溃日志揭秘
这篇文章还可以在这里找到 英语 If you're new here, you may want to subscribe to my RSS feed or follow me on Twitter ...
- iOS应用崩溃日志揭秘
这篇文章还可以在这里找到 英语 Learn how to make sense of crash logs! 本文作者是 Soheil Moayedi Azarpour, 他是一名独立iOS开发者. ...
- iOS应用崩溃日志分析 iOS应用崩溃日志揭秘
转自:http://www.raywenderlich.com/zh-hans/30818/ios%E5%BA%94%E7%94%A8%E5%B4%A9%E6%BA%83%E6%97%A5%E5%BF ...
- iOS崩溃日志 如何看
日志主要分为六个部分:进程信息.基本信息.异常信息.线程回溯.线程状态和二进制映像. 我们在进行iPhone应用测试时必然会在"隐私"中找到不少应用的崩溃日志,但是不会阅读对于很多 ...
- iOS开发--应用崩溃日志揭秘(二)
场景 4: 吃棒棒糖时闪退! 用户邮件说, “当rage master吃棒棒糖时应用就闪退…” 另一用户说, “我让rage master 吃棒棒糖,没几次应用就闪退了!”崩溃日志如下: Incide ...
随机推荐
- 【selenium+python】自动化测试目录与文件结构
一.首先,看一下完整的项目目录结构图,如下: ==================目录结构================== ==================目录结构============== ...
- HDU 5338(ZZX and Permutations-用线段树贪心)
ZZX and Permutations Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/O ...
- ASP.NET动态网站制作(7)-- JS(2)
前言:这节课是JS的第二节课,主要是JS中的控制语句. 内容: 1.条件语句: (1)比较操作符:==,!=,>,>=,<,<=.字符串大小写转换:toUpperCase() ...
- C#抓取网面上的html内容(JS动态生成的无法抓取)
抓取内容的代码: /// </summary> /// <param name="url">路径URL</param> /// <para ...
- l两张图片轮播
在head里面加 <script language="javascript"> function scroll(spanlevel) { if (spanlevel.s ...
- jquery Jsonp的使用
<script type="text/javascript"> $(function(){ $.ajax({ url:"test", jsonpCa ...
- SP1437 Longest path in a tree(树的直径)
应该是模板题了吧 定义: 树的直径是指一棵树上相距最远的两个点之间的距离. 方法:我使用的是比较常见的方法:两边dfs,第一遍从任意一个节点开始找出最远的节点x,第二遍从x开始做dfs找到最远节点的距 ...
- python数据分析之Pandas:基本功能介绍
Pandas有两个主要的数据结构:Series和DataFrame. Series是一种类似于一维数组的对象,它由一组数据以及一组与之相关的数据标签构成.来看下它的使用过程 In [1]: from ...
- 在cocos2d-x中使用LUA
在cocos2d-x中使用LUA 1.注冊LUA脚本引擎 CCLuaEngine* pEngine = CCLuaEngine::defaultEngine(); CCScriptEngineMana ...
- 链表的C++实现
有的时候,处于内存中的数据并非连续的.那么这时候.我们就须要在数据结构中加入一个属性.这个属性会记录以下一个数据的地址.有了这个地址之后.全部的数据就像一条链子一样串起来了,那么这个地址属性就起到 ...