xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.cpp (revision fcaf7f8644a9988098ac6be2165bce3ea4786e91)
1 //===-------- JITLink_DWARFRecordSectionSplitter.cpp - JITLink-------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"
10 #include "llvm/Support/BinaryStreamReader.h"
11 
12 #define DEBUG_TYPE "jitlink"
13 
14 namespace llvm {
15 namespace jitlink {
16 
DWARFRecordSectionSplitter(StringRef SectionName)17 DWARFRecordSectionSplitter::DWARFRecordSectionSplitter(StringRef SectionName)
18     : SectionName(SectionName) {}
19 
operator ()(LinkGraph & G)20 Error DWARFRecordSectionSplitter::operator()(LinkGraph &G) {
21   auto *Section = G.findSectionByName(SectionName);
22 
23   if (!Section) {
24     LLVM_DEBUG({
25       dbgs() << "DWARFRecordSectionSplitter: No " << SectionName
26              << " section. Nothing to do\n";
27     });
28     return Error::success();
29   }
30 
31   LLVM_DEBUG({
32     dbgs() << "DWARFRecordSectionSplitter: Processing " << SectionName
33            << "...\n";
34   });
35 
36   DenseMap<Block *, LinkGraph::SplitBlockCache> Caches;
37 
38   {
39     // Pre-build the split caches.
40     for (auto *B : Section->blocks())
41       Caches[B] = LinkGraph::SplitBlockCache::value_type();
42     for (auto *Sym : Section->symbols())
43       Caches[&Sym->getBlock()]->push_back(Sym);
44     for (auto *B : Section->blocks())
45       llvm::sort(*Caches[B], [](const Symbol *LHS, const Symbol *RHS) {
46         return LHS->getOffset() > RHS->getOffset();
47       });
48   }
49 
50   // Iterate over blocks (we do this by iterating over Caches entries rather
51   // than Section->blocks() as we will be inserting new blocks along the way,
52   // which would invalidate iterators in the latter sequence.
53   for (auto &KV : Caches) {
54     auto &B = *KV.first;
55     auto &BCache = KV.second;
56     if (auto Err = processBlock(G, B, BCache))
57       return Err;
58   }
59 
60   return Error::success();
61 }
62 
processBlock(LinkGraph & G,Block & B,LinkGraph::SplitBlockCache & Cache)63 Error DWARFRecordSectionSplitter::processBlock(
64     LinkGraph &G, Block &B, LinkGraph::SplitBlockCache &Cache) {
65   LLVM_DEBUG(dbgs() << "  Processing block at " << B.getAddress() << "\n");
66 
67   // Section should not contain zero-fill blocks.
68   if (B.isZeroFill())
69     return make_error<JITLinkError>("Unexpected zero-fill block in " +
70                                     SectionName + " section");
71 
72   if (B.getSize() == 0) {
73     LLVM_DEBUG(dbgs() << "    Block is empty. Skipping.\n");
74     return Error::success();
75   }
76 
77   BinaryStreamReader BlockReader(
78       StringRef(B.getContent().data(), B.getContent().size()),
79       G.getEndianness());
80 
81   while (true) {
82     uint64_t RecordStartOffset = BlockReader.getOffset();
83 
84     LLVM_DEBUG({
85       dbgs() << "    Processing CFI record at "
86              << formatv("{0:x16}", B.getAddress()) << "\n";
87     });
88 
89     uint32_t Length;
90     if (auto Err = BlockReader.readInteger(Length))
91       return Err;
92     if (Length != 0xffffffff) {
93       if (auto Err = BlockReader.skip(Length))
94         return Err;
95     } else {
96       uint64_t ExtendedLength;
97       if (auto Err = BlockReader.readInteger(ExtendedLength))
98         return Err;
99       if (auto Err = BlockReader.skip(ExtendedLength))
100         return Err;
101     }
102 
103     // If this was the last block then there's nothing to split
104     if (BlockReader.empty()) {
105       LLVM_DEBUG(dbgs() << "      Extracted " << B << "\n");
106       return Error::success();
107     }
108 
109     uint64_t BlockSize = BlockReader.getOffset() - RecordStartOffset;
110     auto &NewBlock = G.splitBlock(B, BlockSize, &Cache);
111     (void)NewBlock;
112     LLVM_DEBUG(dbgs() << "      Extracted " << NewBlock << "\n");
113   }
114 }
115 
116 } // namespace jitlink
117 } // namespace llvm
118