//===---- RemoteTargetExternal.cpp - LLVM out-of-process JIT execution ----===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Implementation of the RemoteTargetExternal class which executes JITed code // in a separate process from where it was built. // //===----------------------------------------------------------------------===// #include "llvm/Config/config.h" #include "RemoteTarget.h" #include "RemoteTargetExternal.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" #include "llvm/Support/Memory.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" #include <string> using namespace llvm; #define DEBUG_TYPE "lli" bool RemoteTargetExternal::allocateSpace(size_t Size, unsigned Alignment, uint64_t &Address) { DEBUG(dbgs() << "Message [allocate space] size: " << Size << ", align: " << Alignment << "\n"); if (!SendAllocateSpace(Alignment, Size)) { ErrorMsg += ", (RemoteTargetExternal::allocateSpace)"; return false; } if (!Receive(LLI_AllocationResult, Address)) { ErrorMsg += ", (RemoteTargetExternal::allocateSpace)"; return false; } if (Address == 0) { ErrorMsg += "failed allocation, (RemoteTargetExternal::allocateSpace)"; return false; } DEBUG(dbgs() << "Message [allocate space] addr: 0x" << format("%llx", Address) << "\n"); return true; } bool RemoteTargetExternal::loadData(uint64_t Address, const void *Data, size_t Size) { DEBUG(dbgs() << "Message [load data] addr: 0x" << format("%llx", Address) << ", size: " << Size << "\n"); if (!SendLoadSection(Address, Data, (uint32_t)Size, false)) { ErrorMsg += ", (RemoteTargetExternal::loadData)"; return false; } int Status = LLI_Status_Success; if (!Receive(LLI_LoadResult, Status)) { ErrorMsg += ", (RemoteTargetExternal::loadData)"; return false; } if (Status == LLI_Status_IncompleteMsg) { ErrorMsg += "incomplete load data, (RemoteTargetExternal::loadData)"; return false; } if (Status == LLI_Status_NotAllocated) { ErrorMsg += "data memory not allocated, (RemoteTargetExternal::loadData)"; return false; } DEBUG(dbgs() << "Message [load data] complete\n"); return true; } bool RemoteTargetExternal::loadCode(uint64_t Address, const void *Data, size_t Size) { DEBUG(dbgs() << "Message [load code] addr: 0x" << format("%llx", Address) << ", size: " << Size << "\n"); if (!SendLoadSection(Address, Data, (uint32_t)Size, true)) { ErrorMsg += ", (RemoteTargetExternal::loadCode)"; return false; } int Status = LLI_Status_Success; if (!Receive(LLI_LoadResult, Status)) { ErrorMsg += ", (RemoteTargetExternal::loadCode)"; return false; } if (Status == LLI_Status_IncompleteMsg) { ErrorMsg += "incomplete load data, (RemoteTargetExternal::loadData)"; return false; } if (Status == LLI_Status_NotAllocated) { ErrorMsg += "data memory not allocated, (RemoteTargetExternal::loadData)"; return false; } DEBUG(dbgs() << "Message [load code] complete\n"); return true; } bool RemoteTargetExternal::executeCode(uint64_t Address, int32_t &RetVal) { DEBUG(dbgs() << "Message [exectue code] addr: " << Address << "\n"); if (!SendExecute(Address)) { ErrorMsg += ", (RemoteTargetExternal::executeCode)"; return false; } if (!Receive(LLI_ExecutionResult, RetVal)) { ErrorMsg += ", (RemoteTargetExternal::executeCode)"; return false; } DEBUG(dbgs() << "Message [exectue code] return: " << RetVal << "\n"); return true; } void RemoteTargetExternal::stop() { SendTerminate(); RPC.Wait(); } bool RemoteTargetExternal::SendAllocateSpace(uint32_t Alignment, uint32_t Size) { if (!SendHeader(LLI_AllocateSpace)) { ErrorMsg += ", (RemoteTargetExternal::SendAllocateSpace)"; return false; } AppendWrite((const void *)&Alignment, 4); AppendWrite((const void *)&Size, 4); if (!SendPayload()) { ErrorMsg += ", (RemoteTargetExternal::SendAllocateSpace)"; return false; } return true; } bool RemoteTargetExternal::SendLoadSection(uint64_t Addr, const void *Data, uint32_t Size, bool IsCode) { LLIMessageType MsgType = IsCode ? LLI_LoadCodeSection : LLI_LoadDataSection; if (!SendHeader(MsgType)) { ErrorMsg += ", (RemoteTargetExternal::SendLoadSection)"; return false; } AppendWrite((const void *)&Addr, 8); AppendWrite(Data, Size); if (!SendPayload()) { ErrorMsg += ", (RemoteTargetExternal::SendLoadSection)"; return false; } return true; } bool RemoteTargetExternal::SendExecute(uint64_t Addr) { if (!SendHeader(LLI_Execute)) { ErrorMsg += ", (RemoteTargetExternal::SendExecute)"; return false; } AppendWrite((const void *)&Addr, 8); if (!SendPayload()) { ErrorMsg += ", (RemoteTargetExternal::SendExecute)"; return false; } return true; } bool RemoteTargetExternal::SendTerminate() { return SendHeader(LLI_Terminate); // No data or data size is sent with Terminate } bool RemoteTargetExternal::Receive(LLIMessageType Msg) { if (!ReceiveHeader(Msg)) return false; int Unused; AppendRead(&Unused, 0); if (!ReceivePayload()) return false; ReceiveData.clear(); Sizes.clear(); return true; } bool RemoteTargetExternal::Receive(LLIMessageType Msg, int32_t &Data) { if (!ReceiveHeader(Msg)) return false; AppendRead(&Data, 4); if (!ReceivePayload()) return false; ReceiveData.clear(); Sizes.clear(); return true; } bool RemoteTargetExternal::Receive(LLIMessageType Msg, uint64_t &Data) { if (!ReceiveHeader(Msg)) return false; AppendRead(&Data, 8); if (!ReceivePayload()) return false; ReceiveData.clear(); Sizes.clear(); return true; } bool RemoteTargetExternal::ReceiveHeader(LLIMessageType ExpectedMsgType) { assert(ReceiveData.empty() && Sizes.empty() && "Payload vector not empty to receive header"); // Message header, with type to follow uint32_t MsgType; if (!ReadBytes(&MsgType, 4)) { ErrorMsg += ", (RemoteTargetExternal::ReceiveHeader)"; return false; } if (MsgType != (uint32_t)ExpectedMsgType) { ErrorMsg = "received unexpected message type"; ErrorMsg += ". Expecting: "; ErrorMsg += ExpectedMsgType; ErrorMsg += ", Got: "; ErrorMsg += MsgType; return false; } return true; } bool RemoteTargetExternal::ReceivePayload() { assert(!ReceiveData.empty() && "Payload vector empty to receive"); assert(ReceiveData.size() == Sizes.size() && "Unexpected mismatch between data and size"); uint32_t TotalSize = 0; for (int I=0, E=Sizes.size(); I < E; I++) TotalSize += Sizes[I]; // Payload size header uint32_t DataSize; if (!ReadBytes(&DataSize, 4)) { ErrorMsg += ", invalid data size"; return false; } if (DataSize != TotalSize) { ErrorMsg = "unexpected data size"; ErrorMsg += ". Expecting: "; ErrorMsg += TotalSize; ErrorMsg += ", Got: "; ErrorMsg += DataSize; return false; } if (DataSize == 0) return true; // Payload itself for (int I=0, E=Sizes.size(); I < E; I++) { if (!ReadBytes(ReceiveData[I], Sizes[I])) { ErrorMsg = "unexpected data while reading message"; return false; } } return true; } bool RemoteTargetExternal::SendHeader(LLIMessageType MsgType) { assert(SendData.empty() && Sizes.empty() && "Payload vector not empty to send header"); // Message header, with type to follow if (!WriteBytes(&MsgType, 4)) { ErrorMsg += ", (RemoteTargetExternal::SendHeader)"; return false; } return true; } bool RemoteTargetExternal::SendPayload() { assert(!SendData.empty() && !Sizes.empty() && "Payload vector empty to send"); assert(SendData.size() == Sizes.size() && "Unexpected mismatch between data and size"); uint32_t TotalSize = 0; for (int I=0, E=Sizes.size(); I < E; I++) TotalSize += Sizes[I]; // Payload size header if (!WriteBytes(&TotalSize, 4)) { ErrorMsg += ", invalid data size"; return false; } if (TotalSize == 0) return true; // Payload itself for (int I=0, E=Sizes.size(); I < E; I++) { if (!WriteBytes(SendData[I], Sizes[I])) { ErrorMsg = "unexpected data while writing message"; return false; } } SendData.clear(); Sizes.clear(); return true; } void RemoteTargetExternal::AppendWrite(const void *Data, uint32_t Size) { SendData.push_back(Data); Sizes.push_back(Size); } void RemoteTargetExternal::AppendRead(void *Data, uint32_t Size) { ReceiveData.push_back(Data); Sizes.push_back(Size); } #ifdef LLVM_ON_UNIX #include "Unix/RPCChannel.inc" #endif #ifdef LLVM_ON_WIN32 #include "Windows/RPCChannel.inc" #endif