如何在 iOS 的ios crash log 分析上 debug

IOS 调试Crash Log的方法 - 为程序员服务
IOS 调试Crash Log的方法
在iPhone上输出日志
如果不是在模拟器上,又或者我们的设备没有连接到PC上,那么如何调试我们的程序呢?假如我们通过AdHoc发布了程序,希望随时得到测试人员的反馈,可以利用下面的方法,将标准出力(stderr)信息记录到文件中,然后通过邮件新式发给开发者。
1. 设置一个开关,用来清空日志文件内容,并切换输出位置;
- (BOOL)deleteLogFile {
[self finishLog];
BOOL success = [[NSFileManager defaultManager] removeItemAtPath:[self loggingPath] error:nil];
[self startLog];
当我们调用上面的deleteLogFile后,就会清空之前的日志,并设置新的输出。
- (void)finishLog {
fflush(stderr);
dup2(dup(STDERR_FILENO), STDERR_FILENO);
close(dup(STDERR_FILENO));
- (NSString*)loggingPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console.log"];
return logP
- (void)startLog {
freopen([[self loggingPath] cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
2. 当日志取得之后,可以通过下面的方式发送邮件给开发者
- (void)sendLogByMail {
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate =
[picker setSubject:[NSString stringWithFormat:@"%@ - Log", [self appName]]];
NSString *message = [NSString stringWithContentsOfFile:[self loggingPath] encoding:NSUTF8StringEncoding error:nil];
[picker setMessageBody:message isHTML:NO];
[self.navigationController presentModalViewController:picker animated:YES];
[picker release];
iPhone应用程序的CrashReporter机能
苹果在固件2.0发布的时候,其中一项特性是向iPhone开发者通过邮件发送错误报告,以便开发人员更好的了解自己的软件运行状况。不过不少开发者报告此服务有时无法获取到~/Library/Logs/CrashReporter/MobileDevice directory的错误信息。
现在苹果提供了一种更简单的方法,使iPhone开发者可以通过iTunes更容易的查看崩溃报告。具体方法使进入iTunesConnect(在进入之前确定你有iPhone开发者帐号),点击管理你应用程序,之后就可以看到用户崩溃日志了。
这里我介绍一下从设备中取出CrashLog,并解析的方法。
CrashLog的位置
程序Crash之后,将设备与PC中的iTunes连接,设备中的CrashLog文件也将一并同步到PC中。其中位置如下;
~/Library/Logs/CrashReporter/MobileDevice
Windows Vista/7:
C:\Users\&user_name&\AppData\Roaming\Apple computer\Logs\CrashReporter/MobileDevice
Windows XP:
C:\Documents and Settings\&user_name&\Application Data\Apple computer\Logs\CrashReporter
在这些目录下,会有具体设备的目录,其下就是许多*.crash的文件。
比如程序TestEditor在iPhone1设备上的crashLog如下:
~Library/Logs/CrashReporter/MobileDevice/iPhone1/TestEditor_-454678_iPhone1.crash
Incident Identifier: CAF9ED40-2D59-45EA-96B0-52BDA1115E9F
CrashReporter Key:
30af939d26f6ecc5f0d08653b2aaf4e
TestEditor [12506]
/var/mobile/Applications/60ACEDBC-600E-42AF-88A044/TestEditor.app/TestEditor
Identifier:
TestEditor
Code Type:
ARM (Native)
Parent Process:
launchd [1]
Date/Time:
11:25:56.357 +0900
OS Version:
iPhone OS 3.1.3 (7E18)
Report Version:
Exception Type:
EXC_BAD_ACCESS (SIGBUS)
Exception Codes: KERN_PROTECTION_FAILURE at 0x
Crashed Thread:
Thread 0 Crashed:
0x332b98d8 0x331b2000 + 1079512
0x 0x331b2000 + 438696
0xx331b2000 + 438312
0x332bb2000 + 1078824
0xx331b2000 + 359792
0xx331b2000 + 359432
QuartzCore
0x324cc05c 0x324ae000 + 122972
QuartzCore
0x324cbe64 0x324ae000 + 122468
CoreFoundation
0x3244f4bc 0x323f8000 + 357564
CoreFoundation
0xx323f8000 + 355352
GraphicsServices
0x342e91c0 0x342e5000 + 16832
0x331b5c28 0x331b2000 + 15400
0x331bb2000 + 8744
TestEditor
0xx1000 + 7226
TestEditor
0xx1000 + 7172
... (以下略)
虽然我们看到了出为题时的堆栈信息,但是因为没有符号信息,仍然不知道到底哪里出问题了...
编译调试相关的符号信息都被包含在编译时的 xxxx.app.dSYM 文件当中,所以我们在发布程序前将它们保存起来,调试Crash问题的时候会很有用。
首先,我们来找到该文件。
用Xcode编译的程序,在其编译目录下都会生成 [程序名].app.dSMY 文件,比如 Xcode 4 的编译目录缺省的是
~Library/Developer/Xcode/DerivedData
# 在改目录下搜寻编译后的.dSMY文件
$ cd ~/Library/Developer/Xcode/DerivedData
$ find . -name '*.dSYM'
另外,我们也可以通过 Xcode的Preferences... -& Locations -& Locations 的Derived Data来确认该目录的位置。
上面例子中的程序,我们就找到了其位置是
~/Library/Developer/Xcode/DerivedData/TestEditor-aahmlrjpobenlsdvhjppcfqhogru/ArchiveIntermediates/TestEditor/BuildProductsPath/Release-iphoneos/TestEditor.app.dSYM
※ 大家每次像App Store发布自己程序的时候都记着保存该文件哦,要不然出现Crash的时候,就无从下手了。
解决符号问题
接下来,我们再来介绍一下使用.dSYM文件来恢复程序符号的方法。
首先,使用一个Xcode提供的叫做 symbolicatecrash 的小工具,它可以实现我们在CrashLog中添加符号信息的机能。该文件位于下面的位置,为方便起见,可以把它拷贝到系统默认路径下。
Xcode4.3.1的位置好像在这 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/DTDeviceKit.framework/Versions/A/Resources/symbolicatecrash
/Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/DTDeviceKit.framework/Versions/A/Resources/symbolicatecrash
$ sudo cp /Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/DTDeviceKit.framework/Versions/A/Resources/symbolicatecrash /usr/local/bin
使用下面的命令,可以在终端输出有符号信息的CrashLog
$ symbolicatecrash [CrashLog file] [dSYM file]
$ symbolicatecrash TestEditor_-454678_iPhone1.crash TestEditor.app.dSYM
Thread 0 Crashed:
0x332b98d8 -[UIWindowController transitionViewDidComplete:fromView:toView:] + 668
0x -[UITransitionView notifyDidCompleteTransition:] + 160
0x -[UITransitionView _didCompleteTransition:] + 704
0x332b9628 -[UITransitionView _transitionDidStop:finished:] + 44
0x33209d70 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 284
0x33209c08 -[UIViewAnimationState animationDidStop:finished:] + 60
QuartzCore
0x324cc05c _ZL23run_animation_callbacksdPv + 440
QuartzCore
0x324cbe64 _ZN2CAL14timer_callbackEP16__CFRunLoopTimerPv + 156
CoreFoundation
0x3244f4bc CFRunLoopRunSpecific + 2192
CoreFoundation
0x3244ec18 CFRunLoopRunInMode + 44
GraphicsServices
0x342e91c0 GSEventRunModal + 188
0x331b5c28 -[UIApplication _run] + 552
0x331b4228 UIApplicationMain + 960
TestEditor
0x00002c3a main (main.m:14)
TestEditor
0xx1000 + 7172
由此,我们可以具体定位程序中出问题的地方。
用StackTrace取得崩溃时的日志
异常处理机制
任何语言都有异常的处理机制,Objective-C也不例外。与C++/Java类似的语法,它也提供@try, @catch, @throw, @finally关键字。使用方法如下。
@catch (CustomException *ce) {
@catch (NSException *ne) {
// Perform processing necessary at this level.
@catch (id ue) {
@finally {
// Perform processing necessary whether an exception occurred or not.
同时对于系统Crash而引起的程序异常退出,可以通过UncaughtExceptionHandler机制捕获;也就是说在程序中catch以外的内容,被系统自带的错误处理而捕获。我们要做的就是用自定义的函数替代该ExceptionHandler即可。
这里主要有两个函数
NSGetUncaughtExceptionHandler() 得到现在系统自带处理Handler;得到它后,如果程序正常退出时用来回复系统原先设置
NSSetUncaughtExceptionHandler() 红色设置自定义的函数
简单的使用例子如下所示
void MyUncaughtExceptionHandler(NSException *exception)
printf("uncaught %s\n", [[exception name] cString]);
// 显示当前堆栈内容
NSArray *callStackArray = [exception callStackReturnAddresses];
int frameCount = [callStackArray count];
void *backtraceFrames[frameCount];
for (int i=0; i&frameC i++) {
backtraceFrames[i] = (void *)[[callStackArray objectAtIndex:i] unsignedIntegerValue];
int main()
NSUncaughtExceptionHandler *ueh = NSGetUncaughtExceptionHandler();
NSSetUncaughtExceptionHandler(&MyUncaughtExceptionHandler);
- (void)exit_processing:(NSNotification *)notification {
NSSetUncaughtExceptionHandler(ueh);
- (void)viewDidLoad {
// 这里重载程序正常退出时UIApplicationWillTerminateNotification接口
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(exit_processing:)
name:UIApplicationWillTerminateNotification
object:app]
处理signal
使用Objective-C的异常处理是不能得到signal的,如果要处理它,我们还要利用unix标准的signal机制,注册SIGABRT, SIGBUS, SIGSEGV等信号发生时的处理函数。该函数中我们可以输出栈信息,版本信息等其他一切我们所想要的。
例子代码如下
#include &signal.h&
void stacktrace(int sig, siginfo_t *info, void *context)
[mstr appendString:@"Stack:\n"];
void* callstack[128];
int i, frames = backtrace(callstack, 128);
char** strs = backtrace_symbols(callstack, frames);
for (i = 0; i &; ++i) {
[mstr appendFormat:@"%s\n", strs[i]];
int main(int argc, char *argv[])
struct sigaction mySigA
mySigAction.sa_sigaction =
mySigAction.sa_flags = SA_SIGINFO;
sigemptyset(&mySigAction.sa_mask);
sigaction(SIGQUIT, &mySigAction, NULL);
sigaction(SIGILL , &mySigAction, NULL);
sigaction(SIGTRAP, &mySigAction, NULL);
sigaction(SIGABRT, &mySigAction, NULL);
sigaction(SIGEMT , &mySigAction, NULL);
sigaction(SIGFPE , &mySigAction, NULL);
sigaction(SIGBUS , &mySigAction, NULL);
sigaction(SIGSEGV, &mySigAction, NULL);
sigaction(SIGSYS , &mySigAction, NULL);
sigaction(SIGPIPE, &mySigAction, NULL);
sigaction(SIGALRM, &mySigAction, NULL);
sigaction(SIGXCPU, &mySigAction, NULL);
sigaction(SIGXFSZ, &mySigAction, NULL);
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return (retVal);
综上所述,我们可以看到用StackTrace取得崩溃时日志的手顺如下
用NSGetUncaughtExceptionHandler()取得当前系统异常处理Handler
用NSSetUncaughtExceptionHandler()注册自定义异常处理Handler
注册signal处理机制
注册Handler中打印堆栈,版本号等信息
必要的时候将其保存到dump.txt文件
异常程序退出
如果程序不是异常退出,则还原之前系统的异常处理函数句柄
如果下次程序启动,发现有dump.txt的异常文件,启动邮件发送报告机制
整体的代码框架如下
#include &signal.h&
void stacktrace(int sig, siginfo_t *info, void *context)
[mstr appendString:@"Stack:\n"];
void* callstack[128];
int i, frames = backtrace(callstack, 128);
char** strs = backtrace_symbols(callstack, frames);
for (i = 0; i &; ++i) {
[mstr appendFormat:@"%s\n", strs[i]];
void MyUncaughtExceptionHandler(NSException *exception)
printf("uncaught %s\n", [[exception name] cString]);
// 显示当前堆栈内容
NSArray *callStackArray = [exception callStackReturnAddresses];
int frameCount = [callStackArray count];
void *backtraceFrames[frameCount];
for (int i=0; i&frameC i++) {
backtraceFrames[i] = (void *)[[callStackArray objectAtIndex:i] unsignedIntegerValue];
int main(int argc, char *argv[])
struct sigaction mySigA
mySigAction.sa_sigaction =
mySigAction.sa_flags = SA_SIGINFO;
sigemptyset(&mySigAction.sa_mask);
sigaction(SIGQUIT, &mySigAction, NULL);
sigaction(SIGILL , &mySigAction, NULL);
sigaction(SIGTRAP, &mySigAction, NULL);
sigaction(SIGABRT, &mySigAction, NULL);
sigaction(SIGEMT , &mySigAction, NULL);
sigaction(SIGFPE , &mySigAction, NULL);
sigaction(SIGBUS , &mySigAction, NULL);
sigaction(SIGSEGV, &mySigAction, NULL);
sigaction(SIGSYS , &mySigAction, NULL);
sigaction(SIGPIPE, &mySigAction, NULL);
sigaction(SIGALRM, &mySigAction, NULL);
sigaction(SIGXCPU, &mySigAction, NULL);
sigaction(SIGXFSZ, &mySigAction, NULL);
NSUncaughtExceptionHandler *ueh = NSGetUncaughtExceptionHandler();
NSSetUncaughtExceptionHandler(&MyUncaughtExceptionHandler);
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return (retVal);
- (void)exit_processing:(NSNotification *)notification {
NSSetUncaughtExceptionHandler(ueh);
- (void)viewDidLoad {
// 这里重载程序正常退出时UIApplicationWillTerminateNotification接口
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(exit_processing:)
name:UIApplicationWillTerminateNotification
object:app]
输入的CrashLog如下
TestEditor 0x0006989d dump + 64
TestEditor 0x00069b4b signalHandler + 46
libSystem.B.dylib 0x31dcd60b _sigtramp + 26
TestEditor 0x -[PopClientcreateUnreadMessageWithUIDL:maxMessageCount:] + 76
TestEditor 0x00025b85 -[PopClientgetUnreadIdList:] + 348
TestEditor 0x000454dd -[Connection receiveMessages:] + 688
TestEditor 0x00042db1 -[Connection main] + 188
Foundation 0x __NSThread__main__ + 858
libSystem.B.dylib 0x31d6a5a8 _pthread_body + 28
AppVer:TestEditor 1.2.0
System:iPhone OS
OS Ver:3.0
Model:iPhoneDate:09/06/08 21:25:59JST
其中从_sigtramp函数下面开始进入我们的程序,即地址0x开始。其所对应的具体文件名和行号我们能知道吗?
利用之前介绍的dSYM文件和gdb,我们可以得到这些信息。
cd $PROJ_PATH$/build/Release-iphoneos/TestEditor.app.dSYM/
cd Contents/Resources/DWARF
gdb TestEditor
gdb&info line *0x
Line 333 of "~/IbisMail/Classes/Models/PopClient.m";
starts at address 0x2a386 &-[PopClient retrieve:]+86& and
ends at 0x2a390 &-[PopClient retrieve:]+96&
致力于开发简洁,实用,界面可交互性优秀的手机应用软件 IOS Andriod WP7 / 承接移动应用开发
原文地址:, 感谢原作者分享。
您可能感兴趣的代码iOS崩溃日志crash&logs追踪以及调试方法
&在IOS程序开发和以及在真机运行程序时,经常会遇到程序crash的情况,从哪里可以获得crash的日志文件,以便更好的分析程序崩溃的原因,让应用更加完美。
&在真机运行程序出现crash状况时,机器会自动产生log文件,它包含了在程序crash之前正在做什么的信息。在pc上对手机或者ipad设备进行同步,就可以将这些日志文件存储在电脑中。下面时如何找到这些日志文件:
1.同步你的移动设备;
2.浏览下面的文件夹,这里假设在iTunes中你的设备显示名称为DEVICE_NAME。那么日志文件的路径为:
Mac OS X : ~/Library/Logs/CrashReporter/MobileDevice/
Windows XP: C:\Documents and Settings\\Application Data\Apple computer\Logs\CrashReporter\\
Windows Vista: C:\Users\\AppData\Roaming\Apple computer\Logs\CrashReporter\MobileDevice\\
3.每个日志文件都是以应用的名称开头。你可以将日志文件打包给开发者,以便开发者及时改进程序。
如何debug程序参见iphone参考文档。
&而在开发程序过程也会出现程序crash的情况,那么这时生成的文件目录为:
~/Library/Logs/DiagnosticReports/
在该目录下有以.crash扩展名后缀的文件。
除了上面在出现崩溃后的查找crash的原因,而在程序编写调试的过程经常用到的调试手法为NSLog方法,打印出出错信息。但是,在iPhone
应用发布后,程序运行过程中尽量不要有调试 log 信息输出,因为这样会影响程序运行的效率。因此可以通过宏定义设置,使程序只在
debug 模式下输出对我们有用的信息, release 时不会输出。 具体步骤如下:
1、首先建立一个宏定义文件,文件内容如下:&
#if DEBUG&
#define debuglog(format, ...)&&
NSLog(format, __VA_ARGS__)&
#define debuglog(format, ...)&
2,打开project--&Build setting选项,在下面找LLVM
GCC4.2-preprocessing下面的-preprocessor macros &下一级
Debug中设置DEBUG=1 。
这样我们就可以做到log调试信息在release时不会输出,更好的提高应用性能。
如何编写高质量的代码可以参见&。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。iOS日常Debug之Crash日志文件分析 - ShebingYang的博客 - CSDN博客
iOS日常Debug之Crash日志文件分析
Objective-C
好久没写博客了,真的不是忙没有时间。就是懒!闲话少说,言归正传。事件起因,群里一个朋友说自己的app被拒了,苹果给的被拒原因是AppStore审核指南条例2.1,说是app存在崩溃。还附带上了Crash日志文件。看了一眼Crash日志文件,彻底懵了!
What?(此处略过一句脏话)
一、查看Crash日志文件信息
看到这种东西,我第一反应就是跑去看!
Incident Identifier:crash报告的唯一标识符。
CrashReporter Key:每台设备的匿名标识符。
Hardware Model:crash产生的设备类型
OS Version:设备操作系统版本
Exception Type:crash异常类型
Exception Codes:crash异常错误码
Exception Note:crash异常附加信息
Triggered by Thread:异常产生的线程。
Last Exception Backtrace:最后的异常回溯
然并卵,有了这些信息还是看不懂啊!难道是打开方式不对?
二、开始分析
我们可以用Xcode自带的symbolicatecrash工具分析.crash文件
1、找到Xcode自带的symbolicatecrash工具路径:
/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash
2、找到苹果公司反馈的crash日志文件(我这里只有一个链接,我直接把链接里面的crash日志内容保存成了一个.crash文件“XX.crash”)
3、找到崩溃app对应的dSYM文件。(别人直接发了崩溃app的xcarchive文件给我,.dSYM文件就在xcarchive文件的dSYMs文件夹下的“XX.app.dSYM”)
4、在终端执行以下命令:
symbolicatecrash路径 XX.crash(苹果公司给的crash日志文件路径) XX.app.dSYM(崩溃app对应的dSYM文件路径) & 输出文件路径
如果在执行命令的过程中会出现错误信息:“Error: “DEVELOPER_DIR” is not defined at /Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash line 69.”
解决方案:
在终端执行export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
执行完成后,再执行第4步。
第4步执行具体过程如下图所示:
三、分析结果
经过以上4步之后,我们可以在打开桌面上生成的crash文件(我的输出路径是”~/desktop/exam.crash”)。
这样是不是思路就清晰了很多?接下来定位bug就看你的了!
本文内容中部分参考网络资料,后续会不断更新完善。欢迎一起学习交流!
四、参考文章地址:
我的热门文章/videos/wwdc/2010/?id=317
/smileEvday/p/Crash1.html
/industry/7.html &&
/tiechui/p/3820044.html (/library/ios/#technotes/tn2151/_index.html)
  当一个应用程序在一台iOS&设备上崩溃时,一份&崩溃报告&将在该设备上次创建并存储起来。崩溃报告描述应用程序是在何种条件下崩溃的,大部分情况下包含一份当前正在运行线程的完整的堆栈跟踪。
产生崩溃日志的原因
应用违反操作系统规则,包括在启动、恢复、挂起、退出时watchdog超时、用户强制退出和低内存终止等。
应用中有Bug
  从多任务窗口中终止一个暂停的应用程序不会产生崩溃日志。一旦一个应用被暂停,它有资格被iOS在任何时间终止,因此不会产生崩溃日志。
Crash获取途径
本机通过Xcode的Devices窗口获取某个设备的崩溃日志
设备与电脑上的iTunes Store同步后,会将崩溃日志保存在电脑上。根据电脑操作系统的不同,崩溃日志将保存在以下位置:
Mac OS X: & & & & & & & ~/Library/Logs/CrashReporter/MobileDevice/
Windows XP: & & & & & &C:/Documents and Settings/Application Data/Apple Computer/Logs/CrashReporte/rMobileDevice/
Windows Vista以上: & C:/Users/用户名/AppData/Roaming/Apple&Computer/Logs/CrashReporter/MobileDevice/
应用提交到App Store后,可通过itunes connect后台获取到用户上报的Crash日志。
有很多优秀的第三方Crash收集系统大大的方便了我们收集Crash,甚至还带了符号化Crash日志的功能。比较常用的有,等。
Crash文件结构
1.Process Information
Incident Identifier: 66AFBBF0-7ACB--6F44E09FF9EB
//崩溃报告的唯一标识符
CrashReporter Key:
97aecc0d1cfdfc17c1b8c86ba4c5
//设备标识相对应的唯一键值(并非真正的设备的UDID,为保护隐私iOS6以后已无法获取)
Hardware Model:
//发生Crash的设备类型
XXXXClient [407]
           
//Crash的进程名称,通常都是我们的App的名字, []里面是当时进程的ID
/private/var/mobile/Containers/Bundle/Application/A40--7E1F3E3D4FCA/XXXXClient.app/XXXXClient
            //可执行程序在手机上的存储位置,注意路径时到x.app/x,x.app其实是作为一个Bundle的,真正的可执行文件其实是Bundle里面的x
Identifier:
com.xxxx.myapp
//App的Indentifier,通常为&com.xxx.yyy&
//App的版本号,由Info.plist中CFBundleShortVersionString + CFBundleVersion
Code Type:
ARM-64 (Native)                
//App的CPU架构
Parent Process:
launchd [1]
//当前进程的父进程,由于iOS中App通常都是单进程的,一般父进程都是launchd
2.Basic Information
Date/Time:
00:34:43.449 -0800
//Crash发生的时间
Launch Time:
00:34:43.399 -0800
OS Version:
iOS 8.4 (12H143)
//系统版本,括号内的数字代表的时Bulid号
Report Version:
//Crash日志的格式
3.Exception
Exception Type:
  EXC_CRASH (SIGABRT)
//异常类型Exception Subtype:
Exception Codes:   0x0
Triggered by Thread: 0
//v105Crashed Thread
&4.Thread Backtrace
发生Crash的线程的Crash调用栈,从上到下分别代表调用顺序,最上面的一个表示抛出异常的位置,依次往下可以看到API的调用顺序。
Thread 0 name:
Dispatch queue: com.apple.main-thread
Thread 0 Crashed://编号
二进制库名
调用方法的地址
基本地址 + 偏移
libsystem_kernel.dylib
0xb3b270 __pthread_kill + 8
libsystem_pthread.dylib
0xbd916c pthread_kill + 108
libsystem_c.dylib
0xab2b14 abort + 108
...g_rt.asan_ios_dynamic.dylib 0x56d0 0x + 333520
...g_rt.asan_ios_dynamic.dylib 0x955c 0x + 283996
...g_rt.asan_ios_dynamic.dylib 0xcf28 0x + 298792
...g_rt.asan_ios_dynamic.dylib 0x224000 + 284224
...g_rt.asan_ios_dynamic.dylib 0xd0e8 0x + 299240
...g_rt.asan_ios_dynamic.dylib 0xef50 0x + 241488
...g_rt.asan_ios_dynamic.dylib 0x8d18 0x + 281880
0xb9234 ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) + 256
0xb93ec ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) + 32
0xb5688 ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 328
0xb561c ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 220
0xb54d8 ImageLoader::processInitializers(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 136
0xb57a0 ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) + 80
0xaa150 dyld::initializeMainExecutable() + 196
0xad8bc dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) + 2664
0xa9040 _dyld_start + 64
5.Thread State
Crash时发生时刻,线程的状态(寄存器中的值)
Thread 0 crashed with ARM Thread State (64-bit):
x0: 0x0000
x1: 0x0000
x2: 0x0000
x3: 0x0000
x4: 0x027b
x5: 0x0000
x6: 0x0000
x7: 0x0250
x8: 0x0000
x9: 0x0000
x10: 0x0000
x11: 0x0018
x12: 0x0001
x13: 0x2aa8
x14: 0x0015
x15: 0x0000
x16: 0x0148
x17: 0x0000
x18: 0x0000
x19: 0x0006
x20: 0xae4310
x21: 0x0963
x22: 0x0000
x23: 0x0000
x24: 0x0093
x25: 0xfd182d8
x26: 0xd8d11
x27: 0xc000
x28: 0x43d0
fp: 0xfd17920
lr: 0xbd9170
sp: 0xfd17900
pc: 0xb3b270 cpsr: 0x
6.Binary Images
Crash时刻App加载的所有的库,其中第一行是Crash发生时我们App可执行文件的信息,可以看出为armv7,可执行文件的包得uuid位c0f&&cd65,解析Crash的时候dsym文件的uuid必须和这个一样才能完成Crash的符号化解析。
Binary Images:
0x - 0x101fdffff XXXClient arm64
&aa8ef7e9f9c43c7c87f4f75cf266d479& /var/mobile/Containers/Bundle/Application/A40--7E1F3E3D4FCA/XXXXClient.app/XXXXClient
0x - 0x103287fff libclang_rt.asan_ios_dynamic.dylib arm64
&c3a8e9b6c2b& /var/mobile/Containers/Bundle/Application/A40--7E1F3E3D4FCA/XXXX.app/Frameworks/libclang_rt.asan_ios_dynamic.dylib
0x - 0x1200cffff dyld arm64
&de589ea6cf724cb236d83c& /usr/lib/dyld
0x - 0x181240fff AVFoundation arm64
&b9c4b32ba43a3a798c4adcaad3608f52& /System/Library/Frameworks/AVFoundation.framework/AVFoundation
0x - 0x1812a8fff libAVFAudio.dylib arm64
&f1d6b79062e1& /System/Library/Frameworks/AVFoundation.framework/libAVFAudio.dylib
0x194bf0000 - 0x194bf5fff libunwind.dylib arm64
&8b69a95e75457cadba3e& /usr/lib/system/libunwind.dylib
0x194bf8000 - 0x194c1bfff libxpc.dylib arm64
&c9f3c08a8a3b& /usr/lib/system/libxpc.dylib
包含堆栈跟踪的崩溃报告需要先进行符号化(symbolicated)才可以进行分析。符号化的过程是将内存地址替换为便于人们阅读的函数名称和行号。假如你通过Xcode的Organizer窗口获取崩溃日志,那么该报告将在几秒钟后自动进行符号化。否则你需要将.crash文件导入到Xcode的Organizer进行符号化。
//符号化前
Rage Masters
0x0001625c
0x2a000 + 3003
//符号化后
Rage Masters
0x0001625c
-[RMAppDelegate application:didFinishLaunchingWithOptions:]
(RMAppDelegate.m:35)
符号化与归档
  Xcode符号化崩溃日志时,需要访问与App Store上对应的应用二进制文件以及生成二进制文件时产生的 .dSYM 文件。必需完全匹配才行。否则,日志将无法被完全符号化。所以,保留每个分发给用户的编译版本非常重要。提交应用前进行归档时,Xcode将保存应用的二进制文件。可以在Xcode Organizer的Archives标签栏下找到所有已归档的应用文件。在发现崩溃日志时,如果有相匹配的.dSYM文件和应用二进制文件,Xcode会自动对崩溃日志进行符号化。如果你换到别的电脑或创建新的账户,务必将所有二进制文件移动到正确的位置,使Xcode能找到它们。
(注意:&你必需同时保留应用二进制文件和.dSYM文件才能将崩溃日志完整符号化。每次提交到iTunes Connect的构建都必需归档。.dSYM文件和二进制文件是特定绑定于每一次构建和后续构建的,即使来自相同的源代码文件,每一次构建也与其他构建不同,不能相互替换。如果你使用Build 和 Archive 命令,这些文件会自动放在适当位置。 如果不是使用Build 和 Archive命令,放在Spotlight能够搜索到的位置(比如Home目录)即可。)
&&&&&&在崩溃报告中最令人感兴趣的部分是在你的应用程序执行终止时的堆栈跟踪。这个跟踪和你在调试器中停止执行时的类似,但遗憾的是这里没有提供被认为是符号的方法或函数的名称。取而代之的是16位的内存地址和它所指向的你的应用程序或系统框架的可执行代码。你需要将这些地址映射到符号中。崩溃日志在输出时并不包含土豪信息,你需要在你分析日志前进行符号化处理。
&&&&&&符号化&&将堆栈跟踪地址转化为源代码方法名称及行号&&需要上次到苹果应用商店的应用程序的二进制文件以及构建二进制文件时产生的.dSYM文件。这些必须是精确匹配的,否则你的报告将不能完整地符号化。基本要求你保持每个分发给用户(忽略那些分发的细节)的构建和它的.dSYM是一致的。
&&&&&&注意:
&&&&&&你必须保存应用程序的二进制文件和.dSYM文件以便于完整地符号化崩溃日志。你应该打包每一个你所提交到iTunes Connect中的构建。.dSYM文件和应用程序的二进制文件应该绑定到一起,不管是基础版本的构建还是后续版本的构建。即便是相同的源代码,不同构建的文件也不会弄混。假如你使用&构建并打包&命令,那么它们将会被自动放置到一个合适的位置。虽然任何位置都可以用Spotlight搜索到。
&&&&& Xcode的&打包(Archive)&命令使保持二进制文件和.dSYM匹配变得很简单,当你使用打包命令(通过点击产品(&Product&)-)打包(Archive)或是按下Shift+Command+B),Xode将会把应用程序的二进制文件及包含符号信息的.dSYM文件收集到一起,并存储到你的主目录文件夹下的一个合适位置。你可以在Xcode中的Organizer下的&已打包(Archived)&中知道你所打包的所有应用程序。Xcode在符号化崩溃日志时会自动寻找打包的应用程序,在确认你要的发布应用程序和.dSYM文件匹配的情况下,你可以将它们打包,直接提交到ITunes Connect。
&&&&&&如果Xcode拥有产生崩溃日志的应用程序的二进制代码和.dSYM文件,那么它将自动进行符号化。Xcode Organizer符号化所需要提供的是崩溃日志及相应的二进制文件和.dSYM文件。打开Xcode Organizer,选择&设备(Devices)&选选看,选择边栏顶部&文库(LIBRARY)&下的&设备日志(Device Logs)&,点击导入按钮,选择需要符号化的.crash文件,当这些步骤完成后,Xcode将自动符号化崩溃日志并显示结果。
常见Crash类型
0x8badf00d(eat bad food) & &Watchdog timeout
紧接着下面会有一段描述:
Application Specific Information:
com.xxx.yyy   failed to resume in time
该应用程序花了太长的时间加载,终止或响应系统时间。如果你没有把需要花费时间比较长的操作(如网络访问)放在后台线程上就很容易发生这种情况。
从iOS 4.x开始,退出应用时,应用不会立即终止,而是退到后台。但是,如果你的应用响应不够快,操作系统有可能会终止你的应用,并产生一个崩溃日志。下面这些方法,应用只有有限的时间去完成处理。如果花费时间太长,操作系统将终止应用。
application:didFinishLaunchingWithOptions:
applicationWillResignActive:
applicationDidEnterBackground:
applicationWillEnterForeground:
applicationDidBecomeActive:
applicationWillTerminate:
后面的分号说明只有一个参数
对于此类Crash,我们应该去审视自己App初始化时做的事情是否正确,是否在主线程请求了网络,或者其他耗时的事情卡住了正常初始化流程。
通常系统允许一个App从启动到可以相应用户事件的时间最多为5S,如果超过了5S,App就会被系统终止掉。在Launch,resume,suspend,quit时都会有相应的时间要求。在Highlight Thread里面我们可以看到被终止时调用到的位置,xxxAppDelegate加上行号。&
PS. 在连接Xcode调试时为了便于调试,系统会暂时禁用掉Watchdog,所以此类问题的发现需要使用正常的启动模式。
0xdeadfa11(dead fall) &User force-quit
  这个强制退出跟我们平时所说的kill掉后台任务操作还不太一样,通常在程序bug造成系统无法响应时可以采用长按电源键,当屏幕出现关机确认画面时按下Home键即可关闭当前程序。
  双击Home按钮后,你将看到运行过的所有应用。那些应用不一定是正在运行,也不一定是被挂起。&通常,用户点击Home按钮时,应用将在后台保留约10分钟,然后操作系统自动将其终止。 所以双击Home按钮显示的应用列表只是表明那是一系列过去打开过的应用。删除那些应用的图标不会产生任何崩溃日志。
0xbaaaaaad
该Crash log并非一个真正的Crash,它仅仅只是包含了整个系统某一时刻的运行状态。通常可以通过同时按Home键和音量键,可能由于用户不小心触发
0xbad22222
当VOIP程序在后台太过频繁的激活时,系统可能会终止此类程序
0xc00010ff
程序执行大量耗费CPU和GPU的运算,导致设备过热,触发系统过热保护被系统终止
0xdead10cc
程序退到后台时还占用系统资源,如通讯录被系统终止
Low Memory termination
跟一般的Crash结构不太一样,通常有Free pages,Wired Pages,Purgeable pages,largest process 组成,同时会列出当前时刻系统运行所有进程的信息。
App在运行过程中,系统内存紧张时通常会先发警告(子类化UIViewController时,你或许已经注意到didReceiveMemoryWarning方法),同时把后台挂起的程序终止掉,最终如果还是内存不够的话就会终止掉当前前台的进程。
当接受到内存警告的事后,我们应该释放尽可能多的内存,Crash其实也可以看做是对App的一种保护。
&当监测到内存不足时,iOS的虚拟内存系统依靠应用程序间的合作来释放内存。内存不足的通知被发送到所有正在运行的应用程序,并作为内存释放的请求来进行处理,以期望降低所使用的内存总量。如果内存的压力始终存在,那么系统可能会终止一些后台进程来降低内存压力。如果可以释放足够多的内存,那么你的应用程序将继续运行而不会产生崩溃报告。如果不可以,那么你的程序将被iOS终止,因为此时已没有足够的内存来满足应用程序的需求,一份内存不足的报告将被产生并存储在设备中。
&&&&&&内存不足报告与其他崩溃报告的不同之处在于它里面没有应用程序的堆栈跟踪。每个进程的内存使用量依据内存页面的数量进行报告,每个内存页面量的大小为4KB。你将会看到&抛弃(jettisoned)&紧跟在iOS为了释放内存而终止的进程名称后。如果你看到它紧跟在你的应用程序名称后面,那么可以确定这个应用因为使用了太多的内存而被终止。否则,应该不是内存压力引起的崩溃。你可以通过查看.crash文件(下一节中进行描述)获取更多信息。
&&&&&&当你看到一个内存不足报告时,你更应该研究一下你使用内存的方式和你对内存不足警告的处理方式,而不是去关心在程序终止时你的哪一部分代码被执行了。内存分配帮助()列举了如何使用泄露工具(Leaks Instrument)来发现内存泄露,以及如何使用分配工具(Allocations Instrument's)的标记堆功能来避免被抛弃的内存。内存使用性能指导方案()讨论了像其他内存使用秘诀一样的适当的方案来响应内存不足通知。同时也建议你看一下WWSC2010中的关于使用工具进行高效内存分析的视频()。
  泄露和分配工具不能跟踪显存。你需要使用VM Tracker工具(包含在分配工具模板中)来运行你的应用以便观察显存的使用情况。VM Tracker默认是禁用的。为了在你的应用程序使用VM Tracker,请点击工具,选中&自动快照Automatic Snapshotting&标志或者手工按下&获取快照(Snapshot Now)&按钮。
当应用发生低内存闪退时,你必需看看应用中内存使用的方式,以及是如何处理低内存警告的。你可以使用Instruments工具中使用Allocations 和 Leaks来发现内存分配问题和内存泄漏问题。如果你不知道如何利用 Instruments 检查内存问题,可以看看这个教程 。
还有,别忘记虚拟内存! Instruments工具的Leaks 和 Allocations 不能跟踪显存使用情况。必需使用 VM Tracker 才能查看显存使用情况。
VM Tracker 默认是关闭的。打开Instrument,手动 选中Automatic Snapshotting 标志或者按下Snapshot Now 按钮。
当内存使用达到一定程度时,操作系统将发出一个 UIApplicationDidReceiveMemoryWarningNotification&通知。同时,调用 didReceiveMemoryWarning 方法。
此时,为了让应用继续正常运行,操作系统开始终止在后台的其他应用以释放一些内存。所有后台应用被终止后,如果你的应用还需要更多内存,操作系统会将你的应用也终止掉,并产生一个崩溃日志。而在这种情况下被终止的后台应用,不会产生崩溃日志。
在极短时间内分配一大块内存将给系统内存带来巨大负担。这样,也会产生内存警告的通知。
低内存崩溃日志上没有应用线程的堆栈回溯。相反,上面显示的是以内存页数为单位的各进程内存使用量。
被iOS因释放内存页终止的进程名称后面你会看到jettisoned 字样。如果看到它出现在你的应用名称后面,说明你的应用因使用太多内存而被终止了。
Free Pages & &可用内存页数(每页大约4KB)
Purgeable pages & 可被清除重用的内存
Largest process &闪退时使用大部分内存的应用
Processes显示了闪退时各进程列表,还包含内存使用量。包含进程名 (第一列), 进程唯一标识符(第二名), 进程使用的内存页数(第三列)。最后一列是每个应用的状态。通常,发生闪退的应用的状态是 frontmost。
&SpringBoard 进程是显示主屏幕的应用
Crash due to bugs
常见Exception Type
EXC_BAD_ACCESS &通常用于访问了不改访问的内存导致。一般EXC_BAD_ACCESS后面的"()"还会带有补充信息。
SIGSEGV: 通常由于重复释放对象导致,这种类型在切换了ARC以后应该已经很少见到了。
SIGABRT: &收到Abort信号退出,通常Foundation库中的容器为了保护状态正常会做一些检测,例如插入nil到数组中等会遇到此类错误。
SEGV:(Segmentation &Violation),代表无效内存地址,比如空指针,未初始化指针,栈溢出等;
SIGBUS:总线错误,与 SIGSEGV 不同的是,SIGSEGV 访问的是无效地址,而 SIGBUS 访问的是有效地址,但总线访问异常(如地址对齐问题)
SIGILL:尝试执行非法的指令,可能不被识别或者没有权限
异常代码是SIGABRT。通常, &SIGABRT 异常是由于某个对象接收到未实现的消息引起的。 或者,用简单的话说,在某个对象上调用了不存在的方法。
这种情况一般不会发生,因为A对象调用了B方法,如果B方法不存在,编译器会报错。但是,如果你是使用selector间接调用方法的,编译器则无法检测对象是否存在该方法了。
EXC_BAD_INSTRUCTION
  此类异常通常由于线程执行非法指令导致
EXC_ARITHMETIC
  除零错误会抛出此类异常
&------------------------------
AddressSenitizer引发的崩溃
iOS9可以正常启动。
iOS9以下版本设备连接调试可以正确启动,断开调试后启动崩溃,日志如下
Exception Type:
EXC_CRASH (SIGABRT)
Exception Codes: 0x0000, 0x0000
Triggered by Thread:
Thread 0 name:
Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
libsystem_kernel.dylib
0x7270 __pthread_kill + 8
libsystem_pthread.dylib
0xe516c pthread_kill + 108
libsystem_c.dylib
0xbeb14 abort + 108
...g_rt.asan_ios_dynamic.dylib
0xd56d0 0x + 333520
...g_rt.asan_ios_dynamic.dylib
0xc955c 0x + 283996
...g_rt.asan_ios_dynamic.dylib
0xccf28 0x + 298792
...g_rt.asan_ios_dynamic.dylib
0xc9640 0x + 284224
...g_rt.asan_ios_dynamic.dylib
0xcd0e8 0x + 299240
...g_rt.asan_ios_dynamic.dylib
0xbef50 0x + 241488
...g_rt.asan_ios_dynamic.dylib
0xc8d18 0x + 281880
0x5234 ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) + 256
0x53ec ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) + 32
0x1688 ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 328
0x161c ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 220
0x14d8 ImageLoader::processInitializers(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 136
0x17a0 ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) + 80
0x6150 dyld::initializeMainExecutable() + 196
0x98bc dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) + 2664
0x5040 _dyld_start + 64
&XCode 7 give use new opportunity AddressSenitizer!
&DISABLE it's if you want run app without connected device to debug XCode mode.
更多关于AddressSenitizer
/ios/94.html
/xitang/p/4904405.html
阅读(...) 评论()}

我要回帖

更多关于 crashlog 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信