CatNiP prefinal
Sähköinen nuottikirja, HY-TKTKL-OHTUPROJ KESÄ11
|
00001 00002 00003 00004 00005 00006 00007 00008 00009 00010 00011 00012 00013 #import "UncaughtExceptionHandler.h" 00014 #include <libkern/OSAtomic.h> 00015 #include <execinfo.h> 00016 00017 NSString * const UncaughtExceptionHandlerSignalExceptionName = @"UncaughtExceptionHandlerSignalExceptionName"; 00018 NSString * const UncaughtExceptionHandlerSignalKey = @"UncaughtExceptionHandlerSignalKey"; 00019 NSString * const UncaughtExceptionHandlerAddressesKey = @"UncaughtExceptionHandlerAddressesKey"; 00020 00021 volatile int32_t UncaughtExceptionCount = 0; 00022 const int32_t UncaughtExceptionMaximum = 10; 00023 00024 const NSInteger UncaughtExceptionHandlerSkipAddressCount = 4; 00025 const NSInteger UncaughtExceptionHandlerReportAddressCount = 5; 00026 00027 @implementation UncaughtExceptionHandler 00028 00029 + (NSArray *)backtrace 00030 { 00031 void* callstack[128]; 00032 int frames = backtrace(callstack, 128); 00033 char **strs = backtrace_symbols(callstack, frames); 00034 00035 int i; 00036 NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames]; 00037 for ( 00038 i = UncaughtExceptionHandlerSkipAddressCount; 00039 i < UncaughtExceptionHandlerSkipAddressCount + 00040 UncaughtExceptionHandlerReportAddressCount; 00041 i++) 00042 { 00043 [backtrace addObject:[NSString stringWithUTF8String:strs[i]]]; 00044 } 00045 free(strs); 00046 00047 return backtrace; 00048 } 00049 00050 - (void)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex 00051 { 00052 if (anIndex == 0) 00053 { 00054 dismissed = YES; 00055 } 00056 } 00057 00058 - (void)validateAndSaveCriticalApplicationData 00059 { 00060 00061 } 00062 00063 - (void)handleException:(NSException *)exception 00064 { 00065 [self validateAndSaveCriticalApplicationData]; 00066 00067 UIAlertView *alert = 00068 [[[UIAlertView alloc] 00069 initWithTitle:NSLocalizedString(@"Unhandled exception", nil) 00070 message:[NSString stringWithFormat:NSLocalizedString( 00071 @"You can try to continue but the application may be unstable.\n\n" 00072 @"Debug details follow:\n%@\n%@", nil), 00073 [exception reason], 00074 [[exception userInfo] objectForKey:UncaughtExceptionHandlerAddressesKey]] 00075 delegate:self 00076 cancelButtonTitle:NSLocalizedString(@"Quit", nil) 00077 otherButtonTitles:NSLocalizedString(@"Continue", nil), nil] 00078 autorelease]; 00079 [alert show]; 00080 00081 CFRunLoopRef runLoop = CFRunLoopGetCurrent(); 00082 CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop); 00083 00084 while (!dismissed) 00085 { 00086 for (NSString *mode in (NSArray *)allModes) 00087 { 00088 CFRunLoopRunInMode((CFStringRef)mode, 0.001, false); 00089 } 00090 } 00091 00092 CFRelease(allModes); 00093 00094 NSSetUncaughtExceptionHandler(NULL); 00095 signal(SIGABRT, SIG_DFL); 00096 signal(SIGILL, SIG_DFL); 00097 signal(SIGSEGV, SIG_DFL); 00098 signal(SIGFPE, SIG_DFL); 00099 signal(SIGBUS, SIG_DFL); 00100 signal(SIGPIPE, SIG_DFL); 00101 00102 if ([[exception name] isEqual:UncaughtExceptionHandlerSignalExceptionName]) 00103 { 00104 kill(getpid(), [[[exception userInfo] objectForKey:UncaughtExceptionHandlerSignalKey] intValue]); 00105 } 00106 else 00107 { 00108 [exception raise]; 00109 } 00110 } 00111 00112 @end 00113 00114 void HandleException(NSException *exception) 00115 { 00116 int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount); 00117 if (exceptionCount > UncaughtExceptionMaximum) 00118 { 00119 return; 00120 } 00121 00122 NSArray *callStack = [UncaughtExceptionHandler backtrace]; 00123 NSMutableDictionary *userInfo = 00124 [NSMutableDictionary dictionaryWithDictionary:[exception userInfo]]; 00125 [userInfo 00126 setObject:callStack 00127 forKey:UncaughtExceptionHandlerAddressesKey]; 00128 00129 [[[[UncaughtExceptionHandler alloc] init] autorelease] 00130 performSelectorOnMainThread:@selector(handleException:) 00131 withObject: 00132 [NSException 00133 exceptionWithName:[exception name] 00134 reason:[exception reason] 00135 userInfo:userInfo] 00136 waitUntilDone:YES]; 00137 } 00138 00139 void SignalHandler(int signal) 00140 { 00141 int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount); 00142 if (exceptionCount > UncaughtExceptionMaximum) 00143 { 00144 return; 00145 } 00146 00147 NSMutableDictionary *userInfo = 00148 [NSMutableDictionary 00149 dictionaryWithObject:[NSNumber numberWithInt:signal] 00150 forKey:UncaughtExceptionHandlerSignalKey]; 00151 00152 NSArray *callStack = [UncaughtExceptionHandler backtrace]; 00153 [userInfo 00154 setObject:callStack 00155 forKey:UncaughtExceptionHandlerAddressesKey]; 00156 00157 [[[[UncaughtExceptionHandler alloc] init] autorelease] 00158 performSelectorOnMainThread:@selector(handleException:) 00159 withObject: 00160 [NSException 00161 exceptionWithName:UncaughtExceptionHandlerSignalExceptionName 00162 reason: 00163 [NSString stringWithFormat: 00164 NSLocalizedString(@"Signal %d was raised.", nil), 00165 signal] 00166 userInfo: 00167 [NSDictionary 00168 dictionaryWithObject:[NSNumber numberWithInt:signal] 00169 forKey:UncaughtExceptionHandlerSignalKey]] 00170 waitUntilDone:YES]; 00171 } 00172 00173 void InstallUncaughtExceptionHandler() 00174 { 00175 NSSetUncaughtExceptionHandler(&HandleException); 00176 signal(SIGABRT, SignalHandler); 00177 signal(SIGILL, SignalHandler); 00178 signal(SIGSEGV, SignalHandler); 00179 signal(SIGFPE, SignalHandler); 00180 signal(SIGBUS, SignalHandler); 00181 signal(SIGPIPE, SignalHandler); 00182 } 00183