diff options
Diffstat (limited to 'lldb/unittests/TestingSupport/Host/NativeProcessTestUtils.h')
| -rw-r--r-- | lldb/unittests/TestingSupport/Host/NativeProcessTestUtils.h | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/lldb/unittests/TestingSupport/Host/NativeProcessTestUtils.h b/lldb/unittests/TestingSupport/Host/NativeProcessTestUtils.h new file mode 100644 index 00000000000..c72aacd880f --- /dev/null +++ b/lldb/unittests/TestingSupport/Host/NativeProcessTestUtils.h @@ -0,0 +1,150 @@ +//===-- NativeProcessTestUtils.cpp ------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_unittests_Host_NativeProcessTestUtils_h_ +#define lldb_unittests_Host_NativeProcessTestUtils_h_ + +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "llvm/Testing/Support/Error.h" +#include "gmock/gmock.h" + +using namespace lldb_private; +using namespace lldb; +using namespace testing; + +namespace lldb_private { + +class MockDelegate : public NativeProcessProtocol::NativeDelegate { +public: + MOCK_METHOD1(InitializeDelegate, void(NativeProcessProtocol *Process)); + MOCK_METHOD2(ProcessStateChanged, + void(NativeProcessProtocol *Process, StateType State)); + MOCK_METHOD1(DidExec, void(NativeProcessProtocol *Process)); +}; + +// NB: This class doesn't use the override keyword to avoid +// -Winconsistent-missing-override warnings from the compiler. The +// inconsistency comes from the overriding definitions in the MOCK_*** macros. +template <typename T> class MockProcess : public T { +public: + MockProcess(NativeProcessProtocol::NativeDelegate &Delegate, + const ArchSpec &Arch, lldb::pid_t Pid = 1) + : T(Pid, -1, Delegate), Arch(Arch) {} + + MOCK_METHOD1(Resume, Status(const ResumeActionList &ResumeActions)); + MOCK_METHOD0(Halt, Status()); + MOCK_METHOD0(Detach, Status()); + MOCK_METHOD1(Signal, Status(int Signo)); + MOCK_METHOD0(Kill, Status()); + MOCK_METHOD3(AllocateMemory, + Status(size_t Size, uint32_t Permissions, addr_t &Addr)); + MOCK_METHOD1(DeallocateMemory, Status(addr_t Addr)); + MOCK_METHOD0(GetSharedLibraryInfoAddress, addr_t()); + MOCK_METHOD0(UpdateThreads, size_t()); + MOCK_CONST_METHOD0(GetAuxvData, + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>()); + MOCK_METHOD2(GetLoadedModuleFileSpec, + Status(const char *ModulePath, FileSpec &Spec)); + MOCK_METHOD2(GetFileLoadAddress, + Status(const llvm::StringRef &FileName, addr_t &Addr)); + + const ArchSpec &GetArchitecture() const /*override*/ { return Arch; } + Status SetBreakpoint(lldb::addr_t Addr, uint32_t Size, + bool Hardware) /*override*/ { + if (Hardware) + return this->SetHardwareBreakpoint(Addr, Size); + else + return this->SetSoftwareBreakpoint(Addr, Size); + } + + // Redirect base class Read/Write Memory methods to functions whose signatures + // are more mock-friendly. + Status ReadMemory(addr_t Addr, void *Buf, size_t Size, + size_t &BytesRead) /*override*/ { + auto ExpectedMemory = this->ReadMemory(Addr, Size); + if (!ExpectedMemory) { + BytesRead = 0; + return Status(ExpectedMemory.takeError()); + } + BytesRead = ExpectedMemory->size(); + assert(BytesRead <= Size); + std::memcpy(Buf, ExpectedMemory->data(), BytesRead); + return Status(); + } + + Status WriteMemory(addr_t Addr, const void *Buf, size_t Size, + size_t &BytesWritten) /*override*/ { + auto ExpectedBytes = this->WriteMemory( + Addr, llvm::makeArrayRef(static_cast<const uint8_t *>(Buf), Size)); + if (!ExpectedBytes) { + BytesWritten = 0; + return Status(ExpectedBytes.takeError()); + } + BytesWritten = *ExpectedBytes; + return Status(); + } + + MOCK_METHOD2(ReadMemory, + llvm::Expected<std::vector<uint8_t>>(addr_t Addr, size_t Size)); + MOCK_METHOD2(WriteMemory, + llvm::Expected<size_t>(addr_t Addr, + llvm::ArrayRef<uint8_t> Data)); + + using T::GetSoftwareBreakpointTrapOpcode; + llvm::Expected<std::vector<uint8_t>> ReadMemoryWithoutTrap(addr_t Addr, + size_t Size) { + std::vector<uint8_t> Data(Size, 0); + size_t BytesRead; + Status ST = + T::ReadMemoryWithoutTrap(Addr, Data.data(), Data.size(), BytesRead); + if (ST.Fail()) + return ST.ToError(); + Data.resize(BytesRead); + return std::move(Data); + } + +private: + ArchSpec Arch; +}; + +class FakeMemory { +public: + FakeMemory(llvm::ArrayRef<uint8_t> Data, addr_t start_addr = 0) + : Data(Data), m_start_addr(start_addr) {} + + FakeMemory(const void *Data, size_t data_size, addr_t start_addr = 0) + : Data((const uint8_t *)Data, ((const uint8_t *)Data) + data_size), + m_start_addr(start_addr) {} + + llvm::Expected<std::vector<uint8_t>> Read(addr_t Addr, size_t Size) { + Addr -= m_start_addr; + if (Addr >= Data.size()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Address out of range."); + Size = std::min(Size, Data.size() - (size_t)Addr); + auto Begin = std::next(Data.begin(), Addr); + return std::vector<uint8_t>(Begin, std::next(Begin, Size)); + } + + llvm::Expected<size_t> Write(addr_t Addr, llvm::ArrayRef<uint8_t> Chunk) { + Addr -= m_start_addr; + if (Addr >= Data.size()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Address out of range."); + size_t Size = std::min(Chunk.size(), Data.size() - (size_t)Addr); + std::copy_n(Chunk.begin(), Size, &Data[Addr]); + return Size; + } + +private: + std::vector<uint8_t> Data; + addr_t m_start_addr; +}; +} // namespace lldb_private + +#endif
\ No newline at end of file |

