//===-------- 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, &Cache); (void)NewBlock; LLVM_DEBUG(dbgs() << " Extracted " << NewBlock << "\n"); } } } // namespace jitlink } // namespace llvm