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