GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
                                                        Error &error,
                                                        bool &interrupt,
                                                        bool &quit)
{
    StringExtractorGDBRemote packet;

    PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec, false);
    if (packet_result == PacketResult::Success)
    {
        const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType ();
        switch (packet_type)
        {
        case StringExtractorGDBRemote::eServerPacketType_nack:
        case StringExtractorGDBRemote::eServerPacketType_ack:
            break;

        case StringExtractorGDBRemote::eServerPacketType_invalid:
            error.SetErrorString("invalid packet");
            quit = true;
            break;

        case StringExtractorGDBRemote::eServerPacketType_unimplemented:
            packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str());
            break;

        default:
            auto handler_it = m_packet_handlers.find(packet_type);
            if (handler_it == m_packet_handlers.end())
                packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str());
            else
                packet_result = handler_it->second (packet, error, interrupt, quit);
            break;
        }
    }
    else
    {
        if (!IsConnected())
        {
            error.SetErrorString("lost connection");
            quit = true;
        }
        else
        {
            error.SetErrorString("timeout");
        }
    }

    // Check if anything occurred that would force us to want to exit.
    if (m_exit_now)
        quit = true;

    return packet_result;
}
size_t
GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &packet, uint32_t timeout_usec)
{
    uint8_t buffer[8192];
    Error error;

    Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS | GDBR_LOG_VERBOSE));

    // Check for a packet from our cache first without trying any reading...
    if (CheckForPacket (NULL, 0, packet))
        return packet.GetStringRef().size();

    bool timed_out = false;
    while (IsConnected() && !timed_out)
    {
        lldb::ConnectionStatus status = eConnectionStatusNoConnection;
        size_t bytes_read = Read (buffer, sizeof(buffer), timeout_usec, status, &error);
        
        if (log)
            log->Printf ("%s: Read (buffer, (sizeof(buffer), timeout_usec = 0x%x, status = %s, error = %s) => bytes_read = %" PRIu64,
                         __PRETTY_FUNCTION__,
                         timeout_usec, 
                         Communication::ConnectionStatusAsCString (status),
                         error.AsCString(), 
                         (uint64_t)bytes_read);

        if (bytes_read > 0)
        {
            if (CheckForPacket (buffer, bytes_read, packet))
                return packet.GetStringRef().size();
        }
        else
        {
            switch (status)
            {
            case eConnectionStatusTimedOut:
                timed_out = true;
                break;
            case eConnectionStatusSuccess:
                //printf ("status = success but error = %s\n", error.AsCString("<invalid>"));
                break;
                
            case eConnectionStatusEndOfFile:
            case eConnectionStatusNoConnection:
            case eConnectionStatusLostConnection:
            case eConnectionStatusError:
                Disconnect();
                break;
            }
        }
    }
    packet.Clear ();    
    return 0;
}
TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateStructuredDataReceipt) {
  // Build the plain-text version of the JSON data we will have the
  // server send.
  const std::string json_payload =
      "{ \"type\": \"MyFeatureType\", "
      "  \"elements\": [ \"entry1\", \"entry2\" ] }";
  const std::string json_packet = "JSON-async:" + json_payload;

  // Escape it properly for transit.
  StreamGDBRemote stream;
  stream.PutEscapedBytes(json_packet.c_str(), json_packet.length());
  stream.Flush();

  StringExtractorGDBRemote response;

  // Send async structured data packet, then stop.
  ASSERT_EQ(PacketResult::Success, server.SendPacket(stream.GetData()));
  ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
  ASSERT_EQ(eStateStopped, SendCPacket(response));
  ASSERT_EQ("T01", response.GetStringRef());
  ASSERT_EQ(1ul, delegate.structured_data_packets.size());

  // Verify the packet contents.  It should have been unescaped upon packet
  // reception.
  ASSERT_EQ(json_packet, delegate.structured_data_packets[0]);
}
GDBRemoteCommunication::PacketResult
GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock(
    llvm::StringRef payload, StringExtractorGDBRemote &response) {
  PacketResult packet_result = SendPacketNoLock(payload);
  if (packet_result != PacketResult::Success)
    return packet_result;

  const size_t max_response_retries = 3;
  for (size_t i = 0; i < max_response_retries; ++i) {
    packet_result = ReadPacket(response, GetPacketTimeout(), true);
    // Make sure we received a response
    if (packet_result != PacketResult::Success)
      return packet_result;
    // Make sure our response is valid for the payload that was sent
    if (response.ValidateResponse())
      return packet_result;
    // Response says it wasn't valid
    Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS);
    if (log)
      log->Printf(
          "error: packet with payload \"%.*s\" got invalid response \"%s\": %s",
          int(payload.size()), payload.data(), response.GetStringRef().c_str(),
          (i == (max_response_retries - 1))
              ? "using invalid response and giving up"
              : "ignoring response and waiting for another");
  }
  return packet_result;
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::SendIllFormedResponse(
    const StringExtractorGDBRemote &failed_packet, const char *message) {
  Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS));
  if (log)
    log->Printf("GDBRemoteCommunicationServer::%s: ILLFORMED: '%s' (%s)",
                __FUNCTION__, failed_packet.GetStringRef().c_str(),
                message ? message : "");
  return SendErrorResponse(0x03);
}
TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateInterface) {
  StringExtractorGDBRemote response;

  // Continue. We'll have the server send a bunch of async packets before it
  // stops.
  ASSERT_EQ(PacketResult::Success, server.SendPacket("O4142"));
  ASSERT_EQ(PacketResult::Success, server.SendPacket("Apro"));
  ASSERT_EQ(PacketResult::Success, server.SendPacket("O4344"));
  ASSERT_EQ(PacketResult::Success, server.SendPacket("Afile"));
  ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
  ASSERT_EQ(eStateStopped, SendCPacket(response));
  ASSERT_EQ("T01", response.GetStringRef());
  ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
  ASSERT_EQ("c", response.GetStringRef());

  EXPECT_EQ("ABCD", delegate.output);
  EXPECT_EQ("profile", delegate.misc_data);
  EXPECT_EQ(1u, delegate.stop_reply_called);
}
TEST_F(GDBRemoteClientBaseTest, SendContinueAndWait) {
  StringExtractorGDBRemote response;
  ContinueFixture fix;
  if (HasFailure())
    return;

  // Continue. The inferior will stop with a signal.
  ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
  ASSERT_EQ(eStateStopped, fix.SendCPacket(response));
  ASSERT_EQ("T01", response.GetStringRef());
  ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
  ASSERT_EQ("c", response.GetStringRef());

  // Continue. The inferior will exit.
  ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("W01"));
  ASSERT_EQ(eStateExited, fix.SendCPacket(response));
  ASSERT_EQ("W01", response.GetStringRef());
  ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
  ASSERT_EQ("c", response.GetStringRef());

  // Continue. The inferior will get killed.
  ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("X01"));
  ASSERT_EQ(eStateExited, fix.SendCPacket(response));
  ASSERT_EQ("X01", response.GetStringRef());
  ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
  ASSERT_EQ("c", response.GetStringRef());
}
TEST_F(GDBRemoteClientBaseTest, SendPacketAndReceiveResponseWithOutputSupport) {
  StringExtractorGDBRemote response;
  StreamString command_output;

  ASSERT_EQ(PacketResult::Success, server.SendPacket("O"));
  ASSERT_EQ(PacketResult::Success, server.SendPacket("O48656c6c6f2c"));
  ASSERT_EQ(PacketResult::Success, server.SendPacket("O20"));
  ASSERT_EQ(PacketResult::Success, server.SendPacket("O"));
  ASSERT_EQ(PacketResult::Success, server.SendPacket("O776f726c64"));
  ASSERT_EQ(PacketResult::Success, server.SendPacket("OK"));

  PacketResult result = client.SendPacketAndReceiveResponseWithOutputSupport(
      "qRcmd,test", response, true,
      [&command_output](llvm::StringRef output) { command_output << output; });

  ASSERT_EQ(PacketResult::Success, result);
  ASSERT_EQ("OK", response.GetStringRef());
  ASSERT_EQ("Hello, world", command_output.GetString().str());
}
TEST_F(GDBRemoteCommunicationClientTest, TestPacketSpeedJSON) {
  std::thread server_thread([this] {
    for (;;) {
      StringExtractorGDBRemote request;
      PacketResult result = server.GetPacket(request);
      if (result == PacketResult::ErrorDisconnected)
        return;
      ASSERT_EQ(PacketResult::Success, result);
      StringRef ref = request.GetStringRef();
      ASSERT_TRUE(ref.consume_front("qSpeedTest:response_size:"));
      int size;
      ASSERT_FALSE(ref.consumeInteger(10, size)) << "ref: " << ref;
      std::string response(size, 'X');
      ASSERT_EQ(PacketResult::Success, server.SendPacket(response));
    }
  });

  StreamString ss;
  client.TestPacketSpeed(10, 32, 32, 4096, true, ss);
  client.Disconnect();
  server_thread.join();

  GTEST_LOG_(INFO) << "Formatted output: " << ss.GetData();
  auto object_sp = StructuredData::ParseJSON(ss.GetString());
  ASSERT_TRUE(bool(object_sp));
  auto dict_sp = object_sp->GetAsDictionary();
  ASSERT_TRUE(bool(dict_sp));

  object_sp = dict_sp->GetValueForKey("packet_speeds");
  ASSERT_TRUE(bool(object_sp));
  dict_sp = object_sp->GetAsDictionary();
  ASSERT_TRUE(bool(dict_sp));

  int num_packets;
  ASSERT_TRUE(dict_sp->GetValueForKeyAsInteger("num_packets", num_packets))
      << ss.GetString();
  ASSERT_EQ(10, num_packets);
}
//void *
//GDBRemoteCommunicationServer::AsyncThread (void *arg)
//{
//    GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer*) arg;
//
//    Log *log;// (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
//    if (log)
//        log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread starting...", __FUNCTION__, arg, process->GetID());
//
//    StringExtractorGDBRemote packet;
//
//    while ()
//    {
//        if (packet.
//    }
//
//    if (log)
//        log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread exiting...", __FUNCTION__, arg, process->GetID());
//
//    process->m_async_thread = LLDB_INVALID_HOST_THREAD;
//    return NULL;
//}
//
bool
GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
                                                        Error &error,
                                                        bool &interrupt,
                                                        bool &quit)
{
    StringExtractorGDBRemote packet;
    PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec);
    if (packet_result == PacketResult::Success)
    {
        const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType ();
        switch (packet_type)
        {
        case StringExtractorGDBRemote::eServerPacketType_nack:
        case StringExtractorGDBRemote::eServerPacketType_ack:
            break;

        case StringExtractorGDBRemote::eServerPacketType_invalid:
            error.SetErrorString("invalid packet");
            quit = true;
            break;

        case StringExtractorGDBRemote::eServerPacketType_interrupt:
            error.SetErrorString("interrupt received");
            interrupt = true;
            break;

        default:
        case StringExtractorGDBRemote::eServerPacketType_unimplemented:
            packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str());
            break;

        case StringExtractorGDBRemote::eServerPacketType_A:
            packet_result = Handle_A (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_qfProcessInfo:
            packet_result = Handle_qfProcessInfo (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_qsProcessInfo:
            packet_result = Handle_qsProcessInfo (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_qC:
            packet_result = Handle_qC (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_qHostInfo:
            packet_result = Handle_qHostInfo (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer:
            packet_result = Handle_qLaunchGDBServer (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess:
            packet_result = Handle_qKillSpawnedProcess (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess:
            packet_result = Handle_qLaunchSuccess (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_qGroupName:
            packet_result = Handle_qGroupName (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID:
            packet_result = Handle_qProcessInfoPID (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_qSpeedTest:
            packet_result = Handle_qSpeedTest (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_qUserName:
            packet_result = Handle_qUserName (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir:
            packet_result = Handle_qGetWorkingDir(packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_QEnvironment:
            packet_result = Handle_QEnvironment (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_QLaunchArch:
            packet_result = Handle_QLaunchArch (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR:
            packet_result = Handle_QSetDisableASLR (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN:
            packet_result = Handle_QSetSTDIN (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT:
            packet_result = Handle_QSetSTDOUT (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_QSetSTDERR:
            packet_result = Handle_QSetSTDERR (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir:
            packet_result = Handle_QSetWorkingDir (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode:
            packet_result = Handle_QStartNoAckMode (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir:
            packet_result = Handle_qPlatform_mkdir (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod:
            packet_result = Handle_qPlatform_chmod (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_qPlatform_shell:
            packet_result = Handle_qPlatform_shell (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_vFile_open:
            packet_result = Handle_vFile_Open (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_vFile_close:
            packet_result = Handle_vFile_Close (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_vFile_pread:
            packet_result = Handle_vFile_pRead (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_vFile_pwrite:
            packet_result = Handle_vFile_pWrite (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_vFile_size:
            packet_result = Handle_vFile_Size (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_vFile_mode:
            packet_result = Handle_vFile_Mode (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_vFile_exists:
            packet_result = Handle_vFile_Exists (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_vFile_stat:
            packet_result = Handle_vFile_Stat (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_vFile_md5:
            packet_result = Handle_vFile_MD5 (packet);
            break;

        case StringExtractorGDBRemote::eServerPacketType_vFile_symlink:
            packet_result = Handle_vFile_symlink (packet);
            break;
            
        case StringExtractorGDBRemote::eServerPacketType_vFile_unlink:
            packet_result = Handle_vFile_unlink (packet);
            break;
        }
    }
    else
    {
        if (!IsConnected())
        {
            error.SetErrorString("lost connection");
            quit = true;
        }
        else
        {
            error.SetErrorString("timeout");
        }
    }
    return packet_result == PacketResult::Success;
}
bool
GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, StringExtractorGDBRemote &packet)
{
    // Put the packet data into the buffer in a thread safe fashion
    Mutex::Locker locker(m_bytes_mutex);
    
    Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));

    if (src && src_len > 0)
    {
        if (log && log->GetVerbose())
        {
            StreamString s;
            log->Printf ("GDBRemoteCommunication::%s adding %u bytes: %.*s",
                         __FUNCTION__, 
                         (uint32_t)src_len, 
                         (uint32_t)src_len, 
                         src);
        }
        m_bytes.append ((const char *)src, src_len);
    }

    // Parse up the packets into gdb remote packets
    if (!m_bytes.empty())
    {
        // end_idx must be one past the last valid packet byte. Start
        // it off with an invalid value that is the same as the current
        // index.
        size_t content_start = 0;
        size_t content_length = 0;
        size_t total_length = 0;
        size_t checksum_idx = std::string::npos;

        switch (m_bytes[0])
        {
            case '+':       // Look for ack
            case '-':       // Look for cancel
            case '\x03':    // ^C to halt target
                content_length = total_length = 1;  // The command is one byte long...
                break;

            case '$':
                // Look for a standard gdb packet?
                {
                    size_t hash_pos = m_bytes.find('#');
                    if (hash_pos != std::string::npos)
                    {
                        if (hash_pos + 2 < m_bytes.size())
                        {
                            checksum_idx = hash_pos + 1;
                            // Skip the dollar sign
                            content_start = 1; 
                            // Don't include the # in the content or the $ in the content length
                            content_length = hash_pos - 1;  
                            
                            total_length = hash_pos + 3; // Skip the # and the two hex checksum bytes
                        }
                        else
                        {
                            // Checksum bytes aren't all here yet
                            content_length = std::string::npos;
                        }
                    }
                }
                break;

            default:
                {
                    // We have an unexpected byte and we need to flush all bad 
                    // data that is in m_bytes, so we need to find the first
                    // byte that is a '+' (ACK), '-' (NACK), \x03 (CTRL+C interrupt),
                    // or '$' character (start of packet header) or of course,
                    // the end of the data in m_bytes...
                    const size_t bytes_len = m_bytes.size();
                    bool done = false;
                    uint32_t idx;
                    for (idx = 1; !done && idx < bytes_len; ++idx)
                    {
                        switch (m_bytes[idx])
                        {
                        case '+':
                        case '-':
                        case '\x03':
                        case '$':
                            done = true;
                            break;
                                
                        default:
                            break;
                        }
                    }
                    if (log)
                        log->Printf ("GDBRemoteCommunication::%s tossing %u junk bytes: '%.*s'",
                                     __FUNCTION__, idx, idx, m_bytes.c_str());
                    m_bytes.erase(0, idx);
                }
                break;
        }

        if (content_length == std::string::npos)
        {
            packet.Clear();
            return false;
        }
        else if (total_length > 0)
        {

            // We have a valid packet...
            assert (content_length <= m_bytes.size());
            assert (total_length <= m_bytes.size());
            assert (content_length <= total_length);
            
            bool success = true;
            std::string &packet_str = packet.GetStringRef();
            
            
            if (log)
            {
                // If logging was just enabled and we have history, then dump out what
                // we have to the log so we get the historical context. The Dump() call that
                // logs all of the packet will set a boolean so that we don't dump this more
                // than once
                if (!m_history.DidDumpToLog ())
                    m_history.Dump (log);
                
                log->Printf("<%4" PRIu64 "> read packet: %.*s", (uint64_t)total_length, (int)(total_length), m_bytes.c_str());
            }

            m_history.AddPacket (m_bytes.c_str(), total_length, History::ePacketTypeRecv, total_length);

            // Clear packet_str in case there is some existing data in it.
            packet_str.clear();
            // Copy the packet from m_bytes to packet_str expanding the
            // run-length encoding in the process.
            // Reserve enough byte for the most common case (no RLE used)
            packet_str.reserve(m_bytes.length());
            for (std::string::const_iterator c = m_bytes.begin() + content_start; c != m_bytes.begin() + content_start + content_length; ++c)
            {
                if (*c == '*')
                {
                    // '*' indicates RLE. Next character will give us the
                    // repeat count and previous character is what is to be
                    // repeated.
                    char char_to_repeat = packet_str.back();
                    // Number of time the previous character is repeated
                    int repeat_count = *++c + 3 - ' ';
                    // We have the char_to_repeat and repeat_count. Now push
                    // it in the packet.
                    for (int i = 0; i < repeat_count; ++i)
                        packet_str.push_back(char_to_repeat);
                }
                else
                {
                    packet_str.push_back(*c);
                }
            }

            if (m_bytes[0] == '$')
            {
                assert (checksum_idx < m_bytes.size());
                if (::isxdigit (m_bytes[checksum_idx+0]) || 
                    ::isxdigit (m_bytes[checksum_idx+1]))
                {
                    if (GetSendAcks ())
                    {
                        const char *packet_checksum_cstr = &m_bytes[checksum_idx];
                        char packet_checksum = strtol (packet_checksum_cstr, NULL, 16);
                        char actual_checksum = CalculcateChecksum (packet_str.c_str(), packet_str.size());
                        success = packet_checksum == actual_checksum;
                        if (!success)
                        {
                            if (log)
                                log->Printf ("error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x", 
                                             (int)(total_length), 
                                             m_bytes.c_str(),
                                             (uint8_t)packet_checksum,
                                             (uint8_t)actual_checksum);
                        }
                        // Send the ack or nack if needed
                        if (!success)
                            SendNack();
                        else
                            SendAck();
                    }
                }
                else
                {
                    success = false;
                    if (log)
                        log->Printf ("error: invalid checksum in packet: '%s'\n", m_bytes.c_str());
                }
            }
            
            m_bytes.erase(0, total_length);
            packet.SetFilePos(0);
            return success;
        }
    }
    packet.Clear();
    return false;
}
const UnixSignalsSP &
PlatformRemoteGDBServer::GetRemoteUnixSignals()
{
    if (!IsConnected())
        return Platform::GetRemoteUnixSignals();

    if (m_remote_signals_sp)
        return m_remote_signals_sp;

    // If packet not implemented or JSON failed to parse,
    // we'll guess the signal set based on the remote architecture.
    m_remote_signals_sp = UnixSignals::Create(GetRemoteSystemArchitecture());

    const char packet[] = "jSignalsInfo";
    StringExtractorGDBRemote response;
    auto result = m_gdb_client.SendPacketAndWaitForResponse(
            packet, strlen(packet), response, false);

    if (result != decltype(result)::Success ||
            response.GetResponseType() != response.eResponse)
        return m_remote_signals_sp;

    auto object_sp = StructuredData::ParseJSON(response.GetStringRef());
    if (!object_sp || !object_sp->IsValid())
        return m_remote_signals_sp;

    auto array_sp = object_sp->GetAsArray();
    if (!array_sp || !array_sp->IsValid())
        return m_remote_signals_sp;

    auto remote_signals_sp = std::make_shared<lldb_private::GDBRemoteSignals>();

    bool done = array_sp->ForEach(
        [&remote_signals_sp](StructuredData::Object *object) -> bool
        {
            if (!object || !object->IsValid())
                return false;

            auto dict = object->GetAsDictionary();
            if (!dict || !dict->IsValid())
                return false;

            // Signal number and signal name are required.
            int signo;
            if (!dict->GetValueForKeyAsInteger("signo", signo))
                return false;

            std::string name;
            if (!dict->GetValueForKeyAsString("name", name))
                return false;

            // We can live without short_name, description, etc.
            std::string short_name{""};
            auto object_sp = dict->GetValueForKey("short_name");
            if (object_sp && object_sp->IsValid())
                short_name = object_sp->GetStringValue();

            bool suppress{false};
            object_sp = dict->GetValueForKey("suppress");
            if (object_sp && object_sp->IsValid())
                suppress = object_sp->GetBooleanValue();

            bool stop{false};
            object_sp = dict->GetValueForKey("stop");
            if (object_sp && object_sp->IsValid())
                stop = object_sp->GetBooleanValue();

            bool notify{false};
            object_sp = dict->GetValueForKey("notify");
            if (object_sp && object_sp->IsValid())
                notify = object_sp->GetBooleanValue();

            std::string description{""};
            object_sp = dict->GetValueForKey("description");
            if (object_sp && object_sp->IsValid())
                description = object_sp->GetStringValue();

            remote_signals_sp->AddSignal(signo,
                                         name.c_str(),
                                         short_name.c_str(),
                                         suppress, stop, notify,
                                         description.c_str());
            return true;
        });

    if (done)
        m_remote_signals_sp = std::move(remote_signals_sp);

    return m_remote_signals_sp;
}
StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse(
    ContinueDelegate &delegate, const UnixSignals &signals,
    llvm::StringRef payload, StringExtractorGDBRemote &response) {
  Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
  response.Clear();

  {
    std::lock_guard<std::mutex> lock(m_mutex);
    m_continue_packet = payload;
    m_should_stop = false;
  }
  ContinueLock cont_lock(*this);
  if (!cont_lock)
    return eStateInvalid;
  OnRunPacketSent(true);

  for (;;) {
    PacketResult read_result = ReadPacket(response, kInterruptTimeout, false);
    switch (read_result) {
    case PacketResult::ErrorReplyTimeout: {
      std::lock_guard<std::mutex> lock(m_mutex);
      if (m_async_count == 0)
        continue;
      if (steady_clock::now() >= m_interrupt_time + kInterruptTimeout)
        return eStateInvalid;
    }
    case PacketResult::Success:
      break;
    default:
      if (log)
        log->Printf("GDBRemoteClientBase::%s () ReadPacket(...) => false",
                    __FUNCTION__);
      return eStateInvalid;
    }
    if (response.Empty())
      return eStateInvalid;

    const char stop_type = response.GetChar();
    if (log)
      log->Printf("GDBRemoteClientBase::%s () got packet: %s", __FUNCTION__,
                  response.GetStringRef().c_str());

    switch (stop_type) {
    case 'W':
    case 'X':
      return eStateExited;
    case 'E':
      // ERROR
      return eStateInvalid;
    default:
      if (log)
        log->Printf("GDBRemoteClientBase::%s () unrecognized async packet",
                    __FUNCTION__);
      return eStateInvalid;
    case 'O': {
      std::string inferior_stdout;
      response.GetHexByteString(inferior_stdout);
      delegate.HandleAsyncStdout(inferior_stdout);
      break;
    }
    case 'A':
      delegate.HandleAsyncMisc(
          llvm::StringRef(response.GetStringRef()).substr(1));
      break;
    case 'J':
      delegate.HandleAsyncStructuredDataPacket(response.GetStringRef());
      break;
    case 'T':
    case 'S':
      // Do this with the continue lock held.
      const bool should_stop = ShouldStop(signals, response);
      response.SetFilePos(0);

      // The packet we should resume with. In the future
      // we should check our thread list and "do the right thing"
      // for new threads that show up while we stop and run async
      // packets. Setting the packet to 'c' to continue all threads
      // is the right thing to do 99.99% of the time because if a
      // thread was single stepping, and we sent an interrupt, we
      // will notice above that we didn't stop due to an interrupt
      // but stopped due to stepping and we would _not_ continue.
      // This packet may get modified by the async actions (e.g. to send a
      // signal).
      m_continue_packet = 'c';
      cont_lock.unlock();

      delegate.HandleStopReply();
      if (should_stop)
        return eStateStopped;

      switch (cont_lock.lock()) {
      case ContinueLock::LockResult::Success:
        break;
      case ContinueLock::LockResult::Failed:
        return eStateInvalid;
      case ContinueLock::LockResult::Cancelled:
        return eStateStopped;
      }
      OnRunPacketSent(false);
      break;
    }
  }
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerCommon::Handle_qEcho(
    StringExtractorGDBRemote &packet) {
  // Just echo back the exact same packet for qEcho...
  return SendPacketNoLock(packet.GetStringRef());
}
//void *
//GDBRemoteCommunicationServer::AsyncThread (void *arg)
//{
//    GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer*) arg;
//
//    LogSP log;// (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
//    if (log)
//        log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread starting...", __FUNCTION__, arg, process->GetID());
//
//    StringExtractorGDBRemote packet;
//    
//    while ()
//    {
//        if (packet.
//    }
//
//    if (log)
//        log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread exiting...", __FUNCTION__, arg, process->GetID());
//
//    process->m_async_thread = LLDB_INVALID_HOST_THREAD;
//    return NULL;
//}
//
bool
GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, 
                                                        Error &error,
                                                        bool &interrupt, 
                                                        bool &quit)
{
    StringExtractorGDBRemote packet;
    if (WaitForPacketWithTimeoutMicroSeconds(packet, timeout_usec))
    {
        const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType ();
        switch (packet_type)
        {
            case StringExtractorGDBRemote::eServerPacketType_nack:
            case StringExtractorGDBRemote::eServerPacketType_ack:
                break;

            case StringExtractorGDBRemote::eServerPacketType_invalid:
                error.SetErrorString("invalid packet");
                quit = true;
                break;

            case StringExtractorGDBRemote::eServerPacketType_interrupt:
                error.SetErrorString("interrupt received");
                interrupt = true;
                break;
            
            case StringExtractorGDBRemote::eServerPacketType_unimplemented:
                return SendUnimplementedResponse (packet.GetStringRef().c_str()) > 0;

            case StringExtractorGDBRemote::eServerPacketType_A:
                return Handle_A (packet);

            case StringExtractorGDBRemote::eServerPacketType_qfProcessInfo:
                return Handle_qfProcessInfo (packet);
                
            case StringExtractorGDBRemote::eServerPacketType_qsProcessInfo:
                return Handle_qsProcessInfo (packet);
                
            case StringExtractorGDBRemote::eServerPacketType_qC:
                return Handle_qC (packet);
                
            case StringExtractorGDBRemote::eServerPacketType_qHostInfo:
                return Handle_qHostInfo (packet);
                
            case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer:
                return Handle_qLaunchGDBServer (packet);
                
            case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess:
                return Handle_qLaunchSuccess (packet);
                
            case StringExtractorGDBRemote::eServerPacketType_qGroupName:
                return Handle_qGroupName (packet);

            case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID:
                return Handle_qProcessInfoPID (packet);

            case StringExtractorGDBRemote::eServerPacketType_qSpeedTest:
                return Handle_qSpeedTest (packet);

            case StringExtractorGDBRemote::eServerPacketType_qUserName:
                return Handle_qUserName (packet);

            case StringExtractorGDBRemote::eServerPacketType_QEnvironment:
                return Handle_QEnvironment (packet);
            
            case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR:
                return Handle_QSetDisableASLR (packet);
            
            case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN:
                return Handle_QSetSTDIN (packet);
            
            case StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT:
                return Handle_QSetSTDOUT (packet);
            
            case StringExtractorGDBRemote::eServerPacketType_QSetSTDERR:
                return Handle_QSetSTDERR (packet);
            
            case StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir:
                return Handle_QSetWorkingDir (packet);

            case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode:
                return Handle_QStartNoAckMode (packet);
        }
        return true;
    }
    else
    {
        if (!IsConnected())
            error.SetErrorString("lost connection");
        else
            error.SetErrorString("timeout");
    }

    return false;
}