From 647e1ed343ca96af002d6446ac340f86a7691f27 Mon Sep 17 00:00:00 2001 From: Shankar Easwaran Date: Wed, 11 Feb 2026 16:24:14 -0600 Subject: [PATCH] [NFC] Create FDE and CIE as a piece of EhFrameFragment We used to create CIE fragments and FDE fragments, which might interfere with how dependent chunks are handled. The atomic unit that the linker should treat are chunks that cannot be further divided up. Fix these cases and cleanup to form a better design. Also add support for dumping EhFrame and EhFrame Header chunks for debug support, making the linker map files further useful to debug eh_frame handling. Signed-off-by: Shankar Easwaran --- include/eld/Fragment/EhFrameFragment.h | 117 +++---- include/eld/Fragment/EhFrameHdrFragment.h | 6 +- include/eld/Readers/EhFrameHdrSection.h | 8 +- include/eld/Readers/EhFrameSection.h | 22 +- lib/Fragment/EhFrameFragment.cpp | 288 ++++++++++++------ lib/Fragment/EhFrameHdrFragment.cpp | 115 +++++-- lib/Fragment/FragmentRef.cpp | 2 +- lib/Object/ObjectLinker.cpp | 4 +- lib/Readers/EhFrameHdrSection.cpp | 6 +- lib/Readers/EhFrameSection.cpp | 61 ++-- lib/Target/GNULDBackend.cpp | 13 +- .../Map/EhFrameDump/EhFrameDump.test | 14 + .../Map/EhFrameDump/EhFrameDumpGcFDE.test | 12 + .../Map/EhFrameDump/EhFrameDumpMergeCIE.test | 14 + .../Map/EhFrameDump/EhFrameDumpMulti.test | 14 + .../Map/EhFrameDump/Inputs/eh-frame-gc.s | 27 ++ .../EhFrameDump/Inputs/eh-frame-map-multi.s | 16 + .../Map/EhFrameDump/Inputs/eh-frame-map.s | 8 + .../Map/EhFrameDump/Inputs/eh-frame-merge-1.s | 8 + .../Map/EhFrameDump/Inputs/eh-frame-merge-2.s | 8 + 20 files changed, 534 insertions(+), 229 deletions(-) create mode 100644 test/Common/standalone/Map/EhFrameDump/EhFrameDump.test create mode 100644 test/Common/standalone/Map/EhFrameDump/EhFrameDumpGcFDE.test create mode 100644 test/Common/standalone/Map/EhFrameDump/EhFrameDumpMergeCIE.test create mode 100644 test/Common/standalone/Map/EhFrameDump/EhFrameDumpMulti.test create mode 100644 test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-gc.s create mode 100644 test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-map-multi.s create mode 100644 test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-map.s create mode 100644 test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-merge-1.s create mode 100644 test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-merge-2.s diff --git a/include/eld/Fragment/EhFrameFragment.h b/include/eld/Fragment/EhFrameFragment.h index 29409a6ae..1d55b93fe 100644 --- a/include/eld/Fragment/EhFrameFragment.h +++ b/include/eld/Fragment/EhFrameFragment.h @@ -7,8 +7,7 @@ #ifndef ELD_FRAGMENT_EHFRAMEFRAGMENT_H #define ELD_FRAGMENT_EHFRAMEFRAGMENT_H -#include "eld/Fragment/Fragment.h" -#include "eld/Readers/EhFrameSection.h" +#include "eld/Fragment/RegionFragment.h" #include "llvm/ADT/ArrayRef.h" #include #include @@ -16,14 +15,16 @@ namespace eld { class DiagnosticEngine; -class EhFrameSection; +class EhFrameFragment; +class ELFSection; +class FDEPiece; class LinkerConfig; class Relocation; class EhFramePiece { public: - EhFramePiece(size_t Off, size_t Sz, Relocation *R, EhFrameSection *O) - : MOffset(Off), ThisSize(Sz), MRelocation(R), MSection(O) {} + EhFramePiece(size_t Off, size_t Sz, Relocation *R) + : MOffset(Off), ThisSize(Sz), MRelocation(R) {} size_t getSize() const { return ThisSize; } @@ -37,23 +38,24 @@ class EhFramePiece { Relocation *getRelocation() const { return MRelocation; } - EhFrameSection *getOwningSection() const { return MSection; } + llvm::ArrayRef getData(llvm::StringRef Region) const; - llvm::ArrayRef getData(); + uint8_t readByte(DiagnosticEngine *DiagEngine, const ELFSection &S); - uint8_t readByte(DiagnosticEngine *DiagEngine); + void skipBytes(size_t Count, DiagnosticEngine *DiagEngine, + const ELFSection &S); - void skipBytes(size_t Count, DiagnosticEngine *DiagEngine); + llvm::StringRef readString(DiagnosticEngine *DiagEngine, const ELFSection &S); - llvm::StringRef readString(DiagnosticEngine *DiagEngine); - - void skipLeb128(DiagnosticEngine *DiagEngine); + void skipLeb128(DiagnosticEngine *DiagEngine, const ELFSection &S); size_t getAugPSize(unsigned Enc, bool Is64Bit, DiagnosticEngine *DiagEngine); - void skipAugP(bool Is64Bit, DiagnosticEngine *DiagEngine); + void skipAugP(bool Is64Bit, DiagnosticEngine *DiagEngine, + const ELFSection &S); - uint8_t getFdeEncoding(bool Is64Bit, DiagnosticEngine *DiagEngine); + uint8_t getFdeEncoding(llvm::StringRef Region, bool Is64Bit, + DiagnosticEngine *DiagEngine, const ELFSection &S); private: llvm::ArrayRef D; @@ -61,74 +63,87 @@ class EhFramePiece { size_t MOutputOffset = -1; size_t ThisSize = 0; Relocation *MRelocation = nullptr; - EhFrameSection *MSection = nullptr; }; -class FDEFragment : public Fragment { +class EhFrameCIE { public: - FDEFragment(EhFramePiece &P, EhFrameSection *O); + explicit EhFrameCIE(EhFramePiece &P) : CIE(P) {} - virtual ~FDEFragment(); + const std::string name() const { return "CIE"; } - /// name - name of this stub - const std::string name() const; + size_t size() const; - virtual size_t size() const override; + EhFramePiece &getCIE() { return CIE; } - llvm::ArrayRef getContent() const; + const EhFramePiece &getCIE() const { return CIE; } - static bool classof(const Fragment *F) { - return F->getKind() == Fragment::Type::FDE; - } + llvm::ArrayRef getContent(const EhFrameFragment &F) const; - virtual eld::Expected emit(MemoryRegion &Mr, Module &M) override; + eld::Expected emit(MemoryRegion &Mr, Module &M, uint32_t CieOff, + const EhFrameFragment &F); - virtual void dump(llvm::raw_ostream &OS) override; + void dump(llvm::raw_ostream &OS) {} - EhFramePiece &getFDE() { return FDE; } + void appendFDE(FDEPiece *F) { FDEs.push_back(F); } + + const std::vector &getFDEs() const { return FDEs; } + + void setOffset(uint32_t CieOff); - size_t getSize() const; + size_t getNumFDE() const { return FDEs.size(); } + + uint8_t getFdeEncoding(const EhFrameFragment &F, bool Is64Bit, + DiagnosticEngine *DiagEngine); private: - EhFramePiece &FDE; + EhFramePiece &CIE; + std::vector FDEs; }; -class CIEFragment : public Fragment { +class EhFrameFragment : public RegionFragment { public: - CIEFragment(EhFramePiece &P, EhFrameSection *O); + EhFrameFragment(llvm::StringRef Region, ELFSection *O, uint32_t Align = 1) + : RegionFragment(Region, O, Fragment::Type::Region, Align) {} - virtual ~CIEFragment(); + EhFramePiece &addPiece(size_t Off, size_t Sz, Relocation *R); - /// name - name of this stub - const std::string name() const; + std::vector &getPieces() { return Pieces; } + const std::vector &getPieces() const { return Pieces; } - virtual size_t size() const override; + std::vector &getCIEs() { return CIEs; } + const std::vector &getCIEs() const { return CIEs; } - llvm::ArrayRef getContent() const; + size_t size() const override; - static bool classof(const Fragment *F) { - return F->getKind() == Fragment::CIE; - } + void setOffset(uint32_t O) override; - static bool classof(const CIEFragment *) { return true; } + eld::Expected emit(MemoryRegion &Mr, Module &M) override; - virtual eld::Expected emit(MemoryRegion &Mr, Module &M) override; + void dump(llvm::raw_ostream &OS) override; - virtual void dump(llvm::raw_ostream &OS) override; +private: + std::vector Pieces; + std::vector CIEs; +}; - void appendFragment(FDEFragment *F) { FDEs.push_back(F); } +class FDEPiece { +public: + explicit FDEPiece(EhFramePiece &P) : FDE(P) {} - const std::vector &getFDEs() const { return FDEs; } + size_t size() const { return FDE.getSize(); } - void setOffset(uint32_t Offset) override; + llvm::ArrayRef getContent(const EhFrameFragment &F) const { + return FDE.getData(F.getRegion()); + } - size_t getNumFDE() const { return FDEs.size(); } + eld::Expected emit(MemoryRegion &Mr, Module &M, + const EhFrameFragment &F); - uint8_t getFdeEncoding(bool Is64Bit, DiagnosticEngine *DiagEngine); + EhFramePiece &getFDE() { return FDE; } + const EhFramePiece &getFDE() const { return FDE; } -protected: - EhFramePiece &CIE; - std::vector FDEs; +private: + EhFramePiece &FDE; }; } // namespace eld diff --git a/include/eld/Fragment/EhFrameHdrFragment.h b/include/eld/Fragment/EhFrameHdrFragment.h index fede96190..2f5a76395 100644 --- a/include/eld/Fragment/EhFrameHdrFragment.h +++ b/include/eld/Fragment/EhFrameHdrFragment.h @@ -17,10 +17,10 @@ namespace eld { class DiagnosticEngine; +class EhFrameFragment; class EhFrameHdrSection; class LinkerConfig; -class CIEFragment; -class FDEFragment; +class FDEPiece; class Relocation; class EhFrameHdrFragment : public Fragment { @@ -56,7 +56,7 @@ class EhFrameHdrFragment : public Fragment { uint64_t readFdeAddr(uint8_t *Buf, int Size, DiagnosticEngine *DiagEngine); - uint64_t getFdePc(uint8_t *, FDEFragment *, uint8_t Enc, + uint64_t getFdePc(uint8_t *, const EhFrameFragment &, FDEPiece *, uint8_t Enc, DiagnosticEngine *DiagEngine); bool Is64Bit = false; diff --git a/include/eld/Readers/EhFrameHdrSection.h b/include/eld/Readers/EhFrameHdrSection.h index e152e3c48..3780379e8 100644 --- a/include/eld/Readers/EhFrameHdrSection.h +++ b/include/eld/Readers/EhFrameHdrSection.h @@ -15,7 +15,7 @@ namespace eld { class DiagnosticEngine; class ELFSection; -class CIEFragment; +class EhFrameFragment; class EhFrameHdrFragment; class EhFrameHdrSection : public ELFSection { @@ -27,7 +27,7 @@ class EhFrameHdrSection : public ELFSection { return S->getSectionKind() == Section::Kind::EhFrameHdr; } - void addCIE(std::vector &C); + void addEhFrame(EhFrameFragment &F); size_t getNumCIE() const { return NumCIE; } @@ -35,10 +35,10 @@ class EhFrameHdrSection : public ELFSection { size_t sizeOfHeader() const { return 12; } - std::vector &getCIEs() { return m_CIEs; } + const std::vector &getEhFrames() const { return EhFrames; } private: - std::vector m_CIEs; + std::vector EhFrames; size_t NumCIE = 0; size_t NumFDE = 0; }; diff --git a/include/eld/Readers/EhFrameSection.h b/include/eld/Readers/EhFrameSection.h index d50ba07cd..9e4d497c9 100644 --- a/include/eld/Readers/EhFrameSection.h +++ b/include/eld/Readers/EhFrameSection.h @@ -18,10 +18,10 @@ class DiagnosticPrinter; class ELFSection; class Module; class Relocation; -class RegionFragment; class EhFrameSection; -class CIEFragment; +class EhFrameCIE; class EhFramePiece; +class EhFrameFragment; class EhFrameSection : public ELFSection { public: @@ -36,20 +36,16 @@ class EhFrameSection : public ELFSection { Relocation *getReloc(size_t Off, size_t Size); - RegionFragment *getEhFrameFragment() const { return m_EhFrame; } + EhFrameFragment *getEhFrameFragment() const { return m_EhFrame; } - llvm::ArrayRef getData() const { return Data; } + llvm::ArrayRef getData() const; bool createCIEAndFDEFragments(); - CIEFragment *addCie(EhFramePiece &P); + EhFrameCIE *addCie(EhFramePiece &P); bool isFdeLive(EhFramePiece &P); - std::vector &getPieces() { return m_EhFramePieces; } - - std::vector &getCIEs() { return m_CIEFragments; } - void finishAddingFragments(Module &M); private: @@ -57,13 +53,7 @@ class EhFrameSection : public ELFSection { DiagnosticPrinter *getDiagPrinter(); private: - RegionFragment *m_EhFrame = nullptr; - llvm::ArrayRef Data; - std::vector m_EhFramePieces; - llvm::DenseMap m_OffsetToCie; - std::vector m_CIEFragments; - size_t NumCie = 0; - size_t NumFDE = 0; + EhFrameFragment *m_EhFrame = nullptr; DiagnosticEngine *m_DiagEngine = nullptr; }; } // namespace eld diff --git a/lib/Fragment/EhFrameFragment.cpp b/lib/Fragment/EhFrameFragment.cpp index 63656d0e0..f922d4503 100644 --- a/lib/Fragment/EhFrameFragment.cpp +++ b/lib/Fragment/EhFrameFragment.cpp @@ -14,7 +14,8 @@ #include "eld/Fragment/EhFrameFragment.h" #include "eld/Core/Module.h" #include "eld/Input/InputFile.h" -#include "eld/Readers/EhFrameSection.h" +#include "eld/Readers/ELFSection.h" +#include "eld/Readers/Relocation.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" @@ -22,41 +23,21 @@ #include "llvm/Support/Endian.h" using namespace eld; -// -// FDE -// -FDEFragment::FDEFragment(EhFramePiece &P, EhFrameSection *O) - : Fragment(Fragment::FDE, O, 1), FDE(P) {} - -const std::string FDEFragment::name() const { return "FDE"; } - -size_t FDEFragment::size() const { return FDE.getSize(); } - -llvm::ArrayRef FDEFragment::getContent() const { - return FDE.getData(); +EhFramePiece &EhFrameFragment::addPiece(size_t Off, size_t Sz, Relocation *R) { + Pieces.emplace_back(Off, Sz, R); + return Pieces.back(); } -void FDEFragment::dump(llvm::raw_ostream &OS) {} - -FDEFragment::~FDEFragment() {} - -eld::Expected FDEFragment::emit(MemoryRegion &Mr, Module &M) { - uint8_t *Buf = Mr.begin() + getOffset(M.getConfig().getDiagEngine()); - memcpy(Buf, getContent().data(), size()); +eld::Expected FDEPiece::emit(MemoryRegion &Mr, Module &M, + const EhFrameFragment &F) { + assert(FDE.hasOutputOffset() && "FDE output offset must be assigned"); + uint8_t *Buf = Mr.begin() + FDE.getOutputOffset(); + memcpy(Buf, getContent(F).data(), size()); llvm::support::endian::write32le(Buf, FDE.getSize() - 4); return {}; } -// -// CIE -// - -CIEFragment::CIEFragment(EhFramePiece &P, EhFrameSection *O) - : Fragment(Fragment::CIE, O, 1), CIE(P) {} - -const std::string CIEFragment::name() const { return "CIE"; } - -size_t CIEFragment::size() const { +size_t EhFrameCIE::size() const { if (!FDEs.size()) return 0; uint32_t Off = CIE.getSize(); @@ -65,62 +46,177 @@ size_t CIEFragment::size() const { return Off; } -llvm::ArrayRef CIEFragment::getContent() const { - return CIE.getData(); +llvm::ArrayRef EhFrameCIE::getContent(const EhFrameFragment &F) const { + return CIE.getData(F.getRegion()); } -void CIEFragment::dump(llvm::raw_ostream &OS) {} - -CIEFragment::~CIEFragment() {} - -void CIEFragment::setOffset(uint32_t O) { - Fragment::setOffset(O); +void EhFrameCIE::setOffset(uint32_t CieOff) { if (!FDEs.size()) return; - uint32_t Off = getOffset() + CIE.getSize(); - for (auto &F : FDEs) { - F->setOffset(Off); - F->getFDE().setOutputOffset(F->getOffset()); - Off = F->getOffset() + F->size(); + uint32_t Off = CieOff + CIE.getSize(); + for (auto *F : FDEs) { + F->getFDE().setOutputOffset(Off); + Off += F->size(); } - CIE.setOutputOffset(getOffset()); + CIE.setOutputOffset(CieOff); } -eld::Expected CIEFragment::emit(MemoryRegion &Mr, Module &M) { +eld::Expected EhFrameCIE::emit(MemoryRegion &Mr, Module &M, + uint32_t CieOff, + const EhFrameFragment &F) { if (!FDEs.size()) return {}; - uint8_t *Buf = Mr.begin() + getOffset(M.getConfig().getDiagEngine()); - memcpy(Buf, getContent().data(), CIE.getSize()); + uint8_t *Buf = Mr.begin() + CieOff; + memcpy(Buf, getContent(F).data(), CIE.getSize()); llvm::support::endian::write32le(Buf, CIE.getSize() - 4); - for (auto &F : FDEs) { - F->emit(Mr, M); - uint8_t *FDEBuf = Mr.begin() + F->getOffset(M.getConfig().getDiagEngine()); - llvm::support::endian::write32le( - FDEBuf + 4, F->getOffset(M.getConfig().getDiagEngine()) + 4 - - this->getOffset(M.getConfig().getDiagEngine())); + for (auto *Fde : FDEs) { + auto ExpEmit = Fde->emit(Mr, M, F); + if (!ExpEmit) + return ExpEmit; + uint32_t FdeOff = Fde->getFDE().getOutputOffset(); + uint8_t *FDEBuf = Mr.begin() + FdeOff; + llvm::support::endian::write32le(FDEBuf + 4, FdeOff + 4 - CieOff); } return {}; } -uint8_t CIEFragment::getFdeEncoding(bool Is64Bit, - DiagnosticEngine *DiagEngine) { - return CIE.getFdeEncoding(Is64Bit, DiagEngine); +uint8_t EhFrameCIE::getFdeEncoding(const EhFrameFragment &F, bool Is64Bit, + DiagnosticEngine *DiagEngine) { + return CIE.getFdeEncoding(F.getRegion(), Is64Bit, DiagEngine, + *F.getOwningSection()); } -// -// EhFrameFragment -// -llvm::ArrayRef EhFramePiece::getData() { - return {MSection->getData().data() + MOffset, ThisSize}; +size_t EhFrameFragment::size() const { + if (CIEs.empty()) + return RegionFragment::size(); + size_t Total = 0; + for (auto *C : CIEs) + Total += C->size(); + return Total; +} + +void EhFrameFragment::setOffset(uint32_t O) { + Fragment::setOffset(O); + if (CIEs.empty()) + return; + uint32_t Off = O; + for (auto *C : CIEs) { + if (!C->size()) + continue; + C->setOffset(Off); + Off += C->size(); + } +} + +eld::Expected EhFrameFragment::emit(MemoryRegion &Mr, Module &M) { + if (CIEs.empty()) + return RegionFragment::emit(Mr, M); + uint32_t Off = getOffset(M.getConfig().getDiagEngine()); + for (auto *C : CIEs) { + if (!C->size()) + continue; + auto ExpEmit = C->emit(Mr, M, Off, *this); + if (!ExpEmit) + return ExpEmit; + Off += C->size(); + } + return {}; +} + +void EhFrameFragment::dump(llvm::raw_ostream &OS) { + if (Pieces.empty() && CIEs.empty()) + return; + + auto PrintRelocSym = [&](const EhFramePiece &P) { + if (Relocation *R = P.getRelocation()) { + if (R->symInfo()) + OS << "\tsym=" << R->symInfo()->name(); + } + }; + + OS << "#\tEhFrameLayout\t" << getOwningSection()->name() << "\n"; + + if (!CIEs.empty()) { + for (const EhFrameCIE *C : CIEs) { + const EhFramePiece &CiePiece = C->getCIE(); + OS << "#\tCIE"; + if (CiePiece.hasOutputOffset()) { + OS << "\tout=0x"; + OS.write_hex(CiePiece.getOutputOffset()); + } else { + OS << "\tout="; + } + OS << "\tsize=0x"; + OS.write_hex(CiePiece.getSize()); + OS << "\tin=0x"; + OS.write_hex(CiePiece.getOffset()); + OS << "\tfdes=" << C->getNumFDE(); + PrintRelocSym(CiePiece); + OS << "\n"; + + for (const FDEPiece *F : C->getFDEs()) { + const EhFramePiece &FdePiece = F->getFDE(); + OS << "#\tFDE"; + if (FdePiece.hasOutputOffset()) { + OS << "\tout=0x"; + OS.write_hex(FdePiece.getOutputOffset()); + } else { + OS << "\tout="; + } + OS << "\tsize=0x"; + OS.write_hex(FdePiece.getSize()); + OS << "\tin=0x"; + OS.write_hex(FdePiece.getOffset()); + PrintRelocSym(FdePiece); + OS << "\n"; + } + } + return; + } + + llvm::StringRef Region = getRegion(); + for (const EhFramePiece &P : Pieces) { + OS << "#\tREC"; + if (P.hasOutputOffset()) { + OS << "\tout=0x"; + OS.write_hex(P.getOutputOffset()); + } else { + OS << "\tout="; + } + OS << "\tsize=0x"; + OS.write_hex(P.getSize()); + OS << "\tin=0x"; + OS.write_hex(P.getOffset()); + + if (P.getSize() == 4) { + OS << "\tEND"; + PrintRelocSym(P); + OS << "\n"; + continue; + } + + if (P.getSize() >= 8 && P.getOffset() + 8 <= Region.size()) { + uint32_t ID = llvm::support::endian::read32le( + reinterpret_cast(Region.data()) + P.getOffset() + 4); + OS << (ID == 0 ? "\tCIE" : "\tFDE"); + } + PrintRelocSym(P); + OS << "\n"; + } +} + +llvm::ArrayRef EhFramePiece::getData(llvm::StringRef Region) const { + return {reinterpret_cast(Region.data()) + MOffset, ThisSize}; } // Read a byte and advance D by one byte. // EhFramePiece and EhFrameHdrFragment can take diagnostics. -uint8_t EhFramePiece::readByte(DiagnosticEngine *DiagEngine) { +uint8_t EhFramePiece::readByte(DiagnosticEngine *DiagEngine, + const ELFSection &S) { if (D.empty()) { DiagEngine->raise(Diag::eh_frame_read_error) << "Unexpected end of CIE" - << MSection->getInputFile()->getInput()->decoratedPath(); + << S.getInputFile()->getInput()->decoratedPath(); return 0; } uint8_t B = D.front(); @@ -128,35 +224,37 @@ uint8_t EhFramePiece::readByte(DiagnosticEngine *DiagEngine) { return B; } -void EhFramePiece::skipBytes(size_t Count, DiagnosticEngine *DiagEngine) { +void EhFramePiece::skipBytes(size_t Count, DiagnosticEngine *DiagEngine, + const ELFSection &S) { if (D.size() < Count) { DiagEngine->raise(Diag::eh_frame_read_error) - << "CIE is too small" - << MSection->getInputFile()->getInput()->decoratedPath(); + << "CIE is too small" << S.getInputFile()->getInput()->decoratedPath(); return; } D = D.slice(Count); } // Read a null-terminated string. -llvm::StringRef EhFramePiece::readString(DiagnosticEngine *DiagEngine) { +llvm::StringRef EhFramePiece::readString(DiagnosticEngine *DiagEngine, + const ELFSection &S) { const uint8_t *End = std::find(D.begin(), D.end(), '\0'); if (End == D.end()) { DiagEngine->raise(Diag::eh_frame_read_error) << "corrupted CIE (failed to read string)" - << MSection->getInputFile()->getInput()->decoratedPath(); + << S.getInputFile()->getInput()->decoratedPath(); return llvm::StringRef(""); } - llvm::StringRef S = llvm::toStringRef(D.slice(0, End - D.begin())); - D = D.slice(S.size() + 1); - return S; + llvm::StringRef Str = llvm::toStringRef(D.slice(0, End - D.begin())); + D = D.slice(Str.size() + 1); + return Str; } // Skip an integer encoded in the LEB128 format. // Actual number is not of interest because only the runtime needs it. // But we need to be at least able to skip it so that we can read // the field that follows a LEB128 number. -void EhFramePiece::skipLeb128(DiagnosticEngine *DiagEngine) { +void EhFramePiece::skipLeb128(DiagnosticEngine *DiagEngine, + const ELFSection &S) { while (!D.empty()) { uint8_t Val = D.front(); D = D.slice(1); @@ -165,7 +263,7 @@ void EhFramePiece::skipLeb128(DiagnosticEngine *DiagEngine) { } DiagEngine->raise(Diag::eh_frame_read_error) << "corrupted CIE (failed to read LEB128)" - << MSection->getInputFile()->getInput()->decoratedPath(); + << S.getInputFile()->getInput()->decoratedPath(); } size_t EhFramePiece::getAugPSize(unsigned Enc, bool Is64Bit, @@ -187,71 +285,73 @@ size_t EhFramePiece::getAugPSize(unsigned Enc, bool Is64Bit, return 0; } -void EhFramePiece::skipAugP(bool Is64Bit, DiagnosticEngine *DiagEngine) { - uint8_t Enc = readByte(DiagEngine); +void EhFramePiece::skipAugP(bool Is64Bit, DiagnosticEngine *DiagEngine, + const ELFSection &S) { + uint8_t Enc = readByte(DiagEngine, S); if ((Enc & 0xf0) == llvm::dwarf::DW_EH_PE_aligned) { DiagEngine->raise(Diag::eh_frame_read_error) << "llvm::dwarf::DW_EH_PE_aligned encoding is not supported" - << MSection->getInputFile()->getInput()->decoratedPath(); + << S.getInputFile()->getInput()->decoratedPath(); return; } size_t Size = getAugPSize(Enc, Is64Bit, DiagEngine); if (Size == 0) { DiagEngine->raise(Diag::eh_frame_read_error) << "unknown FDE encoding" - << MSection->getInputFile()->getInput()->decoratedPath(); + << S.getInputFile()->getInput()->decoratedPath(); return; } if (Size >= D.size()) { DiagEngine->raise(Diag::eh_frame_read_error) << "corrupted CIE (failed to skipAugP)" - << MSection->getInputFile()->getInput()->decoratedPath(); + << S.getInputFile()->getInput()->decoratedPath(); return; } D = D.slice(Size); } -uint8_t EhFramePiece::getFdeEncoding(bool Is64Bit, - DiagnosticEngine *DiagEngine) { - D = getData(); - skipBytes(8, DiagEngine); - int Version = readByte(DiagEngine); +uint8_t EhFramePiece::getFdeEncoding(llvm::StringRef Region, bool Is64Bit, + DiagnosticEngine *DiagEngine, + const ELFSection &S) { + D = getData(Region); + skipBytes(8, DiagEngine, S); + int Version = readByte(DiagEngine, S); if (Version != 1 && Version != 3) { DiagEngine->raise(Diag::eh_frame_read_error) << "FDE version 1 or 3 expected, but got " + llvm::Twine(Version).str() - << MSection->getInputFile()->getInput()->decoratedPath(); + << S.getInputFile()->getInput()->decoratedPath(); return -1; } - llvm::StringRef Aug = readString(DiagEngine); + llvm::StringRef Aug = readString(DiagEngine, S); // Skip code and data alignment factors. - skipLeb128(DiagEngine); - skipLeb128(DiagEngine); + skipLeb128(DiagEngine, S); + skipLeb128(DiagEngine, S); // Skip the return address register. In CIE version 1 this is a single // byte. In CIE version 3 this is an unsigned LEB128. if (Version == 1) - readByte(DiagEngine); + readByte(DiagEngine, S); else - skipLeb128(DiagEngine); + skipLeb128(DiagEngine, S); // We only care about an 'R' value, but other records may precede an 'R' // record. Unfortunately records are not in TLV (type-length-value) format, // so we need to teach the linker how to skip records for each type. for (char C : Aug) { if (C == 'R') - return readByte(DiagEngine); + return readByte(DiagEngine, S); if (C == 'z') - skipLeb128(DiagEngine); + skipLeb128(DiagEngine, S); else if (C == 'P') - skipAugP(Is64Bit, DiagEngine); + skipAugP(Is64Bit, DiagEngine, S); else if (C == 'L') - readByte(DiagEngine); + readByte(DiagEngine, S); else if (C != 'B' && C != 'S') { DiagEngine->raise(Diag::eh_frame_read_error) << "unknown .eh_frame augmentation string: " + std::string(Aug) - << MSection->getInputFile()->getInput()->decoratedPath(); + << S.getInputFile()->getInput()->decoratedPath(); } } return llvm::dwarf::DW_EH_PE_absptr; diff --git a/lib/Fragment/EhFrameHdrFragment.cpp b/lib/Fragment/EhFrameHdrFragment.cpp index ff892768c..df65a5a54 100644 --- a/lib/Fragment/EhFrameHdrFragment.cpp +++ b/lib/Fragment/EhFrameHdrFragment.cpp @@ -10,12 +10,12 @@ // //===----------------------------------------------------------------------===// - #include "eld/Fragment/EhFrameHdrFragment.h" #include "eld/Core/Module.h" #include "eld/Diagnostics/DiagnosticEngine.h" #include "eld/Fragment/EhFrameFragment.h" #include "eld/Readers/EhFrameHdrSection.h" +#include "eld/Readers/EhFrameSection.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Support/Endian.h" @@ -41,7 +41,58 @@ size_t EhFrameHdrFragment::size() const { return S->sizeOfHeader() + S->getNumFDE() * 8; } -void EhFrameHdrFragment::dump(llvm::raw_ostream &OS) {} +void EhFrameHdrFragment::dump(llvm::raw_ostream &OS) { + auto *Hdr = llvm::dyn_cast(getOwningSection()); + if (!Hdr) + return; + + OS << "#\tEhFrameHdrLayout\t" << Hdr->name() << "\n"; + + OS << "#\tHdr"; + if (hasOffset()) { + OS << "\tout=0x"; + OS.write_hex(getOffset()); + } else { + OS << "\tout="; + } + OS << "\tsize=0x"; + OS.write_hex(size()); + OS << "\theader=0x"; + OS.write_hex(Hdr->sizeOfHeader()); + OS << "\ttable=" << (CreateTable ? "on" : "off"); + OS << "\tis64=" << (Is64Bit ? "true" : "false"); + OS << "\tCIE=" << Hdr->getNumCIE(); + OS << "\tFDE=" << Hdr->getNumFDE(); + OS << "\n"; + + // Mirror the encodings used by emit(). + OS << "#\tEnc" + << "\tversion=1" + << "\teh_frame_ptr=pcrel|sdata4" + << "\tfde_count=" << (CreateTable ? "udata4" : "omit") + << "\tfde_table=" << (CreateTable ? "datarel|sdata4" : "omit") << "\n"; + + if (Hdr->getEhFrames().empty()) + return; + + const EhFrameFragment *First = Hdr->getEhFrames().front(); + if (First && First->getOwningSection()) { + OS << "#\tFirstEhFrame\t" << First->getOwningSection()->name() << "\n"; + } + + size_t Index = 0; + for (const EhFrameFragment *EhF : Hdr->getEhFrames()) { + if (!EhF || !EhF->getOwningSection()) + continue; + OS << "#\tEhFrame[" << Index++ << "]\t" << EhF->getOwningSection()->name(); + OS << "\tCIE=" << EhF->getCIEs().size(); + size_t TotalFDE = 0; + for (const EhFrameCIE *C : EhF->getCIEs()) + TotalFDE += C ? C->getNumFDE() : 0; + OS << "\tFDE=" << TotalFDE; + OS << "\n"; + } +} EhFrameHdrFragment::~EhFrameHdrFragment() {} @@ -68,9 +119,12 @@ eld::Expected EhFrameHdrFragment::emit(MemoryRegion &Mr, Module &M) { return {}; llvm::support::endian::write32le( - Buf + 4, - S->getCIEs().front()->getOwningSection()->getOutputELFSection()->addr() - - getOwningSection()->getOutputELFSection()->addr() - 4); + Buf + 4, S->getEhFrames() + .front() + ->getOwningSection() + ->getOutputELFSection() + ->addr() - + getOwningSection()->getOutputELFSection()->addr() - 4); llvm::support::endian::write32le(Buf + 8, Fdes.size()); Buf += 12; @@ -86,25 +140,28 @@ std::vector EhFrameHdrFragment::getFdeData(uint8_t *Data, DiagnosticEngine *DiagEngine) { std::vector Ret; uint64_t VA = getOwningSection()->getOutputELFSection()->addr(); - for (CIEFragment *CIE : - llvm::dyn_cast(getOwningSection())->getCIEs()) { - uint8_t Enc = CIE->getFdeEncoding(Is64Bit, DiagEngine); - for (FDEFragment *FDE : CIE->getFDEs()) { - uint64_t PC = getFdePc(Data, FDE, Enc, DiagEngine); - uint64_t FdeVA = FDE->getOwningSection()->getOutputELFSection()->addr() + - FDE->getOffset(DiagEngine); - // With noinhbit-exec there may be an issue that the VA might not fit, - // just because the symbol is not resolved. - if (!llvm::isInt<32>(PC - VA)) { - DiagEngine->raise(Diag::eh_frame_read_warn) - << "PC Offset is too large in " + - std::string(FDE->getOwningSection()->name()) - << FDE->getOwningSection() - ->getInputFile() - ->getInput() - ->decoratedPath(); + auto *Hdr = llvm::dyn_cast(getOwningSection()); + for (const EhFrameFragment *EhF : Hdr->getEhFrames()) { + for (EhFrameCIE *CIE : EhF->getCIEs()) { + uint8_t Enc = CIE->getFdeEncoding(*EhF, Is64Bit, DiagEngine); + for (FDEPiece *FDE : CIE->getFDEs()) { + uint64_t PC = getFdePc(Data, *EhF, FDE, Enc, DiagEngine); + uint64_t FdeVA = + EhF->getOwningSection()->getOutputELFSection()->addr() + + FDE->getFDE().getOutputOffset(); + // With noinhbit-exec there may be an issue that the VA might not fit, + // just because the symbol is not resolved. + if (!llvm::isInt<32>(PC - VA)) { + DiagEngine->raise(Diag::eh_frame_read_warn) + << "PC Offset is too large in " + + std::string(EhF->getOwningSection()->name()) + << EhF->getOwningSection() + ->getInputFile() + ->getInput() + ->decoratedPath(); + } + Ret.push_back({uint32_t(PC - VA), uint32_t(FdeVA - VA)}); } - Ret.push_back({uint32_t(PC - VA), uint32_t(FdeVA - VA)}); } } @@ -152,19 +209,21 @@ uint64_t EhFrameHdrFragment::readFdeAddr(uint8_t *Buf, int Size, // Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to. // We need it to create .eh_frame_hdr section. -uint64_t EhFrameHdrFragment::getFdePc(uint8_t *Buf, FDEFragment *F, uint8_t Enc, +uint64_t EhFrameHdrFragment::getFdePc(uint8_t *Buf, const EhFrameFragment &EhF, + FDEPiece *F, uint8_t Enc, DiagnosticEngine *DiagEngine) { // The starting address to which this FDE applies is // stored at FDE + 8 byte. - ELFSection *S = F->getOwningSection()->getOutputELFSection(); - size_t Off = S->offset() + F->getOffset(DiagEngine) + 8; + ELFSection *S = EhF.getOwningSection()->getOutputELFSection(); + size_t FdeOff = F->getFDE().getOutputOffset(); + size_t Off = S->offset() + FdeOff + 8; uint64_t Addr = readFdeAddr(Buf + Off, Enc & 0xf, DiagEngine); if ((Enc & 0x70) == llvm::dwarf::DW_EH_PE_absptr) return Addr; if ((Enc & 0x70) == llvm::dwarf::DW_EH_PE_pcrel) { if (Is64Bit) - return (int64_t)Addr + S->addr() + F->getOffset(DiagEngine) + 8; - return (int32_t)Addr + S->addr() + F->getOffset(DiagEngine) + 8; + return (int64_t)Addr + S->addr() + FdeOff + 8; + return (int32_t)Addr + S->addr() + FdeOff + 8; } return 0; } diff --git a/lib/Fragment/FragmentRef.cpp b/lib/Fragment/FragmentRef.cpp index 0174a3ada..1d2a3f7ce 100644 --- a/lib/Fragment/FragmentRef.cpp +++ b/lib/Fragment/FragmentRef.cpp @@ -123,7 +123,7 @@ FragmentRef::Offset FragmentRef::getOutputOffset(Module &M) const { // Find the proper piece EhFrameSection *S = llvm::dyn_cast(ThisFragment->getOwningSection()); - std::vector &Pieces = S->getPieces(); + std::vector &Pieces = S->getEhFrameFragment()->getPieces(); size_t I = 0; while (I != Pieces.size() && Pieces[I].getOffset() + Pieces[I].getSize() <= ThisOffset) diff --git a/lib/Object/ObjectLinker.cpp b/lib/Object/ObjectLinker.cpp index aee256f00..ff46589e3 100644 --- a/lib/Object/ObjectLinker.cpp +++ b/lib/Object/ObjectLinker.cpp @@ -836,8 +836,8 @@ bool ObjectLinker::mergeInputSections(ObjectBuilder &Builder, *ThisModule); if (getTargetBackend().getEhFrameHdr() && Sect->getKind() == LDFileFormat::EhFrame) { - getTargetBackend().getEhFrameHdr()->addCIE( - llvm::dyn_cast(Sect)->getCIEs()); + getTargetBackend().getEhFrameHdr()->addEhFrame( + *llvm::dyn_cast(Sect)->getEhFrameFragment()); // Since we found an EhFrame section, lets go ahead and start creating // the fragments necessary to create the .eh_frame_hdr section and // the filler eh_frame section. diff --git a/lib/Readers/EhFrameHdrSection.cpp b/lib/Readers/EhFrameHdrSection.cpp index 31944de3d..538c95ce5 100644 --- a/lib/Readers/EhFrameHdrSection.cpp +++ b/lib/Readers/EhFrameHdrSection.cpp @@ -23,9 +23,9 @@ EhFrameHdrSection::EhFrameHdrSection(std::string Name, uint32_t pType, pFlag, entSize, /*AddrAlign=*/0, pType, /*Info=*/0, /*Link=*/nullptr, pSize, /*PAddr=*/0) {} -void EhFrameHdrSection::addCIE(std::vector &C) { - for (auto &CIE : C) { - m_CIEs.push_back(CIE); +void EhFrameHdrSection::addEhFrame(EhFrameFragment &F) { + EhFrames.push_back(&F); + for (auto *CIE : F.getCIEs()) { ++NumCIE; NumFDE += CIE->getNumFDE(); } diff --git a/lib/Readers/EhFrameSection.cpp b/lib/Readers/EhFrameSection.cpp index b0816dfcd..7536ae9c4 100644 --- a/lib/Readers/EhFrameSection.cpp +++ b/lib/Readers/EhFrameSection.cpp @@ -24,7 +24,7 @@ using namespace eld; namespace { // CIE records are uniquified by their contents and personality functions -llvm::DenseMap, ResolveInfo *>, CIEFragment *> +llvm::DenseMap, ResolveInfo *>, EhFrameCIE *> CieMap; } // namespace @@ -37,7 +37,8 @@ EhFrameSection::EhFrameSection(std::string Name, DiagnosticEngine *E, m_DiagEngine(E) {} size_t EhFrameSection::readEhRecordSize(size_t Off) { - llvm::ArrayRef D = Data.slice(Off); + llvm::ArrayRef SectionData = getData(); + llvm::ArrayRef D = SectionData.slice(Off); if (D.size() < 4) { m_DiagEngine->raise(Diag::eh_frame_read_error) @@ -69,23 +70,25 @@ bool EhFrameSection::splitEhFrameSection() { return true; if (m_EhFrame == nullptr) { - m_EhFrame = llvm::dyn_cast(Fragments.front()); - Data = llvm::ArrayRef((const uint8_t *)m_EhFrame->getRegion().data(), - m_EhFrame->size()); + if (Fragments.empty()) + return false; + assert(Fragments.front()->getKind() == Fragment::Type::Region && + "EhFrameSection must start with a Region-like fragment"); + m_EhFrame = static_cast(Fragments.front()); Fragments.clear(); } if (!m_EhFrame) return false; - llvm::StringRef Data = m_EhFrame->getRegion(); - for (size_t Off = 0, End = Data.size(); Off != End;) { + llvm::StringRef Region = m_EhFrame->getRegion(); + for (size_t Off = 0, End = Region.size(); Off != End;) { size_t Size = readEhRecordSize(Off); if (Size == (size_t)-1) return false; Relocation *Reloc = getReloc(Off, Size); - m_EhFramePieces.emplace_back(Off, Size, Reloc, this); + m_EhFrame->addPiece(Off, Size, Reloc); if (Reloc && getDiagPrinter()->isVerbose()) m_DiagEngine->raise(Diag::verbose_ehframe) << Reloc->symInfo()->name() << Off << Size; @@ -108,19 +111,23 @@ Relocation *EhFrameSection::getReloc(size_t Off, size_t Size) { } bool EhFrameSection::createCIEAndFDEFragments() { - for (auto &Piece : m_EhFramePieces) { + llvm::DenseMap OffsetToCie; + if (!m_EhFrame) + return true; + llvm::StringRef Region = m_EhFrame->getRegion(); + for (auto &Piece : m_EhFrame->getPieces()) { if (Piece.getSize() == 4) return true; size_t Offset = Piece.getOffset(); - uint32_t ID = llvm::support::endian::read32le(Piece.getData().data() + 4); + uint32_t ID = + llvm::support::endian::read32le(Piece.getData(Region).data() + 4); if (ID == 0) { - m_OffsetToCie[Offset] = addCie(Piece); - ++NumCie; + OffsetToCie[Offset] = addCie(Piece); continue; } uint32_t CieOffset = Offset + 4 - ID; - CIEFragment *Cie = m_OffsetToCie[CieOffset]; + EhFrameCIE *Cie = OffsetToCie[CieOffset]; if (!Cie) { m_DiagEngine->raise(Diag::eh_frame_read_error) << "Invalid CIE Reference" @@ -139,23 +146,22 @@ bool EhFrameSection::createCIEAndFDEFragments() { if (getDiagPrinter()->isVerbose()) m_DiagEngine->raise(Diag::verbose_ehframe_read_fde) << "Reading FDE of size " + std::to_string(Piece.getSize()); - Cie->appendFragment(make(Piece, this)); - ++NumFDE; + Cie->appendFDE(make(Piece)); } return true; } -CIEFragment *EhFrameSection::addCie(EhFramePiece &P) { +EhFrameCIE *EhFrameSection::addCie(EhFramePiece &P) { ResolveInfo *R = nullptr; if (P.getRelocation()) R = P.getRelocation()->symInfo(); - CIEFragment *E = CieMap[{P.getData(), R}]; + EhFrameCIE *E = CieMap[{P.getData(m_EhFrame->getRegion()), R}]; if (!E) { if (getDiagPrinter()->isVerbose()) m_DiagEngine->raise(Diag::verbose_ehframe_read_cie) << "Reading CIE of size " + std::to_string(P.getSize()); - E = make(P, this); - m_CIEFragments.push_back(E); + E = make(P); + m_EhFrame->getCIEs().push_back(E); } return E; } @@ -166,18 +172,16 @@ void EhFrameSection::finishAddingFragments(Module &ThisModule) { setKind(LDFileFormat::Regular); return; } - if (!m_CIEFragments.size()) { + if (m_EhFrame->getCIEs().empty()) { setKind(LDFileFormat::Regular); Fragments.push_back(m_EhFrame); if (ThisModule.getLayoutInfo()) ThisModule.getLayoutInfo()->recordFragment(getInputFile(), this, m_EhFrame); return; } - for (auto &F : m_CIEFragments) { - if (ThisModule.getLayoutInfo()) - ThisModule.getLayoutInfo()->recordFragment(getInputFile(), this, F); - Fragments.push_back(F); - } + if (ThisModule.getLayoutInfo()) + ThisModule.getLayoutInfo()->recordFragment(getInputFile(), this, m_EhFrame); + Fragments.push_back(m_EhFrame); } bool EhFrameSection::isFdeLive(EhFramePiece &P) { @@ -201,6 +205,13 @@ bool EhFrameSection::isFdeLive(EhFramePiece &P) { return true; } +llvm::ArrayRef EhFrameSection::getData() const { + assert(m_EhFrame && "EhFrame fragment must be initialized"); + llvm::StringRef Region = m_EhFrame->getRegion(); + return llvm::ArrayRef( + reinterpret_cast(Region.data()), Region.size()); +} + DiagnosticPrinter *EhFrameSection::getDiagPrinter() { return m_DiagEngine->getPrinter(); } diff --git a/lib/Target/GNULDBackend.cpp b/lib/Target/GNULDBackend.cpp index 3f6f62be0..8fa6d6753 100644 --- a/lib/Target/GNULDBackend.cpp +++ b/lib/Target/GNULDBackend.cpp @@ -21,15 +21,17 @@ #include "eld/Diagnostics/DiagnosticEngine.h" #include "eld/Diagnostics/DiagnosticInfos.h" #include "eld/Fragment/BuildIDFragment.h" +#include "eld/Fragment/EhFrameFragment.h" #include "eld/Fragment/FillFragment.h" #include "eld/Fragment/GNUHashFragment.h" #ifdef ELD_ENABLE_SYMBOL_VERSIONING #include "eld/Fragment/GNUVerDefFragment.h" #include "eld/Fragment/GNUVerSymFragment.h" #endif +#include "eld/Fragment/RegionFragment.h" #include "eld/Fragment/RegionFragmentEx.h" -#include "eld/Fragment/StringFragment.h" #include "eld/Fragment/SFrameFragment.h" +#include "eld/Fragment/StringFragment.h" #include "eld/Fragment/SysVHashFragment.h" #include "eld/Fragment/TimingFragment.h" #include "eld/Input/ELFDynObjectFile.h" @@ -885,6 +887,7 @@ void GNULDBackend::createEhFrameFillerAndHdrFragment() { eld::RegisterTimer T("Create EhFrame Hdr Output Section", "Perform Layout", m_Module.getConfig().options().printTimingStats()); + LayoutInfo *layoutInfo = m_Module.getLayoutInfo(); // The LSB standard does not allow a .eh_frame section with zero // Call Frame Information records. glibc unwind-dw2-fde.c // classify_object_over_fdes expects there is a CIE record length 0 as a @@ -904,6 +907,9 @@ void GNULDBackend::createEhFrameFillerAndHdrFragment() { m_pEhFrameHdrFragment = make( m_pEhFrameHdrSection, m_EhFrameHdrContainsTable, config().targets().is64Bits()); + if (layoutInfo) + layoutInfo->recordFragment(m_pEhFrameHdrSection->getInputFile(), + m_pEhFrameHdrSection, m_pEhFrameHdrFragment); m_pEhFrameHdrSection->addFragmentAndUpdateSize(m_pEhFrameHdrFragment); } } @@ -1050,7 +1056,10 @@ bool GNULDBackend::readSection(InputFile &pInput, ELFSection *S) { F = make(getModule(), 0x0, S->size(), S, S->getAddrAlign()); else { llvm::StringRef R = pInput.getSlice(S->offset(), S->size()); - F = make(R, S, Fragment::Type::Region, S->getAddrAlign()); + if (S->getKind() == LDFileFormat::EhFrame) + F = make(R, S, S->getAddrAlign()); + else + F = make(R, S, Fragment::Type::Region, S->getAddrAlign()); } S->addFragment(F); if (layoutInfo) diff --git a/test/Common/standalone/Map/EhFrameDump/EhFrameDump.test b/test/Common/standalone/Map/EhFrameDump/EhFrameDump.test new file mode 100644 index 000000000..d154b232d --- /dev/null +++ b/test/Common/standalone/Map/EhFrameDump/EhFrameDump.test @@ -0,0 +1,14 @@ +#UNSUPPORTED: arm +#---EhFrameDump.test--------------------------- Executable -----------------# +# This test verifies that .eh_frame and .eh_frame_hdr fragments dump into the +# text map output. +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/eh-frame-map.s -o %t.o +RUN: %link %linkopts --eh-frame-hdr %t.o -o %t.out -MapStyle txt -Map %t.map +RUN: %filecheck %s < %t.map + +#CHECK: # EhFrameLayout .eh_frame +#CHECK: # CIE out=0x +#CHECK: # FDE out=0x +#CHECK: # EhFrameHdrLayout .eh_frame_hdr +#CHECK: # Hdr out=0x diff --git a/test/Common/standalone/Map/EhFrameDump/EhFrameDumpGcFDE.test b/test/Common/standalone/Map/EhFrameDump/EhFrameDumpGcFDE.test new file mode 100644 index 000000000..2e397ca0b --- /dev/null +++ b/test/Common/standalone/Map/EhFrameDump/EhFrameDumpGcFDE.test @@ -0,0 +1,12 @@ +#UNSUPPORTED: arm, aarch64, riscv32, riscv64 +#---EhFrameDumpGcFDE.test---------------------- Executable -----------------# +# This test checks that GC'd functions do not contribute FDEs to the image. +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/eh-frame-gc.s -o %t.o +RUN: %link %linkopts --gc-sections --eh-frame-hdr %t.o -o %t.out -MapStyle txt -Map %t.map +RUN: %filecheck %s --input-file=%t.map + +#CHECK: # EhFrameLayout .eh_frame +#CHECK: sym={{.*}}foo +#CHECK-NOT: sym=bar +#CHECK: # EhFrameHdrLayout .eh_frame_hdr diff --git a/test/Common/standalone/Map/EhFrameDump/EhFrameDumpMergeCIE.test b/test/Common/standalone/Map/EhFrameDump/EhFrameDumpMergeCIE.test new file mode 100644 index 000000000..161181498 --- /dev/null +++ b/test/Common/standalone/Map/EhFrameDump/EhFrameDumpMergeCIE.test @@ -0,0 +1,14 @@ +#UNSUPPORTED: arm +#---EhFrameDumpMergeCIE.test------------------- Executable -----------------# +# This test verifies that identical CIEs from multiple inputs are merged. +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/eh-frame-merge-1.s -o %t1.o +RUN: %clang %clangopts -c %p/Inputs/eh-frame-merge-2.s -o %t2.o +RUN: %link %linkopts --eh-frame-hdr %t1.o %t2.o -o %t.out -MapStyle txt -Map %t.map +RUN: %filecheck %s --input-file=%t.map + +#CHECK: # EhFrameLayout .eh_frame +#CHECK-COUNT-1: # CIE out=0x{{[0-9A-Fa-f]+}} +#CHECK-COUNT-2: # FDE out=0x{{[0-9A-Fa-f]+}} +#CHECK: # EhFrameHdrLayout .eh_frame_hdr +#CHECK: # Hdr out=0x{{[0-9A-Fa-f]+}} diff --git a/test/Common/standalone/Map/EhFrameDump/EhFrameDumpMulti.test b/test/Common/standalone/Map/EhFrameDump/EhFrameDumpMulti.test new file mode 100644 index 000000000..b3cfd7465 --- /dev/null +++ b/test/Common/standalone/Map/EhFrameDump/EhFrameDumpMulti.test @@ -0,0 +1,14 @@ +#UNSUPPORTED: arm +#---EhFrameDumpMulti.test---------------------- Executable -----------------# +# This test verifies map dumps for multiple .eh_frame records. +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/eh-frame-map-multi.s -o %t.o +RUN: %link %linkopts --eh-frame-hdr %t.o -o %t.out -MapStyle txt -Map %t.map +RUN: %filecheck %s --input-file=%t.map + +#CHECK: # EhFrameLayout .eh_frame +#CHECK: # CIE out=0x +#CHECK-DAG: # FDE out=0x +#CHECK-DAG: # FDE out=0x +#CHECK: # EhFrameHdrLayout .eh_frame_hdr +#CHECK: # Hdr out=0x diff --git a/test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-gc.s b/test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-gc.s new file mode 100644 index 000000000..eb56ce07a --- /dev/null +++ b/test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-gc.s @@ -0,0 +1,27 @@ + .section .text.main,"ax",@progbits + .globl main + .type main, @function +main: + .cfi_startproc + call foo + nop + .cfi_endproc + .size main, .-main + + .section .text.foo,"ax",@progbits + .globl foo + .type foo, @function +foo: + .cfi_startproc + nop + .cfi_endproc + .size foo, .-foo + + .section .text.bar,"ax",@progbits + .globl bar + .type bar, @function +bar: + .cfi_startproc + nop + .cfi_endproc + .size bar, .-bar diff --git a/test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-map-multi.s b/test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-map-multi.s new file mode 100644 index 000000000..a65dc36c5 --- /dev/null +++ b/test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-map-multi.s @@ -0,0 +1,16 @@ + .text + .globl foo + .type foo, @function +foo: + .cfi_startproc + nop + .cfi_endproc + .size foo, .-foo + + .globl bar + .type bar, @function +bar: + .cfi_startproc + nop + .cfi_endproc + .size bar, .-bar diff --git a/test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-map.s b/test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-map.s new file mode 100644 index 000000000..3ba73cf09 --- /dev/null +++ b/test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-map.s @@ -0,0 +1,8 @@ + .text + .globl foo + .type foo, @function +foo: + .cfi_startproc + nop + .cfi_endproc + .size foo, .-foo diff --git a/test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-merge-1.s b/test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-merge-1.s new file mode 100644 index 000000000..3ba73cf09 --- /dev/null +++ b/test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-merge-1.s @@ -0,0 +1,8 @@ + .text + .globl foo + .type foo, @function +foo: + .cfi_startproc + nop + .cfi_endproc + .size foo, .-foo diff --git a/test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-merge-2.s b/test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-merge-2.s new file mode 100644 index 000000000..6fde39d4a --- /dev/null +++ b/test/Common/standalone/Map/EhFrameDump/Inputs/eh-frame-merge-2.s @@ -0,0 +1,8 @@ + .text + .globl bar + .type bar, @function +bar: + .cfi_startproc + nop + .cfi_endproc + .size bar, .-bar