From 3d2911f5cdabb6bb46bc9962c10c409f99b7c4ff Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Sat, 16 May 2015 00:08:02 +0000 Subject: [PATCH] [LLD] Make sure MachO FDEs read their augmentation data strings from the right CIE, not just the most recently encountered one. llvm-svn: 237491 --- .../MachO/MachONormalizedFileToAtoms.cpp | 46 +++-- .../mach-o/parse-eh-frame-relocs-x86_64.yaml | 179 ++++++++++++------ 2 files changed, 152 insertions(+), 73 deletions(-) diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp index d92d7a7a798f..6ef5a0b4a459 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp @@ -647,13 +647,15 @@ static int64_t readSPtr(bool is64, bool isBig, const uint8_t *addr) { /// --- Augmentation String Processing --- -struct AugmentationDataInfo { - bool _present = false; +struct CIEInfo { + bool _augmentationDataPresent = false; bool _mayHaveLSDA = false; }; +typedef llvm::DenseMap CIEInfoMap; + static std::error_code processAugmentationString(const uint8_t *augStr, - AugmentationDataInfo &adi, + CIEInfo &cieInfo, unsigned *len = nullptr) { if (augStr[0] == '\0') { @@ -666,12 +668,12 @@ static std::error_code processAugmentationString(const uint8_t *augStr, return make_dynamic_error_code("expected 'z' at start of augmentation " "string"); - adi._present = true; + cieInfo._augmentationDataPresent = true; uint64_t idx = 1; while (augStr[idx] != '\0') { if (augStr[idx] == 'L') { - adi._mayHaveLSDA = true; + cieInfo._mayHaveLSDA = true; ++idx; } else ++idx; @@ -684,10 +686,12 @@ static std::error_code processAugmentationString(const uint8_t *augStr, static std::error_code processCIE(const NormalizedFile &normalizedFile, MachODefinedAtom *atom, - AugmentationDataInfo &adi) { + CIEInfoMap &cieInfos) { const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); - const uint8_t *frameData = atom->rawContent().data(); + + CIEInfo cieInfo; + uint32_t size = read32(frameData, isBig); uint64_t cieIDField = size == 0xffffffffU ? sizeof(uint32_t) + sizeof(uint64_t) @@ -696,9 +700,11 @@ static std::error_code processCIE(const NormalizedFile &normalizedFile, uint64_t augmentationStringField = versionField + sizeof(uint8_t); if (auto err = processAugmentationString(frameData + augmentationStringField, - adi)) + cieInfo)) return err; + cieInfos[atom] = std::move(cieInfo); + return std::error_code(); } @@ -708,7 +714,7 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile, const Section *ehFrameSection, MachODefinedAtom *atom, uint64_t offset, - const AugmentationDataInfo &adi) { + const CIEInfoMap &cieInfos) { const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch); @@ -730,11 +736,16 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile, cieAddress -= cieDelta; Reference::Addend addend; - const Atom *cie = + const MachODefinedAtom *cie = findAtomCoveringAddress(normalizedFile, file, cieAddress, &addend); atom->addReference(cieFieldInFDE, handler.unwindRefToCIEKind(), cie, addend, handler.kindArch()); + assert(cie && cie->contentType() == DefinedAtom::typeCFI && !addend && + "FDE's CIE field does not point at the start of a CIE."); + + const CIEInfo &cieInfo = cieInfos.find(cie)->second; + // Linker needs to fixup reference from the FDE to the function it's // describing. FIXME: there are actually different ways to do this, and the // particular method used is specified in the CIE's augmentation fields @@ -752,7 +763,7 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile, func, addend, handler.kindArch()); // Handle the augmentation data if there is any. - if (adi._present) { + if (cieInfo._augmentationDataPresent) { // First process the augmentation data length field. uint64_t augmentationDataLengthFieldInFDE = rangeFieldInFDE + 2 * (is64 ? sizeof(uint64_t) : sizeof(uint32_t)); @@ -761,7 +772,7 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile, llvm::decodeULEB128(frameData + augmentationDataLengthFieldInFDE, &lengthFieldSize); - if (adi._mayHaveLSDA && augmentationDataLength > 0) { + if (cieInfo._mayHaveLSDA && augmentationDataLength > 0) { // Look at the augmentation data field. uint64_t augmentationDataFieldInFDE = @@ -800,7 +811,7 @@ std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile, return std::error_code(); std::error_code ehFrameErr; - AugmentationDataInfo adi; + CIEInfoMap cieInfos; file.eachAtomInSection(*ehFrameSection, [&](MachODefinedAtom *atom, uint64_t offset) -> void { @@ -811,12 +822,11 @@ std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile, return; const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); - if (ArchHandler::isDwarfCIE(isBig, atom)) { - adi = AugmentationDataInfo(); - ehFrameErr = processCIE(normalizedFile, atom, adi); - } else + if (ArchHandler::isDwarfCIE(isBig, atom)) + ehFrameErr = processCIE(normalizedFile, atom, cieInfos); + else ehFrameErr = processFDE(normalizedFile, file, handler, ehFrameSection, - atom, offset, adi); + atom, offset, cieInfos); }); return ehFrameErr; diff --git a/lld/test/mach-o/parse-eh-frame-relocs-x86_64.yaml b/lld/test/mach-o/parse-eh-frame-relocs-x86_64.yaml index c8281b3d8c6b..b009cbcea139 100644 --- a/lld/test/mach-o/parse-eh-frame-relocs-x86_64.yaml +++ b/lld/test/mach-o/parse-eh-frame-relocs-x86_64.yaml @@ -1,83 +1,110 @@ # RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s # # Test parsing of x86_64 __eh_frame (dwarf unwind) relocations. -# -#_catchMyException: -# pushq %rbp -# movq %rsp, %rbp -# callq _foo -# popq %rbp -# retq -# movq %rax, %rdi -# callq ___cxa_begin_catch -# popq %rbp -# jmp ___cxa_end_catch --- !mach-o arch: x86_64 file-type: MH_OBJECT -flags: [ ] +flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ] +compat-version: 0.0 +current-version: 0.0 +has-UUID: false +OS: unknown sections: - segment: __TEXT section: __text type: S_REGULAR attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ] + alignment: 16 address: 0x0000000000000000 - content: [0x55, 0x48, 0x89, 0xe5, 0xe8, 0x00, 0x00, 0x00, - 0x00, 0x5d, 0xc3, 0x48, 0x89, 0xc7, 0xe8, 0x00, - 0x00, 0x00, 0x00, 0x5d, 0xe9, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 ] - relocations: - - offset: 0x00000015 - type: X86_64_RELOC_BRANCH - length: 2 - pc-rel: true - extern: true - symbol: 2 - - offset: 0x0000000f - type: X86_64_RELOC_BRANCH - length: 2 - pc-rel: true - extern: true - symbol: 1 - - offset: 0x00000005 - type: X86_64_RELOC_BRANCH - length: 2 - pc-rel: true - extern: true - symbol: 0 + content: [ 0x55, 0x48, 0x89, 0xE5, 0xE8, 0x00, 0x00, 0x00, + 0x00, 0x5D, 0xC3, 0x48, 0x89, 0xC7, 0xE8, 0x00, + 0x00, 0x00, 0x00, 0x5D, 0xE9, 0x00, 0x00, 0x00, + 0x00, 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x66, 0x2E, + 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x55, 0x48, 0x89, 0xE5, 0xE8, 0x00, 0x00, 0x00, + 0x00, 0x5D, 0xC3, 0x48, 0x89, 0xC7, 0xE8, 0x00, + 0x00, 0x00, 0x00, 0x5D, 0xE9, 0x00, 0x00, 0x00, + 0x00 ] - segment: __TEXT section: __gcc_except_tab type: S_REGULAR attributes: [ ] - address: 0x000000000000001c - content: [ 0x00, 0x00, 0x00, 0x00 ] + alignment: 4 + address: 0x000000000000004C + content: [ 0xFF, 0x9B, 0xA2, 0x80, 0x80, 0x00, 0x03, 0x1A, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x01, 0x09, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x9B, 0xA2, 0x80, 0x80, 0x00, 0x03, 0x1A, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x01, 0x09, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 ] - segment: __TEXT section: __eh_frame type: S_COALESCED attributes: [ ] - address: 0x0000000000000020 - content: [ 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x7a, 0x50, 0x4c, 0x52, 0x00, 0x01, 0x78, - 0x10, 0x07, 0x9b, 0x04, 0x00, 0x00, 0x00, 0x10, - 0x10, 0x0c, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, - 0xB8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + alignment: 8 + address: 0x0000000000000100 + content: [ 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x7A, 0x50, 0x4C, 0x52, 0x00, 0x01, 0x78, + 0x10, 0x07, 0x9B, 0x04, 0x00, 0x00, 0x00, 0x10, + 0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00, + 0x2C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0xD8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x41, 0x0e, 0x10, 0x86, 0x02, 0x43, 0x0d, + 0x08, 0x13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x10, 0x01, + 0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, + 0xB0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2C, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, + 0x98, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0xCB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] - - segment: __DATA - section: __data - type: S_REGULAR - attributes: [ ] - address: 0x0000000000000068 - content: [ 0x00, 0x00, 0x00, 0x00 ] + relocations: + - offset: 0x00000013 + type: X86_64_RELOC_GOT + length: 2 + pc-rel: true + extern: true + symbol: 8 local-symbols: - - name: _catchMyException + - name: GCC_except_table0 type: N_SECT + sect: 2 + value: 0x000000000000004C + - name: GCC_except_table2 + type: N_SECT + sect: 2 + value: 0x0000000000000074 +global-symbols: + - name: _catchMyException1 + type: N_SECT + scope: [ N_EXT ] sect: 1 value: 0x0000000000000000 + - name: _catchMyException2 + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000030 + - name: _bar + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000020 undefined-symbols: - name: _foo type: N_UNDF @@ -91,17 +118,59 @@ undefined-symbols: type: N_UNDF scope: [ N_EXT ] value: 0x0000000000000000 + - name: ___gxx_personality_v0 + type: N_UNDF + scope: [ N_EXT ] + value: 0x0000000000000000 +page-size: 0x00000000 ... +# Check that LSDA fields are fixed up correctly, even when there are multiple +# CIEs involved. +# +# (1) Check that we can relocate an LSDA at all. Requires correct interpretation +# of augmentation data strings in CIEs and augmentation data fields of FDEs. +# # CHECK: - type: unwind-cfi # CHECK-NOT: - type: # CHECK: references: # CHECK-NEXT: - kind: negDelta32 # CHECK-NEXT: offset: 4 -# CHECK-NEXT: target: L000 +# CHECK-NEXT: target: L002 # CHECK-NEXT: - kind: unwindFDEToFunction # CHECK-NEXT: offset: 8 -# CHECK-NEXT: target: _catchMyException +# CHECK-NEXT: target: _catchMyException1 # CHECK-NEXT: - kind: unwindFDEToFunction # CHECK-NEXT: offset: 25 +# CHECK-NEXT: target: GCC_except_table0 +# +# (2) Check that we have an intervening FDE with a different CIE. +# If the test fails here then test (3) probably isn't testing what it +# should, and this test-case should be updated. +# +# CHECK: - type: unwind-cfi +# CHECK-NOT: - type: +# CHECK: references: +# CHECK-NEXT: - kind: negDelta32 +# CHECK-NEXT: offset: 4 # CHECK-NEXT: target: L001 +# CHECK-NEXT: - kind: unwindFDEToFunction +# CHECK-NEXT: offset: 8 +# CHECK-NEXT: target: _bar +# +# (3) Check that we can relocate the LSDA on a second FDE that references the +# original CIE from (1). Requires us to match this FDE up with the correct +# CIE. +# +# CHECK-NEXT: - type: unwind-cfi +# CHECK-NOT: - type: +# CHECK: references: +# CHECK-NEXT: - kind: negDelta32 +# CHECK-NEXT: offset: 4 +# CHECK-NEXT: target: L002 +# CHECK-NEXT: - kind: unwindFDEToFunction +# CHECK-NEXT: offset: 8 +# CHECK-NEXT: target: _catchMyException2 +# CHECK-NEXT: - kind: unwindFDEToFunction +# CHECK-NEXT: offset: 25 +# CHECK-NEXT: target: GCC_except_table2