UncaughtExceptionHandler.m 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. //
  2. // UncaughtExceptionHandler.m
  3. // UncaughtExceptions
  4. //
  5. // Created by Matt Gallagher on 2010/05/25.
  6. // Copyright 2010 Matt Gallagher. All rights reserved.
  7. //
  8. // Permission is given to use this source code file, free of charge, in any
  9. // project, commercial or otherwise, entirely at your risk, with the condition
  10. // that any redistribution (in part or whole) of source code must retain
  11. // this copyright and permission notice. Attribution in compiled projects is
  12. // appreciated but not required.
  13. //
  14. #import "UncaughtExceptionHandler.h"
  15. #include <libkern/OSAtomic.h>
  16. #include <execinfo.h>
  17. NSString * const UncaughtExceptionHandlerSignalExceptionName = @"UncaughtExceptionHandlerSignalExceptionName";
  18. NSString * const UncaughtExceptionHandlerSignalKey = @"UncaughtExceptionHandlerSignalKey";
  19. NSString * const UncaughtExceptionHandlerAddressesKey = @"UncaughtExceptionHandlerAddressesKey";
  20. volatile int32_t UncaughtExceptionCount = 0;
  21. const int32_t UncaughtExceptionMaximum = 10;
  22. const NSInteger UncaughtExceptionHandlerSkipAddressCount = 4;
  23. const NSInteger UncaughtExceptionHandlerReportAddressCount = 5;
  24. @implementation UncaughtExceptionHandler
  25. + (NSArray *)backtrace
  26. {
  27. void* callstack[128];
  28. int frames = backtrace(callstack, 128);
  29. char **strs = backtrace_symbols(callstack, frames);
  30. int i;
  31. NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];
  32. for (
  33. i = UncaughtExceptionHandlerSkipAddressCount;
  34. i < UncaughtExceptionHandlerSkipAddressCount +
  35. UncaughtExceptionHandlerReportAddressCount;
  36. i++)
  37. {
  38. [backtrace addObject:[NSString stringWithUTF8String:strs[i]]];
  39. }
  40. free(strs);
  41. return backtrace;
  42. }
  43. - (void)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex
  44. {
  45. if (anIndex == 0)
  46. {
  47. dismissed = YES;
  48. }
  49. }
  50. - (void)validateAndSaveCriticalApplicationData
  51. {
  52. }
  53. - (void)handleException:(NSException *)exception
  54. {
  55. [self validateAndSaveCriticalApplicationData];
  56. id delegate = [[UIApplication sharedApplication] delegate];
  57. if([delegate respondsToSelector:@selector(terminateWithException:)])
  58. {
  59. dismissed = (BOOL)[delegate performSelector:@selector(terminateWithException:) withObject:exception];
  60. }
  61. NSSetUncaughtExceptionHandler(NULL);
  62. signal(SIGABRT, SIG_DFL);
  63. signal(SIGILL, SIG_DFL);
  64. signal(SIGSEGV, SIG_DFL);
  65. signal(SIGFPE, SIG_DFL);
  66. signal(SIGBUS, SIG_DFL);
  67. signal(SIGPIPE, SIG_DFL);
  68. if ([[exception name] isEqual:UncaughtExceptionHandlerSignalExceptionName])
  69. {
  70. kill(getpid(), [[[exception userInfo] objectForKey:UncaughtExceptionHandlerSignalKey] intValue]);
  71. }
  72. else
  73. {
  74. [exception raise];
  75. }
  76. }
  77. @end
  78. void HandleException(NSException *exception)
  79. {
  80. int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);
  81. if (exceptionCount > UncaughtExceptionMaximum)
  82. {
  83. return;
  84. }
  85. NSArray *callStack = [UncaughtExceptionHandler backtrace];
  86. NSMutableDictionary *userInfo =
  87. [NSMutableDictionary dictionaryWithDictionary:[exception userInfo]];
  88. [userInfo
  89. setObject:callStack
  90. forKey:UncaughtExceptionHandlerAddressesKey];
  91. [[[UncaughtExceptionHandler alloc] init]
  92. performSelectorOnMainThread:@selector(handleException:)
  93. withObject:
  94. [NSException
  95. exceptionWithName:[exception name]
  96. reason:[exception reason]
  97. userInfo:userInfo]
  98. waitUntilDone:YES];
  99. }
  100. void SignalHandler(int signal)
  101. {
  102. int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);
  103. if (exceptionCount > UncaughtExceptionMaximum)
  104. {
  105. return;
  106. }
  107. NSMutableDictionary *userInfo =
  108. [NSMutableDictionary
  109. dictionaryWithObject:[NSNumber numberWithInt:signal]
  110. forKey:UncaughtExceptionHandlerSignalKey];
  111. NSArray *callStack = [UncaughtExceptionHandler backtrace];
  112. [userInfo
  113. setObject:callStack
  114. forKey:UncaughtExceptionHandlerAddressesKey];
  115. [[[UncaughtExceptionHandler alloc] init]
  116. performSelectorOnMainThread:@selector(handleException:)
  117. withObject:
  118. [NSException
  119. exceptionWithName:UncaughtExceptionHandlerSignalExceptionName
  120. reason:
  121. [NSString stringWithFormat:
  122. NSLocalizedString(@"Signal %d was raised.", nil),
  123. signal]
  124. userInfo:
  125. [NSDictionary
  126. dictionaryWithObject:[NSNumber numberWithInt:signal]
  127. forKey:UncaughtExceptionHandlerSignalKey]]
  128. waitUntilDone:YES];
  129. }
  130. void InstallUncaughtExceptionHandler(void)
  131. {
  132. NSSetUncaughtExceptionHandler(&HandleException);
  133. signal(SIGABRT, SignalHandler);
  134. signal(SIGILL, SignalHandler);
  135. signal(SIGSEGV, SignalHandler);
  136. signal(SIGFPE, SignalHandler);
  137. signal(SIGBUS, SignalHandler);
  138. signal(SIGPIPE, SignalHandler);
  139. }