//===- EPCGenericMemoryAccessTest.cpp -- Tests for EPCGenericMemoryAccess -===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "OrcTestCommon.h" #include "llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h" #include "llvm/ExecutionEngine/Orc/SelfExecutorProcessControl.h" #include "llvm/Testing/Support/Error.h" using namespace llvm; using namespace llvm::orc; using namespace llvm::orc::shared; namespace { template CWrapperFunctionResult testWriteUInts(const char *ArgData, size_t ArgSize) { return WrapperFunction)>::handle( ArgData, ArgSize, [](std::vector Ws) { for (auto &W : Ws) *W.Addr.template toPtr() = W.Value; }) .release(); } CWrapperFunctionResult testWritePointers(const char *ArgData, size_t ArgSize) { return WrapperFunction)>:: handle(ArgData, ArgSize, [](std::vector Ws) { for (auto &W : Ws) *W.Addr.template toPtr() = W.Value.toPtr(); }) .release(); } CWrapperFunctionResult testWriteBuffers(const char *ArgData, size_t ArgSize) { return WrapperFunction)>::handle( ArgData, ArgSize, [](std::vector Ws) { for (auto &W : Ws) memcpy(W.Addr.template toPtr(), W.Buffer.data(), W.Buffer.size()); }) .release(); } template CWrapperFunctionResult testReadUInts(const char *ArgData, size_t ArgSize) { using SPSSig = SPSSequence(SPSSequence); return WrapperFunction::handle(ArgData, ArgSize, [](std::vector Rs) { std::vector Result; Result.reserve(Rs.size()); for (auto &R : Rs) Result.push_back( *R.template toPtr()); return Result; }) .release(); } CWrapperFunctionResult testReadPointers(const char *ArgData, size_t ArgSize) { using SPSSig = SPSSequence(SPSSequence); return WrapperFunction::handle( ArgData, ArgSize, [](std::vector Rs) { std::vector Result; Result.reserve(Rs.size()); for (auto &R : Rs) Result.push_back( ExecutorAddr::fromPtr(*R.template toPtr())); return Result; }) .release(); } CWrapperFunctionResult testReadBuffers(const char *ArgData, size_t ArgSize) { using SPSSig = SPSSequence>(SPSSequence); return WrapperFunction::handle( ArgData, ArgSize, [](std::vector Rs) { std::vector> Result; Result.reserve(Rs.size()); for (auto &R : Rs) { Result.push_back({}); Result.back().resize(R.size()); memcpy(reinterpret_cast(Result.back().data()), R.Start.toPtr(), R.size()); } return Result; }) .release(); } CWrapperFunctionResult testReadStrings(const char *ArgData, size_t ArgSize) { using SPSSig = SPSSequence(SPSSequence); return WrapperFunction::handle( ArgData, ArgSize, [](std::vector Rs) { std::vector Result; Result.reserve(Rs.size()); for (auto &R : Rs) Result.push_back(std::string(R.toPtr())); return Result; }) .release(); } class EPCGenericMemoryAccessTest : public testing::Test { public: EPCGenericMemoryAccessTest() { EPC = cantFail(SelfExecutorProcessControl::Create()); EPCGenericMemoryAccess::FuncAddrs FAs; FAs.WriteUInt8s = ExecutorAddr::fromPtr( &testWriteUInts); FAs.WriteUInt16s = ExecutorAddr::fromPtr( &testWriteUInts); FAs.WriteUInt32s = ExecutorAddr::fromPtr( &testWriteUInts); FAs.WriteUInt64s = ExecutorAddr::fromPtr( &testWriteUInts); FAs.WritePointers = ExecutorAddr::fromPtr(&testWritePointers); FAs.WriteBuffers = ExecutorAddr::fromPtr(&testWriteBuffers); FAs.ReadUInt8s = ExecutorAddr::fromPtr(&testReadUInts); FAs.ReadUInt16s = ExecutorAddr::fromPtr(&testReadUInts); FAs.ReadUInt32s = ExecutorAddr::fromPtr(&testReadUInts); FAs.ReadUInt64s = ExecutorAddr::fromPtr(&testReadUInts); FAs.ReadPointers = ExecutorAddr::fromPtr(&testReadPointers); FAs.ReadBuffers = ExecutorAddr::fromPtr(&testReadBuffers); FAs.ReadStrings = ExecutorAddr::fromPtr(&testReadStrings); MemAccess = std::make_unique(*EPC, FAs); } ~EPCGenericMemoryAccessTest() { cantFail(EPC->disconnect()); } protected: std::shared_ptr EPC; std::unique_ptr 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(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); 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); 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); 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); 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); 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>); 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_F(EPCGenericMemoryAccessTest, ReadStrings) { auto Vals = MemAccess->readStrings({{ExecutorAddr::fromPtr(String_TestValue)}}); static_assert( std::is_same_v>); 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