181ad6265SDimitry Andric //===-------- JITLink_DWARFRecordSectionSplitter.cpp - JITLink-------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric
981ad6265SDimitry Andric #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"
1081ad6265SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
1181ad6265SDimitry Andric
1281ad6265SDimitry Andric #define DEBUG_TYPE "jitlink"
1381ad6265SDimitry Andric
1481ad6265SDimitry Andric namespace llvm {
1581ad6265SDimitry Andric namespace jitlink {
1681ad6265SDimitry Andric
DWARFRecordSectionSplitter(StringRef SectionName)1781ad6265SDimitry Andric DWARFRecordSectionSplitter::DWARFRecordSectionSplitter(StringRef SectionName)
1881ad6265SDimitry Andric : SectionName(SectionName) {}
1981ad6265SDimitry Andric
operator ()(LinkGraph & G)2081ad6265SDimitry Andric Error DWARFRecordSectionSplitter::operator()(LinkGraph &G) {
2181ad6265SDimitry Andric auto *Section = G.findSectionByName(SectionName);
2281ad6265SDimitry Andric
2381ad6265SDimitry Andric if (!Section) {
2481ad6265SDimitry Andric LLVM_DEBUG({
2581ad6265SDimitry Andric dbgs() << "DWARFRecordSectionSplitter: No " << SectionName
2681ad6265SDimitry Andric << " section. Nothing to do\n";
2781ad6265SDimitry Andric });
2881ad6265SDimitry Andric return Error::success();
2981ad6265SDimitry Andric }
3081ad6265SDimitry Andric
3181ad6265SDimitry Andric LLVM_DEBUG({
3281ad6265SDimitry Andric dbgs() << "DWARFRecordSectionSplitter: Processing " << SectionName
3381ad6265SDimitry Andric << "...\n";
3481ad6265SDimitry Andric });
3581ad6265SDimitry Andric
3681ad6265SDimitry Andric DenseMap<Block *, LinkGraph::SplitBlockCache> Caches;
3781ad6265SDimitry Andric
3881ad6265SDimitry Andric {
3981ad6265SDimitry Andric // Pre-build the split caches.
4081ad6265SDimitry Andric for (auto *B : Section->blocks())
4181ad6265SDimitry Andric Caches[B] = LinkGraph::SplitBlockCache::value_type();
4281ad6265SDimitry Andric for (auto *Sym : Section->symbols())
4381ad6265SDimitry Andric Caches[&Sym->getBlock()]->push_back(Sym);
4481ad6265SDimitry Andric for (auto *B : Section->blocks())
4581ad6265SDimitry Andric llvm::sort(*Caches[B], [](const Symbol *LHS, const Symbol *RHS) {
4681ad6265SDimitry Andric return LHS->getOffset() > RHS->getOffset();
4781ad6265SDimitry Andric });
4881ad6265SDimitry Andric }
4981ad6265SDimitry Andric
5081ad6265SDimitry Andric // Iterate over blocks (we do this by iterating over Caches entries rather
5181ad6265SDimitry Andric // than Section->blocks() as we will be inserting new blocks along the way,
5281ad6265SDimitry Andric // which would invalidate iterators in the latter sequence.
5381ad6265SDimitry Andric for (auto &KV : Caches) {
5481ad6265SDimitry Andric auto &B = *KV.first;
5581ad6265SDimitry Andric auto &BCache = KV.second;
5681ad6265SDimitry Andric if (auto Err = processBlock(G, B, BCache))
5781ad6265SDimitry Andric return Err;
5881ad6265SDimitry Andric }
5981ad6265SDimitry Andric
6081ad6265SDimitry Andric return Error::success();
6181ad6265SDimitry Andric }
6281ad6265SDimitry Andric
processBlock(LinkGraph & G,Block & B,LinkGraph::SplitBlockCache & Cache)6381ad6265SDimitry Andric Error DWARFRecordSectionSplitter::processBlock(
6481ad6265SDimitry Andric LinkGraph &G, Block &B, LinkGraph::SplitBlockCache &Cache) {
6581ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " Processing block at " << B.getAddress() << "\n");
6681ad6265SDimitry Andric
6781ad6265SDimitry Andric // Section should not contain zero-fill blocks.
6881ad6265SDimitry Andric if (B.isZeroFill())
6981ad6265SDimitry Andric return make_error<JITLinkError>("Unexpected zero-fill block in " +
7081ad6265SDimitry Andric SectionName + " section");
7181ad6265SDimitry Andric
7281ad6265SDimitry Andric if (B.getSize() == 0) {
7381ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n");
7481ad6265SDimitry Andric return Error::success();
7581ad6265SDimitry Andric }
7681ad6265SDimitry Andric
7781ad6265SDimitry Andric BinaryStreamReader BlockReader(
7881ad6265SDimitry Andric StringRef(B.getContent().data(), B.getContent().size()),
7981ad6265SDimitry Andric G.getEndianness());
8081ad6265SDimitry Andric
8181ad6265SDimitry Andric while (true) {
8281ad6265SDimitry Andric uint64_t RecordStartOffset = BlockReader.getOffset();
8381ad6265SDimitry Andric
8481ad6265SDimitry Andric LLVM_DEBUG({
8581ad6265SDimitry Andric dbgs() << " Processing CFI record at "
8681ad6265SDimitry Andric << formatv("{0:x16}", B.getAddress()) << "\n";
8781ad6265SDimitry Andric });
8881ad6265SDimitry Andric
8981ad6265SDimitry Andric uint32_t Length;
9081ad6265SDimitry Andric if (auto Err = BlockReader.readInteger(Length))
9181ad6265SDimitry Andric return Err;
9281ad6265SDimitry Andric if (Length != 0xffffffff) {
9381ad6265SDimitry Andric if (auto Err = BlockReader.skip(Length))
9481ad6265SDimitry Andric return Err;
9581ad6265SDimitry Andric } else {
9681ad6265SDimitry Andric uint64_t ExtendedLength;
9781ad6265SDimitry Andric if (auto Err = BlockReader.readInteger(ExtendedLength))
9881ad6265SDimitry Andric return Err;
9981ad6265SDimitry Andric if (auto Err = BlockReader.skip(ExtendedLength))
10081ad6265SDimitry Andric return Err;
10181ad6265SDimitry Andric }
10281ad6265SDimitry Andric
10381ad6265SDimitry Andric // If this was the last block then there's nothing to split
10481ad6265SDimitry Andric if (BlockReader.empty()) {
10581ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " Extracted " << B << "\n");
10681ad6265SDimitry Andric return Error::success();
10781ad6265SDimitry Andric }
10881ad6265SDimitry Andric
10981ad6265SDimitry Andric uint64_t BlockSize = BlockReader.getOffset() - RecordStartOffset;
110*fcaf7f86SDimitry Andric auto &NewBlock = G.splitBlock(B, BlockSize, &Cache);
11181ad6265SDimitry Andric (void)NewBlock;
11281ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " Extracted " << NewBlock << "\n");
11381ad6265SDimitry Andric }
11481ad6265SDimitry Andric }
11581ad6265SDimitry Andric
11681ad6265SDimitry Andric } // namespace jitlink
11781ad6265SDimitry Andric } // namespace llvm
118