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; }