385 lines · cpp
1//===-------- ObjectLinkingLayerTest.cpp - ObjectLinkingLayer tests -------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"10#include "llvm/ExecutionEngine/JITLink/JITLink.h"11#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"12#include "llvm/ExecutionEngine/JITLink/x86_64.h"13#include "llvm/ExecutionEngine/JITSymbol.h"14#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"15#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"16#include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h"17#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"18#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"19#include "llvm/Testing/Support/Error.h"20#include "gtest/gtest.h"21 22#include "OrcTestCommon.h"23 24using namespace llvm;25using namespace llvm::jitlink;26using namespace llvm::orc;27 28namespace {29 30const char BlockContentBytes[] = {0x01, 0x02, 0x03, 0x04,31 0x05, 0x06, 0x07, 0x08};32 33ArrayRef<char> BlockContent(BlockContentBytes);34 35class ObjectLinkingLayerTest : public testing::Test {36public:37 ~ObjectLinkingLayerTest() override {38 if (auto Err = ES.endSession())39 ES.reportError(std::move(Err));40 }41 42protected:43 ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()};44 JITDylib &JD = ES.createBareJITDylib("main");45 ObjectLinkingLayer ObjLinkingLayer{46 ES, std::make_unique<InProcessMemoryManager>(4096)};47};48 49TEST_F(ObjectLinkingLayerTest, AddLinkGraph) {50 auto G = std::make_unique<LinkGraph>(51 "foo", ES.getSymbolStringPool(), Triple("x86_64-apple-darwin"),52 SubtargetFeatures(), x86_64::getEdgeKindName);53 54 auto &Sec1 = G->createSection("__data", MemProt::Read | MemProt::Write);55 auto &B1 =56 G->createContentBlock(Sec1, BlockContent, ExecutorAddr(0x1000), 8, 0);57 G->addDefinedSymbol(B1, 4, "_X", 4, Linkage::Strong, Scope::Default, false,58 false);59 G->addDefinedSymbol(B1, 4, "_Y", 4, Linkage::Weak, Scope::Default, false,60 false);61 G->addDefinedSymbol(B1, 4, "_Z", 4, Linkage::Strong, Scope::Hidden, false,62 false);63 G->addDefinedSymbol(B1, 4, "_W", 4, Linkage::Strong, Scope::Default, true,64 false);65 66 EXPECT_THAT_ERROR(ObjLinkingLayer.add(JD, std::move(G)), Succeeded());67 68 EXPECT_THAT_EXPECTED(ES.lookup(&JD, "_X"), Succeeded());69}70 71TEST_F(ObjectLinkingLayerTest, ResourceTracker) {72 // This test transfers allocations to previously unknown ResourceTrackers,73 // while increasing the number of trackers in the ObjectLinkingLayer, which74 // may invalidate some iterators internally.75 std::vector<ResourceTrackerSP> Trackers;76 for (unsigned I = 0; I < 64; I++) {77 auto G = std::make_unique<LinkGraph>(78 "foo", ES.getSymbolStringPool(), Triple("x86_64-apple-darwin"),79 SubtargetFeatures(), x86_64::getEdgeKindName);80 81 auto &Sec1 = G->createSection("__data", MemProt::Read | MemProt::Write);82 auto &B1 =83 G->createContentBlock(Sec1, BlockContent, ExecutorAddr(0x1000), 8, 0);84 llvm::SmallString<0> SymbolName;85 SymbolName += "_X";86 SymbolName += std::to_string(I);87 G->addDefinedSymbol(B1, 4, SymbolName, 4, Linkage::Strong, Scope::Default,88 false, false);89 90 auto RT1 = JD.createResourceTracker();91 EXPECT_THAT_ERROR(ObjLinkingLayer.add(RT1, std::move(G)), Succeeded());92 EXPECT_THAT_EXPECTED(ES.lookup(&JD, SymbolName), Succeeded());93 94 auto RT2 = JD.createResourceTracker();95 RT1->transferTo(*RT2);96 97 Trackers.push_back(RT2);98 }99}100 101TEST_F(ObjectLinkingLayerTest, ClaimLateDefinedWeakSymbols) {102 // Check that claiming weak symbols works as expected.103 //104 // To do this we'll need a custom plugin to inject some new symbols during105 // the link.106 class TestPlugin : public ObjectLinkingLayer::Plugin {107 public:108 void modifyPassConfig(MaterializationResponsibility &MR,109 jitlink::LinkGraph &G,110 jitlink::PassConfiguration &Config) override {111 Config.PrePrunePasses.insert(112 Config.PrePrunePasses.begin(), [](LinkGraph &G) {113 auto *DataSec = G.findSectionByName("__data");114 auto &DataBlock = G.createContentBlock(*DataSec, BlockContent,115 ExecutorAddr(0x2000), 8, 0);116 G.addDefinedSymbol(DataBlock, 4, "_x", 4, Linkage::Weak,117 Scope::Default, false, false);118 119 auto &TextSec =120 G.createSection("__text", MemProt::Read | MemProt::Write);121 auto &FuncBlock = G.createContentBlock(TextSec, BlockContent,122 ExecutorAddr(0x3000), 8, 0);123 G.addDefinedSymbol(FuncBlock, 4, "_f", 4, Linkage::Weak,124 Scope::Default, true, false);125 126 return Error::success();127 });128 }129 130 Error notifyFailed(MaterializationResponsibility &MR) override {131 llvm_unreachable("unexpected error");132 }133 134 Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {135 return Error::success();136 }137 void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,138 ResourceKey SrcKey) override {139 llvm_unreachable("unexpected resource transfer");140 }141 };142 143 ObjLinkingLayer.addPlugin(std::make_unique<TestPlugin>());144 auto G = std::make_unique<LinkGraph>(145 "foo", ES.getSymbolStringPool(), Triple("x86_64-apple-darwin"),146 SubtargetFeatures(), getGenericEdgeKindName);147 148 auto &DataSec = G->createSection("__data", MemProt::Read | MemProt::Write);149 auto &DataBlock =150 G->createContentBlock(DataSec, BlockContent, ExecutorAddr(0x1000), 8, 0);151 G->addDefinedSymbol(DataBlock, 4, "_anchor", 4, Linkage::Weak, Scope::Default,152 false, true);153 154 EXPECT_THAT_ERROR(ObjLinkingLayer.add(JD, std::move(G)), Succeeded());155 156 EXPECT_THAT_EXPECTED(ES.lookup(&JD, "_anchor"), Succeeded());157}158 159TEST_F(ObjectLinkingLayerTest, HandleErrorDuringPostAllocationPass) {160 // We want to confirm that Errors in post allocation passes correctly161 // abandon the in-flight allocation and report an error.162 class TestPlugin : public ObjectLinkingLayer::Plugin {163 public:164 ~TestPlugin() override { EXPECT_TRUE(ErrorReported); }165 166 void modifyPassConfig(MaterializationResponsibility &MR,167 jitlink::LinkGraph &G,168 jitlink::PassConfiguration &Config) override {169 Config.PostAllocationPasses.insert(170 Config.PostAllocationPasses.begin(), [](LinkGraph &G) {171 return make_error<StringError>("Kaboom", inconvertibleErrorCode());172 });173 }174 175 Error notifyFailed(MaterializationResponsibility &MR) override {176 ErrorReported = true;177 return Error::success();178 }179 180 Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {181 return Error::success();182 }183 void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,184 ResourceKey SrcKey) override {185 llvm_unreachable("unexpected resource transfer");186 }187 188 private:189 bool ErrorReported = false;190 };191 192 // We expect this test to generate errors. Consume them so that we don't193 // add noise to the test logs.194 ES.setErrorReporter(consumeError);195 196 ObjLinkingLayer.addPlugin(std::make_unique<TestPlugin>());197 auto G = std::make_unique<LinkGraph>(198 "foo", ES.getSymbolStringPool(), Triple("x86_64-apple-darwin"),199 SubtargetFeatures(), getGenericEdgeKindName);200 201 auto &DataSec = G->createSection("__data", MemProt::Read | MemProt::Write);202 auto &DataBlock =203 G->createContentBlock(DataSec, BlockContent, ExecutorAddr(0x1000), 8, 0);204 G->addDefinedSymbol(DataBlock, 4, "_anchor", 4, Linkage::Weak, Scope::Default,205 false, true);206 207 EXPECT_THAT_ERROR(ObjLinkingLayer.add(JD, std::move(G)), Succeeded());208 209 EXPECT_THAT_EXPECTED(ES.lookup(&JD, "_anchor"), Failed());210}211 212TEST_F(ObjectLinkingLayerTest, AddAndRemovePlugins) {213 class TestPlugin : public ObjectLinkingLayer::Plugin {214 public:215 TestPlugin(size_t &ActivationCount, bool &PluginDestroyed)216 : ActivationCount(ActivationCount), PluginDestroyed(PluginDestroyed) {}217 218 ~TestPlugin() override { PluginDestroyed = true; }219 220 void modifyPassConfig(MaterializationResponsibility &MR,221 jitlink::LinkGraph &G,222 jitlink::PassConfiguration &Config) override {223 ++ActivationCount;224 }225 226 Error notifyFailed(MaterializationResponsibility &MR) override {227 ADD_FAILURE() << "TestPlugin::notifyFailed called unexpectedly";228 return Error::success();229 }230 231 Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {232 return Error::success();233 }234 235 void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,236 ResourceKey SrcKey) override {}237 238 private:239 size_t &ActivationCount;240 bool &PluginDestroyed;241 };242 243 size_t ActivationCount = 0;244 bool PluginDestroyed = false;245 246 auto P = std::make_shared<TestPlugin>(ActivationCount, PluginDestroyed);247 248 ObjLinkingLayer.addPlugin(P);249 250 {251 auto G1 = std::make_unique<LinkGraph>(252 "G1", ES.getSymbolStringPool(), Triple("x86_64-apple-darwin"),253 SubtargetFeatures(), x86_64::getEdgeKindName);254 255 auto &DataSec = G1->createSection("__data", MemProt::Read | MemProt::Write);256 auto &DataBlock = G1->createContentBlock(DataSec, BlockContent,257 ExecutorAddr(0x1000), 8, 0);258 G1->addDefinedSymbol(DataBlock, 4, "_anchor1", 4, Linkage::Weak,259 Scope::Default, false, true);260 261 EXPECT_THAT_ERROR(ObjLinkingLayer.add(JD, std::move(G1)), Succeeded());262 EXPECT_THAT_EXPECTED(ES.lookup(&JD, "_anchor1"), Succeeded());263 EXPECT_EQ(ActivationCount, 1U);264 }265 266 ObjLinkingLayer.removePlugin(*P);267 268 {269 auto G2 = std::make_unique<LinkGraph>(270 "G2", ES.getSymbolStringPool(), Triple("x86_64-apple-darwin"),271 SubtargetFeatures(), x86_64::getEdgeKindName);272 273 auto &DataSec = G2->createSection("__data", MemProt::Read | MemProt::Write);274 auto &DataBlock = G2->createContentBlock(DataSec, BlockContent,275 ExecutorAddr(0x1000), 8, 0);276 G2->addDefinedSymbol(DataBlock, 4, "_anchor2", 4, Linkage::Weak,277 Scope::Default, false, true);278 279 EXPECT_THAT_ERROR(ObjLinkingLayer.add(JD, std::move(G2)), Succeeded());280 EXPECT_THAT_EXPECTED(ES.lookup(&JD, "_anchor2"), Succeeded());281 EXPECT_EQ(ActivationCount, 1U);282 }283 284 P.reset();285 EXPECT_TRUE(PluginDestroyed);286}287 288TEST(ObjectLinkingLayerSearchGeneratorTest, AbsoluteSymbolsObjectLayer) {289 class TestEPC : public UnsupportedExecutorProcessControl,290 public DylibManager {291 public:292 TestEPC()293 : UnsupportedExecutorProcessControl(nullptr, nullptr,294 "x86_64-apple-darwin") {295 this->DylibMgr = this;296 }297 298 Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override {299 return ExecutorAddr::fromPtr((void *)nullptr);300 }301 302 void lookupSymbolsAsync(ArrayRef<LookupRequest> Request,303 SymbolLookupCompleteFn Complete) override {304 std::vector<std::optional<ExecutorSymbolDef>> Result;305 EXPECT_EQ(Request.size(), 1u);306 for (auto &LR : Request) {307 EXPECT_EQ(LR.Symbols.size(), 1u);308 for (auto &Sym : LR.Symbols) {309 if (*Sym.first == "_testFunc") {310 ExecutorSymbolDef Def{ExecutorAddr::fromPtr((void *)0x1000),311 JITSymbolFlags::Exported};312 Result.emplace_back(Def);313 } else {314 ADD_FAILURE() << "unexpected symbol request " << *Sym.first;315 }316 }317 }318 Complete(std::vector<tpctypes::LookupResult>{1, Result});319 }320 };321 322 ExecutionSession ES{std::make_unique<TestEPC>()};323 JITDylib &JD = ES.createBareJITDylib("main");324 ObjectLinkingLayer ObjLinkingLayer{325 ES, std::make_unique<InProcessMemoryManager>(4096)};326 327 auto G = EPCDynamicLibrarySearchGenerator::GetForTargetProcess(328 ES, {}, [&](JITDylib &JD, SymbolMap Syms) {329 auto G =330 absoluteSymbolsLinkGraph(Triple("x86_64-apple-darwin"),331 ES.getSymbolStringPool(), std::move(Syms));332 return ObjLinkingLayer.add(JD, std::move(G));333 });334 ASSERT_THAT_EXPECTED(G, Succeeded());335 JD.addGenerator(std::move(*G));336 337 class CheckDefs : public ObjectLinkingLayer::Plugin {338 public:339 ~CheckDefs() override { EXPECT_TRUE(SawSymbolDef); }340 341 void modifyPassConfig(MaterializationResponsibility &MR,342 jitlink::LinkGraph &G,343 jitlink::PassConfiguration &Config) override {344 Config.PostAllocationPasses.push_back([this](LinkGraph &G) {345 unsigned SymCount = 0;346 for (Symbol *Sym : G.absolute_symbols()) {347 SymCount += 1;348 if (!Sym->hasName()) {349 ADD_FAILURE() << "unexpected unnamed symbol";350 continue;351 }352 if (*Sym->getName() == "_testFunc")353 SawSymbolDef = true;354 else355 ADD_FAILURE() << "unexpected symbol " << Sym->getName();356 }357 EXPECT_EQ(SymCount, 1u);358 return Error::success();359 });360 }361 362 Error notifyFailed(MaterializationResponsibility &MR) override {363 return Error::success();364 }365 366 Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {367 return Error::success();368 }369 void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,370 ResourceKey SrcKey) override {371 llvm_unreachable("unexpected resource transfer");372 }373 374 private:375 bool SawSymbolDef = false;376 };377 378 ObjLinkingLayer.addPlugin(std::make_unique<CheckDefs>());379 380 EXPECT_THAT_EXPECTED(ES.lookup(&JD, "_testFunc"), Succeeded());381 EXPECT_THAT_ERROR(ES.endSession(), Succeeded());382}383 384} // end anonymous namespace385