xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/CompactUnwindSupport.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
1 //=------- CompactUnwindSupport.cpp - Compact Unwind format support -------===//
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 // Compact Unwind support.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "CompactUnwindSupport.h"
14 
15 #include "llvm/ADT/Sequence.h"
16 
17 #define DEBUG_TYPE "jitlink"
18 
19 namespace llvm {
20 namespace jitlink {
21 
22 Error splitCompactUnwindBlocks(LinkGraph &G, Section &CompactUnwindSection,
23                                size_t RecordSize) {
24 
25   std::vector<Block *> OriginalBlocks(CompactUnwindSection.blocks().begin(),
26                                       CompactUnwindSection.blocks().end());
27   LLVM_DEBUG({
28     dbgs() << "In " << G.getName() << " splitting compact unwind section "
29            << CompactUnwindSection.getName() << " containing "
30            << OriginalBlocks.size() << " initial blocks...\n";
31   });
32 
33   while (!OriginalBlocks.empty()) {
34     auto *B = OriginalBlocks.back();
35     OriginalBlocks.pop_back();
36 
37     if (B->getSize() == 0) {
38       LLVM_DEBUG({
39         dbgs() << "  Skipping empty block at "
40                << formatv("{0:x16}", B->getAddress()) << "\n";
41       });
42       continue;
43     }
44 
45     unsigned NumBlocks = B->getSize() / RecordSize;
46 
47     LLVM_DEBUG({
48       dbgs() << "  Splitting block at " << formatv("{0:x16}", B->getAddress())
49              << " into " << NumBlocks << " compact unwind record(s)\n";
50     });
51 
52     if (B->getSize() % RecordSize)
53       return make_error<JITLinkError>(
54           "Error splitting compact unwind record in " + G.getName() +
55           ": block at " + formatv("{0:x}", B->getAddress()) + " has size " +
56           formatv("{0:x}", B->getSize()) +
57           " (not a multiple of CU record size of " +
58           formatv("{0:x}", RecordSize) + ")");
59 
60     auto Blocks =
61         G.splitBlock(*B, map_range(seq(1U, NumBlocks), [=](Edge::OffsetT Idx) {
62           return Idx * RecordSize;
63         }));
64 
65     for (auto *CURec : Blocks) {
66       bool AddedKeepAlive = false;
67 
68       for (auto &E : CURec->edges()) {
69         if (E.getOffset() == 0) {
70           LLVM_DEBUG({
71             dbgs() << "    Updating compact unwind record at "
72                    << CURec->getAddress() << " to point to "
73                    << (E.getTarget().hasName() ? *E.getTarget().getName()
74                                                : StringRef())
75                    << " (at " << E.getTarget().getAddress() << ")\n";
76           });
77 
78           if (E.getTarget().isExternal())
79             return make_error<JITLinkError>(
80                 "Error adding keep-alive edge for compact unwind record at " +
81                 formatv("{0:x}", CURec->getAddress()) + ": target " +
82                 *E.getTarget().getName() + " is an external symbol");
83           auto &TgtBlock = E.getTarget().getBlock();
84           auto &CURecSym =
85               G.addAnonymousSymbol(*CURec, 0, RecordSize, false, false);
86           TgtBlock.addEdge(Edge::KeepAlive, 0, CURecSym, 0);
87           AddedKeepAlive = true;
88         }
89       }
90 
91       if (!AddedKeepAlive)
92         return make_error<JITLinkError>(
93             "Error adding keep-alive edge for compact unwind record at " +
94             formatv("{0:x}", CURec->getAddress()) +
95             ": no outgoing target edge at offset 0");
96     }
97   }
98 
99   return Error::success();
100 }
101 
102 } // end namespace jitlink
103 } // end namespace llvm
104