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/Utility/TraceOptions.h"
16 #include "lldb/lldb-enumerations.h"
17 #include "llvm/ADT/ArrayRef.h"
18 #include "llvm/Testing/Support/Error.h"
19 #include "gmock/gmock.h"
20 #include <future>
21
22 using namespace lldb_private::process_gdb_remote;
23 using namespace lldb_private;
24 using namespace lldb;
25 using namespace llvm;
26
27 namespace {
28
29 typedef GDBRemoteCommunication::PacketResult PacketResult;
30
31 struct TestClient : public GDBRemoteCommunicationClient {
TestClient__anon659208d00111::TestClient32 TestClient() { m_send_acks = false; }
33 };
34
Handle_QThreadSuffixSupported(MockServer & server,bool supported)35 void Handle_QThreadSuffixSupported(MockServer &server, bool supported) {
36 StringExtractorGDBRemote request;
37 ASSERT_EQ(PacketResult::Success, server.GetPacket(request));
38 ASSERT_EQ("QThreadSuffixSupported", request.GetStringRef());
39 if (supported)
40 ASSERT_EQ(PacketResult::Success, server.SendOKResponse());
41 else
42 ASSERT_EQ(PacketResult::Success, server.SendUnimplementedResponse(nullptr));
43 }
44
HandlePacket(MockServer & server,const testing::Matcher<const std::string &> & expected,StringRef response)45 void HandlePacket(MockServer &server,
46 const testing::Matcher<const std::string &> &expected,
47 StringRef response) {
48 StringExtractorGDBRemote request;
49 ASSERT_EQ(PacketResult::Success, server.GetPacket(request));
50 ASSERT_THAT(std::string(request.GetStringRef()), expected);
51 ASSERT_EQ(PacketResult::Success, server.SendPacket(response));
52 }
53
54 uint8_t all_registers[] = {'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
55 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'};
56 std::string all_registers_hex = "404142434445464748494a4b4c4d4e4f";
57 uint8_t one_register[] = {'A', 'B', 'C', 'D'};
58 std::string one_register_hex = "41424344";
59
60 } // end anonymous namespace
61
62 class GDBRemoteCommunicationClientTest : public GDBRemoteTest {
63 public:
SetUp()64 void SetUp() override {
65 ASSERT_THAT_ERROR(GDBRemoteCommunication::ConnectLocally(client, server),
66 llvm::Succeeded());
67 }
68
69 protected:
70 TestClient client;
71 MockServer server;
72 };
73
TEST_F(GDBRemoteCommunicationClientTest,WriteRegister)74 TEST_F(GDBRemoteCommunicationClientTest, WriteRegister) {
75 const lldb::tid_t tid = 0x47;
76 const uint32_t reg_num = 4;
77 std::future<bool> write_result = std::async(std::launch::async, [&] {
78 return client.WriteRegister(tid, reg_num, one_register);
79 });
80
81 Handle_QThreadSuffixSupported(server, true);
82
83 HandlePacket(server, "P4=" + one_register_hex + ";thread:0047;", "OK");
84 ASSERT_TRUE(write_result.get());
85
86 write_result = std::async(std::launch::async, [&] {
87 return client.WriteAllRegisters(tid, all_registers);
88 });
89
90 HandlePacket(server, "G" + all_registers_hex + ";thread:0047;", "OK");
91 ASSERT_TRUE(write_result.get());
92 }
93
TEST_F(GDBRemoteCommunicationClientTest,WriteRegisterNoSuffix)94 TEST_F(GDBRemoteCommunicationClientTest, WriteRegisterNoSuffix) {
95 const lldb::tid_t tid = 0x47;
96 const uint32_t reg_num = 4;
97 std::future<bool> write_result = std::async(std::launch::async, [&] {
98 return client.WriteRegister(tid, reg_num, one_register);
99 });
100
101 Handle_QThreadSuffixSupported(server, false);
102 HandlePacket(server, "Hg47", "OK");
103 HandlePacket(server, "P4=" + one_register_hex, "OK");
104 ASSERT_TRUE(write_result.get());
105
106 write_result = std::async(std::launch::async, [&] {
107 return client.WriteAllRegisters(tid, all_registers);
108 });
109
110 HandlePacket(server, "G" + all_registers_hex, "OK");
111 ASSERT_TRUE(write_result.get());
112 }
113
TEST_F(GDBRemoteCommunicationClientTest,ReadRegister)114 TEST_F(GDBRemoteCommunicationClientTest, ReadRegister) {
115 const lldb::tid_t tid = 0x47;
116 const uint32_t reg_num = 4;
117 std::future<bool> async_result = std::async(
118 std::launch::async, [&] { return client.GetpPacketSupported(tid); });
119 Handle_QThreadSuffixSupported(server, true);
120 HandlePacket(server, "p0;thread:0047;", one_register_hex);
121 ASSERT_TRUE(async_result.get());
122
123 std::future<DataBufferSP> read_result = std::async(
124 std::launch::async, [&] { return client.ReadRegister(tid, reg_num); });
125 HandlePacket(server, "p4;thread:0047;", "41424344");
126 auto buffer_sp = read_result.get();
127 ASSERT_TRUE(bool(buffer_sp));
128 ASSERT_EQ(0,
129 memcmp(buffer_sp->GetBytes(), one_register, sizeof one_register));
130
131 read_result = std::async(std::launch::async,
132 [&] { return client.ReadAllRegisters(tid); });
133 HandlePacket(server, "g;thread:0047;", all_registers_hex);
134 buffer_sp = read_result.get();
135 ASSERT_TRUE(bool(buffer_sp));
136 ASSERT_EQ(0,
137 memcmp(buffer_sp->GetBytes(), all_registers, sizeof all_registers));
138 }
139
TEST_F(GDBRemoteCommunicationClientTest,SaveRestoreRegistersNoSuffix)140 TEST_F(GDBRemoteCommunicationClientTest, SaveRestoreRegistersNoSuffix) {
141 const lldb::tid_t tid = 0x47;
142 uint32_t save_id;
143 std::future<bool> async_result = std::async(std::launch::async, [&] {
144 return client.SaveRegisterState(tid, save_id);
145 });
146 Handle_QThreadSuffixSupported(server, false);
147 HandlePacket(server, "Hg47", "OK");
148 HandlePacket(server, "QSaveRegisterState", "1");
149 ASSERT_TRUE(async_result.get());
150 EXPECT_EQ(1u, save_id);
151
152 async_result = std::async(std::launch::async, [&] {
153 return client.RestoreRegisterState(tid, save_id);
154 });
155 HandlePacket(server, "QRestoreRegisterState:1", "OK");
156 ASSERT_TRUE(async_result.get());
157 }
158
TEST_F(GDBRemoteCommunicationClientTest,SyncThreadState)159 TEST_F(GDBRemoteCommunicationClientTest, SyncThreadState) {
160 const lldb::tid_t tid = 0x47;
161 std::future<bool> async_result = std::async(
162 std::launch::async, [&] { return client.SyncThreadState(tid); });
163 HandlePacket(server, "qSyncThreadStateSupported", "OK");
164 HandlePacket(server, "QSyncThreadState:0047;", "OK");
165 ASSERT_TRUE(async_result.get());
166 }
167
TEST_F(GDBRemoteCommunicationClientTest,GetModulesInfo)168 TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo) {
169 llvm::Triple triple("i386-pc-linux");
170
171 FileSpec file_specs[] = {
172 FileSpec("/foo/bar.so", FileSpec::Style::posix),
173 FileSpec("/foo/baz.so", FileSpec::Style::posix),
174
175 // This is a bit dodgy but we currently depend on GetModulesInfo not
176 // performing denormalization. It can go away once the users
177 // (DynamicLoaderPOSIXDYLD, at least) correctly set the path syntax for
178 // the FileSpecs they create.
179 FileSpec("/foo/baw.so", FileSpec::Style::windows),
180 };
181 std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result =
182 std::async(std::launch::async,
183 [&] { return client.GetModulesInfo(file_specs, triple); });
184 HandlePacket(
185 server, "jModulesInfo:["
186 R"({"file":"/foo/bar.so","triple":"i386-pc-linux"},)"
187 R"({"file":"/foo/baz.so","triple":"i386-pc-linux"},)"
188 R"({"file":"/foo/baw.so","triple":"i386-pc-linux"}])",
189 R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
190 R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])");
191
192 auto result = async_result.get();
193 ASSERT_TRUE(result.hasValue());
194 ASSERT_EQ(1u, result->size());
195 EXPECT_EQ("/foo/bar.so", result.getValue()[0].GetFileSpec().GetPath());
196 EXPECT_EQ(triple, result.getValue()[0].GetArchitecture().GetTriple());
197 EXPECT_EQ(UUID::fromData("@ABCDEFGHIJKLMNO", 16),
198 result.getValue()[0].GetUUID());
199 EXPECT_EQ(0u, result.getValue()[0].GetObjectOffset());
200 EXPECT_EQ(1234u, result.getValue()[0].GetObjectSize());
201 }
202
TEST_F(GDBRemoteCommunicationClientTest,GetModulesInfo_UUID20)203 TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo_UUID20) {
204 llvm::Triple triple("i386-pc-linux");
205
206 FileSpec file_spec("/foo/bar.so", FileSpec::Style::posix);
207 std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result =
208 std::async(std::launch::async,
209 [&] { return client.GetModulesInfo(file_spec, triple); });
210 HandlePacket(
211 server,
212 "jModulesInfo:["
213 R"({"file":"/foo/bar.so","triple":"i386-pc-linux"}])",
214 R"([{"uuid":"404142434445464748494a4b4c4d4e4f50515253","triple":"i386-pc-linux",)"
215 R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])");
216
217 auto result = async_result.get();
218 ASSERT_TRUE(result.hasValue());
219 ASSERT_EQ(1u, result->size());
220 EXPECT_EQ("/foo/bar.so", result.getValue()[0].GetFileSpec().GetPath());
221 EXPECT_EQ(triple, result.getValue()[0].GetArchitecture().GetTriple());
222 EXPECT_EQ(UUID::fromData("@ABCDEFGHIJKLMNOPQRS", 20),
223 result.getValue()[0].GetUUID());
224 EXPECT_EQ(0u, result.getValue()[0].GetObjectOffset());
225 EXPECT_EQ(1234u, result.getValue()[0].GetObjectSize());
226 }
227
TEST_F(GDBRemoteCommunicationClientTest,GetModulesInfoInvalidResponse)228 TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfoInvalidResponse) {
229 llvm::Triple triple("i386-pc-linux");
230 FileSpec file_spec("/foo/bar.so", FileSpec::Style::posix);
231
232 const char *invalid_responses[] = {
233 // no UUID
234 R"([{"triple":"i386-pc-linux",)"
235 R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])",
236 // invalid UUID
237 R"([{"uuid":"XXXXXX","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 auto result = async_result.get();
263 ASSERT_TRUE(result);
264 ASSERT_EQ(0u, result->size()) << "response was: " << response;
265 }
266 }
267
TEST_F(GDBRemoteCommunicationClientTest,TestPacketSpeedJSON)268 TEST_F(GDBRemoteCommunicationClientTest, TestPacketSpeedJSON) {
269 std::thread server_thread([this] {
270 for (;;) {
271 StringExtractorGDBRemote request;
272 PacketResult result = server.GetPacket(request);
273 if (result == PacketResult::ErrorDisconnected)
274 return;
275 ASSERT_EQ(PacketResult::Success, result);
276 StringRef ref = request.GetStringRef();
277 ASSERT_TRUE(ref.consume_front("qSpeedTest:response_size:"));
278 int size;
279 ASSERT_FALSE(ref.consumeInteger(10, size)) << "ref: " << ref;
280 std::string response(size, 'X');
281 ASSERT_EQ(PacketResult::Success, server.SendPacket(response));
282 }
283 });
284
285 StreamString ss;
286 client.TestPacketSpeed(10, 32, 32, 4096, true, ss);
287 client.Disconnect();
288 server_thread.join();
289
290 GTEST_LOG_(INFO) << "Formatted output: " << ss.GetData();
291 auto object_sp = StructuredData::ParseJSON(std::string(ss.GetString()));
292 ASSERT_TRUE(bool(object_sp));
293 auto dict_sp = object_sp->GetAsDictionary();
294 ASSERT_TRUE(bool(dict_sp));
295
296 object_sp = dict_sp->GetValueForKey("packet_speeds");
297 ASSERT_TRUE(bool(object_sp));
298 dict_sp = object_sp->GetAsDictionary();
299 ASSERT_TRUE(bool(dict_sp));
300
301 int num_packets;
302 ASSERT_TRUE(dict_sp->GetValueForKeyAsInteger("num_packets", num_packets))
303 << ss.GetString();
304 ASSERT_EQ(10, num_packets);
305 }
306
TEST_F(GDBRemoteCommunicationClientTest,SendSignalsToIgnore)307 TEST_F(GDBRemoteCommunicationClientTest, SendSignalsToIgnore) {
308 std::future<Status> result = std::async(std::launch::async, [&] {
309 return client.SendSignalsToIgnore({2, 3, 5, 7, 0xB, 0xD, 0x11});
310 });
311
312 HandlePacket(server, "QPassSignals:02;03;05;07;0b;0d;11", "OK");
313 EXPECT_TRUE(result.get().Success());
314
315 result = std::async(std::launch::async, [&] {
316 return client.SendSignalsToIgnore(std::vector<int32_t>());
317 });
318
319 HandlePacket(server, "QPassSignals:", "OK");
320 EXPECT_TRUE(result.get().Success());
321 }
322
TEST_F(GDBRemoteCommunicationClientTest,GetMemoryRegionInfo)323 TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfo) {
324 const lldb::addr_t addr = 0xa000;
325 MemoryRegionInfo region_info;
326 std::future<Status> result = std::async(std::launch::async, [&] {
327 return client.GetMemoryRegionInfo(addr, region_info);
328 });
329
330 HandlePacket(server,
331 "qMemoryRegionInfo:a000",
332 "start:a000;size:2000;permissions:rx;name:2f666f6f2f6261722e736f;");
333 if (XMLDocument::XMLEnabled()) {
334 // In case we have XML support, this will also do a "qXfer:memory-map".
335 // Preceeded by a query for supported extensions. Pretend we don't support
336 // that.
337 HandlePacket(server, testing::StartsWith("qSupported:"), "");
338 }
339 EXPECT_TRUE(result.get().Success());
340 EXPECT_EQ(addr, region_info.GetRange().GetRangeBase());
341 EXPECT_EQ(0x2000u, region_info.GetRange().GetByteSize());
342 EXPECT_EQ(MemoryRegionInfo::eYes, region_info.GetReadable());
343 EXPECT_EQ(MemoryRegionInfo::eNo, region_info.GetWritable());
344 EXPECT_EQ(MemoryRegionInfo::eYes, region_info.GetExecutable());
345 EXPECT_EQ("/foo/bar.so", region_info.GetName().GetStringRef());
346 EXPECT_EQ(MemoryRegionInfo::eDontKnow, region_info.GetMemoryTagged());
347
348 result = std::async(std::launch::async, [&] {
349 return client.GetMemoryRegionInfo(addr, region_info);
350 });
351
352 HandlePacket(server, "qMemoryRegionInfo:a000",
353 "start:a000;size:2000;flags:;");
354 EXPECT_TRUE(result.get().Success());
355 EXPECT_EQ(MemoryRegionInfo::eNo, region_info.GetMemoryTagged());
356
357 result = std::async(std::launch::async, [&] {
358 return client.GetMemoryRegionInfo(addr, region_info);
359 });
360
361 HandlePacket(server, "qMemoryRegionInfo:a000",
362 "start:a000;size:2000;flags: mt zz mt ;");
363 EXPECT_TRUE(result.get().Success());
364 EXPECT_EQ(MemoryRegionInfo::eYes, region_info.GetMemoryTagged());
365 }
366
TEST_F(GDBRemoteCommunicationClientTest,GetMemoryRegionInfoInvalidResponse)367 TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfoInvalidResponse) {
368 const lldb::addr_t addr = 0x4000;
369 MemoryRegionInfo region_info;
370 std::future<Status> result = std::async(std::launch::async, [&] {
371 return client.GetMemoryRegionInfo(addr, region_info);
372 });
373
374 HandlePacket(server, "qMemoryRegionInfo:4000", "start:4000;size:0000;");
375 if (XMLDocument::XMLEnabled()) {
376 // In case we have XML support, this will also do a "qXfer:memory-map".
377 // Preceeded by a query for supported extensions. Pretend we don't support
378 // that.
379 HandlePacket(server, testing::StartsWith("qSupported:"), "");
380 }
381 EXPECT_FALSE(result.get().Success());
382 }
383
TEST_F(GDBRemoteCommunicationClientTest,SendTraceSupportedTypePacket)384 TEST_F(GDBRemoteCommunicationClientTest, SendTraceSupportedTypePacket) {
385 TraceTypeInfo trace_type;
386 std::string error_message;
387 auto callback = [&] {
388 if (llvm::Expected<TraceTypeInfo> trace_type_or_err =
389 client.SendGetSupportedTraceType()) {
390 trace_type = *trace_type_or_err;
391 error_message = "";
392 return true;
393 } else {
394 trace_type = {};
395 error_message = llvm::toString(trace_type_or_err.takeError());
396 return false;
397 }
398 };
399
400 // Success response
401 {
402 std::future<bool> result = std::async(std::launch::async, callback);
403
404 HandlePacket(
405 server, "jLLDBTraceSupportedType",
406 R"({"name":"intel-pt","description":"Intel Processor Trace"}])");
407
408 EXPECT_TRUE(result.get());
409 ASSERT_STREQ(trace_type.name.c_str(), "intel-pt");
410 ASSERT_STREQ(trace_type.description.c_str(), "Intel Processor Trace");
411 }
412
413 // Error response - wrong json
414 {
415 std::future<bool> result = std::async(std::launch::async, callback);
416
417 HandlePacket(server, "jLLDBTraceSupportedType", R"({"type":"intel-pt"}])");
418
419 EXPECT_FALSE(result.get());
420 ASSERT_STREQ(error_message.c_str(), "missing value at (root).name");
421 }
422
423 // Error response
424 {
425 std::future<bool> result = std::async(std::launch::async, callback);
426
427 HandlePacket(server, "jLLDBTraceSupportedType", "E23");
428
429 EXPECT_FALSE(result.get());
430 }
431
432 // Error response with error message
433 {
434 std::future<bool> result = std::async(std::launch::async, callback);
435
436 HandlePacket(server, "jLLDBTraceSupportedType",
437 "E23;50726F63657373206E6F742072756E6E696E672E");
438
439 EXPECT_FALSE(result.get());
440 ASSERT_STREQ(error_message.c_str(), "Process not running.");
441 }
442 }
443
TEST_F(GDBRemoteCommunicationClientTest,SendStartTracePacket)444 TEST_F(GDBRemoteCommunicationClientTest, SendStartTracePacket) {
445 TraceOptions options;
446 Status error;
447
448 options.setType(lldb::TraceType::eTraceTypeProcessorTrace);
449 options.setMetaDataBufferSize(8192);
450 options.setTraceBufferSize(8192);
451 options.setThreadID(0x23);
452
453 StructuredData::DictionarySP custom_params =
454 std::make_shared<StructuredData::Dictionary>();
455 custom_params->AddStringItem("tracetech", "intel-pt");
456 custom_params->AddIntegerItem("psb", 0x01);
457
458 options.setTraceParams(custom_params);
459
460 std::future<lldb::user_id_t> result = std::async(std::launch::async, [&] {
461 return client.SendStartTracePacket(options, error);
462 });
463
464 // Since the line is exceeding 80 characters.
465 std::string expected_packet1 =
466 R"(jTraceStart:{"buffersize":8192,"metabuffersize":8192,"params":)";
467 std::string expected_packet2 =
468 R"({"psb":1,"tracetech":"intel-pt"},"threadid":35,"type":1})";
469 HandlePacket(server, (expected_packet1 + expected_packet2), "1");
470 ASSERT_TRUE(error.Success());
471 ASSERT_EQ(result.get(), 1u);
472
473 error.Clear();
474 result = std::async(std::launch::async, [&] {
475 return client.SendStartTracePacket(options, error);
476 });
477
478 HandlePacket(server, (expected_packet1 + expected_packet2), "E23");
479 ASSERT_EQ(result.get(), LLDB_INVALID_UID);
480 ASSERT_FALSE(error.Success());
481 }
482
TEST_F(GDBRemoteCommunicationClientTest,SendStopTracePacket)483 TEST_F(GDBRemoteCommunicationClientTest, SendStopTracePacket) {
484 lldb::tid_t thread_id = 0x23;
485 lldb::user_id_t trace_id = 3;
486
487 std::future<Status> result = std::async(std::launch::async, [&] {
488 return client.SendStopTracePacket(trace_id, thread_id);
489 });
490
491 const char *expected_packet = R"(jTraceStop:{"threadid":35,"traceid":3})";
492 HandlePacket(server, expected_packet, "OK");
493 ASSERT_TRUE(result.get().Success());
494
495 result = std::async(std::launch::async, [&] {
496 return client.SendStopTracePacket(trace_id, thread_id);
497 });
498
499 HandlePacket(server, expected_packet, "E23");
500 ASSERT_FALSE(result.get().Success());
501 }
502
TEST_F(GDBRemoteCommunicationClientTest,SendGetDataPacket)503 TEST_F(GDBRemoteCommunicationClientTest, SendGetDataPacket) {
504 lldb::tid_t thread_id = 0x23;
505 lldb::user_id_t trace_id = 3;
506
507 uint8_t buf[32] = {};
508 llvm::MutableArrayRef<uint8_t> buffer(buf, 32);
509 size_t offset = 0;
510
511 std::future<Status> result = std::async(std::launch::async, [&] {
512 return client.SendGetDataPacket(trace_id, thread_id, buffer, offset);
513 });
514
515 std::string expected_packet1 =
516 R"(jTraceBufferRead:{"buffersize":32,"offset":0,"threadid":35,)";
517 std::string expected_packet2 = R"("traceid":3})";
518 HandlePacket(server, expected_packet1+expected_packet2, "123456");
519 ASSERT_TRUE(result.get().Success());
520 ASSERT_EQ(buffer.size(), 3u);
521 ASSERT_EQ(buf[0], 0x12);
522 ASSERT_EQ(buf[1], 0x34);
523 ASSERT_EQ(buf[2], 0x56);
524
525 llvm::MutableArrayRef<uint8_t> buffer2(buf, 32);
526 result = std::async(std::launch::async, [&] {
527 return client.SendGetDataPacket(trace_id, thread_id, buffer2, offset);
528 });
529
530 HandlePacket(server, expected_packet1+expected_packet2, "E23");
531 ASSERT_FALSE(result.get().Success());
532 ASSERT_EQ(buffer2.size(), 0u);
533 }
534
TEST_F(GDBRemoteCommunicationClientTest,SendGetMetaDataPacket)535 TEST_F(GDBRemoteCommunicationClientTest, SendGetMetaDataPacket) {
536 lldb::tid_t thread_id = 0x23;
537 lldb::user_id_t trace_id = 3;
538
539 uint8_t buf[32] = {};
540 llvm::MutableArrayRef<uint8_t> buffer(buf, 32);
541 size_t offset = 0;
542
543 std::future<Status> result = std::async(std::launch::async, [&] {
544 return client.SendGetMetaDataPacket(trace_id, thread_id, buffer, offset);
545 });
546
547 std::string expected_packet1 =
548 R"(jTraceMetaRead:{"buffersize":32,"offset":0,"threadid":35,)";
549 std::string expected_packet2 = R"("traceid":3})";
550 HandlePacket(server, expected_packet1+expected_packet2, "123456");
551 ASSERT_TRUE(result.get().Success());
552 ASSERT_EQ(buffer.size(), 3u);
553 ASSERT_EQ(buf[0], 0x12);
554 ASSERT_EQ(buf[1], 0x34);
555 ASSERT_EQ(buf[2], 0x56);
556
557 llvm::MutableArrayRef<uint8_t> buffer2(buf, 32);
558 result = std::async(std::launch::async, [&] {
559 return client.SendGetMetaDataPacket(trace_id, thread_id, buffer2, offset);
560 });
561
562 HandlePacket(server, expected_packet1+expected_packet2, "E23");
563 ASSERT_FALSE(result.get().Success());
564 ASSERT_EQ(buffer2.size(), 0u);
565 }
566
TEST_F(GDBRemoteCommunicationClientTest,SendGetTraceConfigPacket)567 TEST_F(GDBRemoteCommunicationClientTest, SendGetTraceConfigPacket) {
568 lldb::tid_t thread_id = 0x23;
569 lldb::user_id_t trace_id = 3;
570 TraceOptions options;
571 options.setThreadID(thread_id);
572
573 std::future<Status> result = std::async(std::launch::async, [&] {
574 return client.SendGetTraceConfigPacket(trace_id, options);
575 });
576
577 const char *expected_packet =
578 R"(jTraceConfigRead:{"threadid":35,"traceid":3})";
579 std::string response1 =
580 R"({"buffersize":8192,"params":{"psb":1,"tracetech":"intel-pt"})";
581 std::string response2 = R"(],"metabuffersize":8192,"threadid":35,"type":1}])";
582 HandlePacket(server, expected_packet, response1+response2);
583 ASSERT_TRUE(result.get().Success());
584 ASSERT_EQ(options.getTraceBufferSize(), 8192u);
585 ASSERT_EQ(options.getMetaDataBufferSize(), 8192u);
586 ASSERT_EQ(options.getType(), 1);
587
588 auto custom_params = options.getTraceParams();
589
590 uint64_t psb_value;
591 llvm::StringRef trace_tech_value;
592
593 ASSERT_TRUE(custom_params);
594 ASSERT_EQ(custom_params->GetType(), eStructuredDataTypeDictionary);
595 ASSERT_TRUE(custom_params->GetValueForKeyAsInteger("psb", psb_value));
596 ASSERT_EQ(psb_value, 1u);
597 ASSERT_TRUE(
598 custom_params->GetValueForKeyAsString("tracetech", trace_tech_value));
599 ASSERT_STREQ(trace_tech_value.data(), "intel-pt");
600
601 // Checking error response.
602 std::future<Status> result2 = std::async(std::launch::async, [&] {
603 return client.SendGetTraceConfigPacket(trace_id, options);
604 });
605
606 HandlePacket(server, expected_packet, "E23");
607 ASSERT_FALSE(result2.get().Success());
608
609 // Wrong JSON as response.
610 std::future<Status> result3 = std::async(std::launch::async, [&] {
611 return client.SendGetTraceConfigPacket(trace_id, options);
612 });
613
614 std::string incorrect_json1 =
615 R"("buffersize" : 8192,"params" : {"psb" : 1,"tracetech" : "intel-pt"})";
616 std::string incorrect_json2 =
617 R"(],"metabuffersize" : 8192,"threadid" : 35,"type" : 1}])";
618 HandlePacket(server, expected_packet, incorrect_json1+incorrect_json2);
619 ASSERT_FALSE(result3.get().Success());
620
621 // Wrong JSON as custom_params.
622 std::future<Status> result4 = std::async(std::launch::async, [&] {
623 return client.SendGetTraceConfigPacket(trace_id, options);
624 });
625
626 std::string incorrect_custom_params1 =
627 R"({"buffersize" : 8192,"params" : "psb" : 1,"tracetech" : "intel-pt"})";
628 std::string incorrect_custom_params2 =
629 R"(],"metabuffersize" : 8192,"threadid" : 35,"type" : 1}])";
630 HandlePacket(server, expected_packet, incorrect_custom_params1+
631 incorrect_custom_params2);
632 ASSERT_FALSE(result4.get().Success());
633 }
634
TEST_F(GDBRemoteCommunicationClientTest,GetQOffsets)635 TEST_F(GDBRemoteCommunicationClientTest, GetQOffsets) {
636 const auto &GetQOffsets = [&](llvm::StringRef response) {
637 std::future<Optional<QOffsets>> result = std::async(
638 std::launch::async, [&] { return client.GetQOffsets(); });
639
640 HandlePacket(server, "qOffsets", response);
641 return result.get();
642 };
643 EXPECT_EQ((QOffsets{false, {0x1234, 0x1234}}),
644 GetQOffsets("Text=1234;Data=1234"));
645 EXPECT_EQ((QOffsets{false, {0x1234, 0x1234, 0x1234}}),
646 GetQOffsets("Text=1234;Data=1234;Bss=1234"));
647 EXPECT_EQ((QOffsets{true, {0x1234}}), GetQOffsets("TextSeg=1234"));
648 EXPECT_EQ((QOffsets{true, {0x1234, 0x2345}}),
649 GetQOffsets("TextSeg=1234;DataSeg=2345"));
650
651 EXPECT_EQ(llvm::None, GetQOffsets("E05"));
652 EXPECT_EQ(llvm::None, GetQOffsets("Text=bogus"));
653 EXPECT_EQ(llvm::None, GetQOffsets("Text=1234"));
654 EXPECT_EQ(llvm::None, GetQOffsets("Text=1234;Data=1234;"));
655 EXPECT_EQ(llvm::None, GetQOffsets("Text=1234;Data=1234;Bss=1234;"));
656 EXPECT_EQ(llvm::None, GetQOffsets("TEXTSEG=1234"));
657 EXPECT_EQ(llvm::None, GetQOffsets("TextSeg=0x1234"));
658 EXPECT_EQ(llvm::None, GetQOffsets("TextSeg=12345678123456789"));
659 }
660