KWSymbolicator.m 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. //
  2. // KWSymbolicator.m
  3. // Kiwi
  4. //
  5. // Created by Jerry Marino on 4/28/13.
  6. // Copyright (c) 2013 Allen Ding. All rights reserved.
  7. //
  8. #import <objc/runtime.h>
  9. #import <libunwind.h>
  10. #import <mach-o/dyld.h>
  11. #import "KWSymbolicator.h"
  12. #import "KWBackgroundTask.h"
  13. long kwCallerAddress (void){
  14. #if !__arm__
  15. unw_cursor_t cursor; unw_context_t uc;
  16. unw_word_t ip;
  17. unw_getcontext(&uc);
  18. unw_init_local(&cursor, &uc);
  19. int pos = 2;
  20. while (unw_step(&cursor) && pos--){
  21. unw_get_reg (&cursor, UNW_REG_IP, &ip);
  22. if(pos == 0) return (NSUInteger)(ip - 4);
  23. }
  24. #endif
  25. return 0;
  26. }
  27. @implementation KWCallSite (KWSymbolication)
  28. static void GetTestBundleExecutablePathSlide(NSString **executablePath, long *slide) {
  29. for (int i = 0; i < _dyld_image_count(); i++) {
  30. if (strstr(_dyld_get_image_name(i), ".octest/") || strstr(_dyld_get_image_name(i), ".xctest/")) {
  31. *executablePath = [NSString stringWithUTF8String:_dyld_get_image_name(i)];
  32. *slide = _dyld_get_image_vmaddr_slide(i);
  33. break;
  34. }
  35. }
  36. }
  37. + (KWCallSite *)callSiteWithCallerAddress:(long)address {
  38. // Symbolicate the address with atos to get the line number & filename.
  39. // If the command raises, no specs will run so don't bother catching
  40. // In the case of a non 0 exit code, failure to launch, or timeout, the
  41. // user will atleast have an idea of why the task failed.
  42. long slide;
  43. NSString *executablePath;
  44. GetTestBundleExecutablePathSlide(&executablePath, &slide);
  45. NSArray *arguments = @[@"-o", executablePath, @"-s", [NSString stringWithFormat:@"%lx", slide], [NSString stringWithFormat:@"%lx", address]];
  46. // See atos man page for more information on arguments.
  47. KWBackgroundTask *symbolicationTask = [[KWBackgroundTask alloc] initWithCommand:@"/usr/bin/atos" arguments:arguments];
  48. [symbolicationTask launchAndWaitForExit];
  49. NSString *symbolicatedCallerAddress = [[NSString alloc] initWithData:symbolicationTask.output encoding:NSUTF8StringEncoding];
  50. NSString *pattern = @".+\\((.+):([0-9]+)\\)";
  51. NSError *error;
  52. NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:&error];
  53. NSArray *matches = [regex matchesInString:symbolicatedCallerAddress options:0 range:NSMakeRange(0, symbolicatedCallerAddress.length)];
  54. NSString *fileName;
  55. NSInteger lineNumber = 0;
  56. for (NSTextCheckingResult *ntcr in matches) {
  57. fileName = [symbolicatedCallerAddress substringWithRange:[ntcr rangeAtIndex:1]];
  58. NSString *lineNumberMatch = [symbolicatedCallerAddress substringWithRange:[ntcr rangeAtIndex:2]];
  59. lineNumber = lineNumberMatch.integerValue;
  60. }
  61. return [KWCallSite callSiteWithFilename:fileName lineNumber:lineNumber];
  62. }
  63. @end