diff options
Diffstat (limited to 'tools/lli')
-rw-r--r-- | tools/lli/ChildTarget/ChildTarget.cpp | 56 | ||||
-rw-r--r-- | tools/lli/RemoteMemoryManager.cpp | 10 | ||||
-rw-r--r-- | tools/lli/RemoteTarget.cpp | 15 | ||||
-rw-r--r-- | tools/lli/RemoteTarget.h | 16 | ||||
-rw-r--r-- | tools/lli/RemoteTargetExternal.cpp | 331 | ||||
-rw-r--r-- | tools/lli/RemoteTargetExternal.h | 51 | ||||
-rw-r--r-- | tools/lli/RemoteTargetMessage.h | 54 | ||||
-rw-r--r-- | tools/lli/Unix/RemoteTargetExternal.inc | 49 | ||||
-rw-r--r-- | tools/lli/lli.cpp | 7 |
9 files changed, 437 insertions, 152 deletions
diff --git a/tools/lli/ChildTarget/ChildTarget.cpp b/tools/lli/ChildTarget/ChildTarget.cpp index dba8966cf4..ca75beb842 100644 --- a/tools/lli/ChildTarget/ChildTarget.cpp +++ b/tools/lli/ChildTarget/ChildTarget.cpp @@ -25,8 +25,8 @@ private: // Outgoing message handlers void sendChildActive(); void sendAllocationResult(uint64_t Addr); - void sendLoadComplete(); - void sendExecutionComplete(uint64_t Result); + void sendLoadStatus(uint32_t Status); + void sendExecutionComplete(int Result); // OS-specific functions void initializeConnection(); @@ -36,6 +36,7 @@ private: void makeSectionExecutable(uint64_t Addr, uint32_t Size); void InvalidateInstructionCache(const void *Addr, size_t Len); void releaseMemory(uint64_t Addr, uint32_t Size); + bool isAllocatedMemory(uint64_t Address, uint32_t Size); // Store a map of allocated buffers to sizes. typedef std::map<uint64_t, uint32_t> AllocMapType; @@ -121,33 +122,36 @@ void LLIChildTarget::handleLoadSection(bool IsCode) { // Read the message data size. uint32_t DataSize; int rc = ReadBytes(&DataSize, 4); + (void)rc; assert(rc == 4); // Read the target load address. uint64_t Addr; rc = ReadBytes(&Addr, 8); assert(rc == 8); - size_t BufferSize = DataSize - 8; - // FIXME: Verify that this is in allocated space + if (!isAllocatedMemory(Addr, BufferSize)) + return sendLoadStatus(LLI_Status_NotAllocated); // Read section data into previously allocated buffer - rc = ReadBytes((void*)Addr, DataSize - 8); - assert(rc == (int)(BufferSize)); + rc = ReadBytes((void*)Addr, BufferSize); + if (rc != (int)(BufferSize)) + return sendLoadStatus(LLI_Status_IncompleteMsg); // If IsCode, mark memory executable if (IsCode) makeSectionExecutable(Addr, BufferSize); // Send MarkLoadComplete message. - sendLoadComplete(); + sendLoadStatus(LLI_Status_Success); } void LLIChildTarget::handleExecute() { // Read the message data size. uint32_t DataSize; int rc = ReadBytes(&DataSize, 4); + (void)rc; assert(rc == 4); assert(DataSize == 8); @@ -162,7 +166,7 @@ void LLIChildTarget::handleExecute() { Result = fn(); // Send ExecutionResult message. - sendExecutionComplete((int64_t)Result); + sendExecutionComplete(Result); } void LLIChildTarget::handleTerminate() { @@ -175,11 +179,26 @@ void LLIChildTarget::handleTerminate() { m_AllocatedBufferMap.clear(); } +bool LLIChildTarget::isAllocatedMemory(uint64_t Address, uint32_t Size) { + uint64_t End = Address+Size; + AllocMapType::iterator ItBegin = m_AllocatedBufferMap.begin(); + AllocMapType::iterator ItEnd = m_AllocatedBufferMap.end(); + for (AllocMapType::iterator It = ItBegin; It != ItEnd; ++It) { + uint64_t A = It->first; + uint64_t E = A + It->second; + // Starts and finishes inside allocated region + if (Address >= A && End <= E) + return true; + } + return false; +} + // Outgoing message handlers void LLIChildTarget::sendChildActive() { // Write the message type. uint32_t MsgType = (uint32_t)LLI_ChildActive; int rc = WriteBytes(&MsgType, 4); + (void)rc; assert(rc == 4); // Write the data size. @@ -192,6 +211,7 @@ void LLIChildTarget::sendAllocationResult(uint64_t Addr) { // Write the message type. uint32_t MsgType = (uint32_t)LLI_AllocationResult; int rc = WriteBytes(&MsgType, 4); + (void)rc; assert(rc == 4); // Write the data size. @@ -204,33 +224,39 @@ void LLIChildTarget::sendAllocationResult(uint64_t Addr) { assert(rc == 8); } -void LLIChildTarget::sendLoadComplete() { +void LLIChildTarget::sendLoadStatus(uint32_t Status) { // Write the message type. - uint32_t MsgType = (uint32_t)LLI_LoadComplete; + uint32_t MsgType = (uint32_t)LLI_LoadResult; int rc = WriteBytes(&MsgType, 4); + (void)rc; assert(rc == 4); // Write the data size. - uint32_t DataSize = 0; + uint32_t DataSize = 4; rc = WriteBytes(&DataSize, 4); assert(rc == 4); + + // Write the result. + rc = WriteBytes(&Status, 4); + assert(rc == 4); } -void LLIChildTarget::sendExecutionComplete(uint64_t Result) { +void LLIChildTarget::sendExecutionComplete(int Result) { // Write the message type. uint32_t MsgType = (uint32_t)LLI_ExecutionResult; int rc = WriteBytes(&MsgType, 4); + (void)rc; assert(rc == 4); // Write the data size. - uint32_t DataSize = 8; + uint32_t DataSize = 4; rc = WriteBytes(&DataSize, 4); assert(rc == 4); // Write the result. - rc = WriteBytes(&Result, 8); - assert(rc == 8); + rc = WriteBytes(&Result, 4); + assert(rc == 4); } #ifdef LLVM_ON_UNIX diff --git a/tools/lli/RemoteMemoryManager.cpp b/tools/lli/RemoteMemoryManager.cpp index 04fc40e426..c9d426a4e6 100644 --- a/tools/lli/RemoteMemoryManager.cpp +++ b/tools/lli/RemoteMemoryManager.cpp @@ -129,7 +129,7 @@ void RemoteMemoryManager::notifyObjectLoaded(ExecutionEngine *EE, // Allocate space in the remote target. uint64_t RemoteAddr; - if (Target->allocateSpace(CurOffset, MaxAlign, RemoteAddr)) + if (!Target->allocateSpace(CurOffset, MaxAlign, RemoteAddr)) report_fatal_error(Target->getErrorMsg()); // Map the section addresses so relocations will get updated in the local @@ -155,13 +155,13 @@ bool RemoteMemoryManager::finalizeMemory(std::string *ErrMsg) { uint64_t RemoteAddr = I->first; const Allocation &Section = I->second; if (Section.IsCode) { - Target->loadCode(RemoteAddr, Section.MB.base(), Section.MB.size()); - + if (!Target->loadCode(RemoteAddr, Section.MB.base(), Section.MB.size())) + report_fatal_error(Target->getErrorMsg()); DEBUG(dbgs() << " loading code: " << Section.MB.base() << " to remote: 0x" << format("%llx", RemoteAddr) << "\n"); } else { - Target->loadData(RemoteAddr, Section.MB.base(), Section.MB.size()); - + if (!Target->loadData(RemoteAddr, Section.MB.base(), Section.MB.size())) + report_fatal_error(Target->getErrorMsg()); DEBUG(dbgs() << " loading data: " << Section.MB.base() << " to remote: 0x" << format("%llx", RemoteAddr) << "\n"); } diff --git a/tools/lli/RemoteTarget.cpp b/tools/lli/RemoteTarget.cpp index 5c74e6e7a0..9631ef7aac 100644 --- a/tools/lli/RemoteTarget.cpp +++ b/tools/lli/RemoteTarget.cpp @@ -56,34 +56,35 @@ bool RemoteTarget::allocateSpace(size_t Size, unsigned Alignment, sys::MemoryBlock *Prev = Allocations.size() ? &Allocations.back() : NULL; sys::MemoryBlock Mem = sys::Memory::AllocateRWX(Size, Prev, &ErrorMsg); if (Mem.base() == NULL) - return true; + return false; if ((uintptr_t)Mem.base() % Alignment) { ErrorMsg = "unable to allocate sufficiently aligned memory"; - return true; + return false; } Address = reinterpret_cast<uint64_t>(Mem.base()); - return false; + return true; } bool RemoteTarget::loadData(uint64_t Address, const void *Data, size_t Size) { memcpy ((void*)Address, Data, Size); - return false; + return true; } bool RemoteTarget::loadCode(uint64_t Address, const void *Data, size_t Size) { memcpy ((void*)Address, Data, Size); sys::MemoryBlock Mem((void*)Address, Size); sys::Memory::setExecutable(Mem, &ErrorMsg); - return false; + return true; } bool RemoteTarget::executeCode(uint64_t Address, int &RetVal) { int (*fn)(void) = (int(*)(void))Address; RetVal = fn(); - return false; + return true; } -void RemoteTarget::create() { +bool RemoteTarget::create() { + return true; } void RemoteTarget::stop() { diff --git a/tools/lli/RemoteTarget.h b/tools/lli/RemoteTarget.h index c95fbd1ae9..a7d4e59e3b 100644 --- a/tools/lli/RemoteTarget.h +++ b/tools/lli/RemoteTarget.h @@ -25,11 +25,13 @@ namespace llvm { class RemoteTarget { - std::string ErrorMsg; bool IsRunning; SmallVector<sys::MemoryBlock, 16> Allocations; +protected: + std::string ErrorMsg; + public: StringRef getErrorMsg() const { return ErrorMsg; } @@ -39,7 +41,7 @@ public: /// @param Alignment Required minimum alignment for allocated space. /// @param[out] Address Remote address of the allocated memory. /// - /// @returns False on success. On failure, ErrorMsg is updated with + /// @returns True on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. virtual bool allocateSpace(size_t Size, unsigned Alignment, @@ -51,7 +53,7 @@ public: /// @param Data Source address in the host process. /// @param Size Number of bytes to copy. /// - /// @returns False on success. On failure, ErrorMsg is updated with + /// @returns True on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. virtual bool loadData(uint64_t Address, const void *Data, @@ -63,7 +65,7 @@ public: /// @param Data Source address in the host process. /// @param Size Number of bytes to copy. /// - /// @returns False on success. On failure, ErrorMsg is updated with + /// @returns True on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. virtual bool loadCode(uint64_t Address, const void *Data, @@ -76,7 +78,7 @@ public: /// process. /// @param[out] RetVal The integer return value of the called function. /// - /// @returns False on success. On failure, ErrorMsg is updated with + /// @returns True on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. virtual bool executeCode(uint64_t Address, int &RetVal); @@ -89,12 +91,12 @@ public: virtual unsigned getPageAlignment() { return 4096; } /// Start the remote process. - virtual void create(); + virtual bool create(); /// Terminate the remote process. virtual void stop(); - RemoteTarget() : ErrorMsg(""), IsRunning(false) {} + RemoteTarget() : IsRunning(false), ErrorMsg("") {} virtual ~RemoteTarget() { if (IsRunning) stop(); } // Create an instance of the system-specific remote target class. diff --git a/tools/lli/RemoteTargetExternal.cpp b/tools/lli/RemoteTargetExternal.cpp index 809488c9e3..3bf7bf4e3b 100644 --- a/tools/lli/RemoteTargetExternal.cpp +++ b/tools/lli/RemoteTargetExternal.cpp @@ -17,6 +17,8 @@ #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" @@ -26,28 +28,85 @@ using namespace llvm; bool RemoteTargetExternal::allocateSpace(size_t Size, unsigned Alignment, uint64_t &Address) { - SendAllocateSpace(Alignment, Size); - Receive(LLI_AllocationResult, Address); - return false; + 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) { - SendLoadSection(Address, Data, (uint32_t)Size, false); - Receive(LLI_LoadComplete); - return false; + 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) { - SendLoadSection(Address, Data, (uint32_t)Size, true); - Receive(LLI_LoadComplete); - return false; + 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, int &RetVal) { - SendExecute(Address); - - Receive(LLI_ExecutionResult, RetVal); - return false; +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() { @@ -55,106 +114,206 @@ void RemoteTargetExternal::stop() { Wait(); } -void RemoteTargetExternal::SendAllocateSpace(uint32_t Alignment, uint32_t Size) { - int rc; - (void)rc; - uint32_t MsgType = (uint32_t)LLI_AllocateSpace; - rc = WriteBytes(&MsgType, 4); - assert(rc == 4 && "Error writing message type."); - - uint32_t DataSize = 8; - rc = WriteBytes(&DataSize, 4); - assert(rc == 4 && "Error writing data size."); +bool RemoteTargetExternal::SendAllocateSpace(uint32_t Alignment, uint32_t Size) { + if (!SendHeader(LLI_AllocateSpace)) { + ErrorMsg += ", (RemoteTargetExternal::SendAllocateSpace)"; + return false; + } - rc = WriteBytes(&Alignment, 4); - assert(rc == 4 && "Error writing alignment data."); + AppendWrite((const void *)&Alignment, 4); + AppendWrite((const void *)&Size, 4); - rc = WriteBytes(&Size, 4); - assert(rc == 4 && "Error writing size data."); + if (!SendPayload()) { + ErrorMsg += ", (RemoteTargetExternal::SendAllocateSpace)"; + return false; + } + return true; } -void RemoteTargetExternal::SendLoadSection(uint64_t Addr, +bool RemoteTargetExternal::SendLoadSection(uint64_t Addr, const void *Data, uint32_t Size, bool IsCode) { - int rc; - (void)rc; - uint32_t MsgType = IsCode ? LLI_LoadCodeSection : LLI_LoadDataSection; - rc = WriteBytes(&MsgType, 4); - assert(rc == 4 && "Error writing message type."); - - uint32_t DataSize = Size + 8; - rc = WriteBytes(&DataSize, 4); - assert(rc == 4 && "Error writing data size."); + LLIMessageType MsgType = IsCode ? LLI_LoadCodeSection : LLI_LoadDataSection; + if (!SendHeader(MsgType)) { + ErrorMsg += ", (RemoteTargetExternal::SendLoadSection)"; + return false; + } - rc = WriteBytes(&Addr, 8); - assert(rc == 8 && "Error writing data."); + AppendWrite((const void *)&Addr, 8); + AppendWrite(Data, Size); - rc = WriteBytes(Data, Size); - assert(rc == (int)Size && "Error writing data."); + if (!SendPayload()) { + ErrorMsg += ", (RemoteTargetExternal::SendLoadSection)"; + return false; + } + return true; } -void RemoteTargetExternal::SendExecute(uint64_t Addr) { - int rc; - (void)rc; - uint32_t MsgType = (uint32_t)LLI_Execute; - rc = WriteBytes(&MsgType, 4); - assert(rc == 4 && "Error writing message type."); +bool RemoteTargetExternal::SendExecute(uint64_t Addr) { + if (!SendHeader(LLI_Execute)) { + ErrorMsg += ", (RemoteTargetExternal::SendExecute)"; + return false; + } - uint32_t DataSize = 8; - rc = WriteBytes(&DataSize, 4); - assert(rc == 4 && "Error writing data size."); + AppendWrite((const void *)&Addr, 8); - rc = WriteBytes(&Addr, 8); - assert(rc == 8 && "Error writing data."); + if (!SendPayload()) { + ErrorMsg += ", (RemoteTargetExternal::SendExecute)"; + return false; + } + return true; } -void RemoteTargetExternal::SendTerminate() { - int rc; - (void)rc; - uint32_t MsgType = (uint32_t)LLI_Terminate; - rc = WriteBytes(&MsgType, 4); - assert(rc == 4 && "Error writing message type."); - +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; +} -void RemoteTargetExternal::Receive(LLIMessageType ExpectedMsgType) { - int rc; - (void)rc; +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; - rc = ReadBytes(&MsgType, 4); - assert(rc == 4 && "Error reading message type."); - assert(MsgType == (uint32_t)ExpectedMsgType && "Error: received unexpected message type."); + 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; - rc = ReadBytes(&DataSize, 4); - assert(rc == 4 && "Error reading data size."); - assert(DataSize == 0 && "Error: unexpected data size."); + 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; } -void RemoteTargetExternal::Receive(LLIMessageType ExpectedMsgType, int &Data) { - uint64_t Temp; - Receive(ExpectedMsgType, Temp); - Data = (int)(int64_t)Temp; +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; } -void RemoteTargetExternal::Receive(LLIMessageType ExpectedMsgType, uint64_t &Data) { - int rc; - (void)rc; - uint32_t MsgType; - rc = ReadBytes(&MsgType, 4); - assert(rc == 4 && "Error reading message type."); - assert(MsgType == (uint32_t)ExpectedMsgType && "Error: received unexpected message type."); +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 DataSize; - rc = ReadBytes(&DataSize, 4); - assert(rc == 4 && "Error reading data size."); - assert(DataSize == 8 && "Error: unexpected data 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); +} - rc = ReadBytes(&Data, 8); - assert(DataSize == 8 && "Error: unexpected data."); +void RemoteTargetExternal::AppendRead(void *Data, uint32_t Size) { + ReceiveData.push_back(Data); + Sizes.push_back(Size); } #ifdef LLVM_ON_UNIX diff --git a/tools/lli/RemoteTargetExternal.h b/tools/lli/RemoteTargetExternal.h index 63548eb52d..5ef67100e3 100644 --- a/tools/lli/RemoteTargetExternal.h +++ b/tools/lli/RemoteTargetExternal.h @@ -35,7 +35,7 @@ public: /// @param Alignment Required minimum alignment for allocated space. /// @param[out] Address Remote address of the allocated memory. /// - /// @returns False on success. On failure, ErrorMsg is updated with + /// @returns True on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. virtual bool allocateSpace(size_t Size, unsigned Alignment, @@ -47,7 +47,7 @@ public: /// @param Data Source address in the host process. /// @param Size Number of bytes to copy. /// - /// @returns False on success. On failure, ErrorMsg is updated with + /// @returns True on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. virtual bool loadData(uint64_t Address, const void *Data, size_t Size); @@ -57,7 +57,7 @@ public: /// @param Data Source address in the host process. /// @param Size Number of bytes to copy. /// - /// @returns False on success. On failure, ErrorMsg is updated with + /// @returns True on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. virtual bool loadCode(uint64_t Address, const void *Data, size_t Size); @@ -68,7 +68,7 @@ public: /// process. /// @param[out] RetVal The integer return value of the called function. /// - /// @returns False on success. On failure, ErrorMsg is updated with + /// @returns True on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. virtual bool executeCode(uint64_t Address, int &RetVal); @@ -80,7 +80,10 @@ public: virtual unsigned getPageAlignment() { return 4096; } /// Start the remote process. - virtual void create(); + /// + /// @returns True on success. On failure, ErrorMsg is updated with + /// descriptive text of the encountered error. + virtual bool create(); /// Terminate the remote process. virtual void stop(); @@ -91,23 +94,37 @@ public: private: std::string ChildName; - // This will get filled in as a point to an OS-specific structure. - void *ConnectionData; - - void SendAllocateSpace(uint32_t Alignment, uint32_t Size); - void SendLoadSection(uint64_t Addr, + bool SendAllocateSpace(uint32_t Alignment, uint32_t Size); + bool SendLoadSection(uint64_t Addr, const void *Data, uint32_t Size, bool IsCode); - void SendExecute(uint64_t Addr); - void SendTerminate(); + bool SendExecute(uint64_t Addr); + bool SendTerminate(); + + // High-level wrappers for receiving data + bool Receive(LLIMessageType Msg); + bool Receive(LLIMessageType Msg, int32_t &Data); + bool Receive(LLIMessageType Msg, uint64_t &Data); + + // Lower level target-independent read/write to deal with errors + bool ReceiveHeader(LLIMessageType Msg); + bool ReceivePayload(); + bool SendHeader(LLIMessageType Msg); + bool SendPayload(); + + // Functions to append/retrieve data from the payload + SmallVector<const void *, 2> SendData; + SmallVector<void *, 1> ReceiveData; // Future proof + SmallVector<int, 2> Sizes; + void AppendWrite(const void *Data, uint32_t Size); + void AppendRead(void *Data, uint32_t Size); - void Receive(LLIMessageType Msg); - void Receive(LLIMessageType Msg, int &Data); - void Receive(LLIMessageType Msg, uint64_t &Data); + // This will get filled in as a point to an OS-specific structure. + void *ConnectionData; - int WriteBytes(const void *Data, size_t Size); - int ReadBytes(void *Data, size_t Size); + bool WriteBytes(const void *Data, size_t Size); + bool ReadBytes(void *Data, size_t Size); void Wait(); }; diff --git a/tools/lli/RemoteTargetMessage.h b/tools/lli/RemoteTargetMessage.h index 12cfa9a404..cb934a1066 100644 --- a/tools/lli/RemoteTargetMessage.h +++ b/tools/lli/RemoteTargetMessage.h @@ -26,20 +26,60 @@ namespace llvm { // only here for testing purposes and is therefore intended to be the simplest // implementation that will work. It is assumed that the parent and child // share characteristics like endianness. +// +// Quick description of the protocol: +// +// { Header + Payload Size + Payload } +// +// The protocol message consist of a header, the payload size (which can be +// zero), and the payload itself. The payload can contain any number of items, +// and the size has to be the sum of them all. Each end is responsible for +// reading/writing the correct number of items with the correct sizes. +// +// The current four known exchanges are: +// +// * Allocate Space: +// Parent: { LLI_AllocateSpace, 8, Alignment, Size } +// Child: { LLI_AllocationResult, 8, Address } +// +// * Load Data: +// Parent: { LLI_LoadDataSection, 8+Size, Address, Data } +// Child: { LLI_LoadComplete, 4, StatusCode } +// +// * Load Code: +// Parent: { LLI_LoadCodeSection, 8+Size, Address, Code } +// Child: { LLI_LoadComplete, 4, StatusCode } +// +// * Execute Code: +// Parent: { LLI_Execute, 8, Address } +// Child: { LLI_ExecutionResult, 4, Result } +// +// It is the responsibility of either side to check for correct headers, +// sizes and payloads, since any inconsistency would misalign the pipe, and +// result in data corruption. enum LLIMessageType { LLI_Error = -1, LLI_ChildActive = 0, // Data = not used - LLI_AllocateSpace, // Data = struct { uint_32t Align, uint_32t Size } - LLI_AllocationResult, // Data = uint64_t AllocAddress (in Child memory space) - LLI_LoadCodeSection, // Data = uint32_t Addr, followed by section contests - LLI_LoadDataSection, // Data = uint32_t Addr, followed by section contents - LLI_LoadComplete, // Data = not used - LLI_Execute, // Data = Address of function to execute - LLI_ExecutionResult, // Data = uint64_t Result + LLI_AllocateSpace, // Data = struct { uint32_t Align, uint_32t Size } + LLI_AllocationResult, // Data = uint64_t Address (child memory space) + + LLI_LoadCodeSection, // Data = uint64_t Address, void * SectionData + LLI_LoadDataSection, // Data = uint64_t Address, void * SectionData + LLI_LoadResult, // Data = uint32_t LLIMessageStatus + + LLI_Execute, // Data = uint64_t Address + LLI_ExecutionResult, // Data = uint32_t Result + LLI_Terminate // Data = not used }; +enum LLIMessageStatus { + LLI_Status_Success = 0, // Operation succeeded + LLI_Status_NotAllocated, // Address+Size not allocated in child space + LLI_Status_IncompleteMsg // Size received doesn't match request +}; + } // end namespace llvm #endif diff --git a/tools/lli/Unix/RemoteTargetExternal.inc b/tools/lli/Unix/RemoteTargetExternal.inc index 481c1d5156..ea8e4597d5 100644 --- a/tools/lli/Unix/RemoteTargetExternal.inc +++ b/tools/lli/Unix/RemoteTargetExternal.inc @@ -30,7 +30,7 @@ struct ConnectionData_t { namespace llvm { -void RemoteTargetExternal::create() { +bool RemoteTargetExternal::create() { int PipeFD[2][2]; pid_t ChildPID; @@ -73,16 +73,53 @@ void RemoteTargetExternal::create() { // Store the parent ends of the pipes ConnectionData = (void*)new ConnectionData_t(PipeFD[1][0], PipeFD[0][1]); - Receive(LLI_ChildActive); + // We must get Ack from the client (blocking read) + if (!Receive(LLI_ChildActive)) { + ErrorMsg += ", (RemoteTargetExternal::create) - Stopping process!"; + stop(); + return false; + } + } + return true; +} + +static void ReportError(int rc, size_t Size, std::string &ErrorMsg) { + if (rc == -1) { + if (errno == EPIPE) + ErrorMsg += "pipe closed"; + else if (errno == EINTR) + ErrorMsg += "interrupted"; + else + ErrorMsg += "file descriptor error"; + } else { + char Number[10] = { 0 }; + ErrorMsg += "Expecting "; + sprintf(Number, "%d", (uint32_t)Size); + ErrorMsg += Number; + ErrorMsg += " bytes, Got "; + sprintf(Number, "%d", rc); + ErrorMsg += Number; } } -int RemoteTargetExternal::WriteBytes(const void *Data, size_t Size) { - return write(((ConnectionData_t*)ConnectionData)->OutputPipe, Data, Size); +bool RemoteTargetExternal::WriteBytes(const void *Data, size_t Size) { + int rc = write(((ConnectionData_t*)ConnectionData)->OutputPipe, Data, Size); + if (rc != -1 && (size_t)rc == Size) + return true; + + ErrorMsg = "WriteBytes: "; + ReportError(rc, Size, ErrorMsg); + return false; } -int RemoteTargetExternal::ReadBytes(void *Data, size_t Size) { - return read(((ConnectionData_t*)ConnectionData)->InputPipe, Data, Size); +bool RemoteTargetExternal::ReadBytes(void *Data, size_t Size) { + int rc = read(((ConnectionData_t*)ConnectionData)->InputPipe, Data, Size); + if (rc != -1 && (size_t)rc == Size) + return true; + + ErrorMsg = "ReadBytes: "; + ReportError(rc, Size, ErrorMsg); + return false; } void RemoteTargetExternal::Wait() { diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index 3766f8c0ca..c6db51a2b0 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -685,7 +685,10 @@ int main(int argc, char **argv, char * const *envp) { MM->setRemoteTarget(Target.get()); // Create the remote target. - Target->create(); + if (!Target->create()) { + errs() << "ERROR: " << Target->getErrorMsg() << "\n"; + return EXIT_FAILURE; + } // Since we're executing in a (at least simulated) remote address space, // we can't use the ExecutionEngine::runFunctionAsMain(). We have to @@ -702,7 +705,7 @@ int main(int argc, char **argv, char * const *envp) { DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at 0x" << format("%llx", Entry) << "\n"); - if (Target->executeCode(Entry, Result)) + if (!Target->executeCode(Entry, Result)) errs() << "ERROR: " << Target->getErrorMsg() << "\n"; // Like static constructors, the remote target MCJIT support doesn't handle |