RAExceptionHandler.m 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. //
  2. // LPExceptionHandler.m
  3. // Mach-O UUID
  4. //
  5. // Created by Jack on 2018/8/1.
  6. // Copyright © 2018年 USAI. All rights reserved.
  7. //
  8. #import "RAExceptionHandler.h"
  9. #import <UIKit/UIDevice.h>
  10. #import <sys/utsname.h>
  11. // Mach-O UUID
  12. #import <mach-o/ldsyms.h>
  13. // CPU arch
  14. #import <mach-o/arch.h>
  15. // Slide Address
  16. #include <mach-o/dyld.h>
  17. @interface RAExceptionHandler ()
  18. @property (nonatomic,copy) void (^handler)(NSString *);
  19. + (instancetype)sharedHanlder;
  20. @end
  21. #pragma mark - dSYM UUID
  22. // 获取主执行Image UUID,此UUID要和dSYM文件UUID相同
  23. NSString *mach_oUUID() {
  24. const uint8_t *command = (const uint8_t *)(&_mh_execute_header + 1);
  25. for (uint32_t idx = 0; idx < _mh_execute_header.ncmds; ++idx) {
  26. if (((const struct load_command *)command)->cmd == LC_UUID) {
  27. command += sizeof(struct load_command);
  28. // return [NSString stringWithFormat:@"%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
  29. // command[0], command[1], command[2], command[3],
  30. // command[4], command[5],
  31. // command[6], command[7],
  32. // command[8], command[9],
  33. // command[10], command[11], command[12], command[13], command[14], command[15]];
  34. CFUUIDRef uuidRef = CFUUIDCreateFromUUIDBytes(NULL, *((CFUUIDBytes*)command));
  35. NSString* uuidStr = (__bridge_transfer NSString*)CFUUIDCreateString(NULL, uuidRef);
  36. return uuidStr;
  37. } else {
  38. command += ((const struct load_command *)command)->cmdsize;
  39. }
  40. }
  41. return nil;
  42. }
  43. #pragma mark - CPU Type
  44. const char *byteOrder(enum NXByteOrder BO) {
  45. switch (BO) {
  46. case NX_LittleEndian: return ("Little-Endian");
  47. case NX_BigEndian: return ("Big-Endian");
  48. case NX_UnknownByteOrder: return "Unknow";
  49. default: return ("!?!");
  50. }
  51. }
  52. void testGetAllArch () {
  53. const NXArchInfo *known = NXGetAllArchInfos();
  54. while (known && known->description) {
  55. printf("known: %s\t%x/%x\t%s\n", known->description,
  56. known->cputype,
  57. known->cpusubtype,
  58. byteOrder(known->byteorder));
  59. known++;
  60. }
  61. }
  62. // 获取CPU架构类型
  63. NSString *localCPUType() {
  64. const NXArchInfo *local = NXGetLocalArchInfo();
  65. if (local) {
  66. printf("Local - %s\t%x/%x\t%s\n", local->description,
  67. local->cputype,
  68. local->cpusubtype,
  69. byteOrder(local->byteorder));
  70. return [NSString stringWithUTF8String:local->description];
  71. }
  72. return @"unknown";
  73. }
  74. #pragma mark - Slide Address
  75. //获取基地址
  76. uintptr_t loadAddress() {
  77. const struct mach_header *exe_header = NULL;
  78. for (uint32_t i = 0; i < _dyld_image_count(); i++) {
  79. const struct mach_header *header = _dyld_get_image_header(i);
  80. if (header->filetype == MH_EXECUTE) {
  81. exe_header = header;
  82. break;
  83. }
  84. }
  85. //返回值即为加载地址
  86. return (uintptr_t)exe_header;
  87. }
  88. // 获取偏移地址
  89. uintptr_t slideAddress() {
  90. uintptr_t vmaddr_slide = 0;
  91. for (uint32_t i = 0; i < _dyld_image_count(); i++) {
  92. const struct mach_header *header = _dyld_get_image_header(i);
  93. if (header->filetype == MH_EXECUTE) {
  94. vmaddr_slide = _dyld_get_image_vmaddr_slide(i);
  95. break;
  96. }
  97. }
  98. return (uintptr_t)vmaddr_slide;
  99. }
  100. #pragma mark - Binary Image
  101. NSString *binaryImageName() {
  102. for (uint32_t i = 0; i < _dyld_image_count(); i++) {
  103. const struct mach_header *header = _dyld_get_image_header(i);
  104. if (header->filetype == MH_EXECUTE) {
  105. const char *path = _dyld_get_image_name((unsigned)i);
  106. NSString *imagePath = [NSString stringWithUTF8String:path];
  107. NSArray *array = [imagePath componentsSeparatedByString:@"/"];
  108. NSString *imageName = array[array.count - 1];
  109. return imageName;
  110. break;
  111. }
  112. }
  113. return nil;
  114. }
  115. #pragma mark - Caught Exception
  116. void UncaughtExceptionHandler(NSException *exception) {
  117. NSMutableString *exceptionStr = [NSMutableString string];
  118. UIDevice *device = [UIDevice currentDevice];
  119. NSString *modle = device.model;
  120. NSString *os = device.systemName;
  121. NSString *ver = device.systemVersion;
  122. struct utsname systeminfo;
  123. uname(&systeminfo);
  124. NSString *deviceString = [NSString stringWithCString:systeminfo.machine encoding:NSUTF8StringEncoding];
  125. [exceptionStr appendFormat:@"Device: %@\n",modle];
  126. [exceptionStr appendFormat:@"OS: %@ %@\n",os,ver];
  127. [exceptionStr appendFormat:@"Hardware: %@\n",deviceString];
  128. NSDictionary* infoDict =[[NSBundle mainBundle] infoDictionary];
  129. NSString* build =[infoDict objectForKey:@"CFBundleVersion"];
  130. NSString* version =[infoDict objectForKey:@"CFBundleShortVersionString"];
  131. NSString *bundleID = [infoDict objectForKey:@"CFBundleIdentifier"];
  132. NSString *bundleName = [infoDict objectForKey:@"CFBundleName"];
  133. [exceptionStr appendFormat:@"Bundle Name: %@\n",bundleName];
  134. [exceptionStr appendFormat:@"build: %@\n",build];
  135. [exceptionStr appendFormat:@"version: %@\n",version];
  136. [exceptionStr appendFormat:@"identifier: %@\n",bundleID];
  137. NSDate *date = [NSDate date];
  138. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  139. [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss Z"];
  140. NSString *dateStr = [formatter stringFromDate:date];
  141. [exceptionStr appendFormat:@"Date/Time: %@\n\n",dateStr];
  142. NSArray *callStack = [exception callStackSymbols];
  143. NSString *reason = [exception reason];
  144. NSString *name = [exception name];
  145. [exceptionStr appendFormat:@"%@\n%@\n\n%@\n\n",name,reason,callStack];
  146. [exceptionStr appendFormat:@"dSYM UUID: %@\n",mach_oUUID()];
  147. [exceptionStr appendFormat:@"CPU Type: %@\n",localCPUType()];
  148. [exceptionStr appendFormat:@"Slide Address: 0x%lx\n",slideAddress()];
  149. [exceptionStr appendFormat:@"Binary Image: %@\n",binaryImageName()];
  150. [exceptionStr appendFormat:@"Base Address: 0x%lx\n",loadAddress()];
  151. NSLog(@"exception:\n%@",exceptionStr);
  152. if ([RAExceptionHandler sharedHanlder].handler) {
  153. [RAExceptionHandler sharedHanlder].handler(exceptionStr);
  154. }
  155. }
  156. #pragma mark - Handler
  157. @implementation RAExceptionHandler
  158. + (instancetype)sharedHanlder {
  159. static RAExceptionHandler *handler = nil;
  160. static dispatch_once_t onceToken;
  161. dispatch_once(&onceToken, ^{
  162. handler = [[RAExceptionHandler alloc] init];
  163. });
  164. return handler;
  165. }
  166. + (void)registHandler:(void (^)(NSString *))handler {
  167. [[RAExceptionHandler sharedHanlder] registExceptionHandler:handler];
  168. }
  169. - (void)registExceptionHandler:(void (^)(NSString *))handler {
  170. NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
  171. self.handler = handler;
  172. }
  173. @end