GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite( StringExtractorGDBRemote &packet) { #ifdef _WIN32 return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_" "vFile_pWrite() unimplemented"); #else packet.SetFilePos(::strlen("vFile:pwrite:")); StreamGDBRemote response; response.PutChar('F'); int fd = packet.GetU32(UINT32_MAX); if (packet.GetChar() == ',') { off_t offset = packet.GetU64(UINT32_MAX); if (packet.GetChar() == ',') { std::string buffer; if (packet.GetEscapedBinaryData(buffer)) { const ssize_t bytes_written = ::pwrite(fd, buffer.data(), buffer.size(), offset); const int save_errno = bytes_written == -1 ? errno : 0; response.Printf("%zi", bytes_written); if (save_errno) response.Printf(",%i", save_errno); } else { response.Printf("-1,%i", EINVAL); } return SendPacketNoLock(response.GetString()); } } return SendErrorResponse(27); #endif }
GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:open:")); std::string path; packet.GetHexByteStringTerminatedBy(path,','); if (!path.empty()) { if (packet.GetChar() == ',') { uint32_t flags = packet.GetHexMaxU32(false, 0); if (packet.GetChar() == ',') { mode_t mode = packet.GetHexMaxU32(false, 0600); Error error; int fd = ::open (path.c_str(), flags, mode); const int save_errno = fd == -1 ? errno : 0; StreamString response; response.PutChar('F'); response.Printf("%i", fd); if (save_errno) response.Printf(",%i", save_errno); return SendPacketNoLock(response.GetData(), response.GetSize()); } } } return SendErrorResponse(18); }
char GDBRemoteCommunication::GetAck () { StringExtractorGDBRemote packet; if (WaitForPacketWithTimeoutMicroSecondsNoLock (packet, GetPacketTimeoutInMicroSeconds ()) == 1) return packet.GetChar(); return 0; }
GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qModuleInfo( StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("qModuleInfo:")); std::string module_path; packet.GetHexByteStringTerminatedBy(module_path, ';'); if (module_path.empty()) return SendErrorResponse(1); if (packet.GetChar() != ';') return SendErrorResponse(2); std::string triple; packet.GetHexByteString(triple); ModuleSpec matched_module_spec = GetModuleInfo(module_path, triple); if (!matched_module_spec.GetFileSpec()) return SendErrorResponse(3); const auto file_offset = matched_module_spec.GetObjectOffset(); const auto file_size = matched_module_spec.GetObjectSize(); const auto uuid_str = matched_module_spec.GetUUID().GetAsString(""); StreamGDBRemote response; if (uuid_str.empty()) { std::string md5_hash; if (!FileSystem::CalculateMD5AsString(matched_module_spec.GetFileSpec(), file_offset, file_size, md5_hash)) return SendErrorResponse(5); response.PutCString("md5:"); response.PutCStringAsRawHex8(md5_hash.c_str()); } else { response.PutCString("uuid:"); response.PutCStringAsRawHex8(uuid_str.c_str()); } response.PutChar(';'); const auto &module_arch = matched_module_spec.GetArchitecture(); response.PutCString("triple:"); response.PutCStringAsRawHex8(module_arch.GetTriple().getTriple().c_str()); response.PutChar(';'); response.PutCString("file_path:"); response.PutCStringAsRawHex8(matched_module_spec.GetFileSpec().GetCString()); response.PutChar(';'); response.PutCString("file_offset:"); response.PutHex64(file_offset); response.PutChar(';'); response.PutCString("file_size:"); response.PutHex64(file_size); response.PutChar(';'); return SendPacketNoLock(response.GetString()); }
GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("qPlatform_shell:")); std::string path; std::string working_dir; packet.GetHexByteStringTerminatedBy(path,','); if (!path.empty()) { if (packet.GetChar() == ',') { // FIXME: add timeout to qPlatform_shell packet // uint32_t timeout = packet.GetHexMaxU32(false, 32); uint32_t timeout = 10; if (packet.GetChar() == ',') packet.GetHexByteString(working_dir); int status, signo; std::string output; Error err = Host::RunShellCommand(path.c_str(), working_dir.empty() ? NULL : working_dir.c_str(), &status, &signo, &output, timeout); StreamGDBRemote response; if (err.Fail()) { response.PutCString("F,"); response.PutHex32(UINT32_MAX); } else { response.PutCString("F,"); response.PutHex32(status); response.PutChar(','); response.PutHex32(signo); response.PutChar(','); response.PutEscapedBytes(output.c_str(), output.size()); } return SendPacketNoLock(response.GetData(), response.GetSize()); } } return SendErrorResponse(24); }
GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &packet) { #ifdef _WIN32 // Not implemented on Windows return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pRead() unimplemented"); #else StreamGDBRemote response; packet.SetFilePos(::strlen("vFile:pread:")); int fd = packet.GetS32(-1); if (packet.GetChar() == ',') { uint64_t count = packet.GetU64(UINT64_MAX); if (packet.GetChar() == ',') { uint64_t offset = packet.GetU64(UINT32_MAX); if (count == UINT64_MAX) { response.Printf("F-1:%i", EINVAL); return SendPacketNoLock(response.GetData(), response.GetSize()); } std::string buffer(count, 0); const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset); const int save_errno = bytes_read == -1 ? errno : 0; response.PutChar('F'); response.Printf("%zi", bytes_read); if (save_errno) response.Printf(",%i", save_errno); else { response.PutChar(';'); response.PutEscapedBytes(&buffer[0], bytes_read); } return SendPacketNoLock(response.GetData(), response.GetSize()); } } return SendErrorResponse(21); #endif }
GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:symlink:")); std::string dst, src; packet.GetHexByteStringTerminatedBy(dst, ','); packet.GetChar(); // Skip ',' char packet.GetHexByteString(src); Error error = Host::Symlink(src.c_str(), dst.c_str()); StreamString response; response.Printf("F%u,%u", error.GetError(), error.GetError()); return SendPacketNoLock(response.GetData(), response.GetSize()); }
GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_vFile_symlink( StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:symlink:")); std::string dst, src; packet.GetHexByteStringTerminatedBy(dst, ','); packet.GetChar(); // Skip ',' char packet.GetHexByteString(src); Error error = FileSystem::Symlink(FileSpec{src, true}, FileSpec{dst, false}); StreamString response; response.Printf("F%u,%u", error.GetError(), error.GetError()); return SendPacketNoLock(response.GetString()); }
GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("qPlatform_mkdir:")); mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); if (packet.GetChar() == ',') { std::string path; packet.GetHexByteString(path); Error error = Host::MakeDirectory(path.c_str(),mode); if (error.Success()) return SendPacketNoLock ("OK", 2); else return SendErrorResponse(error.GetError()); } return SendErrorResponse(20); }
GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir( StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("qPlatform_mkdir:")); mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); if (packet.GetChar() == ',') { std::string path; packet.GetHexByteString(path); Error error = FileSystem::MakeDirectory(FileSpec{path, false}, mode); StreamGDBRemote response; response.Printf("F%u", error.GetError()); return SendPacketNoLock(response.GetString()); } return SendErrorResponse(20); }
GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("qPlatform_chmod:")); mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); if (packet.GetChar() == ',') { std::string path; packet.GetHexByteString(path); Error error = FileSystem::SetFilePermissions(FileSpec{path, true}, mode); StreamGDBRemote response; response.Printf("F%u", error.GetError()); return SendPacketNoLock(response.GetData(), response.GetSize()); } return SendErrorResponse(19); }
GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) { // The 'A' packet is the most over designed packet ever here with // redundant argument indexes, redundant argument lengths and needed hex // encoded argument string values. Really all that is needed is a comma // separated hex encoded argument value list, but we will stay true to the // documented version of the 'A' packet here... packet.SetFilePos(1); // Skip the 'A' bool success = true; while (success && packet.GetBytesLeft() > 0) { // Decode the decimal argument string length. This length is the // number of hex nibbles in the argument string value. const uint32_t arg_len = packet.GetU32(UINT32_MAX); if (arg_len == UINT32_MAX) success = false; else { // Make sure the argument hex string length is followed by a comma if (packet.GetChar() != ',') success = false; else { // Decode the argument index. We ignore this really becuase // who would really send down the arguments in a random order??? const uint32_t arg_idx = packet.GetU32(UINT32_MAX); if (arg_idx == UINT32_MAX) success = false; else { // Make sure the argument index is followed by a comma if (packet.GetChar() != ',') success = false; else { // Decode the argument string value from hex bytes // back into a UTF8 string and make sure the length // matches the one supplied in the packet std::string arg; if (packet.GetHexByteString(arg) != (arg_len / 2)) success = false; else { // If there are any bytes lft if (packet.GetBytesLeft()) { if (packet.GetChar() != ',') success = false; } if (success) { if (arg_idx == 0) m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false); m_process_launch_info.GetArguments().AppendArgument(arg.c_str()); } } } } } } } if (success) { m_process_launch_info.GetFlags().Set (eLaunchFlagDebug); m_process_launch_error = Host::LaunchProcess (m_process_launch_info); if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { return SendOKResponse (); } } return SendErrorResponse (8); }
GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &packet) { m_proc_infos_index = 0; m_proc_infos.Clear(); ProcessInstanceInfoMatch match_info; packet.SetFilePos(::strlen ("qfProcessInfo")); if (packet.GetChar() == ':') { std::string key; std::string value; while (packet.GetNameColonValue(key, value)) { bool success = true; if (key.compare("name") == 0) { StringExtractor extractor; extractor.GetStringRef().swap(value); extractor.GetHexByteString (value); match_info.GetProcessInfo().GetExecutableFile().SetFile(value.c_str(), false); } else if (key.compare("name_match") == 0) { if (value.compare("equals") == 0) { match_info.SetNameMatchType (eNameMatchEquals); } else if (value.compare("starts_with") == 0) { match_info.SetNameMatchType (eNameMatchStartsWith); } else if (value.compare("ends_with") == 0) { match_info.SetNameMatchType (eNameMatchEndsWith); } else if (value.compare("contains") == 0) { match_info.SetNameMatchType (eNameMatchContains); } else if (value.compare("regex") == 0) { match_info.SetNameMatchType (eNameMatchRegularExpression); } else { success = false; } } else if (key.compare("pid") == 0) { match_info.GetProcessInfo().SetProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success)); } else if (key.compare("parent_pid") == 0) { match_info.GetProcessInfo().SetParentProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success)); } else if (key.compare("uid") == 0) { match_info.GetProcessInfo().SetUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success)); } else if (key.compare("gid") == 0) { match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success)); } else if (key.compare("euid") == 0) { match_info.GetProcessInfo().SetEffectiveUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success)); } else if (key.compare("egid") == 0) { match_info.GetProcessInfo().SetEffectiveGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success)); } else if (key.compare("all_users") == 0) { match_info.SetMatchAllUsers(Args::StringToBoolean(value.c_str(), false, &success)); } else if (key.compare("triple") == 0) { match_info.GetProcessInfo().GetArchitecture().SetTriple (value.c_str(), NULL); } else { success = false; } if (!success) return SendErrorResponse (2); } } if (Host::FindProcesses (match_info, m_proc_infos)) { // We found something, return the first item by calling the get // subsequent process info packet handler... return Handle_qsProcessInfo (packet); } return SendErrorResponse (3); }
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_A(StringExtractorGDBRemote &packet) { // The 'A' packet is the most over designed packet ever here with // redundant argument indexes, redundant argument lengths and needed hex // encoded argument string values. Really all that is needed is a comma // separated hex encoded argument value list, but we will stay true to the // documented version of the 'A' packet here... Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); int actual_arg_index = 0; packet.SetFilePos(1); // Skip the 'A' bool success = true; while (success && packet.GetBytesLeft() > 0) { // Decode the decimal argument string length. This length is the // number of hex nibbles in the argument string value. const uint32_t arg_len = packet.GetU32(UINT32_MAX); if (arg_len == UINT32_MAX) success = false; else { // Make sure the argument hex string length is followed by a comma if (packet.GetChar() != ',') success = false; else { // Decode the argument index. We ignore this really because // who would really send down the arguments in a random order??? const uint32_t arg_idx = packet.GetU32(UINT32_MAX); if (arg_idx == UINT32_MAX) success = false; else { // Make sure the argument index is followed by a comma if (packet.GetChar() != ',') success = false; else { // Decode the argument string value from hex bytes // back into a UTF8 string and make sure the length // matches the one supplied in the packet std::string arg; if (packet.GetHexByteStringFixedLength(arg, arg_len) != (arg_len / 2)) success = false; else { // If there are any bytes left if (packet.GetBytesLeft()) { if (packet.GetChar() != ',') success = false; } if (success) { if (arg_idx == 0) m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false); m_process_launch_info.GetArguments().AppendArgument(arg); if (log) log->Printf("LLGSPacketHandler::%s added arg %d: \"%s\"", __FUNCTION__, actual_arg_index, arg.c_str()); ++actual_arg_index; } } } } } } } if (success) { m_process_launch_error = LaunchProcess(); if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { return SendOKResponse(); } else { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); if (log) log->Printf("LLGSPacketHandler::%s failed to launch exe: %s", __FUNCTION__, m_process_launch_error.AsCString()); } } return SendErrorResponse(8); }
GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo( StringExtractorGDBRemote &packet) { m_proc_infos_index = 0; m_proc_infos.Clear(); ProcessInstanceInfoMatch match_info; packet.SetFilePos(::strlen("qfProcessInfo")); if (packet.GetChar() == ':') { llvm::StringRef key; llvm::StringRef value; while (packet.GetNameColonValue(key, value)) { bool success = true; if (key.equals("name")) { StringExtractor extractor(value); std::string file; extractor.GetHexByteString(file); match_info.GetProcessInfo().GetExecutableFile().SetFile(file.c_str(), false); } else if (key.equals("name_match")) { NameMatchType name_match = llvm::StringSwitch<NameMatchType>(value) .Case("equals", eNameMatchEquals) .Case("starts_with", eNameMatchStartsWith) .Case("ends_with", eNameMatchEndsWith) .Case("contains", eNameMatchContains) .Case("regex", eNameMatchRegularExpression) .Default(eNameMatchIgnore); match_info.SetNameMatchType(name_match); if (name_match == eNameMatchIgnore) return SendErrorResponse(2); } else if (key.equals("pid")) { lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; if (value.getAsInteger(0, pid)) return SendErrorResponse(2); match_info.GetProcessInfo().SetProcessID(pid); } else if (key.equals("parent_pid")) { lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; if (value.getAsInteger(0, pid)) return SendErrorResponse(2); match_info.GetProcessInfo().SetParentProcessID(pid); } else if (key.equals("uid")) { uint32_t uid = UINT32_MAX; if (value.getAsInteger(0, uid)) return SendErrorResponse(2); match_info.GetProcessInfo().SetUserID(uid); } else if (key.equals("gid")) { uint32_t gid = UINT32_MAX; if (value.getAsInteger(0, gid)) return SendErrorResponse(2); match_info.GetProcessInfo().SetGroupID(gid); } else if (key.equals("euid")) { uint32_t uid = UINT32_MAX; if (value.getAsInteger(0, uid)) return SendErrorResponse(2); match_info.GetProcessInfo().SetEffectiveUserID(uid); } else if (key.equals("egid")) { uint32_t gid = UINT32_MAX; if (value.getAsInteger(0, gid)) return SendErrorResponse(2); match_info.GetProcessInfo().SetEffectiveGroupID(gid); } else if (key.equals("all_users")) { match_info.SetMatchAllUsers( Args::StringToBoolean(value, false, &success)); } else if (key.equals("triple")) { match_info.GetProcessInfo().GetArchitecture().SetTriple( value.str().c_str(), NULL); } else { success = false; } if (!success) return SendErrorResponse(2); } } if (Host::FindProcesses(match_info, m_proc_infos)) { // We found something, return the first item by calling the get // subsequent process info packet handler... return Handle_qsProcessInfo(packet); } return SendErrorResponse(3); }