brintos

brintos / llvm-project-archived public Read only

0
0
Text · 25.2 KiB · 966b37e Raw
668 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h"9#include "GDBRemoteTestUtils.h"10#include "lldb/Core/ModuleSpec.h"11#include "lldb/Host/ConnectionFileDescriptor.h"12#include "lldb/Host/XML.h"13#include "lldb/Target/MemoryRegionInfo.h"14#include "lldb/Utility/DataBuffer.h"15#include "lldb/Utility/StructuredData.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#include <limits>22#include <optional>23 24using namespace lldb_private::process_gdb_remote;25using namespace lldb_private;26using namespace lldb;27using namespace llvm;28 29namespace {30 31typedef GDBRemoteCommunication::PacketResult PacketResult;32 33struct TestClient : public GDBRemoteCommunicationClient {34  TestClient() { m_send_acks = false; }35};36 37void Handle_QThreadSuffixSupported(MockServer &server, bool supported) {38  StringExtractorGDBRemote request;39  ASSERT_EQ(PacketResult::Success, server.GetPacket(request));40  ASSERT_EQ("QThreadSuffixSupported", request.GetStringRef());41  if (supported)42    ASSERT_EQ(PacketResult::Success, server.SendOKResponse());43  else44    ASSERT_EQ(PacketResult::Success, server.SendUnimplementedResponse(nullptr));45}46 47void HandlePacket(MockServer &server,48                  const testing::Matcher<const std::string &> &expected,49                  StringRef response) {50  StringExtractorGDBRemote request;51  ASSERT_EQ(PacketResult::Success, server.GetPacket(request));52  ASSERT_THAT(std::string(request.GetStringRef()), expected);53  ASSERT_EQ(PacketResult::Success, server.SendPacket(response));54}55 56uint8_t all_registers[] = {'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',57                           'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'};58std::string all_registers_hex = "404142434445464748494a4b4c4d4e4f";59uint8_t one_register[] = {'A', 'B', 'C', 'D'};60std::string one_register_hex = "41424344";61 62} // end anonymous namespace63 64class GDBRemoteCommunicationClientTest : public GDBRemoteTest {65public:66  void SetUp() override {67    llvm::Expected<Socket::Pair> pair = Socket::CreatePair();68    ASSERT_THAT_EXPECTED(pair, llvm::Succeeded());69    client.SetConnection(70        std::make_unique<ConnectionFileDescriptor>(std::move(pair->first)));71    server.SetConnection(72        std::make_unique<ConnectionFileDescriptor>(std::move(pair->second)));73  }74 75protected:76  TestClient client;77  MockServer server;78};79 80TEST_F(GDBRemoteCommunicationClientTest, WriteRegister) {81  const lldb::tid_t tid = 0x47;82  const uint32_t reg_num = 4;83  std::future<bool> write_result = std::async(std::launch::async, [&] {84    return client.WriteRegister(tid, reg_num, one_register);85  });86 87  Handle_QThreadSuffixSupported(server, true);88 89  HandlePacket(server, "P4=" + one_register_hex + ";thread:0047;", "OK");90  ASSERT_TRUE(write_result.get());91 92  write_result = std::async(std::launch::async, [&] {93    return client.WriteAllRegisters(tid, all_registers);94  });95 96  HandlePacket(server, "G" + all_registers_hex + ";thread:0047;", "OK");97  ASSERT_TRUE(write_result.get());98}99 100TEST_F(GDBRemoteCommunicationClientTest, WriteRegisterNoSuffix) {101  const lldb::tid_t tid = 0x47;102  const uint32_t reg_num = 4;103  std::future<bool> write_result = std::async(std::launch::async, [&] {104    return client.WriteRegister(tid, reg_num, one_register);105  });106 107  Handle_QThreadSuffixSupported(server, false);108  HandlePacket(server, "Hg47", "OK");109  HandlePacket(server, "P4=" + one_register_hex, "OK");110  ASSERT_TRUE(write_result.get());111 112  write_result = std::async(std::launch::async, [&] {113    return client.WriteAllRegisters(tid, all_registers);114  });115 116  HandlePacket(server, "G" + all_registers_hex, "OK");117  ASSERT_TRUE(write_result.get());118}119 120TEST_F(GDBRemoteCommunicationClientTest, ReadRegister) {121  const lldb::tid_t tid = 0x47;122  const uint32_t reg_num = 4;123  std::future<bool> async_result = std::async(124      std::launch::async, [&] { return client.GetpPacketSupported(tid); });125  Handle_QThreadSuffixSupported(server, true);126  HandlePacket(server, "p0;thread:0047;", one_register_hex);127  ASSERT_TRUE(async_result.get());128 129  std::future<DataBufferSP> read_result = std::async(130      std::launch::async, [&] { return client.ReadRegister(tid, reg_num); });131  HandlePacket(server, "p4;thread:0047;", "41424344");132  auto buffer_sp = read_result.get();133  ASSERT_TRUE(bool(buffer_sp));134  ASSERT_EQ(0,135            memcmp(buffer_sp->GetBytes(), one_register, sizeof one_register));136 137  read_result = std::async(std::launch::async,138                           [&] { return client.ReadAllRegisters(tid); });139  HandlePacket(server, "g;thread:0047;", all_registers_hex);140  buffer_sp = read_result.get();141  ASSERT_TRUE(bool(buffer_sp));142  ASSERT_EQ(0,143            memcmp(buffer_sp->GetBytes(), all_registers, sizeof all_registers));144}145 146TEST_F(GDBRemoteCommunicationClientTest, SaveRestoreRegistersNoSuffix) {147  const lldb::tid_t tid = 0x47;148  uint32_t save_id;149  std::future<bool> async_result = std::async(std::launch::async, [&] {150    return client.SaveRegisterState(tid, save_id);151  });152  Handle_QThreadSuffixSupported(server, false);153  HandlePacket(server, "Hg47", "OK");154  HandlePacket(server, "QSaveRegisterState", "1");155  ASSERT_TRUE(async_result.get());156  EXPECT_EQ(1u, save_id);157 158  async_result = std::async(std::launch::async, [&] {159    return client.RestoreRegisterState(tid, save_id);160  });161  HandlePacket(server, "QRestoreRegisterState:1", "OK");162  ASSERT_TRUE(async_result.get());163}164 165TEST_F(GDBRemoteCommunicationClientTest, SyncThreadState) {166  const lldb::tid_t tid = 0x47;167  std::future<bool> async_result = std::async(168      std::launch::async, [&] { return client.SyncThreadState(tid); });169  HandlePacket(server, "qSyncThreadStateSupported", "OK");170  HandlePacket(server, "QSyncThreadState:0047;", "OK");171  ASSERT_TRUE(async_result.get());172}173 174TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo) {175  llvm::Triple triple("i386-pc-linux");176 177  FileSpec file_specs[] = {178      FileSpec("/foo/bar.so", FileSpec::Style::posix),179      FileSpec("/foo/baz.so", FileSpec::Style::posix),180 181      // This is a bit dodgy but we currently depend on GetModulesInfo not182      // performing denormalization. It can go away once the users183      // (DynamicLoaderPOSIXDYLD, at least) correctly set the path syntax for184      // the FileSpecs they create.185      FileSpec("/foo/baw.so", FileSpec::Style::windows),186  };187  std::future<std::optional<std::vector<ModuleSpec>>> async_result =188      std::async(std::launch::async,189                 [&] { return client.GetModulesInfo(file_specs, triple); });190  HandlePacket(191      server, "jModulesInfo:["192              R"({"file":"/foo/bar.so","triple":"i386-pc-linux"},)"193              R"({"file":"/foo/baz.so","triple":"i386-pc-linux"},)"194              R"({"file":"/foo/baw.so","triple":"i386-pc-linux"}])",195      R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"196      R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])");197 198  auto result = async_result.get();199  ASSERT_TRUE(result.has_value());200  ASSERT_EQ(1u, result->size());201  EXPECT_EQ("/foo/bar.so", (*result)[0].GetFileSpec().GetPath());202  EXPECT_EQ(triple, (*result)[0].GetArchitecture().GetTriple());203  EXPECT_EQ(UUID("@ABCDEFGHIJKLMNO", 16), (*result)[0].GetUUID());204  EXPECT_EQ(0u, (*result)[0].GetObjectOffset());205  EXPECT_EQ(1234u, (*result)[0].GetObjectSize());206}207 208TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo_UUID20) {209  llvm::Triple triple("i386-pc-linux");210 211  FileSpec file_spec("/foo/bar.so", FileSpec::Style::posix);212  std::future<std::optional<std::vector<ModuleSpec>>> async_result =213      std::async(std::launch::async,214                 [&] { return client.GetModulesInfo(file_spec, triple); });215  HandlePacket(216      server,217      "jModulesInfo:["218      R"({"file":"/foo/bar.so","triple":"i386-pc-linux"}])",219      R"([{"uuid":"404142434445464748494a4b4c4d4e4f50515253","triple":"i386-pc-linux",)"220      R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])");221 222  auto result = async_result.get();223  ASSERT_TRUE(result.has_value());224  ASSERT_EQ(1u, result->size());225  EXPECT_EQ("/foo/bar.so", (*result)[0].GetFileSpec().GetPath());226  EXPECT_EQ(triple, (*result)[0].GetArchitecture().GetTriple());227  EXPECT_EQ(UUID("@ABCDEFGHIJKLMNOPQRS", 20), (*result)[0].GetUUID());228  EXPECT_EQ(0u, (*result)[0].GetObjectOffset());229  EXPECT_EQ(1234u, (*result)[0].GetObjectSize());230}231 232TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfoInvalidResponse) {233  llvm::Triple triple("i386-pc-linux");234  FileSpec file_spec("/foo/bar.so", FileSpec::Style::posix);235 236  const char *invalid_responses[] = {237      // no UUID238      R"([{"triple":"i386-pc-linux",)"239      R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])",240      // invalid UUID241      R"([{"uuid":"XXXXXX","triple":"i386-pc-linux",)"242      R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])",243      // no triple244      R"([{"uuid":"404142434445464748494a4b4c4d4e4f",)"245      R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])",246      // no file_path247      R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"248      R"("file_offset":0,"file_size":1234}]])",249      // no file_offset250      R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"251      R"("file_path":"/foo/bar.so","file_size":1234}]])",252      // no file_size253      R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"254      R"("file_path":"/foo/bar.so","file_offset":0}]])",255  };256 257  for (const char *response : invalid_responses) {258    std::future<std::optional<std::vector<ModuleSpec>>> async_result =259        std::async(std::launch::async,260                   [&] { return client.GetModulesInfo(file_spec, triple); });261    HandlePacket(262        server,263        R"(jModulesInfo:[{"file":"/foo/bar.so","triple":"i386-pc-linux"}])",264        response);265 266    auto result = async_result.get();267    ASSERT_TRUE(result);268    ASSERT_EQ(0u, result->size()) << "response was: " << response;269  }270}271 272TEST_F(GDBRemoteCommunicationClientTest, TestPacketSpeedJSON) {273  std::thread server_thread([this] {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  size_t num_packets;306  ASSERT_TRUE(dict_sp->GetValueForKeyAsInteger("num_packets", num_packets))307      << ss.GetString();308  ASSERT_EQ(10, (int)num_packets);309}310 311TEST_F(GDBRemoteCommunicationClientTest, SendSignalsToIgnore) {312  std::future<Status> result = std::async(std::launch::async, [&] {313    return client.SendSignalsToIgnore({2, 3, 5, 7, 0xB, 0xD, 0x11});314  });315 316  HandlePacket(server, "QPassSignals:02;03;05;07;0b;0d;11", "OK");317  EXPECT_TRUE(result.get().Success());318 319  result = std::async(std::launch::async, [&] {320    return client.SendSignalsToIgnore(std::vector<int32_t>());321  });322 323  HandlePacket(server, "QPassSignals:", "OK");324  EXPECT_TRUE(result.get().Success());325}326 327TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfo) {328  const lldb::addr_t addr = 0xa000;329  lldb_private::MemoryRegionInfo region_info;330  std::future<Status> result = std::async(std::launch::async, [&] {331    return client.GetMemoryRegionInfo(addr, region_info);332  });333 334  HandlePacket(server,335      "qMemoryRegionInfo:a000",336      "start:a000;size:2000;permissions:rx;name:2f666f6f2f6261722e736f;");337  if (XMLDocument::XMLEnabled()) {338    // In case we have XML support, this will also do a "qXfer:memory-map".339    // Preceeded by a query for supported extensions. Pretend we don't support340    // that.341    HandlePacket(server, testing::StartsWith("qSupported:"), "");342  }343  EXPECT_TRUE(result.get().Success());344  EXPECT_EQ(addr, region_info.GetRange().GetRangeBase());345  EXPECT_EQ(0x2000u, region_info.GetRange().GetByteSize());346  EXPECT_EQ(lldb_private::MemoryRegionInfo::eYes, region_info.GetReadable());347  EXPECT_EQ(lldb_private::MemoryRegionInfo::eNo, region_info.GetWritable());348  EXPECT_EQ(lldb_private::MemoryRegionInfo::eYes, region_info.GetExecutable());349  EXPECT_EQ("/foo/bar.so", region_info.GetName().GetStringRef());350  EXPECT_EQ(lldb_private::MemoryRegionInfo::eDontKnow,351            region_info.GetMemoryTagged());352  EXPECT_EQ(lldb_private::MemoryRegionInfo::eDontKnow,353            region_info.IsStackMemory());354  EXPECT_EQ(lldb_private::MemoryRegionInfo::eDontKnow,355            region_info.IsShadowStack());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:;type:stack;");363  EXPECT_TRUE(result.get().Success());364  EXPECT_EQ(lldb_private::MemoryRegionInfo::eNo, region_info.GetMemoryTagged());365  EXPECT_EQ(lldb_private::MemoryRegionInfo::eYes, region_info.IsStackMemory());366  EXPECT_EQ(lldb_private::MemoryRegionInfo::eNo, region_info.IsShadowStack());367 368  result = std::async(std::launch::async, [&] {369    return client.GetMemoryRegionInfo(addr, region_info);370  });371 372  HandlePacket(server, "qMemoryRegionInfo:a000",373               "start:a000;size:2000;flags: mt  zz mt ss  ;type:ha,ha,stack;");374  EXPECT_TRUE(result.get().Success());375  EXPECT_EQ(lldb_private::MemoryRegionInfo::eYes,376            region_info.GetMemoryTagged());377  EXPECT_EQ(lldb_private::MemoryRegionInfo::eYes, region_info.IsStackMemory());378  EXPECT_EQ(lldb_private::MemoryRegionInfo::eYes, region_info.IsShadowStack());379 380  result = std::async(std::launch::async, [&] {381    return client.GetMemoryRegionInfo(addr, region_info);382  });383 384  HandlePacket(server, "qMemoryRegionInfo:a000",385               "start:a000;size:2000;type:heap;");386  EXPECT_TRUE(result.get().Success());387  EXPECT_EQ(lldb_private::MemoryRegionInfo::eNo, region_info.IsStackMemory());388}389 390TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfoInvalidResponse) {391  const lldb::addr_t addr = 0x4000;392  lldb_private::MemoryRegionInfo region_info;393  std::future<Status> result = std::async(std::launch::async, [&] {394    return client.GetMemoryRegionInfo(addr, region_info);395  });396 397  HandlePacket(server, "qMemoryRegionInfo:4000", "start:4000;size:0000;");398  if (XMLDocument::XMLEnabled()) {399    // In case we have XML support, this will also do a "qXfer:memory-map".400    // Preceeded by a query for supported extensions. Pretend we don't support401    // that.402    HandlePacket(server, testing::StartsWith("qSupported:"), "");403  }404  EXPECT_FALSE(result.get().Success());405}406 407TEST_F(GDBRemoteCommunicationClientTest, SendTraceSupportedPacket) {408  TraceSupportedResponse trace_type;409  std::string error_message;410  auto callback = [&] {411    std::chrono::seconds timeout(10);412    if (llvm::Expected<TraceSupportedResponse> trace_type_or_err =413            client.SendTraceSupported(timeout)) {414      trace_type = *trace_type_or_err;415      error_message = "";416      return true;417    } else {418      trace_type = {};419      error_message = llvm::toString(trace_type_or_err.takeError());420      return false;421    }422  };423 424  // Success response425  {426    std::future<bool> result = std::async(std::launch::async, callback);427 428    HandlePacket(429        server, "jLLDBTraceSupported",430        R"({"name":"intel-pt","description":"Intel Processor Trace"}])");431 432    EXPECT_TRUE(result.get());433    ASSERT_STREQ(trace_type.name.c_str(), "intel-pt");434    ASSERT_STREQ(trace_type.description.c_str(), "Intel Processor Trace");435  }436 437  // Error response - wrong json438  {439    std::future<bool> result = std::async(std::launch::async, callback);440 441    HandlePacket(server, "jLLDBTraceSupported", R"({"type":"intel-pt"}])");442 443    EXPECT_FALSE(result.get());444    ASSERT_STREQ(error_message.c_str(), "missing value at TraceSupportedResponse.description");445  }446 447  // Error response448  {449    std::future<bool> result = std::async(std::launch::async, callback);450 451    HandlePacket(server, "jLLDBTraceSupported", "E23");452 453    EXPECT_FALSE(result.get());454  }455 456  // Error response with error message457  {458    std::future<bool> result = std::async(std::launch::async, callback);459 460    HandlePacket(server, "jLLDBTraceSupported",461                 "E23;50726F63657373206E6F742072756E6E696E672E");462 463    EXPECT_FALSE(result.get());464    ASSERT_STREQ(error_message.c_str(), "Process not running.");465  }466}467 468TEST_F(GDBRemoteCommunicationClientTest, GetQOffsets) {469  const auto &GetQOffsets = [&](llvm::StringRef response) {470    std::future<std::optional<QOffsets>> result =471        std::async(std::launch::async, [&] { return client.GetQOffsets(); });472 473    HandlePacket(server, "qOffsets", response);474    return result.get();475  };476  EXPECT_EQ((QOffsets{false, {0x1234, 0x1234}}),477            GetQOffsets("Text=1234;Data=1234"));478  EXPECT_EQ((QOffsets{false, {0x1234, 0x1234, 0x1234}}),479            GetQOffsets("Text=1234;Data=1234;Bss=1234"));480  EXPECT_EQ((QOffsets{true, {0x1234}}), GetQOffsets("TextSeg=1234"));481  EXPECT_EQ((QOffsets{true, {0x1234, 0x2345}}),482            GetQOffsets("TextSeg=1234;DataSeg=2345"));483 484  EXPECT_EQ(std::nullopt, GetQOffsets("E05"));485  EXPECT_EQ(std::nullopt, GetQOffsets("Text=bogus"));486  EXPECT_EQ(std::nullopt, GetQOffsets("Text=1234"));487  EXPECT_EQ(std::nullopt, GetQOffsets("Text=1234;Data=1234;"));488  EXPECT_EQ(std::nullopt, GetQOffsets("Text=1234;Data=1234;Bss=1234;"));489  EXPECT_EQ(std::nullopt, GetQOffsets("TEXTSEG=1234"));490  EXPECT_EQ(std::nullopt, GetQOffsets("TextSeg=0x1234"));491  EXPECT_EQ(std::nullopt, GetQOffsets("TextSeg=12345678123456789"));492}493 494static void495check_qmemtags(TestClient &client, MockServer &server, size_t read_len,496               int32_t type, const char *packet, llvm::StringRef response,497               std::optional<std::vector<uint8_t>> expected_tag_data) {498  const auto &ReadMemoryTags = [&]() {499    std::future<DataBufferSP> result = std::async(std::launch::async, [&] {500      return client.ReadMemoryTags(0xDEF0, read_len, type);501    });502 503    HandlePacket(server, packet, response);504    return result.get();505  };506 507  auto result = ReadMemoryTags();508  if (expected_tag_data) {509    ASSERT_TRUE(result);510    llvm::ArrayRef<uint8_t> expected(*expected_tag_data);511    llvm::ArrayRef<uint8_t> got = result->GetData();512    ASSERT_THAT(expected, testing::ContainerEq(got));513  } else {514    ASSERT_FALSE(result);515  }516}517 518TEST_F(GDBRemoteCommunicationClientTest, ReadMemoryTags) {519  // Zero length reads are valid520  check_qmemtags(client, server, 0, 1, "qMemTags:def0,0:1", "m",521                 std::vector<uint8_t>{});522 523  // Type can be negative. Put into the packet as the raw bytes524  // (as opposed to a literal -1)525  check_qmemtags(client, server, 0, -1, "qMemTags:def0,0:ffffffff", "m",526                 std::vector<uint8_t>{});527  check_qmemtags(client, server, 0, std::numeric_limits<int32_t>::min(),528                 "qMemTags:def0,0:80000000", "m", std::vector<uint8_t>{});529  check_qmemtags(client, server, 0, std::numeric_limits<int32_t>::max(),530                 "qMemTags:def0,0:7fffffff", "m", std::vector<uint8_t>{});531 532  // The client layer does not check the length of the received data.533  // All we need is the "m" and for the decode to use all of the chars534  check_qmemtags(client, server, 32, 2, "qMemTags:def0,20:2", "m09",535                 std::vector<uint8_t>{0x9});536 537  // Zero length response is fine as long as the "m" is present538  check_qmemtags(client, server, 0, 0x34, "qMemTags:def0,0:34", "m",539                 std::vector<uint8_t>{});540 541  // Normal responses542  check_qmemtags(client, server, 16, 1, "qMemTags:def0,10:1", "m66",543                 std::vector<uint8_t>{0x66});544  check_qmemtags(client, server, 32, 1, "qMemTags:def0,20:1", "m0102",545                 std::vector<uint8_t>{0x1, 0x2});546 547  // Empty response is an error548  check_qmemtags(client, server, 17, 1, "qMemTags:def0,11:1", "", std::nullopt);549  // Usual error response550  check_qmemtags(client, server, 17, 1, "qMemTags:def0,11:1", "E01",551                 std::nullopt);552  // Leading m missing553  check_qmemtags(client, server, 17, 1, "qMemTags:def0,11:1", "01",554                 std::nullopt);555  // Anything other than m is an error556  check_qmemtags(client, server, 17, 1, "qMemTags:def0,11:1", "z01",557                 std::nullopt);558  // Decoding tag data doesn't use all the chars in the packet559  check_qmemtags(client, server, 32, 1, "qMemTags:def0,20:1", "m09zz",560                 std::nullopt);561  // Data that is not hex bytes562  check_qmemtags(client, server, 32, 1, "qMemTags:def0,20:1", "mhello",563                 std::nullopt);564  // Data is not a complete hex char565  check_qmemtags(client, server, 32, 1, "qMemTags:def0,20:1", "m9",566                 std::nullopt);567  // Data has a trailing hex char568  check_qmemtags(client, server, 32, 1, "qMemTags:def0,20:1", "m01020",569                 std::nullopt);570}571 572static void check_Qmemtags(TestClient &client, MockServer &server,573                           lldb::addr_t addr, size_t len, int32_t type,574                           const std::vector<uint8_t> &tags, const char *packet,575                           llvm::StringRef response, bool should_succeed) {576  const auto &WriteMemoryTags = [&]() {577    std::future<Status> result = std::async(std::launch::async, [&] {578      return client.WriteMemoryTags(addr, len, type, tags);579    });580 581    HandlePacket(server, packet, response);582    return result.get();583  };584 585  auto result = WriteMemoryTags();586  if (should_succeed)587    ASSERT_TRUE(result.Success());588  else589    ASSERT_TRUE(result.Fail());590}591 592TEST_F(GDBRemoteCommunicationClientTest, WriteMemoryTags) {593  check_Qmemtags(client, server, 0xABCD, 0x20, 1,594                 std::vector<uint8_t>{0x12, 0x34}, "QMemTags:abcd,20:1:1234",595                 "OK", true);596 597  // The GDB layer doesn't care that the number of tags !=598  // the length of the write.599  check_Qmemtags(client, server, 0x4321, 0x20, 9, std::vector<uint8_t>{},600                 "QMemTags:4321,20:9:", "OK", true);601 602  check_Qmemtags(client, server, 0x8877, 0x123, 0x34,603                 std::vector<uint8_t>{0x55, 0x66, 0x77},604                 "QMemTags:8877,123:34:556677", "E01", false);605 606  // Type is a signed integer but is packed as its raw bytes,607  // instead of having a +/-.608  check_Qmemtags(client, server, 0x456789, 0, -1, std::vector<uint8_t>{0x99},609                 "QMemTags:456789,0:ffffffff:99", "E03", false);610  check_Qmemtags(client, server, 0x456789, 0,611                 std::numeric_limits<int32_t>::max(),612                 std::vector<uint8_t>{0x99}, "QMemTags:456789,0:7fffffff:99",613                 "E03", false);614  check_Qmemtags(client, server, 0x456789, 0,615                 std::numeric_limits<int32_t>::min(),616                 std::vector<uint8_t>{0x99}, "QMemTags:456789,0:80000000:99",617                 "E03", false);618}619 620// Prior to this verison, constructing a std::future for a type without a621// default constructor is not possible.622// https://developercommunity.visualstudio.com/t/c-shared-state-futuresstate-default-constructs-the/60897623#if !defined(_MSC_VER) || _MSC_VER >= 1932624TEST_F(GDBRemoteCommunicationClientTest, CalculateMD5) {625  FileSpec file_spec("/foo/bar", FileSpec::Style::posix);626  std::future<ErrorOr<MD5::MD5Result>> async_result = std::async(627      std::launch::async, [&] { return client.CalculateMD5(file_spec); });628 629  lldb_private::StreamString stream;630  stream.PutCString("vFile:MD5:");631  stream.PutStringAsRawHex8(file_spec.GetPath(false));632  HandlePacket(server, stream.GetString().str(),633               "F,"634               "deadbeef01020304"635               "05060708deadbeef");636  auto result = async_result.get();637 638  // Server and client puts/parses low, and then high639  const uint64_t expected_low = 0xdeadbeef01020304;640  const uint64_t expected_high = 0x05060708deadbeef;641  ASSERT_TRUE(result);642  EXPECT_EQ(expected_low, result->low());643  EXPECT_EQ(expected_high, result->high());644}645#endif646 647TEST_F(GDBRemoteCommunicationClientTest, MultiMemReadSupported) {648  std::future<bool> async_result = std::async(std::launch::async, [&] {649    StringExtractorGDBRemote qSupported_packet_request;650    server.GetPacket(qSupported_packet_request);651    server.SendPacket("MultiMemRead+;");652    return true;653  });654  ASSERT_TRUE(client.GetMultiMemReadSupported());655  async_result.wait();656}657 658TEST_F(GDBRemoteCommunicationClientTest, MultiMemReadNotSupported) {659  std::future<bool> async_result = std::async(std::launch::async, [&] {660    StringExtractorGDBRemote qSupported_packet_request;661    server.GetPacket(qSupported_packet_request);662    server.SendPacket(";");663    return true;664  });665  ASSERT_FALSE(client.GetMultiMemReadSupported());666  async_result.wait();667}668