Error ProcessKDP::DoDetach(bool keep_stopped) { Error error; Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); if (log) log->Printf ("ProcessKDP::DoDetach(keep_stopped = %i)", keep_stopped); if (m_comm.IsRunning()) { // We are running and we can't interrupt a running kernel, so we need // to just close the connection to the kernel and hope for the best } else { DisableAllBreakpointSites (); m_thread_list.DiscardThreadPlans(); // If we are going to keep the target stopped, then don't send the disconnect message. if (!keep_stopped && m_comm.IsConnected()) { const bool success = m_comm.SendRequestDisconnect(); if (log) { if (success) log->PutCString ("ProcessKDP::DoDetach() detach packet sent successfully"); else log->PutCString ("ProcessKDP::DoDetach() connection channel shutdown failed"); } m_comm.Disconnect (); } } StopAsyncThread (); m_comm.Clear(); SetPrivateState (eStateDetached); ResumePrivateStateThread(); //KillDebugserverProcess (); return error; }
Error SoftwareBreakpoint::EnableSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t bp_opcode_size, const uint8_t *bp_opcode_bytes, uint8_t *saved_opcode_bytes) { assert (bp_opcode_size <= MAX_TRAP_OPCODE_SIZE && "bp_opcode_size out of valid range"); assert (bp_opcode_bytes && "bp_opcode_bytes is NULL"); assert (saved_opcode_bytes && "saved_opcode_bytes is NULL"); Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); if (log) log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr); // Save the original opcodes by reading them so we can restore later. size_t bytes_read = 0; Error error = process.ReadMemory(addr, saved_opcode_bytes, bp_opcode_size, bytes_read); if (error.Fail ()) { if (log) log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ()); return error; } // Ensure we read as many bytes as we expected. if (bytes_read != bp_opcode_size) { if (log) log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)bytes_read); return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)bytes_read); } // Log what we read. if (log) { int i = 0; for (const uint8_t *read_byte = saved_opcode_bytes; read_byte < saved_opcode_bytes + bp_opcode_size; ++read_byte) { log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " ovewriting byte index %d (was 0x%hhx)", __FUNCTION__, addr, i++, *read_byte); } } // Write a software breakpoint in place of the original opcode. size_t bytes_written = 0; error = process.WriteMemory(addr, bp_opcode_bytes, bp_opcode_size, bytes_written); if (error.Fail ()) { if (log) log->Printf ("SoftwareBreakpoint::%s failed to write memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ()); return error; } // Ensure we wrote as many bytes as we expected. if (bytes_written != bp_opcode_size) { error.SetErrorStringWithFormat("SoftwareBreakpoint::%s failed write memory while attempting to set breakpoint: attempted to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)bytes_written); if (log) log->PutCString (error.AsCString ()); return error; } uint8_t verify_bp_opcode_bytes [MAX_TRAP_OPCODE_SIZE]; size_t verify_bytes_read = 0; error = process.ReadMemory(addr, verify_bp_opcode_bytes, bp_opcode_size, verify_bytes_read); if (error.Fail ()) { if (log) log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify the breakpoint set: %s", __FUNCTION__, error.AsCString ()); return error; } // Ensure we read as many verification bytes as we expected. if (verify_bytes_read != bp_opcode_size) { if (log) log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)verify_bytes_read); return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)verify_bytes_read); } if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes, bp_opcode_size) != 0) { if (log) log->Printf ("SoftwareBreakpoint::%s: verification of software breakpoint writing failed - trap opcodes not successfully read back after writing when setting breakpoint at 0x%" PRIx64, __FUNCTION__, addr); return Error ("SoftwareBreakpoint::%s: verification of software breakpoint writing failed - trap opcodes not successfully read back after writing when setting breakpoint at 0x%" PRIx64, __FUNCTION__, addr); } if (log) log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, addr); return Error (); }
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); const size_t content_end = content_start + content_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); bool binary = false; // Only detect binary for packets that start with a '$' and have a '#CC' checksum if (m_bytes[0] == '$' && total_length > 4) { for (size_t i=0; !binary && i<total_length; ++i) { if (isprint(m_bytes[i]) == 0) binary = true; } } if (binary) { StreamString strm; // Packet header... strm.Printf("<%4" PRIu64 "> read packet: %c", (uint64_t)total_length, m_bytes[0]); for (size_t i=content_start; i<content_end; ++i) { // Remove binary escaped bytes when displaying the packet... const char ch = m_bytes[i]; if (ch == 0x7d) { // 0x7d is the escape character. The next character is to // be XOR'd with 0x20. const char escapee = m_bytes[++i] ^ 0x20; strm.Printf("%2.2x", escapee); } else { strm.Printf("%2.2x", (uint8_t)ch); } } // Packet footer... strm.Printf("%c%c%c", m_bytes[total_length-3], m_bytes[total_length-2], m_bytes[total_length-1]); log->PutCString(strm.GetString().c_str()); } else { 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_end; ++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 if (*c == 0x7d) { // 0x7d is the escape character. The next character is to // be XOR'd with 0x20. char escapee = *++c ^ 0x20; packet_str.push_back(escapee); } 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; }
GDBRemoteCommunication::PacketResult GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_length) { if (IsConnected()) { StreamString packet(0, 4, eByteOrderBig); packet.PutChar('$'); packet.Write (payload, payload_length); packet.PutChar('#'); packet.PutHex8(CalculcateChecksum (payload, payload_length)); Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); ConnectionStatus status = eConnectionStatusSuccess; const char *packet_data = packet.GetData(); const size_t packet_length = packet.GetSize(); size_t bytes_written = Write (packet_data, packet_length, status, NULL); if (log) { size_t binary_start_offset = 0; if (strncmp(packet_data, "$vFile:pwrite:", strlen("$vFile:pwrite:")) == 0) { const char *first_comma = strchr(packet_data, ','); if (first_comma) { const char *second_comma = strchr(first_comma + 1, ','); if (second_comma) binary_start_offset = second_comma - packet_data + 1; } } // 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); if (binary_start_offset) { StreamString strm; // Print non binary data header strm.Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)binary_start_offset, packet_data); const uint8_t *p; // Print binary data exactly as sent for (p = (uint8_t*)packet_data + binary_start_offset; *p != '#'; ++p) strm.Printf("\\x%2.2x", *p); // Print the checksum strm.Printf("%*s", (int)3, p); log->PutCString(strm.GetString().c_str()); } else log->Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)packet_length, packet_data); } m_history.AddPacket (packet.GetString(), packet_length, History::ePacketTypeSend, bytes_written); if (bytes_written == packet_length) { if (GetSendAcks ()) return GetAck (); else return PacketResult::Success; } else { if (log) log->Printf ("error: failed to send packet: %.*s", (int)packet_length, packet_data); } } return PacketResult::ErrorSendFailed; }