1//===-- GDBRemoteClientBase.cpp -------------------------------------------===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8 9#include "GDBRemoteClientBase.h" 10 11#include "llvm/ADT/StringExtras.h" 12 13#include "lldb/Target/UnixSignals.h" 14#include "lldb/Utility/LLDBAssert.h" 15 16#include "ProcessGDBRemoteLog.h" 17 18using namespace lldb; 19using namespace lldb_private; 20using namespace lldb_private::process_gdb_remote; 21using namespace std::chrono; 22 23// When we've sent a continue packet and are waiting for the target to stop, 24// we wake up the wait with this interval to make sure the stub hasn't gone 25// away while we were waiting. 26static const seconds kWakeupInterval(5); 27 28///////////////////////// 29// GDBRemoteClientBase // 30///////////////////////// 31 32GDBRemoteClientBase::ContinueDelegate::~ContinueDelegate() = default; 33 34GDBRemoteClientBase::GDBRemoteClientBase(const char *comm_name) 35 : GDBRemoteCommunication(), Broadcaster(nullptr, comm_name), 36 m_async_count(0), m_is_running(false), m_should_stop(false) {} 37 38StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse( 39 ContinueDelegate &delegate, const UnixSignals &signals, 40 llvm::StringRef payload, std::chrono::seconds interrupt_timeout, 41 StringExtractorGDBRemote &response) { 42 Log *log = GetLog(GDBRLog::Process); 43 response.Clear(); 44 45 { 46 std::lock_guard<std::mutex> lock(m_mutex); 47 m_continue_packet = std::string(payload); 48 m_should_stop = false; 49 } 50 ContinueLock cont_lock(*this); 51 if (!cont_lock) 52 return eStateInvalid; 53 OnRunPacketSent(true); 54 // The main ReadPacket loop wakes up at computed_timeout intervals, just to 55 // check that the connection hasn't dropped. When we wake up we also check 56 // whether there is an interrupt request that has reached its endpoint. 57 // If we want a shorter interrupt timeout that kWakeupInterval, we need to 58 // choose the shorter interval for the wake up as well. 59 std::chrono::seconds computed_timeout = std::min(interrupt_timeout, 60 kWakeupInterval); 61 for (;;) { 62 PacketResult read_result = ReadPacket(response, computed_timeout, false); 63 // Reset the computed_timeout to the default value in case we are going 64 // round again. 65 computed_timeout = std::min(interrupt_timeout, kWakeupInterval); 66 switch (read_result) { 67 case PacketResult::ErrorReplyTimeout: { 68 std::lock_guard<std::mutex> lock(m_mutex); 69 if (m_async_count == 0) { 70 continue; 71 } 72 auto cur_time = steady_clock::now(); 73 if (cur_time >= m_interrupt_endpoint) 74 return eStateInvalid; 75 else { 76 // We woke up and found an interrupt is in flight, but we haven't 77 // exceeded the interrupt wait time. So reset the wait time to the 78 // time left till the interrupt timeout. But don't wait longer 79 // than our wakeup timeout. 80 auto new_wait = m_interrupt_endpoint - cur_time; 81 computed_timeout = std::min(kWakeupInterval, 82 std::chrono::duration_cast<std::chrono::seconds>(new_wait)); 83 continue; 84 } 85 break; 86 } 87 case PacketResult::Success: 88 break; 89 default: 90 LLDB_LOGF(log, "GDBRemoteClientBase::%s () ReadPacket(...) => false", 91 __FUNCTION__); 92 return eStateInvalid; 93 } 94 if (response.Empty()) 95 return eStateInvalid; 96 97 const char stop_type = response.GetChar(); 98 LLDB_LOGF(log, "GDBRemoteClientBase::%s () got packet: %s", __FUNCTION__, 99 response.GetStringRef().data()); 100 101 switch (stop_type) { 102 case 'W': 103 case 'X': 104 return eStateExited; 105 case 'E': 106 // ERROR 107 return eStateInvalid; 108 default: 109 LLDB_LOGF(log, "GDBRemoteClientBase::%s () unrecognized async packet", 110 __FUNCTION__); 111 return eStateInvalid; 112 case 'O': { 113 std::string inferior_stdout; 114 response.GetHexByteString(inferior_stdout); 115 delegate.HandleAsyncStdout(inferior_stdout); 116 break; 117 } 118 case 'A': 119 delegate.HandleAsyncMisc( 120 llvm::StringRef(response.GetStringRef()).substr(1)); 121 break; 122 case 'J': 123 delegate.HandleAsyncStructuredDataPacket(response.GetStringRef()); 124 break; 125 case 'T': 126 case 'S': 127 // Do this with the continue lock held. 128 const bool should_stop = ShouldStop(signals, response); 129 response.SetFilePos(0); 130 131 // The packet we should resume with. In the future we should check our 132 // thread list and "do the right thing" for new threads that show up 133 // while we stop and run async packets. Setting the packet to 'c' to 134 // continue all threads is the right thing to do 99.99% of the time 135 // because if a thread was single stepping, and we sent an interrupt, we 136 // will notice above that we didn't stop due to an interrupt but stopped 137 // due to stepping and we would _not_ continue. This packet may get 138 // modified by the async actions (e.g. to send a signal). 139 m_continue_packet = 'c'; 140 cont_lock.unlock(); 141 142 delegate.HandleStopReply(); 143 if (should_stop) 144 return eStateStopped; 145 146 switch (cont_lock.lock()) { 147 case ContinueLock::LockResult::Success: 148 break; 149 case ContinueLock::LockResult::Failed: 150 return eStateInvalid; 151 case ContinueLock::LockResult::Cancelled: 152 return eStateStopped; 153 } 154 OnRunPacketSent(false); 155 break; 156 } 157 } 158} 159 160bool GDBRemoteClientBase::SendAsyncSignal( 161 int signo, std::chrono::seconds interrupt_timeout) { 162 Lock lock(*this, interrupt_timeout); 163 if (!lock || !lock.DidInterrupt()) 164 return false; 165 166 m_continue_packet = 'C'; 167 m_continue_packet += llvm::hexdigit((signo / 16) % 16); 168 m_continue_packet += llvm::hexdigit(signo % 16); 169 return true; 170} 171 172bool GDBRemoteClientBase::Interrupt(std::chrono::seconds interrupt_timeout) { 173 Lock lock(*this, interrupt_timeout); 174 if (!lock.DidInterrupt()) 175 return false; 176 m_should_stop = true; 177 return true; 178} 179 180GDBRemoteCommunication::PacketResult 181GDBRemoteClientBase::SendPacketAndWaitForResponse( 182 llvm::StringRef payload, StringExtractorGDBRemote &response, 183 std::chrono::seconds interrupt_timeout) { 184 Lock lock(*this, interrupt_timeout); 185 if (!lock) { 186 if (Log *log = GetLog(GDBRLog::Process)) 187 LLDB_LOGF(log, 188 "GDBRemoteClientBase::%s failed to get mutex, not sending " 189 "packet '%.*s'", 190 __FUNCTION__, int(payload.size()), payload.data()); 191 return PacketResult::ErrorSendFailed; 192 } 193 194 return SendPacketAndWaitForResponseNoLock(payload, response); 195} 196 197GDBRemoteCommunication::PacketResult 198GDBRemoteClientBase::ReadPacketWithOutputSupport( 199 StringExtractorGDBRemote &response, Timeout<std::micro> timeout, 200 bool sync_on_timeout, 201 llvm::function_ref<void(llvm::StringRef)> output_callback) { 202 auto result = ReadPacket(response, timeout, sync_on_timeout); 203 while (result == PacketResult::Success && response.IsNormalResponse() && 204 response.PeekChar() == 'O') { 205 response.GetChar(); 206 std::string output; 207 if (response.GetHexByteString(output)) 208 output_callback(output); 209 result = ReadPacket(response, timeout, sync_on_timeout); 210 } 211 return result; 212} 213 214GDBRemoteCommunication::PacketResult 215GDBRemoteClientBase::SendPacketAndReceiveResponseWithOutputSupport( 216 llvm::StringRef payload, StringExtractorGDBRemote &response, 217 std::chrono::seconds interrupt_timeout, 218 llvm::function_ref<void(llvm::StringRef)> output_callback) { 219 Lock lock(*this, interrupt_timeout); 220 if (!lock) { 221 if (Log *log = GetLog(GDBRLog::Process)) 222 LLDB_LOGF(log, 223 "GDBRemoteClientBase::%s failed to get mutex, not sending " 224 "packet '%.*s'", 225 __FUNCTION__, int(payload.size()), payload.data()); 226 return PacketResult::ErrorSendFailed; 227 } 228 229 PacketResult packet_result = SendPacketNoLock(payload); 230 if (packet_result != PacketResult::Success) 231 return packet_result; 232 233 return ReadPacketWithOutputSupport(response, GetPacketTimeout(), true, 234 output_callback); 235} 236 237GDBRemoteCommunication::PacketResult 238GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock( 239 llvm::StringRef payload, StringExtractorGDBRemote &response) { 240 PacketResult packet_result = SendPacketNoLock(payload); 241 if (packet_result != PacketResult::Success) 242 return packet_result; 243 244 const size_t max_response_retries = 3; 245 for (size_t i = 0; i < max_response_retries; ++i) { 246 packet_result = ReadPacket(response, GetPacketTimeout(), true); 247 // Make sure we received a response 248 if (packet_result != PacketResult::Success) 249 return packet_result; 250 // Make sure our response is valid for the payload that was sent 251 if (response.ValidateResponse()) 252 return packet_result; 253 // Response says it wasn't valid 254 Log *log = GetLog(GDBRLog::Packets); 255 LLDB_LOGF( 256 log, 257 "error: packet with payload \"%.*s\" got invalid response \"%s\": %s", 258 int(payload.size()), payload.data(), response.GetStringRef().data(), 259 (i == (max_response_retries - 1)) 260 ? "using invalid response and giving up" 261 : "ignoring response and waiting for another"); 262 } 263 return packet_result; 264} 265 266bool GDBRemoteClientBase::ShouldStop(const UnixSignals &signals, 267 StringExtractorGDBRemote &response) { 268 std::lock_guard<std::mutex> lock(m_mutex); 269 270 if (m_async_count == 0) 271 return true; // We were not interrupted. The process stopped on its own. 272 273 // Older debugserver stubs (before April 2016) can return two stop-reply 274 // packets in response to a ^C packet. Additionally, all debugservers still 275 // return two stop replies if the inferior stops due to some other reason 276 // before the remote stub manages to interrupt it. We need to wait for this 277 // additional packet to make sure the packet sequence does not get skewed. 278 StringExtractorGDBRemote extra_stop_reply_packet; 279 ReadPacket(extra_stop_reply_packet, milliseconds(100), false); 280 281 // Interrupting is typically done using SIGSTOP or SIGINT, so if the process 282 // stops with some other signal, we definitely want to stop. 283 const uint8_t signo = response.GetHexU8(UINT8_MAX); 284 if (signo != signals.GetSignalNumberFromName("SIGSTOP") && 285 signo != signals.GetSignalNumberFromName("SIGINT")) 286 return true; 287 288 // We probably only stopped to perform some async processing, so continue 289 // after that is done. 290 // TODO: This is not 100% correct, as the process may have been stopped with 291 // SIGINT or SIGSTOP that was not caused by us (e.g. raise(SIGINT)). This will 292 // normally cause a stop, but if it's done concurrently with a async 293 // interrupt, that stop will get eaten (llvm.org/pr20231). 294 return false; 295} 296 297void GDBRemoteClientBase::OnRunPacketSent(bool first) { 298 if (first) 299 BroadcastEvent(eBroadcastBitRunPacketSent, nullptr); 300} 301 302/////////////////////////////////////// 303// GDBRemoteClientBase::ContinueLock // 304/////////////////////////////////////// 305 306GDBRemoteClientBase::ContinueLock::ContinueLock(GDBRemoteClientBase &comm) 307 : m_comm(comm), m_acquired(false) { 308 lock(); 309} 310 311GDBRemoteClientBase::ContinueLock::~ContinueLock() { 312 if (m_acquired) 313 unlock(); 314} 315 316void GDBRemoteClientBase::ContinueLock::unlock() { 317 lldbassert(m_acquired); 318 { 319 std::unique_lock<std::mutex> lock(m_comm.m_mutex); 320 m_comm.m_is_running = false; 321 } 322 m_comm.m_cv.notify_all(); 323 m_acquired = false; 324} 325 326GDBRemoteClientBase::ContinueLock::LockResult 327GDBRemoteClientBase::ContinueLock::lock() { 328 Log *log = GetLog(GDBRLog::Process); 329 LLDB_LOGF(log, "GDBRemoteClientBase::ContinueLock::%s() resuming with %s", 330 __FUNCTION__, m_comm.m_continue_packet.c_str()); 331 332 lldbassert(!m_acquired); 333 std::unique_lock<std::mutex> lock(m_comm.m_mutex); 334 m_comm.m_cv.wait(lock, [this] { return m_comm.m_async_count == 0; }); 335 if (m_comm.m_should_stop) { 336 m_comm.m_should_stop = false; 337 LLDB_LOGF(log, "GDBRemoteClientBase::ContinueLock::%s() cancelled", 338 __FUNCTION__); 339 return LockResult::Cancelled; 340 } 341 if (m_comm.SendPacketNoLock(m_comm.m_continue_packet) != 342 PacketResult::Success) 343 return LockResult::Failed; 344 345 lldbassert(!m_comm.m_is_running); 346 m_comm.m_is_running = true; 347 m_acquired = true; 348 return LockResult::Success; 349} 350 351/////////////////////////////// 352// GDBRemoteClientBase::Lock // 353/////////////////////////////// 354 355GDBRemoteClientBase::Lock::Lock(GDBRemoteClientBase &comm, 356 std::chrono::seconds interrupt_timeout) 357 : m_async_lock(comm.m_async_mutex, std::defer_lock), m_comm(comm), 358 m_interrupt_timeout(interrupt_timeout), m_acquired(false), 359 m_did_interrupt(false) { 360 SyncWithContinueThread(); 361 if (m_acquired) 362 m_async_lock.lock(); 363} 364 365void GDBRemoteClientBase::Lock::SyncWithContinueThread() { 366 Log *log = GetLog(GDBRLog::Process|GDBRLog::Packets); 367 std::unique_lock<std::mutex> lock(m_comm.m_mutex); 368 if (m_comm.m_is_running && m_interrupt_timeout == std::chrono::seconds(0)) 369 return; // We were asked to avoid interrupting the sender. Lock is not 370 // acquired. 371 372 ++m_comm.m_async_count; 373 if (m_comm.m_is_running) { 374 if (m_comm.m_async_count == 1) { 375 // The sender has sent the continue packet and we are the first async 376 // packet. Let's interrupt it. 377 const char ctrl_c = '\x03'; 378 ConnectionStatus status = eConnectionStatusSuccess; 379 size_t bytes_written = m_comm.Write(&ctrl_c, 1, status, nullptr); 380 if (bytes_written == 0) { 381 --m_comm.m_async_count; 382 LLDB_LOGF(log, "GDBRemoteClientBase::Lock::Lock failed to send " 383 "interrupt packet"); 384 return; 385 } 386 m_comm.m_interrupt_endpoint = steady_clock::now() + m_interrupt_timeout; 387 if (log) 388 log->PutCString("GDBRemoteClientBase::Lock::Lock sent packet: \\x03"); 389 } 390 m_comm.m_cv.wait(lock, [this] { return !m_comm.m_is_running; }); 391 m_did_interrupt = true; 392 } 393 m_acquired = true; 394} 395 396GDBRemoteClientBase::Lock::~Lock() { 397 if (!m_acquired) 398 return; 399 { 400 std::unique_lock<std::mutex> lock(m_comm.m_mutex); 401 --m_comm.m_async_count; 402 } 403 m_comm.m_cv.notify_one(); 404} 405