1 //===-- NativeProcessProtocolTest.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 #include "lldb/Host/common/NativeProcessProtocol.h" 10 #include "llvm/Testing/Support/Error.h" 11 #include "gmock/gmock.h" 12 13 using namespace lldb_private; 14 using namespace lldb; 15 using namespace testing; 16 17 namespace { 18 class MockDelegate : public NativeProcessProtocol::NativeDelegate { 19 public: 20 MOCK_METHOD1(InitializeDelegate, void(NativeProcessProtocol *Process)); 21 MOCK_METHOD2(ProcessStateChanged, 22 void(NativeProcessProtocol *Process, StateType State)); 23 MOCK_METHOD1(DidExec, void(NativeProcessProtocol *Process)); 24 }; 25 26 // NB: This class doesn't use the override keyword to avoid 27 // -Winconsistent-missing-override warnings from the compiler. The 28 // inconsistency comes from the overriding definitions in the MOCK_*** macros. 29 class MockProcess : public NativeProcessProtocol { 30 public: 31 MockProcess(NativeDelegate &Delegate, const ArchSpec &Arch, 32 lldb::pid_t Pid = 1) 33 : NativeProcessProtocol(Pid, -1, Delegate), Arch(Arch) {} 34 35 MOCK_METHOD1(Resume, Status(const ResumeActionList &ResumeActions)); 36 MOCK_METHOD0(Halt, Status()); 37 MOCK_METHOD0(Detach, Status()); 38 MOCK_METHOD1(Signal, Status(int Signo)); 39 MOCK_METHOD0(Kill, Status()); 40 MOCK_METHOD3(AllocateMemory, 41 Status(size_t Size, uint32_t Permissions, addr_t &Addr)); 42 MOCK_METHOD1(DeallocateMemory, Status(addr_t Addr)); 43 MOCK_METHOD0(GetSharedLibraryInfoAddress, addr_t()); 44 MOCK_METHOD0(UpdateThreads, size_t()); 45 MOCK_CONST_METHOD0(GetAuxvData, 46 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>()); 47 MOCK_METHOD2(GetLoadedModuleFileSpec, 48 Status(const char *ModulePath, FileSpec &Spec)); 49 MOCK_METHOD2(GetFileLoadAddress, 50 Status(const llvm::StringRef &FileName, addr_t &Addr)); 51 52 const ArchSpec &GetArchitecture() const /*override*/ { return Arch; } 53 Status SetBreakpoint(lldb::addr_t Addr, uint32_t Size, 54 bool Hardware) /*override*/ { 55 if (Hardware) 56 return SetHardwareBreakpoint(Addr, Size); 57 else 58 return SetSoftwareBreakpoint(Addr, Size); 59 } 60 61 // Redirect base class Read/Write Memory methods to functions whose signatures 62 // are more mock-friendly. 63 Status ReadMemory(addr_t Addr, void *Buf, size_t Size, 64 size_t &BytesRead) /*override*/; 65 Status WriteMemory(addr_t Addr, const void *Buf, size_t Size, 66 size_t &BytesWritten) /*override*/; 67 68 MOCK_METHOD2(ReadMemory, 69 llvm::Expected<std::vector<uint8_t>>(addr_t Addr, size_t Size)); 70 MOCK_METHOD2(WriteMemory, 71 llvm::Expected<size_t>(addr_t Addr, 72 llvm::ArrayRef<uint8_t> Data)); 73 74 using NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode; 75 llvm::Expected<std::vector<uint8_t>> ReadMemoryWithoutTrap(addr_t Addr, 76 size_t Size); 77 78 private: 79 ArchSpec Arch; 80 }; 81 82 class FakeMemory { 83 public: 84 FakeMemory(llvm::ArrayRef<uint8_t> Data) : Data(Data) {} 85 llvm::Expected<std::vector<uint8_t>> Read(addr_t Addr, size_t Size); 86 llvm::Expected<size_t> Write(addr_t Addr, llvm::ArrayRef<uint8_t> Chunk); 87 88 private: 89 std::vector<uint8_t> Data; 90 }; 91 } // namespace 92 93 Status MockProcess::ReadMemory(addr_t Addr, void *Buf, size_t Size, 94 size_t &BytesRead) { 95 auto ExpectedMemory = ReadMemory(Addr, Size); 96 if (!ExpectedMemory) { 97 BytesRead = 0; 98 return Status(ExpectedMemory.takeError()); 99 } 100 BytesRead = ExpectedMemory->size(); 101 assert(BytesRead <= Size); 102 std::memcpy(Buf, ExpectedMemory->data(), BytesRead); 103 return Status(); 104 } 105 106 Status MockProcess::WriteMemory(addr_t Addr, const void *Buf, size_t Size, 107 size_t &BytesWritten) { 108 auto ExpectedBytes = WriteMemory( 109 Addr, llvm::makeArrayRef(static_cast<const uint8_t *>(Buf), Size)); 110 if (!ExpectedBytes) { 111 BytesWritten = 0; 112 return Status(ExpectedBytes.takeError()); 113 } 114 BytesWritten = *ExpectedBytes; 115 return Status(); 116 } 117 118 llvm::Expected<std::vector<uint8_t>> 119 MockProcess::ReadMemoryWithoutTrap(addr_t Addr, size_t Size) { 120 std::vector<uint8_t> Data(Size, 0); 121 size_t BytesRead; 122 Status ST = NativeProcessProtocol::ReadMemoryWithoutTrap( 123 Addr, Data.data(), Data.size(), BytesRead); 124 if (ST.Fail()) 125 return ST.ToError(); 126 Data.resize(BytesRead); 127 return std::move(Data); 128 } 129 130 llvm::Expected<std::vector<uint8_t>> FakeMemory::Read(addr_t Addr, 131 size_t Size) { 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> FakeMemory::Write(addr_t Addr, 141 llvm::ArrayRef<uint8_t> Chunk) { 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 150 TEST(NativeProcessProtocolTest, SetBreakpoint) { 151 NiceMock<MockDelegate> DummyDelegate; 152 MockProcess Process(DummyDelegate, ArchSpec("x86_64-pc-linux")); 153 auto Trap = cantFail(Process.GetSoftwareBreakpointTrapOpcode(1)); 154 InSequence S; 155 EXPECT_CALL(Process, ReadMemory(0x47, 1)) 156 .WillOnce(Return(ByMove(std::vector<uint8_t>{0xbb}))); 157 EXPECT_CALL(Process, WriteMemory(0x47, Trap)).WillOnce(Return(ByMove(1))); 158 EXPECT_CALL(Process, ReadMemory(0x47, 1)).WillOnce(Return(ByMove(Trap))); 159 EXPECT_THAT_ERROR(Process.SetBreakpoint(0x47, 0, false).ToError(), 160 llvm::Succeeded()); 161 } 162 163 TEST(NativeProcessProtocolTest, SetBreakpointFailRead) { 164 NiceMock<MockDelegate> DummyDelegate; 165 MockProcess Process(DummyDelegate, ArchSpec("x86_64-pc-linux")); 166 EXPECT_CALL(Process, ReadMemory(0x47, 1)) 167 .WillOnce(Return(ByMove( 168 llvm::createStringError(llvm::inconvertibleErrorCode(), "Foo")))); 169 EXPECT_THAT_ERROR(Process.SetBreakpoint(0x47, 0, false).ToError(), 170 llvm::Failed()); 171 } 172 173 TEST(NativeProcessProtocolTest, SetBreakpointFailWrite) { 174 NiceMock<MockDelegate> DummyDelegate; 175 MockProcess Process(DummyDelegate, ArchSpec("x86_64-pc-linux")); 176 auto Trap = cantFail(Process.GetSoftwareBreakpointTrapOpcode(1)); 177 InSequence S; 178 EXPECT_CALL(Process, ReadMemory(0x47, 1)) 179 .WillOnce(Return(ByMove(std::vector<uint8_t>{0xbb}))); 180 EXPECT_CALL(Process, WriteMemory(0x47, Trap)) 181 .WillOnce(Return(ByMove( 182 llvm::createStringError(llvm::inconvertibleErrorCode(), "Foo")))); 183 EXPECT_THAT_ERROR(Process.SetBreakpoint(0x47, 0, false).ToError(), 184 llvm::Failed()); 185 } 186 187 TEST(NativeProcessProtocolTest, SetBreakpointFailVerify) { 188 NiceMock<MockDelegate> DummyDelegate; 189 MockProcess Process(DummyDelegate, ArchSpec("x86_64-pc-linux")); 190 auto Trap = cantFail(Process.GetSoftwareBreakpointTrapOpcode(1)); 191 InSequence S; 192 EXPECT_CALL(Process, ReadMemory(0x47, 1)) 193 .WillOnce(Return(ByMove(std::vector<uint8_t>{0xbb}))); 194 EXPECT_CALL(Process, WriteMemory(0x47, Trap)).WillOnce(Return(ByMove(1))); 195 EXPECT_CALL(Process, ReadMemory(0x47, 1)) 196 .WillOnce(Return(ByMove( 197 llvm::createStringError(llvm::inconvertibleErrorCode(), "Foo")))); 198 EXPECT_THAT_ERROR(Process.SetBreakpoint(0x47, 0, false).ToError(), 199 llvm::Failed()); 200 } 201 202 TEST(NativeProcessProtocolTest, ReadMemoryWithoutTrap) { 203 NiceMock<MockDelegate> DummyDelegate; 204 MockProcess Process(DummyDelegate, ArchSpec("aarch64-pc-linux")); 205 FakeMemory M{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}; 206 EXPECT_CALL(Process, ReadMemory(_, _)) 207 .WillRepeatedly(Invoke(&M, &FakeMemory::Read)); 208 EXPECT_CALL(Process, WriteMemory(_, _)) 209 .WillRepeatedly(Invoke(&M, &FakeMemory::Write)); 210 211 EXPECT_THAT_ERROR(Process.SetBreakpoint(0x4, 0, false).ToError(), 212 llvm::Succeeded()); 213 EXPECT_THAT_EXPECTED( 214 Process.ReadMemoryWithoutTrap(0, 10), 215 llvm::HasValue(std::vector<uint8_t>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})); 216 EXPECT_THAT_EXPECTED(Process.ReadMemoryWithoutTrap(0, 6), 217 llvm::HasValue(std::vector<uint8_t>{0, 1, 2, 3, 4, 5})); 218 EXPECT_THAT_EXPECTED(Process.ReadMemoryWithoutTrap(6, 4), 219 llvm::HasValue(std::vector<uint8_t>{6, 7, 8, 9})); 220 EXPECT_THAT_EXPECTED(Process.ReadMemoryWithoutTrap(6, 2), 221 llvm::HasValue(std::vector<uint8_t>{6, 7})); 222 EXPECT_THAT_EXPECTED(Process.ReadMemoryWithoutTrap(4, 2), 223 llvm::HasValue(std::vector<uint8_t>{4, 5})); 224 } 225