//===-------- 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<Block *, LinkGraph::SplitBlockCache> 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<JITLinkError>("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