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