| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- // Copyright 2019 Google
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #import <XCTest/XCTest.h>
- #include "Crashlytics/third_party/libunwind/dwarf.h"
- #import "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h"
- #include "Crashlytics/Crashlytics/Components/FIRCLSContext.h"
- #include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
- #include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
- #include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwind.h"
- #include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_arch.h"
- @interface FIRCLSDwarfTests : XCTestCase
- @end
- @implementation FIRCLSDwarfTests
- - (void)setUp {
- [super setUp];
- _firclsContext.readonly = malloc(sizeof(FIRCLSReadOnlyContext));
- _firclsContext.readonly->logPath = "/tmp/test.log";
- }
- - (void)tearDown {
- [super tearDown];
- }
- - (NSString*)resourcePath {
- return [[NSBundle bundleForClass:[self class]] resourcePath];
- }
- - (NSString*)pathForResource:(NSString*)name {
- return [[self resourcePath] stringByAppendingPathComponent:name];
- }
- #if CLS_DWARF_UNWINDING_SUPPORTED
- #if CLS_CPU_X86_64
- - (void)testParseDwarfUnwindInfoForobjc_msgSend_x86_64_1093 {
- NSString* dylibPath = [self pathForResource:@"10.9.3_libobjc.A.dylib"];
- struct FIRCLSMachOFile file;
- XCTAssertTrue(FIRCLSMachOFileInitWithPath(&file, [dylibPath fileSystemRepresentation]), @"");
- struct FIRCLSMachOSlice slice = FIRCLSMachOFileSliceWithArchitectureName(&file, "x86_64");
- FIRCLSMachOSection section;
- const void* ehFrame = NULL;
- FIRCLSMachOSliceInitSectionByName(&slice, SEG_TEXT, "__eh_frame", §ion);
- // This computation is a little funny. Because we've just opened this dylib as a file,
- // the "slide" is really whereever the file ended up being mapped in memory.
- ehFrame = (void*)(section.addr + (uintptr_t)slice.startAddress);
- XCTAssertTrue(ehFrame != NULL, @"");
- FIRCLSDwarfCFIRecord record;
- // hard-code to the FDE offset for objc_msgSend
- XCTAssertTrue(FIRCLSDwarfParseCFIFromFDERecordOffset(&record, ehFrame, 0x00001a48), @"");
- // check the CIE record
- XCTAssertEqual(record.cie.length, 28, @"");
- XCTAssertEqual(record.cie.version, 3, @"");
- XCTAssertEqual(record.cie.ehData, 0, @"");
- XCTAssertEqualObjects([NSString stringWithUTF8String:record.cie.augmentation], @"zPR", @"");
- XCTAssertEqual(record.cie.pointerEncoding, DW_EH_PE_absptr | DW_EH_PE_pcrel, @"");
- XCTAssertEqual(record.cie.lsdaEncoding, DW_EH_PE_absptr, @"");
- XCTAssertEqual(record.cie.personalityEncoding,
- DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4, @"");
- XCTAssertEqual(record.cie.codeAlignFactor, 1, @"");
- XCTAssertEqual(record.cie.dataAlignFactor, -8, @"");
- XCTAssertEqual(record.cie.returnAddressRegister, 16, @"");
- XCTAssertEqual(record.cie.signalFrame, false, @"");
- XCTAssertTrue(FIRCLSDwarfCIEHasAugmentationData(&record.cie), @"");
- // check the FDE record
- XCTAssertEqual(record.fde.length, 44, @"");
- XCTAssertEqual(record.fde.cieOffset, 68, @"");
- XCTAssertEqual(record.fde.startAddress, (uintptr_t)slice.startAddress + 0x5080, @"");
- XCTAssertEqual(record.fde.rangeSize, 0x124, @"");
- FIRCLSMachOFileDestroy(&file);
- }
- #endif
- - (void)testGetSavedRegisterWithInvalidValues {
- FIRCLSThreadContext registers;
- const FIRCLSDwarfRegister dRegister = {FIRCLSDwarfRegisterUnused, 0};
- XCTAssertEqual(FIRCLSDwarfGetSavedRegister(NULL, 0, dRegister), 0, @"");
- XCTAssertEqual(FIRCLSDwarfGetSavedRegister(®isters, 0, dRegister), 0, @"");
- }
- - (void)testGetSavedRegisterWithInCFA {
- uintptr_t memoryBuffer[2] = {45, 46};
- FIRCLSThreadContext registers;
- const FIRCLSDwarfRegister dRegister = {FIRCLSDwarfRegisterInCFA, sizeof(uintptr_t)};
- // this should compute *(memoryBuffer + sizeof(uintptr_t)) = 46
- XCTAssertEqual(FIRCLSDwarfGetSavedRegister(®isters, (uintptr_t)memoryBuffer, dRegister), 46,
- @"");
- }
- - (void)testRegisterStructureSizingAndMaxValues {
- FIRCLSDwarfState state;
- XCTAssertEqual(sizeof(state.registers) / sizeof(FIRCLSDwarfRegister),
- CLS_DWARF_MAX_REGISTER_NUM + 1,
- @"Number of DWARF register values needs to match the max register size for the "
- @"architecture, plus one");
- XCTAssertTrue(CLS_DWARF_MAX_REGISTER_NUM > 1);
- XCTAssertTrue(CLS_DWARF_INVALID_REGISTER_NUM > CLS_DWARF_MAX_REGISTER_NUM);
- }
- - (void)testAssignReturnRegisterNumber {
- FIRCLSDwarfState state;
- FIRCLSThreadContext inputRegisters;
- FIRCLSThreadContext outputRegisters;
- memset(&state, 0, sizeof(FIRCLSDwarfState));
- memset(&inputRegisters, 0, sizeof(FIRCLSThreadContext));
- memset(&outputRegisters, 0, sizeof(FIRCLSThreadContext));
- uintptr_t cfaRegister = 42; // doesn't matter for this test
- // set the return register to live inside another reg, just for convenience
- state.registers[CLS_DWARF_REG_RETURN].location = FIRCLSDwarfRegisterInRegister;
- // Setup our arch-specific values. Be careful not to use the 0 register enum value
- // because that can artifically pass.
- #if CLS_CPU_X86_64
- state.registers[CLS_DWARF_REG_RETURN].value = CLS_DWARF_X86_64_RDX;
- FIRCLSDwarfUnwindSetRegisterValue(&inputRegisters, CLS_DWARF_X86_64_RDX, 777);
- #elif CLS_CPU_I386
- state.registers[CLS_DWARF_REG_RETURN].value = CLS_DWARF_X86_ECX;
- FIRCLSDwarfUnwindSetRegisterValue(&inputRegisters, CLS_DWARF_X86_ECX, 777);
- #elif CLS_CPU_ARM64
- state.registers[CLS_DWARF_REG_RETURN].value = CLS_DWARF_ARM64_X1;
- FIRCLSDwarfUnwindSetRegisterValue(&inputRegisters, CLS_DWARF_ARM64_X1, 777);
- #endif
- XCTAssertTrue(
- FIRCLSDwarfUnwindAssignRegisters(&state, &inputRegisters, cfaRegister, &outputRegisters));
- XCTAssertEqual(FIRCLSDwarfUnwindGetRegisterValue(&outputRegisters, CLS_DWARF_REG_RETURN), 777);
- }
- #endif
- @end
|