1 //===------------- JITLink.cpp - Core Run-time JIT linker APIs ------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
11 
12 #include "llvm/BinaryFormat/Magic.h"
13 #include "llvm/ExecutionEngine/JITLink/MachO.h"
14 #include "llvm/Support/Format.h"
15 #include "llvm/Support/ManagedStatic.h"
16 #include "llvm/Support/MemoryBuffer.h"
17 #include "llvm/Support/Process.h"
18 #include "llvm/Support/raw_ostream.h"
19 
20 using namespace llvm;
21 using namespace llvm::object;
22 
23 #define DEBUG_TYPE "jitlink"
24 
25 namespace {
26 
27 enum JITLinkErrorCode { GenericJITLinkError = 1 };
28 
29 // FIXME: This class is only here to support the transition to llvm::Error. It
30 // will be removed once this transition is complete. Clients should prefer to
31 // deal with the Error value directly, rather than converting to error_code.
32 class JITLinkerErrorCategory : public std::error_category {
33 public:
34   const char *name() const noexcept override { return "runtimedyld"; }
35 
36   std::string message(int Condition) const override {
37     switch (static_cast<JITLinkErrorCode>(Condition)) {
38     case GenericJITLinkError:
39       return "Generic JITLink error";
40     }
41     llvm_unreachable("Unrecognized JITLinkErrorCode");
42   }
43 };
44 
45 static ManagedStatic<JITLinkerErrorCategory> JITLinkerErrorCategory;
46 
47 } // namespace
48 
49 namespace llvm {
50 namespace jitlink {
51 
52 char JITLinkError::ID = 0;
53 
54 void JITLinkError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; }
55 
56 std::error_code JITLinkError::convertToErrorCode() const {
57   return std::error_code(GenericJITLinkError, *JITLinkerErrorCategory);
58 }
59 
60 JITLinkMemoryManager::~JITLinkMemoryManager() = default;
61 
62 JITLinkMemoryManager::Allocation::~Allocation() = default;
63 
64 const StringRef getGenericEdgeKindName(Edge::Kind K) {
65   switch (K) {
66   case Edge::Invalid:
67     return "INVALID RELOCATION";
68   case Edge::KeepAlive:
69     return "Keep-Alive";
70   case Edge::LayoutNext:
71     return "Layout-Next";
72   default:
73     llvm_unreachable("Unrecognized relocation kind");
74   }
75 }
76 
77 raw_ostream &operator<<(raw_ostream &OS, const Atom &A) {
78   OS << "<";
79   if (A.getName().empty())
80     OS << "anon@" << format("0x%016" PRIx64, A.getAddress());
81   else
82     OS << A.getName();
83   OS << " [";
84   if (A.isDefined()) {
85     auto &DA = static_cast<const DefinedAtom &>(A);
86     OS << " section=" << DA.getSection().getName();
87     if (DA.isLive())
88       OS << " live";
89     if (DA.shouldDiscard())
90       OS << " should-discard";
91   } else
92     OS << " external";
93   OS << " ]>";
94   return OS;
95 }
96 
97 void printEdge(raw_ostream &OS, const Atom &FixupAtom, const Edge &E,
98                StringRef EdgeKindName) {
99   OS << "edge@" << formatv("{0:x16}", FixupAtom.getAddress() + E.getOffset())
100      << ": " << FixupAtom << " + " << E.getOffset() << " -- " << EdgeKindName
101      << " -> " << E.getTarget() << " + " << E.getAddend();
102 }
103 
104 Section::~Section() {
105   for (auto *DA : DefinedAtoms)
106     DA->~DefinedAtom();
107 }
108 
109 void AtomGraph::dump(raw_ostream &OS,
110                      std::function<StringRef(Edge::Kind)> EdgeKindToName) {
111   if (!EdgeKindToName)
112     EdgeKindToName = [](Edge::Kind K) { return StringRef(); };
113 
114   OS << "Defined atoms:\n";
115   for (auto *DA : defined_atoms()) {
116     OS << "  " << format("0x%016" PRIx64, DA->getAddress()) << ": " << *DA
117        << "\n";
118     for (auto &E : DA->edges()) {
119       OS << "    ";
120       StringRef EdgeName = (E.getKind() < Edge::FirstRelocation
121                                 ? getGenericEdgeKindName(E.getKind())
122                                 : EdgeKindToName(E.getKind()));
123 
124       if (!EdgeName.empty())
125         printEdge(OS, *DA, E, EdgeName);
126       else {
127         auto EdgeNumberString = std::to_string(E.getKind());
128         printEdge(OS, *DA, E, EdgeNumberString);
129       }
130       OS << "\n";
131     }
132   }
133 
134   OS << "Absolute atoms:\n";
135   for (auto *A : absolute_atoms())
136     OS << "  " << format("0x%016" PRIx64, A->getAddress()) << ": " << *A
137        << "\n";
138 
139   OS << "External atoms:\n";
140   for (auto *A : external_atoms())
141     OS << "  " << format("0x%016" PRIx64, A->getAddress()) << ": " << *A
142        << "\n";
143 }
144 
145 Expected<std::unique_ptr<JITLinkMemoryManager::Allocation>>
146 InProcessMemoryManager::allocate(const SegmentsRequestMap &Request) {
147 
148   using AllocationMap = DenseMap<unsigned, sys::MemoryBlock>;
149 
150   // Local class for allocation.
151   class IPMMAlloc : public Allocation {
152   public:
153     IPMMAlloc(AllocationMap SegBlocks) : SegBlocks(std::move(SegBlocks)) {}
154     MutableArrayRef<char> getWorkingMemory(ProtectionFlags Seg) override {
155       assert(SegBlocks.count(Seg) && "No allocation for segment");
156       return {static_cast<char *>(SegBlocks[Seg].base()),
157               SegBlocks[Seg].size()};
158     }
159     JITTargetAddress getTargetMemory(ProtectionFlags Seg) override {
160       assert(SegBlocks.count(Seg) && "No allocation for segment");
161       return reinterpret_cast<JITTargetAddress>(SegBlocks[Seg].base());
162     }
163     void finalizeAsync(FinalizeContinuation OnFinalize) override {
164       OnFinalize(applyProtections());
165     }
166     Error deallocate() override {
167       for (auto &KV : SegBlocks)
168         if (auto EC = sys::Memory::releaseMappedMemory(KV.second))
169           return errorCodeToError(EC);
170       return Error::success();
171     }
172 
173   private:
174     Error applyProtections() {
175       for (auto &KV : SegBlocks) {
176         auto &Prot = KV.first;
177         auto &Block = KV.second;
178         if (auto EC = sys::Memory::protectMappedMemory(Block, Prot))
179           return errorCodeToError(EC);
180         if (Prot & sys::Memory::MF_EXEC)
181           sys::Memory::InvalidateInstructionCache(Block.base(), Block.size());
182       }
183       return Error::success();
184     }
185 
186     AllocationMap SegBlocks;
187   };
188 
189   AllocationMap Blocks;
190   const sys::Memory::ProtectionFlags ReadWrite =
191       static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
192                                                 sys::Memory::MF_WRITE);
193 
194   for (auto &KV : Request) {
195     auto &Seg = KV.second;
196 
197     if (Seg.getContentAlignment() > sys::Process::getPageSize())
198       return make_error<StringError>("Cannot request higher than page "
199                                      "alignment",
200                                      inconvertibleErrorCode());
201 
202     if (sys::Process::getPageSize() % Seg.getContentAlignment() != 0)
203       return make_error<StringError>("Page size is not a multiple of "
204                                      "alignment",
205                                      inconvertibleErrorCode());
206 
207     uint64_t ZeroFillStart =
208         alignTo(Seg.getContentSize(), Seg.getZeroFillAlignment());
209     uint64_t SegmentSize = ZeroFillStart + Seg.getZeroFillSize();
210 
211     std::error_code EC;
212     auto SegMem =
213         sys::Memory::allocateMappedMemory(SegmentSize, nullptr, ReadWrite, EC);
214 
215     if (EC)
216       return errorCodeToError(EC);
217 
218     // Zero out the zero-fill memory.
219     memset(static_cast<char *>(SegMem.base()) + ZeroFillStart, 0,
220            Seg.getZeroFillSize());
221 
222     // Record the block for this segment.
223     Blocks[KV.first] = std::move(SegMem);
224   }
225   return std::unique_ptr<InProcessMemoryManager::Allocation>(
226       new IPMMAlloc(std::move(Blocks)));
227 }
228 
229 JITLinkContext::~JITLinkContext() {}
230 
231 bool JITLinkContext::shouldAddDefaultTargetPasses(const Triple &TT) const {
232   return true;
233 }
234 
235 AtomGraphPassFunction JITLinkContext::getMarkLivePass(const Triple &TT) const {
236   return AtomGraphPassFunction();
237 }
238 
239 Error JITLinkContext::modifyPassConfig(const Triple &TT,
240                                        PassConfiguration &Config) {
241   return Error::success();
242 }
243 
244 Error markAllAtomsLive(AtomGraph &G) {
245   for (auto *DA : G.defined_atoms())
246     DA->setLive(true);
247   return Error::success();
248 }
249 
250 void jitLink(std::unique_ptr<JITLinkContext> Ctx) {
251   auto Magic = identify_magic(Ctx->getObjectBuffer().getBuffer());
252   switch (Magic) {
253   case file_magic::macho_object:
254     return jitLink_MachO(std::move(Ctx));
255   default:
256     Ctx->notifyFailed(make_error<JITLinkError>("Unsupported file format"));
257   };
258 }
259 
260 } // end namespace jitlink
261 } // end namespace llvm
262