xref: /llvm-project/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp (revision 93df2fbeabaf5f706ff01aafc7b03a811bf8c5a1)
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/Core/TraceOptions.h"
17 #include "lldb/Target/MemoryRegionInfo.h"
18 #include "lldb/Utility/DataBuffer.h"
19 #include "lldb/lldb-enumerations.h"
20 #include "llvm/ADT/ArrayRef.h"
21 #include "llvm/Testing/Support/Error.h"
22 
23 using namespace lldb_private::process_gdb_remote;
24 using namespace lldb_private;
25 using namespace lldb;
26 using namespace llvm;
27 
28 namespace {
29 
30 typedef GDBRemoteCommunication::PacketResult PacketResult;
31 
32 struct TestClient : public GDBRemoteCommunicationClient {
33   TestClient() { m_send_acks = false; }
34 };
35 
36 void Handle_QThreadSuffixSupported(MockServer &server, bool supported) {
37   StringExtractorGDBRemote request;
38   ASSERT_EQ(PacketResult::Success, server.GetPacket(request));
39   ASSERT_EQ("QThreadSuffixSupported", request.GetStringRef());
40   if (supported)
41     ASSERT_EQ(PacketResult::Success, server.SendOKResponse());
42   else
43     ASSERT_EQ(PacketResult::Success, server.SendUnimplementedResponse(nullptr));
44 }
45 
46 void HandlePacket(MockServer &server, StringRef expected, StringRef response) {
47   StringExtractorGDBRemote request;
48   ASSERT_EQ(PacketResult::Success, server.GetPacket(request));
49   ASSERT_EQ(expected, request.GetStringRef());
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(Connect(client, server), llvm::Succeeded());
65   }
66 
67 protected:
68   TestClient client;
69   MockServer server;
70 };
71 
72 TEST_F(GDBRemoteCommunicationClientTest, WriteRegister) {
73   const lldb::tid_t tid = 0x47;
74   const uint32_t reg_num = 4;
75   std::future<bool> write_result = std::async(std::launch::async, [&] {
76     return client.WriteRegister(tid, reg_num, one_register);
77   });
78 
79   Handle_QThreadSuffixSupported(server, true);
80 
81   HandlePacket(server, "P4=" + one_register_hex + ";thread:0047;", "OK");
82   ASSERT_TRUE(write_result.get());
83 
84   write_result = std::async(std::launch::async, [&] {
85     return client.WriteAllRegisters(tid, all_registers);
86   });
87 
88   HandlePacket(server, "G" + all_registers_hex + ";thread:0047;", "OK");
89   ASSERT_TRUE(write_result.get());
90 }
91 
92 TEST_F(GDBRemoteCommunicationClientTest, WriteRegisterNoSuffix) {
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   const lldb::tid_t tid = 0x47;
114   const uint32_t reg_num = 4;
115   std::future<bool> async_result = std::async(
116       std::launch::async, [&] { return client.GetpPacketSupported(tid); });
117   Handle_QThreadSuffixSupported(server, true);
118   HandlePacket(server, "p0;thread:0047;", one_register_hex);
119   ASSERT_TRUE(async_result.get());
120 
121   std::future<DataBufferSP> read_result = std::async(
122       std::launch::async, [&] { return client.ReadRegister(tid, reg_num); });
123   HandlePacket(server, "p4;thread:0047;", "41424344");
124   auto buffer_sp = read_result.get();
125   ASSERT_TRUE(bool(buffer_sp));
126   ASSERT_EQ(0,
127             memcmp(buffer_sp->GetBytes(), one_register, sizeof one_register));
128 
129   read_result = std::async(std::launch::async,
130                            [&] { return client.ReadAllRegisters(tid); });
131   HandlePacket(server, "g;thread:0047;", all_registers_hex);
132   buffer_sp = read_result.get();
133   ASSERT_TRUE(bool(buffer_sp));
134   ASSERT_EQ(0,
135             memcmp(buffer_sp->GetBytes(), all_registers, sizeof all_registers));
136 }
137 
138 TEST_F(GDBRemoteCommunicationClientTest, SaveRestoreRegistersNoSuffix) {
139   const lldb::tid_t tid = 0x47;
140   uint32_t save_id;
141   std::future<bool> async_result = std::async(std::launch::async, [&] {
142     return client.SaveRegisterState(tid, save_id);
143   });
144   Handle_QThreadSuffixSupported(server, false);
145   HandlePacket(server, "Hg47", "OK");
146   HandlePacket(server, "QSaveRegisterState", "1");
147   ASSERT_TRUE(async_result.get());
148   EXPECT_EQ(1u, save_id);
149 
150   async_result = std::async(std::launch::async, [&] {
151     return client.RestoreRegisterState(tid, save_id);
152   });
153   HandlePacket(server, "QRestoreRegisterState:1", "OK");
154   ASSERT_TRUE(async_result.get());
155 }
156 
157 TEST_F(GDBRemoteCommunicationClientTest, SyncThreadState) {
158   const lldb::tid_t tid = 0x47;
159   std::future<bool> async_result = std::async(
160       std::launch::async, [&] { return client.SyncThreadState(tid); });
161   HandlePacket(server, "qSyncThreadStateSupported", "OK");
162   HandlePacket(server, "QSyncThreadState:0047;", "OK");
163   ASSERT_TRUE(async_result.get());
164 }
165 
166 TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo) {
167   llvm::Triple triple("i386-pc-linux");
168 
169   FileSpec file_specs[] = {
170       FileSpec("/foo/bar.so", false, FileSpec::ePathSyntaxPosix),
171       FileSpec("/foo/baz.so", false, FileSpec::ePathSyntaxPosix),
172 
173       // This is a bit dodgy but we currently depend on GetModulesInfo not
174       // performing denormalization. It can go away once the users
175       // (DynamicLoaderPOSIXDYLD, at least) correctly set the path syntax for
176       // the FileSpecs they create.
177       FileSpec("/foo/baw.so", false, FileSpec::ePathSyntaxWindows),
178   };
179   std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result =
180       std::async(std::launch::async,
181                  [&] { return client.GetModulesInfo(file_specs, triple); });
182   HandlePacket(
183       server, "jModulesInfo:["
184               R"({"file":"/foo/bar.so","triple":"i386-pc-linux"},)"
185               R"({"file":"/foo/baz.so","triple":"i386-pc-linux"},)"
186               R"({"file":"/foo/baw.so","triple":"i386-pc-linux"}])",
187       R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
188       R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])");
189 
190   auto result = async_result.get();
191   ASSERT_TRUE(result.hasValue());
192   ASSERT_EQ(1u, result->size());
193   EXPECT_EQ("/foo/bar.so", result.getValue()[0].GetFileSpec().GetPath());
194   EXPECT_EQ(triple, result.getValue()[0].GetArchitecture().GetTriple());
195   EXPECT_EQ(UUID("@ABCDEFGHIJKLMNO", 16), result.getValue()[0].GetUUID());
196   EXPECT_EQ(0u, result.getValue()[0].GetObjectOffset());
197   EXPECT_EQ(1234u, result.getValue()[0].GetObjectSize());
198 }
199 
200 TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfoInvalidResponse) {
201   llvm::Triple triple("i386-pc-linux");
202   FileSpec file_spec("/foo/bar.so", false, FileSpec::ePathSyntaxPosix);
203 
204   const char *invalid_responses[] = {
205       "OK", "E47", "[]",
206       // no UUID
207       R"([{"triple":"i386-pc-linux",)"
208       R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}])",
209       // no triple
210       R"([{"uuid":"404142434445464748494a4b4c4d4e4f",)"
211       R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}])",
212       // no file_path
213       R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
214       R"("file_offset":0,"file_size":1234}])",
215       // no file_offset
216       R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
217       R"("file_path":"/foo/bar.so","file_size":1234}])",
218       // no file_size
219       R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
220       R"("file_path":"/foo/bar.so","file_offset":0}])",
221   };
222 
223   for (const char *response : invalid_responses) {
224     std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result =
225         std::async(std::launch::async,
226                    [&] { return client.GetModulesInfo(file_spec, triple); });
227     HandlePacket(
228         server,
229         R"(jModulesInfo:[{"file":"/foo/bar.so","triple":"i386-pc-linux"}])",
230         response);
231 
232     ASSERT_FALSE(async_result.get().hasValue()) << "response was: " << response;
233   }
234 }
235 
236 TEST_F(GDBRemoteCommunicationClientTest, TestPacketSpeedJSON) {
237   std::thread server_thread([this] {
238     for (;;) {
239       StringExtractorGDBRemote request;
240       PacketResult result = server.GetPacket(request);
241       if (result == PacketResult::ErrorDisconnected)
242         return;
243       ASSERT_EQ(PacketResult::Success, result);
244       StringRef ref = request.GetStringRef();
245       ASSERT_TRUE(ref.consume_front("qSpeedTest:response_size:"));
246       int size;
247       ASSERT_FALSE(ref.consumeInteger(10, size)) << "ref: " << ref;
248       std::string response(size, 'X');
249       ASSERT_EQ(PacketResult::Success, server.SendPacket(response));
250     }
251   });
252 
253   StreamString ss;
254   client.TestPacketSpeed(10, 32, 32, 4096, true, ss);
255   client.Disconnect();
256   server_thread.join();
257 
258   GTEST_LOG_(INFO) << "Formatted output: " << ss.GetData();
259   auto object_sp = StructuredData::ParseJSON(ss.GetString());
260   ASSERT_TRUE(bool(object_sp));
261   auto dict_sp = object_sp->GetAsDictionary();
262   ASSERT_TRUE(bool(dict_sp));
263 
264   object_sp = dict_sp->GetValueForKey("packet_speeds");
265   ASSERT_TRUE(bool(object_sp));
266   dict_sp = object_sp->GetAsDictionary();
267   ASSERT_TRUE(bool(dict_sp));
268 
269   int num_packets;
270   ASSERT_TRUE(dict_sp->GetValueForKeyAsInteger("num_packets", num_packets))
271       << ss.GetString();
272   ASSERT_EQ(10, num_packets);
273 }
274 
275 TEST_F(GDBRemoteCommunicationClientTest, SendSignalsToIgnore) {
276   std::future<Status> result = std::async(std::launch::async, [&] {
277     return client.SendSignalsToIgnore({2, 3, 5, 7, 0xB, 0xD, 0x11});
278   });
279 
280   HandlePacket(server, "QPassSignals:02;03;05;07;0b;0d;11", "OK");
281   EXPECT_TRUE(result.get().Success());
282 
283   result = std::async(std::launch::async, [&] {
284     return client.SendSignalsToIgnore(std::vector<int32_t>());
285   });
286 
287   HandlePacket(server, "QPassSignals:", "OK");
288   EXPECT_TRUE(result.get().Success());
289 }
290 
291 TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfo) {
292   const lldb::addr_t addr = 0xa000;
293   MemoryRegionInfo region_info;
294   std::future<Status> result = std::async(std::launch::async, [&] {
295     return client.GetMemoryRegionInfo(addr, region_info);
296   });
297 
298   // name is: /foo/bar.so
299   HandlePacket(server,
300       "qMemoryRegionInfo:a000",
301       "start:a000;size:2000;permissions:rx;name:2f666f6f2f6261722e736f;");
302   EXPECT_TRUE(result.get().Success());
303 
304 }
305 
306 TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfoInvalidResponse) {
307   const lldb::addr_t addr = 0x4000;
308   MemoryRegionInfo region_info;
309   std::future<Status> result = std::async(std::launch::async, [&] {
310     return client.GetMemoryRegionInfo(addr, region_info);
311   });
312 
313   HandlePacket(server, "qMemoryRegionInfo:4000", "start:4000;size:0000;");
314   EXPECT_FALSE(result.get().Success());
315 }
316 
317 TEST_F(GDBRemoteCommunicationClientTest, SendStartTracePacket) {
318   TraceOptions options;
319   Status error;
320 
321   options.setType(lldb::TraceType::eTraceTypeProcessorTrace);
322   options.setMetaDataBufferSize(8192);
323   options.setTraceBufferSize(8192);
324   options.setThreadID(0x23);
325 
326   StructuredData::DictionarySP custom_params =
327       std::make_shared<StructuredData::Dictionary>();
328   custom_params->AddStringItem("tracetech", "intel-pt");
329   custom_params->AddIntegerItem("psb", 0x01);
330 
331   options.setTraceParams(custom_params);
332 
333   std::future<lldb::user_id_t> result = std::async(std::launch::async, [&] {
334     return client.SendStartTracePacket(options, error);
335   });
336 
337   // Since the line is exceeding 80 characters.
338   std::string expected_packet1 =
339       R"(jTraceStart:{"buffersize" : 8192,"metabuffersize" : 8192,"params" :)";
340   std::string expected_packet2 =
341       R"( {"psb" : 1,"tracetech" : "intel-pt"},"threadid" : 35,"type" : 1})";
342   HandlePacket(server, (expected_packet1 + expected_packet2), "1");
343   ASSERT_TRUE(error.Success());
344   ASSERT_EQ(result.get(), 1u);
345 
346   error.Clear();
347   result = std::async(std::launch::async, [&] {
348     return client.SendStartTracePacket(options, error);
349   });
350 
351   HandlePacket(server, (expected_packet1 + expected_packet2), "E23");
352   ASSERT_EQ(result.get(), LLDB_INVALID_UID);
353   ASSERT_FALSE(error.Success());
354 }
355 
356 TEST_F(GDBRemoteCommunicationClientTest, SendStopTracePacket) {
357   lldb::tid_t thread_id = 0x23;
358   lldb::user_id_t trace_id = 3;
359 
360   std::future<Status> result = std::async(std::launch::async, [&] {
361     return client.SendStopTracePacket(trace_id, thread_id);
362   });
363 
364   const char *expected_packet =
365       R"(jTraceStop:{"threadid" : 35,"traceid" : 3})";
366   HandlePacket(server, expected_packet, "OK");
367   ASSERT_TRUE(result.get().Success());
368 
369   result = std::async(std::launch::async, [&] {
370     return client.SendStopTracePacket(trace_id, thread_id);
371   });
372 
373   HandlePacket(server, expected_packet, "E23");
374   ASSERT_FALSE(result.get().Success());
375 }
376 
377 TEST_F(GDBRemoteCommunicationClientTest, SendGetDataPacket) {
378   lldb::tid_t thread_id = 0x23;
379   lldb::user_id_t trace_id = 3;
380 
381   uint8_t buf[32] = {};
382   llvm::MutableArrayRef<uint8_t> buffer(buf, 32);
383   size_t offset = 0;
384 
385   std::future<Status> result = std::async(std::launch::async, [&] {
386     return client.SendGetDataPacket(trace_id, thread_id, buffer, offset);
387   });
388 
389   std::string expected_packet1 =
390       R"(jTraceBufferRead:{"buffersize" : 32,"offset" : 0,"threadid" : 35,)";
391   std::string expected_packet2 = R"("traceid" : 3})";
392   HandlePacket(server, expected_packet1+expected_packet2, "123456");
393   ASSERT_TRUE(result.get().Success());
394   ASSERT_EQ(buffer.size(), 3u);
395   ASSERT_EQ(buf[0], 0x12);
396   ASSERT_EQ(buf[1], 0x34);
397   ASSERT_EQ(buf[2], 0x56);
398 
399   llvm::MutableArrayRef<uint8_t> buffer2(buf, 32);
400   result = std::async(std::launch::async, [&] {
401     return client.SendGetDataPacket(trace_id, thread_id, buffer2, offset);
402   });
403 
404   HandlePacket(server, expected_packet1+expected_packet2, "E23");
405   ASSERT_FALSE(result.get().Success());
406   ASSERT_EQ(buffer2.size(), 0u);
407 }
408 
409 TEST_F(GDBRemoteCommunicationClientTest, SendGetMetaDataPacket) {
410   lldb::tid_t thread_id = 0x23;
411   lldb::user_id_t trace_id = 3;
412 
413   uint8_t buf[32] = {};
414   llvm::MutableArrayRef<uint8_t> buffer(buf, 32);
415   size_t offset = 0;
416 
417   std::future<Status> result = std::async(std::launch::async, [&] {
418     return client.SendGetMetaDataPacket(trace_id, thread_id, buffer, offset);
419   });
420 
421   std::string expected_packet1 =
422       R"(jTraceMetaRead:{"buffersize" : 32,"offset" : 0,"threadid" : 35,)";
423   std::string expected_packet2 = R"("traceid" : 3})";
424   HandlePacket(server, expected_packet1+expected_packet2, "123456");
425   ASSERT_TRUE(result.get().Success());
426   ASSERT_EQ(buffer.size(), 3u);
427   ASSERT_EQ(buf[0], 0x12);
428   ASSERT_EQ(buf[1], 0x34);
429   ASSERT_EQ(buf[2], 0x56);
430 
431   llvm::MutableArrayRef<uint8_t> buffer2(buf, 32);
432   result = std::async(std::launch::async, [&] {
433     return client.SendGetMetaDataPacket(trace_id, thread_id, buffer2, offset);
434   });
435 
436   HandlePacket(server, expected_packet1+expected_packet2, "E23");
437   ASSERT_FALSE(result.get().Success());
438   ASSERT_EQ(buffer2.size(), 0u);
439 }
440 
441 TEST_F(GDBRemoteCommunicationClientTest, SendGetTraceConfigPacket) {
442   lldb::tid_t thread_id = 0x23;
443   lldb::user_id_t trace_id = 3;
444   TraceOptions options;
445   options.setThreadID(thread_id);
446 
447   std::future<Status> result = std::async(std::launch::async, [&] {
448     return client.SendGetTraceConfigPacket(trace_id, options);
449   });
450 
451   const char *expected_packet =
452       R"(jTraceConfigRead:{"threadid" : 35,"traceid" : 3})";
453   std::string response1 =
454       R"({"buffersize" : 8192,"params" : {"psb" : 1,"tracetech" : "intel-pt"})";
455   std::string response2 =
456       R"(],"metabuffersize" : 8192,"threadid" : 35,"type" : 1}])";
457   HandlePacket(server, expected_packet, response1+response2);
458   ASSERT_TRUE(result.get().Success());
459   ASSERT_EQ(options.getTraceBufferSize(), 8192u);
460   ASSERT_EQ(options.getMetaDataBufferSize(), 8192u);
461   ASSERT_EQ(options.getType(), 1);
462 
463   auto custom_params = options.getTraceParams();
464 
465   uint64_t psb_value;
466   llvm::StringRef trace_tech_value;
467 
468   ASSERT_TRUE(custom_params);
469   ASSERT_EQ(custom_params->GetType(), eStructuredDataTypeDictionary);
470   ASSERT_TRUE(custom_params->GetValueForKeyAsInteger("psb", psb_value));
471   ASSERT_EQ(psb_value, 1u);
472   ASSERT_TRUE(
473       custom_params->GetValueForKeyAsString("tracetech", trace_tech_value));
474   ASSERT_STREQ(trace_tech_value.data(), "intel-pt");
475 
476   // Checking error response.
477   std::future<Status> result2 = std::async(std::launch::async, [&] {
478     return client.SendGetTraceConfigPacket(trace_id, options);
479   });
480 
481   HandlePacket(server, expected_packet, "E23");
482   ASSERT_FALSE(result2.get().Success());
483 
484   // Wrong JSON as response.
485   std::future<Status> result3 = std::async(std::launch::async, [&] {
486     return client.SendGetTraceConfigPacket(trace_id, options);
487   });
488 
489   std::string incorrect_json1 =
490       R"("buffersize" : 8192,"params" : {"psb" : 1,"tracetech" : "intel-pt"})";
491   std::string incorrect_json2 =
492       R"(],"metabuffersize" : 8192,"threadid" : 35,"type" : 1}])";
493   HandlePacket(server, expected_packet, incorrect_json1+incorrect_json2);
494   ASSERT_FALSE(result3.get().Success());
495 
496   // Wrong JSON as custom_params.
497   std::future<Status> result4 = std::async(std::launch::async, [&] {
498     return client.SendGetTraceConfigPacket(trace_id, options);
499   });
500 
501   std::string incorrect_custom_params1 =
502       R"({"buffersize" : 8192,"params" : "psb" : 1,"tracetech" : "intel-pt"})";
503   std::string incorrect_custom_params2 =
504       R"(],"metabuffersize" : 8192,"threadid" : 35,"type" : 1}])";
505   HandlePacket(server, expected_packet, incorrect_custom_params1+
506       incorrect_custom_params2);
507   ASSERT_FALSE(result4.get().Success());
508 }
509