FIRCLSCompactUnwindTests.m 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // Copyright 2019 Google
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind.h"
  15. #import <Foundation/Foundation.h>
  16. #import <XCTest/XCTest.h>
  17. #import "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h"
  18. #include "Crashlytics/Crashlytics/Components/FIRCLSContext.h"
  19. #include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
  20. #include "Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind_Private.h"
  21. #include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_x86.h"
  22. @interface FIRCLSCompactUnwindTests : XCTestCase
  23. @end
  24. @implementation FIRCLSCompactUnwindTests
  25. - (void)setUp {
  26. [super setUp];
  27. _firclsContext.readonly = malloc(sizeof(FIRCLSReadOnlyContext));
  28. _firclsContext.readonly->logPath = "/tmp/test.log";
  29. }
  30. - (void)tearDown {
  31. [super tearDown];
  32. }
  33. - (NSString*)resourcePath {
  34. #if SWIFT_PACKAGE
  35. NSBundle* bundle = SWIFTPM_MODULE_BUNDLE;
  36. return [bundle.resourcePath stringByAppendingPathComponent:@"Data"];
  37. #else
  38. NSBundle *bundle = [NSBundle bundleForClass:[self class]];
  39. return bundle.resourcePath;
  40. #endif
  41. }
  42. - (NSString*)pathForResource:(NSString*)name {
  43. return [[self resourcePath] stringByAppendingPathComponent:name];
  44. }
  45. #if CLS_COMPACT_UNWINDING_SUPPORTED
  46. #if !TARGET_OS_IPHONE
  47. - (void)testParseCompactUnwindInfoForthread_get_state_10_9_4 {
  48. NSString* dylibPath = [self pathForResource:@"10.9.4_libsystem_kernel.dylib"];
  49. struct FIRCLSMachOFile file;
  50. XCTAssertTrue(FIRCLSMachOFileInitWithPath(&file, [dylibPath fileSystemRepresentation]), @"");
  51. struct FIRCLSMachOSlice slice = FIRCLSMachOFileSliceWithArchitectureName(&file, "x86_64");
  52. const void* compactUnwind = NULL;
  53. const void* ehFrame = NULL;
  54. XCTAssert(FIRCLSMachOSliceGetSectionByName(&slice, SEG_TEXT, "__eh_frame", &ehFrame));
  55. XCTAssert(FIRCLSMachOSliceGetSectionByName(&slice, SEG_TEXT, "__unwind_info", &compactUnwind));
  56. XCTAssertTrue(ehFrame != NULL, @"");
  57. XCTAssertTrue(compactUnwind != NULL, @"");
  58. FIRCLSCompactUnwindContext context;
  59. // hard-code a load address seen during testing
  60. uintptr_t loadAddress = 0x7fff94044000;
  61. XCTAssertTrue(FIRCLSCompactUnwindInit(&context, compactUnwind, ehFrame, loadAddress), @"");
  62. FIRCLSCompactUnwindResult result;
  63. XCTAssertTrue(FIRCLSCompactUnwindLookup(&context, 0x7fff94051e6c, &result), @"");
  64. XCTAssertEqual(result.encoding & UNWIND_X86_64_MODE_MASK, UNWIND_X86_64_MODE_RBP_FRAME, @"");
  65. XCTAssertEqual(result.functionStart, loadAddress + 0x0000DCC1, @"");
  66. }
  67. - (void)testParseCompactUnwindInfoForFunctionInLastIndexEntry {
  68. NSString* dylibPath = [self pathForResource:@"10.9.4_libsystem_kernel.dylib"];
  69. struct FIRCLSMachOFile file;
  70. XCTAssertTrue(FIRCLSMachOFileInitWithPath(&file, [dylibPath fileSystemRepresentation]), @"");
  71. struct FIRCLSMachOSlice slice = FIRCLSMachOFileSliceWithArchitectureName(&file, "x86_64");
  72. const void* compactUnwind = NULL;
  73. const void* ehFrame = NULL;
  74. XCTAssert(FIRCLSMachOSliceGetSectionByName(&slice, SEG_TEXT, "__eh_frame", &ehFrame));
  75. XCTAssert(FIRCLSMachOSliceGetSectionByName(&slice, SEG_TEXT, "__unwind_info", &compactUnwind));
  76. XCTAssertTrue(ehFrame != NULL, @"");
  77. XCTAssertTrue(compactUnwind != NULL, @"");
  78. FIRCLSCompactUnwindContext context;
  79. // hard-code a load address seen during testing
  80. uintptr_t loadAddress = 0x7fff94044000;
  81. XCTAssertTrue(FIRCLSCompactUnwindInit(&context, compactUnwind, ehFrame, loadAddress), @"");
  82. FIRCLSCompactUnwindResult result;
  83. // there should be no entry here (0x00016FDE maps to the last index entry, 0x00016FDF)
  84. XCTAssertFalse(FIRCLSCompactUnwindLookup(&context, loadAddress + 0x00016FDE, &result), @"");
  85. }
  86. - (void)testParseCompactUnwindInfoForBoundaryBetween2ndLevelEntries {
  87. NSString* dylibPath = [self pathForResource:@"10.9.4_libsystem_kernel.dylib"];
  88. struct FIRCLSMachOFile file;
  89. XCTAssertTrue(FIRCLSMachOFileInitWithPath(&file, [dylibPath fileSystemRepresentation]), @"");
  90. struct FIRCLSMachOSlice slice = FIRCLSMachOFileSliceWithArchitectureName(&file, "x86_64");
  91. const void* compactUnwind = NULL;
  92. const void* ehFrame = NULL;
  93. XCTAssert(FIRCLSMachOSliceGetSectionByName(&slice, SEG_TEXT, "__eh_frame", &ehFrame));
  94. XCTAssert(FIRCLSMachOSliceGetSectionByName(&slice, SEG_TEXT, "__unwind_info", &compactUnwind));
  95. XCTAssertTrue(ehFrame != NULL, @"");
  96. XCTAssertTrue(compactUnwind != NULL, @"");
  97. FIRCLSCompactUnwindContext context;
  98. // hard-code a load address seen during testing
  99. uintptr_t loadAddress = 0x7fff94044000;
  100. XCTAssertTrue(FIRCLSCompactUnwindInit(&context, compactUnwind, ehFrame, loadAddress), @"");
  101. FIRCLSCompactUnwindResult result;
  102. // funcOffset=0x0000151A _reallocf
  103. // funcOffset=0x00001558 __pthread_exit_if_canceled
  104. // make sure we hit the last byte of _reallocf
  105. XCTAssertTrue(FIRCLSCompactUnwindLookup(&context, loadAddress + 0x00001557, &result), @"");
  106. XCTAssertEqual(result.encoding & UNWIND_X86_64_MODE_MASK, UNWIND_X86_64_MODE_RBP_FRAME, @"");
  107. XCTAssertEqual(result.functionStart, loadAddress + 0x0000151A, @"");
  108. XCTAssertEqual(result.functionEnd, loadAddress + 0x00001558, @"");
  109. // and check the very next value, which should be in __pthread_exit_if_canceled
  110. XCTAssertTrue(FIRCLSCompactUnwindLookup(&context, loadAddress + 0x00001558, &result), @"");
  111. XCTAssertEqual(result.encoding & UNWIND_X86_64_MODE_MASK, UNWIND_X86_64_MODE_DWARF, @"");
  112. XCTAssertEqual(result.functionStart, loadAddress + 0x00001558, @"");
  113. }
  114. #endif
  115. #if CLS_CPU_X86_64
  116. - (void)testComputeDirectStackSize {
  117. const compact_unwind_encoding_t encoding = 0x20a1860;
  118. const intptr_t functionStart = 0x0;
  119. uint32_t stackSize = 0;
  120. XCTAssertTrue(FIRCLSCompactUnwindComputeStackSize(encoding, functionStart, false, &stackSize),
  121. @"");
  122. // 0x20a1860 & 0x00FF0000 = 0xA0000
  123. // 0x270000 >> 16 = 0xA
  124. // 0xA * 8 = 0x50
  125. XCTAssertEqual(stackSize, 0x50, @"");
  126. }
  127. #endif
  128. #endif
  129. @end