xref: /llvm-project/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp (revision bf9f21a28be171dc500cc68b4cb1fcd3fc33f229)
1 //===-- GDBRemoteCommunicationClientTest.cpp ------------------------------===//
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 #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h"
9 #include "GDBRemoteTestUtils.h"
10 #include "lldb/Core/ModuleSpec.h"
11 #include "lldb/Host/XML.h"
12 #include "lldb/Target/MemoryRegionInfo.h"
13 #include "lldb/Utility/DataBuffer.h"
14 #include "lldb/Utility/StructuredData.h"
15 #include "lldb/lldb-enumerations.h"
16 #include "llvm/ADT/ArrayRef.h"
17 #include "llvm/Testing/Support/Error.h"
18 #include "gmock/gmock.h"
19 #include <future>
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,
45                   const testing::Matcher<const std::string &> &expected,
46                   StringRef response) {
47   StringExtractorGDBRemote request;
48   ASSERT_EQ(PacketResult::Success, server.GetPacket(request));
49   ASSERT_THAT(std::string(request.GetStringRef()), expected);
50   ASSERT_EQ(PacketResult::Success, server.SendPacket(response));
51 }
52 
53 uint8_t all_registers[] = {'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
54                            'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'};
55 std::string all_registers_hex = "404142434445464748494a4b4c4d4e4f";
56 uint8_t one_register[] = {'A', 'B', 'C', 'D'};
57 std::string one_register_hex = "41424344";
58 
59 } // end anonymous namespace
60 
61 class GDBRemoteCommunicationClientTest : public GDBRemoteTest {
62 public:
63   void SetUp() override {
64     ASSERT_THAT_ERROR(GDBRemoteCommunication::ConnectLocally(client, server),
65                       llvm::Succeeded());
66   }
67 
68 protected:
69   TestClient client;
70   MockServer server;
71 };
72 
73 TEST_F(GDBRemoteCommunicationClientTest, WriteRegister) {
74   const lldb::tid_t tid = 0x47;
75   const uint32_t reg_num = 4;
76   std::future<bool> write_result = std::async(std::launch::async, [&] {
77     return client.WriteRegister(tid, reg_num, one_register);
78   });
79 
80   Handle_QThreadSuffixSupported(server, true);
81 
82   HandlePacket(server, "P4=" + one_register_hex + ";thread:0047;", "OK");
83   ASSERT_TRUE(write_result.get());
84 
85   write_result = std::async(std::launch::async, [&] {
86     return client.WriteAllRegisters(tid, all_registers);
87   });
88 
89   HandlePacket(server, "G" + all_registers_hex + ";thread:0047;", "OK");
90   ASSERT_TRUE(write_result.get());
91 }
92 
93 TEST_F(GDBRemoteCommunicationClientTest, WriteRegisterNoSuffix) {
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   const lldb::tid_t tid = 0x47;
115   const uint32_t reg_num = 4;
116   std::future<bool> async_result = std::async(
117       std::launch::async, [&] { return client.GetpPacketSupported(tid); });
118   Handle_QThreadSuffixSupported(server, true);
119   HandlePacket(server, "p0;thread:0047;", one_register_hex);
120   ASSERT_TRUE(async_result.get());
121 
122   std::future<DataBufferSP> read_result = std::async(
123       std::launch::async, [&] { return client.ReadRegister(tid, reg_num); });
124   HandlePacket(server, "p4;thread:0047;", "41424344");
125   auto buffer_sp = read_result.get();
126   ASSERT_TRUE(bool(buffer_sp));
127   ASSERT_EQ(0,
128             memcmp(buffer_sp->GetBytes(), one_register, sizeof one_register));
129 
130   read_result = std::async(std::launch::async,
131                            [&] { return client.ReadAllRegisters(tid); });
132   HandlePacket(server, "g;thread:0047;", all_registers_hex);
133   buffer_sp = read_result.get();
134   ASSERT_TRUE(bool(buffer_sp));
135   ASSERT_EQ(0,
136             memcmp(buffer_sp->GetBytes(), all_registers, sizeof all_registers));
137 }
138 
139 TEST_F(GDBRemoteCommunicationClientTest, SaveRestoreRegistersNoSuffix) {
140   const lldb::tid_t tid = 0x47;
141   uint32_t save_id;
142   std::future<bool> async_result = std::async(std::launch::async, [&] {
143     return client.SaveRegisterState(tid, save_id);
144   });
145   Handle_QThreadSuffixSupported(server, false);
146   HandlePacket(server, "Hg47", "OK");
147   HandlePacket(server, "QSaveRegisterState", "1");
148   ASSERT_TRUE(async_result.get());
149   EXPECT_EQ(1u, save_id);
150 
151   async_result = std::async(std::launch::async, [&] {
152     return client.RestoreRegisterState(tid, save_id);
153   });
154   HandlePacket(server, "QRestoreRegisterState:1", "OK");
155   ASSERT_TRUE(async_result.get());
156 }
157 
158 TEST_F(GDBRemoteCommunicationClientTest, SyncThreadState) {
159   const lldb::tid_t tid = 0x47;
160   std::future<bool> async_result = std::async(
161       std::launch::async, [&] { return client.SyncThreadState(tid); });
162   HandlePacket(server, "qSyncThreadStateSupported", "OK");
163   HandlePacket(server, "QSyncThreadState:0047;", "OK");
164   ASSERT_TRUE(async_result.get());
165 }
166 
167 TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo) {
168   llvm::Triple triple("i386-pc-linux");
169 
170   FileSpec file_specs[] = {
171       FileSpec("/foo/bar.so", FileSpec::Style::posix),
172       FileSpec("/foo/baz.so", FileSpec::Style::posix),
173 
174       // This is a bit dodgy but we currently depend on GetModulesInfo not
175       // performing denormalization. It can go away once the users
176       // (DynamicLoaderPOSIXDYLD, at least) correctly set the path syntax for
177       // the FileSpecs they create.
178       FileSpec("/foo/baw.so", FileSpec::Style::windows),
179   };
180   std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result =
181       std::async(std::launch::async,
182                  [&] { return client.GetModulesInfo(file_specs, triple); });
183   HandlePacket(
184       server, "jModulesInfo:["
185               R"({"file":"/foo/bar.so","triple":"i386-pc-linux"},)"
186               R"({"file":"/foo/baz.so","triple":"i386-pc-linux"},)"
187               R"({"file":"/foo/baw.so","triple":"i386-pc-linux"}])",
188       R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
189       R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])");
190 
191   auto result = async_result.get();
192   ASSERT_TRUE(result.hasValue());
193   ASSERT_EQ(1u, result->size());
194   EXPECT_EQ("/foo/bar.so", result.getValue()[0].GetFileSpec().GetPath());
195   EXPECT_EQ(triple, result.getValue()[0].GetArchitecture().GetTriple());
196   EXPECT_EQ(UUID::fromData("@ABCDEFGHIJKLMNO", 16),
197             result.getValue()[0].GetUUID());
198   EXPECT_EQ(0u, result.getValue()[0].GetObjectOffset());
199   EXPECT_EQ(1234u, result.getValue()[0].GetObjectSize());
200 }
201 
202 TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo_UUID20) {
203   llvm::Triple triple("i386-pc-linux");
204 
205   FileSpec file_spec("/foo/bar.so", FileSpec::Style::posix);
206   std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result =
207       std::async(std::launch::async,
208                  [&] { return client.GetModulesInfo(file_spec, triple); });
209   HandlePacket(
210       server,
211       "jModulesInfo:["
212       R"({"file":"/foo/bar.so","triple":"i386-pc-linux"}])",
213       R"([{"uuid":"404142434445464748494a4b4c4d4e4f50515253","triple":"i386-pc-linux",)"
214       R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])");
215 
216   auto result = async_result.get();
217   ASSERT_TRUE(result.hasValue());
218   ASSERT_EQ(1u, result->size());
219   EXPECT_EQ("/foo/bar.so", result.getValue()[0].GetFileSpec().GetPath());
220   EXPECT_EQ(triple, result.getValue()[0].GetArchitecture().GetTriple());
221   EXPECT_EQ(UUID::fromData("@ABCDEFGHIJKLMNOPQRS", 20),
222             result.getValue()[0].GetUUID());
223   EXPECT_EQ(0u, result.getValue()[0].GetObjectOffset());
224   EXPECT_EQ(1234u, result.getValue()[0].GetObjectSize());
225 }
226 
227 TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfoInvalidResponse) {
228   llvm::Triple triple("i386-pc-linux");
229   FileSpec file_spec("/foo/bar.so", FileSpec::Style::posix);
230 
231   const char *invalid_responses[] = {
232       // no UUID
233       R"([{"triple":"i386-pc-linux",)"
234       R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])",
235       // invalid UUID
236       R"([{"uuid":"XXXXXX","triple":"i386-pc-linux",)"
237       R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])",
238       // no triple
239       R"([{"uuid":"404142434445464748494a4b4c4d4e4f",)"
240       R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])",
241       // no file_path
242       R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
243       R"("file_offset":0,"file_size":1234}]])",
244       // no file_offset
245       R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
246       R"("file_path":"/foo/bar.so","file_size":1234}]])",
247       // no file_size
248       R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
249       R"("file_path":"/foo/bar.so","file_offset":0}]])",
250   };
251 
252   for (const char *response : invalid_responses) {
253     std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result =
254         std::async(std::launch::async,
255                    [&] { return client.GetModulesInfo(file_spec, triple); });
256     HandlePacket(
257         server,
258         R"(jModulesInfo:[{"file":"/foo/bar.so","triple":"i386-pc-linux"}])",
259         response);
260 
261     auto result = async_result.get();
262     ASSERT_TRUE(result);
263     ASSERT_EQ(0u, result->size()) << "response was: " << response;
264   }
265 }
266 
267 TEST_F(GDBRemoteCommunicationClientTest, TestPacketSpeedJSON) {
268   std::thread server_thread([this] {
269     for (;;) {
270       StringExtractorGDBRemote request;
271       PacketResult result = server.GetPacket(request);
272       if (result == PacketResult::ErrorDisconnected)
273         return;
274       ASSERT_EQ(PacketResult::Success, result);
275       StringRef ref = request.GetStringRef();
276       ASSERT_TRUE(ref.consume_front("qSpeedTest:response_size:"));
277       int size;
278       ASSERT_FALSE(ref.consumeInteger(10, size)) << "ref: " << ref;
279       std::string response(size, 'X');
280       ASSERT_EQ(PacketResult::Success, server.SendPacket(response));
281     }
282   });
283 
284   StreamString ss;
285   client.TestPacketSpeed(10, 32, 32, 4096, true, ss);
286   client.Disconnect();
287   server_thread.join();
288 
289   GTEST_LOG_(INFO) << "Formatted output: " << ss.GetData();
290   auto object_sp = StructuredData::ParseJSON(std::string(ss.GetString()));
291   ASSERT_TRUE(bool(object_sp));
292   auto dict_sp = object_sp->GetAsDictionary();
293   ASSERT_TRUE(bool(dict_sp));
294 
295   object_sp = dict_sp->GetValueForKey("packet_speeds");
296   ASSERT_TRUE(bool(object_sp));
297   dict_sp = object_sp->GetAsDictionary();
298   ASSERT_TRUE(bool(dict_sp));
299 
300   int num_packets;
301   ASSERT_TRUE(dict_sp->GetValueForKeyAsInteger("num_packets", num_packets))
302       << ss.GetString();
303   ASSERT_EQ(10, num_packets);
304 }
305 
306 TEST_F(GDBRemoteCommunicationClientTest, SendSignalsToIgnore) {
307   std::future<Status> result = std::async(std::launch::async, [&] {
308     return client.SendSignalsToIgnore({2, 3, 5, 7, 0xB, 0xD, 0x11});
309   });
310 
311   HandlePacket(server, "QPassSignals:02;03;05;07;0b;0d;11", "OK");
312   EXPECT_TRUE(result.get().Success());
313 
314   result = std::async(std::launch::async, [&] {
315     return client.SendSignalsToIgnore(std::vector<int32_t>());
316   });
317 
318   HandlePacket(server, "QPassSignals:", "OK");
319   EXPECT_TRUE(result.get().Success());
320 }
321 
322 TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfo) {
323   const lldb::addr_t addr = 0xa000;
324   MemoryRegionInfo region_info;
325   std::future<Status> result = std::async(std::launch::async, [&] {
326     return client.GetMemoryRegionInfo(addr, region_info);
327   });
328 
329   HandlePacket(server,
330       "qMemoryRegionInfo:a000",
331       "start:a000;size:2000;permissions:rx;name:2f666f6f2f6261722e736f;");
332   if (XMLDocument::XMLEnabled()) {
333     // In case we have XML support, this will also do a "qXfer:memory-map".
334     // Preceeded by a query for supported extensions. Pretend we don't support
335     // that.
336     HandlePacket(server, testing::StartsWith("qSupported:"), "");
337   }
338   EXPECT_TRUE(result.get().Success());
339   EXPECT_EQ(addr, region_info.GetRange().GetRangeBase());
340   EXPECT_EQ(0x2000u, region_info.GetRange().GetByteSize());
341   EXPECT_EQ(MemoryRegionInfo::eYes, region_info.GetReadable());
342   EXPECT_EQ(MemoryRegionInfo::eNo, region_info.GetWritable());
343   EXPECT_EQ(MemoryRegionInfo::eYes, region_info.GetExecutable());
344   EXPECT_EQ("/foo/bar.so", region_info.GetName().GetStringRef());
345   EXPECT_EQ(MemoryRegionInfo::eDontKnow, region_info.GetMemoryTagged());
346 
347   result = std::async(std::launch::async, [&] {
348     return client.GetMemoryRegionInfo(addr, region_info);
349   });
350 
351   HandlePacket(server, "qMemoryRegionInfo:a000",
352                "start:a000;size:2000;flags:;");
353   EXPECT_TRUE(result.get().Success());
354   EXPECT_EQ(MemoryRegionInfo::eNo, region_info.GetMemoryTagged());
355 
356   result = std::async(std::launch::async, [&] {
357     return client.GetMemoryRegionInfo(addr, region_info);
358   });
359 
360   HandlePacket(server, "qMemoryRegionInfo:a000",
361                "start:a000;size:2000;flags: mt  zz mt  ;");
362   EXPECT_TRUE(result.get().Success());
363   EXPECT_EQ(MemoryRegionInfo::eYes, region_info.GetMemoryTagged());
364 }
365 
366 TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfoInvalidResponse) {
367   const lldb::addr_t addr = 0x4000;
368   MemoryRegionInfo region_info;
369   std::future<Status> result = std::async(std::launch::async, [&] {
370     return client.GetMemoryRegionInfo(addr, region_info);
371   });
372 
373   HandlePacket(server, "qMemoryRegionInfo:4000", "start:4000;size:0000;");
374   if (XMLDocument::XMLEnabled()) {
375     // In case we have XML support, this will also do a "qXfer:memory-map".
376     // Preceeded by a query for supported extensions. Pretend we don't support
377     // that.
378     HandlePacket(server, testing::StartsWith("qSupported:"), "");
379   }
380   EXPECT_FALSE(result.get().Success());
381 }
382 
383 TEST_F(GDBRemoteCommunicationClientTest, SendTraceSupportedPacket) {
384   TraceSupportedResponse trace_type;
385   std::string error_message;
386   auto callback = [&] {
387     if (llvm::Expected<TraceSupportedResponse> trace_type_or_err =
388             client.SendTraceSupported()) {
389       trace_type = *trace_type_or_err;
390       error_message = "";
391       return true;
392     } else {
393       trace_type = {};
394       error_message = llvm::toString(trace_type_or_err.takeError());
395       return false;
396     }
397   };
398 
399   // Success response
400   {
401     std::future<bool> result = std::async(std::launch::async, callback);
402 
403     HandlePacket(
404         server, "jLLDBTraceSupported",
405         R"({"name":"intel-pt","description":"Intel Processor Trace"}])");
406 
407     EXPECT_TRUE(result.get());
408     ASSERT_STREQ(trace_type.name.c_str(), "intel-pt");
409     ASSERT_STREQ(trace_type.description.c_str(), "Intel Processor Trace");
410   }
411 
412   // Error response - wrong json
413   {
414     std::future<bool> result = std::async(std::launch::async, callback);
415 
416     HandlePacket(server, "jLLDBTraceSupported", R"({"type":"intel-pt"}])");
417 
418     EXPECT_FALSE(result.get());
419     ASSERT_STREQ(error_message.c_str(), "missing value at TraceSupportedResponse.description");
420   }
421 
422   // Error response
423   {
424     std::future<bool> result = std::async(std::launch::async, callback);
425 
426     HandlePacket(server, "jLLDBTraceSupported", "E23");
427 
428     EXPECT_FALSE(result.get());
429   }
430 
431   // Error response with error message
432   {
433     std::future<bool> result = std::async(std::launch::async, callback);
434 
435     HandlePacket(server, "jLLDBTraceSupported",
436                  "E23;50726F63657373206E6F742072756E6E696E672E");
437 
438     EXPECT_FALSE(result.get());
439     ASSERT_STREQ(error_message.c_str(), "Process not running.");
440   }
441 }
442 
443 TEST_F(GDBRemoteCommunicationClientTest, GetQOffsets) {
444   const auto &GetQOffsets = [&](llvm::StringRef response) {
445     std::future<Optional<QOffsets>> result = std::async(
446         std::launch::async, [&] { return client.GetQOffsets(); });
447 
448     HandlePacket(server, "qOffsets", response);
449     return result.get();
450   };
451   EXPECT_EQ((QOffsets{false, {0x1234, 0x1234}}),
452             GetQOffsets("Text=1234;Data=1234"));
453   EXPECT_EQ((QOffsets{false, {0x1234, 0x1234, 0x1234}}),
454             GetQOffsets("Text=1234;Data=1234;Bss=1234"));
455   EXPECT_EQ((QOffsets{true, {0x1234}}), GetQOffsets("TextSeg=1234"));
456   EXPECT_EQ((QOffsets{true, {0x1234, 0x2345}}),
457             GetQOffsets("TextSeg=1234;DataSeg=2345"));
458 
459   EXPECT_EQ(llvm::None, GetQOffsets("E05"));
460   EXPECT_EQ(llvm::None, GetQOffsets("Text=bogus"));
461   EXPECT_EQ(llvm::None, GetQOffsets("Text=1234"));
462   EXPECT_EQ(llvm::None, GetQOffsets("Text=1234;Data=1234;"));
463   EXPECT_EQ(llvm::None, GetQOffsets("Text=1234;Data=1234;Bss=1234;"));
464   EXPECT_EQ(llvm::None, GetQOffsets("TEXTSEG=1234"));
465   EXPECT_EQ(llvm::None, GetQOffsets("TextSeg=0x1234"));
466   EXPECT_EQ(llvm::None, GetQOffsets("TextSeg=12345678123456789"));
467 }
468