FIRCLSDwarfTests.m 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. #import <XCTest/XCTest.h>
  15. #include "Crashlytics/third_party/libunwind/dwarf.h"
  16. #import "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h"
  17. #include "Crashlytics/Crashlytics/Components/FIRCLSContext.h"
  18. #include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
  19. #include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
  20. #include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwind.h"
  21. #include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_arch.h"
  22. @interface FIRCLSDwarfTests : XCTestCase
  23. @end
  24. @implementation FIRCLSDwarfTests
  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_DWARF_UNWINDING_SUPPORTED
  46. #if CLS_CPU_X86_64
  47. - (void)testParseDwarfUnwindInfoForobjc_msgSend_x86_64_1093 {
  48. NSString* dylibPath = [self pathForResource:@"10.9.3_libobjc.A.dylib"];
  49. struct FIRCLSMachOFile file;
  50. XCTAssertTrue(FIRCLSMachOFileInitWithPath(&file, [dylibPath fileSystemRepresentation]), @"");
  51. struct FIRCLSMachOSlice slice = FIRCLSMachOFileSliceWithArchitectureName(&file, "x86_64");
  52. FIRCLSMachOSection section;
  53. const void* ehFrame = NULL;
  54. FIRCLSMachOSliceInitSectionByName(&slice, SEG_TEXT, "__eh_frame", &section);
  55. // This computation is a little funny. Because we've just opened this dylib as a file,
  56. // the "slide" is really whereever the file ended up being mapped in memory.
  57. ehFrame = (void*)(section.addr + (uintptr_t)slice.startAddress);
  58. XCTAssertTrue(ehFrame != NULL, @"");
  59. FIRCLSDwarfCFIRecord record;
  60. // hard-code to the FDE offset for objc_msgSend
  61. XCTAssertTrue(FIRCLSDwarfParseCFIFromFDERecordOffset(&record, ehFrame, 0x00001a48), @"");
  62. // check the CIE record
  63. XCTAssertEqual(record.cie.length, 28, @"");
  64. XCTAssertEqual(record.cie.version, 3, @"");
  65. XCTAssertEqual(record.cie.ehData, 0, @"");
  66. XCTAssertEqualObjects([NSString stringWithUTF8String:record.cie.augmentation], @"zPR", @"");
  67. XCTAssertEqual(record.cie.pointerEncoding, DW_EH_PE_absptr | DW_EH_PE_pcrel, @"");
  68. XCTAssertEqual(record.cie.lsdaEncoding, DW_EH_PE_absptr, @"");
  69. XCTAssertEqual(record.cie.personalityEncoding,
  70. DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4, @"");
  71. XCTAssertEqual(record.cie.codeAlignFactor, 1, @"");
  72. XCTAssertEqual(record.cie.dataAlignFactor, -8, @"");
  73. XCTAssertEqual(record.cie.returnAddressRegister, 16, @"");
  74. XCTAssertEqual(record.cie.signalFrame, false, @"");
  75. XCTAssertTrue(FIRCLSDwarfCIEHasAugmentationData(&record.cie), @"");
  76. // check the FDE record
  77. XCTAssertEqual(record.fde.length, 44, @"");
  78. XCTAssertEqual(record.fde.cieOffset, 68, @"");
  79. XCTAssertEqual(record.fde.startAddress, (uintptr_t)slice.startAddress + 0x5080, @"");
  80. XCTAssertEqual(record.fde.rangeSize, 0x124, @"");
  81. FIRCLSMachOFileDestroy(&file);
  82. }
  83. #endif
  84. - (void)testGetSavedRegisterWithInvalidValues {
  85. FIRCLSThreadContext registers;
  86. const FIRCLSDwarfRegister dRegister = {FIRCLSDwarfRegisterUnused, 0};
  87. XCTAssertEqual(FIRCLSDwarfGetSavedRegister(NULL, 0, dRegister), 0, @"");
  88. XCTAssertEqual(FIRCLSDwarfGetSavedRegister(&registers, 0, dRegister), 0, @"");
  89. }
  90. - (void)testGetSavedRegisterWithInCFA {
  91. uintptr_t memoryBuffer[2] = {45, 46};
  92. FIRCLSThreadContext registers;
  93. const FIRCLSDwarfRegister dRegister = {FIRCLSDwarfRegisterInCFA, sizeof(uintptr_t)};
  94. // this should compute *(memoryBuffer + sizeof(uintptr_t)) = 46
  95. XCTAssertEqual(FIRCLSDwarfGetSavedRegister(&registers, (uintptr_t)memoryBuffer, dRegister), 46,
  96. @"");
  97. }
  98. - (void)testRegisterStructureSizingAndMaxValues {
  99. FIRCLSDwarfState state;
  100. XCTAssertEqual(sizeof(state.registers) / sizeof(FIRCLSDwarfRegister),
  101. CLS_DWARF_MAX_REGISTER_NUM + 1,
  102. @"Number of DWARF register values needs to match the max register size for the "
  103. @"architecture, plus one");
  104. XCTAssertTrue(CLS_DWARF_MAX_REGISTER_NUM > 1);
  105. XCTAssertTrue(CLS_DWARF_INVALID_REGISTER_NUM > CLS_DWARF_MAX_REGISTER_NUM);
  106. }
  107. - (void)testAssignReturnRegisterNumber {
  108. FIRCLSDwarfState state;
  109. FIRCLSThreadContext inputRegisters;
  110. FIRCLSThreadContext outputRegisters;
  111. memset(&state, 0, sizeof(FIRCLSDwarfState));
  112. memset(&inputRegisters, 0, sizeof(FIRCLSThreadContext));
  113. memset(&outputRegisters, 0, sizeof(FIRCLSThreadContext));
  114. uintptr_t cfaRegister = 42; // doesn't matter for this test
  115. // set the return register to live inside another reg, just for convenience
  116. state.registers[CLS_DWARF_REG_RETURN].location = FIRCLSDwarfRegisterInRegister;
  117. // Setup our arch-specific values. Be careful not to use the 0 register enum value
  118. // because that can artifically pass.
  119. #if CLS_CPU_X86_64
  120. state.registers[CLS_DWARF_REG_RETURN].value = CLS_DWARF_X86_64_RDX;
  121. FIRCLSDwarfUnwindSetRegisterValue(&inputRegisters, CLS_DWARF_X86_64_RDX, 777);
  122. #elif CLS_CPU_I386
  123. state.registers[CLS_DWARF_REG_RETURN].value = CLS_DWARF_X86_ECX;
  124. FIRCLSDwarfUnwindSetRegisterValue(&inputRegisters, CLS_DWARF_X86_ECX, 777);
  125. #elif CLS_CPU_ARM64
  126. state.registers[CLS_DWARF_REG_RETURN].value = CLS_DWARF_ARM64_X1;
  127. FIRCLSDwarfUnwindSetRegisterValue(&inputRegisters, CLS_DWARF_ARM64_X1, 777);
  128. #endif
  129. XCTAssertTrue(
  130. FIRCLSDwarfUnwindAssignRegisters(&state, &inputRegisters, cfaRegister, &outputRegisters));
  131. XCTAssertEqual(FIRCLSDwarfUnwindGetRegisterValue(&outputRegisters, CLS_DWARF_REG_RETURN), 777);
  132. }
  133. #endif
  134. @end