aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lli
diff options
context:
space:
mode:
authorStephen Hines <srhines@google.com>2014-04-23 16:57:46 -0700
committerStephen Hines <srhines@google.com>2014-04-24 15:53:16 -0700
commit36b56886974eae4f9c5ebc96befd3e7bfe5de338 (patch)
treee6cfb69fbbd937f450eeb83bfb83b9da3b01275a /tools/lli
parent69a8640022b04415ae9fac62f8ab090601d8f889 (diff)
downloadexternal_llvm-36b56886974eae4f9c5ebc96befd3e7bfe5de338.zip
external_llvm-36b56886974eae4f9c5ebc96befd3e7bfe5de338.tar.gz
external_llvm-36b56886974eae4f9c5ebc96befd3e7bfe5de338.tar.bz2
Update to LLVM 3.5a.
Change-Id: Ifadecab779f128e62e430c2b4f6ddd84953ed617
Diffstat (limited to 'tools/lli')
-rw-r--r--tools/lli/CMakeLists.txt18
-rw-r--r--tools/lli/ChildTarget/CMakeLists.txt9
-rw-r--r--tools/lli/ChildTarget/ChildTarget.cpp96
-rw-r--r--tools/lli/ChildTarget/Makefile4
-rw-r--r--tools/lli/ChildTarget/Unix/ChildTarget.inc166
-rw-r--r--tools/lli/ChildTarget/Windows/ChildTarget.inc44
-rw-r--r--tools/lli/RPCChannel.h49
-rw-r--r--tools/lli/RemoteMemoryManager.cpp12
-rw-r--r--tools/lli/RemoteMemoryManager.h42
-rw-r--r--tools/lli/RemoteTarget.cpp39
-rw-r--r--tools/lli/RemoteTarget.h38
-rw-r--r--tools/lli/RemoteTargetExternal.cpp333
-rw-r--r--tools/lli/RemoteTargetExternal.h97
-rw-r--r--tools/lli/RemoteTargetMessage.h54
-rw-r--r--tools/lli/Unix/RPCChannel.inc (renamed from tools/lli/Unix/RemoteTargetExternal.inc)58
-rw-r--r--tools/lli/Windows/RPCChannel.inc29
-rw-r--r--tools/lli/Windows/RemoteTargetExternal.inc35
-rw-r--r--tools/lli/lli.cpp208
18 files changed, 793 insertions, 538 deletions
diff --git a/tools/lli/CMakeLists.txt b/tools/lli/CMakeLists.txt
index 5f8c7c9..731b61a 100644
--- a/tools/lli/CMakeLists.txt
+++ b/tools/lli/CMakeLists.txt
@@ -1,8 +1,19 @@
-
-set(LLVM_LINK_COMPONENTS mcjit jit interpreter nativecodegen bitreader asmparser irreader selectiondag native instrumentation)
-
add_subdirectory(ChildTarget)
+set(LLVM_LINK_COMPONENTS
+ CodeGen
+ Core
+ ExecutionEngine
+ IRReader
+ Instrumentation
+ Interpreter
+ JIT
+ MCJIT
+ SelectionDAG
+ Support
+ native
+ )
+
if( LLVM_USE_OPROFILE )
set(LLVM_LINK_COMPONENTS
${LLVM_LINK_COMPONENTS}
@@ -25,3 +36,4 @@ add_llvm_tool(lli
RemoteTarget.cpp
RemoteTargetExternal.cpp
)
+set_target_properties(lli PROPERTIES ENABLE_EXPORTS 1)
diff --git a/tools/lli/ChildTarget/CMakeLists.txt b/tools/lli/ChildTarget/CMakeLists.txt
index fd1ac24..9f88b2c 100644
--- a/tools/lli/ChildTarget/CMakeLists.txt
+++ b/tools/lli/ChildTarget/CMakeLists.txt
@@ -1,3 +1,8 @@
-add_llvm_tool(lli-child-target
+set(LLVM_LINK_COMPONENTS support)
+
+add_llvm_executable(lli-child-target
ChildTarget.cpp
- )
+ ../RemoteTarget.cpp
+)
+
+set_target_properties(lli-child-target PROPERTIES FOLDER "Misc")
diff --git a/tools/lli/ChildTarget/ChildTarget.cpp b/tools/lli/ChildTarget/ChildTarget.cpp
index 55fcae9..0d71b17 100644
--- a/tools/lli/ChildTarget/ChildTarget.cpp
+++ b/tools/lli/ChildTarget/ChildTarget.cpp
@@ -1,6 +1,8 @@
#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>
@@ -11,36 +13,32 @@ using namespace llvm;
class LLIChildTarget {
public:
- ~LLIChildTarget(); // OS-specific destructor
void initialize();
LLIMessageType waitForIncomingMessage();
void handleMessage(LLIMessageType messageType);
+ RemoteTarget *RT;
+ RPCChannel RPC;
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);
+ void sendLoadStatus(uint32_t Status);
+ void sendExecutionComplete(int 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;
+ 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;
@@ -48,6 +46,7 @@ private:
int main() {
LLIChildTarget ThisChild;
+ ThisChild.RT = new RemoteTarget();
ThisChild.initialize();
LLIMessageType MsgType;
do {
@@ -55,12 +54,13 @@ int main() {
ThisChild.handleMessage(MsgType);
} while (MsgType != LLI_Terminate &&
MsgType != LLI_Error);
+ delete ThisChild.RT;
return 0;
}
// Public methods
void LLIChildTarget::initialize() {
- initializeConnection();
+ RPC.createClient();
sendChildActive();
}
@@ -86,7 +86,7 @@ void LLIChildTarget::handleMessage(LLIMessageType messageType) {
handleExecute();
break;
case LLI_Terminate:
- handleTerminate();
+ RT->stop();
break;
default:
// FIXME: Handle error!
@@ -99,6 +99,7 @@ void LLIChildTarget::handleAllocateSpace() {
// Read and verify the message data size.
uint32_t DataSize;
int rc = ReadBytes(&DataSize, 4);
+ (void)rc;
assert(rc == 4);
assert(DataSize == 8);
@@ -111,7 +112,8 @@ void LLIChildTarget::handleAllocateSpace() {
assert(rc == 4);
// Allocate the memory.
- uint64_t Addr = allocate(Alignment, AllocSize);
+ uint64_t Addr;
+ RT->allocateSpace(AllocSize, Alignment, Addr);
// Send AllocationResult message.
sendAllocationResult(Addr);
@@ -121,33 +123,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 (!RT->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);
+ sys::Memory::InvalidateInstructionCache((void *)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);
@@ -157,22 +162,11 @@ void LLIChildTarget::handleExecute() {
assert(rc == 8);
// Call function
- int Result;
- int (*fn)(void) = (int(*)(void))Addr;
- Result = fn();
+ int32_t Result = -1;
+ RT->executeCode(Addr, Result);
// 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();
+ sendExecutionComplete(Result);
}
// Outgoing message handlers
@@ -180,6 +174,7 @@ 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 +187,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,39 +200,45 @@ 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
-#include "Unix/ChildTarget.inc"
+#include "../Unix/RPCChannel.inc"
#endif
#ifdef LLVM_ON_WIN32
-#include "Windows/ChildTarget.inc"
+#include "../Windows/RPCChannel.inc"
#endif
diff --git a/tools/lli/ChildTarget/Makefile b/tools/lli/ChildTarget/Makefile
index f77b144..6f4ddef 100644
--- a/tools/lli/ChildTarget/Makefile
+++ b/tools/lli/ChildTarget/Makefile
@@ -12,6 +12,8 @@ TOOLNAME := lli-child-target
include $(LEVEL)/Makefile.config
-LINK_COMPONENTS :=
+LINK_COMPONENTS := support
+
+SOURCES := ChildTarget.cpp ../RemoteTarget.cpp
include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/tools/lli/ChildTarget/Unix/ChildTarget.inc b/tools/lli/ChildTarget/Unix/ChildTarget.inc
deleted file mode 100644
index cc95810..0000000
--- a/tools/lli/ChildTarget/Unix/ChildTarget.inc
+++ /dev/null
@@ -1,166 +0,0 @@
-//===- ChildTarget.inc - Child process for external JIT execution for Unix -==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Implementation of the Unix-specific parts of the ChildTarget class
-// which executes JITed code in a separate process from where it was built.
-//
-//===----------------------------------------------------------------------===//
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifdef HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#endif
-
-#ifdef __APPLE__
-#include <mach/mach.h>
-#endif
-
-#if defined(__mips__)
-# if defined(__OpenBSD__)
-# include <mips64/sysarch.h>
-# else
-# include <sys/cachectl.h>
-# endif
-#endif
-
-#ifdef __APPLE__
-extern "C" void sys_icache_invalidate(const void *Addr, size_t len);
-#else
-extern "C" void __clear_cache(void *, void*);
-#endif
-
-namespace {
-
-struct ConnectionData_t {
- int InputPipe;
- int OutputPipe;
-
- ConnectionData_t(int in, int out) : InputPipe(in), OutputPipe(out) {}
-};
-
-} // namespace
-
-LLIChildTarget::~LLIChildTarget() {
- delete static_cast<ConnectionData_t *>(ConnectionData);
-}
-
-// OS-specific methods
-void LLIChildTarget::initializeConnection() {
- // Store the parent ends of the pipes
- ConnectionData = (void*)new ConnectionData_t(STDIN_FILENO, STDOUT_FILENO);
-}
-
-int LLIChildTarget::WriteBytes(const void *Data, size_t Size) {
- return write(((ConnectionData_t*)ConnectionData)->OutputPipe, Data, Size);
-}
-
-int LLIChildTarget::ReadBytes(void *Data, size_t Size) {
- return read(((ConnectionData_t*)ConnectionData)->InputPipe, Data, Size);
-}
-
-// The functions below duplicate functionality that is implemented in
-// Support/Memory.cpp with the goal of avoiding a dependency on any
-// llvm libraries.
-
-uint64_t LLIChildTarget::allocate(uint32_t Alignment, uint32_t Size) {
- if (!Alignment)
- Alignment = 16;
-
- static const size_t PageSize = getpagesize();
- const size_t NumPages = (Size+PageSize-1)/PageSize;
- Size = NumPages*PageSize;
-
- int fd = -1;
-#ifdef NEED_DEV_ZERO_FOR_MMAP
- static int zero_fd = open("/dev/zero", O_RDWR);
- if (zero_fd == -1)
- return 0;
- fd = zero_fd;
-#endif
-
- int MMFlags = MAP_PRIVATE |
-#ifdef HAVE_MMAP_ANONYMOUS
- MAP_ANONYMOUS
-#else
- MAP_ANON
-#endif
- ; // Ends statement above
-
- uint64_t Addr = (uint64_t)::mmap(0, Size, PROT_READ | PROT_WRITE, MMFlags, fd, 0);
- if (Addr == (uint64_t)MAP_FAILED)
- return 0;
-
- // Align the address.
- Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
-
- m_AllocatedBufferMap[Addr] = Size;
-
- // Return aligned address
- return Addr;
-}
-
-void LLIChildTarget::makeSectionExecutable(uint64_t Addr, uint32_t Size) {
- // FIXME: We have to mark the memory as RWX because multiple code chunks may
- // be on the same page. The RemoteTarget interface should be changed to
- // work around that.
- int Result = ::mprotect((void*)Addr, Size, PROT_READ | PROT_WRITE | PROT_EXEC);
- if (Result != 0)
- InvalidateInstructionCache((const void *)Addr, Size);
-}
-
-/// InvalidateInstructionCache - Before the JIT can run a block of code
-/// that has been emitted it must invalidate the instruction cache on some
-/// platforms.
-void LLIChildTarget::InvalidateInstructionCache(const void *Addr,
- size_t Len) {
-
-// icache invalidation for PPC and ARM.
-#if defined(__APPLE__)
-
-# if (defined(__POWERPC__) || defined (__ppc__) || \
- defined(_POWER) || defined(_ARCH_PPC)) || defined(__arm__)
- sys_icache_invalidate(const_cast<void *>(Addr), Len);
-# endif
-
-#else
-
-# if (defined(__POWERPC__) || defined (__ppc__) || \
- defined(_POWER) || defined(_ARCH_PPC)) && defined(__GNUC__)
- const size_t LineSize = 32;
-
- const intptr_t Mask = ~(LineSize - 1);
- const intptr_t StartLine = ((intptr_t) Addr) & Mask;
- const intptr_t EndLine = ((intptr_t) Addr + Len + LineSize - 1) & Mask;
-
- for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize)
- asm volatile("dcbf 0, %0" : : "r"(Line));
- asm volatile("sync");
-
- for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize)
- asm volatile("icbi 0, %0" : : "r"(Line));
- asm volatile("isync");
-# elif defined(__arm__) && defined(__GNUC__)
- // FIXME: Can we safely always call this for __GNUC__ everywhere?
- const char *Start = static_cast<const char *>(Addr);
- const char *End = Start + Len;
- __clear_cache(const_cast<char *>(Start), const_cast<char *>(End));
-# elif defined(__mips__)
- const char *Start = static_cast<const char *>(Addr);
- cacheflush(const_cast<char *>(Start), Len, BCACHE);
-# endif
-
-#endif // end apple
-}
-
-void LLIChildTarget::releaseMemory(uint64_t Addr, uint32_t Size) {
- ::munmap((void*)Addr, Size);
-}
diff --git a/tools/lli/ChildTarget/Windows/ChildTarget.inc b/tools/lli/ChildTarget/Windows/ChildTarget.inc
deleted file mode 100644
index 45db2b0..0000000
--- a/tools/lli/ChildTarget/Windows/ChildTarget.inc
+++ /dev/null
@@ -1,44 +0,0 @@
-//=- ChildTarget.inc - Child process for external JIT execution for Windows -=//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Non-implementation of the Windows-specific parts of the ChildTarget class
-// which executes JITed code in a separate process from where it was built.
-//
-//===----------------------------------------------------------------------===//
-
-LLIChildTarget::~LLIChildTarget() {
-}
-
-// The RemoteTargetExternal implementation should prevent us from ever getting
-// here on Windows, but nothing prevents a user from running this directly.
-void LLIChildTarget::initializeConnection() {
- assert(0 && "lli-child-target is not implemented for Windows");
-}
-
-int LLIChildTarget::WriteBytes(const void *Data, size_t Size) {
- return 0;
-}
-
-int LLIChildTarget::ReadBytes(void *Data, size_t Size) {
- return 0;
-}
-
-uint64_t LLIChildTarget::allocate(uint32_t Alignment, uint32_t Size) {
- return 0;
-}
-
-void LLIChildTarget::makeSectionExecutable(uint64_t Addr, uint32_t Size) {
-}
-
-void LLIChildTarget::InvalidateInstructionCache(const void *Addr,
- size_t Len) {
-}
-
-void LLIChildTarget::releaseMemory(uint64_t Addr, uint32_t Size) {
-}
diff --git a/tools/lli/RPCChannel.h b/tools/lli/RPCChannel.h
new file mode 100644
index 0000000..2d8c708
--- /dev/null
+++ b/tools/lli/RPCChannel.h
@@ -0,0 +1,49 @@
+//===---------- RPCChannel.h - 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// Definition of the RemoteTargetExternal class which executes JITed code in a
+// separate process from where it was built.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLI_RPCCHANNEL_H
+#define LLI_RPCCHANNEL_H
+
+#include <stdlib.h>
+#include <string>
+
+namespace llvm {
+
+class RPCChannel {
+public:
+ std::string ChildName;
+
+ RPCChannel() {}
+ ~RPCChannel();
+
+ /// Start the remote process.
+ ///
+ /// @returns True on success. On failure, ErrorMsg is updated with
+ /// descriptive text of the encountered error.
+ bool createServer();
+
+ bool createClient();
+
+ // This will get filled in as a point to an OS-specific structure.
+ void *ConnectionData;
+
+ bool WriteBytes(const void *Data, size_t Size);
+ bool ReadBytes(void *Data, size_t Size);
+
+ void Wait();
+};
+
+} // end namespace llvm
+
+#endif // LLI_RPCCHANNEL_H
diff --git a/tools/lli/RemoteMemoryManager.cpp b/tools/lli/RemoteMemoryManager.cpp
index 04fc40e..e9f4d53 100644
--- a/tools/lli/RemoteMemoryManager.cpp
+++ b/tools/lli/RemoteMemoryManager.cpp
@@ -109,7 +109,7 @@ void RemoteMemoryManager::notifyObjectLoaded(ExecutionEngine *EE,
CurOffset += Size;
}
}
- // Adjust to keep code and data aligned on seperate pages.
+ // Adjust to keep code and data aligned on separate pages.
CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign;
for (size_t i = 0, e = NumSections; i != e; ++i) {
Allocation &Section = UnmappedSections[i];
@@ -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/RemoteMemoryManager.h b/tools/lli/RemoteMemoryManager.h
index 5d0456f..11f600f 100644
--- a/tools/lli/RemoteMemoryManager.h
+++ b/tools/lli/RemoteMemoryManager.h
@@ -15,6 +15,7 @@
#ifndef REMOTEMEMORYMANAGER_H
#define REMOTEMEMORYMANAGER_H
+#include "RemoteTarget.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ExecutionEngine/JITMemoryManager.h"
@@ -22,8 +23,6 @@
#include "llvm/Support/Memory.h"
#include <utility>
-#include "RemoteTarget.h"
-
namespace llvm {
class RemoteMemoryManager : public JITMemoryManager {
@@ -68,45 +67,48 @@ public:
virtual ~RemoteMemoryManager();
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
- unsigned SectionID, StringRef SectionName);
+ unsigned SectionID,
+ StringRef SectionName) override;
uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID, StringRef SectionName,
- bool IsReadOnly);
+ bool IsReadOnly) override;
// For now, remote symbol resolution is not support in lli. The MCJIT
// interface does support this, but clients must provide their own
// mechanism for finding remote symbol addresses. MCJIT will resolve
// symbols from Modules it contains.
- uint64_t getSymbolAddress(const std::string &Name) { return 0; }
+ uint64_t getSymbolAddress(const std::string &Name) override { return 0; }
- void notifyObjectLoaded(ExecutionEngine *EE, const ObjectImage *Obj);
+ void notifyObjectLoaded(ExecutionEngine *EE, const ObjectImage *Obj) override;
- bool finalizeMemory(std::string *ErrMsg);
+ bool finalizeMemory(std::string *ErrMsg) override;
// For now, remote EH frame registration isn't supported. Remote symbol
// resolution is a prerequisite to supporting remote EH frame registration.
- void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) {}
- void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) {}
+ void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
+ size_t Size) override {}
+ void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr,
+ size_t Size) override {}
// This is a non-interface function used by lli
void setRemoteTarget(RemoteTarget *T) { Target = T; }
// The following obsolete JITMemoryManager calls are stubbed out for
// this model.
- void setMemoryWritable();
- void setMemoryExecutable();
- void setPoisonMemory(bool poison);
- void AllocateGOT();
- uint8_t *getGOTBase() const;
- uint8_t *startFunctionBody(const Function *F, uintptr_t &ActualSize);
+ void setMemoryWritable() override;
+ void setMemoryExecutable() override;
+ void setPoisonMemory(bool poison) override;
+ void AllocateGOT() override;
+ uint8_t *getGOTBase() const override;
+ uint8_t *startFunctionBody(const Function *F, uintptr_t &ActualSize) override;
uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize,
- unsigned Alignment);
+ unsigned Alignment) override;
void endFunctionBody(const Function *F, uint8_t *FunctionStart,
- uint8_t *FunctionEnd);
- uint8_t *allocateSpace(intptr_t Size, unsigned Alignment);
- uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment);
- void deallocateFunctionBody(void *Body);
+ uint8_t *FunctionEnd) override;
+ uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) override;
+ uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) override;
+ void deallocateFunctionBody(void *Body) override;
};
} // end namespace llvm
diff --git a/tools/lli/RemoteTarget.cpp b/tools/lli/RemoteTarget.cpp
index 5c74e6e..55fc064 100644
--- a/tools/lli/RemoteTarget.cpp
+++ b/tools/lli/RemoteTarget.cpp
@@ -13,7 +13,6 @@
//===----------------------------------------------------------------------===//
#include "RemoteTarget.h"
-#include "RemoteTargetExternal.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Memory.h"
@@ -22,28 +21,6 @@
using namespace llvm;
-// Static methods
-RemoteTarget *RemoteTarget::createRemoteTarget() {
- return new RemoteTarget;
-}
-
-RemoteTarget *RemoteTarget::createExternalRemoteTarget(std::string &ChildName) {
-#ifdef LLVM_ON_UNIX
- return new RemoteTargetExternal(ChildName);
-#else
- return 0;
-#endif
-}
-
-bool RemoteTarget::hostSupportsExternalRemoteTarget() {
-#ifdef LLVM_ON_UNIX
- return true;
-#else
- return false;
-#endif
-}
-
-
////////////////////////////////////////////////////////////////////////////////
// Simulated remote execution
//
@@ -56,34 +33,36 @@ 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;
+ Allocations.push_back(Mem);
+ 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 c95fbd1..73e8ae2 100644
--- a/tools/lli/RemoteTarget.h
+++ b/tools/lli/RemoteTarget.h
@@ -25,10 +25,13 @@
namespace llvm {
class RemoteTarget {
- std::string ErrorMsg;
bool IsRunning;
- SmallVector<sys::MemoryBlock, 16> Allocations;
+ typedef SmallVector<sys::MemoryBlock, 16> AllocMapType;
+ AllocMapType Allocations;
+
+protected:
+ std::string ErrorMsg;
public:
StringRef getErrorMsg() const { return ErrorMsg; }
@@ -39,19 +42,31 @@ 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,
uint64_t &Address);
+ bool isAllocatedMemory(uint64_t Address, uint32_t Size) {
+ uint64_t AddressEnd = Address + Size;
+ for (AllocMapType::const_iterator I = Allocations.begin(),
+ E = Allocations.end();
+ I != E; ++I) {
+ if (Address >= (uint64_t)I->base() &&
+ AddressEnd <= (uint64_t)I->base() + I->size())
+ return true;
+ }
+ return false;
+ }
+
/// Load data into the target address space.
///
/// @param Address Destination address in the target process.
/// @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 +78,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,12 +91,12 @@ 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);
- /// Minimum alignment for memory permissions. Used to seperate code and
+ /// Minimum alignment for memory permissions. Used to separate code and
/// data regions to make sure data doesn't get marked as code or vice
/// versa.
///
@@ -89,18 +104,13 @@ 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.
- static RemoteTarget *createRemoteTarget();
- static RemoteTarget *createExternalRemoteTarget(std::string &ChildName);
- static bool hostSupportsExternalRemoteTarget();
private:
// Main processing function for the remote target process. Command messages
// are received on file descriptor CmdFD and responses come back on OutFD.
diff --git a/tools/lli/RemoteTargetExternal.cpp b/tools/lli/RemoteTargetExternal.cpp
index 742a948..c1bc8df 100644
--- a/tools/lli/RemoteTargetExternal.cpp
+++ b/tools/lli/RemoteTargetExternal.cpp
@@ -13,12 +13,12 @@
//===----------------------------------------------------------------------===//
#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"
@@ -28,135 +28,298 @@ 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() {
SendTerminate();
- Wait();
+ RPC.Wait();
}
-void RemoteTargetExternal::SendAllocateSpace(uint32_t Alignment, uint32_t Size) {
- int rc;
- uint32_t MsgType = (uint32_t)LLI_AllocateSpace;
- rc = WriteBytes(&MsgType, 4);
- assert(rc == 4 && "Error writing message type.");
+bool RemoteTargetExternal::SendAllocateSpace(uint32_t Alignment, uint32_t Size) {
+ if (!SendHeader(LLI_AllocateSpace)) {
+ ErrorMsg += ", (RemoteTargetExternal::SendAllocateSpace)";
+ return false;
+ }
- uint32_t DataSize = 8;
- rc = WriteBytes(&DataSize, 4);
- assert(rc == 4 && "Error writing data size.");
+ AppendWrite((const void *)&Alignment, 4);
+ AppendWrite((const void *)&Size, 4);
- rc = WriteBytes(&Alignment, 4);
- assert(rc == 4 && "Error writing alignment data.");
-
- 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;
- uint32_t MsgType = IsCode ? LLI_LoadCodeSection : LLI_LoadDataSection;
- rc = WriteBytes(&MsgType, 4);
- assert(rc == 4 && "Error writing message type.");
+ 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;
+}
- uint32_t DataSize = Size + 8;
- rc = WriteBytes(&DataSize, 4);
- assert(rc == 4 && "Error writing data size.");
+bool RemoteTargetExternal::SendExecute(uint64_t Addr) {
+ if (!SendHeader(LLI_Execute)) {
+ ErrorMsg += ", (RemoteTargetExternal::SendExecute)";
+ return false;
+ }
- rc = WriteBytes(&Addr, 8);
- assert(rc == 8 && "Error writing data.");
+ AppendWrite((const void *)&Addr, 8);
- rc = WriteBytes(Data, Size);
- assert(rc == (int)Size && "Error writing data.");
+ if (!SendPayload()) {
+ ErrorMsg += ", (RemoteTargetExternal::SendExecute)";
+ return false;
+ }
+ return true;
}
-void RemoteTargetExternal::SendExecute(uint64_t Addr) {
- int rc;
- uint32_t MsgType = (uint32_t)LLI_Execute;
- 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::SendTerminate() {
+ return SendHeader(LLI_Terminate);
+ // No data or data size is sent with Terminate
+}
- rc = WriteBytes(&Addr, 8);
- assert(rc == 8 && "Error writing data.");
+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;
}
-void RemoteTargetExternal::SendTerminate() {
- int rc;
- uint32_t MsgType = (uint32_t)LLI_Terminate;
- rc = WriteBytes(&MsgType, 4);
- assert(rc == 4 && "Error writing message type.");
+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;
+}
- // No data or data size is sent with Terminate
+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");
-void RemoteTargetExternal::Receive(LLIMessageType ExpectedMsgType) {
- int rc;
+ // 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;
- 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 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;
+}
- uint32_t DataSize;
- rc = ReadBytes(&DataSize, 4);
- assert(rc == 4 && "Error reading data size.");
- assert(DataSize == 8 && "Error: unexpected data size.");
+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
-#include "Unix/RemoteTargetExternal.inc"
+#include "Unix/RPCChannel.inc"
#endif
#ifdef LLVM_ON_WIN32
-#include "Windows/RemoteTargetExternal.inc"
+#include "Windows/RPCChannel.inc"
#endif
diff --git a/tools/lli/RemoteTargetExternal.h b/tools/lli/RemoteTargetExternal.h
index a4bfad2..f87fc61 100644
--- a/tools/lli/RemoteTargetExternal.h
+++ b/tools/lli/RemoteTargetExternal.h
@@ -15,21 +15,28 @@
#ifndef LLI_REMOTETARGETEXTERNAL_H
#define LLI_REMOTETARGETEXTERNAL_H
-#include "llvm/Config/config.h"
-
+#include "RPCChannel.h"
+#include "RemoteTarget.h"
+#include "RemoteTargetMessage.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Config/config.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Memory.h"
#include <stdlib.h>
#include <string>
-#include "RemoteTarget.h"
-#include "RemoteTargetMessage.h"
-
namespace llvm {
class RemoteTargetExternal : public RemoteTarget {
+ RPCChannel RPC;
+
+ bool WriteBytes(const void *Data, size_t Size) {
+ return RPC.WriteBytes(Data, Size);
+ }
+
+ bool ReadBytes(void *Data, size_t Size) { return RPC.ReadBytes(Data, Size); }
+
public:
/// Allocate space in the remote target address space.
///
@@ -37,11 +44,10 @@ 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,
- uint64_t &Address);
+ bool allocateSpace(size_t Size, unsigned Alignment,
+ uint64_t &Address) override;
/// Load data into the target address space.
///
@@ -49,9 +55,9 @@ 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);
+ bool loadData(uint64_t Address, const void *Data, size_t Size) override;
/// Load code into the target address space and prepare it for execution.
///
@@ -59,9 +65,9 @@ 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);
+ bool loadCode(uint64_t Address, const void *Data, size_t Size) override;
/// Execute code in the target process. The called function is required
/// to be of signature int "(*)(void)".
@@ -70,47 +76,66 @@ 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);
+ bool executeCode(uint64_t Address, int &RetVal) override;
- /// Minimum alignment for memory permissions. Used to seperate code and
+ /// Minimum alignment for memory permissions. Used to separate code and
/// data regions to make sure data doesn't get marked as code or vice
/// versa.
///
/// @returns Page alignment return value. Default of 4k.
- virtual unsigned getPageAlignment() { return 4096; }
+ unsigned getPageAlignment() override { return 4096; }
+
+ bool create() override {
+ RPC.ChildName = ChildName;
+ if (!RPC.createServer())
+ return true;
- /// Start the remote process.
- virtual void create();
+ // We must get Ack from the client (blocking read)
+ if (!Receive(LLI_ChildActive)) {
+ ErrorMsg += ", (RPCChannel::create) - Stopping process!";
+ stop();
+ return false;
+ }
+
+ return true;
+ }
/// Terminate the remote process.
- virtual void stop();
+ void stop() override;
RemoteTargetExternal(std::string &Name) : RemoteTarget(), ChildName(Name) {}
- virtual ~RemoteTargetExternal();
+ virtual ~RemoteTargetExternal() {}
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();
-
- void Receive(LLIMessageType Msg);
- void Receive(LLIMessageType Msg, int &Data);
- void Receive(LLIMessageType Msg, uint64_t &Data);
-
- int WriteBytes(const void *Data, size_t Size);
- int ReadBytes(void *Data, size_t Size);
- void Wait();
+ 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);
};
} // end namespace llvm
diff --git a/tools/lli/RemoteTargetMessage.h b/tools/lli/RemoteTargetMessage.h
index 12cfa9a..cb934a1 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/RPCChannel.inc
index 9c1a4cc..4d245d6 100644
--- a/tools/lli/Unix/RemoteTargetExternal.inc
+++ b/tools/lli/Unix/RPCChannel.inc
@@ -1,4 +1,4 @@
-//=- RemoteTargetExternal.inc - LLVM out-of-process JIT execution for Unix --=//
+//=- RPCChannel.inc - LLVM out-of-process JIT execution for Unix --=//
//
// The LLVM Compiler Infrastructure
//
@@ -7,15 +7,17 @@
//
//===----------------------------------------------------------------------===//
//
-// Implementation of the Unix-specific parts of the RemoteTargetExternal class
+// Implementation of the Unix-specific parts of the RPCChannel class
// which executes JITed code in a separate process from where it was built.
//
//===----------------------------------------------------------------------===//
-#include <unistd.h>
+#include "llvm/Support/Errno.h"
+#include "llvm/Support/raw_ostream.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
+#include <unistd.h>
namespace {
@@ -30,7 +32,7 @@ struct ConnectionData_t {
namespace llvm {
-void RemoteTargetExternal::create() {
+bool RPCChannel::createServer() {
int PipeFD[2][2];
pid_t ChildPID;
@@ -62,8 +64,7 @@ void RemoteTargetExternal::create() {
int rc = execv(ChildName.c_str(), args);
if (rc != 0)
perror("Error executing child process: ");
- }
- else {
+ } else {
// In the parent...
// Close the child ends of the pipes
@@ -71,25 +72,50 @@ void RemoteTargetExternal::create() {
close(PipeFD[1][1]);
// Store the parent ends of the pipes
- ConnectionData = (void*)new ConnectionData_t(PipeFD[1][0], PipeFD[0][1]);
-
- Receive(LLI_ChildActive);
+ ConnectionData = (void *)new ConnectionData_t(PipeFD[1][0], PipeFD[0][1]);
+ return true;
}
+ return false;
}
-int RemoteTargetExternal::WriteBytes(const void *Data, size_t Size) {
- return write(((ConnectionData_t*)ConnectionData)->OutputPipe, Data, Size);
+bool RPCChannel::createClient() {
+ // Store the parent ends of the pipes
+ ConnectionData = (void *)new ConnectionData_t(STDIN_FILENO, STDOUT_FILENO);
+ return true;
+}
+
+void RPCChannel::Wait() { wait(NULL); }
+
+static bool CheckError(int rc, size_t Size, const char *Desc) {
+ if (rc < 0) {
+ llvm::errs() << "IO Error: " << Desc << ": " << sys::StrError() << '\n';
+ return false;
+ } else if ((size_t)rc != Size) {
+ std::string ErrorMsg;
+ char Number[10] = { 0 };
+ ErrorMsg += "Expecting ";
+ sprintf(Number, "%d", (uint32_t)Size);
+ ErrorMsg += Number;
+ ErrorMsg += " bytes, Got ";
+ sprintf(Number, "%d", rc);
+ ErrorMsg += Number;
+ llvm::errs() << "RPC Error: " << Desc << ": " << ErrorMsg << '\n';
+ return false;
+ }
+ return true;
}
-int RemoteTargetExternal::ReadBytes(void *Data, size_t Size) {
- return read(((ConnectionData_t*)ConnectionData)->InputPipe, Data, Size);
+bool RPCChannel::WriteBytes(const void *Data, size_t Size) {
+ int rc = write(((ConnectionData_t *)ConnectionData)->OutputPipe, Data, Size);
+ return CheckError(rc, Size, "WriteBytes");
}
-void RemoteTargetExternal::Wait() {
- wait(NULL);
+bool RPCChannel::ReadBytes(void *Data, size_t Size) {
+ int rc = read(((ConnectionData_t *)ConnectionData)->InputPipe, Data, Size);
+ return CheckError(rc, Size, "ReadBytes");
}
-RemoteTargetExternal::~RemoteTargetExternal() {
+RPCChannel::~RPCChannel() {
delete static_cast<ConnectionData_t *>(ConnectionData);
}
diff --git a/tools/lli/Windows/RPCChannel.inc b/tools/lli/Windows/RPCChannel.inc
new file mode 100644
index 0000000..82f2acb
--- /dev/null
+++ b/tools/lli/Windows/RPCChannel.inc
@@ -0,0 +1,29 @@
+//=- RPCChannel.inc - LLVM out-of-process JIT execution for Windows --=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of the Windows-specific parts of the RPCChannel class
+// which executes JITed code in a separate process from where it was built.
+//
+//===----------------------------------------------------------------------===//
+
+namespace llvm {
+
+bool RPCChannel::createServer() { return false; }
+
+bool RPCChannel::createClient() { return false; }
+
+bool RPCChannel::WriteBytes(const void *Data, size_t Size) { return false; }
+
+bool RPCChannel::ReadBytes(void *Data, size_t Size) { return false; }
+
+void RPCChannel::Wait() {}
+
+RPCChannel::~RPCChannel() {}
+
+} // namespace llvm
diff --git a/tools/lli/Windows/RemoteTargetExternal.inc b/tools/lli/Windows/RemoteTargetExternal.inc
deleted file mode 100644
index aef4627..0000000
--- a/tools/lli/Windows/RemoteTargetExternal.inc
+++ /dev/null
@@ -1,35 +0,0 @@
-//= RemoteTargetExternal.inc - LLVM out-of-process JIT execution for Windows =//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Definition of the Windows-specific parts of the RemoteTargetExternal class
-// which is meant to execute JITed code in a separate process from where it was
-// built. To support this functionality on Windows, implement these functions.
-//
-//===----------------------------------------------------------------------===//
-
-namespace llvm {
-
-void RemoteTargetExternal::create() {
-}
-
-int RemoteTargetExternal::WriteBytes(const void *Data, size_t Size) {
- return 0;
-}
-
-int RemoteTargetExternal::ReadBytes(void *Data, size_t Size) {
- return 0;
-}
-
-void RemoteTargetExternal::Wait() {
-}
-
-RemoteTargetExternal::~RemoteTargetExternal() {
-}
-
-} // namespace llvm
diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp
index f317566..c0c0f9d 100644
--- a/tools/lli/lli.cpp
+++ b/tools/lli/lli.cpp
@@ -17,6 +17,7 @@
#include "llvm/IR/LLVMContext.h"
#include "RemoteMemoryManager.h"
#include "RemoteTarget.h"
+#include "RemoteTargetExternal.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/CodeGen/LinkAllCodegenComponents.h"
@@ -26,12 +27,15 @@
#include "llvm/ExecutionEngine/JITEventListener.h"
#include "llvm/ExecutionEngine/JITMemoryManager.h"
#include "llvm/ExecutionEngine/MCJIT.h"
+#include "llvm/ExecutionEngine/ObjectCache.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/TypeBuilder.h"
#include "llvm/IRReader/IRReader.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/DynamicLibrary.h"
@@ -91,12 +95,11 @@ namespace {
// execution. The child process will be executed and will communicate with
// lli via stdin/stdout pipes.
cl::opt<std::string>
- MCJITRemoteProcess("mcjit-remote-process",
- cl::desc("Specify the filename of the process to launch "
- "for remote MCJIT execution. If none is specified,"
- "\n\tremote execution will be simulated in-process."),
- cl::value_desc("filename"),
- cl::init(""));
+ ChildExecPath("mcjit-remote-process",
+ cl::desc("Specify the filename of the process to launch "
+ "for remote MCJIT execution. If none is specified,"
+ "\n\tremote execution will be simulated in-process."),
+ cl::value_desc("filename"), cl::init(""));
// Determine optimization level.
cl::opt<char>
@@ -138,6 +141,27 @@ namespace {
cl::desc("Extra modules to be loaded"),
cl::value_desc("input bitcode"));
+ cl::list<std::string>
+ ExtraObjects("extra-object",
+ cl::desc("Extra object files to be loaded"),
+ cl::value_desc("input object"));
+
+ cl::list<std::string>
+ ExtraArchives("extra-archive",
+ cl::desc("Extra archive files to be loaded"),
+ cl::value_desc("input archive"));
+
+ cl::opt<bool>
+ EnableCacheManager("enable-cache-manager",
+ cl::desc("Use cache manager to save/load mdoules"),
+ cl::init(false));
+
+ cl::opt<std::string>
+ ObjectCacheDir("object-cache-dir",
+ cl::desc("Directory to store cached object files "
+ "(must be user writable)"),
+ cl::init(""));
+
cl::opt<std::string>
FakeArgv0("fake-argv0",
cl::desc("Override the 'argv[0]' value passed into the executing"
@@ -219,12 +243,91 @@ namespace {
cl::init(false));
}
+//===----------------------------------------------------------------------===//
+// Object cache
+//
+// This object cache implementation writes cached objects to disk to the
+// directory specified by CacheDir, using a filename provided in the module
+// descriptor. The cache tries to load a saved object using that path if the
+// file exists. CacheDir defaults to "", in which case objects are cached
+// alongside their originating bitcodes.
+//
+class LLIObjectCache : public ObjectCache {
+public:
+ LLIObjectCache(const std::string& CacheDir) : CacheDir(CacheDir) {
+ // Add trailing '/' to cache dir if necessary.
+ if (!this->CacheDir.empty() &&
+ this->CacheDir[this->CacheDir.size() - 1] != '/')
+ this->CacheDir += '/';
+ }
+ virtual ~LLIObjectCache() {}
+
+ void notifyObjectCompiled(const Module *M, const MemoryBuffer *Obj) override {
+ const std::string ModuleID = M->getModuleIdentifier();
+ std::string CacheName;
+ if (!getCacheFilename(ModuleID, CacheName))
+ return;
+ std::string errStr;
+ if (!CacheDir.empty()) { // Create user-defined cache dir.
+ SmallString<128> dir(CacheName);
+ sys::path::remove_filename(dir);
+ sys::fs::create_directories(Twine(dir));
+ }
+ raw_fd_ostream outfile(CacheName.c_str(), errStr, sys::fs::F_None);
+ outfile.write(Obj->getBufferStart(), Obj->getBufferSize());
+ outfile.close();
+ }
+
+ MemoryBuffer* getObject(const Module* M) override {
+ const std::string ModuleID = M->getModuleIdentifier();
+ std::string CacheName;
+ if (!getCacheFilename(ModuleID, CacheName))
+ return NULL;
+ // Load the object from the cache filename
+ std::unique_ptr<MemoryBuffer> IRObjectBuffer;
+ MemoryBuffer::getFile(CacheName.c_str(), IRObjectBuffer, -1, false);
+ // If the file isn't there, that's OK.
+ if (!IRObjectBuffer)
+ return NULL;
+ // MCJIT will want to write into this buffer, and we don't want that
+ // because the file has probably just been mmapped. Instead we make
+ // a copy. The filed-based buffer will be released when it goes
+ // out of scope.
+ return MemoryBuffer::getMemBufferCopy(IRObjectBuffer->getBuffer());
+ }
+
+private:
+ std::string CacheDir;
+
+ bool getCacheFilename(const std::string &ModID, std::string &CacheName) {
+ std::string Prefix("file:");
+ size_t PrefixLength = Prefix.length();
+ if (ModID.substr(0, PrefixLength) != Prefix)
+ return false;
+ std::string CacheSubdir = ModID.substr(PrefixLength);
+#if defined(_WIN32)
+ // Transform "X:\foo" => "/X\foo" for convenience.
+ if (isalpha(CacheSubdir[0]) && CacheSubdir[1] == ':') {
+ CacheSubdir[1] = CacheSubdir[0];
+ CacheSubdir[0] = '/';
+ }
+#endif
+ CacheName = CacheDir + CacheSubdir;
+ size_t pos = CacheName.rfind('.');
+ CacheName.replace(pos, CacheName.length() - pos, ".o");
+ return true;
+ }
+};
+
static ExecutionEngine *EE = 0;
+static LLIObjectCache *CacheManager = 0;
static void do_shutdown() {
// Cygwin-1.5 invokes DLL's dtors before atexit handler.
#ifndef DO_NOTHING_ATEXIT
delete EE;
+ if (CacheManager)
+ delete CacheManager;
llvm_shutdown();
#endif
}
@@ -300,12 +403,20 @@ int main(int argc, char **argv, char * const *envp) {
return 1;
}
+ if (EnableCacheManager) {
+ if (UseMCJIT) {
+ std::string CacheName("file:");
+ CacheName.append(InputFile);
+ Mod->setModuleIdentifier(CacheName);
+ } else
+ errs() << "warning: -enable-cache-manager can only be used with MCJIT.";
+ }
+
// If not jitting lazily, load the whole bitcode file eagerly too.
- std::string ErrorMsg;
if (NoLazyCompilation) {
- if (Mod->MaterializeAllPermanently(&ErrorMsg)) {
+ if (error_code EC = Mod->materializeAllPermanently()) {
errs() << argv[0] << ": bitcode didn't read correctly.\n";
- errs() << "Reason: " << ErrorMsg << "\n";
+ errs() << "Reason: " << EC.message() << "\n";
exit(1);
}
}
@@ -321,6 +432,7 @@ int main(int argc, char **argv, char * const *envp) {
DebugIRPass->runOnModule(*Mod);
}
+ std::string ErrorMsg;
EngineBuilder builder(Mod);
builder.setMArch(MArch);
builder.setMCPU(MCPU);
@@ -391,6 +503,11 @@ int main(int argc, char **argv, char * const *envp) {
exit(1);
}
+ if (EnableCacheManager) {
+ CacheManager = new LLIObjectCache(ObjectCacheDir);
+ EE->setObjectCache(CacheManager);
+ }
+
// Load any additional modules specified on the command line.
for (unsigned i = 0, e = ExtraModules.size(); i != e; ++i) {
Module *XMod = ParseIRFile(ExtraModules[i], Err, Context);
@@ -398,9 +515,43 @@ int main(int argc, char **argv, char * const *envp) {
Err.print(argv[0], errs());
return 1;
}
+ if (EnableCacheManager) {
+ if (UseMCJIT) {
+ std::string CacheName("file:");
+ CacheName.append(ExtraModules[i]);
+ XMod->setModuleIdentifier(CacheName);
+ }
+ // else, we already printed a warning above.
+ }
EE->addModule(XMod);
}
+ for (unsigned i = 0, e = ExtraObjects.size(); i != e; ++i) {
+ ErrorOr<object::ObjectFile *> Obj =
+ object::ObjectFile::createObjectFile(ExtraObjects[i]);
+ if (!Obj) {
+ Err.print(argv[0], errs());
+ return 1;
+ }
+ EE->addObjectFile(Obj.get());
+ }
+
+ for (unsigned i = 0, e = ExtraArchives.size(); i != e; ++i) {
+ std::unique_ptr<MemoryBuffer> ArBuf;
+ error_code ec;
+ ec = MemoryBuffer::getFileOrSTDIN(ExtraArchives[i], ArBuf);
+ if (ec) {
+ Err.print(argv[0], errs());
+ return 1;
+ }
+ object::Archive *Ar = new object::Archive(ArBuf.release(), ec);
+ if (ec || !Ar) {
+ Err.print(argv[0], errs());
+ return 1;
+ }
+ EE->addArchive(Ar);
+ }
+
// If the target is Cygwin/MingW and we are generating remote code, we
// need an extra module to help out with linking.
if (RemoteMCJIT && Triple(Mod->getTargetTriple()).isOSCygMing()) {
@@ -472,7 +623,7 @@ int main(int argc, char **argv, char * const *envp) {
}
}
- // Trigger compilation separately so code regions that need to be
+ // Trigger compilation separately so code regions that need to be
// invalidated will be known.
(void)EE->getPointerToFunction(EntryFn);
// Clear instruction cache before code will be executed.
@@ -511,30 +662,35 @@ int main(int argc, char **argv, char * const *envp) {
// address space, assign the section addresses to resolve any relocations,
// and send it to the target.
- OwningPtr<RemoteTarget> Target;
- if (!MCJITRemoteProcess.empty()) { // Remote execution on a child process
- if (!RemoteTarget::hostSupportsExternalRemoteTarget()) {
- errs() << "Warning: host does not support external remote targets.\n"
- << " Defaulting to simulated remote execution\n";
- Target.reset(RemoteTarget::createRemoteTarget());
- } else {
- std::string ChildEXE = sys::FindProgramByName(MCJITRemoteProcess);
- if (ChildEXE == "") {
- errs() << "Unable to find child target: '\''" << MCJITRemoteProcess << "\'\n";
- return -1;
- }
- Target.reset(RemoteTarget::createExternalRemoteTarget(ChildEXE));
+ std::unique_ptr<RemoteTarget> Target;
+ if (!ChildExecPath.empty()) { // Remote execution on a child process
+#ifndef LLVM_ON_UNIX
+ // FIXME: Remove this pointless fallback mode which causes tests to "pass"
+ // on platforms where they should XFAIL.
+ errs() << "Warning: host does not support external remote targets.\n"
+ << " Defaulting to simulated remote execution\n";
+ Target.reset(new RemoteTarget);
+#else
+ if (!sys::fs::can_execute(ChildExecPath)) {
+ errs() << "Unable to find usable child executable: '" << ChildExecPath
+ << "'\n";
+ return -1;
}
+ Target.reset(new RemoteTargetExternal(ChildExecPath));
+#endif
} else {
// No child process name provided, use simulated remote execution.
- Target.reset(RemoteTarget::createRemoteTarget());
+ Target.reset(new RemoteTarget);
}
// Give the memory manager a pointer to our remote target interface object.
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
@@ -551,7 +707,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