1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 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_TESTINGSUPPORT_HOST_NATIVEPROCESSTESTUTILS_H
#define LLDB_UNITTESTS_TESTINGSUPPORT_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
|