1 //===-- GDBRemoteCommunicationClientTest.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 #include <future> 10 11 #include "GDBRemoteTestUtils.h" 12 13 #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h" 14 #include "lldb/Core/DataBuffer.h" 15 #include "lldb/Core/ModuleSpec.h" 16 #include "lldb/Core/StructuredData.h" 17 18 #include "llvm/ADT/ArrayRef.h" 19 20 using namespace lldb_private::process_gdb_remote; 21 using namespace lldb_private; 22 using namespace lldb; 23 using namespace llvm; 24 25 namespace { 26 27 typedef GDBRemoteCommunication::PacketResult PacketResult; 28 29 struct TestClient : public GDBRemoteCommunicationClient { 30 TestClient() { m_send_acks = false; } 31 }; 32 33 void Handle_QThreadSuffixSupported(MockServer &server, bool supported) { 34 StringExtractorGDBRemote request; 35 ASSERT_EQ(PacketResult::Success, server.GetPacket(request)); 36 ASSERT_EQ("QThreadSuffixSupported", request.GetStringRef()); 37 if (supported) 38 ASSERT_EQ(PacketResult::Success, server.SendOKResponse()); 39 else 40 ASSERT_EQ(PacketResult::Success, server.SendUnimplementedResponse(nullptr)); 41 } 42 43 void HandlePacket(MockServer &server, StringRef expected, StringRef response) { 44 StringExtractorGDBRemote request; 45 ASSERT_EQ(PacketResult::Success, server.GetPacket(request)); 46 ASSERT_EQ(expected, request.GetStringRef()); 47 ASSERT_EQ(PacketResult::Success, server.SendPacket(response)); 48 } 49 50 uint8_t all_registers[] = {'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 51 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'}; 52 std::string all_registers_hex = "404142434445464748494a4b4c4d4e4f"; 53 uint8_t one_register[] = {'A', 'B', 'C', 'D'}; 54 std::string one_register_hex = "41424344"; 55 56 } // end anonymous namespace 57 58 class GDBRemoteCommunicationClientTest : public GDBRemoteTest {}; 59 60 TEST_F(GDBRemoteCommunicationClientTest, WriteRegister) { 61 TestClient client; 62 MockServer server; 63 Connect(client, server); 64 if (HasFailure()) 65 return; 66 67 const lldb::tid_t tid = 0x47; 68 const uint32_t reg_num = 4; 69 std::future<bool> write_result = std::async(std::launch::async, [&] { 70 return client.WriteRegister(tid, reg_num, one_register); 71 }); 72 73 Handle_QThreadSuffixSupported(server, true); 74 75 HandlePacket(server, "P4=" + one_register_hex + ";thread:0047;", "OK"); 76 ASSERT_TRUE(write_result.get()); 77 78 write_result = std::async(std::launch::async, [&] { 79 return client.WriteAllRegisters(tid, all_registers); 80 }); 81 82 HandlePacket(server, "G" + all_registers_hex + ";thread:0047;", "OK"); 83 ASSERT_TRUE(write_result.get()); 84 } 85 86 TEST_F(GDBRemoteCommunicationClientTest, WriteRegisterNoSuffix) { 87 TestClient client; 88 MockServer server; 89 Connect(client, server); 90 if (HasFailure()) 91 return; 92 93 const lldb::tid_t tid = 0x47; 94 const uint32_t reg_num = 4; 95 std::future<bool> write_result = std::async(std::launch::async, [&] { 96 return client.WriteRegister(tid, reg_num, one_register); 97 }); 98 99 Handle_QThreadSuffixSupported(server, false); 100 HandlePacket(server, "Hg47", "OK"); 101 HandlePacket(server, "P4=" + one_register_hex, "OK"); 102 ASSERT_TRUE(write_result.get()); 103 104 write_result = std::async(std::launch::async, [&] { 105 return client.WriteAllRegisters(tid, all_registers); 106 }); 107 108 HandlePacket(server, "G" + all_registers_hex, "OK"); 109 ASSERT_TRUE(write_result.get()); 110 } 111 112 TEST_F(GDBRemoteCommunicationClientTest, ReadRegister) { 113 TestClient client; 114 MockServer server; 115 Connect(client, server); 116 if (HasFailure()) 117 return; 118 119 const lldb::tid_t tid = 0x47; 120 const uint32_t reg_num = 4; 121 std::future<bool> async_result = std::async( 122 std::launch::async, [&] { return client.GetpPacketSupported(tid); }); 123 Handle_QThreadSuffixSupported(server, true); 124 HandlePacket(server, "p0;thread:0047;", one_register_hex); 125 ASSERT_TRUE(async_result.get()); 126 127 std::future<DataBufferSP> read_result = std::async( 128 std::launch::async, [&] { return client.ReadRegister(tid, reg_num); }); 129 HandlePacket(server, "p4;thread:0047;", "41424344"); 130 auto buffer_sp = read_result.get(); 131 ASSERT_TRUE(bool(buffer_sp)); 132 ASSERT_EQ(0, 133 memcmp(buffer_sp->GetBytes(), one_register, sizeof one_register)); 134 135 read_result = std::async(std::launch::async, 136 [&] { return client.ReadAllRegisters(tid); }); 137 HandlePacket(server, "g;thread:0047;", all_registers_hex); 138 buffer_sp = read_result.get(); 139 ASSERT_TRUE(bool(buffer_sp)); 140 ASSERT_EQ(0, 141 memcmp(buffer_sp->GetBytes(), all_registers, sizeof all_registers)); 142 } 143 144 TEST_F(GDBRemoteCommunicationClientTest, SaveRestoreRegistersNoSuffix) { 145 TestClient client; 146 MockServer server; 147 Connect(client, server); 148 if (HasFailure()) 149 return; 150 151 const lldb::tid_t tid = 0x47; 152 uint32_t save_id; 153 std::future<bool> async_result = std::async(std::launch::async, [&] { 154 return client.SaveRegisterState(tid, save_id); 155 }); 156 Handle_QThreadSuffixSupported(server, false); 157 HandlePacket(server, "Hg47", "OK"); 158 HandlePacket(server, "QSaveRegisterState", "1"); 159 ASSERT_TRUE(async_result.get()); 160 EXPECT_EQ(1u, save_id); 161 162 async_result = std::async(std::launch::async, [&] { 163 return client.RestoreRegisterState(tid, save_id); 164 }); 165 HandlePacket(server, "QRestoreRegisterState:1", "OK"); 166 ASSERT_TRUE(async_result.get()); 167 } 168 169 TEST_F(GDBRemoteCommunicationClientTest, SyncThreadState) { 170 TestClient client; 171 MockServer server; 172 Connect(client, server); 173 if (HasFailure()) 174 return; 175 176 const lldb::tid_t tid = 0x47; 177 std::future<bool> async_result = std::async( 178 std::launch::async, [&] { return client.SyncThreadState(tid); }); 179 HandlePacket(server, "qSyncThreadStateSupported", "OK"); 180 HandlePacket(server, "QSyncThreadState:0047;", "OK"); 181 ASSERT_TRUE(async_result.get()); 182 } 183 184 TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo) { 185 TestClient client; 186 MockServer server; 187 Connect(client, server); 188 if (HasFailure()) 189 return; 190 191 llvm::Triple triple("i386-pc-linux"); 192 193 FileSpec file_specs[] = { 194 FileSpec("/foo/bar.so", false, FileSpec::ePathSyntaxPosix), 195 FileSpec("/foo/baz.so", false, FileSpec::ePathSyntaxPosix), 196 197 // This is a bit dodgy but we currently depend on GetModulesInfo not 198 // performing denormalization. It can go away once the users 199 // (DynamicLoaderPOSIXDYLD, at least) correctly set the path syntax for 200 // the FileSpecs they create. 201 FileSpec("/foo/baw.so", false, FileSpec::ePathSyntaxWindows), 202 }; 203 std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result = 204 std::async(std::launch::async, 205 [&] { return client.GetModulesInfo(file_specs, triple); }); 206 HandlePacket( 207 server, "jModulesInfo:[" 208 R"({"file":"/foo/bar.so","triple":"i386-pc-linux"},)" 209 R"({"file":"/foo/baz.so","triple":"i386-pc-linux"},)" 210 R"({"file":"/foo/baw.so","triple":"i386-pc-linux"}])", 211 R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)" 212 R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])"); 213 214 auto result = async_result.get(); 215 ASSERT_TRUE(result.hasValue()); 216 ASSERT_EQ(1u, result->size()); 217 EXPECT_EQ("/foo/bar.so", result.getValue()[0].GetFileSpec().GetPath()); 218 EXPECT_EQ(triple, result.getValue()[0].GetArchitecture().GetTriple()); 219 EXPECT_EQ(UUID("@ABCDEFGHIJKLMNO", 16), result.getValue()[0].GetUUID()); 220 EXPECT_EQ(0u, result.getValue()[0].GetObjectOffset()); 221 EXPECT_EQ(1234u, result.getValue()[0].GetObjectSize()); 222 } 223 224 TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfoInvalidResponse) { 225 TestClient client; 226 MockServer server; 227 Connect(client, server); 228 if (HasFailure()) 229 return; 230 231 llvm::Triple triple("i386-pc-linux"); 232 FileSpec file_spec("/foo/bar.so", false, FileSpec::ePathSyntaxPosix); 233 234 const char *invalid_responses[] = { 235 "OK", "E47", "[]", 236 // no UUID 237 R"([{"triple":"i386-pc-linux",)" 238 R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}])", 239 // no triple 240 R"([{"uuid":"404142434445464748494a4b4c4d4e4f",)" 241 R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}])", 242 // no file_path 243 R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)" 244 R"("file_offset":0,"file_size":1234}])", 245 // no file_offset 246 R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)" 247 R"("file_path":"/foo/bar.so","file_size":1234}])", 248 // no file_size 249 R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)" 250 R"("file_path":"/foo/bar.so","file_offset":0}])", 251 }; 252 253 for (const char *response : invalid_responses) { 254 std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result = 255 std::async(std::launch::async, 256 [&] { return client.GetModulesInfo(file_spec, triple); }); 257 HandlePacket( 258 server, 259 R"(jModulesInfo:[{"file":"/foo/bar.so","triple":"i386-pc-linux"}])", 260 response); 261 262 ASSERT_FALSE(async_result.get().hasValue()) << "response was: " << response; 263 } 264 } 265 266 TEST_F(GDBRemoteCommunicationClientTest, TestPacketSpeedJSON) { 267 TestClient client; 268 MockServer server; 269 Connect(client, server); 270 if (HasFailure()) 271 return; 272 273 std::thread server_thread([&server] { 274 for (;;) { 275 StringExtractorGDBRemote request; 276 PacketResult result = server.GetPacket(request); 277 if (result == PacketResult::ErrorDisconnected) 278 return; 279 ASSERT_EQ(PacketResult::Success, result); 280 StringRef ref = request.GetStringRef(); 281 ASSERT_TRUE(ref.consume_front("qSpeedTest:response_size:")); 282 int size; 283 ASSERT_FALSE(ref.consumeInteger(10, size)) << "ref: " << ref; 284 std::string response(size, 'X'); 285 ASSERT_EQ(PacketResult::Success, server.SendPacket(response)); 286 } 287 }); 288 289 StreamString ss; 290 client.TestPacketSpeed(10, 32, 32, 4096, true, ss); 291 client.Disconnect(); 292 server_thread.join(); 293 294 GTEST_LOG_(INFO) << "Formatted output: " << ss.GetData(); 295 auto object_sp = StructuredData::ParseJSON(ss.GetString()); 296 ASSERT_TRUE(bool(object_sp)); 297 auto dict_sp = object_sp->GetAsDictionary(); 298 ASSERT_TRUE(bool(dict_sp)); 299 300 object_sp = dict_sp->GetValueForKey("packet_speeds"); 301 ASSERT_TRUE(bool(object_sp)); 302 dict_sp = object_sp->GetAsDictionary(); 303 ASSERT_TRUE(bool(dict_sp)); 304 305 int num_packets; 306 ASSERT_TRUE(dict_sp->GetValueForKeyAsInteger("num_packets", num_packets)) 307 << ss.GetString(); 308 ASSERT_EQ(10, num_packets); 309 } 310