180814287SRaphael Isemann //===-- CommunicationKDP.cpp ----------------------------------------------===//
2f9765acdSGreg Clayton //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f9765acdSGreg Clayton //
7f9765acdSGreg Clayton //===----------------------------------------------------------------------===//
8f9765acdSGreg Clayton 
9f9765acdSGreg Clayton #include "CommunicationKDP.h"
10f9765acdSGreg Clayton 
1176e47d48SRaphael Isemann #include <cerrno>
1276e47d48SRaphael Isemann #include <climits>
1376e47d48SRaphael Isemann #include <cstring>
14a63d08c9SGreg Clayton 
159739a552SZachary Turner #include "lldb/Core/DumpDataExtractor.h"
16f9765acdSGreg Clayton #include "lldb/Host/Host.h"
17f9765acdSGreg Clayton #include "lldb/Target/Process.h"
18666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h"
19666cc0b2SZachary Turner #include "lldb/Utility/DataExtractor.h"
205713a05bSZachary Turner #include "lldb/Utility/FileSpec.h"
216f9e6901SZachary Turner #include "lldb/Utility/Log.h"
22d821c997SPavel Labath #include "lldb/Utility/State.h"
23666cc0b2SZachary Turner #include "lldb/Utility/UUID.h"
24f9765acdSGreg Clayton 
25f9765acdSGreg Clayton #include "ProcessKDPLog.h"
26f9765acdSGreg Clayton 
27f9765acdSGreg Clayton using namespace lldb;
28f9765acdSGreg Clayton using namespace lldb_private;
29f9765acdSGreg Clayton 
30f9765acdSGreg Clayton // CommunicationKDP constructor
CommunicationKDP(const char * comm_name)31bb19a13cSSaleem Abdulrasool CommunicationKDP::CommunicationKDP(const char *comm_name)
32b9c1b51eSKate Stone     : Communication(comm_name), m_addr_byte_size(4),
33b9c1b51eSKate Stone       m_byte_order(eByteOrderLittle), m_packet_timeout(5), m_sequence_mutex(),
34b9c1b51eSKate Stone       m_is_running(false), m_session_key(0u), m_request_sequence_id(0u),
35b9c1b51eSKate Stone       m_exception_sequence_id(0u), m_kdp_version_version(0u),
36b9c1b51eSKate Stone       m_kdp_version_feature(0u), m_kdp_hostinfo_cpu_mask(0u),
37b9c1b51eSKate Stone       m_kdp_hostinfo_cpu_type(0u), m_kdp_hostinfo_cpu_subtype(0u) {}
38f9765acdSGreg Clayton 
39f9765acdSGreg Clayton // Destructor
~CommunicationKDP()40b9c1b51eSKate Stone CommunicationKDP::~CommunicationKDP() {
41b9c1b51eSKate Stone   if (IsConnected()) {
42f9765acdSGreg Clayton     Disconnect();
43f9765acdSGreg Clayton   }
44f9765acdSGreg Clayton }
45f9765acdSGreg Clayton 
SendRequestPacket(const PacketStreamType & request_packet)46b9c1b51eSKate Stone bool CommunicationKDP::SendRequestPacket(
47b9c1b51eSKate Stone     const PacketStreamType &request_packet) {
48bb19a13cSSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_sequence_mutex);
4957508026SGreg Clayton   return SendRequestPacketNoLock(request_packet);
50f9765acdSGreg Clayton }
51f9765acdSGreg Clayton 
MakeRequestPacketHeader(CommandType request_type,PacketStreamType & request_packet,uint16_t request_length)52b9c1b51eSKate Stone void CommunicationKDP::MakeRequestPacketHeader(CommandType request_type,
534df8ddfcSGreg Clayton                                                PacketStreamType &request_packet,
54b9c1b51eSKate Stone                                                uint16_t request_length) {
5557508026SGreg Clayton   request_packet.Clear();
56b9c1b51eSKate Stone   request_packet.PutHex8(request_type |
57b9c1b51eSKate Stone                          ePacketTypeRequest);      // Set the request type
584df8ddfcSGreg Clayton   request_packet.PutHex8(m_request_sequence_id++); // Sequence number
59b9c1b51eSKate Stone   request_packet.PutHex16(
60b9c1b51eSKate Stone       request_length); // Length of the packet including this header
6157508026SGreg Clayton   request_packet.PutHex32(m_session_key); // Session key
62f9765acdSGreg Clayton }
63f9765acdSGreg Clayton 
SendRequestAndGetReply(const CommandType command,const PacketStreamType & request_packet,DataExtractor & reply_packet)64b9c1b51eSKate Stone bool CommunicationKDP::SendRequestAndGetReply(
65b9c1b51eSKate Stone     const CommandType command, const PacketStreamType &request_packet,
66b9c1b51eSKate Stone     DataExtractor &reply_packet) {
67b9c1b51eSKate Stone   if (IsRunning()) {
68*c8fbf803SPavel Labath     Log *log = GetLog(KDPLog::Packets);
69b9c1b51eSKate Stone     if (log) {
7097d5cf05SGreg Clayton       PacketStreamType log_strm;
7197d5cf05SGreg Clayton       DumpPacket(log_strm, request_packet.GetData(), request_packet.GetSize());
7263e5fb76SJonas Devlieghere       LLDB_LOGF(log, "error: kdp running, not sending packet: %.*s",
73b9c1b51eSKate Stone                 (uint32_t)log_strm.GetSize(), log_strm.GetData());
7497d5cf05SGreg Clayton     }
7597d5cf05SGreg Clayton     return false;
7697d5cf05SGreg Clayton   }
774df8ddfcSGreg Clayton 
78bb19a13cSSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_sequence_mutex);
7997d5cf05SGreg Clayton   // NOTE: this only works for packets that are in native endian byte order
80b9c1b51eSKate Stone   assert(request_packet.GetSize() ==
81a01e024aSAdrian Prantl          *((const uint16_t *)(request_packet.GetData() + 2)));
820ee809b7SGreg Clayton   lldb::offset_t offset = 1;
830ee809b7SGreg Clayton   const uint32_t num_retries = 3;
84b9c1b51eSKate Stone   for (uint32_t i = 0; i < num_retries; ++i) {
85b9c1b51eSKate Stone     if (SendRequestPacketNoLock(request_packet)) {
860ee809b7SGreg Clayton       const uint8_t request_sequence_id = (uint8_t)request_packet.GetData()[1];
8709ad8c8fSJonas Devlieghere       while (true) {
88b9c1b51eSKate Stone         if (WaitForPacketWithTimeoutMicroSecondsNoLock(
895cddd608SPavel Labath                 reply_packet,
905cddd608SPavel Labath                 std::chrono::microseconds(GetPacketTimeout()).count())) {
910ee809b7SGreg Clayton           offset = 0;
92a063c810SGreg Clayton           const uint8_t reply_command = reply_packet.GetU8(&offset);
934df8ddfcSGreg Clayton           const uint8_t reply_sequence_id = reply_packet.GetU8(&offset);
94b9c1b51eSKate Stone           if (request_sequence_id == reply_sequence_id) {
95b9c1b51eSKate Stone             // The sequent ID was correct, now verify we got the response we
96b9c1b51eSKate Stone             // were looking for
97b9c1b51eSKate Stone             if ((reply_command & eCommandTypeMask) == command) {
987ad05d13SGreg Clayton               // Success
9997d5cf05SGreg Clayton               if (command == KDP_RESUMECPUS)
10097d5cf05SGreg Clayton                 m_is_running.SetValue(true, eBroadcastAlways);
1014df8ddfcSGreg Clayton               return true;
102b9c1b51eSKate Stone             } else {
1037ad05d13SGreg Clayton               // Failed to get the correct response, bail
1047ad05d13SGreg Clayton               reply_packet.Clear();
1057ad05d13SGreg Clayton               return false;
1067ad05d13SGreg Clayton             }
107b9c1b51eSKate Stone           } else if (reply_sequence_id > request_sequence_id) {
108b9c1b51eSKate Stone             // Sequence ID was greater than the sequence ID of the packet we
10905097246SAdrian Prantl             // sent, something is really wrong...
1107ad05d13SGreg Clayton             reply_packet.Clear();
1117ad05d13SGreg Clayton             return false;
112b9c1b51eSKate Stone           } else {
11305097246SAdrian Prantl             // The reply sequence ID was less than our current packet's
11405097246SAdrian Prantl             // sequence ID so we should keep trying to get a response because
11505097246SAdrian Prantl             // this was a response for a previous packet that we must have
11605097246SAdrian Prantl             // retried.
1177ad05d13SGreg Clayton           }
118b9c1b51eSKate Stone         } else {
119b9c1b51eSKate Stone           // Break and retry sending the packet as we didn't get a response due
120b9c1b51eSKate Stone           // to timeout
1217ad05d13SGreg Clayton           break;
1224df8ddfcSGreg Clayton         }
1234df8ddfcSGreg Clayton       }
12497d5cf05SGreg Clayton     }
1250ee809b7SGreg Clayton   }
1264df8ddfcSGreg Clayton   reply_packet.Clear();
1274df8ddfcSGreg Clayton   return false;
1284df8ddfcSGreg Clayton }
129f9765acdSGreg Clayton 
SendRequestPacketNoLock(const PacketStreamType & request_packet)130b9c1b51eSKate Stone bool CommunicationKDP::SendRequestPacketNoLock(
131b9c1b51eSKate Stone     const PacketStreamType &request_packet) {
132b9c1b51eSKate Stone   if (IsConnected()) {
13357508026SGreg Clayton     const char *packet_data = request_packet.GetData();
13457508026SGreg Clayton     const size_t packet_size = request_packet.GetSize();
135f9765acdSGreg Clayton 
136*c8fbf803SPavel Labath     Log *log = GetLog(KDPLog::Packets);
137b9c1b51eSKate Stone     if (log) {
1384df8ddfcSGreg Clayton       PacketStreamType log_strm;
139a63d08c9SGreg Clayton       DumpPacket(log_strm, packet_data, packet_size);
14063e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%.*s", (uint32_t)log_strm.GetSize(), log_strm.GetData());
14157508026SGreg Clayton     }
142f9765acdSGreg Clayton     ConnectionStatus status = eConnectionStatusSuccess;
143f9765acdSGreg Clayton 
144b9c1b51eSKate Stone     size_t bytes_written = Write(packet_data, packet_size, status, NULL);
14557508026SGreg Clayton 
14657508026SGreg Clayton     if (bytes_written == packet_size)
14757508026SGreg Clayton       return true;
14857508026SGreg Clayton 
14963e5fb76SJonas Devlieghere     LLDB_LOGF(log,
15063e5fb76SJonas Devlieghere               "error: failed to send packet entire packet %" PRIu64
151b9c1b51eSKate Stone               " of %" PRIu64 " bytes sent",
152b9c1b51eSKate Stone               (uint64_t)bytes_written, (uint64_t)packet_size);
15357508026SGreg Clayton   }
15457508026SGreg Clayton   return false;
155f9765acdSGreg Clayton }
156f9765acdSGreg Clayton 
GetSequenceMutex(std::unique_lock<std::recursive_mutex> & lock)157b9c1b51eSKate Stone bool CommunicationKDP::GetSequenceMutex(
158b9c1b51eSKate Stone     std::unique_lock<std::recursive_mutex> &lock) {
159b9c1b51eSKate Stone   return (lock = std::unique_lock<std::recursive_mutex>(m_sequence_mutex,
160b9c1b51eSKate Stone                                                         std::try_to_lock))
161b9c1b51eSKate Stone       .owns_lock();
162f9765acdSGreg Clayton }
163f9765acdSGreg Clayton 
WaitForNotRunningPrivate(const std::chrono::microseconds & timeout)164b9c1b51eSKate Stone bool CommunicationKDP::WaitForNotRunningPrivate(
165b9c1b51eSKate Stone     const std::chrono::microseconds &timeout) {
16638d67db3SPavel Labath   return m_is_running.WaitForValueEqualTo(false, timeout);
167f9765acdSGreg Clayton }
168f9765acdSGreg Clayton 
169f9765acdSGreg Clayton size_t
WaitForPacketWithTimeoutMicroSeconds(DataExtractor & packet,uint32_t timeout_usec)170b9c1b51eSKate Stone CommunicationKDP::WaitForPacketWithTimeoutMicroSeconds(DataExtractor &packet,
171b9c1b51eSKate Stone                                                        uint32_t timeout_usec) {
172bb19a13cSSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_sequence_mutex);
173f9765acdSGreg Clayton   return WaitForPacketWithTimeoutMicroSecondsNoLock(packet, timeout_usec);
174f9765acdSGreg Clayton }
175f9765acdSGreg Clayton 
WaitForPacketWithTimeoutMicroSecondsNoLock(DataExtractor & packet,uint32_t timeout_usec)176b9c1b51eSKate Stone size_t CommunicationKDP::WaitForPacketWithTimeoutMicroSecondsNoLock(
177b9c1b51eSKate Stone     DataExtractor &packet, uint32_t timeout_usec) {
178f9765acdSGreg Clayton   uint8_t buffer[8192];
17997206d57SZachary Turner   Status error;
180f9765acdSGreg Clayton 
181*c8fbf803SPavel Labath   Log *log = GetLog(KDPLog::Packets);
182f9765acdSGreg Clayton 
183f9765acdSGreg Clayton   // Check for a packet from our cache first without trying any reading...
184f9765acdSGreg Clayton   if (CheckForPacket(NULL, 0, packet))
1854df8ddfcSGreg Clayton     return packet.GetByteSize();
186f9765acdSGreg Clayton 
187f9765acdSGreg Clayton   bool timed_out = false;
188b9c1b51eSKate Stone   while (IsConnected() && !timed_out) {
189becabe0eSJohnny Chen     lldb::ConnectionStatus status = eConnectionStatusNoConnection;
190ce8d6d9cSPavel Labath     size_t bytes_read = Read(buffer, sizeof(buffer),
191ce8d6d9cSPavel Labath                              timeout_usec == UINT32_MAX
192ce8d6d9cSPavel Labath                                  ? Timeout<std::micro>(llvm::None)
193ce8d6d9cSPavel Labath                                  : std::chrono::microseconds(timeout_usec),
194ce8d6d9cSPavel Labath                              status, &error);
195f9765acdSGreg Clayton 
196250858a0SPavel Labath     LLDB_LOGV(log,
197250858a0SPavel Labath               "Read (buffer, sizeof(buffer), timeout_usec = 0x{0:x}, "
198250858a0SPavel Labath               "status = {1}, error = {2}) => bytes_read = {4}",
199a4a08442SRaphael Isemann               timeout_usec, Communication::ConnectionStatusAsString(status),
200250858a0SPavel Labath               error, bytes_read);
201f9765acdSGreg Clayton 
202b9c1b51eSKate Stone     if (bytes_read > 0) {
203f9765acdSGreg Clayton       if (CheckForPacket(buffer, bytes_read, packet))
2044df8ddfcSGreg Clayton         return packet.GetByteSize();
205b9c1b51eSKate Stone     } else {
206b9c1b51eSKate Stone       switch (status) {
207f0066ad0SGreg Clayton       case eConnectionStatusInterrupted:
208f9765acdSGreg Clayton       case eConnectionStatusTimedOut:
209f9765acdSGreg Clayton         timed_out = true;
210f9765acdSGreg Clayton         break;
211f9765acdSGreg Clayton       case eConnectionStatusSuccess:
212b9c1b51eSKate Stone         // printf ("status = success but error = %s\n",
213b9c1b51eSKate Stone         // error.AsCString("<invalid>"));
214f9765acdSGreg Clayton         break;
215f9765acdSGreg Clayton 
216f9765acdSGreg Clayton       case eConnectionStatusEndOfFile:
217f9765acdSGreg Clayton       case eConnectionStatusNoConnection:
218f9765acdSGreg Clayton       case eConnectionStatusLostConnection:
219f9765acdSGreg Clayton       case eConnectionStatusError:
220f9765acdSGreg Clayton         Disconnect();
221f9765acdSGreg Clayton         break;
222f9765acdSGreg Clayton       }
223f9765acdSGreg Clayton     }
224f9765acdSGreg Clayton   }
225f9765acdSGreg Clayton   packet.Clear();
226f9765acdSGreg Clayton   return 0;
227f9765acdSGreg Clayton }
228f9765acdSGreg Clayton 
CheckForPacket(const uint8_t * src,size_t src_len,DataExtractor & packet)229b9c1b51eSKate Stone bool CommunicationKDP::CheckForPacket(const uint8_t *src, size_t src_len,
230b9c1b51eSKate Stone                                       DataExtractor &packet) {
231f9765acdSGreg Clayton   // Put the packet data into the buffer in a thread safe fashion
23216ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_bytes_mutex);
233f9765acdSGreg Clayton 
234*c8fbf803SPavel Labath   Log *log = GetLog(KDPLog::Packets);
235f9765acdSGreg Clayton 
236b9c1b51eSKate Stone   if (src && src_len > 0) {
237b9c1b51eSKate Stone     if (log && log->GetVerbose()) {
2384df8ddfcSGreg Clayton       PacketStreamType log_strm;
2399739a552SZachary Turner       DumpHexBytes(&log_strm, src, src_len, UINT32_MAX, LLDB_INVALID_ADDRESS);
240c932266cSJason Molenda       log_strm.PutChar('\0');
24163e5fb76SJonas Devlieghere       LLDB_LOGF(log, "CommunicationKDP::%s adding %u bytes: %s", __FUNCTION__,
242b9c1b51eSKate Stone                 (uint32_t)src_len, log_strm.GetData());
243f9765acdSGreg Clayton     }
244f9765acdSGreg Clayton     m_bytes.append((const char *)src, src_len);
245f9765acdSGreg Clayton   }
246f9765acdSGreg Clayton 
2474df8ddfcSGreg Clayton   // Make sure we at least have enough bytes for a packet header
2484df8ddfcSGreg Clayton   const size_t bytes_available = m_bytes.size();
249b9c1b51eSKate Stone   if (bytes_available >= 8) {
2504df8ddfcSGreg Clayton     packet.SetData(&m_bytes[0], bytes_available, m_byte_order);
251c7bece56SGreg Clayton     lldb::offset_t offset = 0;
2524df8ddfcSGreg Clayton     uint8_t reply_command = packet.GetU8(&offset);
253b9c1b51eSKate Stone     switch (reply_command) {
2544b1b8b3eSGreg Clayton     case ePacketTypeRequest | KDP_EXCEPTION:
2554b1b8b3eSGreg Clayton     case ePacketTypeRequest | KDP_TERMINATION:
2564b1b8b3eSGreg Clayton       // We got an exception request, so be sure to send an ACK
2574b1b8b3eSGreg Clayton       {
258b9c1b51eSKate Stone         PacketStreamType request_ack_packet(Stream::eBinary, m_addr_byte_size,
259b9c1b51eSKate Stone                                             m_byte_order);
2604b1b8b3eSGreg Clayton         // Set the reply but and make the ACK packet
2614b1b8b3eSGreg Clayton         request_ack_packet.PutHex8(reply_command | ePacketTypeReply);
2624b1b8b3eSGreg Clayton         request_ack_packet.PutHex8(packet.GetU8(&offset));
2634b1b8b3eSGreg Clayton         request_ack_packet.PutHex16(packet.GetU16(&offset));
2644b1b8b3eSGreg Clayton         request_ack_packet.PutHex32(packet.GetU32(&offset));
26597d5cf05SGreg Clayton         m_is_running.SetValue(false, eBroadcastAlways);
2664b1b8b3eSGreg Clayton         // Ack to the exception or termination
2674b1b8b3eSGreg Clayton         SendRequestPacketNoLock(request_ack_packet);
2684b1b8b3eSGreg Clayton       }
2694b1b8b3eSGreg Clayton       // Fall through to case below to get packet contents
27062e0681aSJason Molenda       LLVM_FALLTHROUGH;
2715b88216dSGreg Clayton     case ePacketTypeReply | KDP_CONNECT:
2725b88216dSGreg Clayton     case ePacketTypeReply | KDP_DISCONNECT:
2735b88216dSGreg Clayton     case ePacketTypeReply | KDP_HOSTINFO:
2745b88216dSGreg Clayton     case ePacketTypeReply | KDP_VERSION:
2755b88216dSGreg Clayton     case ePacketTypeReply | KDP_MAXBYTES:
2765b88216dSGreg Clayton     case ePacketTypeReply | KDP_READMEM:
2775b88216dSGreg Clayton     case ePacketTypeReply | KDP_WRITEMEM:
2785b88216dSGreg Clayton     case ePacketTypeReply | KDP_READREGS:
2795b88216dSGreg Clayton     case ePacketTypeReply | KDP_WRITEREGS:
2805b88216dSGreg Clayton     case ePacketTypeReply | KDP_LOAD:
2815b88216dSGreg Clayton     case ePacketTypeReply | KDP_IMAGEPATH:
2825b88216dSGreg Clayton     case ePacketTypeReply | KDP_SUSPEND:
2835b88216dSGreg Clayton     case ePacketTypeReply | KDP_RESUMECPUS:
2845b88216dSGreg Clayton     case ePacketTypeReply | KDP_BREAKPOINT_SET:
2855b88216dSGreg Clayton     case ePacketTypeReply | KDP_BREAKPOINT_REMOVE:
2865b88216dSGreg Clayton     case ePacketTypeReply | KDP_REGIONS:
2875b88216dSGreg Clayton     case ePacketTypeReply | KDP_REATTACH:
2885b88216dSGreg Clayton     case ePacketTypeReply | KDP_HOSTREBOOT:
2895b88216dSGreg Clayton     case ePacketTypeReply | KDP_READMEM64:
2905b88216dSGreg Clayton     case ePacketTypeReply | KDP_WRITEMEM64:
2915b88216dSGreg Clayton     case ePacketTypeReply | KDP_BREAKPOINT_SET64:
2925b88216dSGreg Clayton     case ePacketTypeReply | KDP_BREAKPOINT_REMOVE64:
2935b88216dSGreg Clayton     case ePacketTypeReply | KDP_KERNELVERSION:
294ce62fd72SJason Molenda     case ePacketTypeReply | KDP_READPHYSMEM64:
295ce62fd72SJason Molenda     case ePacketTypeReply | KDP_WRITEPHYSMEM64:
296ce62fd72SJason Molenda     case ePacketTypeReply | KDP_READIOPORT:
297ce62fd72SJason Molenda     case ePacketTypeReply | KDP_WRITEIOPORT:
298ce62fd72SJason Molenda     case ePacketTypeReply | KDP_READMSR64:
299ce62fd72SJason Molenda     case ePacketTypeReply | KDP_WRITEMSR64:
300b9c1b51eSKate Stone     case ePacketTypeReply | KDP_DUMPINFO: {
3014df8ddfcSGreg Clayton       offset = 2;
3024df8ddfcSGreg Clayton       const uint16_t length = packet.GetU16(&offset);
303b9c1b51eSKate Stone       if (length <= bytes_available) {
30405097246SAdrian Prantl         // We have an entire packet ready, we need to copy the data bytes into
30505097246SAdrian Prantl         // a buffer that will be owned by the packet and erase the bytes from
306e9264b74SKazuaki Ishizaki         // our communication buffer "m_bytes"
3074df8ddfcSGreg Clayton         packet.SetData(DataBufferSP(new DataBufferHeap(&m_bytes[0], length)));
3084df8ddfcSGreg Clayton         m_bytes.erase(0, length);
3093a29bdbeSGreg Clayton 
310b9c1b51eSKate Stone         if (log) {
3113a29bdbeSGreg Clayton           PacketStreamType log_strm;
312a63d08c9SGreg Clayton           DumpPacket(log_strm, packet);
3133a29bdbeSGreg Clayton 
31463e5fb76SJonas Devlieghere           LLDB_LOGF(log, "%.*s", (uint32_t)log_strm.GetSize(),
31563e5fb76SJonas Devlieghere                     log_strm.GetData());
3163a29bdbeSGreg Clayton         }
3174df8ddfcSGreg Clayton         return true;
3184df8ddfcSGreg Clayton       }
319b9c1b51eSKate Stone     } break;
3204df8ddfcSGreg Clayton 
3214df8ddfcSGreg Clayton     default:
32205097246SAdrian Prantl       // Unrecognized reply command byte, erase this byte and try to get back
32305097246SAdrian Prantl       // on track
32463e5fb76SJonas Devlieghere       LLDB_LOGF(log, "CommunicationKDP::%s: tossing junk byte: 0x%2.2x",
325b9c1b51eSKate Stone                 __FUNCTION__, (uint8_t)m_bytes[0]);
3264df8ddfcSGreg Clayton       m_bytes.erase(0, 1);
3274df8ddfcSGreg Clayton       break;
3284df8ddfcSGreg Clayton     }
329f9765acdSGreg Clayton   }
330f9765acdSGreg Clayton   packet.Clear();
331f9765acdSGreg Clayton   return false;
332f9765acdSGreg Clayton }
333f9765acdSGreg Clayton 
SendRequestConnect(uint16_t reply_port,uint16_t exc_port,const char * greeting)334b9c1b51eSKate Stone bool CommunicationKDP::SendRequestConnect(uint16_t reply_port,
33557508026SGreg Clayton                                           uint16_t exc_port,
336b9c1b51eSKate Stone                                           const char *greeting) {
337b9c1b51eSKate Stone   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
338b9c1b51eSKate Stone                                   m_byte_order);
3394df8ddfcSGreg Clayton   if (greeting == NULL)
3404df8ddfcSGreg Clayton     greeting = "";
3414df8ddfcSGreg Clayton 
3425b88216dSGreg Clayton   const CommandType command = KDP_CONNECT;
343b9c1b51eSKate Stone   // Length is 82 uint16_t and the length of the greeting C string with the
344b9c1b51eSKate Stone   // terminating NULL
3453a29bdbeSGreg Clayton   const uint32_t command_length = 8 + 2 + 2 + ::strlen(greeting) + 1;
3464df8ddfcSGreg Clayton   MakeRequestPacketHeader(command, request_packet, command_length);
3473a29bdbeSGreg Clayton   // Always send connect ports as little endian
3483a29bdbeSGreg Clayton   request_packet.SetByteOrder(eByteOrderLittle);
34999e384c8SGreg Clayton   request_packet.PutHex16(htons(reply_port));
35099e384c8SGreg Clayton   request_packet.PutHex16(htons(exc_port));
3513a29bdbeSGreg Clayton   request_packet.SetByteOrder(m_byte_order);
35257508026SGreg Clayton   request_packet.PutCString(greeting);
3534df8ddfcSGreg Clayton   DataExtractor reply_packet;
3540ee809b7SGreg Clayton   return SendRequestAndGetReply(command, request_packet, reply_packet);
35557508026SGreg Clayton }
35657508026SGreg Clayton 
ClearKDPSettings()357b9c1b51eSKate Stone void CommunicationKDP::ClearKDPSettings() {
3584df8ddfcSGreg Clayton   m_request_sequence_id = 0;
3594df8ddfcSGreg Clayton   m_kdp_version_version = 0;
3604df8ddfcSGreg Clayton   m_kdp_version_feature = 0;
3614df8ddfcSGreg Clayton   m_kdp_hostinfo_cpu_mask = 0;
3624df8ddfcSGreg Clayton   m_kdp_hostinfo_cpu_type = 0;
3634df8ddfcSGreg Clayton   m_kdp_hostinfo_cpu_subtype = 0;
3644df8ddfcSGreg Clayton }
3654df8ddfcSGreg Clayton 
SendRequestReattach(uint16_t reply_port)366b9c1b51eSKate Stone bool CommunicationKDP::SendRequestReattach(uint16_t reply_port) {
367b9c1b51eSKate Stone   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
368b9c1b51eSKate Stone                                   m_byte_order);
3695b88216dSGreg Clayton   const CommandType command = KDP_REATTACH;
3704df8ddfcSGreg Clayton   // Length is 8 bytes for the header plus 2 bytes for the reply UDP port
3714df8ddfcSGreg Clayton   const uint32_t command_length = 8 + 2;
3724df8ddfcSGreg Clayton   MakeRequestPacketHeader(command, request_packet, command_length);
3733a29bdbeSGreg Clayton   // Always send connect ports as little endian
3743a29bdbeSGreg Clayton   request_packet.SetByteOrder(eByteOrderLittle);
37599e384c8SGreg Clayton   request_packet.PutHex16(htons(reply_port));
3763a29bdbeSGreg Clayton   request_packet.SetByteOrder(m_byte_order);
3774df8ddfcSGreg Clayton   DataExtractor reply_packet;
378b9c1b51eSKate Stone   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
3794df8ddfcSGreg Clayton     // Reset the sequence ID to zero for reattach
3804df8ddfcSGreg Clayton     ClearKDPSettings();
381c7bece56SGreg Clayton     lldb::offset_t offset = 4;
3824df8ddfcSGreg Clayton     m_session_key = reply_packet.GetU32(&offset);
3834df8ddfcSGreg Clayton     return true;
3844df8ddfcSGreg Clayton   }
3854df8ddfcSGreg Clayton   return false;
3864df8ddfcSGreg Clayton }
3874df8ddfcSGreg Clayton 
GetVersion()388b9c1b51eSKate Stone uint32_t CommunicationKDP::GetVersion() {
3894df8ddfcSGreg Clayton   if (!VersionIsValid())
3904df8ddfcSGreg Clayton     SendRequestVersion();
3914df8ddfcSGreg Clayton   return m_kdp_version_version;
3924df8ddfcSGreg Clayton }
3934df8ddfcSGreg Clayton 
GetFeatureFlags()394b9c1b51eSKate Stone uint32_t CommunicationKDP::GetFeatureFlags() {
3954df8ddfcSGreg Clayton   if (!VersionIsValid())
3964df8ddfcSGreg Clayton     SendRequestVersion();
3974df8ddfcSGreg Clayton   return m_kdp_version_feature;
3984df8ddfcSGreg Clayton }
3994df8ddfcSGreg Clayton 
SendRequestVersion()400b9c1b51eSKate Stone bool CommunicationKDP::SendRequestVersion() {
401b9c1b51eSKate Stone   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
402b9c1b51eSKate Stone                                   m_byte_order);
4035b88216dSGreg Clayton   const CommandType command = KDP_VERSION;
4044df8ddfcSGreg Clayton   const uint32_t command_length = 8;
4054df8ddfcSGreg Clayton   MakeRequestPacketHeader(command, request_packet, command_length);
4064df8ddfcSGreg Clayton   DataExtractor reply_packet;
407b9c1b51eSKate Stone   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
408c7bece56SGreg Clayton     lldb::offset_t offset = 8;
4094df8ddfcSGreg Clayton     m_kdp_version_version = reply_packet.GetU32(&offset);
4104df8ddfcSGreg Clayton     m_kdp_version_feature = reply_packet.GetU32(&offset);
4114df8ddfcSGreg Clayton     return true;
4124df8ddfcSGreg Clayton   }
4134df8ddfcSGreg Clayton   return false;
4144df8ddfcSGreg Clayton }
4154df8ddfcSGreg Clayton 
GetCPUMask()416b9c1b51eSKate Stone uint32_t CommunicationKDP::GetCPUMask() {
4174df8ddfcSGreg Clayton   if (!HostInfoIsValid())
4184df8ddfcSGreg Clayton     SendRequestHostInfo();
4194df8ddfcSGreg Clayton   return m_kdp_hostinfo_cpu_mask;
4204df8ddfcSGreg Clayton }
4214df8ddfcSGreg Clayton 
GetCPUType()422b9c1b51eSKate Stone uint32_t CommunicationKDP::GetCPUType() {
4234df8ddfcSGreg Clayton   if (!HostInfoIsValid())
4244df8ddfcSGreg Clayton     SendRequestHostInfo();
4254df8ddfcSGreg Clayton   return m_kdp_hostinfo_cpu_type;
4264df8ddfcSGreg Clayton }
4274df8ddfcSGreg Clayton 
GetCPUSubtype()428b9c1b51eSKate Stone uint32_t CommunicationKDP::GetCPUSubtype() {
4294df8ddfcSGreg Clayton   if (!HostInfoIsValid())
4304df8ddfcSGreg Clayton     SendRequestHostInfo();
4314df8ddfcSGreg Clayton   return m_kdp_hostinfo_cpu_subtype;
4324df8ddfcSGreg Clayton }
4334df8ddfcSGreg Clayton 
GetUUID()434b9c1b51eSKate Stone lldb_private::UUID CommunicationKDP::GetUUID() {
4354bd4e7e3SJason Molenda   UUID uuid;
4364bd4e7e3SJason Molenda   if (GetKernelVersion() == NULL)
4374bd4e7e3SJason Molenda     return uuid;
4384bd4e7e3SJason Molenda 
4394bd4e7e3SJason Molenda   if (m_kernel_version.find("UUID=") == std::string::npos)
4404bd4e7e3SJason Molenda     return uuid;
4414bd4e7e3SJason Molenda 
4424bd4e7e3SJason Molenda   size_t p = m_kernel_version.find("UUID=") + strlen("UUID=");
4434bd4e7e3SJason Molenda   std::string uuid_str = m_kernel_version.substr(p, 36);
4444bd4e7e3SJason Molenda   if (uuid_str.size() < 32)
4454bd4e7e3SJason Molenda     return uuid;
4464bd4e7e3SJason Molenda 
4471beffc18SJaroslav Sevcik   if (!uuid.SetFromStringRef(uuid_str)) {
4484bd4e7e3SJason Molenda     UUID invalid_uuid;
4494bd4e7e3SJason Molenda     return invalid_uuid;
4504bd4e7e3SJason Molenda   }
4514bd4e7e3SJason Molenda 
4524bd4e7e3SJason Molenda   return uuid;
4534bd4e7e3SJason Molenda }
4544bd4e7e3SJason Molenda 
RemoteIsEFI()455b9c1b51eSKate Stone bool CommunicationKDP::RemoteIsEFI() {
456840f12cfSJason Molenda   if (GetKernelVersion() == NULL)
457840f12cfSJason Molenda     return false;
458a6682a41SJonas Devlieghere   return strncmp(m_kernel_version.c_str(), "EFI", 3) == 0;
459840f12cfSJason Molenda }
460840f12cfSJason Molenda 
RemoteIsDarwinKernel()461b9c1b51eSKate Stone bool CommunicationKDP::RemoteIsDarwinKernel() {
462ca2ffa7eSJason Molenda   if (GetKernelVersion() == NULL)
463ca2ffa7eSJason Molenda     return false;
464a6682a41SJonas Devlieghere   return m_kernel_version.find("Darwin Kernel") != std::string::npos;
465ca2ffa7eSJason Molenda }
466ca2ffa7eSJason Molenda 
GetLoadAddress()467b9c1b51eSKate Stone lldb::addr_t CommunicationKDP::GetLoadAddress() {
4684bd4e7e3SJason Molenda   if (GetKernelVersion() == NULL)
4694bd4e7e3SJason Molenda     return LLDB_INVALID_ADDRESS;
4704bd4e7e3SJason Molenda 
4714bd4e7e3SJason Molenda   if (m_kernel_version.find("stext=") == std::string::npos)
4724bd4e7e3SJason Molenda     return LLDB_INVALID_ADDRESS;
4734bd4e7e3SJason Molenda   size_t p = m_kernel_version.find("stext=") + strlen("stext=");
4744bd4e7e3SJason Molenda   if (m_kernel_version[p] != '0' || m_kernel_version[p + 1] != 'x')
4754bd4e7e3SJason Molenda     return LLDB_INVALID_ADDRESS;
4764bd4e7e3SJason Molenda 
4774bd4e7e3SJason Molenda   addr_t kernel_load_address;
4784bd4e7e3SJason Molenda   errno = 0;
4794bd4e7e3SJason Molenda   kernel_load_address = ::strtoul(m_kernel_version.c_str() + p, NULL, 16);
4804bd4e7e3SJason Molenda   if (errno != 0 || kernel_load_address == 0)
4814bd4e7e3SJason Molenda     return LLDB_INVALID_ADDRESS;
4824bd4e7e3SJason Molenda 
4834bd4e7e3SJason Molenda   return kernel_load_address;
4844bd4e7e3SJason Molenda }
4854bd4e7e3SJason Molenda 
SendRequestHostInfo()486b9c1b51eSKate Stone bool CommunicationKDP::SendRequestHostInfo() {
487b9c1b51eSKate Stone   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
488b9c1b51eSKate Stone                                   m_byte_order);
4895b88216dSGreg Clayton   const CommandType command = KDP_HOSTINFO;
4904df8ddfcSGreg Clayton   const uint32_t command_length = 8;
4914df8ddfcSGreg Clayton   MakeRequestPacketHeader(command, request_packet, command_length);
4924df8ddfcSGreg Clayton   DataExtractor reply_packet;
493b9c1b51eSKate Stone   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
494c7bece56SGreg Clayton     lldb::offset_t offset = 8;
4954df8ddfcSGreg Clayton     m_kdp_hostinfo_cpu_mask = reply_packet.GetU32(&offset);
4964df8ddfcSGreg Clayton     m_kdp_hostinfo_cpu_type = reply_packet.GetU32(&offset);
4974df8ddfcSGreg Clayton     m_kdp_hostinfo_cpu_subtype = reply_packet.GetU32(&offset);
498a63d08c9SGreg Clayton 
499a63d08c9SGreg Clayton     ArchSpec kernel_arch;
500b9c1b51eSKate Stone     kernel_arch.SetArchitecture(eArchTypeMachO, m_kdp_hostinfo_cpu_type,
501a63d08c9SGreg Clayton                                 m_kdp_hostinfo_cpu_subtype);
502a63d08c9SGreg Clayton 
503a63d08c9SGreg Clayton     m_addr_byte_size = kernel_arch.GetAddressByteSize();
504a63d08c9SGreg Clayton     m_byte_order = kernel_arch.GetByteOrder();
5054df8ddfcSGreg Clayton     return true;
5064df8ddfcSGreg Clayton   }
5074df8ddfcSGreg Clayton   return false;
5084df8ddfcSGreg Clayton }
5094df8ddfcSGreg Clayton 
GetKernelVersion()510b9c1b51eSKate Stone const char *CommunicationKDP::GetKernelVersion() {
51107e66e3eSGreg Clayton   if (m_kernel_version.empty())
51207e66e3eSGreg Clayton     SendRequestKernelVersion();
51307e66e3eSGreg Clayton   return m_kernel_version.c_str();
51407e66e3eSGreg Clayton }
51507e66e3eSGreg Clayton 
SendRequestKernelVersion()516b9c1b51eSKate Stone bool CommunicationKDP::SendRequestKernelVersion() {
517b9c1b51eSKate Stone   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
518b9c1b51eSKate Stone                                   m_byte_order);
5195b88216dSGreg Clayton   const CommandType command = KDP_KERNELVERSION;
52007e66e3eSGreg Clayton   const uint32_t command_length = 8;
52107e66e3eSGreg Clayton   MakeRequestPacketHeader(command, request_packet, command_length);
52207e66e3eSGreg Clayton   DataExtractor reply_packet;
523b9c1b51eSKate Stone   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
52407e66e3eSGreg Clayton     const char *kernel_version_cstr = reply_packet.PeekCStr(8);
52507e66e3eSGreg Clayton     if (kernel_version_cstr && kernel_version_cstr[0])
52607e66e3eSGreg Clayton       m_kernel_version.assign(kernel_version_cstr);
52707e66e3eSGreg Clayton     return true;
52807e66e3eSGreg Clayton   }
52907e66e3eSGreg Clayton   return false;
53007e66e3eSGreg Clayton }
53107e66e3eSGreg Clayton 
SendRequestDisconnect()532b9c1b51eSKate Stone bool CommunicationKDP::SendRequestDisconnect() {
533b9c1b51eSKate Stone   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
534b9c1b51eSKate Stone                                   m_byte_order);
5355b88216dSGreg Clayton   const CommandType command = KDP_DISCONNECT;
5364df8ddfcSGreg Clayton   const uint32_t command_length = 8;
5374df8ddfcSGreg Clayton   MakeRequestPacketHeader(command, request_packet, command_length);
5384df8ddfcSGreg Clayton   DataExtractor reply_packet;
539b9c1b51eSKate Stone   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
5404df8ddfcSGreg Clayton     // Are we supposed to get a reply for disconnect?
5414df8ddfcSGreg Clayton   }
5424df8ddfcSGreg Clayton   ClearKDPSettings();
5434df8ddfcSGreg Clayton   return true;
54457508026SGreg Clayton }
54557508026SGreg Clayton 
SendRequestReadMemory(lldb::addr_t addr,void * dst,uint32_t dst_len,Status & error)546b9c1b51eSKate Stone uint32_t CommunicationKDP::SendRequestReadMemory(lldb::addr_t addr, void *dst,
547a63d08c9SGreg Clayton                                                  uint32_t dst_len,
54897206d57SZachary Turner                                                  Status &error) {
549b9c1b51eSKate Stone   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
550b9c1b51eSKate Stone                                   m_byte_order);
551a63d08c9SGreg Clayton   bool use_64 = (GetVersion() >= 11);
552a63d08c9SGreg Clayton   uint32_t command_addr_byte_size = use_64 ? 8 : 4;
5535b88216dSGreg Clayton   const CommandType command = use_64 ? KDP_READMEM64 : KDP_READMEM;
554a63d08c9SGreg Clayton   // Size is header + address size + uint32_t length
555a63d08c9SGreg Clayton   const uint32_t command_length = 8 + command_addr_byte_size + 4;
556a63d08c9SGreg Clayton   MakeRequestPacketHeader(command, request_packet, command_length);
557a63d08c9SGreg Clayton   request_packet.PutMaxHex64(addr, command_addr_byte_size);
558a63d08c9SGreg Clayton   request_packet.PutHex32(dst_len);
559a63d08c9SGreg Clayton   DataExtractor reply_packet;
560b9c1b51eSKate Stone   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
561c7bece56SGreg Clayton     lldb::offset_t offset = 8;
562a63d08c9SGreg Clayton     uint32_t kdp_error = reply_packet.GetU32(&offset);
563a63d08c9SGreg Clayton     uint32_t src_len = reply_packet.GetByteSize() - 12;
564a63d08c9SGreg Clayton 
565b9c1b51eSKate Stone     if (src_len > 0) {
566a63d08c9SGreg Clayton       const void *src = reply_packet.GetData(&offset, src_len);
567b9c1b51eSKate Stone       if (src) {
568a63d08c9SGreg Clayton         ::memcpy(dst, src, src_len);
569a63d08c9SGreg Clayton         error.Clear();
570a63d08c9SGreg Clayton         return src_len;
571a63d08c9SGreg Clayton       }
572a63d08c9SGreg Clayton     }
573a63d08c9SGreg Clayton     if (kdp_error)
574b9c1b51eSKate Stone       error.SetErrorStringWithFormat("kdp read memory failed (error %u)",
575b9c1b51eSKate Stone                                      kdp_error);
576a63d08c9SGreg Clayton     else
577a63d08c9SGreg Clayton       error.SetErrorString("kdp read memory failed");
578b9c1b51eSKate Stone   } else {
5791d19a2f2SGreg Clayton     error.SetErrorString("failed to send packet");
5801d19a2f2SGreg Clayton   }
581a63d08c9SGreg Clayton   return 0;
582a63d08c9SGreg Clayton }
583a63d08c9SGreg Clayton 
SendRequestWriteMemory(lldb::addr_t addr,const void * src,uint32_t src_len,Status & error)584b9c1b51eSKate Stone uint32_t CommunicationKDP::SendRequestWriteMemory(lldb::addr_t addr,
5850c54d8a9SGreg Clayton                                                   const void *src,
5860c54d8a9SGreg Clayton                                                   uint32_t src_len,
58797206d57SZachary Turner                                                   Status &error) {
588b9c1b51eSKate Stone   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
589b9c1b51eSKate Stone                                   m_byte_order);
5900c54d8a9SGreg Clayton   bool use_64 = (GetVersion() >= 11);
5910c54d8a9SGreg Clayton   uint32_t command_addr_byte_size = use_64 ? 8 : 4;
5925b88216dSGreg Clayton   const CommandType command = use_64 ? KDP_WRITEMEM64 : KDP_WRITEMEM;
5930c54d8a9SGreg Clayton   // Size is header + address size + uint32_t length
594b556c9b9SGreg Clayton   const uint32_t command_length = 8 + command_addr_byte_size + 4 + src_len;
5950c54d8a9SGreg Clayton   MakeRequestPacketHeader(command, request_packet, command_length);
5960c54d8a9SGreg Clayton   request_packet.PutMaxHex64(addr, command_addr_byte_size);
5970c54d8a9SGreg Clayton   request_packet.PutHex32(src_len);
59857656e7aSJason Molenda   request_packet.PutRawBytes(src, src_len);
5990c54d8a9SGreg Clayton 
6000c54d8a9SGreg Clayton   DataExtractor reply_packet;
601b9c1b51eSKate Stone   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
602c7bece56SGreg Clayton     lldb::offset_t offset = 8;
6030c54d8a9SGreg Clayton     uint32_t kdp_error = reply_packet.GetU32(&offset);
6040c54d8a9SGreg Clayton     if (kdp_error)
605b9c1b51eSKate Stone       error.SetErrorStringWithFormat("kdp write memory failed (error %u)",
606b9c1b51eSKate Stone                                      kdp_error);
607b9c1b51eSKate Stone     else {
6080c54d8a9SGreg Clayton       error.Clear();
6090c54d8a9SGreg Clayton       return src_len;
6100c54d8a9SGreg Clayton     }
611b9c1b51eSKate Stone   } else {
6121d19a2f2SGreg Clayton     error.SetErrorString("failed to send packet");
6131d19a2f2SGreg Clayton   }
6140c54d8a9SGreg Clayton   return 0;
6150c54d8a9SGreg Clayton }
6160c54d8a9SGreg Clayton 
SendRawRequest(uint8_t command_byte,const void * src,uint32_t src_len,DataExtractor & reply_packet,Status & error)617b9c1b51eSKate Stone bool CommunicationKDP::SendRawRequest(
618b9c1b51eSKate Stone     uint8_t command_byte,
6191d19a2f2SGreg Clayton     const void *src,  // Raw packet payload bytes
6201d19a2f2SGreg Clayton     uint32_t src_len, // Raw packet payload length
62197206d57SZachary Turner     DataExtractor &reply_packet, Status &error) {
622b9c1b51eSKate Stone   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
623b9c1b51eSKate Stone                                   m_byte_order);
6241d19a2f2SGreg Clayton   // Size is header + address size + uint32_t length
6251d19a2f2SGreg Clayton   const uint32_t command_length = 8 + src_len;
6261d19a2f2SGreg Clayton   const CommandType command = (CommandType)command_byte;
6271d19a2f2SGreg Clayton   MakeRequestPacketHeader(command, request_packet, command_length);
6281d19a2f2SGreg Clayton   request_packet.PutRawBytes(src, src_len);
6291d19a2f2SGreg Clayton 
630b9c1b51eSKate Stone   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
631c7bece56SGreg Clayton     lldb::offset_t offset = 8;
6321d19a2f2SGreg Clayton     uint32_t kdp_error = reply_packet.GetU32(&offset);
633ce62fd72SJason Molenda     if (kdp_error && (command_byte != KDP_DUMPINFO))
634b9c1b51eSKate Stone       error.SetErrorStringWithFormat("request packet 0x%8.8x failed (error %u)",
635b9c1b51eSKate Stone                                      command_byte, kdp_error);
636b9c1b51eSKate Stone     else {
6371d19a2f2SGreg Clayton       error.Clear();
6381d19a2f2SGreg Clayton       return true;
6391d19a2f2SGreg Clayton     }
640b9c1b51eSKate Stone   } else {
6411d19a2f2SGreg Clayton     error.SetErrorString("failed to send packet");
6421d19a2f2SGreg Clayton   }
6431d19a2f2SGreg Clayton   return false;
6441d19a2f2SGreg Clayton }
6451d19a2f2SGreg Clayton 
GetCommandAsCString(uint8_t command)646b9c1b51eSKate Stone const char *CommunicationKDP::GetCommandAsCString(uint8_t command) {
647b9c1b51eSKate Stone   switch (command) {
648b9c1b51eSKate Stone   case KDP_CONNECT:
649b9c1b51eSKate Stone     return "KDP_CONNECT";
650b9c1b51eSKate Stone   case KDP_DISCONNECT:
651b9c1b51eSKate Stone     return "KDP_DISCONNECT";
652b9c1b51eSKate Stone   case KDP_HOSTINFO:
653b9c1b51eSKate Stone     return "KDP_HOSTINFO";
654b9c1b51eSKate Stone   case KDP_VERSION:
655b9c1b51eSKate Stone     return "KDP_VERSION";
656b9c1b51eSKate Stone   case KDP_MAXBYTES:
657b9c1b51eSKate Stone     return "KDP_MAXBYTES";
658b9c1b51eSKate Stone   case KDP_READMEM:
659b9c1b51eSKate Stone     return "KDP_READMEM";
660b9c1b51eSKate Stone   case KDP_WRITEMEM:
661b9c1b51eSKate Stone     return "KDP_WRITEMEM";
662b9c1b51eSKate Stone   case KDP_READREGS:
663b9c1b51eSKate Stone     return "KDP_READREGS";
664b9c1b51eSKate Stone   case KDP_WRITEREGS:
665b9c1b51eSKate Stone     return "KDP_WRITEREGS";
666b9c1b51eSKate Stone   case KDP_LOAD:
667b9c1b51eSKate Stone     return "KDP_LOAD";
668b9c1b51eSKate Stone   case KDP_IMAGEPATH:
669b9c1b51eSKate Stone     return "KDP_IMAGEPATH";
670b9c1b51eSKate Stone   case KDP_SUSPEND:
671b9c1b51eSKate Stone     return "KDP_SUSPEND";
672b9c1b51eSKate Stone   case KDP_RESUMECPUS:
673b9c1b51eSKate Stone     return "KDP_RESUMECPUS";
674b9c1b51eSKate Stone   case KDP_EXCEPTION:
675b9c1b51eSKate Stone     return "KDP_EXCEPTION";
676b9c1b51eSKate Stone   case KDP_TERMINATION:
677b9c1b51eSKate Stone     return "KDP_TERMINATION";
678b9c1b51eSKate Stone   case KDP_BREAKPOINT_SET:
679b9c1b51eSKate Stone     return "KDP_BREAKPOINT_SET";
680b9c1b51eSKate Stone   case KDP_BREAKPOINT_REMOVE:
681b9c1b51eSKate Stone     return "KDP_BREAKPOINT_REMOVE";
682b9c1b51eSKate Stone   case KDP_REGIONS:
683b9c1b51eSKate Stone     return "KDP_REGIONS";
684b9c1b51eSKate Stone   case KDP_REATTACH:
685b9c1b51eSKate Stone     return "KDP_REATTACH";
686b9c1b51eSKate Stone   case KDP_HOSTREBOOT:
687b9c1b51eSKate Stone     return "KDP_HOSTREBOOT";
688b9c1b51eSKate Stone   case KDP_READMEM64:
689b9c1b51eSKate Stone     return "KDP_READMEM64";
690b9c1b51eSKate Stone   case KDP_WRITEMEM64:
691b9c1b51eSKate Stone     return "KDP_WRITEMEM64";
692b9c1b51eSKate Stone   case KDP_BREAKPOINT_SET64:
693b9c1b51eSKate Stone     return "KDP_BREAKPOINT64_SET";
694b9c1b51eSKate Stone   case KDP_BREAKPOINT_REMOVE64:
695b9c1b51eSKate Stone     return "KDP_BREAKPOINT64_REMOVE";
696b9c1b51eSKate Stone   case KDP_KERNELVERSION:
697b9c1b51eSKate Stone     return "KDP_KERNELVERSION";
698b9c1b51eSKate Stone   case KDP_READPHYSMEM64:
699b9c1b51eSKate Stone     return "KDP_READPHYSMEM64";
700b9c1b51eSKate Stone   case KDP_WRITEPHYSMEM64:
701b9c1b51eSKate Stone     return "KDP_WRITEPHYSMEM64";
702b9c1b51eSKate Stone   case KDP_READIOPORT:
703b9c1b51eSKate Stone     return "KDP_READIOPORT";
704b9c1b51eSKate Stone   case KDP_WRITEIOPORT:
705b9c1b51eSKate Stone     return "KDP_WRITEIOPORT";
706b9c1b51eSKate Stone   case KDP_READMSR64:
707b9c1b51eSKate Stone     return "KDP_READMSR64";
708b9c1b51eSKate Stone   case KDP_WRITEMSR64:
709b9c1b51eSKate Stone     return "KDP_WRITEMSR64";
710b9c1b51eSKate Stone   case KDP_DUMPINFO:
711b9c1b51eSKate Stone     return "KDP_DUMPINFO";
712a63d08c9SGreg Clayton   }
713a63d08c9SGreg Clayton   return NULL;
714a63d08c9SGreg Clayton }
715a63d08c9SGreg Clayton 
DumpPacket(Stream & s,const void * data,uint32_t data_len)716b9c1b51eSKate Stone void CommunicationKDP::DumpPacket(Stream &s, const void *data,
717b9c1b51eSKate Stone                                   uint32_t data_len) {
718a63d08c9SGreg Clayton   DataExtractor extractor(data, data_len, m_byte_order, m_addr_byte_size);
719a63d08c9SGreg Clayton   DumpPacket(s, extractor);
720a63d08c9SGreg Clayton }
721a63d08c9SGreg Clayton 
DumpPacket(Stream & s,const DataExtractor & packet)722b9c1b51eSKate Stone void CommunicationKDP::DumpPacket(Stream &s, const DataExtractor &packet) {
723a63d08c9SGreg Clayton   const char *error_desc = NULL;
724b9c1b51eSKate Stone   if (packet.GetByteSize() < 8) {
725a63d08c9SGreg Clayton     error_desc = "error: invalid packet (too short): ";
726b9c1b51eSKate Stone   } else {
727c7bece56SGreg Clayton     lldb::offset_t offset = 0;
728a63d08c9SGreg Clayton     const uint8_t first_packet_byte = packet.GetU8(&offset);
729a63d08c9SGreg Clayton     const uint8_t sequence_id = packet.GetU8(&offset);
730a63d08c9SGreg Clayton     const uint16_t length = packet.GetU16(&offset);
731a63d08c9SGreg Clayton     const uint32_t key = packet.GetU32(&offset);
732a63d08c9SGreg Clayton     const CommandType command = ExtractCommand(first_packet_byte);
733a63d08c9SGreg Clayton     const char *command_name = GetCommandAsCString(command);
734b9c1b51eSKate Stone     if (command_name) {
735a63d08c9SGreg Clayton       const bool is_reply = ExtractIsReply(first_packet_byte);
73697d5cf05SGreg Clayton       s.Printf("(running=%i) %s %24s: 0x%2.2x 0x%2.2x 0x%4.4x 0x%8.8x ",
737b9c1b51eSKate Stone                IsRunning(), is_reply ? "<--" : "-->", command_name,
738b9c1b51eSKate Stone                first_packet_byte, sequence_id, length, key);
739a63d08c9SGreg Clayton 
740b9c1b51eSKate Stone       if (is_reply) {
741a63d08c9SGreg Clayton         // Dump request reply packets
742b9c1b51eSKate Stone         switch (command) {
7430c54d8a9SGreg Clayton         // Commands that return a single 32 bit error
7445b88216dSGreg Clayton         case KDP_CONNECT:
7455b88216dSGreg Clayton         case KDP_WRITEMEM:
7465b88216dSGreg Clayton         case KDP_WRITEMEM64:
7475b88216dSGreg Clayton         case KDP_BREAKPOINT_SET:
7485b88216dSGreg Clayton         case KDP_BREAKPOINT_REMOVE:
7495b88216dSGreg Clayton         case KDP_BREAKPOINT_SET64:
7505b88216dSGreg Clayton         case KDP_BREAKPOINT_REMOVE64:
7515b88216dSGreg Clayton         case KDP_WRITEREGS:
7525b88216dSGreg Clayton         case KDP_LOAD:
753ce62fd72SJason Molenda         case KDP_WRITEIOPORT:
754b9c1b51eSKate Stone         case KDP_WRITEMSR64: {
755a63d08c9SGreg Clayton           const uint32_t error = packet.GetU32(&offset);
756a63d08c9SGreg Clayton           s.Printf(" (error=0x%8.8x)", error);
757b9c1b51eSKate Stone         } break;
758a63d08c9SGreg Clayton 
7595b88216dSGreg Clayton         case KDP_DISCONNECT:
7605b88216dSGreg Clayton         case KDP_REATTACH:
7615b88216dSGreg Clayton         case KDP_HOSTREBOOT:
7625b88216dSGreg Clayton         case KDP_SUSPEND:
7635b88216dSGreg Clayton         case KDP_RESUMECPUS:
7645b88216dSGreg Clayton         case KDP_EXCEPTION:
7655b88216dSGreg Clayton         case KDP_TERMINATION:
766a63d08c9SGreg Clayton           // No return value for the reply, just the header to ack
7670c54d8a9SGreg Clayton           s.PutCString(" ()");
768a63d08c9SGreg Clayton           break;
769a63d08c9SGreg Clayton 
770b9c1b51eSKate Stone         case KDP_HOSTINFO: {
771a63d08c9SGreg Clayton           const uint32_t cpu_mask = packet.GetU32(&offset);
772a63d08c9SGreg Clayton           const uint32_t cpu_type = packet.GetU32(&offset);
773a63d08c9SGreg Clayton           const uint32_t cpu_subtype = packet.GetU32(&offset);
774b9c1b51eSKate Stone           s.Printf(" (cpu_mask=0x%8.8x, cpu_type=0x%8.8x, cpu_subtype=0x%8.8x)",
775b9c1b51eSKate Stone                    cpu_mask, cpu_type, cpu_subtype);
776b9c1b51eSKate Stone         } break;
777a63d08c9SGreg Clayton 
778b9c1b51eSKate Stone         case KDP_VERSION: {
779a63d08c9SGreg Clayton           const uint32_t version = packet.GetU32(&offset);
780a63d08c9SGreg Clayton           const uint32_t feature = packet.GetU32(&offset);
781a63d08c9SGreg Clayton           s.Printf(" (version=0x%8.8x, feature=0x%8.8x)", version, feature);
782b9c1b51eSKate Stone         } break;
783a63d08c9SGreg Clayton 
784b9c1b51eSKate Stone         case KDP_REGIONS: {
785a63d08c9SGreg Clayton           const uint32_t region_count = packet.GetU32(&offset);
786a63d08c9SGreg Clayton           s.Printf(" (count = %u", region_count);
787b9c1b51eSKate Stone           for (uint32_t i = 0; i < region_count; ++i) {
7880863f675SPavel Labath             const addr_t region_addr = packet.GetAddress(&offset);
789a63d08c9SGreg Clayton             const uint32_t region_size = packet.GetU32(&offset);
790a63d08c9SGreg Clayton             const uint32_t region_prot = packet.GetU32(&offset);
791b9c1b51eSKate Stone             s.Printf("\n\tregion[%" PRIu64 "] = { range = [0x%16.16" PRIx64
792b9c1b51eSKate Stone                      " - 0x%16.16" PRIx64 "), size = 0x%8.8x, prot = %s }",
793b9c1b51eSKate Stone                      region_addr, region_addr, region_addr + region_size,
794b9c1b51eSKate Stone                      region_size, GetPermissionsAsCString(region_prot));
795a63d08c9SGreg Clayton           }
796b9c1b51eSKate Stone         } break;
797a63d08c9SGreg Clayton 
7985b88216dSGreg Clayton         case KDP_READMEM:
7995b88216dSGreg Clayton         case KDP_READMEM64:
800b9c1b51eSKate Stone         case KDP_READPHYSMEM64: {
801a63d08c9SGreg Clayton           const uint32_t error = packet.GetU32(&offset);
8020c54d8a9SGreg Clayton           const uint32_t count = packet.GetByteSize() - offset;
8035b442374SGreg Clayton           s.Printf(" (error = 0x%8.8x:\n", error);
804a63d08c9SGreg Clayton           if (count > 0)
805c963f20eSJim Ingham             DumpDataExtractor(packet,
806c963f20eSJim Ingham                               &s,                      // Stream to dump to
80707e66e3eSGreg Clayton                               offset,                  // Offset within "packet"
80807e66e3eSGreg Clayton                               eFormatBytesWithASCII,   // Format to use
809c963f20eSJim Ingham                               1,                       // Size of each item
810c963f20eSJim Ingham                                                        // in bytes
81107e66e3eSGreg Clayton                               count,                   // Number of items
81207e66e3eSGreg Clayton                               16,                      // Number per line
813c963f20eSJim Ingham                               m_last_read_memory_addr, // Don't show addresses
814c963f20eSJim Ingham                                                        // before each line
81507e66e3eSGreg Clayton                               0, 0);                   // No bitfields
816b9c1b51eSKate Stone         } break;
817a63d08c9SGreg Clayton 
818b9c1b51eSKate Stone         case KDP_READREGS: {
8190c54d8a9SGreg Clayton           const uint32_t error = packet.GetU32(&offset);
8200c54d8a9SGreg Clayton           const uint32_t count = packet.GetByteSize() - offset;
8215b442374SGreg Clayton           s.Printf(" (error = 0x%8.8x regs:\n", error);
8220c54d8a9SGreg Clayton           if (count > 0)
823c963f20eSJim Ingham             DumpDataExtractor(packet,
824b9c1b51eSKate Stone                               &s,                       // Stream to dump to
8250c54d8a9SGreg Clayton                               offset,                   // Offset within "packet"
8260c54d8a9SGreg Clayton                               eFormatHex,               // Format to use
827c963f20eSJim Ingham                               m_addr_byte_size,         // Size of each item
828c963f20eSJim Ingham                                                         // in bytes
8290c54d8a9SGreg Clayton                               count / m_addr_byte_size, // Number of items
8300c54d8a9SGreg Clayton                               16 / m_addr_byte_size,    // Number per line
831c963f20eSJim Ingham                               LLDB_INVALID_ADDRESS,
832c963f20eSJim Ingham                                                         // Don't
833c963f20eSJim Ingham                                                         // show addresses before
834c963f20eSJim Ingham                                                         // each line
8350c54d8a9SGreg Clayton                               0, 0);                    // No bitfields
836b9c1b51eSKate Stone         } break;
8370c54d8a9SGreg Clayton 
838b9c1b51eSKate Stone         case KDP_KERNELVERSION: {
83907e66e3eSGreg Clayton           const char *kernel_version = packet.PeekCStr(8);
84007e66e3eSGreg Clayton           s.Printf(" (version = \"%s\")", kernel_version);
841b9c1b51eSKate Stone         } break;
84207e66e3eSGreg Clayton 
843b9c1b51eSKate Stone         case KDP_MAXBYTES: {
84407e66e3eSGreg Clayton           const uint32_t max_bytes = packet.GetU32(&offset);
84507e66e3eSGreg Clayton           s.Printf(" (max_bytes = 0x%8.8x (%u))", max_bytes, max_bytes);
846b9c1b51eSKate Stone         } break;
847b9c1b51eSKate Stone         case KDP_IMAGEPATH: {
84807e66e3eSGreg Clayton           const char *path = packet.GetCStr(&offset);
84907e66e3eSGreg Clayton           s.Printf(" (path = \"%s\")", path);
850b9c1b51eSKate Stone         } break;
851ce62fd72SJason Molenda 
852ce62fd72SJason Molenda         case KDP_READIOPORT:
853b9c1b51eSKate Stone         case KDP_READMSR64: {
854ce62fd72SJason Molenda           const uint32_t error = packet.GetU32(&offset);
855ce62fd72SJason Molenda           const uint32_t count = packet.GetByteSize() - offset;
856ce62fd72SJason Molenda           s.Printf(" (error = 0x%8.8x io:\n", error);
857ce62fd72SJason Molenda           if (count > 0)
858c963f20eSJim Ingham             DumpDataExtractor(packet,
859b9c1b51eSKate Stone                               &s,                   // Stream to dump to
860ce62fd72SJason Molenda                               offset,               // Offset within "packet"
861ce62fd72SJason Molenda                               eFormatHex,           // Format to use
862ce62fd72SJason Molenda                               1,                    // Size of each item in bytes
863ce62fd72SJason Molenda                               count,                // Number of items
864ce62fd72SJason Molenda                               16,                   // Number per line
865c963f20eSJim Ingham                               LLDB_INVALID_ADDRESS, // Don't show addresses
866c963f20eSJim Ingham                                                     // before each line
867ce62fd72SJason Molenda                               0, 0);                // No bitfields
868b9c1b51eSKate Stone         } break;
869b9c1b51eSKate Stone         case KDP_DUMPINFO: {
870ce62fd72SJason Molenda           const uint32_t count = packet.GetByteSize() - offset;
871ce62fd72SJason Molenda           s.Printf(" (count = %u, bytes = \n", count);
872ce62fd72SJason Molenda           if (count > 0)
873c963f20eSJim Ingham             DumpDataExtractor(packet,
874b9c1b51eSKate Stone                               &s,                   // Stream to dump to
875ce62fd72SJason Molenda                               offset,               // Offset within "packet"
876ce62fd72SJason Molenda                               eFormatHex,           // Format to use
877c963f20eSJim Ingham                               1,                    // Size of each item in
878c963f20eSJim Ingham                                                     // bytes
879ce62fd72SJason Molenda                               count,                // Number of items
880ce62fd72SJason Molenda                               16,                   // Number per line
881c963f20eSJim Ingham                               LLDB_INVALID_ADDRESS, // Don't show addresses
882c963f20eSJim Ingham                                                     // before each line
883ce62fd72SJason Molenda                               0, 0);                // No bitfields
884ce62fd72SJason Molenda 
885b9c1b51eSKate Stone         } break;
886ce62fd72SJason Molenda 
88707e66e3eSGreg Clayton         default:
8880c54d8a9SGreg Clayton           s.Printf(" (add support for dumping this packet reply!!!");
889a63d08c9SGreg Clayton           break;
890a63d08c9SGreg Clayton         }
891b9c1b51eSKate Stone       } else {
892a63d08c9SGreg Clayton         // Dump request packets
893b9c1b51eSKate Stone         switch (command) {
894b9c1b51eSKate Stone         case KDP_CONNECT: {
89599e384c8SGreg Clayton           const uint16_t reply_port = ntohs(packet.GetU16(&offset));
89699e384c8SGreg Clayton           const uint16_t exc_port = ntohs(packet.GetU16(&offset));
897b9c1b51eSKate Stone           s.Printf(" (reply_port = %u, exc_port = %u, greeting = \"%s\")",
898b9c1b51eSKate Stone                    reply_port, exc_port, packet.GetCStr(&offset));
899b9c1b51eSKate Stone         } break;
900a63d08c9SGreg Clayton 
9015b88216dSGreg Clayton         case KDP_DISCONNECT:
9025b88216dSGreg Clayton         case KDP_HOSTREBOOT:
9035b88216dSGreg Clayton         case KDP_HOSTINFO:
9045b88216dSGreg Clayton         case KDP_VERSION:
9055b88216dSGreg Clayton         case KDP_REGIONS:
9065b88216dSGreg Clayton         case KDP_KERNELVERSION:
9075b88216dSGreg Clayton         case KDP_MAXBYTES:
9085b88216dSGreg Clayton         case KDP_IMAGEPATH:
9095b88216dSGreg Clayton         case KDP_SUSPEND:
910a63d08c9SGreg Clayton           // No args, just the header in the request...
91107e66e3eSGreg Clayton           s.PutCString(" ()");
91207e66e3eSGreg Clayton           break;
91307e66e3eSGreg Clayton 
914b9c1b51eSKate Stone         case KDP_RESUMECPUS: {
91507e66e3eSGreg Clayton           const uint32_t cpu_mask = packet.GetU32(&offset);
91607e66e3eSGreg Clayton           s.Printf(" (cpu_mask = 0x%8.8x)", cpu_mask);
917b9c1b51eSKate Stone         } break;
918a63d08c9SGreg Clayton 
919b9c1b51eSKate Stone         case KDP_READMEM: {
920a63d08c9SGreg Clayton           const uint32_t addr = packet.GetU32(&offset);
921a63d08c9SGreg Clayton           const uint32_t size = packet.GetU32(&offset);
922a63d08c9SGreg Clayton           s.Printf(" (addr = 0x%8.8x, size = %u)", addr, size);
92307e66e3eSGreg Clayton           m_last_read_memory_addr = addr;
924b9c1b51eSKate Stone         } break;
925a63d08c9SGreg Clayton 
926b9c1b51eSKate Stone         case KDP_WRITEMEM: {
9270c54d8a9SGreg Clayton           const uint32_t addr = packet.GetU32(&offset);
9280c54d8a9SGreg Clayton           const uint32_t size = packet.GetU32(&offset);
9295b442374SGreg Clayton           s.Printf(" (addr = 0x%8.8x, size = %u, bytes = \n", addr, size);
9300c54d8a9SGreg Clayton           if (size > 0)
9319739a552SZachary Turner             DumpHexBytes(&s, packet.GetData(&offset, size), size, 32, addr);
932b9c1b51eSKate Stone         } break;
9330c54d8a9SGreg Clayton 
934b9c1b51eSKate Stone         case KDP_READMEM64: {
935a63d08c9SGreg Clayton           const uint64_t addr = packet.GetU64(&offset);
936a63d08c9SGreg Clayton           const uint32_t size = packet.GetU32(&offset);
937d01b2953SDaniel Malea           s.Printf(" (addr = 0x%16.16" PRIx64 ", size = %u)", addr, size);
93807e66e3eSGreg Clayton           m_last_read_memory_addr = addr;
939b9c1b51eSKate Stone         } break;
940a63d08c9SGreg Clayton 
941b9c1b51eSKate Stone         case KDP_READPHYSMEM64: {
942ce62fd72SJason Molenda           const uint64_t addr = packet.GetU64(&offset);
943ce62fd72SJason Molenda           const uint32_t size = packet.GetU32(&offset);
944ce62fd72SJason Molenda           const uint32_t lcpu = packet.GetU16(&offset);
945b9c1b51eSKate Stone           s.Printf(" (addr = 0x%16.16llx, size = %u, lcpu = %u)", addr, size,
946b9c1b51eSKate Stone                    lcpu);
947ce62fd72SJason Molenda           m_last_read_memory_addr = addr;
948b9c1b51eSKate Stone         } break;
949ce62fd72SJason Molenda 
950b9c1b51eSKate Stone         case KDP_WRITEMEM64: {
9510c54d8a9SGreg Clayton           const uint64_t addr = packet.GetU64(&offset);
9520c54d8a9SGreg Clayton           const uint32_t size = packet.GetU32(&offset);
953b9c1b51eSKate Stone           s.Printf(" (addr = 0x%16.16" PRIx64 ", size = %u, bytes = \n", addr,
954b9c1b51eSKate Stone                    size);
9550c54d8a9SGreg Clayton           if (size > 0)
9569739a552SZachary Turner             DumpHexBytes(&s, packet.GetData(&offset, size), size, 32, addr);
957b9c1b51eSKate Stone         } break;
9580c54d8a9SGreg Clayton 
959b9c1b51eSKate Stone         case KDP_WRITEPHYSMEM64: {
960ce62fd72SJason Molenda           const uint64_t addr = packet.GetU64(&offset);
961ce62fd72SJason Molenda           const uint32_t size = packet.GetU32(&offset);
962ce62fd72SJason Molenda           const uint32_t lcpu = packet.GetU16(&offset);
963b9c1b51eSKate Stone           s.Printf(" (addr = 0x%16.16llx, size = %u, lcpu = %u, bytes = \n",
964b9c1b51eSKate Stone                    addr, size, lcpu);
965ce62fd72SJason Molenda           if (size > 0)
9669739a552SZachary Turner             DumpHexBytes(&s, packet.GetData(&offset, size), size, 32, addr);
967b9c1b51eSKate Stone         } break;
968ce62fd72SJason Molenda 
969b9c1b51eSKate Stone         case KDP_READREGS: {
970a63d08c9SGreg Clayton           const uint32_t cpu = packet.GetU32(&offset);
971a63d08c9SGreg Clayton           const uint32_t flavor = packet.GetU32(&offset);
972a63d08c9SGreg Clayton           s.Printf(" (cpu = %u, flavor = %u)", cpu, flavor);
973b9c1b51eSKate Stone         } break;
974a63d08c9SGreg Clayton 
975b9c1b51eSKate Stone         case KDP_WRITEREGS: {
9760c54d8a9SGreg Clayton           const uint32_t cpu = packet.GetU32(&offset);
9770c54d8a9SGreg Clayton           const uint32_t flavor = packet.GetU32(&offset);
9780c54d8a9SGreg Clayton           const uint32_t nbytes = packet.GetByteSize() - offset;
9795b442374SGreg Clayton           s.Printf(" (cpu = %u, flavor = %u, regs = \n", cpu, flavor);
9800c54d8a9SGreg Clayton           if (nbytes > 0)
981c963f20eSJim Ingham             DumpDataExtractor(packet,
982b9c1b51eSKate Stone                               &s,                        // Stream to dump to
983c963f20eSJim Ingham                               offset,                    // Offset within
984c963f20eSJim Ingham                                                          // "packet"
9850c54d8a9SGreg Clayton                               eFormatHex,                // Format to use
986c963f20eSJim Ingham                               m_addr_byte_size,          // Size of each item in
987c963f20eSJim Ingham                                                          // bytes
9880c54d8a9SGreg Clayton                               nbytes / m_addr_byte_size, // Number of items
9890c54d8a9SGreg Clayton                               16 / m_addr_byte_size,     // Number per line
990c963f20eSJim Ingham                               LLDB_INVALID_ADDRESS,      // Don't show addresses
991c963f20eSJim Ingham                                                          // before each line
9920c54d8a9SGreg Clayton                               0, 0);                // No bitfields
993b9c1b51eSKate Stone         } break;
9940c54d8a9SGreg Clayton 
9955b88216dSGreg Clayton         case KDP_BREAKPOINT_SET:
996b9c1b51eSKate Stone         case KDP_BREAKPOINT_REMOVE: {
99707e66e3eSGreg Clayton           const uint32_t addr = packet.GetU32(&offset);
99807e66e3eSGreg Clayton           s.Printf(" (addr = 0x%8.8x)", addr);
999b9c1b51eSKate Stone         } break;
100007e66e3eSGreg Clayton 
10015b88216dSGreg Clayton         case KDP_BREAKPOINT_SET64:
1002b9c1b51eSKate Stone         case KDP_BREAKPOINT_REMOVE64: {
100307e66e3eSGreg Clayton           const uint64_t addr = packet.GetU64(&offset);
1004d01b2953SDaniel Malea           s.Printf(" (addr = 0x%16.16" PRIx64 ")", addr);
1005b9c1b51eSKate Stone         } break;
100607e66e3eSGreg Clayton 
1007b9c1b51eSKate Stone         case KDP_LOAD: {
100807e66e3eSGreg Clayton           const char *path = packet.GetCStr(&offset);
100907e66e3eSGreg Clayton           s.Printf(" (path = \"%s\")", path);
1010b9c1b51eSKate Stone         } break;
101107e66e3eSGreg Clayton 
1012b9c1b51eSKate Stone         case KDP_EXCEPTION: {
101307e66e3eSGreg Clayton           const uint32_t count = packet.GetU32(&offset);
101407e66e3eSGreg Clayton 
1015b9c1b51eSKate Stone           for (uint32_t i = 0; i < count; ++i) {
101607e66e3eSGreg Clayton             const uint32_t cpu = packet.GetU32(&offset);
101707e66e3eSGreg Clayton             const uint32_t exc = packet.GetU32(&offset);
101807e66e3eSGreg Clayton             const uint32_t code = packet.GetU32(&offset);
101907e66e3eSGreg Clayton             const uint32_t subcode = packet.GetU32(&offset);
102007e66e3eSGreg Clayton             const char *exc_cstr = NULL;
1021b9c1b51eSKate Stone             switch (exc) {
1022b9c1b51eSKate Stone             case 1:
1023b9c1b51eSKate Stone               exc_cstr = "EXC_BAD_ACCESS";
1024b9c1b51eSKate Stone               break;
1025b9c1b51eSKate Stone             case 2:
1026b9c1b51eSKate Stone               exc_cstr = "EXC_BAD_INSTRUCTION";
1027b9c1b51eSKate Stone               break;
1028b9c1b51eSKate Stone             case 3:
1029b9c1b51eSKate Stone               exc_cstr = "EXC_ARITHMETIC";
1030b9c1b51eSKate Stone               break;
1031b9c1b51eSKate Stone             case 4:
1032b9c1b51eSKate Stone               exc_cstr = "EXC_EMULATION";
1033b9c1b51eSKate Stone               break;
1034b9c1b51eSKate Stone             case 5:
1035b9c1b51eSKate Stone               exc_cstr = "EXC_SOFTWARE";
1036b9c1b51eSKate Stone               break;
1037b9c1b51eSKate Stone             case 6:
1038b9c1b51eSKate Stone               exc_cstr = "EXC_BREAKPOINT";
1039b9c1b51eSKate Stone               break;
1040b9c1b51eSKate Stone             case 7:
1041b9c1b51eSKate Stone               exc_cstr = "EXC_SYSCALL";
1042b9c1b51eSKate Stone               break;
1043b9c1b51eSKate Stone             case 8:
1044b9c1b51eSKate Stone               exc_cstr = "EXC_MACH_SYSCALL";
1045b9c1b51eSKate Stone               break;
1046b9c1b51eSKate Stone             case 9:
1047b9c1b51eSKate Stone               exc_cstr = "EXC_RPC_ALERT";
1048b9c1b51eSKate Stone               break;
1049b9c1b51eSKate Stone             case 10:
1050b9c1b51eSKate Stone               exc_cstr = "EXC_CRASH";
1051b9c1b51eSKate Stone               break;
105207e66e3eSGreg Clayton             default:
105307e66e3eSGreg Clayton               break;
105407e66e3eSGreg Clayton             }
105507e66e3eSGreg Clayton 
1056b9c1b51eSKate Stone             s.Printf("{ cpu = 0x%8.8x, exc = %s (%u), code = %u (0x%8.8x), "
1057b9c1b51eSKate Stone                      "subcode = %u (0x%8.8x)} ",
105807e66e3eSGreg Clayton                      cpu, exc_cstr, exc, code, code, subcode, subcode);
105907e66e3eSGreg Clayton           }
1060b9c1b51eSKate Stone         } break;
106107e66e3eSGreg Clayton 
1062b9c1b51eSKate Stone         case KDP_TERMINATION: {
106307e66e3eSGreg Clayton           const uint32_t term_code = packet.GetU32(&offset);
106407e66e3eSGreg Clayton           const uint32_t exit_code = packet.GetU32(&offset);
1065b9c1b51eSKate Stone           s.Printf(" (term_code = 0x%8.8x (%u), exit_code = 0x%8.8x (%u))",
1066b9c1b51eSKate Stone                    term_code, term_code, exit_code, exit_code);
1067b9c1b51eSKate Stone         } break;
1068a63d08c9SGreg Clayton 
1069b9c1b51eSKate Stone         case KDP_REATTACH: {
107099e384c8SGreg Clayton           const uint16_t reply_port = ntohs(packet.GetU16(&offset));
1071a63d08c9SGreg Clayton           s.Printf(" (reply_port = %u)", reply_port);
1072b9c1b51eSKate Stone         } break;
1073ce62fd72SJason Molenda 
1074b9c1b51eSKate Stone         case KDP_READMSR64: {
1075ce62fd72SJason Molenda           const uint32_t address = packet.GetU32(&offset);
1076ce62fd72SJason Molenda           const uint16_t lcpu = packet.GetU16(&offset);
1077ce62fd72SJason Molenda           s.Printf(" (address=0x%8.8x, lcpu=0x%4.4x)", address, lcpu);
1078b9c1b51eSKate Stone         } break;
1079ce62fd72SJason Molenda 
1080b9c1b51eSKate Stone         case KDP_WRITEMSR64: {
1081ce62fd72SJason Molenda           const uint32_t address = packet.GetU32(&offset);
1082ce62fd72SJason Molenda           const uint16_t lcpu = packet.GetU16(&offset);
1083ce62fd72SJason Molenda           const uint32_t nbytes = packet.GetByteSize() - offset;
1084b9c1b51eSKate Stone           s.Printf(" (address=0x%8.8x, lcpu=0x%4.4x, nbytes=0x%8.8x)", lcpu,
1085b9c1b51eSKate Stone                    address, nbytes);
1086ce62fd72SJason Molenda           if (nbytes > 0)
1087c963f20eSJim Ingham             DumpDataExtractor(packet,
1088b9c1b51eSKate Stone                               &s,                   // Stream to dump to
1089ce62fd72SJason Molenda                               offset,               // Offset within "packet"
1090ce62fd72SJason Molenda                               eFormatHex,           // Format to use
1091c963f20eSJim Ingham                               1,                    // Size of each item in
1092c963f20eSJim Ingham                                                     // bytes
1093ce62fd72SJason Molenda                               nbytes,               // Number of items
1094ce62fd72SJason Molenda                               16,                   // Number per line
1095c963f20eSJim Ingham                               LLDB_INVALID_ADDRESS, // Don't show addresses
1096c963f20eSJim Ingham                                                     // before each line
1097ce62fd72SJason Molenda                               0, 0);                // No bitfields
1098b9c1b51eSKate Stone         } break;
1099ce62fd72SJason Molenda 
1100b9c1b51eSKate Stone         case KDP_READIOPORT: {
1101ce62fd72SJason Molenda           const uint16_t lcpu = packet.GetU16(&offset);
1102ce62fd72SJason Molenda           const uint16_t address = packet.GetU16(&offset);
1103ce62fd72SJason Molenda           const uint16_t nbytes = packet.GetU16(&offset);
1104b9c1b51eSKate Stone           s.Printf(" (lcpu=0x%4.4x, address=0x%4.4x, nbytes=%u)", lcpu, address,
1105b9c1b51eSKate Stone                    nbytes);
1106b9c1b51eSKate Stone         } break;
1107ce62fd72SJason Molenda 
1108b9c1b51eSKate Stone         case KDP_WRITEIOPORT: {
1109ce62fd72SJason Molenda           const uint16_t lcpu = packet.GetU16(&offset);
1110ce62fd72SJason Molenda           const uint16_t address = packet.GetU16(&offset);
1111ce62fd72SJason Molenda           const uint16_t nbytes = packet.GetU16(&offset);
1112b9c1b51eSKate Stone           s.Printf(" (lcpu = %u, addr = 0x%4.4x, nbytes = %u, bytes = \n", lcpu,
1113b9c1b51eSKate Stone                    address, nbytes);
1114ce62fd72SJason Molenda           if (nbytes > 0)
1115c963f20eSJim Ingham             DumpDataExtractor(packet,
1116b9c1b51eSKate Stone                               &s,                   // Stream to dump to
1117ce62fd72SJason Molenda                               offset,               // Offset within "packet"
1118ce62fd72SJason Molenda                               eFormatHex,           // Format to use
1119c963f20eSJim Ingham                               1,                    // Size of each item in
1120c963f20eSJim Ingham                                                     // bytes
1121ce62fd72SJason Molenda                               nbytes,               // Number of items
1122ce62fd72SJason Molenda                               16,                   // Number per line
1123c963f20eSJim Ingham                               LLDB_INVALID_ADDRESS, // Don't show addresses
1124c963f20eSJim Ingham                                                     // before each line
1125ce62fd72SJason Molenda                               0, 0);                // No bitfields
1126b9c1b51eSKate Stone         } break;
1127ce62fd72SJason Molenda 
1128b9c1b51eSKate Stone         case KDP_DUMPINFO: {
1129ce62fd72SJason Molenda           const uint32_t count = packet.GetByteSize() - offset;
1130ce62fd72SJason Molenda           s.Printf(" (count = %u, bytes = \n", count);
1131ce62fd72SJason Molenda           if (count > 0)
1132c963f20eSJim Ingham             DumpDataExtractor(packet,
1133b9c1b51eSKate Stone                 &s,                   // Stream to dump to
1134ce62fd72SJason Molenda                 offset,               // Offset within "packet"
1135ce62fd72SJason Molenda                 eFormatHex,           // Format to use
1136ce62fd72SJason Molenda                 1,                    // Size of each item in bytes
1137ce62fd72SJason Molenda                 count,                // Number of items
1138ce62fd72SJason Molenda                 16,                   // Number per line
1139ce62fd72SJason Molenda                 LLDB_INVALID_ADDRESS, // Don't show addresses before each line
1140ce62fd72SJason Molenda                 0, 0);                // No bitfields
1141ce62fd72SJason Molenda 
1142b9c1b51eSKate Stone         } break;
1143a63d08c9SGreg Clayton         }
1144a63d08c9SGreg Clayton       }
1145b9c1b51eSKate Stone     } else {
1146a63d08c9SGreg Clayton       error_desc = "error: invalid packet command: ";
1147a63d08c9SGreg Clayton     }
1148a63d08c9SGreg Clayton   }
1149a63d08c9SGreg Clayton 
1150b9c1b51eSKate Stone   if (error_desc) {
1151a63d08c9SGreg Clayton     s.PutCString(error_desc);
1152a63d08c9SGreg Clayton 
1153c963f20eSJim Ingham     DumpDataExtractor(packet,
1154c963f20eSJim Ingham                       &s,                   // Stream to dump to
1155a63d08c9SGreg Clayton                       0,                    // Offset into "packet"
1156a63d08c9SGreg Clayton                       eFormatBytes,         // Dump as hex bytes
1157c963f20eSJim Ingham                       1,                    // Size of each item is 1 for
1158c963f20eSJim Ingham                                             // single bytes
1159a63d08c9SGreg Clayton                       packet.GetByteSize(), // Number of bytes
1160a63d08c9SGreg Clayton                       UINT32_MAX,           // Num bytes per line
1161a63d08c9SGreg Clayton                       LLDB_INVALID_ADDRESS, // Base address
1162c963f20eSJim Ingham                       0, 0);                // Bitfield info set to not do
1163c963f20eSJim Ingham                                             // anything bitfield related
1164a63d08c9SGreg Clayton   }
1165a63d08c9SGreg Clayton }
1166a63d08c9SGreg Clayton 
SendRequestReadRegisters(uint32_t cpu,uint32_t flavor,void * dst,uint32_t dst_len,Status & error)1167b9c1b51eSKate Stone uint32_t CommunicationKDP::SendRequestReadRegisters(uint32_t cpu,
1168b9c1b51eSKate Stone                                                     uint32_t flavor, void *dst,
1169a63d08c9SGreg Clayton                                                     uint32_t dst_len,
117097206d57SZachary Turner                                                     Status &error) {
1171b9c1b51eSKate Stone   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
1172b9c1b51eSKate Stone                                   m_byte_order);
11735b88216dSGreg Clayton   const CommandType command = KDP_READREGS;
1174a63d08c9SGreg Clayton   // Size is header + 4 byte cpu and 4 byte flavor
1175a63d08c9SGreg Clayton   const uint32_t command_length = 8 + 4 + 4;
1176a63d08c9SGreg Clayton   MakeRequestPacketHeader(command, request_packet, command_length);
1177a63d08c9SGreg Clayton   request_packet.PutHex32(cpu);
1178a63d08c9SGreg Clayton   request_packet.PutHex32(flavor);
1179a63d08c9SGreg Clayton   DataExtractor reply_packet;
1180b9c1b51eSKate Stone   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
1181c7bece56SGreg Clayton     lldb::offset_t offset = 8;
1182a63d08c9SGreg Clayton     uint32_t kdp_error = reply_packet.GetU32(&offset);
1183a63d08c9SGreg Clayton     uint32_t src_len = reply_packet.GetByteSize() - 12;
1184a63d08c9SGreg Clayton 
1185b9c1b51eSKate Stone     if (src_len > 0) {
1186a63d08c9SGreg Clayton       const uint32_t bytes_to_copy = std::min<uint32_t>(src_len, dst_len);
1187a63d08c9SGreg Clayton       const void *src = reply_packet.GetData(&offset, bytes_to_copy);
1188b9c1b51eSKate Stone       if (src) {
1189a63d08c9SGreg Clayton         ::memcpy(dst, src, bytes_to_copy);
1190a63d08c9SGreg Clayton         error.Clear();
119105097246SAdrian Prantl         // Return the number of bytes we could have returned regardless if we
119205097246SAdrian Prantl         // copied them or not, just so we know when things don't match up
1193a63d08c9SGreg Clayton         return src_len;
1194a63d08c9SGreg Clayton       }
1195a63d08c9SGreg Clayton     }
1196a63d08c9SGreg Clayton     if (kdp_error)
1197b9c1b51eSKate Stone       error.SetErrorStringWithFormat(
1198b9c1b51eSKate Stone           "failed to read kdp registers for cpu %u flavor %u (error %u)", cpu,
1199b9c1b51eSKate Stone           flavor, kdp_error);
1200a63d08c9SGreg Clayton     else
1201b9c1b51eSKate Stone       error.SetErrorStringWithFormat(
1202b9c1b51eSKate Stone           "failed to read kdp registers for cpu %u flavor %u", cpu, flavor);
1203b9c1b51eSKate Stone   } else {
12041d19a2f2SGreg Clayton     error.SetErrorString("failed to send packet");
12051d19a2f2SGreg Clayton   }
1206a63d08c9SGreg Clayton   return 0;
1207a63d08c9SGreg Clayton }
1208a63d08c9SGreg Clayton 
SendRequestWriteRegisters(uint32_t cpu,uint32_t flavor,const void * src,uint32_t src_len,Status & error)1209b9c1b51eSKate Stone uint32_t CommunicationKDP::SendRequestWriteRegisters(uint32_t cpu,
12104b1b8b3eSGreg Clayton                                                      uint32_t flavor,
12114b1b8b3eSGreg Clayton                                                      const void *src,
12124b1b8b3eSGreg Clayton                                                      uint32_t src_len,
121397206d57SZachary Turner                                                      Status &error) {
1214b9c1b51eSKate Stone   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
1215b9c1b51eSKate Stone                                   m_byte_order);
12164b1b8b3eSGreg Clayton   const CommandType command = KDP_WRITEREGS;
12174b1b8b3eSGreg Clayton   // Size is header + 4 byte cpu and 4 byte flavor
121897d5cf05SGreg Clayton   const uint32_t command_length = 8 + 4 + 4 + src_len;
12194b1b8b3eSGreg Clayton   MakeRequestPacketHeader(command, request_packet, command_length);
12204b1b8b3eSGreg Clayton   request_packet.PutHex32(cpu);
12214b1b8b3eSGreg Clayton   request_packet.PutHex32(flavor);
12224b1b8b3eSGreg Clayton   request_packet.Write(src, src_len);
12234b1b8b3eSGreg Clayton   DataExtractor reply_packet;
1224b9c1b51eSKate Stone   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
1225c7bece56SGreg Clayton     lldb::offset_t offset = 8;
12264b1b8b3eSGreg Clayton     uint32_t kdp_error = reply_packet.GetU32(&offset);
12274b1b8b3eSGreg Clayton     if (kdp_error == 0)
12284b1b8b3eSGreg Clayton       return src_len;
1229b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
1230b9c1b51eSKate Stone         "failed to read kdp registers for cpu %u flavor %u (error %u)", cpu,
1231b9c1b51eSKate Stone         flavor, kdp_error);
1232b9c1b51eSKate Stone   } else {
12331d19a2f2SGreg Clayton     error.SetErrorString("failed to send packet");
12341d19a2f2SGreg Clayton   }
12354b1b8b3eSGreg Clayton   return 0;
12364b1b8b3eSGreg Clayton }
12374b1b8b3eSGreg Clayton 
SendRequestResume()1238b9c1b51eSKate Stone bool CommunicationKDP::SendRequestResume() {
1239b9c1b51eSKate Stone   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
1240b9c1b51eSKate Stone                                   m_byte_order);
12415b88216dSGreg Clayton   const CommandType command = KDP_RESUMECPUS;
124207e66e3eSGreg Clayton   const uint32_t command_length = 12;
124307e66e3eSGreg Clayton   MakeRequestPacketHeader(command, request_packet, command_length);
124497d5cf05SGreg Clayton   request_packet.PutHex32(GetCPUMask());
124507e66e3eSGreg Clayton 
124607e66e3eSGreg Clayton   DataExtractor reply_packet;
1247a6682a41SJonas Devlieghere   return SendRequestAndGetReply(command, request_packet, reply_packet);
124807e66e3eSGreg Clayton }
124907e66e3eSGreg Clayton 
SendRequestBreakpoint(bool set,addr_t addr)1250b9c1b51eSKate Stone bool CommunicationKDP::SendRequestBreakpoint(bool set, addr_t addr) {
1251b9c1b51eSKate Stone   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
1252b9c1b51eSKate Stone                                   m_byte_order);
125307e66e3eSGreg Clayton   bool use_64 = (GetVersion() >= 11);
125407e66e3eSGreg Clayton   uint32_t command_addr_byte_size = use_64 ? 8 : 4;
1255b9c1b51eSKate Stone   const CommandType command =
1256b9c1b51eSKate Stone       set ? (use_64 ? KDP_BREAKPOINT_SET64 : KDP_BREAKPOINT_SET)
1257b9c1b51eSKate Stone           : (use_64 ? KDP_BREAKPOINT_REMOVE64 : KDP_BREAKPOINT_REMOVE);
125807e66e3eSGreg Clayton 
125907e66e3eSGreg Clayton   const uint32_t command_length = 8 + command_addr_byte_size;
126007e66e3eSGreg Clayton   MakeRequestPacketHeader(command, request_packet, command_length);
126107e66e3eSGreg Clayton   request_packet.PutMaxHex64(addr, command_addr_byte_size);
126207e66e3eSGreg Clayton 
126307e66e3eSGreg Clayton   DataExtractor reply_packet;
1264b9c1b51eSKate Stone   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
1265c7bece56SGreg Clayton     lldb::offset_t offset = 8;
12665b442374SGreg Clayton     uint32_t kdp_error = reply_packet.GetU32(&offset);
12675b442374SGreg Clayton     if (kdp_error == 0)
126807e66e3eSGreg Clayton       return true;
12695b442374SGreg Clayton   }
127007e66e3eSGreg Clayton   return false;
127107e66e3eSGreg Clayton }
127207e66e3eSGreg Clayton 
SendRequestSuspend()1273b9c1b51eSKate Stone bool CommunicationKDP::SendRequestSuspend() {
1274b9c1b51eSKate Stone   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
1275b9c1b51eSKate Stone                                   m_byte_order);
12765b88216dSGreg Clayton   const CommandType command = KDP_SUSPEND;
127707e66e3eSGreg Clayton   const uint32_t command_length = 8;
127807e66e3eSGreg Clayton   MakeRequestPacketHeader(command, request_packet, command_length);
127907e66e3eSGreg Clayton   DataExtractor reply_packet;
1280a6682a41SJonas Devlieghere   return SendRequestAndGetReply(command, request_packet, reply_packet);
128107e66e3eSGreg Clayton }
1282