blob: 55fcae9def8fab51a54490a00f0e2e70a6951a2e [file] [log] [blame]
#include "llvm/Config/config.h"
#include "../RemoteTargetMessage.h"
#include <assert.h>
#include <map>
#include <stdint.h>
#include <string>
#include <vector>
using namespace llvm;
class LLIChildTarget {
public:
~LLIChildTarget(); // OS-specific destructor
void initialize();
LLIMessageType waitForIncomingMessage();
void handleMessage(LLIMessageType messageType);
private:
// Incoming message handlers
void handleAllocateSpace();
void handleLoadSection(bool IsCode);
void handleExecute();
void handleTerminate();
// Outgoing message handlers
void sendChildActive();
void sendAllocationResult(uint64_t Addr);
void sendLoadComplete();
void sendExecutionComplete(uint64_t Result);
// OS-specific functions
void initializeConnection();
int WriteBytes(const void *Data, size_t Size);
int ReadBytes(void *Data, size_t Size);
uint64_t allocate(uint32_t Alignment, uint32_t Size);
void makeSectionExecutable(uint64_t Addr, uint32_t Size);
void InvalidateInstructionCache(const void *Addr, size_t Len);
void releaseMemory(uint64_t Addr, uint32_t Size);
// Store a map of allocated buffers to sizes.
typedef std::map<uint64_t, uint32_t> AllocMapType;
AllocMapType m_AllocatedBufferMap;
// Communication handles (OS-specific)
void *ConnectionData;
};
int main() {
LLIChildTarget ThisChild;
ThisChild.initialize();
LLIMessageType MsgType;
do {
MsgType = ThisChild.waitForIncomingMessage();
ThisChild.handleMessage(MsgType);
} while (MsgType != LLI_Terminate &&
MsgType != LLI_Error);
return 0;
}
// Public methods
void LLIChildTarget::initialize() {
initializeConnection();
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:
handleTerminate();
break;
default:
// FIXME: Handle error!
break;
}
}
// Incoming message handlers
void LLIChildTarget::handleAllocateSpace() {
// Read and verify the message data size.
uint32_t DataSize;
int rc = ReadBytes(&DataSize, 4);
assert(rc == 4);
assert(DataSize == 8);
// Read the message arguments.
uint32_t Alignment;
uint32_t AllocSize;
rc = ReadBytes(&Alignment, 4);
assert(rc == 4);
rc = ReadBytes(&AllocSize, 4);
assert(rc == 4);
// Allocate the memory.
uint64_t Addr = allocate(Alignment, AllocSize);
// Send AllocationResult message.
sendAllocationResult(Addr);
}
void LLIChildTarget::handleLoadSection(bool IsCode) {
// Read the message data size.
uint32_t DataSize;
int rc = ReadBytes(&DataSize, 4);
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
// Read section data into previously allocated buffer
rc = ReadBytes((void*)Addr, DataSize - 8);
assert(rc == (int)(BufferSize));
// If IsCode, mark memory executable
if (IsCode)
makeSectionExecutable(Addr, BufferSize);
// Send MarkLoadComplete message.
sendLoadComplete();
}
void LLIChildTarget::handleExecute() {
// Read the message data size.
uint32_t DataSize;
int rc = ReadBytes(&DataSize, 4);
assert(rc == 4);
assert(DataSize == 8);
// Read the target address.
uint64_t Addr;
rc = ReadBytes(&Addr, 8);
assert(rc == 8);
// Call function
int Result;
int (*fn)(void) = (int(*)(void))Addr;
Result = fn();
// Send ExecutionResult message.
sendExecutionComplete((int64_t)Result);
}
void LLIChildTarget::handleTerminate() {
// Release all allocated memory
AllocMapType::iterator Begin = m_AllocatedBufferMap.begin();
AllocMapType::iterator End = m_AllocatedBufferMap.end();
for (AllocMapType::iterator It = Begin; It != End; ++It) {
releaseMemory(It->first, It->second);
}
m_AllocatedBufferMap.clear();
}
// Outgoing message handlers
void LLIChildTarget::sendChildActive() {
// Write the message type.
uint32_t MsgType = (uint32_t)LLI_ChildActive;
int rc = WriteBytes(&MsgType, 4);
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);
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::sendLoadComplete() {
// Write the message type.
uint32_t MsgType = (uint32_t)LLI_LoadComplete;
int rc = WriteBytes(&MsgType, 4);
assert(rc == 4);
// Write the data size.
uint32_t DataSize = 0;
rc = WriteBytes(&DataSize, 4);
assert(rc == 4);
}
void LLIChildTarget::sendExecutionComplete(uint64_t Result) {
// Write the message type.
uint32_t MsgType = (uint32_t)LLI_ExecutionResult;
int rc = WriteBytes(&MsgType, 4);
assert(rc == 4);
// Write the data size.
uint32_t DataSize = 8;
rc = WriteBytes(&DataSize, 4);
assert(rc == 4);
// Write the result.
rc = WriteBytes(&Result, 8);
assert(rc == 8);
}
#ifdef LLVM_ON_UNIX
#include "Unix/ChildTarget.inc"
#endif
#ifdef LLVM_ON_WIN32
#include "Windows/ChildTarget.inc"
#endif