diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h b/llvm/include/llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h @@ -0,0 +1,35 @@ +//===--------- DWARFRecordSectionSplitter.h - JITLink -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_JITLINK_DWARFRECORDSECTIONSPLITTER_H +#define LLVM_EXECUTIONENGINE_JITLINK_DWARFRECORDSECTIONSPLITTER_H + +#include "llvm/ExecutionEngine/JITLink/JITLink.h" + +namespace llvm { +namespace jitlink { + +/// A LinkGraph pass that splits blocks in a section that follows the DWARF +/// Record format into sub-blocks where each header gets its own block. +/// When splitting EHFrames, DWARFRecordSectionSplitter should not be run +/// without EHFrameEdgeFixer, which is responsible for adding FDE-to-CIE edges. +class DWARFRecordSectionSplitter { +public: + DWARFRecordSectionSplitter(StringRef SectionName); + Error operator()(LinkGraph &G); + +private: + Error processBlock(LinkGraph &G, Block &B, LinkGraph::SplitBlockCache &Cache); + + StringRef SectionName; +}; + +} // namespace jitlink +} // namespace llvm + +#endif // LLVM_EXECUTIONENGINE_JITLINK_DWARFRECORDSECTIONSPLITTER_H diff --git a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt --- a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt +++ b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt @@ -1,4 +1,5 @@ add_llvm_component_library(LLVMJITLink + DWARFRecordSectionSplitter.cpp EHFrameSupport.cpp JITLink.cpp JITLinkGeneric.cpp diff --git a/llvm/lib/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.cpp b/llvm/lib/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.cpp @@ -0,0 +1,117 @@ +//===-------- JITLink_DWARFRecordSectionSplitter.cpp - JITLink-------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" +#include "llvm/Support/BinaryStreamReader.h" + +#define DEBUG_TYPE "jitlink" + +namespace llvm { +namespace jitlink { + +DWARFRecordSectionSplitter::DWARFRecordSectionSplitter(StringRef SectionName) + : SectionName(SectionName) {} + +Error DWARFRecordSectionSplitter::operator()(LinkGraph &G) { + auto *Section = G.findSectionByName(SectionName); + + if (!Section) { + LLVM_DEBUG({ + dbgs() << "DWARFRecordSectionSplitter: No " << SectionName + << " section. Nothing to do\n"; + }); + return Error::success(); + } + + LLVM_DEBUG({ + dbgs() << "DWARFRecordSectionSplitter: Processing " << SectionName + << "...\n"; + }); + + DenseMap Caches; + + { + // Pre-build the split caches. + for (auto *B : Section->blocks()) + Caches[B] = LinkGraph::SplitBlockCache::value_type(); + for (auto *Sym : Section->symbols()) + Caches[&Sym->getBlock()]->push_back(Sym); + for (auto *B : Section->blocks()) + llvm::sort(*Caches[B], [](const Symbol *LHS, const Symbol *RHS) { + return LHS->getOffset() > RHS->getOffset(); + }); + } + + // Iterate over blocks (we do this by iterating over Caches entries rather + // than Section->blocks() as we will be inserting new blocks along the way, + // which would invalidate iterators in the latter sequence. + for (auto &KV : Caches) { + auto &B = *KV.first; + auto &BCache = KV.second; + if (auto Err = processBlock(G, B, BCache)) + return Err; + } + + return Error::success(); +} + +Error DWARFRecordSectionSplitter::processBlock( + LinkGraph &G, Block &B, LinkGraph::SplitBlockCache &Cache) { + LLVM_DEBUG(dbgs() << " Processing block at " << B.getAddress() << "\n"); + + // Section should not contain zero-fill blocks. + if (B.isZeroFill()) + return make_error("Unexpected zero-fill block in " + + SectionName + " section"); + + if (B.getSize() == 0) { + LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n"); + return Error::success(); + } + + BinaryStreamReader BlockReader( + StringRef(B.getContent().data(), B.getContent().size()), + G.getEndianness()); + + while (true) { + uint64_t RecordStartOffset = BlockReader.getOffset(); + + LLVM_DEBUG({ + dbgs() << " Processing CFI record at " + << formatv("{0:x16}", B.getAddress()) << "\n"; + }); + + uint32_t Length; + if (auto Err = BlockReader.readInteger(Length)) + return Err; + if (Length != 0xffffffff) { + if (auto Err = BlockReader.skip(Length)) + return Err; + } else { + uint64_t ExtendedLength; + if (auto Err = BlockReader.readInteger(ExtendedLength)) + return Err; + if (auto Err = BlockReader.skip(ExtendedLength)) + return Err; + } + + // If this was the last block then there's nothing to split + if (BlockReader.empty()) { + LLVM_DEBUG(dbgs() << " Extracted " << B << "\n"); + return Error::success(); + } + + uint64_t BlockSize = BlockReader.getOffset() - RecordStartOffset; + auto &NewBlock = G.splitBlock(B, BlockSize); + (void)NewBlock; + LLVM_DEBUG(dbgs() << " Extracted " << NewBlock << "\n"); + } +} + +} // namespace jitlink +} // namespace llvm diff --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp --- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp @@ -10,6 +10,7 @@ #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Config/config.h" +#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h" #include "llvm/Support/DynamicLibrary.h" @@ -18,105 +19,6 @@ namespace llvm { namespace jitlink { -DWARFRecordSectionSplitter::DWARFRecordSectionSplitter(StringRef SectionName) - : SectionName(SectionName) {} - -Error DWARFRecordSectionSplitter::operator()(LinkGraph &G) { - auto *Section = G.findSectionByName(SectionName); - - if (!Section) { - LLVM_DEBUG({ - dbgs() << "DWARFRecordSectionSplitter: No " << SectionName - << " section. Nothing to do\n"; - }); - return Error::success(); - } - - LLVM_DEBUG({ - dbgs() << "DWARFRecordSectionSplitter: Processing " << SectionName - << "...\n"; - }); - - DenseMap Caches; - - { - // Pre-build the split caches. - for (auto *B : Section->blocks()) - Caches[B] = LinkGraph::SplitBlockCache::value_type(); - for (auto *Sym : Section->symbols()) - Caches[&Sym->getBlock()]->push_back(Sym); - for (auto *B : Section->blocks()) - llvm::sort(*Caches[B], [](const Symbol *LHS, const Symbol *RHS) { - return LHS->getOffset() > RHS->getOffset(); - }); - } - - // Iterate over blocks (we do this by iterating over Caches entries rather - // than Section->blocks() as we will be inserting new blocks along the way, - // which would invalidate iterators in the latter sequence. - for (auto &KV : Caches) { - auto &B = *KV.first; - auto &BCache = KV.second; - if (auto Err = processBlock(G, B, BCache)) - return Err; - } - - return Error::success(); -} - -Error DWARFRecordSectionSplitter::processBlock( - LinkGraph &G, Block &B, LinkGraph::SplitBlockCache &Cache) { - LLVM_DEBUG(dbgs() << " Processing block at " << B.getAddress() << "\n"); - - // Section should not contain zero-fill blocks. - if (B.isZeroFill()) - return make_error("Unexpected zero-fill block in " + - SectionName + " section"); - - if (B.getSize() == 0) { - LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n"); - return Error::success(); - } - - BinaryStreamReader BlockReader( - StringRef(B.getContent().data(), B.getContent().size()), - G.getEndianness()); - - while (true) { - uint64_t RecordStartOffset = BlockReader.getOffset(); - - LLVM_DEBUG({ - dbgs() << " Processing CFI record at " - << formatv("{0:x16}", B.getAddress()) << "\n"; - }); - - uint32_t Length; - if (auto Err = BlockReader.readInteger(Length)) - return Err; - if (Length != 0xffffffff) { - if (auto Err = BlockReader.skip(Length)) - return Err; - } else { - uint64_t ExtendedLength; - if (auto Err = BlockReader.readInteger(ExtendedLength)) - return Err; - if (auto Err = BlockReader.skip(ExtendedLength)) - return Err; - } - - // If this was the last block then there's nothing to split - if (BlockReader.empty()) { - LLVM_DEBUG(dbgs() << " Extracted " << B << "\n"); - return Error::success(); - } - - uint64_t BlockSize = BlockReader.getOffset() - RecordStartOffset; - auto &NewBlock = G.splitBlock(B, BlockSize); - (void)NewBlock; - LLVM_DEBUG(dbgs() << " Extracted " << NewBlock << "\n"); - } -} - EHFrameEdgeFixer::EHFrameEdgeFixer(StringRef EHFrameSectionName, unsigned PointerSize, Edge::Kind Delta64, Edge::Kind Delta32, Edge::Kind NegDelta32) diff --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h --- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h +++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h @@ -21,21 +21,6 @@ namespace llvm { namespace jitlink { -/// A LinkGraph pass that splits blocks in a section that follows the DWARF -/// Record format into sub-blocks where each header gets its own block. -/// When splitting EHFrames, DWARFRecordSectionSplitter should not be run -/// without EHFrameEdgeFixer, which is responsible for adding FDE-to-CIE edges. -class DWARFRecordSectionSplitter { -public: - DWARFRecordSectionSplitter(StringRef SectionName); - Error operator()(LinkGraph &G); - -private: - Error processBlock(LinkGraph &G, Block &B, LinkGraph::SplitBlockCache &Cache); - - StringRef SectionName; -}; - /// A LinkGraph pass that adds missing FDE-to-CIE, FDE-to-PC and FDE-to-LSDA /// edges. class EHFrameEdgeFixer { diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp --- a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/JITLink/ELF_x86_64.h" +#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" #include "llvm/ExecutionEngine/JITLink/JITLink.h" #include "llvm/ExecutionEngine/JITLink/TableManager.h" #include "llvm/ExecutionEngine/JITLink/x86_64.h" diff --git a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp --- a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/JITLink/MachO_arm64.h" +#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" #include "MachOLinkGraphBuilder.h" #include "PerGraphGOTAndPLTStubsBuilder.h" diff --git a/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp --- a/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h" +#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" #include "llvm/ExecutionEngine/JITLink/x86_64.h" #include "MachOLinkGraphBuilder.h"