#include "llvm/Config/config.h" #include "../RPCChannel.h" #include "../RemoteTarget.h" #include "../RemoteTargetMessage.h" #include "llvm/Support/Memory.h" #include <assert.h> #include <map> #include <stdint.h> #include <string> #include <vector> using namespace llvm; class LLIChildTarget { public: void initialize(); LLIMessageType waitForIncomingMessage(); void handleMessage(LLIMessageType messageType); RemoteTarget *RT; RPCChannel RPC; private: // Incoming message handlers void handleAllocateSpace(); void handleLoadSection(bool IsCode); void handleExecute(); // Outgoing message handlers void sendChildActive(); void sendAllocationResult(uint64_t Addr); void sendLoadStatus(uint32_t Status); void sendExecutionComplete(int Result); // OS-specific functions void initializeConnection(); int WriteBytes(const void *Data, size_t Size) { return RPC.WriteBytes(Data, Size) ? Size : -1; } int ReadBytes(void *Data, size_t Size) { return RPC.ReadBytes(Data, Size) ? Size : -1; } // Communication handles (OS-specific) void *ConnectionData; }; int main() { LLIChildTarget ThisChild; ThisChild.RT = new RemoteTarget(); ThisChild.initialize(); LLIMessageType MsgType; do { MsgType = ThisChild.waitForIncomingMessage(); ThisChild.handleMessage(MsgType); } while (MsgType != LLI_Terminate && MsgType != LLI_Error); delete ThisChild.RT; return 0; } // Public methods void LLIChildTarget::initialize() { RPC.createClient(); sendChildActive(); } LLIMessageType LLIChildTarget::waitForIncomingMessage() { int32_t MsgType = -1; if (ReadBytes(&MsgType, 4) > 0) return (LLIMessageType)MsgType; return LLI_Error; } void LLIChildTarget::handleMessage(LLIMessageType messageType) { switch (messageType) { case LLI_AllocateSpace: handleAllocateSpace(); break; case LLI_LoadCodeSection: handleLoadSection(true); break; case LLI_LoadDataSection: handleLoadSection(false); break; case LLI_Execute: handleExecute(); break; case LLI_Terminate: RT->stop(); break; default: // FIXME: Handle error! break; } } // Incoming message handlers void LLIChildTarget::handleAllocateSpace() { // Read and verify the message data size. uint32_t DataSize = 0; int rc = ReadBytes(&DataSize, 4); (void)rc; assert(rc == 4); assert(DataSize == 8); // Read the message arguments. uint32_t Alignment = 0; uint32_t AllocSize = 0; rc = ReadBytes(&Alignment, 4); assert(rc == 4); rc = ReadBytes(&AllocSize, 4); assert(rc == 4); // Allocate the memory. uint64_t Addr; RT->allocateSpace(AllocSize, Alignment, Addr); // Send AllocationResult message. sendAllocationResult(Addr); } void LLIChildTarget::handleLoadSection(bool IsCode) { // Read the message data size. uint32_t DataSize = 0; int rc = ReadBytes(&DataSize, 4); (void)rc; assert(rc == 4); // Read the target load address. uint64_t Addr = 0; rc = ReadBytes(&Addr, 8); assert(rc == 8); size_t BufferSize = DataSize - 8; if (!RT->isAllocatedMemory(Addr, BufferSize)) return sendLoadStatus(LLI_Status_NotAllocated); // Read section data into previously allocated buffer rc = ReadBytes((void*)Addr, BufferSize); if (rc != (int)(BufferSize)) return sendLoadStatus(LLI_Status_IncompleteMsg); // If IsCode, mark memory executable if (IsCode) sys::Memory::InvalidateInstructionCache((void *)Addr, BufferSize); // Send MarkLoadComplete message. sendLoadStatus(LLI_Status_Success); } void LLIChildTarget::handleExecute() { // Read the message data size. uint32_t DataSize = 0; int rc = ReadBytes(&DataSize, 4); (void)rc; assert(rc == 4); assert(DataSize == 8); // Read the target address. uint64_t Addr = 0; rc = ReadBytes(&Addr, 8); assert(rc == 8); // Call function int32_t Result = -1; RT->executeCode(Addr, Result); // Send ExecutionResult message. sendExecutionComplete(Result); } // 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. uint32_t DataSize = 0; rc = WriteBytes(&DataSize, 4); assert(rc == 4); } 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. uint32_t DataSize = 8; rc = WriteBytes(&DataSize, 4); assert(rc == 4); // Write the allocated address. rc = WriteBytes(&Addr, 8); assert(rc == 8); } void LLIChildTarget::sendLoadStatus(uint32_t Status) { // Write the message type. uint32_t MsgType = (uint32_t)LLI_LoadResult; int rc = WriteBytes(&MsgType, 4); (void)rc; assert(rc == 4); // Write the data size. uint32_t DataSize = 4; rc = WriteBytes(&DataSize, 4); assert(rc == 4); // Write the result. rc = WriteBytes(&Status, 4); assert(rc == 4); } 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 = 4; rc = WriteBytes(&DataSize, 4); assert(rc == 4); // Write the result. rc = WriteBytes(&Result, 4); assert(rc == 4); } #ifdef LLVM_ON_UNIX #include "../Unix/RPCChannel.inc" #endif #ifdef LLVM_ON_WIN32 #include "../Windows/RPCChannel.inc" #endif