xref: /netbsd-src/external/apache2/llvm/dist/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 //===------ MachOPlatform.cpp - Utilities for executing MachO in Orc ------===//
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/Orc/MachOPlatform.h"
10 
11 #include "llvm/BinaryFormat/MachO.h"
12 #include "llvm/ExecutionEngine/Orc/DebugUtils.h"
13 #include "llvm/Support/BinaryByteStream.h"
14 #include "llvm/Support/Debug.h"
15 
16 #define DEBUG_TYPE "orc"
17 
18 namespace {
19 
20 struct objc_class;
21 struct objc_image_info;
22 struct objc_object;
23 struct objc_selector;
24 
25 using Class = objc_class *;
26 using id = objc_object *;
27 using SEL = objc_selector *;
28 
29 using ObjCMsgSendTy = id (*)(id, SEL, ...);
30 using ObjCReadClassPairTy = Class (*)(Class, const objc_image_info *);
31 using SelRegisterNameTy = SEL (*)(const char *);
32 
33 enum class ObjCRegistrationAPI { Uninitialized, Unavailable, Initialized };
34 
35 ObjCRegistrationAPI ObjCRegistrationAPIState =
36     ObjCRegistrationAPI::Uninitialized;
37 ObjCMsgSendTy objc_msgSend = nullptr;
38 ObjCReadClassPairTy objc_readClassPair = nullptr;
39 SelRegisterNameTy sel_registerName = nullptr;
40 
41 } // end anonymous namespace
42 
43 namespace llvm {
44 namespace orc {
45 
46 template <typename FnTy>
setUpObjCRegAPIFunc(FnTy & Target,sys::DynamicLibrary & LibObjC,const char * Name)47 static Error setUpObjCRegAPIFunc(FnTy &Target, sys::DynamicLibrary &LibObjC,
48                                  const char *Name) {
49   if (void *Addr = LibObjC.getAddressOfSymbol(Name))
50     Target = reinterpret_cast<FnTy>(Addr);
51   else
52     return make_error<StringError>(
53         (Twine("Could not find address for ") + Name).str(),
54         inconvertibleErrorCode());
55   return Error::success();
56 }
57 
enableObjCRegistration(const char * PathToLibObjC)58 Error enableObjCRegistration(const char *PathToLibObjC) {
59   // If we've already tried to initialize then just bail out.
60   if (ObjCRegistrationAPIState != ObjCRegistrationAPI::Uninitialized)
61     return Error::success();
62 
63   ObjCRegistrationAPIState = ObjCRegistrationAPI::Unavailable;
64 
65   std::string ErrMsg;
66   auto LibObjC =
67       sys::DynamicLibrary::getPermanentLibrary(PathToLibObjC, &ErrMsg);
68 
69   if (!LibObjC.isValid())
70     return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode());
71 
72   if (auto Err = setUpObjCRegAPIFunc(objc_msgSend, LibObjC, "objc_msgSend"))
73     return Err;
74   if (auto Err = setUpObjCRegAPIFunc(objc_readClassPair, LibObjC,
75                                      "objc_readClassPair"))
76     return Err;
77   if (auto Err =
78           setUpObjCRegAPIFunc(sel_registerName, LibObjC, "sel_registerName"))
79     return Err;
80 
81   ObjCRegistrationAPIState = ObjCRegistrationAPI::Initialized;
82   return Error::success();
83 }
84 
objCRegistrationEnabled()85 bool objCRegistrationEnabled() {
86   return ObjCRegistrationAPIState == ObjCRegistrationAPI::Initialized;
87 }
88 
runModInits() const89 void MachOJITDylibInitializers::runModInits() const {
90   for (const auto &ModInit : ModInitSections) {
91     for (uint64_t I = 0; I != ModInit.NumPtrs; ++I) {
92       auto *InitializerAddr = jitTargetAddressToPointer<uintptr_t *>(
93           ModInit.Address + (I * sizeof(uintptr_t)));
94       auto *Initializer =
95           jitTargetAddressToFunction<void (*)()>(*InitializerAddr);
96       Initializer();
97     }
98   }
99 }
100 
registerObjCSelectors() const101 void MachOJITDylibInitializers::registerObjCSelectors() const {
102   assert(objCRegistrationEnabled() && "ObjC registration not enabled.");
103 
104   for (const auto &ObjCSelRefs : ObjCSelRefsSections) {
105     for (uint64_t I = 0; I != ObjCSelRefs.NumPtrs; ++I) {
106       auto SelEntryAddr = ObjCSelRefs.Address + (I * sizeof(uintptr_t));
107       const auto *SelName =
108           *jitTargetAddressToPointer<const char **>(SelEntryAddr);
109       auto Sel = sel_registerName(SelName);
110       *jitTargetAddressToPointer<SEL *>(SelEntryAddr) = Sel;
111     }
112   }
113 }
114 
registerObjCClasses() const115 Error MachOJITDylibInitializers::registerObjCClasses() const {
116   assert(objCRegistrationEnabled() && "ObjC registration not enabled.");
117 
118   struct ObjCClassCompiled {
119     void *Metaclass;
120     void *Parent;
121     void *Cache1;
122     void *Cache2;
123     void *Data;
124   };
125 
126   auto *ImageInfo =
127       jitTargetAddressToPointer<const objc_image_info *>(ObjCImageInfoAddr);
128   auto ClassSelector = sel_registerName("class");
129 
130   for (const auto &ObjCClassList : ObjCClassListSections) {
131     for (uint64_t I = 0; I != ObjCClassList.NumPtrs; ++I) {
132       auto ClassPtrAddr = ObjCClassList.Address + (I * sizeof(uintptr_t));
133       auto Cls = *jitTargetAddressToPointer<Class *>(ClassPtrAddr);
134       auto *ClassCompiled =
135           *jitTargetAddressToPointer<ObjCClassCompiled **>(ClassPtrAddr);
136       objc_msgSend(reinterpret_cast<id>(ClassCompiled->Parent), ClassSelector);
137       auto Registered = objc_readClassPair(Cls, ImageInfo);
138 
139       // FIXME: Improve diagnostic by reporting the failed class's name.
140       if (Registered != Cls)
141         return make_error<StringError>("Unable to register Objective-C class",
142                                        inconvertibleErrorCode());
143     }
144   }
145   return Error::success();
146 }
147 
MachOPlatform(ExecutionSession & ES,ObjectLinkingLayer & ObjLinkingLayer,std::unique_ptr<MemoryBuffer> StandardSymbolsObject)148 MachOPlatform::MachOPlatform(
149     ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
150     std::unique_ptr<MemoryBuffer> StandardSymbolsObject)
151     : ES(ES), ObjLinkingLayer(ObjLinkingLayer),
152       StandardSymbolsObject(std::move(StandardSymbolsObject)) {
153   ObjLinkingLayer.addPlugin(std::make_unique<InitScraperPlugin>(*this));
154 }
155 
setupJITDylib(JITDylib & JD)156 Error MachOPlatform::setupJITDylib(JITDylib &JD) {
157   auto ObjBuffer = MemoryBuffer::getMemBuffer(
158       StandardSymbolsObject->getMemBufferRef(), false);
159   return ObjLinkingLayer.add(JD, std::move(ObjBuffer));
160 }
161 
notifyAdding(ResourceTracker & RT,const MaterializationUnit & MU)162 Error MachOPlatform::notifyAdding(ResourceTracker &RT,
163                                   const MaterializationUnit &MU) {
164   auto &JD = RT.getJITDylib();
165   const auto &InitSym = MU.getInitializerSymbol();
166   if (!InitSym)
167     return Error::success();
168 
169   RegisteredInitSymbols[&JD].add(InitSym,
170                                  SymbolLookupFlags::WeaklyReferencedSymbol);
171   LLVM_DEBUG({
172     dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU "
173            << MU.getName() << "\n";
174   });
175   return Error::success();
176 }
177 
notifyRemoving(ResourceTracker & RT)178 Error MachOPlatform::notifyRemoving(ResourceTracker &RT) {
179   llvm_unreachable("Not supported yet");
180 }
181 
182 Expected<MachOPlatform::InitializerSequence>
getInitializerSequence(JITDylib & JD)183 MachOPlatform::getInitializerSequence(JITDylib &JD) {
184 
185   LLVM_DEBUG({
186     dbgs() << "MachOPlatform: Building initializer sequence for "
187            << JD.getName() << "\n";
188   });
189 
190   std::vector<JITDylibSP> DFSLinkOrder;
191 
192   while (true) {
193 
194     DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;
195 
196     ES.runSessionLocked([&]() {
197       DFSLinkOrder = JD.getDFSLinkOrder();
198 
199       for (auto &InitJD : DFSLinkOrder) {
200         auto RISItr = RegisteredInitSymbols.find(InitJD.get());
201         if (RISItr != RegisteredInitSymbols.end()) {
202           NewInitSymbols[InitJD.get()] = std::move(RISItr->second);
203           RegisteredInitSymbols.erase(RISItr);
204         }
205       }
206     });
207 
208     if (NewInitSymbols.empty())
209       break;
210 
211     LLVM_DEBUG({
212       dbgs() << "MachOPlatform: Issuing lookups for new init symbols: "
213                 "(lookup may require multiple rounds)\n";
214       for (auto &KV : NewInitSymbols)
215         dbgs() << "  \"" << KV.first->getName() << "\": " << KV.second << "\n";
216     });
217 
218     // Outside the lock, issue the lookup.
219     if (auto R = lookupInitSymbols(JD.getExecutionSession(), NewInitSymbols))
220       ; // Nothing to do in the success case.
221     else
222       return R.takeError();
223   }
224 
225   LLVM_DEBUG({
226     dbgs() << "MachOPlatform: Init symbol lookup complete, building init "
227               "sequence\n";
228   });
229 
230   // Lock again to collect the initializers.
231   InitializerSequence FullInitSeq;
232   {
233     std::lock_guard<std::mutex> Lock(InitSeqsMutex);
234     for (auto &InitJD : reverse(DFSLinkOrder)) {
235       LLVM_DEBUG({
236         dbgs() << "MachOPlatform: Appending inits for \"" << InitJD->getName()
237                << "\" to sequence\n";
238       });
239       auto ISItr = InitSeqs.find(InitJD.get());
240       if (ISItr != InitSeqs.end()) {
241         FullInitSeq.emplace_back(InitJD.get(), std::move(ISItr->second));
242         InitSeqs.erase(ISItr);
243       }
244     }
245   }
246 
247   return FullInitSeq;
248 }
249 
250 Expected<MachOPlatform::DeinitializerSequence>
getDeinitializerSequence(JITDylib & JD)251 MachOPlatform::getDeinitializerSequence(JITDylib &JD) {
252   std::vector<JITDylibSP> DFSLinkOrder = JD.getDFSLinkOrder();
253 
254   DeinitializerSequence FullDeinitSeq;
255   {
256     std::lock_guard<std::mutex> Lock(InitSeqsMutex);
257     for (auto &DeinitJD : DFSLinkOrder) {
258       FullDeinitSeq.emplace_back(DeinitJD.get(), MachOJITDylibDeinitializers());
259     }
260   }
261 
262   return FullDeinitSeq;
263 }
264 
registerInitInfo(JITDylib & JD,JITTargetAddress ObjCImageInfoAddr,MachOJITDylibInitializers::SectionExtent ModInits,MachOJITDylibInitializers::SectionExtent ObjCSelRefs,MachOJITDylibInitializers::SectionExtent ObjCClassList)265 void MachOPlatform::registerInitInfo(
266     JITDylib &JD, JITTargetAddress ObjCImageInfoAddr,
267     MachOJITDylibInitializers::SectionExtent ModInits,
268     MachOJITDylibInitializers::SectionExtent ObjCSelRefs,
269     MachOJITDylibInitializers::SectionExtent ObjCClassList) {
270   std::lock_guard<std::mutex> Lock(InitSeqsMutex);
271 
272   auto &InitSeq = InitSeqs[&JD];
273 
274   InitSeq.setObjCImageInfoAddr(ObjCImageInfoAddr);
275 
276   if (ModInits.Address)
277     InitSeq.addModInitsSection(std::move(ModInits));
278 
279   if (ObjCSelRefs.Address)
280     InitSeq.addObjCSelRefsSection(std::move(ObjCSelRefs));
281 
282   if (ObjCClassList.Address)
283     InitSeq.addObjCClassListSection(std::move(ObjCClassList));
284 }
285 
286 static Expected<MachOJITDylibInitializers::SectionExtent>
getSectionExtent(jitlink::LinkGraph & G,StringRef SectionName)287 getSectionExtent(jitlink::LinkGraph &G, StringRef SectionName) {
288   auto *Sec = G.findSectionByName(SectionName);
289   if (!Sec)
290     return MachOJITDylibInitializers::SectionExtent();
291   jitlink::SectionRange R(*Sec);
292   if (R.getSize() % G.getPointerSize() != 0)
293     return make_error<StringError>(SectionName + " section size is not a "
294                                                  "multiple of the pointer size",
295                                    inconvertibleErrorCode());
296   return MachOJITDylibInitializers::SectionExtent(
297       R.getStart(), R.getSize() / G.getPointerSize());
298 }
299 
modifyPassConfig(MaterializationResponsibility & MR,jitlink::LinkGraph & LG,jitlink::PassConfiguration & Config)300 void MachOPlatform::InitScraperPlugin::modifyPassConfig(
301     MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
302     jitlink::PassConfiguration &Config) {
303 
304   if (!MR.getInitializerSymbol())
305     return;
306 
307   Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) -> Error {
308     JITLinkSymbolVector InitSectionSymbols;
309     preserveInitSectionIfPresent(InitSectionSymbols, G,
310                                  "__DATA,__mod_init_func");
311     preserveInitSectionIfPresent(InitSectionSymbols, G,
312                                  "__DATA,__objc_selrefs");
313     preserveInitSectionIfPresent(InitSectionSymbols, G,
314                                  "__DATA,__objc_classlist");
315 
316     if (!InitSectionSymbols.empty()) {
317       std::lock_guard<std::mutex> Lock(InitScraperMutex);
318       InitSymbolDeps[&MR] = std::move(InitSectionSymbols);
319     }
320 
321     if (auto Err = processObjCImageInfo(G, MR))
322       return Err;
323 
324     return Error::success();
325   });
326 
327   Config.PostFixupPasses.push_back([this, &JD = MR.getTargetJITDylib()](
328                                        jitlink::LinkGraph &G) -> Error {
329     MachOJITDylibInitializers::SectionExtent ModInits, ObjCSelRefs,
330         ObjCClassList;
331 
332     JITTargetAddress ObjCImageInfoAddr = 0;
333     if (auto *ObjCImageInfoSec =
334             G.findSectionByName("__DATA,__objc_image_info")) {
335       if (auto Addr = jitlink::SectionRange(*ObjCImageInfoSec).getStart())
336         ObjCImageInfoAddr = Addr;
337     }
338 
339     // Record __mod_init_func.
340     if (auto ModInitsOrErr = getSectionExtent(G, "__DATA,__mod_init_func"))
341       ModInits = std::move(*ModInitsOrErr);
342     else
343       return ModInitsOrErr.takeError();
344 
345     // Record __objc_selrefs.
346     if (auto ObjCSelRefsOrErr = getSectionExtent(G, "__DATA,__objc_selrefs"))
347       ObjCSelRefs = std::move(*ObjCSelRefsOrErr);
348     else
349       return ObjCSelRefsOrErr.takeError();
350 
351     // Record __objc_classlist.
352     if (auto ObjCClassListOrErr =
353             getSectionExtent(G, "__DATA,__objc_classlist"))
354       ObjCClassList = std::move(*ObjCClassListOrErr);
355     else
356       return ObjCClassListOrErr.takeError();
357 
358     // Dump the scraped inits.
359     LLVM_DEBUG({
360       dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n";
361       dbgs() << "  __objc_selrefs: ";
362       if (ObjCSelRefs.NumPtrs)
363         dbgs() << ObjCSelRefs.NumPtrs << " pointer(s) at "
364                << formatv("{0:x16}", ObjCSelRefs.Address) << "\n";
365       else
366         dbgs() << "none\n";
367 
368       dbgs() << "  __objc_classlist: ";
369       if (ObjCClassList.NumPtrs)
370         dbgs() << ObjCClassList.NumPtrs << " pointer(s) at "
371                << formatv("{0:x16}", ObjCClassList.Address) << "\n";
372       else
373         dbgs() << "none\n";
374 
375       dbgs() << "  __mod_init_func: ";
376       if (ModInits.NumPtrs)
377         dbgs() << ModInits.NumPtrs << " pointer(s) at "
378                << formatv("{0:x16}", ModInits.Address) << "\n";
379       else
380         dbgs() << "none\n";
381     });
382 
383     MP.registerInitInfo(JD, ObjCImageInfoAddr, std::move(ModInits),
384                         std::move(ObjCSelRefs), std::move(ObjCClassList));
385 
386     return Error::success();
387   });
388 }
389 
390 ObjectLinkingLayer::Plugin::LocalDependenciesMap
getSyntheticSymbolLocalDependencies(MaterializationResponsibility & MR)391 MachOPlatform::InitScraperPlugin::getSyntheticSymbolLocalDependencies(
392     MaterializationResponsibility &MR) {
393   std::lock_guard<std::mutex> Lock(InitScraperMutex);
394   auto I = InitSymbolDeps.find(&MR);
395   if (I != InitSymbolDeps.end()) {
396     LocalDependenciesMap Result;
397     Result[MR.getInitializerSymbol()] = std::move(I->second);
398     InitSymbolDeps.erase(&MR);
399     return Result;
400   }
401   return LocalDependenciesMap();
402 }
403 
preserveInitSectionIfPresent(JITLinkSymbolVector & Symbols,jitlink::LinkGraph & G,StringRef SectionName)404 void MachOPlatform::InitScraperPlugin::preserveInitSectionIfPresent(
405     JITLinkSymbolVector &Symbols, jitlink::LinkGraph &G,
406     StringRef SectionName) {
407   if (auto *Sec = G.findSectionByName(SectionName)) {
408     auto SecBlocks = Sec->blocks();
409     if (!llvm::empty(SecBlocks))
410       Symbols.push_back(
411           &G.addAnonymousSymbol(**SecBlocks.begin(), 0, 0, false, true));
412   }
413 }
414 
processObjCImageInfo(jitlink::LinkGraph & G,MaterializationResponsibility & MR)415 Error MachOPlatform::InitScraperPlugin::processObjCImageInfo(
416     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
417 
418   // If there's an ObjC imagine info then either
419   //   (1) It's the first __objc_imageinfo we've seen in this JITDylib. In
420   //       this case we name and record it.
421   // OR
422   //   (2) We already have a recorded __objc_imageinfo for this JITDylib,
423   //       in which case we just verify it.
424   auto *ObjCImageInfo = G.findSectionByName("__objc_imageinfo");
425   if (!ObjCImageInfo)
426     return Error::success();
427 
428   auto ObjCImageInfoBlocks = ObjCImageInfo->blocks();
429 
430   // Check that the section is not empty if present.
431   if (llvm::empty(ObjCImageInfoBlocks))
432     return make_error<StringError>("Empty __objc_imageinfo section in " +
433                                        G.getName(),
434                                    inconvertibleErrorCode());
435 
436   // Check that there's only one block in the section.
437   if (std::next(ObjCImageInfoBlocks.begin()) != ObjCImageInfoBlocks.end())
438     return make_error<StringError>("Multiple blocks in __objc_imageinfo "
439                                    "section in " +
440                                        G.getName(),
441                                    inconvertibleErrorCode());
442 
443   // Check that the __objc_imageinfo section is unreferenced.
444   // FIXME: We could optimize this check if Symbols had a ref-count.
445   for (auto &Sec : G.sections()) {
446     if (&Sec != ObjCImageInfo)
447       for (auto *B : Sec.blocks())
448         for (auto &E : B->edges())
449           if (E.getTarget().isDefined() &&
450               &E.getTarget().getBlock().getSection() == ObjCImageInfo)
451             return make_error<StringError>("__objc_imageinfo is referenced "
452                                            "within file " +
453                                                G.getName(),
454                                            inconvertibleErrorCode());
455   }
456 
457   auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin();
458   auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data();
459   auto Version = support::endian::read32(ObjCImageInfoData, G.getEndianness());
460   auto Flags =
461       support::endian::read32(ObjCImageInfoData + 4, G.getEndianness());
462 
463   // Lock the mutex while we verify / update the ObjCImageInfos map.
464   std::lock_guard<std::mutex> Lock(InitScraperMutex);
465 
466   auto ObjCImageInfoItr = ObjCImageInfos.find(&MR.getTargetJITDylib());
467   if (ObjCImageInfoItr != ObjCImageInfos.end()) {
468     // We've already registered an __objc_imageinfo section. Verify the
469     // content of this new section matches, then delete it.
470     if (ObjCImageInfoItr->second.first != Version)
471       return make_error<StringError>(
472           "ObjC version in " + G.getName() +
473               " does not match first registered version",
474           inconvertibleErrorCode());
475     if (ObjCImageInfoItr->second.second != Flags)
476       return make_error<StringError>("ObjC flags in " + G.getName() +
477                                          " do not match first registered flags",
478                                      inconvertibleErrorCode());
479 
480     // __objc_imageinfo is valid. Delete the block.
481     for (auto *S : ObjCImageInfo->symbols())
482       G.removeDefinedSymbol(*S);
483     G.removeBlock(ObjCImageInfoBlock);
484   } else {
485     // We haven't registered an __objc_imageinfo section yet. Register and
486     // move on. The section should already be marked no-dead-strip.
487     ObjCImageInfos[&MR.getTargetJITDylib()] = std::make_pair(Version, Flags);
488   }
489 
490   return Error::success();
491 }
492 
493 } // End namespace orc.
494 } // End namespace llvm.
495