llvm.org GIT mirror llvm / b20e09c
[LLI] Replace the LLI remote-JIT support with the new ORC remote-JIT components. The new ORC remote-JITing support provides a superset of the old code's functionality, so we can replace the old stuff. As a bonus, a couple of previously XFAILed tests have started passing. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@257343 91177308-0d34-0410-b5e6-96231b3b80d8 Lang Hames 4 years ago
23 changed file(s) with 395 addition(s) and 1533 deletion(s). Raw diff Collapse all Expand all
2424 namespace llvm {
2525 namespace orc {
2626
27 /// Generic ORC Architecture support.
28 ///
29 /// This class can be substituted as the target architecure support class for
30 /// ORC templates that require one (e.g. IndirectStubsManagers). It does not
31 /// support lazy JITing however, and any attempt to use that functionality
32 /// will result in execution of an llvm_unreachable.
33 class OrcGenericArchitecture {
34 public:
35 static const unsigned PointerSize = sizeof(uintptr_t);
36 static const unsigned TrampolineSize = 1;
37 static const unsigned ResolverCodeSize = 1;
38
39 typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, void *TrampolineId);
40
41 static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
42 void *CallbackMgr) {
43 llvm_unreachable("writeResolverCode is not supported by the generic host "
44 "support class");
45 }
46
47 static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
48 unsigned NumTrampolines) {
49 llvm_unreachable("writeTrampolines is not supported by the generic host "
50 "support class");
51 }
52
53 class IndirectStubsInfo {
54 public:
55 const static unsigned StubSize = 1;
56 unsigned getNumStubs() const { llvm_unreachable("Not supported"); }
57 void *getStub(unsigned Idx) const { llvm_unreachable("Not supported"); }
58 void **getPtr(unsigned Idx) const { llvm_unreachable("Not supported"); }
59 };
60
61 static std::error_code emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
62 unsigned MinStubs,
63 void *InitialPtrVal) {
64 llvm_unreachable("emitIndirectStubsBlock is not supported by the generic "
65 "host support class");
66 }
67 };
68
69 /// @brief X86_64 support.
70 ///
71 /// X86_64 supports lazy JITing.
2772 class OrcX86_64 {
2873 public:
2974 static const unsigned PointerSize = 8;
3075 static const unsigned TrampolineSize = 8;
3176 static const unsigned ResolverCodeSize = 0x78;
3277
33 typedef TargetAddress (*JITReentryFn)(void *CallbackMgr,
34 void *TrampolineId);
78 typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, void *TrampolineId);
3579
3680 /// @brief Write the resolver code into the given memory. The user is be
3781 /// responsible for allocating the memory and setting permissions.
4892 /// makeIndirectStubsBlock function.
4993 class IndirectStubsInfo {
5094 friend class OrcX86_64;
95
5196 public:
5297 const static unsigned StubSize = 8;
5398
56101 : NumStubs(Other.NumStubs), StubsMem(std::move(Other.StubsMem)) {
57102 Other.NumStubs = 0;
58103 }
59 IndirectStubsInfo& operator=(IndirectStubsInfo &&Other) {
104 IndirectStubsInfo &operator=(IndirectStubsInfo &&Other) {
60105 NumStubs = Other.NumStubs;
61106 Other.NumStubs = 0;
62107 StubsMem = std::move(Other.StubsMem);
68113
69114 /// @brief Get a pointer to the stub at the given index, which must be in
70115 /// the range 0 .. getNumStubs() - 1.
71 void* getStub(unsigned Idx) const {
72 return static_cast(StubsMem.base()) + Idx;
116 void *getStub(unsigned Idx) const {
117 return static_cast(StubsMem.base()) + Idx;
73118 }
74119
75120 /// @brief Get a pointer to the implementation-pointer at the given index,
76121 /// which must be in the range 0 .. getNumStubs() - 1.
77 void** getPtr(unsigned Idx) const {
122 void **getPtr(unsigned Idx) const {
78123 char *PtrsBase =
79 static_cast(StubsMem.base()) + NumStubs * StubSize;
80 return reinterpret_cast(PtrsBase) + Idx;
124 static_cast(StubsMem.base()) + NumStubs * StubSize;
125 return reinterpret_cast(PtrsBase) + Idx;
81126 }
127
82128 private:
83129 unsigned NumStubs;
84130 sys::OwningMemoryBlock StubsMem;
7474 void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr,
7575 size_t Size) override {
7676 return ClientMM->deregisterEHFrames(Addr, LoadAddr, Size);
77 }
78
79 void notifyObjectLoaded(RuntimeDyld &RTDyld,
80 const object::ObjectFile &O) override {
81 return ClientMM->notifyObjectLoaded(RTDyld, O);
7782 }
7883
7984 void notifyObjectLoaded(ExecutionEngine *EE,
0 ; RUN: %lli -remote-mcjit -disable-lazy-compilation=false -mcjit-remote-process=lli-child-target%exeext %s
1 ; XFAIL: *
21 ; This test should fail until remote symbol resolution is supported.
32
43 define i32 @main() nounwind {
None ; RUN: %lli -remote-mcjit -relocation-model=pic -code-model=small %s > /dev/null
0 ; RUN: %lli -remote-mcjit -mcjit-remote-process=lli-child-target%exeext \
1 ; RUN: -relocation-model=pic -code-model=small %s > /dev/null
12 ; XFAIL: mips-, mipsel-, aarch64, arm, i686, i386
23
34 @count = global i32 1, align 4
None ; RUN: %lli -remote-mcjit -O0 -relocation-model=pic -code-model=small %s
0 ; RUN: %lli -remote-mcjit -mcjit-remote-process=lli-child-target%exeext \
1 ; RUN: -O0 -relocation-model=pic -code-model=small %s
12 ; XFAIL: mips-, mipsel-, aarch64, arm, i686, i386
23
34 @.str = private unnamed_addr constant [6 x i8] c"data1\00", align 1
0 ; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -disable-lazy-compilation=false -mcjit-remote-process=lli-child-target%exeext %s
1 ; XFAIL: *
21 ; This test should fail until remote symbol resolution is supported.
32
43 define i32 @main() nounwind {
None ; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -relocation-model=pic -code-model=small %s > /dev/null
0 ; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -mcjit-remote-process=lli-child-target%exeext \
1 ; RUN: -relocation-model=pic -code-model=small %s > /dev/null
12 ; XFAIL: mips-, mipsel-, aarch64, arm, i686, i386
23
34 @count = global i32 1, align 4
None ; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -O0 -relocation-model=pic -code-model=small %s
0 ; RUN: %lli -jit-kind=orc-mcjit -remote-mcjit -mcjit-remote-process=lli-child-target%exeext \
1 ; RUN: -O0 -relocation-model=pic -code-model=small %s
12 ; XFAIL: mips-, mipsel-, aarch64, arm, i686, i386
23
34 @.str = private unnamed_addr constant [6 x i8] c"data1\00", align 1
3737 add_llvm_tool(lli
3838 lli.cpp
3939 OrcLazyJIT.cpp
40 RemoteMemoryManager.cpp
41 RemoteTarget.cpp
42 RemoteTargetExternal.cpp
4340 )
4441 export_executable_symbols(lli)
None set(LLVM_LINK_COMPONENTS support)
0 set(LLVM_LINK_COMPONENTS
1 OrcJIT
2 Support
3 )
14
25 add_llvm_executable(lli-child-target
36 ChildTarget.cpp
4 ../RemoteTarget.cpp
57 )
68
79 set_target_properties(lli-child-target PROPERTIES FOLDER "Misc")
None #include "llvm/Config/config.h"
1 #include "../RPCChannel.h"
2 #include "../RemoteTarget.h"
3 #include "../RemoteTargetMessage.h"
4 #include "llvm/Support/Memory.h"
5 #include
6 #include
7 #include
8 #include
9 #include
0 #include "llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h"
1 #include "llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h"
2 #include "llvm/Support/Debug.h"
3 #include "llvm/Support/DynamicLibrary.h"
4 #include "llvm/Support/Process.h"
5 #include
6
7 #include "../RemoteJITUtils.h"
108
119 using namespace llvm;
10 using namespace llvm::orc;
11 using namespace llvm::sys;
1212
13 class LLIChildTarget {
14 public:
15 void initialize();
16 LLIMessageType waitForIncomingMessage();
17 void handleMessage(LLIMessageType messageType);
18 RemoteTarget *RT;
19 RPCChannel RPC;
13 #ifdef __x86_64__
14 typedef OrcX86_64 HostOrcArch;
15 #else
16 typedef OrcGenericArchitecture HostOrcArch;
17 #endif
2018
21 private:
22 // Incoming message handlers
23 void handleAllocateSpace();
24 void handleLoadSection(bool IsCode);
25 void handleExecute();
19 int main(int argc, char *argv[]) {
2620
27 // Outgoing message handlers
28 void sendChildActive();
29 void sendAllocationResult(uint64_t Addr);
30 void sendLoadStatus(uint32_t Status);
31 void sendExecutionComplete(int Result);
32
33 // OS-specific functions
34 void initializeConnection();
35 int WriteBytes(const void *Data, size_t Size) {
36 return RPC.WriteBytes(Data, Size) ? Size : -1;
37 }
38 int ReadBytes(void *Data, size_t Size) {
39 return RPC.ReadBytes(Data, Size) ? Size : -1;
21 if (argc != 3) {
22 errs() << "Usage: " << argv[0] << " \n";
23 return 1;
4024 }
4125
42 // Communication handles (OS-specific)
43 void *ConnectionData;
44 };
26 int InFD;
27 int OutFD;
28 {
29 std::istringstream InFDStream(argv[1]), OutFDStream(argv[2]);
30 InFDStream >> InFD;
31 OutFDStream >> OutFD;
32 }
4533
46 int main() {
47 LLIChildTarget ThisChild;
48 ThisChild.RT = new RemoteTarget();
49 ThisChild.initialize();
50 LLIMessageType MsgType;
51 do {
52 MsgType = ThisChild.waitForIncomingMessage();
53 ThisChild.handleMessage(MsgType);
54 } while (MsgType != LLI_Terminate &&
55 MsgType != LLI_Error);
56 delete ThisChild.RT;
34 if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr)) {
35 errs() << "Error loading program symbols.\n";
36 return 1;
37 }
38
39 auto SymbolLookup = [](const std::string &Name) {
40 return RTDyldMemoryManager::getSymbolAddressInProcess(Name);
41 };
42
43 FDRPCChannel Channel(InFD, OutFD);
44 typedef remote::OrcRemoteTargetServer JITServer;
45 JITServer Server(Channel, SymbolLookup);
46
47 while (1) {
48 JITServer::JITProcId Id = JITServer::InvalidId;
49 if (auto EC = Server.getNextProcId(Id)) {
50 errs() << "Error: " << EC.message() << "\n";
51 return 1;
52 }
53 switch (Id) {
54 case JITServer::TerminateSessionId:
55 return 0;
56 default:
57 if (auto EC = Server.handleKnownProcedure(Id)) {
58 errs() << "Error: " << EC.message() << "\n";
59 return 1;
60 }
61 }
62 }
63
64 close(InFD);
65 close(OutFD);
66
5767 return 0;
5868 }
59
60 // Public methods
61 void LLIChildTarget::initialize() {
62 RPC.createClient();
63 sendChildActive();
64 }
65
66 LLIMessageType LLIChildTarget::waitForIncomingMessage() {
67 int32_t MsgType = -1;
68 if (ReadBytes(&MsgType, 4) > 0)
69 return (LLIMessageType)MsgType;
70 return LLI_Error;
71 }
72
73 void LLIChildTarget::handleMessage(LLIMessageType messageType) {
74 switch (messageType) {
75 case LLI_AllocateSpace:
76 handleAllocateSpace();
77 break;
78 case LLI_LoadCodeSection:
79 handleLoadSection(true);
80 break;
81 case LLI_LoadDataSection:
82 handleLoadSection(false);
83 break;
84 case LLI_Execute:
85 handleExecute();
86 break;
87 case LLI_Terminate:
88 RT->stop();
89 break;
90 default:
91 // FIXME: Handle error!
92 break;
93 }
94 }
95
96 // Incoming message handlers
97 void LLIChildTarget::handleAllocateSpace() {
98 // Read and verify the message data size.
99 uint32_t DataSize = 0;
100 int rc = ReadBytes(&DataSize, 4);
101 (void)rc;
102 assert(rc == 4);
103 assert(DataSize == 8);
104
105 // Read the message arguments.
106 uint32_t Alignment = 0;
107 uint32_t AllocSize = 0;
108 rc = ReadBytes(&Alignment, 4);
109 assert(rc == 4);
110 rc = ReadBytes(&AllocSize, 4);
111 assert(rc == 4);
112
113 // Allocate the memory.
114 uint64_t Addr;
115 RT->allocateSpace(AllocSize, Alignment, Addr);
116
117 // Send AllocationResult message.
118 sendAllocationResult(Addr);
119 }
120
121 void LLIChildTarget::handleLoadSection(bool IsCode) {
122 // Read the message data size.
123 uint32_t DataSize = 0;
124 int rc = ReadBytes(&DataSize, 4);
125 (void)rc;
126 assert(rc == 4);
127
128 // Read the target load address.
129 uint64_t Addr = 0;
130 rc = ReadBytes(&Addr, 8);
131 assert(rc == 8);
132 size_t BufferSize = DataSize - 8;
133
134 if (!RT->isAllocatedMemory(Addr, BufferSize))
135 return sendLoadStatus(LLI_Status_NotAllocated);
136
137 // Read section data into previously allocated buffer
138 rc = ReadBytes((void*)Addr, BufferSize);
139 if (rc != (int)(BufferSize))
140 return sendLoadStatus(LLI_Status_IncompleteMsg);
141
142 // If IsCode, mark memory executable
143 if (IsCode)
144 sys::Memory::InvalidateInstructionCache((void *)Addr, BufferSize);
145
146 // Send MarkLoadComplete message.
147 sendLoadStatus(LLI_Status_Success);
148 }
149
150 void LLIChildTarget::handleExecute() {
151 // Read the message data size.
152 uint32_t DataSize = 0;
153 int rc = ReadBytes(&DataSize, 4);
154 (void)rc;
155 assert(rc == 4);
156 assert(DataSize == 8);
157
158 // Read the target address.
159 uint64_t Addr = 0;
160 rc = ReadBytes(&Addr, 8);
161 assert(rc == 8);
162
163 // Call function
164 int32_t Result = -1;
165 RT->executeCode(Addr, Result);
166
167 // Send ExecutionResult message.
168 sendExecutionComplete(Result);
169 }
170
171 // Outgoing message handlers
172 void LLIChildTarget::sendChildActive() {
173 // Write the message type.
174 uint32_t MsgType = (uint32_t)LLI_ChildActive;
175 int rc = WriteBytes(&MsgType, 4);
176 (void)rc;
177 assert(rc == 4);
178
179 // Write the data size.
180 uint32_t DataSize = 0;
181 rc = WriteBytes(&DataSize, 4);
182 assert(rc == 4);
183 }
184
185 void LLIChildTarget::sendAllocationResult(uint64_t Addr) {
186 // Write the message type.
187 uint32_t MsgType = (uint32_t)LLI_AllocationResult;
188 int rc = WriteBytes(&MsgType, 4);
189 (void)rc;
190 assert(rc == 4);
191
192 // Write the data size.
193 uint32_t DataSize = 8;
194 rc = WriteBytes(&DataSize, 4);
195 assert(rc == 4);
196
197 // Write the allocated address.
198 rc = WriteBytes(&Addr, 8);
199 assert(rc == 8);
200 }
201
202 void LLIChildTarget::sendLoadStatus(uint32_t Status) {
203 // Write the message type.
204 uint32_t MsgType = (uint32_t)LLI_LoadResult;
205 int rc = WriteBytes(&MsgType, 4);
206 (void)rc;
207 assert(rc == 4);
208
209 // Write the data size.
210 uint32_t DataSize = 4;
211 rc = WriteBytes(&DataSize, 4);
212 assert(rc == 4);
213
214 // Write the result.
215 rc = WriteBytes(&Status, 4);
216 assert(rc == 4);
217 }
218
219 void LLIChildTarget::sendExecutionComplete(int Result) {
220 // Write the message type.
221 uint32_t MsgType = (uint32_t)LLI_ExecutionResult;
222 int rc = WriteBytes(&MsgType, 4);
223 (void)rc;
224 assert(rc == 4);
225
226
227 // Write the data size.
228 uint32_t DataSize = 4;
229 rc = WriteBytes(&DataSize, 4);
230 assert(rc == 4);
231
232 // Write the result.
233 rc = WriteBytes(&Result, 4);
234 assert(rc == 4);
235 }
236
237 #ifdef LLVM_ON_UNIX
238 #include "../Unix/RPCChannel.inc"
239 #endif
240
241 #ifdef LLVM_ON_WIN32
242 #include "../Windows/RPCChannel.inc"
243 #endif
+0
-49
tools/lli/RPCChannel.h less more
None //===---------- RPCChannel.h - LLVM out-of-process JIT execution ----------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Definition of the RemoteTargetExternal class which executes JITed code in a
10 // separate process from where it was built.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_TOOLS_LLI_RPCCHANNEL_H
15 #define LLVM_TOOLS_LLI_RPCCHANNEL_H
16
17 #include
18 #include
19
20 namespace llvm {
21
22 class RPCChannel {
23 public:
24 std::string ChildName;
25
26 RPCChannel() {}
27 ~RPCChannel();
28
29 /// Start the remote process.
30 ///
31 /// @returns True on success. On failure, ErrorMsg is updated with
32 /// descriptive text of the encountered error.
33 bool createServer();
34
35 bool createClient();
36
37 // This will get filled in as a point to an OS-specific structure.
38 void *ConnectionData;
39
40 bool WriteBytes(const void *Data, size_t Size);
41 bool ReadBytes(void *Data, size_t Size);
42
43 void Wait();
44 };
45
46 } // end namespace llvm
47
48 #endif
0 //===-- RemoteJITUtils.h - Utilities for remote-JITing with LLI -*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Utilities for remote-JITing with LLI.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_TOOLS_LLI_REMOTEJITUTILS_H
14 #define LLVM_TOOLS_LLI_REMOTEJITUTILS_H
15
16 #include "llvm/ExecutionEngine/Orc/RPCChannel.h"
17 #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
18
19 #if !defined(_MSC_VER) && !defined(__MINGW32__)
20 #include
21 #else
22 #include
23 #endif
24
25 /// RPC channel that reads from and writes from file descriptors.
26 class FDRPCChannel : public llvm::orc::remote::RPCChannel {
27 public:
28 FDRPCChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {}
29
30 std::error_code readBytes(char *Dst, unsigned Size) override {
31 assert(Dst && "Attempt to read into null.");
32 ssize_t ReadResult = ::read(InFD, Dst, Size);
33 if (ReadResult != Size)
34 return std::error_code(errno, std::generic_category());
35 return std::error_code();
36 }
37
38 std::error_code appendBytes(const char *Src, unsigned Size) override {
39 assert(Src && "Attempt to append from null.");
40 ssize_t WriteResult = ::write(OutFD, Src, Size);
41 if (WriteResult != Size)
42 std::error_code(errno, std::generic_category());
43 return std::error_code();
44 }
45
46 std::error_code send() override { return std::error_code(); }
47
48 private:
49 int InFD, OutFD;
50 };
51
52 // launch the remote process (see lli.cpp) and return a channel to it.
53 std::unique_ptr launchRemote();
54
55 namespace llvm {
56
57 // ForwardingMM - Adapter to connect MCJIT to Orc's Remote memory manager.
58 class ForwardingMemoryManager : public llvm::RTDyldMemoryManager {
59 public:
60 void setMemMgr(std::unique_ptr MemMgr) {
61 this->MemMgr = std::move(MemMgr);
62 }
63
64 void setResolver(std::unique_ptr Resolver) {
65 this->Resolver = std::move(Resolver);
66 }
67
68 uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
69 unsigned SectionID,
70 StringRef SectionName) override {
71 return MemMgr->allocateCodeSection(Size, Alignment, SectionID, SectionName);
72 }
73
74 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
75 unsigned SectionID, StringRef SectionName,
76 bool IsReadOnly) override {
77 return MemMgr->allocateDataSection(Size, Alignment, SectionID, SectionName,
78 IsReadOnly);
79 }
80
81 void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
82 uintptr_t RODataSize, uint32_t RODataAlign,
83 uintptr_t RWDataSize,
84 uint32_t RWDataAlign) override {
85 MemMgr->reserveAllocationSpace(CodeSize, CodeAlign, RODataSize, RODataAlign,
86 RWDataSize, RWDataAlign);
87 }
88
89 bool needsToReserveAllocationSpace() override {
90 return MemMgr->needsToReserveAllocationSpace();
91 }
92
93 void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
94 size_t Size) override {
95 MemMgr->registerEHFrames(Addr, LoadAddr, Size);
96 }
97
98 void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr,
99 size_t Size) override {
100 MemMgr->deregisterEHFrames(Addr, LoadAddr, Size);
101 }
102
103 bool finalizeMemory(std::string *ErrMsg = nullptr) override {
104 return MemMgr->finalizeMemory(ErrMsg);
105 }
106
107 void notifyObjectLoaded(RuntimeDyld &RTDyld,
108 const object::ObjectFile &Obj) override {
109 MemMgr->notifyObjectLoaded(RTDyld, Obj);
110 }
111
112 // Don't hide the sibling notifyObjectLoaded from RTDyldMemoryManager.
113 using RTDyldMemoryManager::notifyObjectLoaded;
114
115 RuntimeDyld::SymbolInfo findSymbol(const std::string &Name) override {
116 return Resolver->findSymbol(Name);
117 }
118
119 RuntimeDyld::SymbolInfo
120 findSymbolInLogicalDylib(const std::string &Name) override {
121 return Resolver->findSymbolInLogicalDylib(Name);
122 }
123
124 private:
125 std::unique_ptr MemMgr;
126 std::unique_ptr Resolver;
127 };
128 }
129
130 #endif
+0
-174
tools/lli/RemoteMemoryManager.cpp less more
None //===---- RemoteMemoryManager.cpp - Recording memory manager --------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This memory manager allocates local storage and keeps a record of each
10 // allocation. Iterators are provided for all data and code allocations.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "RemoteMemoryManager.h"
15 #include "llvm/ExecutionEngine/ExecutionEngine.h"
16 #include "llvm/Support/Debug.h"
17 #include "llvm/Support/Format.h"
18 #include "llvm/Support/raw_ostream.h"
19
20 using namespace llvm;
21
22 #define DEBUG_TYPE "lli"
23
24 RemoteMemoryManager::~RemoteMemoryManager() {
25 for (SmallVector::iterator
26 I = AllocatedSections.begin(), E = AllocatedSections.end();
27 I != E; ++I)
28 sys::Memory::releaseMappedMemory(I->MB);
29 }
30
31 uint8_t *RemoteMemoryManager::
32 allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID,
33 StringRef SectionName) {
34 // The recording memory manager is just a local copy of the remote target.
35 // The alignment requirement is just stored here for later use. Regular
36 // heap storage is sufficient here, but we're using mapped memory to work
37 // around a bug in MCJIT.
38 sys::MemoryBlock Block = allocateSection(Size);
39 // AllocatedSections will own this memory.
40 AllocatedSections.push_back( Allocation(Block, Alignment, true) );
41 // UnmappedSections has the same information but does not own the memory.
42 UnmappedSections.push_back( Allocation(Block, Alignment, true) );
43 return (uint8_t*)Block.base();
44 }
45
46 uint8_t *RemoteMemoryManager::
47 allocateDataSection(uintptr_t Size, unsigned Alignment,
48 unsigned SectionID, StringRef SectionName,
49 bool IsReadOnly) {
50 // The recording memory manager is just a local copy of the remote target.
51 // The alignment requirement is just stored here for later use. Regular
52 // heap storage is sufficient here, but we're using mapped memory to work
53 // around a bug in MCJIT.
54 sys::MemoryBlock Block = allocateSection(Size);
55 // AllocatedSections will own this memory.
56 AllocatedSections.push_back( Allocation(Block, Alignment, false) );
57 // UnmappedSections has the same information but does not own the memory.
58 UnmappedSections.push_back( Allocation(Block, Alignment, false) );
59 return (uint8_t*)Block.base();
60 }
61
62 sys::MemoryBlock RemoteMemoryManager::allocateSection(uintptr_t Size) {
63 std::error_code ec;
64 sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(Size,
65 &Near,
66 sys::Memory::MF_READ |
67 sys::Memory::MF_WRITE,
68 ec);
69 assert(!ec && MB.base());
70
71 // FIXME: This is part of a work around to keep sections near one another
72 // when MCJIT performs relocations after code emission but before
73 // the generated code is moved to the remote target.
74 // Save this address as the basis for our next request
75 Near = MB;
76 return MB;
77 }
78
79 void RemoteMemoryManager::notifyObjectLoaded(ExecutionEngine *EE,
80 const object::ObjectFile &Obj) {
81 // The client should have called setRemoteTarget() before triggering any
82 // code generation.
83 assert(Target);
84 if (!Target)
85 return;
86
87 // FIXME: Make this function thread safe.
88
89 // Lay out our sections in order, with all the code sections first, then
90 // all the data sections.
91 uint64_t CurOffset = 0;
92 unsigned MaxAlign = Target->getPageAlignment();
93 SmallVector, 16> Offsets;
94 unsigned NumSections = UnmappedSections.size();
95 // We're going to go through the list twice to separate code and data, but
96 // it's a very small list, so that's OK.
97 for (size_t i = 0, e = NumSections; i != e; ++i) {
98 Allocation &Section = UnmappedSections[i];
99 if (Section.IsCode) {
100 unsigned Size = Section.MB.size();
101 unsigned Align = Section.Alignment;
102 DEBUG(dbgs() << "code region: size " << Size
103 << ", alignment " << Align << "\n");
104 // Align the current offset up to whatever is needed for the next
105 // section.
106 CurOffset = (CurOffset + Align - 1) / Align * Align;
107 // Save off the address of the new section and allocate its space.
108 Offsets.push_back(std::pair(Section, CurOffset));
109 CurOffset += Size;
110 }
111 }
112 // Adjust to keep code and data aligned on separate pages.
113 CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign;
114 for (size_t i = 0, e = NumSections; i != e; ++i) {
115 Allocation &Section = UnmappedSections[i];
116 if (!Section.IsCode) {
117 unsigned Size = Section.MB.size();
118 unsigned Align = Section.Alignment;
119 DEBUG(dbgs() << "data region: size " << Size
120 << ", alignment " << Align << "\n");
121 // Align the current offset up to whatever is needed for the next
122 // section.
123 CurOffset = (CurOffset + Align - 1) / Align * Align;
124 // Save off the address of the new section and allocate its space.
125 Offsets.push_back(std::pair(Section, CurOffset));
126 CurOffset += Size;
127 }
128 }
129
130 // Allocate space in the remote target.
131 uint64_t RemoteAddr;
132 if (!Target->allocateSpace(CurOffset, MaxAlign, RemoteAddr))
133 report_fatal_error(Target->getErrorMsg());
134
135 // Map the section addresses so relocations will get updated in the local
136 // copies of the sections.
137 for (unsigned i = 0, e = Offsets.size(); i != e; ++i) {
138 uint64_t Addr = RemoteAddr + Offsets[i].second;
139 EE->mapSectionAddress(const_cast(Offsets[i].first.MB.base()), Addr);
140
141 DEBUG(dbgs() << " Mapping local: " << Offsets[i].first.MB.base()
142 << " to remote: 0x" << format("%llx", Addr) << "\n");
143
144 MappedSections[Addr] = Offsets[i].first;
145 }
146
147 UnmappedSections.clear();
148 }
149
150 bool RemoteMemoryManager::finalizeMemory(std::string *ErrMsg) {
151 // FIXME: Make this function thread safe.
152 for (DenseMap::iterator
153 I = MappedSections.begin(), E = MappedSections.end();
154 I != E; ++I) {
155 uint64_t RemoteAddr = I->first;
156 const Allocation &Section = I->second;
157 if (Section.IsCode) {
158 if (!Target->loadCode(RemoteAddr, Section.MB.base(), Section.MB.size()))
159 report_fatal_error(Target->getErrorMsg());
160 DEBUG(dbgs() << " loading code: " << Section.MB.base()
161 << " to remote: 0x" << format("%llx", RemoteAddr) << "\n");
162 } else {
163 if (!Target->loadData(RemoteAddr, Section.MB.base(), Section.MB.size()))
164 report_fatal_error(Target->getErrorMsg());
165 DEBUG(dbgs() << " loading data: " << Section.MB.base()
166 << " to remote: 0x" << format("%llx", RemoteAddr) << "\n");
167 }
168 }
169
170 MappedSections.clear();
171
172 return false;
173 }
+0
-101
tools/lli/RemoteMemoryManager.h less more
None //===- RemoteMemoryManager.h - LLI MCJIT recording memory manager ------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This memory manager allocates local storage and keeps a record of each
10 // allocation. Iterators are provided for all data and code allocations.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_TOOLS_LLI_REMOTEMEMORYMANAGER_H
15 #define LLVM_TOOLS_LLI_REMOTEMEMORYMANAGER_H
16
17 #include "RemoteTarget.h"
18 #include "llvm/ADT/DenseMap.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
21 #include "llvm/Support/ErrorHandling.h"
22 #include "llvm/Support/Memory.h"
23 #include
24
25 namespace llvm {
26
27 class RemoteMemoryManager : public RTDyldMemoryManager {
28 public:
29 // Notice that this structure takes ownership of the memory allocated.
30 struct Allocation {
31 Allocation() {}
32 Allocation(sys::MemoryBlock mb, unsigned a, bool code)
33 : MB(mb), Alignment(a), IsCode(code) {}
34
35 sys::MemoryBlock MB;
36 unsigned Alignment;
37 bool IsCode;
38 };
39
40 private:
41 // This vector contains Allocation objects for all sections which we have
42 // allocated. This vector effectively owns the memory associated with the
43 // allocations.
44 SmallVector AllocatedSections;
45
46 // This vector contains pointers to Allocation objects for any sections we
47 // have allocated locally but have not yet remapped for the remote target.
48 // When we receive notification of a completed module load, we will map
49 // these sections into the remote target.
50 SmallVector UnmappedSections;
51
52 // This map tracks the sections we have remapped for the remote target
53 // but have not yet copied to the target.
54 DenseMap MappedSections;
55
56 // FIXME: This is part of a work around to keep sections near one another
57 // when MCJIT performs relocations after code emission but before
58 // the generated code is moved to the remote target.
59 sys::MemoryBlock Near;
60 sys::MemoryBlock allocateSection(uintptr_t Size);
61
62 RemoteTarget *Target;
63
64 public:
65 RemoteMemoryManager() : Target(nullptr) {}
66 ~RemoteMemoryManager() override;
67
68 uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
69 unsigned SectionID,
70 StringRef SectionName) override;
71
72 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
73 unsigned SectionID, StringRef SectionName,
74 bool IsReadOnly) override;
75
76 // For now, remote symbol resolution is not support in lli. The MCJIT
77 // interface does support this, but clients must provide their own
78 // mechanism for finding remote symbol addresses. MCJIT will resolve
79 // symbols from Modules it contains.
80 uint64_t getSymbolAddress(const std::string &Name) override { return 0; }
81
82 void notifyObjectLoaded(ExecutionEngine *EE,
83 const object::ObjectFile &Obj) override;
84
85 bool finalizeMemory(std::string *ErrMsg) override;
86
87 // For now, remote EH frame registration isn't supported. Remote symbol
88 // resolution is a prerequisite to supporting remote EH frame registration.
89 void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
90 size_t Size) override {}
91 void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr,
92 size_t Size) override {}
93
94 // This is a non-interface function used by lli
95 void setRemoteTarget(RemoteTarget *T) { Target = T; }
96 };
97
98 } // end namespace llvm
99
100 #endif
+0
-71
tools/lli/RemoteTarget.cpp less more
None //===- RemoteTarget.cpp - LLVM Remote process JIT execution -----*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Implementation of the RemoteTarget class which executes JITed code in a
10 // separate address range from where it was built.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "RemoteTarget.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/Support/DataTypes.h"
17 #include "llvm/Support/Memory.h"
18 #include
19 #include
20
21 using namespace llvm;
22
23 ////////////////////////////////////////////////////////////////////////////////
24 // Simulated remote execution
25 //
26 // This implementation will simply move generated code and data to a new memory
27 // location in the current executable and let it run from there.
28 ////////////////////////////////////////////////////////////////////////////////
29
30 bool RemoteTarget::allocateSpace(size_t Size, unsigned Alignment,
31 uint64_t &Address) {
32 sys::MemoryBlock *Prev = Allocations.size() ? &Allocations.back() : nullptr;
33 sys::MemoryBlock Mem = sys::Memory::AllocateRWX(Size, Prev, &ErrorMsg);
34 if (Mem.base() == nullptr)
35 return false;
36 if ((uintptr_t)Mem.base() % Alignment) {
37 ErrorMsg = "unable to allocate sufficiently aligned memory";
38 return false;
39 }
40 Address = reinterpret_cast(Mem.base());
41 Allocations.push_back(Mem);
42 return true;
43 }
44
45 bool RemoteTarget::loadData(uint64_t Address, const void *Data, size_t Size) {
46 memcpy ((void*)Address, Data, Size);
47 return true;
48 }
49
50 bool RemoteTarget::loadCode(uint64_t Address, const void *Data, size_t Size) {
51 memcpy ((void*)Address, Data, Size);
52 sys::MemoryBlock Mem((void*)Address, Size);
53 sys::Memory::setExecutable(Mem, &ErrorMsg);
54 return true;
55 }
56
57 bool RemoteTarget::executeCode(uint64_t Address, int &RetVal) {
58 int (*fn)() = (int(*)())Address;
59 RetVal = fn();
60 return true;
61 }
62
63 bool RemoteTarget::create() {
64 return true;
65 }
66
67 void RemoteTarget::stop() {
68 for (unsigned i = 0, e = Allocations.size(); i != e; ++i)
69 sys::Memory::ReleaseRWX(Allocations[i]);
70 }
+0
-122
tools/lli/RemoteTarget.h less more
None //===- RemoteTarget.h - LLVM Remote process JIT execution ----------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Definition of the RemoteTarget class which executes JITed code in a
10 // separate address range from where it was built.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_TOOLS_LLI_REMOTETARGET_H
15 #define LLVM_TOOLS_LLI_REMOTETARGET_H
16
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Support/DataTypes.h"
20 #include "llvm/Support/Memory.h"
21 #include
22 #include
23
24 namespace llvm {
25
26 class RemoteTarget {
27 bool IsRunning;
28
29 typedef SmallVector AllocMapType;
30 AllocMapType Allocations;
31
32 protected:
33 std::string ErrorMsg;
34
35 public:
36 StringRef getErrorMsg() const { return ErrorMsg; }
37
38 /// Allocate space in the remote target address space.
39 ///
40 /// @param Size Amount of space, in bytes, to allocate.
41 /// @param Alignment Required minimum alignment for allocated space.
42 /// @param[out] Address Remote address of the allocated memory.
43 ///
44 /// @returns True on success. On failure, ErrorMsg is updated with
45 /// descriptive text of the encountered error.
46 virtual bool allocateSpace(size_t Size,
47 unsigned Alignment,
48 uint64_t &Address);
49
50 bool isAllocatedMemory(uint64_t Address, uint32_t Size) {
51 uint64_t AddressEnd = Address + Size;
52 for (AllocMapType::const_iterator I = Allocations.begin(),
53 E = Allocations.end();
54 I != E; ++I) {
55 if (Address >= (uint64_t)I->base() &&
56 AddressEnd <= (uint64_t)I->base() + I->size())
57 return true;
58 }
59 return false;
60 }
61
62 /// Load data into the target address space.
63 ///
64 /// @param Address Destination address in the target process.
65 /// @param Data Source address in the host process.
66 /// @param Size Number of bytes to copy.
67 ///
68 /// @returns True on success. On failure, ErrorMsg is updated with
69 /// descriptive text of the encountered error.
70 virtual bool loadData(uint64_t Address,
71 const void *Data,
72 size_t Size);
73
74 /// Load code into the target address space and prepare it for execution.
75 ///
76 /// @param Address Destination address in the target process.
77 /// @param Data Source address in the host process.
78 /// @param Size Number of bytes to copy.
79 ///
80 /// @returns True on success. On failure, ErrorMsg is updated with
81 /// descriptive text of the encountered error.
82 virtual bool loadCode(uint64_t Address,
83 const void *Data,
84 size_t Size);
85
86 /// Execute code in the target process. The called function is required
87 /// to be of signature int "(*)(void)".
88 ///
89 /// @param Address Address of the loaded function in the target
90 /// process.
91 /// @param[out] RetVal The integer return value of the called function.
92 ///
93 /// @returns True on success. On failure, ErrorMsg is updated with
94 /// descriptive text of the encountered error.
95 virtual bool executeCode(uint64_t Address,
96 int &RetVal);
97
98 /// Minimum alignment for memory permissions. Used to separate code and
99 /// data regions to make sure data doesn't get marked as code or vice
100 /// versa.
101 ///
102 /// @returns Page alignment return value. Default of 4k.
103 virtual unsigned getPageAlignment() { return 4096; }
104
105 /// Start the remote process.
106 virtual bool create();
107
108 /// Terminate the remote process.
109 virtual void stop();
110
111 RemoteTarget() : IsRunning(false), ErrorMsg("") {}
112 virtual ~RemoteTarget() { if (IsRunning) stop(); }
113 private:
114 // Main processing function for the remote target process. Command messages
115 // are received on file descriptor CmdFD and responses come back on OutFD.
116 static void doRemoteTargeting(int CmdFD, int OutFD);
117 };
118
119 } // end namespace llvm
120
121 #endif
+0
-327
tools/lli/RemoteTargetExternal.cpp less more
None //===---- RemoteTargetExternal.cpp - LLVM out-of-process JIT execution ----===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Implementation of the RemoteTargetExternal class which executes JITed code
10 // in a separate process from where it was built.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "llvm/Config/config.h"
15 #include "RemoteTarget.h"
16 #include "RemoteTargetExternal.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/Support/DataTypes.h"
19 #include "llvm/Support/Debug.h"
20 #include "llvm/Support/Format.h"
21 #include "llvm/Support/Memory.h"
22 #include "llvm/Support/Program.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include
25
26 using namespace llvm;
27
28 #define DEBUG_TYPE "lli"
29
30 bool RemoteTargetExternal::allocateSpace(size_t Size, unsigned Alignment,
31 uint64_t &Address) {
32 DEBUG(dbgs() << "Message [allocate space] size: " << Size <<
33 ", align: " << Alignment << "\n");
34 if (!SendAllocateSpace(Alignment, Size)) {
35 ErrorMsg += ", (RemoteTargetExternal::allocateSpace)";
36 return false;
37 }
38 if (!Receive(LLI_AllocationResult, Address)) {
39 ErrorMsg += ", (RemoteTargetExternal::allocateSpace)";
40 return false;
41 }
42 if (Address == 0) {
43 ErrorMsg += "failed allocation, (RemoteTargetExternal::allocateSpace)";
44 return false;
45 }
46 DEBUG(dbgs() << "Message [allocate space] addr: 0x" <<
47 format("%llx", Address) << "\n");
48 return true;
49 }
50
51 bool RemoteTargetExternal::loadData(uint64_t Address, const void *Data, size_t Size) {
52 DEBUG(dbgs() << "Message [load data] addr: 0x" << format("%llx", Address) <<
53 ", size: " << Size << "\n");
54 if (!SendLoadSection(Address, Data, (uint32_t)Size, false)) {
55 ErrorMsg += ", (RemoteTargetExternal::loadData)";
56 return false;
57 }
58 int Status = LLI_Status_Success;
59 if (!Receive(LLI_LoadResult, Status)) {
60 ErrorMsg += ", (RemoteTargetExternal::loadData)";
61 return false;
62 }
63 if (Status == LLI_Status_IncompleteMsg) {
64 ErrorMsg += "incomplete load data, (RemoteTargetExternal::loadData)";
65 return false;
66 }
67 if (Status == LLI_Status_NotAllocated) {
68 ErrorMsg += "data memory not allocated, (RemoteTargetExternal::loadData)";
69 return false;
70 }
71 DEBUG(dbgs() << "Message [load data] complete\n");
72 return true;
73 }
74
75 bool RemoteTargetExternal::loadCode(uint64_t Address, const void *Data, size_t Size) {
76 DEBUG(dbgs() << "Message [load code] addr: 0x" << format("%llx", Address) <<
77 ", size: " << Size << "\n");
78 if (!SendLoadSection(Address, Data, (uint32_t)Size, true)) {
79 ErrorMsg += ", (RemoteTargetExternal::loadCode)";
80 return false;
81 }
82 int Status = LLI_Status_Success;
83 if (!Receive(LLI_LoadResult, Status)) {
84 ErrorMsg += ", (RemoteTargetExternal::loadCode)";
85 return false;
86 }
87 if (Status == LLI_Status_IncompleteMsg) {
88 ErrorMsg += "incomplete load data, (RemoteTargetExternal::loadData)";
89 return false;
90 }
91 if (Status == LLI_Status_NotAllocated) {
92 ErrorMsg += "data memory not allocated, (RemoteTargetExternal::loadData)";
93 return false;
94 }
95 DEBUG(dbgs() << "Message [load code] complete\n");
96 return true;
97 }
98
99 bool RemoteTargetExternal::executeCode(uint64_t Address, int32_t &RetVal) {
100 DEBUG(dbgs() << "Message [exectue code] addr: " << Address << "\n");
101 if (!SendExecute(Address)) {
102 ErrorMsg += ", (RemoteTargetExternal::executeCode)";
103 return false;
104 }
105 if (!Receive(LLI_ExecutionResult, RetVal)) {
106 ErrorMsg += ", (RemoteTargetExternal::executeCode)";
107 return false;
108 }
109 DEBUG(dbgs() << "Message [exectue code] return: " << RetVal << "\n");
110 return true;
111 }
112
113 void RemoteTargetExternal::stop() {
114 SendTerminate();
115 RPC.Wait();
116 }
117
118 bool RemoteTargetExternal::SendAllocateSpace(uint32_t Alignment, uint32_t Size) {
119 if (!SendHeader(LLI_AllocateSpace)) {
120 ErrorMsg += ", (RemoteTargetExternal::SendAllocateSpace)";
121 return false;
122 }
123
124 AppendWrite((const void *)&Alignment, 4);
125 AppendWrite((const void *)&Size, 4);
126
127 if (!SendPayload()) {
128 ErrorMsg += ", (RemoteTargetExternal::SendAllocateSpace)";
129 return false;
130 }
131 return true;
132 }
133
134 bool RemoteTargetExternal::SendLoadSection(uint64_t Addr,
135 const void *Data,
136 uint32_t Size,
137 bool IsCode) {
138 LLIMessageType MsgType = IsCode ? LLI_LoadCodeSection : LLI_LoadDataSection;
139 if (!SendHeader(MsgType)) {
140 ErrorMsg += ", (RemoteTargetExternal::SendLoadSection)";
141 return false;
142 }
143
144 AppendWrite((const void *)&Addr, 8);
145 AppendWrite(Data, Size);
146
147 if (!SendPayload()) {
148 ErrorMsg += ", (RemoteTargetExternal::SendLoadSection)";
149 return false;
150 }
151 return true;
152 }
153
154 bool RemoteTargetExternal::SendExecute(uint64_t Addr) {
155 if (!SendHeader(LLI_Execute)) {
156 ErrorMsg += ", (RemoteTargetExternal::SendExecute)";
157 return false;
158 }
159
160 AppendWrite((const void *)&Addr, 8);
161
162 if (!SendPayload()) {
163 ErrorMsg += ", (RemoteTargetExternal::SendExecute)";
164 return false;
165 }
166 return true;
167 }
168
169 bool RemoteTargetExternal::SendTerminate() {
170 return SendHeader(LLI_Terminate);
171 // No data or data size is sent with Terminate
172 }
173
174 bool RemoteTargetExternal::Receive(LLIMessageType Msg) {
175 if (!ReceiveHeader(Msg))
176 return false;
177 int Unused;
178 AppendRead(&Unused, 0);
179 if (!ReceivePayload())
180 return false;
181 ReceiveData.clear();
182 Sizes.clear();
183 return true;
184 }
185
186 bool RemoteTargetExternal::Receive(LLIMessageType Msg, int32_t &Data) {
187 if (!ReceiveHeader(Msg))
188 return false;
189 AppendRead(&Data, 4);
190 if (!ReceivePayload())
191 return false;
192 ReceiveData.clear();
193 Sizes.clear();
194 return true;
195 }
196
197 bool RemoteTargetExternal::Receive(LLIMessageType Msg, uint64_t &Data) {
198 if (!ReceiveHeader(Msg))
199 return false;
200 AppendRead(&Data, 8);
201 if (!ReceivePayload())
202 return false;
203 ReceiveData.clear();
204 Sizes.clear();
205 return true;
206 }
207
208 bool RemoteTargetExternal::ReceiveHeader(LLIMessageType ExpectedMsgType) {
209 assert(ReceiveData.empty() && Sizes.empty() &&
210 "Payload vector not empty to receive header");
211
212 // Message header, with type to follow
213 uint32_t MsgType;
214 if (!ReadBytes(&MsgType, 4)) {
215 ErrorMsg += ", (RemoteTargetExternal::ReceiveHeader)";
216 return false;
217 }
218 if (MsgType != (uint32_t)ExpectedMsgType) {
219 ErrorMsg = "received unexpected message type";
220 ErrorMsg += ". Expecting: ";
221 ErrorMsg += ExpectedMsgType;
222 ErrorMsg += ", Got: ";
223 ErrorMsg += MsgType;
224 return false;
225 }
226 return true;
227 }
228
229 bool RemoteTargetExternal::ReceivePayload() {
230 assert(!ReceiveData.empty() &&
231 "Payload vector empty to receive");
232 assert(ReceiveData.size() == Sizes.size() &&
233 "Unexpected mismatch between data and size");
234
235 uint32_t TotalSize = 0;
236 for (int I=0, E=Sizes.size(); I < E; I++)
237 TotalSize += Sizes[I];
238
239 // Payload size header
240 uint32_t DataSize;
241 if (!ReadBytes(&DataSize, 4)) {
242 ErrorMsg += ", invalid data size";
243 return false;
244 }
245 if (DataSize != TotalSize) {
246 ErrorMsg = "unexpected data size";
247 ErrorMsg += ". Expecting: ";
248 ErrorMsg += TotalSize;
249 ErrorMsg += ", Got: ";
250 ErrorMsg += DataSize;
251 return false;
252 }
253 if (DataSize == 0)
254 return true;
255
256 // Payload itself
257 for (int I=0, E=Sizes.size(); I < E; I++) {
258 if (!ReadBytes(ReceiveData[I], Sizes[I])) {
259 ErrorMsg = "unexpected data while reading message";
260 return false;
261 }
262 }
263
264 return true;
265 }
266
267 bool RemoteTargetExternal::SendHeader(LLIMessageType MsgType) {
268 assert(SendData.empty() && Sizes.empty() &&
269 "Payload vector not empty to send header");
270
271 // Message header, with type to follow
272 if (!WriteBytes(&MsgType, 4)) {
273 ErrorMsg += ", (RemoteTargetExternal::SendHeader)";
274 return false;
275 }
276 return true;
277 }
278
279 bool RemoteTargetExternal::SendPayload() {
280 assert(!SendData.empty() && !Sizes.empty() &&
281 "Payload vector empty to send");
282 assert(SendData.size() == Sizes.size() &&
283 "Unexpected mismatch between data and size");
284
285 uint32_t TotalSize = 0;
286 for (int I=0, E=Sizes.size(); I < E; I++)
287 TotalSize += Sizes[I];
288
289 // Payload size header
290 if (!WriteBytes(&TotalSize, 4)) {
291 ErrorMsg += ", invalid data size";
292 return false;
293 }
294 if (TotalSize == 0)
295 return true;
296
297 // Payload itself
298 for (int I=0, E=Sizes.size(); I < E; I++) {
299 if (!WriteBytes(SendData[I], Sizes[I])) {
300 ErrorMsg = "unexpected data while writing message";
301 return false;
302 }
303 }
304
305 SendData.clear();
306 Sizes.clear();
307 return true;
308 }
309
310 void RemoteTargetExternal::AppendWrite(const void *Data, uint32_t Size) {
311 SendData.push_back(Data);
312 Sizes.push_back(Size);
313 }
314
315 void RemoteTargetExternal::AppendRead(void *Data, uint32_t Size) {
316 ReceiveData.push_back(Data);
317 Sizes.push_back(Size);
318 }
319
320 #ifdef LLVM_ON_UNIX
321 #include "Unix/RPCChannel.inc"
322 #endif
323
324 #ifdef LLVM_ON_WIN32
325 #include "Windows/RPCChannel.inc"
326 #endif
+0
-143
tools/lli/RemoteTargetExternal.h less more
None //===----- RemoteTargetExternal.h - LLVM out-of-process JIT execution -----===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Definition of the RemoteTargetExternal class which executes JITed code in a
10 // separate process from where it was built.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_TOOLS_LLI_REMOTETARGETEXTERNAL_H
15 #define LLVM_TOOLS_LLI_REMOTETARGETEXTERNAL_H
16
17 #include "RPCChannel.h"
18 #include "RemoteTarget.h"
19 #include "RemoteTargetMessage.h"
20 #include "llvm/ADT/SmallVector.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/Config/config.h"
23 #include "llvm/Support/DataTypes.h"
24 #include "llvm/Support/Memory.h"
25 #include
26 #include
27
28 namespace llvm {
29
30 class RemoteTargetExternal : public RemoteTarget {
31 RPCChannel RPC;
32
33 bool WriteBytes(const void *Data, size_t Size) {
34 return RPC.WriteBytes(Data, Size);
35 }
36
37 bool ReadBytes(void *Data, size_t Size) { return RPC.ReadBytes(Data, Size); }
38
39 public:
40 /// Allocate space in the remote target address space.
41 ///
42 /// @param Size Amount of space, in bytes, to allocate.
43 /// @param Alignment Required minimum alignment for allocated space.
44 /// @param[out] Address Remote address of the allocated memory.
45 ///
46 /// @returns True on success. On failure, ErrorMsg is updated with
47 /// descriptive text of the encountered error.
48 bool allocateSpace(size_t Size, unsigned Alignment,
49 uint64_t &Address) override;
50
51 /// Load data into the target address space.
52 ///
53 /// @param Address Destination address in the target process.
54 /// @param Data Source address in the host process.
55 /// @param Size Number of bytes to copy.
56 ///
57 /// @returns True on success. On failure, ErrorMsg is updated with
58 /// descriptive text of the encountered error.
59 bool loadData(uint64_t Address, const void *Data, size_t Size) override;
60
61 /// Load code into the target address space and prepare it for execution.
62 ///
63 /// @param Address Destination address in the target process.
64 /// @param Data Source address in the host process.
65 /// @param Size Number of bytes to copy.
66 ///
67 /// @returns True on success. On failure, ErrorMsg is updated with
68 /// descriptive text of the encountered error.
69 bool loadCode(uint64_t Address, const void *Data, size_t Size) override;
70
71 /// Execute code in the target process. The called function is required
72 /// to be of signature int "(*)(void)".
73 ///
74 /// @param Address Address of the loaded function in the target
75 /// process.
76 /// @param[out] RetVal The integer return value of the called function.
77 ///
78 /// @returns True on success. On failure, ErrorMsg is updated with
79 /// descriptive text of the encountered error.
80 bool executeCode(uint64_t Address, int &RetVal) override;
81
82 /// Minimum alignment for memory permissions. Used to separate code and
83 /// data regions to make sure data doesn't get marked as code or vice
84 /// versa.
85 ///
86 /// @returns Page alignment return value. Default of 4k.
87 unsigned getPageAlignment() override { return 4096; }
88
89 bool create() override {
90 RPC.ChildName = ChildName;
91 if (!RPC.createServer())
92 return true;
93
94 // We must get Ack from the client (blocking read)
95 if (!Receive(LLI_ChildActive)) {
96 ErrorMsg += ", (RPCChannel::create) - Stopping process!";
97 stop();
98 return false;
99 }
100
101 return true;
102 }
103
104 /// Terminate the remote process.
105 void stop() override;
106
107 RemoteTargetExternal(std::string &Name) : RemoteTarget(), ChildName(Name) {}
108 ~RemoteTargetExternal() override {}
109
110 private:
111 std::string ChildName;
112
113 bool SendAllocateSpace(uint32_t Alignment, uint32_t Size);
114 bool SendLoadSection(uint64_t Addr,
115 const void *Data,
116 uint32_t Size,
117 bool IsCode);
118 bool SendExecute(uint64_t Addr);
119 bool SendTerminate();
120
121 // High-level wrappers for receiving data
122 bool Receive(LLIMessageType Msg);
123 bool Receive(LLIMessageType Msg, int32_t &Data);
124 bool Receive(LLIMessageType Msg, uint64_t &Data);
125
126 // Lower level target-independent read/write to deal with errors
127 bool ReceiveHeader(LLIMessageType Msg);
128 bool ReceivePayload();
129 bool SendHeader(LLIMessageType Msg);
130 bool SendPayload();
131
132 // Functions to append/retrieve data from the payload
133 SmallVector SendData;
134 SmallVector ReceiveData; // Future proof
135 SmallVector Sizes;
136 void AppendWrite(const void *Data, uint32_t Size);
137 void AppendRead(void *Data, uint32_t Size);
138 };
139
140 } // end namespace llvm
141
142 #endif
+0
-85
tools/lli/RemoteTargetMessage.h less more
None //===---- RemoteTargetMessage.h - LLI out-of-process message protocol -----===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Definition of the LLIMessageType enum which is used for communication with a
10 // child process for remote execution.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_TOOLS_LLI_REMOTETARGETMESSAGE_H
15 #define LLVM_TOOLS_LLI_REMOTETARGETMESSAGE_H
16
17 namespace llvm {
18
19 // LLI messages from parent-to-child or vice versa follow an exceedingly simple
20 // protocol where the first four bytes represent the message type, the next
21 // four bytes represent the size of data for the command and following bytes
22 // represent the actual data.
23 //
24 // The protocol is not intended to be robust, secure or fault-tolerant. It is
25 // only here for testing purposes and is therefore intended to be the simplest
26 // implementation that will work. It is assumed that the parent and child
27 // share characteristics like endianness.
28 //
29 // Quick description of the protocol:
30 //
31 // { Header + Payload Size + Payload }
32 //
33 // The protocol message consist of a header, the payload size (which can be
34 // zero), and the payload itself. The payload can contain any number of items,
35 // and the size has to be the sum of them all. Each end is responsible for
36 // reading/writing the correct number of items with the correct sizes.
37 //
38 // The current four known exchanges are:
39 //
40 // * Allocate Space:
41 // Parent: { LLI_AllocateSpace, 8, Alignment, Size }
42 // Child: { LLI_AllocationResult, 8, Address }
43 //
44 // * Load Data:
45 // Parent: { LLI_LoadDataSection, 8+Size, Address, Data }
46 // Child: { LLI_LoadComplete, 4, StatusCode }
47 //
48 // * Load Code:
49 // Parent: { LLI_LoadCodeSection, 8+Size, Address, Code }
50 // Child: { LLI_LoadComplete, 4, StatusCode }
51 //
52 // * Execute Code:
53 // Parent: { LLI_Execute, 8, Address }
54 // Child: { LLI_ExecutionResult, 4, Result }
55 //
56 // It is the responsibility of either side to check for correct headers,
57 // sizes and payloads, since any inconsistency would misalign the pipe, and
58 // result in data corruption.
59
60 enum LLIMessageType {
61 LLI_Error = -1,
62 LLI_ChildActive = 0, // Data = not used
63 LLI_AllocateSpace, // Data = struct { uint32_t Align, uint_32t Size }
64 LLI_AllocationResult, // Data = uint64_t Address (child memory space)
65
66 LLI_LoadCodeSection, // Data = uint64_t Address, void * SectionData
67 LLI_LoadDataSection, // Data = uint64_t Address, void * SectionData
68 LLI_LoadResult, // Data = uint32_t LLIMessageStatus
69
70 LLI_Execute, // Data = uint64_t Address
71 LLI_ExecutionResult, // Data = uint32_t Result
72
73 LLI_Terminate // Data = not used
74 };
75
76 enum LLIMessageStatus {
77 LLI_Status_Success = 0, // Operation succeeded
78 LLI_Status_NotAllocated, // Address+Size not allocated in child space
79 LLI_Status_IncompleteMsg // Size received doesn't match request
80 };
81
82 } // end namespace llvm
83
84 #endif
+0
-122
tools/lli/Unix/RPCChannel.inc less more
None //=- RPCChannel.inc - LLVM out-of-process JIT execution for Unix --=//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Implementation of the Unix-specific parts of the RPCChannel class
10 // which executes JITed code in a separate process from where it was built.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "llvm/Support/Errno.h"
15 #include "llvm/Support/raw_ostream.h"
16 #include
17 #include
18 #include
19 #include
20
21 namespace {
22
23 struct ConnectionData_t {
24 int InputPipe;
25 int OutputPipe;
26
27 ConnectionData_t(int in, int out) : InputPipe(in), OutputPipe(out) {}
28 };
29
30 } // namespace
31
32 namespace llvm {
33
34 bool RPCChannel::createServer() {
35 int PipeFD[2][2];
36 pid_t ChildPID;
37
38 // Create two pipes.
39 if (pipe(PipeFD[0]) != 0 || pipe(PipeFD[1]) != 0)
40 perror("Error creating pipe: ");
41
42 ChildPID = fork();
43
44 if (ChildPID == 0) {
45 // In the child...
46
47 // Close the parent ends of the pipes
48 close(PipeFD[0][1]);
49 close(PipeFD[1][0]);
50
51 // Use our pipes as stdin and stdout
52 if (PipeFD[0][0] != STDIN_FILENO) {
53 dup2(PipeFD[0][0], STDIN_FILENO);
54 close(PipeFD[0][0]);
55 }
56 if (PipeFD[1][1] != STDOUT_FILENO) {
57 dup2(PipeFD[1][1], STDOUT_FILENO);
58 close(PipeFD[1][1]);
59 }
60
61 // Execute the child process.
62 char *args[1] = { nullptr };
63 int rc = execv(ChildName.c_str(), args);
64 if (rc != 0)
65 perror("Error executing child process: ");
66 } else {
67 // In the parent...
68
69 // Close the child ends of the pipes
70 close(PipeFD[0][0]);
71 close(PipeFD[1][1]);
72
73 // Store the parent ends of the pipes
74 ConnectionData = (void *)new ConnectionData_t(PipeFD[1][0], PipeFD[0][1]);
75 return true;
76 }
77 return false;
78 }
79
80 bool RPCChannel::createClient() {
81 // Store the parent ends of the pipes
82 ConnectionData = (void *)new ConnectionData_t(STDIN_FILENO, STDOUT_FILENO);
83 return true;
84 }
85
86 void RPCChannel::Wait() { wait(nullptr); }
87
88 static bool CheckError(int rc, size_t Size, const char *Desc) {
89 if (rc < 0) {
90 llvm::errs() << "IO Error: " << Desc << ": " << sys::StrError() << '\n';
91 return false;
92 } else if ((size_t)rc != Size) {
93 std::string ErrorMsg;
94 char Number[10] = { 0 };
95 ErrorMsg += "Expecting ";
96 sprintf(Number, "%d", (uint32_t)Size);
97 ErrorMsg += Number;
98 ErrorMsg += " bytes, Got ";
99 sprintf(Number, "%d", rc);
100 ErrorMsg += Number;
101 llvm::errs() << "RPC Error: " << Desc << ": " << ErrorMsg << '\n';
102 return false;
103 }
104 return true;
105 }
106
107 bool RPCChannel::WriteBytes(const void *Data, size_t Size) {
108 int rc = write(((ConnectionData_t *)ConnectionData)->OutputPipe, Data, Size);
109 return CheckError(rc, Size, "WriteBytes");
110 }
111
112 bool RPCChannel::ReadBytes(void *Data, size_t Size) {
113 int rc = read(((ConnectionData_t *)ConnectionData)->InputPipe, Data, Size);
114 return CheckError(rc, Size, "ReadBytes");
115 }
116
117 RPCChannel::~RPCChannel() {
118 delete static_cast(ConnectionData);
119 }
120
121 } // namespace llvm
+0
-29
tools/lli/Windows/RPCChannel.inc less more
None //=- RPCChannel.inc - LLVM out-of-process JIT execution for Windows --=//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Implementation of the Windows-specific parts of the RPCChannel class
10 // which executes JITed code in a separate process from where it was built.
11 //
12 //===----------------------------------------------------------------------===//
13
14 namespace llvm {
15
16 bool RPCChannel::createServer() { return false; }
17
18 bool RPCChannel::createClient() { return false; }
19
20 bool RPCChannel::WriteBytes(const void *Data, size_t Size) { return false; }
21
22 bool RPCChannel::ReadBytes(void *Data, size_t Size) { return false; }
23
24 void RPCChannel::Wait() {}
25
26 RPCChannel::~RPCChannel() {}
27
28 } // namespace llvm
1212 //
1313 //===----------------------------------------------------------------------===//
1414
15 #include "OrcLazyJIT.h"
16 #include "RemoteJITUtils.h"
1517 #include "llvm/IR/LLVMContext.h"
16 #include "OrcLazyJIT.h"
17 #include "RemoteMemoryManager.h"
18 #include "RemoteTarget.h"
19 #include "RemoteTargetExternal.h"
2018 #include "llvm/ADT/Triple.h"
2119 #include "llvm/Bitcode/ReaderWriter.h"
2220 #include "llvm/CodeGen/LinkAllCodegenComponents.h"
2725 #include "llvm/ExecutionEngine/ObjectCache.h"
2826 #include "llvm/ExecutionEngine/OrcMCJITReplacement.h"
2927 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
28 #include "llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h"
3029 #include "llvm/IR/IRBuilder.h"
3130 #include "llvm/IR/Module.h"
3231 #include "llvm/IR/Type.h"
448447 RTDyldMemoryManager *RTDyldMM = nullptr;
449448 if (!ForceInterpreter) {
450449 if (RemoteMCJIT)
451 RTDyldMM = new RemoteMemoryManager();
450 RTDyldMM = new ForwardingMemoryManager();
452451 else
453452 RTDyldMM = new SectionMemoryManager();
454453
580579 errno = 0;
581580
582581 int Result;
582
583 // Sanity check use of remote-jit: LLI currently only supports use of the
584 // remote JIT on Unix platforms.
585 // FIXME: Remove this pointless fallback mode which causes tests to "pass"
586 // on platforms where they should XFAIL.
587 if (RemoteMCJIT) {
588 #ifndef LLVM_ON_UNIX
589 errs() << "Warning: host does not support external remote targets.\n"
590 << " Defaulting to local execution execution\n";
591 RemoteMCJIT = false;
592 #else
593 if (ChildExecPath.empty()) {
594 errs() << "-remote-mcjit requires -mcjit-remote-process.\n";
595 exit(1);
596 } else if (!sys::fs::can_execute(ChildExecPath)) {
597 errs() << "Unable to find usable child executable: '" << ChildExecPath
598 << "'\n";
599 return -1;
600 }
601 #endif
602 }
583603
584604 if (!RemoteMCJIT) {
585605 // If the program doesn't explicitly call exit, we will need the Exit
628648 // Remote target MCJIT doesn't (yet) support static constructors. No reason
629649 // it couldn't. This is a limitation of the LLI implemantation, not the
630650 // MCJIT itself. FIXME.
631 //
632 RemoteMemoryManager *MM = static_cast(RTDyldMM);
633 // Everything is prepared now, so lay out our program for the target
634 // address space, assign the section addresses to resolve any relocations,
635 // and send it to the target.
636
637 std::unique_ptr Target;
638 if (!ChildExecPath.empty()) { // Remote execution on a child process
639 #ifndef LLVM_ON_UNIX
640 // FIXME: Remove this pointless fallback mode which causes tests to "pass"
641 // on platforms where they should XFAIL.
642 errs() << "Warning: host does not support external remote targets.\n"
643 << " Defaulting to simulated remote execution\n";
644 Target.reset(new RemoteTarget);
645 #else
646 if (!sys::fs::can_execute(ChildExecPath)) {
647 errs() << "Unable to find usable child executable: '" << ChildExecPath
648 << "'\n";
649 return -1;
650 }
651 Target.reset(new RemoteTargetExternal(ChildExecPath));
652 #endif
653 } else {
654 // No child process name provided, use simulated remote execution.
655 Target.reset(new RemoteTarget);
656 }
657
658 // Give the memory manager a pointer to our remote target interface object.
659 MM->setRemoteTarget(Target.get());
660
661 // Create the remote target.
662 if (!Target->create()) {
663 errs() << "ERROR: " << Target->getErrorMsg() << "\n";
664 return EXIT_FAILURE;
665 }
666
667 // Since we're executing in a (at least simulated) remote address space,
668 // we can't use the ExecutionEngine::runFunctionAsMain(). We have to
669 // grab the function address directly here and tell the remote target
670 // to execute the function.
671 //
672 // Our memory manager will map generated code into the remote address
673 // space as it is loaded and copy the bits over during the finalizeMemory
674 // operation.
675 //
651
652 // Lanch the remote process and get a channel to it.
653 std::unique_ptr C = launchRemote();
654 if (!C) {
655 errs() << "Failed to launch remote JIT.\n";
656 exit(1);
657 }
658
659 // Create a remote target client running over the channel.
660 typedef orc::remote::OrcRemoteTargetClient MyRemote;
661 ErrorOr R = MyRemote::Create(*C);
662 if (!R) {
663 errs() << "Could not create remote: " << R.getError().message() << "\n";
664 exit(1);
665 }
666
667 // Create a remote memory manager.
668 std::unique_ptr RemoteMM;
669 if (auto EC = R->createRemoteMemoryManager(RemoteMM)) {
670 errs() << "Could not create remote memory manager: " << EC.message() << "\n";
671 exit(1);
672 }
673
674 // Forward MCJIT's memory manager calls to the remote memory manager.
675 static_cast(RTDyldMM)->setMemMgr(
676 std::move(RemoteMM));
677
678 // Forward MCJIT's symbol resolution calls to the remote.
679 static_cast(RTDyldMM)->setResolver(
680 orc::createLambdaResolver(
681 [&](const std::string &Name) {
682 orc::TargetAddress Addr = 0;
683 if (auto EC = R->getSymbolAddress(Addr, Name)) {
684 errs() << "Failure during symbol lookup: " << EC.message() << "\n";
685 exit(1);
686 }
687 return RuntimeDyld::SymbolInfo(Addr, JITSymbolFlags::Exported);
688 },
689 [](const std::string &Name) { return nullptr; }
690 ));
691
692 // Grab the target address of the JIT'd main function on the remote and call
693 // it.
676694 // FIXME: argv and envp handling.
677 uint64_t Entry = EE->getFunctionAddress(EntryFn->getName().str());
678
695 orc::TargetAddress Entry = EE->getFunctionAddress(EntryFn->getName().str());
696 EE->finalizeObject();
679697 DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at 0x"
680698 << format("%llx", Entry) << "\n");
681
682 if (!Target->executeCode(Entry, Result))
683 errs() << "ERROR: " << Target->getErrorMsg() << "\n";
699 if (auto EC = R->callIntVoid(Result, Entry))
700 errs() << "ERROR: " << EC.message() << "\n";
684701
685702 // Like static constructors, the remote target MCJIT support doesn't handle
686703 // this yet. It could. FIXME.
687704
688 // Stop the remote target
689 Target->stop();
705 // Delete the EE - we need to tear it down *before* we terminate the session
706 // with the remote, otherwise it'll crash when it tries to release resources
707 // on a remote that has already been disconnected.
708 delete EE;
709 EE = nullptr;
710
711 // Signal the remote target that we're done JITing.
712 R->terminateSession();
690713 }
691714
692715 return Result;
693716 }
717
718 std::unique_ptr launchRemote() {
719 #ifndef LLVM_ON_UNIX
720 llvm_unreachable("launchRemote not supported on non-Unix platforms");
721 #else
722 int PipeFD[2][2];
723 pid_t ChildPID;
724
725 // Create two pipes.
726 if (pipe(PipeFD[0]) != 0 || pipe(PipeFD[1]) != 0)
727 perror("Error creating pipe: ");
728
729 ChildPID = fork();
730
731 if (ChildPID == 0) {
732 // In the child...
733
734 // Close the parent ends of the pipes
735 close(PipeFD[0][1]);
736 close(PipeFD[1][0]);
737
738
739 // Execute the child process.
740 std::unique_ptr ChildPath, ChildIn, ChildOut;
741 {
742 ChildPath.reset(new char[ChildExecPath.size() + 1]);
743 std::copy(ChildExecPath.begin(), ChildExecPath.end(), &ChildPath[0]);
744 ChildPath[ChildExecPath.size()] = '\0';
745 std::string ChildInStr = std::to_string(PipeFD[0][0]);
746 ChildIn.reset(new char[ChildInStr.size() + 1]);
747 std::copy(ChildInStr.begin(), ChildInStr.end(), &ChildIn[0]);
748 ChildIn[ChildInStr.size()] = '\0';
749 std::string ChildOutStr = std::to_string(PipeFD[1][1]);
750 ChildOut.reset(new char[ChildOutStr.size() + 1]);
751 std::copy(ChildOutStr.begin(), ChildOutStr.end(), &ChildOut[0]);
752 ChildOut[ChildOutStr.size()] = '\0';
753 }
754
755 char * const args[] = { &ChildPath[0], &ChildIn[0], &ChildOut[0], nullptr };
756 int rc = execv(ChildExecPath.c_str(), args);
757 if (rc != 0)
758 perror("Error executing child process: ");
759 llvm_unreachable("Error executing child process");
760 }
761 // else we're the parent...
762
763 // Close the child ends of the pipes
764 close(PipeFD[0][0]);
765 close(PipeFD[1][1]);
766
767 // Return an RPC channel connected to our end of the pipes.
768 return llvm::make_unique(PipeFD[1][0], PipeFD[0][1]);
769 #endif
770 }