[llvm] [ORC] Add read operations to orc::MemoryAccess. (PR #145834)
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 26 02:15:49 PDT 2025
https://github.com/lhames updated https://github.com/llvm/llvm-project/pull/145834
>From ab81b22af899c7c5e0c0be5a3512f543f59df708 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Thu, 26 Jun 2025 11:07:11 +1000
Subject: [PATCH] [ORC] Add read operations to orc::MemoryAccess.
This commit adds operations to orc::MemoryAccess for reading basic types
(uint8_t, uint16_t, uint32_t, uint64_t, pointers, buffers, and strings) from
executor memory.
The InProcessMemoryAccess and EPCGenericMemoryAccess implementations are
updated to support the new operations.
---
.../Orc/EPCGenericMemoryAccess.h | 129 ++++++-
.../Orc/InProcessMemoryAccess.h | 25 +-
.../llvm/ExecutionEngine/Orc/MemoryAccess.h | 110 +++++-
.../ExecutionEngine/Orc/Shared/OrcRTBridge.h | 10 +-
.../Orc/Shared/TargetProcessControlTypes.h | 4 +-
.../Orc/InProcessMemoryAccess.cpp | 84 +++-
.../Orc/Shared/OrcRTBridge.cpp | 19 +-
.../ExecutionEngine/Orc/SimpleRemoteEPC.cpp | 8 +-
.../Orc/TargetProcess/OrcRTBootstrap.cpp | 100 ++++-
.../Orc/EPCGenericMemoryAccessTest.cpp | 364 ++++++++++++++----
10 files changed, 748 insertions(+), 105 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h
index e1815e4d303ad..c69b6f736651e 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h
@@ -31,8 +31,15 @@ class EPCGenericMemoryAccess : public MemoryAccess {
ExecutorAddr WriteUInt16s;
ExecutorAddr WriteUInt32s;
ExecutorAddr WriteUInt64s;
- ExecutorAddr WriteBuffers;
ExecutorAddr WritePointers;
+ ExecutorAddr WriteBuffers;
+ ExecutorAddr ReadUInt8s;
+ ExecutorAddr ReadUInt16s;
+ ExecutorAddr ReadUInt32s;
+ ExecutorAddr ReadUInt64s;
+ ExecutorAddr ReadPointers;
+ ExecutorAddr ReadBuffers;
+ ExecutorAddr ReadStrings;
};
/// Create an EPCGenericMemoryAccess instance from a given set of
@@ -68,6 +75,13 @@ class EPCGenericMemoryAccess : public MemoryAccess {
FAs.WriteUInt64s, std::move(OnWriteComplete), Ws);
}
+ void writePointersAsync(ArrayRef<tpctypes::PointerWrite> Ws,
+ WriteResultFn OnWriteComplete) override {
+ using namespace shared;
+ EPC.callSPSWrapperAsync<void(SPSSequence<SPSMemoryAccessPointerWrite>)>(
+ FAs.WritePointers, std::move(OnWriteComplete), Ws);
+ }
+
void writeBuffersAsync(ArrayRef<tpctypes::BufferWrite> Ws,
WriteResultFn OnWriteComplete) override {
using namespace shared;
@@ -75,11 +89,116 @@ class EPCGenericMemoryAccess : public MemoryAccess {
FAs.WriteBuffers, std::move(OnWriteComplete), Ws);
}
- void writePointersAsync(ArrayRef<tpctypes::PointerWrite> Ws,
- WriteResultFn OnWriteComplete) override {
+ void readUInt8sAsync(ArrayRef<ExecutorAddr> Rs,
+ OnReadUIntsCompleteFn<uint8_t> OnComplete) override {
using namespace shared;
- EPC.callSPSWrapperAsync<void(SPSSequence<SPSMemoryAccessPointerWrite>)>(
- FAs.WritePointers, std::move(OnWriteComplete), Ws);
+ EPC.callSPSWrapperAsync<SPSSequence<uint8_t>(SPSSequence<SPSExecutorAddr>)>(
+ FAs.ReadUInt8s,
+ [OnComplete = std::move(OnComplete)](
+ Error Err, ReadUIntsResult<uint8_t> Result) mutable {
+ if (Err)
+ OnComplete(std::move(Err));
+ else
+ OnComplete(std::move(Result));
+ },
+ Rs);
+ }
+
+ void readUInt16sAsync(ArrayRef<ExecutorAddr> Rs,
+ OnReadUIntsCompleteFn<uint16_t> OnComplete) override {
+ using namespace shared;
+ EPC.callSPSWrapperAsync<SPSSequence<uint16_t>(
+ SPSSequence<SPSExecutorAddr>)>(
+ FAs.ReadUInt16s,
+ [OnComplete = std::move(OnComplete)](
+ Error Err, ReadUIntsResult<uint16_t> Result) mutable {
+ if (Err)
+ OnComplete(std::move(Err));
+ else
+ OnComplete(std::move(Result));
+ },
+ Rs);
+ }
+
+ void readUInt32sAsync(ArrayRef<ExecutorAddr> Rs,
+ OnReadUIntsCompleteFn<uint32_t> OnComplete) override {
+ using namespace shared;
+ EPC.callSPSWrapperAsync<SPSSequence<uint32_t>(
+ SPSSequence<SPSExecutorAddr>)>(
+ FAs.ReadUInt32s,
+ [OnComplete = std::move(OnComplete)](
+ Error Err, ReadUIntsResult<uint32_t> Result) mutable {
+ if (Err)
+ OnComplete(std::move(Err));
+ else
+ OnComplete(std::move(Result));
+ },
+ Rs);
+ }
+
+ void readUInt64sAsync(ArrayRef<ExecutorAddr> Rs,
+ OnReadUIntsCompleteFn<uint64_t> OnComplete) override {
+ using namespace shared;
+ EPC.callSPSWrapperAsync<SPSSequence<uint64_t>(
+ SPSSequence<SPSExecutorAddr>)>(
+ FAs.ReadUInt64s,
+ [OnComplete = std::move(OnComplete)](
+ Error Err, ReadUIntsResult<uint64_t> Result) mutable {
+ if (Err)
+ OnComplete(std::move(Err));
+ else
+ OnComplete(std::move(Result));
+ },
+ Rs);
+ }
+
+ void readPointersAsync(ArrayRef<ExecutorAddr> Rs,
+ OnReadPointersCompleteFn OnComplete) override {
+ using namespace shared;
+ using SPSSig = SPSSequence<SPSExecutorAddr>(SPSSequence<SPSExecutorAddr>);
+ EPC.callSPSWrapperAsync<SPSSig>(
+ FAs.ReadPointers,
+ [OnComplete = std::move(OnComplete)](
+ Error Err, ReadPointersResult Result) mutable {
+ if (Err)
+ OnComplete(std::move(Err));
+ else
+ OnComplete(std::move(Result));
+ },
+ Rs);
+ }
+
+ void readBuffersAsync(ArrayRef<ExecutorAddrRange> Rs,
+ OnReadBuffersCompleteFn OnComplete) override {
+ using namespace shared;
+ using SPSSig =
+ SPSSequence<SPSSequence<uint8_t>>(SPSSequence<SPSExecutorAddrRange>);
+ EPC.callSPSWrapperAsync<SPSSig>(
+ FAs.ReadBuffers,
+ [OnComplete = std::move(OnComplete)](Error Err,
+ ReadBuffersResult Result) mutable {
+ if (Err)
+ OnComplete(std::move(Err));
+ else
+ OnComplete(std::move(Result));
+ },
+ Rs);
+ }
+
+ void readStringsAsync(ArrayRef<ExecutorAddr> Rs,
+ OnReadStringsCompleteFn OnComplete) override {
+ using namespace shared;
+ using SPSSig = SPSSequence<SPSString>(SPSSequence<SPSExecutorAddr>);
+ EPC.callSPSWrapperAsync<SPSSig>(
+ FAs.ReadStrings,
+ [OnComplete = std::move(OnComplete)](Error Err,
+ ReadStringsResult Result) mutable {
+ if (Err)
+ OnComplete(std::move(Err));
+ else
+ OnComplete(std::move(Result));
+ },
+ Rs);
}
private:
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/InProcessMemoryAccess.h b/llvm/include/llvm/ExecutionEngine/Orc/InProcessMemoryAccess.h
index 934f6f62ffab0..eb68495469ec0 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/InProcessMemoryAccess.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/InProcessMemoryAccess.h
@@ -32,11 +32,32 @@ class LLVM_ABI InProcessMemoryAccess : public MemoryAccess {
void writeUInt64sAsync(ArrayRef<tpctypes::UInt64Write> Ws,
WriteResultFn OnWriteComplete) override;
+ void writePointersAsync(ArrayRef<tpctypes::PointerWrite> Ws,
+ WriteResultFn OnWriteComplete) override;
+
void writeBuffersAsync(ArrayRef<tpctypes::BufferWrite> Ws,
WriteResultFn OnWriteComplete) override;
- void writePointersAsync(ArrayRef<tpctypes::PointerWrite> Ws,
- WriteResultFn OnWriteComplete) override;
+ void readUInt8sAsync(ArrayRef<ExecutorAddr> Rs,
+ OnReadUIntsCompleteFn<uint8_t> OnComplete) override;
+
+ void readUInt16sAsync(ArrayRef<ExecutorAddr> Rs,
+ OnReadUIntsCompleteFn<uint16_t> OnComplete) override;
+
+ void readUInt32sAsync(ArrayRef<ExecutorAddr> Rs,
+ OnReadUIntsCompleteFn<uint32_t> OnComplete) override;
+
+ void readUInt64sAsync(ArrayRef<ExecutorAddr> Rs,
+ OnReadUIntsCompleteFn<uint64_t> OnComplete) override;
+
+ void readPointersAsync(ArrayRef<ExecutorAddr> Rs,
+ OnReadPointersCompleteFn OnComplete) override;
+
+ void readBuffersAsync(ArrayRef<ExecutorAddrRange> Rs,
+ OnReadBuffersCompleteFn OnComplete) override;
+
+ void readStringsAsync(ArrayRef<ExecutorAddr> Rs,
+ OnReadStringsCompleteFn OnComplete) override;
private:
bool IsArch64Bit;
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/MemoryAccess.h b/llvm/include/llvm/ExecutionEngine/Orc/MemoryAccess.h
index f4b34978f247c..1935f3c564439 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/MemoryAccess.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/MemoryAccess.h
@@ -28,6 +28,23 @@ class LLVM_ABI MemoryAccess {
/// Callback function for asynchronous writes.
using WriteResultFn = unique_function<void(Error)>;
+ template <typename T> using ReadUIntsResult = std::vector<T>;
+ template <typename T>
+ using OnReadUIntsCompleteFn =
+ unique_function<void(Expected<ReadUIntsResult<T>>)>;
+
+ using ReadPointersResult = std::vector<ExecutorAddr>;
+ using OnReadPointersCompleteFn =
+ unique_function<void(Expected<ReadPointersResult>)>;
+
+ using ReadBuffersResult = std::vector<std::vector<uint8_t>>;
+ using OnReadBuffersCompleteFn =
+ unique_function<void(Expected<ReadBuffersResult>)>;
+
+ using ReadStringsResult = std::vector<std::string>;
+ using OnReadStringsCompleteFn =
+ unique_function<void(Expected<ReadStringsResult>)>;
+
virtual ~MemoryAccess();
virtual void writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws,
@@ -42,11 +59,32 @@ class LLVM_ABI MemoryAccess {
virtual void writeUInt64sAsync(ArrayRef<tpctypes::UInt64Write> Ws,
WriteResultFn OnWriteComplete) = 0;
+ virtual void writePointersAsync(ArrayRef<tpctypes::PointerWrite> Ws,
+ WriteResultFn OnWriteComplete) = 0;
+
virtual void writeBuffersAsync(ArrayRef<tpctypes::BufferWrite> Ws,
WriteResultFn OnWriteComplete) = 0;
- virtual void writePointersAsync(ArrayRef<tpctypes::PointerWrite> Ws,
- WriteResultFn OnWriteComplete) = 0;
+ virtual void readUInt8sAsync(ArrayRef<ExecutorAddr> Rs,
+ OnReadUIntsCompleteFn<uint8_t> OnComplete) = 0;
+
+ virtual void readUInt16sAsync(ArrayRef<ExecutorAddr> Rs,
+ OnReadUIntsCompleteFn<uint16_t> OnComplete) = 0;
+
+ virtual void readUInt32sAsync(ArrayRef<ExecutorAddr> Rs,
+ OnReadUIntsCompleteFn<uint32_t> OnComplete) = 0;
+
+ virtual void readUInt64sAsync(ArrayRef<ExecutorAddr> Rs,
+ OnReadUIntsCompleteFn<uint64_t> OnComplete) = 0;
+
+ virtual void readPointersAsync(ArrayRef<ExecutorAddr> Rs,
+ OnReadPointersCompleteFn OnComplete) = 0;
+
+ virtual void readBuffersAsync(ArrayRef<ExecutorAddrRange> Rs,
+ OnReadBuffersCompleteFn OnComplete) = 0;
+
+ virtual void readStringsAsync(ArrayRef<ExecutorAddr> Rs,
+ OnReadStringsCompleteFn OnComplete) = 0;
Error writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws) {
std::promise<MSVCPError> ResultP;
@@ -79,21 +117,77 @@ class LLVM_ABI MemoryAccess {
return ResultF.get();
}
- Error writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws) {
+ Error writePointers(ArrayRef<tpctypes::PointerWrite> Ws) {
std::promise<MSVCPError> ResultP;
auto ResultF = ResultP.get_future();
- writeBuffersAsync(Ws,
- [&](Error Err) { ResultP.set_value(std::move(Err)); });
+ writePointersAsync(Ws,
+ [&](Error Err) { ResultP.set_value(std::move(Err)); });
return ResultF.get();
}
- Error writePointers(ArrayRef<tpctypes::PointerWrite> Ws) {
+ Error writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws) {
std::promise<MSVCPError> ResultP;
auto ResultF = ResultP.get_future();
- writePointersAsync(Ws,
- [&](Error Err) { ResultP.set_value(std::move(Err)); });
+ writeBuffersAsync(Ws,
+ [&](Error Err) { ResultP.set_value(std::move(Err)); });
return ResultF.get();
}
+
+ Expected<ReadUIntsResult<uint8_t>> readUInt8s(ArrayRef<ExecutorAddr> Rs) {
+ std::promise<MSVCPExpected<ReadUIntsResult<uint8_t>>> P;
+ readUInt8sAsync(Rs, [&](Expected<ReadUIntsResult<uint8_t>> Result) {
+ P.set_value(std::move(Result));
+ });
+ return P.get_future().get();
+ }
+
+ Expected<ReadUIntsResult<uint16_t>> readUInt16s(ArrayRef<ExecutorAddr> Rs) {
+ std::promise<MSVCPExpected<ReadUIntsResult<uint16_t>>> P;
+ readUInt16sAsync(Rs, [&](Expected<ReadUIntsResult<uint16_t>> Result) {
+ P.set_value(std::move(Result));
+ });
+ return P.get_future().get();
+ }
+
+ Expected<ReadUIntsResult<uint32_t>> readUInt32s(ArrayRef<ExecutorAddr> Rs) {
+ std::promise<MSVCPExpected<ReadUIntsResult<uint32_t>>> P;
+ readUInt32sAsync(Rs, [&](Expected<ReadUIntsResult<uint32_t>> Result) {
+ P.set_value(std::move(Result));
+ });
+ return P.get_future().get();
+ }
+
+ Expected<ReadUIntsResult<uint64_t>> readUInt64s(ArrayRef<ExecutorAddr> Rs) {
+ std::promise<MSVCPExpected<ReadUIntsResult<uint64_t>>> P;
+ readUInt64sAsync(Rs, [&](Expected<ReadUIntsResult<uint64_t>> Result) {
+ P.set_value(std::move(Result));
+ });
+ return P.get_future().get();
+ }
+
+ Expected<ReadPointersResult> readPointers(ArrayRef<ExecutorAddr> Rs) {
+ std::promise<MSVCPExpected<ReadPointersResult>> P;
+ readPointersAsync(Rs, [&](Expected<ReadPointersResult> Result) {
+ P.set_value(std::move(Result));
+ });
+ return P.get_future().get();
+ }
+
+ Expected<ReadBuffersResult> readBuffers(ArrayRef<ExecutorAddrRange> Rs) {
+ std::promise<MSVCPExpected<ReadBuffersResult>> P;
+ readBuffersAsync(Rs, [&](Expected<ReadBuffersResult> Result) {
+ P.set_value(std::move(Result));
+ });
+ return P.get_future().get();
+ }
+
+ Expected<ReadStringsResult> readStrings(ArrayRef<ExecutorAddr> Rs) {
+ std::promise<MSVCPExpected<ReadStringsResult>> P;
+ readStringsAsync(Rs, [&](Expected<ReadStringsResult> Result) {
+ P.set_value(std::move(Result));
+ });
+ return P.get_future().get();
+ }
};
} // namespace llvm::orc
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h
index 017ef70469e29..2bc6c1218ae72 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h
@@ -44,8 +44,16 @@ LLVM_ABI extern const char *MemoryWriteUInt8sWrapperName;
LLVM_ABI extern const char *MemoryWriteUInt16sWrapperName;
LLVM_ABI extern const char *MemoryWriteUInt32sWrapperName;
LLVM_ABI extern const char *MemoryWriteUInt64sWrapperName;
-LLVM_ABI extern const char *MemoryWriteBuffersWrapperName;
LLVM_ABI extern const char *MemoryWritePointersWrapperName;
+LLVM_ABI extern const char *MemoryWriteBuffersWrapperName;
+
+LLVM_ABI extern const char *MemoryReadUInt8sWrapperName;
+LLVM_ABI extern const char *MemoryReadUInt16sWrapperName;
+LLVM_ABI extern const char *MemoryReadUInt32sWrapperName;
+LLVM_ABI extern const char *MemoryReadUInt64sWrapperName;
+LLVM_ABI extern const char *MemoryReadPointersWrapperName;
+LLVM_ABI extern const char *MemoryReadBuffersWrapperName;
+LLVM_ABI extern const char *MemoryReadStringsWrapperName;
LLVM_ABI extern const char *RegisterEHFrameSectionAllocActionName;
LLVM_ABI extern const char *DeregisterEHFrameSectionAllocActionName;
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h
index e91d8d926d88c..adb07ba29b92a 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h
@@ -93,11 +93,11 @@ using UInt64Write = UIntWrite<uint64_t>;
/// For use with TargetProcessControl::MemoryAccess objects.
struct BufferWrite {
BufferWrite() = default;
- BufferWrite(ExecutorAddr Addr, StringRef Buffer)
+ BufferWrite(ExecutorAddr Addr, ArrayRef<char> Buffer)
: Addr(Addr), Buffer(Buffer) {}
ExecutorAddr Addr;
- StringRef Buffer;
+ ArrayRef<char> Buffer;
};
/// Describes a write to a pointer.
diff --git a/llvm/lib/ExecutionEngine/Orc/InProcessMemoryAccess.cpp b/llvm/lib/ExecutionEngine/Orc/InProcessMemoryAccess.cpp
index c8b2f00bc199d..261eedc5461e3 100644
--- a/llvm/lib/ExecutionEngine/Orc/InProcessMemoryAccess.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/InProcessMemoryAccess.cpp
@@ -42,13 +42,6 @@ void InProcessMemoryAccess::writeUInt64sAsync(
OnWriteComplete(Error::success());
}
-void InProcessMemoryAccess::writeBuffersAsync(
- ArrayRef<tpctypes::BufferWrite> Ws, WriteResultFn OnWriteComplete) {
- for (auto &W : Ws)
- memcpy(W.Addr.toPtr<char *>(), W.Buffer.data(), W.Buffer.size());
- OnWriteComplete(Error::success());
-}
-
void InProcessMemoryAccess::writePointersAsync(
ArrayRef<tpctypes::PointerWrite> Ws, WriteResultFn OnWriteComplete) {
if (IsArch64Bit) {
@@ -61,4 +54,81 @@ void InProcessMemoryAccess::writePointersAsync(
OnWriteComplete(Error::success());
}
+
+void InProcessMemoryAccess::writeBuffersAsync(
+ ArrayRef<tpctypes::BufferWrite> Ws, WriteResultFn OnWriteComplete) {
+ for (auto &W : Ws)
+ memcpy(W.Addr.toPtr<char *>(), W.Buffer.data(), W.Buffer.size());
+ OnWriteComplete(Error::success());
+}
+
+void InProcessMemoryAccess::readUInt8sAsync(
+ ArrayRef<ExecutorAddr> Rs, OnReadUIntsCompleteFn<uint8_t> OnComplete) {
+ ReadUIntsResult<uint8_t> Result;
+ Result.reserve(Rs.size());
+ for (auto &R : Rs)
+ Result.push_back(*R.toPtr<uint8_t *>());
+ OnComplete(std::move(Result));
+}
+
+void InProcessMemoryAccess::readUInt16sAsync(
+ ArrayRef<ExecutorAddr> Rs, OnReadUIntsCompleteFn<uint16_t> OnComplete) {
+ ReadUIntsResult<uint16_t> Result;
+ Result.reserve(Rs.size());
+ for (auto &R : Rs)
+ Result.push_back(*R.toPtr<uint16_t *>());
+ OnComplete(std::move(Result));
+}
+
+void InProcessMemoryAccess::readUInt32sAsync(
+ ArrayRef<ExecutorAddr> Rs, OnReadUIntsCompleteFn<uint32_t> OnComplete) {
+ ReadUIntsResult<uint32_t> Result;
+ Result.reserve(Rs.size());
+ for (auto &R : Rs)
+ Result.push_back(*R.toPtr<uint32_t *>());
+ OnComplete(std::move(Result));
+}
+
+void InProcessMemoryAccess::readUInt64sAsync(
+ ArrayRef<ExecutorAddr> Rs, OnReadUIntsCompleteFn<uint64_t> OnComplete) {
+ ReadUIntsResult<uint64_t> Result;
+ Result.reserve(Rs.size());
+ for (auto &R : Rs)
+ Result.push_back(*R.toPtr<uint64_t *>());
+ OnComplete(std::move(Result));
+}
+
+void InProcessMemoryAccess::readPointersAsync(
+ ArrayRef<ExecutorAddr> Rs, OnReadPointersCompleteFn OnComplete) {
+ ReadPointersResult Result;
+ Result.reserve(Rs.size());
+ for (auto &R : Rs)
+ Result.push_back(ExecutorAddr::fromPtr(*R.toPtr<void **>()));
+ OnComplete(std::move(Result));
+}
+
+void InProcessMemoryAccess::readBuffersAsync(
+ ArrayRef<ExecutorAddrRange> Rs, OnReadBuffersCompleteFn OnComplete) {
+ ReadBuffersResult Result;
+ Result.reserve(Rs.size());
+ for (auto &R : Rs) {
+ Result.push_back({});
+ Result.back().resize(R.size());
+ memcpy(Result.back().data(), R.Start.toPtr<char *>(), R.size());
+ }
+ OnComplete(std::move(Result));
+}
+
+void InProcessMemoryAccess::readStringsAsync(
+ ArrayRef<ExecutorAddr> Rs, OnReadStringsCompleteFn OnComplete) {
+ ReadStringsResult Result;
+ Result.reserve(Rs.size());
+ for (auto &R : Rs) {
+ Result.push_back({});
+ for (auto *P = R.toPtr<char *>(); *P; ++P)
+ Result.back().push_back(*P);
+ }
+ OnComplete(std::move(Result));
+}
+
} // end namespace llvm::orc
diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp
index 4e5b800100b9c..123651fc623e2 100644
--- a/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp
@@ -47,10 +47,25 @@ const char *MemoryWriteUInt32sWrapperName =
"__llvm_orc_bootstrap_mem_write_uint32s_wrapper";
const char *MemoryWriteUInt64sWrapperName =
"__llvm_orc_bootstrap_mem_write_uint64s_wrapper";
-const char *MemoryWriteBuffersWrapperName =
- "__llvm_orc_bootstrap_mem_write_buffers_wrapper";
const char *MemoryWritePointersWrapperName =
"__llvm_orc_bootstrap_mem_write_pointers_wrapper";
+const char *MemoryWriteBuffersWrapperName =
+ "__llvm_orc_bootstrap_mem_write_buffers_wrapper";
+
+const char *MemoryReadUInt8sWrapperName =
+ "__llvm_orc_bootstrap_mem_read_uint8s_wrapper";
+const char *MemoryReadUInt16sWrapperName =
+ "__llvm_orc_bootstrap_mem_read_uint16s_wrapper";
+const char *MemoryReadUInt32sWrapperName =
+ "__llvm_orc_bootstrap_mem_read_uint32s_wrapper";
+const char *MemoryReadUInt64sWrapperName =
+ "__llvm_orc_bootstrap_mem_read_uint64s_wrapper";
+const char *MemoryReadPointersWrapperName =
+ "__llvm_orc_bootstrap_mem_read_pointers_wrapper";
+const char *MemoryReadBuffersWrapperName =
+ "__llvm_orc_bootstrap_mem_read_buffers_wrapper";
+const char *MemoryReadStringsWrapperName =
+ "__llvm_orc_bootstrap_mem_read_strings_wrapper";
const char *RegisterEHFrameSectionAllocActionName =
"llvm_orc_registerEHFrameAllocAction";
diff --git a/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp b/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
index 746b843499101..87d757805a64c 100644
--- a/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
@@ -233,7 +233,13 @@ SimpleRemoteEPC::createDefaultMemoryAccess(SimpleRemoteEPC &SREPC) {
{FAs.WriteUInt32s, rt::MemoryWriteUInt32sWrapperName},
{FAs.WriteUInt64s, rt::MemoryWriteUInt64sWrapperName},
{FAs.WriteBuffers, rt::MemoryWriteBuffersWrapperName},
- {FAs.WritePointers, rt::MemoryWritePointersWrapperName}}))
+ {FAs.WritePointers, rt::MemoryWritePointersWrapperName},
+ {FAs.ReadUInt8s, rt::MemoryReadUInt8sWrapperName},
+ {FAs.ReadUInt16s, rt::MemoryReadUInt16sWrapperName},
+ {FAs.ReadUInt32s, rt::MemoryReadUInt32sWrapperName},
+ {FAs.ReadUInt64s, rt::MemoryReadUInt64sWrapperName},
+ {FAs.ReadBuffers, rt::MemoryReadBuffersWrapperName},
+ {FAs.ReadStrings, rt::MemoryReadStringsWrapperName}}))
return std::move(Err);
return std::make_unique<EPCGenericMemoryAccess>(SREPC, FAs);
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/OrcRTBootstrap.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/OrcRTBootstrap.cpp
index c4f201b353d27..06cb717750e35 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/OrcRTBootstrap.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/OrcRTBootstrap.cpp
@@ -33,6 +33,18 @@ writeUIntsWrapper(const char *ArgData, size_t ArgSize) {
.release();
}
+static llvm::orc::shared::CWrapperFunctionResult
+writePointersWrapper(const char *ArgData, size_t ArgSize) {
+ return WrapperFunction<void(SPSSequence<SPSMemoryAccessPointerWrite>)>::
+ handle(ArgData, ArgSize,
+ [](std::vector<tpctypes::PointerWrite> Ws) {
+ for (auto &W : Ws)
+ *W.Addr.template toPtr<void **>() =
+ W.Value.template toPtr<void *>();
+ })
+ .release();
+}
+
static llvm::orc::shared::CWrapperFunctionResult
writeBuffersWrapper(const char *ArgData, size_t ArgSize) {
return WrapperFunction<void(SPSSequence<SPSMemoryAccessBufferWrite>)>::handle(
@@ -45,16 +57,70 @@ writeBuffersWrapper(const char *ArgData, size_t ArgSize) {
.release();
}
+template <typename ReadT>
static llvm::orc::shared::CWrapperFunctionResult
-writePointersWrapper(const char *ArgData, size_t ArgSize) {
- return WrapperFunction<void(SPSSequence<SPSMemoryAccessPointerWrite>)>::
- handle(ArgData, ArgSize,
- [](std::vector<tpctypes::PointerWrite> Ws) {
- for (auto &W : Ws)
- *W.Addr.template toPtr<void **>() =
- W.Value.template toPtr<void *>();
+readUIntsWrapper(const char *ArgData, size_t ArgSize) {
+ using SPSSig = SPSSequence<ReadT>(SPSSequence<SPSExecutorAddr>);
+ return WrapperFunction<SPSSig>::handle(ArgData, ArgSize,
+ [](std::vector<ExecutorAddr> Rs) {
+ std::vector<ReadT> Result;
+ Result.reserve(Rs.size());
+ for (auto &R : Rs)
+ Result.push_back(
+ *R.toPtr<ReadT *>());
+ return Result;
+ })
+ .release();
+}
+
+static llvm::orc::shared::CWrapperFunctionResult
+readPointersWrapper(const char *ArgData, size_t ArgSize) {
+ using SPSSig = SPSSequence<SPSExecutorAddr>(SPSSequence<SPSExecutorAddr>);
+ return WrapperFunction<SPSSig>::handle(
+ ArgData, ArgSize,
+ [](std::vector<ExecutorAddr> Rs) {
+ std::vector<ExecutorAddr> Result;
+ Result.reserve(Rs.size());
+ for (auto &R : Rs)
+ Result.push_back(ExecutorAddr::fromPtr(*R.toPtr<void **>()));
+ return Result;
})
- .release();
+ .release();
+}
+
+static llvm::orc::shared::CWrapperFunctionResult
+readBuffersWrapper(const char *ArgData, size_t ArgSize) {
+ using SPSSig =
+ SPSSequence<SPSSequence<uint8_t>>(SPSSequence<SPSExecutorAddrRange>);
+ return WrapperFunction<SPSSig>::handle(
+ ArgData, ArgSize,
+ [](std::vector<ExecutorAddrRange> Rs) {
+ std::vector<std::vector<uint8_t>> Result;
+ Result.reserve(Rs.size());
+ for (auto &R : Rs) {
+ Result.push_back({});
+ Result.back().resize(R.size());
+ memcpy(reinterpret_cast<char *>(Result.back().data()),
+ R.Start.toPtr<char *>(), R.size());
+ }
+ return Result;
+ })
+ .release();
+}
+
+static llvm::orc::shared::CWrapperFunctionResult
+readStringsWrapper(const char *ArgData, size_t ArgSize) {
+ using SPSSig = SPSSequence<SPSString>(SPSSequence<SPSExecutorAddr>);
+ return WrapperFunction<SPSSig>::handle(ArgData, ArgSize,
+ [](std::vector<ExecutorAddr> Rs) {
+ std::vector<std::string> Result;
+ Result.reserve(Rs.size());
+ for (auto &R : Rs)
+ Result.push_back(
+ R.toPtr<char *>());
+ return Result;
+ })
+ .release();
}
static llvm::orc::shared::CWrapperFunctionResult
@@ -102,10 +168,24 @@ void addTo(StringMap<ExecutorAddr> &M) {
M[rt::MemoryWriteUInt64sWrapperName] = ExecutorAddr::fromPtr(
&writeUIntsWrapper<tpctypes::UInt64Write,
shared::SPSMemoryAccessUInt64Write>);
- M[rt::MemoryWriteBuffersWrapperName] =
- ExecutorAddr::fromPtr(&writeBuffersWrapper);
M[rt::MemoryWritePointersWrapperName] =
ExecutorAddr::fromPtr(&writePointersWrapper);
+ M[rt::MemoryWriteBuffersWrapperName] =
+ ExecutorAddr::fromPtr(&writeBuffersWrapper);
+ M[rt::MemoryReadUInt8sWrapperName] =
+ ExecutorAddr::fromPtr(&readUIntsWrapper<uint8_t>);
+ M[rt::MemoryReadUInt16sWrapperName] =
+ ExecutorAddr::fromPtr(&readUIntsWrapper<uint16_t>);
+ M[rt::MemoryReadUInt32sWrapperName] =
+ ExecutorAddr::fromPtr(&readUIntsWrapper<uint32_t>);
+ M[rt::MemoryReadUInt64sWrapperName] =
+ ExecutorAddr::fromPtr(&readUIntsWrapper<uint64_t>);
+ M[rt::MemoryReadPointersWrapperName] =
+ ExecutorAddr::fromPtr(&readPointersWrapper);
+ M[rt::MemoryReadBuffersWrapperName] =
+ ExecutorAddr::fromPtr(&readBuffersWrapper);
+ M[rt::MemoryReadStringsWrapperName] =
+ ExecutorAddr::fromPtr(&readStringsWrapper);
M[rt::RunAsMainWrapperName] = ExecutorAddr::fromPtr(&runAsMainWrapper);
M[rt::RunAsVoidFunctionWrapperName] =
ExecutorAddr::fromPtr(&runAsVoidFunctionWrapper);
diff --git a/llvm/unittests/ExecutionEngine/Orc/EPCGenericMemoryAccessTest.cpp b/llvm/unittests/ExecutionEngine/Orc/EPCGenericMemoryAccessTest.cpp
index d54bcd4fd5218..9358ea8149e95 100644
--- a/llvm/unittests/ExecutionEngine/Orc/EPCGenericMemoryAccessTest.cpp
+++ b/llvm/unittests/ExecutionEngine/Orc/EPCGenericMemoryAccessTest.cpp
@@ -29,6 +29,16 @@ CWrapperFunctionResult testWriteUInts(const char *ArgData, size_t ArgSize) {
.release();
}
+CWrapperFunctionResult testWritePointers(const char *ArgData, size_t ArgSize) {
+ return WrapperFunction<void(SPSSequence<SPSMemoryAccessPointerWrite>)>::
+ handle(ArgData, ArgSize,
+ [](std::vector<tpctypes::PointerWrite> Ws) {
+ for (auto &W : Ws)
+ *W.Addr.template toPtr<uint64_t *>() = W.Value.getValue();
+ })
+ .release();
+}
+
CWrapperFunctionResult testWriteBuffers(const char *ArgData, size_t ArgSize) {
return WrapperFunction<void(SPSSequence<SPSMemoryAccessBufferWrite>)>::handle(
ArgData, ArgSize,
@@ -40,76 +50,296 @@ CWrapperFunctionResult testWriteBuffers(const char *ArgData, size_t ArgSize) {
.release();
}
-CWrapperFunctionResult testWritePointers(const char *ArgData, size_t ArgSize) {
- return WrapperFunction<void(SPSSequence<SPSMemoryAccessPointerWrite>)>::
- handle(ArgData, ArgSize,
- [](std::vector<tpctypes::PointerWrite> Ws) {
- for (auto &W : Ws)
- *W.Addr.template toPtr<uint64_t *>() = W.Value.getValue();
+template <typename ReadT>
+CWrapperFunctionResult testReadUInts(const char *ArgData, size_t ArgSize) {
+ using SPSSig = SPSSequence<ReadT>(SPSSequence<SPSExecutorAddr>);
+ return WrapperFunction<SPSSig>::handle(ArgData, ArgSize,
+ [](std::vector<ExecutorAddr> Rs) {
+ std::vector<ReadT> Result;
+ Result.reserve(Rs.size());
+ for (auto &R : Rs)
+ Result.push_back(
+ *R.template toPtr<ReadT *>());
+ return Result;
+ })
+ .release();
+}
+
+CWrapperFunctionResult testReadPointers(const char *ArgData, size_t ArgSize) {
+ using SPSSig = SPSSequence<SPSExecutorAddr>(SPSSequence<SPSExecutorAddr>);
+ return WrapperFunction<SPSSig>::handle(
+ ArgData, ArgSize,
+ [](std::vector<ExecutorAddr> Rs) {
+ std::vector<ExecutorAddr> Result;
+ Result.reserve(Rs.size());
+ for (auto &R : Rs)
+ Result.push_back(
+ ExecutorAddr::fromPtr(*R.template toPtr<void **>()));
+ return Result;
})
- .release();
+ .release();
+}
+
+CWrapperFunctionResult testReadBuffers(const char *ArgData, size_t ArgSize) {
+ using SPSSig =
+ SPSSequence<SPSSequence<uint8_t>>(SPSSequence<SPSExecutorAddrRange>);
+ return WrapperFunction<SPSSig>::handle(
+ ArgData, ArgSize,
+ [](std::vector<ExecutorAddrRange> Rs) {
+ std::vector<std::vector<uint8_t>> Result;
+ Result.reserve(Rs.size());
+ for (auto &R : Rs) {
+ Result.push_back({});
+ Result.back().resize(R.size());
+ memcpy(reinterpret_cast<char *>(Result.back().data()),
+ R.Start.toPtr<char *>(), R.size());
+ }
+ return Result;
+ })
+ .release();
+}
+
+CWrapperFunctionResult testReadStrings(const char *ArgData, size_t ArgSize) {
+ using SPSSig = SPSSequence<SPSString>(SPSSequence<SPSExecutorAddr>);
+ return WrapperFunction<SPSSig>::handle(
+ ArgData, ArgSize,
+ [](std::vector<ExecutorAddr> Rs) {
+ std::vector<std::string> Result;
+ Result.reserve(Rs.size());
+ for (auto &R : Rs)
+ Result.push_back(std::string(R.toPtr<char *>()));
+ return Result;
+ })
+ .release();
+}
+
+class EPCGenericMemoryAccessTest : public testing::Test {
+public:
+ EPCGenericMemoryAccessTest() {
+ EPC = cantFail(SelfExecutorProcessControl::Create());
+
+ EPCGenericMemoryAccess::FuncAddrs FAs;
+ FAs.WriteUInt8s = ExecutorAddr::fromPtr(
+ &testWriteUInts<tpctypes::UInt8Write, SPSMemoryAccessUInt8Write>);
+ FAs.WriteUInt16s = ExecutorAddr::fromPtr(
+ &testWriteUInts<tpctypes::UInt16Write, SPSMemoryAccessUInt16Write>);
+ FAs.WriteUInt32s = ExecutorAddr::fromPtr(
+ &testWriteUInts<tpctypes::UInt32Write, SPSMemoryAccessUInt32Write>);
+ FAs.WriteUInt64s = ExecutorAddr::fromPtr(
+ &testWriteUInts<tpctypes::UInt64Write, SPSMemoryAccessUInt64Write>);
+ FAs.WritePointers = ExecutorAddr::fromPtr(&testWritePointers);
+ FAs.WriteBuffers = ExecutorAddr::fromPtr(&testWriteBuffers);
+ FAs.ReadUInt8s = ExecutorAddr::fromPtr(&testReadUInts<uint8_t>);
+ FAs.ReadUInt16s = ExecutorAddr::fromPtr(&testReadUInts<uint16_t>);
+ FAs.ReadUInt32s = ExecutorAddr::fromPtr(&testReadUInts<uint32_t>);
+ FAs.ReadUInt64s = ExecutorAddr::fromPtr(&testReadUInts<uint64_t>);
+ FAs.ReadPointers = ExecutorAddr::fromPtr(&testReadPointers);
+ FAs.ReadBuffers = ExecutorAddr::fromPtr(&testReadBuffers);
+ FAs.ReadStrings = ExecutorAddr::fromPtr(&testReadStrings);
+
+ MemAccess = std::make_unique<EPCGenericMemoryAccess>(*EPC, FAs);
+ }
+
+ ~EPCGenericMemoryAccessTest() { cantFail(EPC->disconnect()); }
+
+protected:
+ std::shared_ptr<SelfExecutorProcessControl> EPC;
+ std::unique_ptr<MemoryAccess> MemAccess;
+
+ static const uint8_t UInt8_1_TestValue;
+ static const uint8_t UInt8_2_TestValue;
+ static const uint16_t UInt16_TestValue;
+ static const uint32_t UInt32_TestValue;
+ static const uint64_t UInt64_TestValue;
+ static const void *Pointer_TestValue;
+
+ static const char Buffer_TestValue[21];
+ static const char *String_TestValue;
+};
+
+const uint8_t EPCGenericMemoryAccessTest::UInt8_1_TestValue = 1;
+const uint8_t EPCGenericMemoryAccessTest::UInt8_2_TestValue = 2;
+const uint16_t EPCGenericMemoryAccessTest::UInt16_TestValue = 3;
+const uint32_t EPCGenericMemoryAccessTest::UInt32_TestValue = 4;
+const uint64_t EPCGenericMemoryAccessTest::UInt64_TestValue = 5;
+
+const void *EPCGenericMemoryAccessTest::Pointer_TestValue =
+ reinterpret_cast<void *>(uintptr_t(0x6));
+
+const char EPCGenericMemoryAccessTest::Buffer_TestValue[21] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
+ 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14};
+const char *EPCGenericMemoryAccessTest::String_TestValue = "hello, world!";
+
+TEST_F(EPCGenericMemoryAccessTest, WriteUInt8s) {
+ uint8_t UInt8_1_Storage = 0;
+ uint8_t UInt8_2_Storage = 0;
+
+ auto Err = MemAccess->writeUInt8s(
+ {{ExecutorAddr::fromPtr(&UInt8_1_Storage), UInt8_1_TestValue},
+ {ExecutorAddr::fromPtr(&UInt8_2_Storage), UInt8_2_TestValue}});
+ EXPECT_THAT_ERROR(std::move(Err), Succeeded());
+ EXPECT_EQ(UInt8_1_Storage, UInt8_1_TestValue);
+ EXPECT_EQ(UInt8_2_Storage, UInt8_2_TestValue);
+}
+
+TEST_F(EPCGenericMemoryAccessTest, ReadUInt8s) {
+ uint8_t UInt8_1_Storage = UInt8_1_TestValue;
+ uint8_t UInt8_2_Storage = UInt8_2_TestValue;
+
+ auto Vals =
+ MemAccess->readUInt8s({{ExecutorAddr::fromPtr(&UInt8_1_Storage),
+ ExecutorAddr::fromPtr(&UInt8_2_Storage)}});
+ static_assert(
+ std::is_same_v<decltype(Vals)::value_type::value_type, uint8_t>);
+ if (!Vals)
+ return ADD_FAILURE() << toString(Vals.takeError());
+
+ EXPECT_EQ(Vals->size(), 2U);
+ if (Vals->size() >= 1)
+ EXPECT_EQ((*Vals)[0], UInt8_1_TestValue);
+ if (Vals->size() >= 2)
+ EXPECT_EQ((*Vals)[1], UInt8_2_TestValue);
+}
+
+TEST_F(EPCGenericMemoryAccessTest, WriteUInt16s) {
+ uint16_t UInt16_Storage = 0;
+
+ auto Err = MemAccess->writeUInt16s(
+ {{ExecutorAddr::fromPtr(&UInt16_Storage), UInt16_TestValue}});
+ EXPECT_THAT_ERROR(std::move(Err), Succeeded());
+ EXPECT_EQ(UInt16_Storage, UInt16_TestValue);
+}
+
+TEST_F(EPCGenericMemoryAccessTest, ReadUInt16s) {
+ uint16_t UInt16_Storage = UInt16_TestValue;
+
+ auto Vals =
+ MemAccess->readUInt16s({{ExecutorAddr::fromPtr(&UInt16_Storage)}});
+ static_assert(
+ std::is_same_v<decltype(Vals)::value_type::value_type, uint16_t>);
+ if (Vals) {
+ EXPECT_EQ(Vals->size(), 1U);
+ if (Vals->size() == 1)
+ EXPECT_EQ((*Vals)[0], UInt16_TestValue);
+ } else
+ EXPECT_THAT_ERROR(Vals.takeError(), Succeeded());
+}
+
+TEST_F(EPCGenericMemoryAccessTest, WriteUInt32s) {
+ uint32_t UInt32_Storage = 0;
+
+ auto Err = MemAccess->writeUInt32s(
+ {{ExecutorAddr::fromPtr(&UInt32_Storage), UInt32_TestValue}});
+ EXPECT_THAT_ERROR(std::move(Err), Succeeded());
+ EXPECT_EQ(UInt32_Storage, UInt32_TestValue);
+}
+
+TEST_F(EPCGenericMemoryAccessTest, ReadUInt32s) {
+ uint32_t UInt32_Storage = UInt32_TestValue;
+
+ auto Vals =
+ MemAccess->readUInt32s({{ExecutorAddr::fromPtr(&UInt32_Storage)}});
+ static_assert(
+ std::is_same_v<decltype(Vals)::value_type::value_type, uint32_t>);
+ if (Vals) {
+ EXPECT_EQ(Vals->size(), 1U);
+ if (Vals->size() == 1)
+ EXPECT_EQ((*Vals)[0], UInt32_TestValue);
+ } else
+ EXPECT_THAT_ERROR(Vals.takeError(), Succeeded());
+}
+
+TEST_F(EPCGenericMemoryAccessTest, WriteUInt64s) {
+ uint64_t UInt64_Storage = 0;
+
+ auto Err = MemAccess->writeUInt64s(
+ {{ExecutorAddr::fromPtr(&UInt64_Storage), UInt64_TestValue}});
+ EXPECT_THAT_ERROR(std::move(Err), Succeeded());
+ EXPECT_EQ(UInt64_Storage, UInt64_TestValue);
+}
+
+TEST_F(EPCGenericMemoryAccessTest, ReadUInt64s) {
+ uint64_t UInt64_Storage = UInt64_TestValue;
+
+ auto Vals =
+ MemAccess->readUInt64s({{ExecutorAddr::fromPtr(&UInt64_Storage)}});
+ static_assert(
+ std::is_same_v<decltype(Vals)::value_type::value_type, uint64_t>);
+ if (Vals) {
+ EXPECT_EQ(Vals->size(), 1U);
+ if (Vals->size() == 1)
+ EXPECT_EQ((*Vals)[0], UInt64_TestValue);
+ } else
+ EXPECT_THAT_ERROR(Vals.takeError(), Succeeded());
+}
+
+TEST_F(EPCGenericMemoryAccessTest, WritePointers) {
+ void *Pointer_Storage = nullptr;
+
+ auto Err =
+ MemAccess->writePointers({{ExecutorAddr::fromPtr(&Pointer_Storage),
+ ExecutorAddr::fromPtr(Pointer_TestValue)}});
+ EXPECT_THAT_ERROR(std::move(Err), Succeeded());
+ EXPECT_EQ(Pointer_Storage, Pointer_TestValue);
+}
+
+TEST_F(EPCGenericMemoryAccessTest, ReadPointers) {
+ auto Vals =
+ MemAccess->readPointers({{ExecutorAddr::fromPtr(&Pointer_TestValue)}});
+ static_assert(
+ std::is_same_v<decltype(Vals)::value_type::value_type, ExecutorAddr>);
+ if (Vals) {
+ EXPECT_EQ(Vals->size(), 1U);
+ if (Vals->size() == 1)
+ EXPECT_EQ((*Vals)[0], ExecutorAddr::fromPtr(Pointer_TestValue));
+ } else
+ EXPECT_THAT_ERROR(Vals.takeError(), Succeeded());
+}
+
+TEST_F(EPCGenericMemoryAccessTest, WriteBuffers) {
+ char Buffer_Storage[sizeof(Buffer_TestValue)];
+ memset(Buffer_Storage, 0, sizeof(Buffer_TestValue));
+
+ auto Err = MemAccess->writeBuffers(
+ {{ExecutorAddr::fromPtr(&Buffer_Storage),
+ ArrayRef(Buffer_TestValue, sizeof(Buffer_TestValue))}});
+ EXPECT_THAT_ERROR(std::move(Err), Succeeded());
+ EXPECT_EQ(ArrayRef(Buffer_Storage, sizeof(Buffer_TestValue)),
+ ArrayRef(Buffer_TestValue, sizeof(Buffer_TestValue)));
+}
+
+TEST_F(EPCGenericMemoryAccessTest, ReadBuffers) {
+ char Buffer_Storage[sizeof(Buffer_TestValue)];
+ memcpy(Buffer_Storage, Buffer_TestValue, sizeof(Buffer_TestValue));
+
+ auto Vals = MemAccess->readBuffers({{ExecutorAddrRange(
+ ExecutorAddr::fromPtr(&Buffer_Storage), sizeof(Buffer_Storage))}});
+ static_assert(std::is_same_v<decltype(Vals)::value_type::value_type,
+ std::vector<uint8_t>>);
+ if (Vals) {
+ EXPECT_EQ(Vals->size(), 1U);
+ if (Vals->size() == 1) {
+ EXPECT_EQ((*Vals)[0].size(), sizeof(Buffer_Storage));
+ EXPECT_EQ(
+ memcmp((*Vals)[0].data(), Buffer_TestValue, sizeof(Buffer_Storage)),
+ 0);
+ }
+ } else
+ EXPECT_THAT_ERROR(Vals.takeError(), Succeeded());
}
-TEST(EPCGenericMemoryAccessTest, MemWrites) {
- auto SelfEPC = cantFail(SelfExecutorProcessControl::Create());
-
- EPCGenericMemoryAccess::FuncAddrs FAs;
- FAs.WriteUInt8s = ExecutorAddr::fromPtr(
- &testWriteUInts<tpctypes::UInt8Write, SPSMemoryAccessUInt8Write>);
- FAs.WriteUInt16s = ExecutorAddr::fromPtr(
- &testWriteUInts<tpctypes::UInt16Write, SPSMemoryAccessUInt16Write>);
- FAs.WriteUInt32s = ExecutorAddr::fromPtr(
- &testWriteUInts<tpctypes::UInt32Write, SPSMemoryAccessUInt32Write>);
- FAs.WriteUInt64s = ExecutorAddr::fromPtr(
- &testWriteUInts<tpctypes::UInt64Write, SPSMemoryAccessUInt64Write>);
- FAs.WriteBuffers = ExecutorAddr::fromPtr(&testWriteBuffers);
- FAs.WritePointers = ExecutorAddr::fromPtr(&testWritePointers);
-
- auto MemAccess = std::make_unique<EPCGenericMemoryAccess>(*SelfEPC, FAs);
-
- uint8_t Test_UInt8_1 = 0;
- uint8_t Test_UInt8_2 = 0;
- uint16_t Test_UInt16 = 0;
- uint32_t Test_UInt32 = 0;
- uint64_t Test_UInt64 = 0;
- uint64_t Test_Pointer = 0;
- char Test_Buffer[21];
-
- auto Err1 =
- MemAccess->writeUInt8s({{ExecutorAddr::fromPtr(&Test_UInt8_1), 1},
- {ExecutorAddr::fromPtr(&Test_UInt8_2), 0xFE}});
-
- EXPECT_THAT_ERROR(std::move(Err1), Succeeded());
- EXPECT_EQ(Test_UInt8_1, 1U);
- EXPECT_EQ(Test_UInt8_2, 0xFE);
-
- auto Err2 =
- MemAccess->writeUInt16s({{ExecutorAddr::fromPtr(&Test_UInt16), 1}});
- EXPECT_THAT_ERROR(std::move(Err2), Succeeded());
- EXPECT_EQ(Test_UInt16, 1U);
-
- auto Err3 =
- MemAccess->writeUInt32s({{ExecutorAddr::fromPtr(&Test_UInt32), 1}});
- EXPECT_THAT_ERROR(std::move(Err3), Succeeded());
- EXPECT_EQ(Test_UInt32, 1U);
-
- auto Err4 =
- MemAccess->writeUInt64s({{ExecutorAddr::fromPtr(&Test_UInt64), 1}});
- EXPECT_THAT_ERROR(std::move(Err4), Succeeded());
- EXPECT_EQ(Test_UInt64, 1U);
-
- StringRef TestMsg("test-message");
- auto Err5 =
- MemAccess->writeBuffers({{ExecutorAddr::fromPtr(&Test_Buffer), TestMsg}});
- EXPECT_THAT_ERROR(std::move(Err5), Succeeded());
- EXPECT_EQ(StringRef(Test_Buffer, TestMsg.size()), TestMsg);
-
- auto Err6 = MemAccess->writePointers(
- {{ExecutorAddr::fromPtr(&Test_Pointer), ExecutorAddr(1U)}});
- EXPECT_THAT_ERROR(std::move(Err6), Succeeded());
- EXPECT_EQ(Test_Pointer, 1U);
-
- cantFail(SelfEPC->disconnect());
+TEST_F(EPCGenericMemoryAccessTest, ReadStrings) {
+ auto Vals =
+ MemAccess->readStrings({{ExecutorAddr::fromPtr(String_TestValue)}});
+ static_assert(
+ std::is_same_v<decltype(Vals)::value_type, std::vector<std::string>>);
+ if (Vals) {
+ EXPECT_EQ(Vals->size(), 1U);
+ if (Vals->size() == 1)
+ EXPECT_EQ((*Vals)[0], std::string(String_TestValue));
+ } else
+ EXPECT_THAT_ERROR(Vals.takeError(), Succeeded());
}
} // namespace
More information about the llvm-commits
mailing list