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-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef LLDB_UNITTESTS_TESTINGSUPPORT_HOST_NATIVEPROCESSTESTUTILS_H |
10 | #define LLDB_UNITTESTS_TESTINGSUPPORT_HOST_NATIVEPROCESSTESTUTILS_H |
11 | |
12 | #include "lldb/Host/common/NativeProcessProtocol.h" |
13 | #include "llvm/Testing/Support/Error.h" |
14 | #include "gmock/gmock.h" |
15 | |
16 | using namespace lldb_private; |
17 | using namespace lldb; |
18 | using namespace testing; |
19 | |
20 | namespace lldb_private { |
21 | |
22 | class MockDelegate : public NativeProcessProtocol::NativeDelegate { |
23 | public: |
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_ptr |
32 | // passed as value. |
33 | void NewSubprocess(NativeProcessProtocol *parent_process, |
34 | std::unique_ptr<NativeProcessProtocol> child_process) { |
35 | NewSubprocessImpl(gmock_a0: parent_process, gmock_a1&: child_process); |
36 | } |
37 | }; |
38 | |
39 | // NB: This class doesn't use the override keyword to avoid |
40 | // -Winconsistent-missing-override warnings from the compiler. The |
41 | // inconsistency comes from the overriding definitions in the MOCK_*** macros. |
42 | template <typename T> class MockProcess : public T { |
43 | public: |
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 | else |
68 | return this->SetSoftwareBreakpoint(Addr, Size); |
69 | } |
70 | |
71 | // Redirect base class Read/Write Memory methods to functions whose signatures |
72 | // 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(ExpectedMemory.takeError()); |
79 | } |
80 | BytesRead = ExpectedMemory->size(); |
81 | assert(BytesRead <= Size); |
82 | std::memcpy(dest: Buf, src: ExpectedMemory->data(), n: 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(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(new_size: BytesRead); |
114 | return std::move(Data); |
115 | } |
116 | |
117 | private: |
118 | ArchSpec Arch; |
119 | }; |
120 | |
121 | class FakeMemory { |
122 | public: |
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(EC: llvm::inconvertibleErrorCode(), |
134 | Msg: "Address out of range." ); |
135 | Size = std::min(a: Size, b: Data.size() - (size_t)Addr); |
136 | auto Begin = std::next(x: Data.begin(), n: Addr); |
137 | return std::vector<uint8_t>(Begin, std::next(x: Begin, n: 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(EC: llvm::inconvertibleErrorCode(), |
144 | Msg: "Address out of range." ); |
145 | size_t Size = std::min(a: Chunk.size(), b: Data.size() - (size_t)Addr); |
146 | std::copy_n(first: Chunk.begin(), n: Size, result: &Data[Addr]); |
147 | return Size; |
148 | } |
149 | |
150 | private: |
151 | std::vector<uint8_t> Data; |
152 | addr_t m_start_addr; |
153 | }; |
154 | } // namespace lldb_private |
155 | |
156 | #endif |
157 | |