Index: llvm/test/tools/dsymutil/X86/eh_frame.test =================================================================== --- /dev/null +++ llvm/test/tools/dsymutil/X86/eh_frame.test @@ -0,0 +1,24 @@ +// FIXME: Replace otool with llvm-objcopy --dump-section=__TEXT,__eh_frame. +// REQUIRES : system-darwin + +$ cat eh_frame.cpp +int f1() +{ + volatile int i; + return i; +} + +int main(int argc, char** argv) +{ + return f1(); +} + +$ clang eh_frame.cpp -g -c -o eh_frame.o +$ ld -no_compact_unwind eh_frame.o -o eh_frame.out + +RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/eh_frame/eh_frame.out -o %t.dSYM +RUN: otool -s __TEXT __eh_frame %p/../Inputs/private/tmp/eh_frame/eh_frame.out | FileCheck %s +RUN: otool -s __TEXT __eh_frame %t.dSYM/Contents/Resources/DWARF/eh_frame.out | FileCheck %s + +CHECK: 14 00 00 00 00 00 00 00 01 7a 52 00 01 78 10 01 +CHECK: 10 0c 07 08 90 01 00 00 Index: llvm/tools/dsymutil/MachOUtils.cpp =================================================================== --- llvm/tools/dsymutil/MachOUtils.cpp +++ llvm/tools/dsymutil/MachOUtils.cpp @@ -239,27 +239,38 @@ // Transfer \a Segment from \a Obj to the output file. This calls into \a Writer // to write these load commands directly in the output file at the current // position. +// // The function also tries to find a hole in the address map to fit the __DWARF // segment of \a DwarfSegmentSize size. \a EndAddress is updated to point at the // highest segment address. +// // When the __LINKEDIT segment is transferred, its offset and size are set resp. // to \a LinkeditOffset and \a LinkeditSize. +// +// When the eh_frame section is transferred, its offset and size are set resp. +// to \a EHFrameOffset and \a EHFrameSize. template static void transferSegmentAndSections( const object::MachOObjectFile::LoadCommandInfo &LCI, SegmentTy Segment, const object::MachOObjectFile &Obj, MachObjectWriter &Writer, - uint64_t LinkeditOffset, uint64_t LinkeditSize, uint64_t DwarfSegmentSize, - uint64_t &GapForDwarf, uint64_t &EndAddress) { + uint64_t LinkeditOffset, uint64_t LinkeditSize, uint64_t EHFrameOffset, + uint64_t EHFrameSize, uint64_t DwarfSegmentSize, uint64_t &GapForDwarf, + uint64_t &EndAddress) { if (StringRef("__DWARF") == Segment.segname) return; - Segment.fileoff = Segment.filesize = 0; - - if (StringRef("__LINKEDIT") == Segment.segname) { + if (StringRef("__TEXT") == Segment.segname && EHFrameSize != 0) { + Segment.fileoff = EHFrameOffset; + Segment.filesize = EHFrameSize; + // Resize vmsize by rounding to the page size. + Segment.vmsize = alignTo(EHFrameSize, 0x1000); + } else if (StringRef("__LINKEDIT") == Segment.segname) { Segment.fileoff = LinkeditOffset; Segment.filesize = LinkeditSize; // Resize vmsize by rounding to the page size. Segment.vmsize = alignTo(LinkeditSize, 0x1000); + } else { + Segment.fileoff = Segment.filesize = 0; } // Check if the end address of the last segment and our current @@ -280,7 +291,10 @@ Writer.W.OS.write(reinterpret_cast(&Segment), sizeof(Segment)); for (unsigned i = 0; i < nsects; ++i) { auto Sect = getSection(Obj, Segment, LCI, i); - Sect.offset = Sect.reloff = Sect.nreloc = 0; + if (Sect.sectname == "eh_frame") + Sect.offset = Sect.reloff = EHFrameOffset; + else + Sect.offset = Sect.reloff = Sect.nreloc = 0; if (Obj.isLittleEndian() != sys::IsLittleEndianHost) MachO::swapStruct(Sect); Writer.W.OS.write(reinterpret_cast(&Sect), sizeof(Sect)); @@ -417,6 +431,27 @@ ++NumLoadCommands; } + // If we have a valid eh_frame to copy, do it. + uint64_t EHFrameSize = 0; + StringRef EHFrameData; + for (const object::SectionRef &Section : InputBinary.sections()) { + Expected NameOrErr = Section.getName(); + if (!NameOrErr) { + consumeError(NameOrErr.takeError()); + continue; + } + StringRef SectionName = *NameOrErr; + SectionName = SectionName.substr(SectionName.find_first_not_of("._")); + if (SectionName == "eh_frame") { + if (Expected ContentsOrErr = Section.getContents()) { + EHFrameData = *ContentsOrErr; + EHFrameSize = Section.getSize(); + } else { + consumeError(ContentsOrErr.takeError()); + } + } + } + unsigned HeaderSize = Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); // We will copy every segment that isn't __DWARF. @@ -496,7 +531,10 @@ Writer.writeSymtabLoadCommand(SymtabStart, NumSyms, StringStart, NewStringsSize); - uint64_t DwarfSegmentStart = StringStart + NewStringsSize; + uint64_t EHFrameStart = StringStart + NewStringsSize; + EHFrameStart = alignTo(EHFrameStart, 0x1000); + + uint64_t DwarfSegmentStart = EHFrameStart + EHFrameSize; DwarfSegmentStart = alignTo(DwarfSegmentStart, 0x1000); // Write the load commands for the segments and sections we 'import' from @@ -505,15 +543,15 @@ uint64_t GapForDwarf = UINT64_MAX; for (auto &LCI : InputBinary.load_commands()) { if (LCI.C.cmd == MachO::LC_SEGMENT) - transferSegmentAndSections(LCI, InputBinary.getSegmentLoadCommand(LCI), - InputBinary, Writer, SymtabStart, - StringStart + NewStringsSize - SymtabStart, - DwarfSegmentSize, GapForDwarf, EndAddress); + transferSegmentAndSections( + LCI, InputBinary.getSegmentLoadCommand(LCI), InputBinary, Writer, + SymtabStart, StringStart + NewStringsSize - SymtabStart, EHFrameStart, + EHFrameSize, DwarfSegmentSize, GapForDwarf, EndAddress); else if (LCI.C.cmd == MachO::LC_SEGMENT_64) - transferSegmentAndSections(LCI, InputBinary.getSegment64LoadCommand(LCI), - InputBinary, Writer, SymtabStart, - StringStart + NewStringsSize - SymtabStart, - DwarfSegmentSize, GapForDwarf, EndAddress); + transferSegmentAndSections( + LCI, InputBinary.getSegment64LoadCommand(LCI), InputBinary, Writer, + SymtabStart, StringStart + NewStringsSize - SymtabStart, EHFrameStart, + EHFrameSize, DwarfSegmentSize, GapForDwarf, EndAddress); } uint64_t DwarfVMAddr = alignTo(EndAddress, 0x1000); @@ -554,11 +592,19 @@ EntryRef.getString().size() + 1); } } - assert(OutFile.tell() == StringStart + NewStringsSize); + // Pad till the EH frame start. + OutFile.write_zeros(EHFrameStart - (StringStart + NewStringsSize)); + assert(OutFile.tell() == EHFrameStart); + + // Transfer eh_frame. + if (EHFrameSize > 0) + OutFile << EHFrameData; + assert(OutFile.tell() == EHFrameStart + EHFrameSize); + // Pad till the Dwarf segment start. - OutFile.write_zeros(DwarfSegmentStart - (StringStart + NewStringsSize)); + OutFile.write_zeros(DwarfSegmentStart - (EHFrameStart + EHFrameSize)); assert(OutFile.tell() == DwarfSegmentStart); // Emit the Dwarf sections contents.