FIRCLSDwarfTests.m 6.1 KB

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