157 lines · c
1//===-- NativeProcessTestUtils.cpp ------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLDB_UNITTESTS_TESTINGSUPPORT_HOST_NATIVEPROCESSTESTUTILS_H10#define LLDB_UNITTESTS_TESTINGSUPPORT_HOST_NATIVEPROCESSTESTUTILS_H11 12#include "lldb/Host/common/NativeProcessProtocol.h"13#include "llvm/Testing/Support/Error.h"14#include "gmock/gmock.h"15 16using namespace lldb_private;17using namespace lldb;18using namespace testing;19 20namespace lldb_private {21 22class MockDelegate : public NativeProcessProtocol::NativeDelegate {23public:24 MOCK_METHOD1(InitializeDelegate, void(NativeProcessProtocol *Process));25 MOCK_METHOD2(ProcessStateChanged,26 void(NativeProcessProtocol *Process, StateType State));27 MOCK_METHOD1(DidExec, void(NativeProcessProtocol *Process));28 MOCK_METHOD2(NewSubprocessImpl,29 void(NativeProcessProtocol *parent_process,30 std::unique_ptr<NativeProcessProtocol> &child_process));31 // This is a hack to avoid MOCK_METHOD2 incompatibility with std::unique_ptr32 // passed as value.33 void NewSubprocess(NativeProcessProtocol *parent_process,34 std::unique_ptr<NativeProcessProtocol> child_process) {35 NewSubprocessImpl(parent_process, child_process);36 }37};38 39// NB: This class doesn't use the override keyword to avoid40// -Winconsistent-missing-override warnings from the compiler. The41// inconsistency comes from the overriding definitions in the MOCK_*** macros.42template <typename T> class MockProcess : public T {43public:44 MockProcess(NativeProcessProtocol::NativeDelegate &Delegate,45 const ArchSpec &Arch, lldb::pid_t Pid = 1)46 : T(Pid, -1, Delegate), Arch(Arch) {}47 48 MOCK_METHOD1(Resume, Status(const ResumeActionList &ResumeActions));49 MOCK_METHOD0(Halt, Status());50 MOCK_METHOD0(Detach, Status());51 MOCK_METHOD1(Signal, Status(int Signo));52 MOCK_METHOD0(Kill, Status());53 MOCK_METHOD0(GetSharedLibraryInfoAddress, addr_t());54 MOCK_METHOD0(UpdateThreads, size_t());55 MOCK_CONST_METHOD0(GetAuxvData,56 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>());57 MOCK_METHOD2(GetLoadedModuleFileSpec,58 Status(const char *ModulePath, FileSpec &Spec));59 MOCK_METHOD2(GetFileLoadAddress,60 Status(const llvm::StringRef &FileName, addr_t &Addr));61 62 const ArchSpec &GetArchitecture() const /*override*/ { return Arch; }63 Status SetBreakpoint(lldb::addr_t Addr, uint32_t Size,64 bool Hardware) /*override*/ {65 if (Hardware)66 return this->SetHardwareBreakpoint(Addr, Size);67 else68 return this->SetSoftwareBreakpoint(Addr, Size);69 }70 71 // Redirect base class Read/Write Memory methods to functions whose signatures72 // are more mock-friendly.73 Status ReadMemory(addr_t Addr, void *Buf, size_t Size,74 size_t &BytesRead) /*override*/ {75 auto ExpectedMemory = this->ReadMemory(Addr, Size);76 if (!ExpectedMemory) {77 BytesRead = 0;78 return Status::FromError(ExpectedMemory.takeError());79 }80 BytesRead = ExpectedMemory->size();81 assert(BytesRead <= Size);82 std::memcpy(Buf, ExpectedMemory->data(), BytesRead);83 return Status();84 }85 86 Status WriteMemory(addr_t Addr, const void *Buf, size_t Size,87 size_t &BytesWritten) /*override*/ {88 auto ExpectedBytes = this->WriteMemory(89 Addr, llvm::ArrayRef(static_cast<const uint8_t *>(Buf), Size));90 if (!ExpectedBytes) {91 BytesWritten = 0;92 return Status::FromError(ExpectedBytes.takeError());93 }94 BytesWritten = *ExpectedBytes;95 return Status();96 }97 98 MOCK_METHOD2(ReadMemory,99 llvm::Expected<std::vector<uint8_t>>(addr_t Addr, size_t Size));100 MOCK_METHOD2(WriteMemory,101 llvm::Expected<size_t>(addr_t Addr,102 llvm::ArrayRef<uint8_t> Data));103 104 using T::GetSoftwareBreakpointTrapOpcode;105 llvm::Expected<std::vector<uint8_t>> ReadMemoryWithoutTrap(addr_t Addr,106 size_t Size) {107 std::vector<uint8_t> Data(Size, 0);108 size_t BytesRead;109 Status ST =110 T::ReadMemoryWithoutTrap(Addr, Data.data(), Data.size(), BytesRead);111 if (ST.Fail())112 return ST.ToError();113 Data.resize(BytesRead);114 return std::move(Data);115 }116 117private:118 ArchSpec Arch;119};120 121class FakeMemory {122public:123 FakeMemory(llvm::ArrayRef<uint8_t> Data, addr_t start_addr = 0)124 : Data(Data), m_start_addr(start_addr) {}125 126 FakeMemory(const void *Data, size_t data_size, addr_t start_addr = 0)127 : Data((const uint8_t *)Data, ((const uint8_t *)Data) + data_size),128 m_start_addr(start_addr) {}129 130 llvm::Expected<std::vector<uint8_t>> Read(addr_t Addr, size_t Size) {131 Addr -= m_start_addr;132 if (Addr >= Data.size())133 return llvm::createStringError(llvm::inconvertibleErrorCode(),134 "Address out of range.");135 Size = std::min(Size, Data.size() - (size_t)Addr);136 auto Begin = std::next(Data.begin(), Addr);137 return std::vector<uint8_t>(Begin, std::next(Begin, Size));138 }139 140 llvm::Expected<size_t> Write(addr_t Addr, llvm::ArrayRef<uint8_t> Chunk) {141 Addr -= m_start_addr;142 if (Addr >= Data.size())143 return llvm::createStringError(llvm::inconvertibleErrorCode(),144 "Address out of range.");145 size_t Size = std::min(Chunk.size(), Data.size() - (size_t)Addr);146 std::copy_n(Chunk.begin(), Size, &Data[Addr]);147 return Size;148 }149 150private:151 std::vector<uint8_t> Data;152 addr_t m_start_addr;153};154} // namespace lldb_private155 156#endif157