xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- CommunicationKDP.cpp ----------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "CommunicationKDP.h"
10061da546Spatrick 
11be691f3bSpatrick #include <cerrno>
12be691f3bSpatrick #include <climits>
13be691f3bSpatrick #include <cstring>
14061da546Spatrick 
15061da546Spatrick #include "lldb/Core/DumpDataExtractor.h"
16061da546Spatrick #include "lldb/Host/Host.h"
17061da546Spatrick #include "lldb/Target/Process.h"
18061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
19061da546Spatrick #include "lldb/Utility/DataExtractor.h"
20061da546Spatrick #include "lldb/Utility/FileSpec.h"
21061da546Spatrick #include "lldb/Utility/Log.h"
22061da546Spatrick #include "lldb/Utility/State.h"
23061da546Spatrick #include "lldb/Utility/UUID.h"
24061da546Spatrick 
25061da546Spatrick #include "ProcessKDPLog.h"
26061da546Spatrick 
27061da546Spatrick using namespace lldb;
28061da546Spatrick using namespace lldb_private;
29061da546Spatrick 
30061da546Spatrick // CommunicationKDP constructor
CommunicationKDP(const char * comm_name)31061da546Spatrick CommunicationKDP::CommunicationKDP(const char *comm_name)
32*f6aab3d8Srobert     : Communication(), m_addr_byte_size(4),
33061da546Spatrick       m_byte_order(eByteOrderLittle), m_packet_timeout(5), m_sequence_mutex(),
34061da546Spatrick       m_is_running(false), m_session_key(0u), m_request_sequence_id(0u),
35061da546Spatrick       m_exception_sequence_id(0u), m_kdp_version_version(0u),
36061da546Spatrick       m_kdp_version_feature(0u), m_kdp_hostinfo_cpu_mask(0u),
37061da546Spatrick       m_kdp_hostinfo_cpu_type(0u), m_kdp_hostinfo_cpu_subtype(0u) {}
38061da546Spatrick 
39061da546Spatrick // Destructor
~CommunicationKDP()40061da546Spatrick CommunicationKDP::~CommunicationKDP() {
41061da546Spatrick   if (IsConnected()) {
42061da546Spatrick     Disconnect();
43061da546Spatrick   }
44061da546Spatrick }
45061da546Spatrick 
SendRequestPacket(const PacketStreamType & request_packet)46061da546Spatrick bool CommunicationKDP::SendRequestPacket(
47061da546Spatrick     const PacketStreamType &request_packet) {
48061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_sequence_mutex);
49061da546Spatrick   return SendRequestPacketNoLock(request_packet);
50061da546Spatrick }
51061da546Spatrick 
MakeRequestPacketHeader(CommandType request_type,PacketStreamType & request_packet,uint16_t request_length)52061da546Spatrick void CommunicationKDP::MakeRequestPacketHeader(CommandType request_type,
53061da546Spatrick                                                PacketStreamType &request_packet,
54061da546Spatrick                                                uint16_t request_length) {
55061da546Spatrick   request_packet.Clear();
56061da546Spatrick   request_packet.PutHex8(request_type |
57061da546Spatrick                          ePacketTypeRequest);      // Set the request type
58061da546Spatrick   request_packet.PutHex8(m_request_sequence_id++); // Sequence number
59061da546Spatrick   request_packet.PutHex16(
60061da546Spatrick       request_length); // Length of the packet including this header
61061da546Spatrick   request_packet.PutHex32(m_session_key); // Session key
62061da546Spatrick }
63061da546Spatrick 
SendRequestAndGetReply(const CommandType command,const PacketStreamType & request_packet,DataExtractor & reply_packet)64061da546Spatrick bool CommunicationKDP::SendRequestAndGetReply(
65061da546Spatrick     const CommandType command, const PacketStreamType &request_packet,
66061da546Spatrick     DataExtractor &reply_packet) {
67061da546Spatrick   if (IsRunning()) {
68*f6aab3d8Srobert     Log *log = GetLog(KDPLog::Packets);
69061da546Spatrick     if (log) {
70061da546Spatrick       PacketStreamType log_strm;
71061da546Spatrick       DumpPacket(log_strm, request_packet.GetData(), request_packet.GetSize());
72061da546Spatrick       LLDB_LOGF(log, "error: kdp running, not sending packet: %.*s",
73061da546Spatrick                 (uint32_t)log_strm.GetSize(), log_strm.GetData());
74061da546Spatrick     }
75061da546Spatrick     return false;
76061da546Spatrick   }
77061da546Spatrick 
78061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_sequence_mutex);
79061da546Spatrick   // NOTE: this only works for packets that are in native endian byte order
80061da546Spatrick   assert(request_packet.GetSize() ==
81061da546Spatrick          *((const uint16_t *)(request_packet.GetData() + 2)));
82061da546Spatrick   lldb::offset_t offset = 1;
83061da546Spatrick   const uint32_t num_retries = 3;
84061da546Spatrick   for (uint32_t i = 0; i < num_retries; ++i) {
85061da546Spatrick     if (SendRequestPacketNoLock(request_packet)) {
86061da546Spatrick       const uint8_t request_sequence_id = (uint8_t)request_packet.GetData()[1];
87061da546Spatrick       while (true) {
88061da546Spatrick         if (WaitForPacketWithTimeoutMicroSecondsNoLock(
89061da546Spatrick                 reply_packet,
90061da546Spatrick                 std::chrono::microseconds(GetPacketTimeout()).count())) {
91061da546Spatrick           offset = 0;
92061da546Spatrick           const uint8_t reply_command = reply_packet.GetU8(&offset);
93061da546Spatrick           const uint8_t reply_sequence_id = reply_packet.GetU8(&offset);
94061da546Spatrick           if (request_sequence_id == reply_sequence_id) {
95061da546Spatrick             // The sequent ID was correct, now verify we got the response we
96061da546Spatrick             // were looking for
97061da546Spatrick             if ((reply_command & eCommandTypeMask) == command) {
98061da546Spatrick               // Success
99061da546Spatrick               if (command == KDP_RESUMECPUS)
100061da546Spatrick                 m_is_running.SetValue(true, eBroadcastAlways);
101061da546Spatrick               return true;
102061da546Spatrick             } else {
103061da546Spatrick               // Failed to get the correct response, bail
104061da546Spatrick               reply_packet.Clear();
105061da546Spatrick               return false;
106061da546Spatrick             }
107061da546Spatrick           } else if (reply_sequence_id > request_sequence_id) {
108061da546Spatrick             // Sequence ID was greater than the sequence ID of the packet we
109061da546Spatrick             // sent, something is really wrong...
110061da546Spatrick             reply_packet.Clear();
111061da546Spatrick             return false;
112061da546Spatrick           } else {
113061da546Spatrick             // The reply sequence ID was less than our current packet's
114061da546Spatrick             // sequence ID so we should keep trying to get a response because
115061da546Spatrick             // this was a response for a previous packet that we must have
116061da546Spatrick             // retried.
117061da546Spatrick           }
118061da546Spatrick         } else {
119061da546Spatrick           // Break and retry sending the packet as we didn't get a response due
120061da546Spatrick           // to timeout
121061da546Spatrick           break;
122061da546Spatrick         }
123061da546Spatrick       }
124061da546Spatrick     }
125061da546Spatrick   }
126061da546Spatrick   reply_packet.Clear();
127061da546Spatrick   return false;
128061da546Spatrick }
129061da546Spatrick 
SendRequestPacketNoLock(const PacketStreamType & request_packet)130061da546Spatrick bool CommunicationKDP::SendRequestPacketNoLock(
131061da546Spatrick     const PacketStreamType &request_packet) {
132061da546Spatrick   if (IsConnected()) {
133061da546Spatrick     const char *packet_data = request_packet.GetData();
134061da546Spatrick     const size_t packet_size = request_packet.GetSize();
135061da546Spatrick 
136*f6aab3d8Srobert     Log *log = GetLog(KDPLog::Packets);
137061da546Spatrick     if (log) {
138061da546Spatrick       PacketStreamType log_strm;
139061da546Spatrick       DumpPacket(log_strm, packet_data, packet_size);
140061da546Spatrick       LLDB_LOGF(log, "%.*s", (uint32_t)log_strm.GetSize(), log_strm.GetData());
141061da546Spatrick     }
142061da546Spatrick     ConnectionStatus status = eConnectionStatusSuccess;
143061da546Spatrick 
144061da546Spatrick     size_t bytes_written = Write(packet_data, packet_size, status, NULL);
145061da546Spatrick 
146061da546Spatrick     if (bytes_written == packet_size)
147061da546Spatrick       return true;
148061da546Spatrick 
149061da546Spatrick     LLDB_LOGF(log,
150061da546Spatrick               "error: failed to send packet entire packet %" PRIu64
151061da546Spatrick               " of %" PRIu64 " bytes sent",
152061da546Spatrick               (uint64_t)bytes_written, (uint64_t)packet_size);
153061da546Spatrick   }
154061da546Spatrick   return false;
155061da546Spatrick }
156061da546Spatrick 
GetSequenceMutex(std::unique_lock<std::recursive_mutex> & lock)157061da546Spatrick bool CommunicationKDP::GetSequenceMutex(
158061da546Spatrick     std::unique_lock<std::recursive_mutex> &lock) {
159061da546Spatrick   return (lock = std::unique_lock<std::recursive_mutex>(m_sequence_mutex,
160061da546Spatrick                                                         std::try_to_lock))
161061da546Spatrick       .owns_lock();
162061da546Spatrick }
163061da546Spatrick 
WaitForNotRunningPrivate(const std::chrono::microseconds & timeout)164061da546Spatrick bool CommunicationKDP::WaitForNotRunningPrivate(
165061da546Spatrick     const std::chrono::microseconds &timeout) {
166061da546Spatrick   return m_is_running.WaitForValueEqualTo(false, timeout);
167061da546Spatrick }
168061da546Spatrick 
169061da546Spatrick size_t
WaitForPacketWithTimeoutMicroSeconds(DataExtractor & packet,uint32_t timeout_usec)170061da546Spatrick CommunicationKDP::WaitForPacketWithTimeoutMicroSeconds(DataExtractor &packet,
171061da546Spatrick                                                        uint32_t timeout_usec) {
172061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_sequence_mutex);
173061da546Spatrick   return WaitForPacketWithTimeoutMicroSecondsNoLock(packet, timeout_usec);
174061da546Spatrick }
175061da546Spatrick 
WaitForPacketWithTimeoutMicroSecondsNoLock(DataExtractor & packet,uint32_t timeout_usec)176061da546Spatrick size_t CommunicationKDP::WaitForPacketWithTimeoutMicroSecondsNoLock(
177061da546Spatrick     DataExtractor &packet, uint32_t timeout_usec) {
178061da546Spatrick   uint8_t buffer[8192];
179061da546Spatrick   Status error;
180061da546Spatrick 
181*f6aab3d8Srobert   Log *log = GetLog(KDPLog::Packets);
182061da546Spatrick 
183061da546Spatrick   // Check for a packet from our cache first without trying any reading...
184061da546Spatrick   if (CheckForPacket(NULL, 0, packet))
185061da546Spatrick     return packet.GetByteSize();
186061da546Spatrick 
187061da546Spatrick   bool timed_out = false;
188061da546Spatrick   while (IsConnected() && !timed_out) {
189061da546Spatrick     lldb::ConnectionStatus status = eConnectionStatusNoConnection;
190061da546Spatrick     size_t bytes_read = Read(buffer, sizeof(buffer),
191061da546Spatrick                              timeout_usec == UINT32_MAX
192*f6aab3d8Srobert                                  ? Timeout<std::micro>(std::nullopt)
193061da546Spatrick                                  : std::chrono::microseconds(timeout_usec),
194061da546Spatrick                              status, &error);
195061da546Spatrick 
196061da546Spatrick     LLDB_LOGV(log,
197061da546Spatrick               "Read (buffer, sizeof(buffer), timeout_usec = 0x{0:x}, "
198061da546Spatrick               "status = {1}, error = {2}) => bytes_read = {4}",
199be691f3bSpatrick               timeout_usec, Communication::ConnectionStatusAsString(status),
200061da546Spatrick               error, bytes_read);
201061da546Spatrick 
202061da546Spatrick     if (bytes_read > 0) {
203061da546Spatrick       if (CheckForPacket(buffer, bytes_read, packet))
204061da546Spatrick         return packet.GetByteSize();
205061da546Spatrick     } else {
206061da546Spatrick       switch (status) {
207061da546Spatrick       case eConnectionStatusInterrupted:
208061da546Spatrick       case eConnectionStatusTimedOut:
209061da546Spatrick         timed_out = true;
210061da546Spatrick         break;
211061da546Spatrick       case eConnectionStatusSuccess:
212061da546Spatrick         // printf ("status = success but error = %s\n",
213061da546Spatrick         // error.AsCString("<invalid>"));
214061da546Spatrick         break;
215061da546Spatrick 
216061da546Spatrick       case eConnectionStatusEndOfFile:
217061da546Spatrick       case eConnectionStatusNoConnection:
218061da546Spatrick       case eConnectionStatusLostConnection:
219061da546Spatrick       case eConnectionStatusError:
220061da546Spatrick         Disconnect();
221061da546Spatrick         break;
222061da546Spatrick       }
223061da546Spatrick     }
224061da546Spatrick   }
225061da546Spatrick   packet.Clear();
226061da546Spatrick   return 0;
227061da546Spatrick }
228061da546Spatrick 
CheckForPacket(const uint8_t * src,size_t src_len,DataExtractor & packet)229061da546Spatrick bool CommunicationKDP::CheckForPacket(const uint8_t *src, size_t src_len,
230061da546Spatrick                                       DataExtractor &packet) {
231061da546Spatrick   // Put the packet data into the buffer in a thread safe fashion
232061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_bytes_mutex);
233061da546Spatrick 
234*f6aab3d8Srobert   Log *log = GetLog(KDPLog::Packets);
235061da546Spatrick 
236061da546Spatrick   if (src && src_len > 0) {
237061da546Spatrick     if (log && log->GetVerbose()) {
238061da546Spatrick       PacketStreamType log_strm;
239061da546Spatrick       DumpHexBytes(&log_strm, src, src_len, UINT32_MAX, LLDB_INVALID_ADDRESS);
240be691f3bSpatrick       log_strm.PutChar('\0');
241061da546Spatrick       LLDB_LOGF(log, "CommunicationKDP::%s adding %u bytes: %s", __FUNCTION__,
242061da546Spatrick                 (uint32_t)src_len, log_strm.GetData());
243061da546Spatrick     }
244061da546Spatrick     m_bytes.append((const char *)src, src_len);
245061da546Spatrick   }
246061da546Spatrick 
247061da546Spatrick   // Make sure we at least have enough bytes for a packet header
248061da546Spatrick   const size_t bytes_available = m_bytes.size();
249061da546Spatrick   if (bytes_available >= 8) {
250061da546Spatrick     packet.SetData(&m_bytes[0], bytes_available, m_byte_order);
251061da546Spatrick     lldb::offset_t offset = 0;
252061da546Spatrick     uint8_t reply_command = packet.GetU8(&offset);
253061da546Spatrick     switch (reply_command) {
254061da546Spatrick     case ePacketTypeRequest | KDP_EXCEPTION:
255061da546Spatrick     case ePacketTypeRequest | KDP_TERMINATION:
256061da546Spatrick       // We got an exception request, so be sure to send an ACK
257061da546Spatrick       {
258061da546Spatrick         PacketStreamType request_ack_packet(Stream::eBinary, m_addr_byte_size,
259061da546Spatrick                                             m_byte_order);
260061da546Spatrick         // Set the reply but and make the ACK packet
261061da546Spatrick         request_ack_packet.PutHex8(reply_command | ePacketTypeReply);
262061da546Spatrick         request_ack_packet.PutHex8(packet.GetU8(&offset));
263061da546Spatrick         request_ack_packet.PutHex16(packet.GetU16(&offset));
264061da546Spatrick         request_ack_packet.PutHex32(packet.GetU32(&offset));
265061da546Spatrick         m_is_running.SetValue(false, eBroadcastAlways);
266061da546Spatrick         // Ack to the exception or termination
267061da546Spatrick         SendRequestPacketNoLock(request_ack_packet);
268061da546Spatrick       }
269061da546Spatrick       // Fall through to case below to get packet contents
270*f6aab3d8Srobert       [[fallthrough]];
271061da546Spatrick     case ePacketTypeReply | KDP_CONNECT:
272061da546Spatrick     case ePacketTypeReply | KDP_DISCONNECT:
273061da546Spatrick     case ePacketTypeReply | KDP_HOSTINFO:
274061da546Spatrick     case ePacketTypeReply | KDP_VERSION:
275061da546Spatrick     case ePacketTypeReply | KDP_MAXBYTES:
276061da546Spatrick     case ePacketTypeReply | KDP_READMEM:
277061da546Spatrick     case ePacketTypeReply | KDP_WRITEMEM:
278061da546Spatrick     case ePacketTypeReply | KDP_READREGS:
279061da546Spatrick     case ePacketTypeReply | KDP_WRITEREGS:
280061da546Spatrick     case ePacketTypeReply | KDP_LOAD:
281061da546Spatrick     case ePacketTypeReply | KDP_IMAGEPATH:
282061da546Spatrick     case ePacketTypeReply | KDP_SUSPEND:
283061da546Spatrick     case ePacketTypeReply | KDP_RESUMECPUS:
284061da546Spatrick     case ePacketTypeReply | KDP_BREAKPOINT_SET:
285061da546Spatrick     case ePacketTypeReply | KDP_BREAKPOINT_REMOVE:
286061da546Spatrick     case ePacketTypeReply | KDP_REGIONS:
287061da546Spatrick     case ePacketTypeReply | KDP_REATTACH:
288061da546Spatrick     case ePacketTypeReply | KDP_HOSTREBOOT:
289061da546Spatrick     case ePacketTypeReply | KDP_READMEM64:
290061da546Spatrick     case ePacketTypeReply | KDP_WRITEMEM64:
291061da546Spatrick     case ePacketTypeReply | KDP_BREAKPOINT_SET64:
292061da546Spatrick     case ePacketTypeReply | KDP_BREAKPOINT_REMOVE64:
293061da546Spatrick     case ePacketTypeReply | KDP_KERNELVERSION:
294061da546Spatrick     case ePacketTypeReply | KDP_READPHYSMEM64:
295061da546Spatrick     case ePacketTypeReply | KDP_WRITEPHYSMEM64:
296061da546Spatrick     case ePacketTypeReply | KDP_READIOPORT:
297061da546Spatrick     case ePacketTypeReply | KDP_WRITEIOPORT:
298061da546Spatrick     case ePacketTypeReply | KDP_READMSR64:
299061da546Spatrick     case ePacketTypeReply | KDP_WRITEMSR64:
300061da546Spatrick     case ePacketTypeReply | KDP_DUMPINFO: {
301061da546Spatrick       offset = 2;
302061da546Spatrick       const uint16_t length = packet.GetU16(&offset);
303061da546Spatrick       if (length <= bytes_available) {
304061da546Spatrick         // We have an entire packet ready, we need to copy the data bytes into
305061da546Spatrick         // a buffer that will be owned by the packet and erase the bytes from
306dda28197Spatrick         // our communication buffer "m_bytes"
307061da546Spatrick         packet.SetData(DataBufferSP(new DataBufferHeap(&m_bytes[0], length)));
308061da546Spatrick         m_bytes.erase(0, length);
309061da546Spatrick 
310061da546Spatrick         if (log) {
311061da546Spatrick           PacketStreamType log_strm;
312061da546Spatrick           DumpPacket(log_strm, packet);
313061da546Spatrick 
314061da546Spatrick           LLDB_LOGF(log, "%.*s", (uint32_t)log_strm.GetSize(),
315061da546Spatrick                     log_strm.GetData());
316061da546Spatrick         }
317061da546Spatrick         return true;
318061da546Spatrick       }
319061da546Spatrick     } break;
320061da546Spatrick 
321061da546Spatrick     default:
322061da546Spatrick       // Unrecognized reply command byte, erase this byte and try to get back
323061da546Spatrick       // on track
324061da546Spatrick       LLDB_LOGF(log, "CommunicationKDP::%s: tossing junk byte: 0x%2.2x",
325061da546Spatrick                 __FUNCTION__, (uint8_t)m_bytes[0]);
326061da546Spatrick       m_bytes.erase(0, 1);
327061da546Spatrick       break;
328061da546Spatrick     }
329061da546Spatrick   }
330061da546Spatrick   packet.Clear();
331061da546Spatrick   return false;
332061da546Spatrick }
333061da546Spatrick 
SendRequestConnect(uint16_t reply_port,uint16_t exc_port,const char * greeting)334061da546Spatrick bool CommunicationKDP::SendRequestConnect(uint16_t reply_port,
335061da546Spatrick                                           uint16_t exc_port,
336061da546Spatrick                                           const char *greeting) {
337061da546Spatrick   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
338061da546Spatrick                                   m_byte_order);
339061da546Spatrick   if (greeting == NULL)
340061da546Spatrick     greeting = "";
341061da546Spatrick 
342061da546Spatrick   const CommandType command = KDP_CONNECT;
343061da546Spatrick   // Length is 82 uint16_t and the length of the greeting C string with the
344061da546Spatrick   // terminating NULL
345061da546Spatrick   const uint32_t command_length = 8 + 2 + 2 + ::strlen(greeting) + 1;
346061da546Spatrick   MakeRequestPacketHeader(command, request_packet, command_length);
347061da546Spatrick   // Always send connect ports as little endian
348061da546Spatrick   request_packet.SetByteOrder(eByteOrderLittle);
349061da546Spatrick   request_packet.PutHex16(htons(reply_port));
350061da546Spatrick   request_packet.PutHex16(htons(exc_port));
351061da546Spatrick   request_packet.SetByteOrder(m_byte_order);
352061da546Spatrick   request_packet.PutCString(greeting);
353061da546Spatrick   DataExtractor reply_packet;
354061da546Spatrick   return SendRequestAndGetReply(command, request_packet, reply_packet);
355061da546Spatrick }
356061da546Spatrick 
ClearKDPSettings()357061da546Spatrick void CommunicationKDP::ClearKDPSettings() {
358061da546Spatrick   m_request_sequence_id = 0;
359061da546Spatrick   m_kdp_version_version = 0;
360061da546Spatrick   m_kdp_version_feature = 0;
361061da546Spatrick   m_kdp_hostinfo_cpu_mask = 0;
362061da546Spatrick   m_kdp_hostinfo_cpu_type = 0;
363061da546Spatrick   m_kdp_hostinfo_cpu_subtype = 0;
364061da546Spatrick }
365061da546Spatrick 
SendRequestReattach(uint16_t reply_port)366061da546Spatrick bool CommunicationKDP::SendRequestReattach(uint16_t reply_port) {
367061da546Spatrick   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
368061da546Spatrick                                   m_byte_order);
369061da546Spatrick   const CommandType command = KDP_REATTACH;
370061da546Spatrick   // Length is 8 bytes for the header plus 2 bytes for the reply UDP port
371061da546Spatrick   const uint32_t command_length = 8 + 2;
372061da546Spatrick   MakeRequestPacketHeader(command, request_packet, command_length);
373061da546Spatrick   // Always send connect ports as little endian
374061da546Spatrick   request_packet.SetByteOrder(eByteOrderLittle);
375061da546Spatrick   request_packet.PutHex16(htons(reply_port));
376061da546Spatrick   request_packet.SetByteOrder(m_byte_order);
377061da546Spatrick   DataExtractor reply_packet;
378061da546Spatrick   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
379061da546Spatrick     // Reset the sequence ID to zero for reattach
380061da546Spatrick     ClearKDPSettings();
381061da546Spatrick     lldb::offset_t offset = 4;
382061da546Spatrick     m_session_key = reply_packet.GetU32(&offset);
383061da546Spatrick     return true;
384061da546Spatrick   }
385061da546Spatrick   return false;
386061da546Spatrick }
387061da546Spatrick 
GetVersion()388061da546Spatrick uint32_t CommunicationKDP::GetVersion() {
389061da546Spatrick   if (!VersionIsValid())
390061da546Spatrick     SendRequestVersion();
391061da546Spatrick   return m_kdp_version_version;
392061da546Spatrick }
393061da546Spatrick 
GetFeatureFlags()394061da546Spatrick uint32_t CommunicationKDP::GetFeatureFlags() {
395061da546Spatrick   if (!VersionIsValid())
396061da546Spatrick     SendRequestVersion();
397061da546Spatrick   return m_kdp_version_feature;
398061da546Spatrick }
399061da546Spatrick 
SendRequestVersion()400061da546Spatrick bool CommunicationKDP::SendRequestVersion() {
401061da546Spatrick   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
402061da546Spatrick                                   m_byte_order);
403061da546Spatrick   const CommandType command = KDP_VERSION;
404061da546Spatrick   const uint32_t command_length = 8;
405061da546Spatrick   MakeRequestPacketHeader(command, request_packet, command_length);
406061da546Spatrick   DataExtractor reply_packet;
407061da546Spatrick   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
408061da546Spatrick     lldb::offset_t offset = 8;
409061da546Spatrick     m_kdp_version_version = reply_packet.GetU32(&offset);
410061da546Spatrick     m_kdp_version_feature = reply_packet.GetU32(&offset);
411061da546Spatrick     return true;
412061da546Spatrick   }
413061da546Spatrick   return false;
414061da546Spatrick }
415061da546Spatrick 
GetCPUMask()416061da546Spatrick uint32_t CommunicationKDP::GetCPUMask() {
417061da546Spatrick   if (!HostInfoIsValid())
418061da546Spatrick     SendRequestHostInfo();
419061da546Spatrick   return m_kdp_hostinfo_cpu_mask;
420061da546Spatrick }
421061da546Spatrick 
GetCPUType()422061da546Spatrick uint32_t CommunicationKDP::GetCPUType() {
423061da546Spatrick   if (!HostInfoIsValid())
424061da546Spatrick     SendRequestHostInfo();
425061da546Spatrick   return m_kdp_hostinfo_cpu_type;
426061da546Spatrick }
427061da546Spatrick 
GetCPUSubtype()428061da546Spatrick uint32_t CommunicationKDP::GetCPUSubtype() {
429061da546Spatrick   if (!HostInfoIsValid())
430061da546Spatrick     SendRequestHostInfo();
431061da546Spatrick   return m_kdp_hostinfo_cpu_subtype;
432061da546Spatrick }
433061da546Spatrick 
GetUUID()434061da546Spatrick lldb_private::UUID CommunicationKDP::GetUUID() {
435061da546Spatrick   UUID uuid;
436061da546Spatrick   if (GetKernelVersion() == NULL)
437061da546Spatrick     return uuid;
438061da546Spatrick 
439061da546Spatrick   if (m_kernel_version.find("UUID=") == std::string::npos)
440061da546Spatrick     return uuid;
441061da546Spatrick 
442061da546Spatrick   size_t p = m_kernel_version.find("UUID=") + strlen("UUID=");
443061da546Spatrick   std::string uuid_str = m_kernel_version.substr(p, 36);
444061da546Spatrick   if (uuid_str.size() < 32)
445061da546Spatrick     return uuid;
446061da546Spatrick 
447dda28197Spatrick   if (!uuid.SetFromStringRef(uuid_str)) {
448061da546Spatrick     UUID invalid_uuid;
449061da546Spatrick     return invalid_uuid;
450061da546Spatrick   }
451061da546Spatrick 
452061da546Spatrick   return uuid;
453061da546Spatrick }
454061da546Spatrick 
RemoteIsEFI()455061da546Spatrick bool CommunicationKDP::RemoteIsEFI() {
456061da546Spatrick   if (GetKernelVersion() == NULL)
457061da546Spatrick     return false;
458061da546Spatrick   return strncmp(m_kernel_version.c_str(), "EFI", 3) == 0;
459061da546Spatrick }
460061da546Spatrick 
RemoteIsDarwinKernel()461061da546Spatrick bool CommunicationKDP::RemoteIsDarwinKernel() {
462061da546Spatrick   if (GetKernelVersion() == NULL)
463061da546Spatrick     return false;
464061da546Spatrick   return m_kernel_version.find("Darwin Kernel") != std::string::npos;
465061da546Spatrick }
466061da546Spatrick 
GetLoadAddress()467061da546Spatrick lldb::addr_t CommunicationKDP::GetLoadAddress() {
468061da546Spatrick   if (GetKernelVersion() == NULL)
469061da546Spatrick     return LLDB_INVALID_ADDRESS;
470061da546Spatrick 
471061da546Spatrick   if (m_kernel_version.find("stext=") == std::string::npos)
472061da546Spatrick     return LLDB_INVALID_ADDRESS;
473061da546Spatrick   size_t p = m_kernel_version.find("stext=") + strlen("stext=");
474061da546Spatrick   if (m_kernel_version[p] != '0' || m_kernel_version[p + 1] != 'x')
475061da546Spatrick     return LLDB_INVALID_ADDRESS;
476061da546Spatrick 
477061da546Spatrick   addr_t kernel_load_address;
478061da546Spatrick   errno = 0;
479061da546Spatrick   kernel_load_address = ::strtoul(m_kernel_version.c_str() + p, NULL, 16);
480061da546Spatrick   if (errno != 0 || kernel_load_address == 0)
481061da546Spatrick     return LLDB_INVALID_ADDRESS;
482061da546Spatrick 
483061da546Spatrick   return kernel_load_address;
484061da546Spatrick }
485061da546Spatrick 
SendRequestHostInfo()486061da546Spatrick bool CommunicationKDP::SendRequestHostInfo() {
487061da546Spatrick   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
488061da546Spatrick                                   m_byte_order);
489061da546Spatrick   const CommandType command = KDP_HOSTINFO;
490061da546Spatrick   const uint32_t command_length = 8;
491061da546Spatrick   MakeRequestPacketHeader(command, request_packet, command_length);
492061da546Spatrick   DataExtractor reply_packet;
493061da546Spatrick   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
494061da546Spatrick     lldb::offset_t offset = 8;
495061da546Spatrick     m_kdp_hostinfo_cpu_mask = reply_packet.GetU32(&offset);
496061da546Spatrick     m_kdp_hostinfo_cpu_type = reply_packet.GetU32(&offset);
497061da546Spatrick     m_kdp_hostinfo_cpu_subtype = reply_packet.GetU32(&offset);
498061da546Spatrick 
499061da546Spatrick     ArchSpec kernel_arch;
500061da546Spatrick     kernel_arch.SetArchitecture(eArchTypeMachO, m_kdp_hostinfo_cpu_type,
501061da546Spatrick                                 m_kdp_hostinfo_cpu_subtype);
502061da546Spatrick 
503061da546Spatrick     m_addr_byte_size = kernel_arch.GetAddressByteSize();
504061da546Spatrick     m_byte_order = kernel_arch.GetByteOrder();
505061da546Spatrick     return true;
506061da546Spatrick   }
507061da546Spatrick   return false;
508061da546Spatrick }
509061da546Spatrick 
GetKernelVersion()510061da546Spatrick const char *CommunicationKDP::GetKernelVersion() {
511061da546Spatrick   if (m_kernel_version.empty())
512061da546Spatrick     SendRequestKernelVersion();
513061da546Spatrick   return m_kernel_version.c_str();
514061da546Spatrick }
515061da546Spatrick 
SendRequestKernelVersion()516061da546Spatrick bool CommunicationKDP::SendRequestKernelVersion() {
517061da546Spatrick   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
518061da546Spatrick                                   m_byte_order);
519061da546Spatrick   const CommandType command = KDP_KERNELVERSION;
520061da546Spatrick   const uint32_t command_length = 8;
521061da546Spatrick   MakeRequestPacketHeader(command, request_packet, command_length);
522061da546Spatrick   DataExtractor reply_packet;
523061da546Spatrick   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
524061da546Spatrick     const char *kernel_version_cstr = reply_packet.PeekCStr(8);
525061da546Spatrick     if (kernel_version_cstr && kernel_version_cstr[0])
526061da546Spatrick       m_kernel_version.assign(kernel_version_cstr);
527061da546Spatrick     return true;
528061da546Spatrick   }
529061da546Spatrick   return false;
530061da546Spatrick }
531061da546Spatrick 
SendRequestDisconnect()532061da546Spatrick bool CommunicationKDP::SendRequestDisconnect() {
533061da546Spatrick   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
534061da546Spatrick                                   m_byte_order);
535061da546Spatrick   const CommandType command = KDP_DISCONNECT;
536061da546Spatrick   const uint32_t command_length = 8;
537061da546Spatrick   MakeRequestPacketHeader(command, request_packet, command_length);
538061da546Spatrick   DataExtractor reply_packet;
539061da546Spatrick   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
540061da546Spatrick     // Are we supposed to get a reply for disconnect?
541061da546Spatrick   }
542061da546Spatrick   ClearKDPSettings();
543061da546Spatrick   return true;
544061da546Spatrick }
545061da546Spatrick 
SendRequestReadMemory(lldb::addr_t addr,void * dst,uint32_t dst_len,Status & error)546061da546Spatrick uint32_t CommunicationKDP::SendRequestReadMemory(lldb::addr_t addr, void *dst,
547061da546Spatrick                                                  uint32_t dst_len,
548061da546Spatrick                                                  Status &error) {
549061da546Spatrick   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
550061da546Spatrick                                   m_byte_order);
551061da546Spatrick   bool use_64 = (GetVersion() >= 11);
552061da546Spatrick   uint32_t command_addr_byte_size = use_64 ? 8 : 4;
553061da546Spatrick   const CommandType command = use_64 ? KDP_READMEM64 : KDP_READMEM;
554061da546Spatrick   // Size is header + address size + uint32_t length
555061da546Spatrick   const uint32_t command_length = 8 + command_addr_byte_size + 4;
556061da546Spatrick   MakeRequestPacketHeader(command, request_packet, command_length);
557061da546Spatrick   request_packet.PutMaxHex64(addr, command_addr_byte_size);
558061da546Spatrick   request_packet.PutHex32(dst_len);
559061da546Spatrick   DataExtractor reply_packet;
560061da546Spatrick   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
561061da546Spatrick     lldb::offset_t offset = 8;
562061da546Spatrick     uint32_t kdp_error = reply_packet.GetU32(&offset);
563061da546Spatrick     uint32_t src_len = reply_packet.GetByteSize() - 12;
564061da546Spatrick 
565061da546Spatrick     if (src_len > 0) {
566061da546Spatrick       const void *src = reply_packet.GetData(&offset, src_len);
567061da546Spatrick       if (src) {
568061da546Spatrick         ::memcpy(dst, src, src_len);
569061da546Spatrick         error.Clear();
570061da546Spatrick         return src_len;
571061da546Spatrick       }
572061da546Spatrick     }
573061da546Spatrick     if (kdp_error)
574061da546Spatrick       error.SetErrorStringWithFormat("kdp read memory failed (error %u)",
575061da546Spatrick                                      kdp_error);
576061da546Spatrick     else
577061da546Spatrick       error.SetErrorString("kdp read memory failed");
578061da546Spatrick   } else {
579061da546Spatrick     error.SetErrorString("failed to send packet");
580061da546Spatrick   }
581061da546Spatrick   return 0;
582061da546Spatrick }
583061da546Spatrick 
SendRequestWriteMemory(lldb::addr_t addr,const void * src,uint32_t src_len,Status & error)584061da546Spatrick uint32_t CommunicationKDP::SendRequestWriteMemory(lldb::addr_t addr,
585061da546Spatrick                                                   const void *src,
586061da546Spatrick                                                   uint32_t src_len,
587061da546Spatrick                                                   Status &error) {
588061da546Spatrick   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
589061da546Spatrick                                   m_byte_order);
590061da546Spatrick   bool use_64 = (GetVersion() >= 11);
591061da546Spatrick   uint32_t command_addr_byte_size = use_64 ? 8 : 4;
592061da546Spatrick   const CommandType command = use_64 ? KDP_WRITEMEM64 : KDP_WRITEMEM;
593061da546Spatrick   // Size is header + address size + uint32_t length
594061da546Spatrick   const uint32_t command_length = 8 + command_addr_byte_size + 4 + src_len;
595061da546Spatrick   MakeRequestPacketHeader(command, request_packet, command_length);
596061da546Spatrick   request_packet.PutMaxHex64(addr, command_addr_byte_size);
597061da546Spatrick   request_packet.PutHex32(src_len);
598061da546Spatrick   request_packet.PutRawBytes(src, src_len);
599061da546Spatrick 
600061da546Spatrick   DataExtractor reply_packet;
601061da546Spatrick   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
602061da546Spatrick     lldb::offset_t offset = 8;
603061da546Spatrick     uint32_t kdp_error = reply_packet.GetU32(&offset);
604061da546Spatrick     if (kdp_error)
605061da546Spatrick       error.SetErrorStringWithFormat("kdp write memory failed (error %u)",
606061da546Spatrick                                      kdp_error);
607061da546Spatrick     else {
608061da546Spatrick       error.Clear();
609061da546Spatrick       return src_len;
610061da546Spatrick     }
611061da546Spatrick   } else {
612061da546Spatrick     error.SetErrorString("failed to send packet");
613061da546Spatrick   }
614061da546Spatrick   return 0;
615061da546Spatrick }
616061da546Spatrick 
SendRawRequest(uint8_t command_byte,const void * src,uint32_t src_len,DataExtractor & reply_packet,Status & error)617061da546Spatrick bool CommunicationKDP::SendRawRequest(
618061da546Spatrick     uint8_t command_byte,
619061da546Spatrick     const void *src,  // Raw packet payload bytes
620061da546Spatrick     uint32_t src_len, // Raw packet payload length
621061da546Spatrick     DataExtractor &reply_packet, Status &error) {
622061da546Spatrick   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
623061da546Spatrick                                   m_byte_order);
624061da546Spatrick   // Size is header + address size + uint32_t length
625061da546Spatrick   const uint32_t command_length = 8 + src_len;
626061da546Spatrick   const CommandType command = (CommandType)command_byte;
627061da546Spatrick   MakeRequestPacketHeader(command, request_packet, command_length);
628061da546Spatrick   request_packet.PutRawBytes(src, src_len);
629061da546Spatrick 
630061da546Spatrick   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
631061da546Spatrick     lldb::offset_t offset = 8;
632061da546Spatrick     uint32_t kdp_error = reply_packet.GetU32(&offset);
633061da546Spatrick     if (kdp_error && (command_byte != KDP_DUMPINFO))
634061da546Spatrick       error.SetErrorStringWithFormat("request packet 0x%8.8x failed (error %u)",
635061da546Spatrick                                      command_byte, kdp_error);
636061da546Spatrick     else {
637061da546Spatrick       error.Clear();
638061da546Spatrick       return true;
639061da546Spatrick     }
640061da546Spatrick   } else {
641061da546Spatrick     error.SetErrorString("failed to send packet");
642061da546Spatrick   }
643061da546Spatrick   return false;
644061da546Spatrick }
645061da546Spatrick 
GetCommandAsCString(uint8_t command)646061da546Spatrick const char *CommunicationKDP::GetCommandAsCString(uint8_t command) {
647061da546Spatrick   switch (command) {
648061da546Spatrick   case KDP_CONNECT:
649061da546Spatrick     return "KDP_CONNECT";
650061da546Spatrick   case KDP_DISCONNECT:
651061da546Spatrick     return "KDP_DISCONNECT";
652061da546Spatrick   case KDP_HOSTINFO:
653061da546Spatrick     return "KDP_HOSTINFO";
654061da546Spatrick   case KDP_VERSION:
655061da546Spatrick     return "KDP_VERSION";
656061da546Spatrick   case KDP_MAXBYTES:
657061da546Spatrick     return "KDP_MAXBYTES";
658061da546Spatrick   case KDP_READMEM:
659061da546Spatrick     return "KDP_READMEM";
660061da546Spatrick   case KDP_WRITEMEM:
661061da546Spatrick     return "KDP_WRITEMEM";
662061da546Spatrick   case KDP_READREGS:
663061da546Spatrick     return "KDP_READREGS";
664061da546Spatrick   case KDP_WRITEREGS:
665061da546Spatrick     return "KDP_WRITEREGS";
666061da546Spatrick   case KDP_LOAD:
667061da546Spatrick     return "KDP_LOAD";
668061da546Spatrick   case KDP_IMAGEPATH:
669061da546Spatrick     return "KDP_IMAGEPATH";
670061da546Spatrick   case KDP_SUSPEND:
671061da546Spatrick     return "KDP_SUSPEND";
672061da546Spatrick   case KDP_RESUMECPUS:
673061da546Spatrick     return "KDP_RESUMECPUS";
674061da546Spatrick   case KDP_EXCEPTION:
675061da546Spatrick     return "KDP_EXCEPTION";
676061da546Spatrick   case KDP_TERMINATION:
677061da546Spatrick     return "KDP_TERMINATION";
678061da546Spatrick   case KDP_BREAKPOINT_SET:
679061da546Spatrick     return "KDP_BREAKPOINT_SET";
680061da546Spatrick   case KDP_BREAKPOINT_REMOVE:
681061da546Spatrick     return "KDP_BREAKPOINT_REMOVE";
682061da546Spatrick   case KDP_REGIONS:
683061da546Spatrick     return "KDP_REGIONS";
684061da546Spatrick   case KDP_REATTACH:
685061da546Spatrick     return "KDP_REATTACH";
686061da546Spatrick   case KDP_HOSTREBOOT:
687061da546Spatrick     return "KDP_HOSTREBOOT";
688061da546Spatrick   case KDP_READMEM64:
689061da546Spatrick     return "KDP_READMEM64";
690061da546Spatrick   case KDP_WRITEMEM64:
691061da546Spatrick     return "KDP_WRITEMEM64";
692061da546Spatrick   case KDP_BREAKPOINT_SET64:
693061da546Spatrick     return "KDP_BREAKPOINT64_SET";
694061da546Spatrick   case KDP_BREAKPOINT_REMOVE64:
695061da546Spatrick     return "KDP_BREAKPOINT64_REMOVE";
696061da546Spatrick   case KDP_KERNELVERSION:
697061da546Spatrick     return "KDP_KERNELVERSION";
698061da546Spatrick   case KDP_READPHYSMEM64:
699061da546Spatrick     return "KDP_READPHYSMEM64";
700061da546Spatrick   case KDP_WRITEPHYSMEM64:
701061da546Spatrick     return "KDP_WRITEPHYSMEM64";
702061da546Spatrick   case KDP_READIOPORT:
703061da546Spatrick     return "KDP_READIOPORT";
704061da546Spatrick   case KDP_WRITEIOPORT:
705061da546Spatrick     return "KDP_WRITEIOPORT";
706061da546Spatrick   case KDP_READMSR64:
707061da546Spatrick     return "KDP_READMSR64";
708061da546Spatrick   case KDP_WRITEMSR64:
709061da546Spatrick     return "KDP_WRITEMSR64";
710061da546Spatrick   case KDP_DUMPINFO:
711061da546Spatrick     return "KDP_DUMPINFO";
712061da546Spatrick   }
713061da546Spatrick   return NULL;
714061da546Spatrick }
715061da546Spatrick 
DumpPacket(Stream & s,const void * data,uint32_t data_len)716061da546Spatrick void CommunicationKDP::DumpPacket(Stream &s, const void *data,
717061da546Spatrick                                   uint32_t data_len) {
718061da546Spatrick   DataExtractor extractor(data, data_len, m_byte_order, m_addr_byte_size);
719061da546Spatrick   DumpPacket(s, extractor);
720061da546Spatrick }
721061da546Spatrick 
DumpPacket(Stream & s,const DataExtractor & packet)722061da546Spatrick void CommunicationKDP::DumpPacket(Stream &s, const DataExtractor &packet) {
723061da546Spatrick   const char *error_desc = NULL;
724061da546Spatrick   if (packet.GetByteSize() < 8) {
725061da546Spatrick     error_desc = "error: invalid packet (too short): ";
726061da546Spatrick   } else {
727061da546Spatrick     lldb::offset_t offset = 0;
728061da546Spatrick     const uint8_t first_packet_byte = packet.GetU8(&offset);
729061da546Spatrick     const uint8_t sequence_id = packet.GetU8(&offset);
730061da546Spatrick     const uint16_t length = packet.GetU16(&offset);
731061da546Spatrick     const uint32_t key = packet.GetU32(&offset);
732061da546Spatrick     const CommandType command = ExtractCommand(first_packet_byte);
733061da546Spatrick     const char *command_name = GetCommandAsCString(command);
734061da546Spatrick     if (command_name) {
735061da546Spatrick       const bool is_reply = ExtractIsReply(first_packet_byte);
736061da546Spatrick       s.Printf("(running=%i) %s %24s: 0x%2.2x 0x%2.2x 0x%4.4x 0x%8.8x ",
737061da546Spatrick                IsRunning(), is_reply ? "<--" : "-->", command_name,
738061da546Spatrick                first_packet_byte, sequence_id, length, key);
739061da546Spatrick 
740061da546Spatrick       if (is_reply) {
741061da546Spatrick         // Dump request reply packets
742061da546Spatrick         switch (command) {
743061da546Spatrick         // Commands that return a single 32 bit error
744061da546Spatrick         case KDP_CONNECT:
745061da546Spatrick         case KDP_WRITEMEM:
746061da546Spatrick         case KDP_WRITEMEM64:
747061da546Spatrick         case KDP_BREAKPOINT_SET:
748061da546Spatrick         case KDP_BREAKPOINT_REMOVE:
749061da546Spatrick         case KDP_BREAKPOINT_SET64:
750061da546Spatrick         case KDP_BREAKPOINT_REMOVE64:
751061da546Spatrick         case KDP_WRITEREGS:
752061da546Spatrick         case KDP_LOAD:
753061da546Spatrick         case KDP_WRITEIOPORT:
754061da546Spatrick         case KDP_WRITEMSR64: {
755061da546Spatrick           const uint32_t error = packet.GetU32(&offset);
756061da546Spatrick           s.Printf(" (error=0x%8.8x)", error);
757061da546Spatrick         } break;
758061da546Spatrick 
759061da546Spatrick         case KDP_DISCONNECT:
760061da546Spatrick         case KDP_REATTACH:
761061da546Spatrick         case KDP_HOSTREBOOT:
762061da546Spatrick         case KDP_SUSPEND:
763061da546Spatrick         case KDP_RESUMECPUS:
764061da546Spatrick         case KDP_EXCEPTION:
765061da546Spatrick         case KDP_TERMINATION:
766061da546Spatrick           // No return value for the reply, just the header to ack
767061da546Spatrick           s.PutCString(" ()");
768061da546Spatrick           break;
769061da546Spatrick 
770061da546Spatrick         case KDP_HOSTINFO: {
771061da546Spatrick           const uint32_t cpu_mask = packet.GetU32(&offset);
772061da546Spatrick           const uint32_t cpu_type = packet.GetU32(&offset);
773061da546Spatrick           const uint32_t cpu_subtype = packet.GetU32(&offset);
774061da546Spatrick           s.Printf(" (cpu_mask=0x%8.8x, cpu_type=0x%8.8x, cpu_subtype=0x%8.8x)",
775061da546Spatrick                    cpu_mask, cpu_type, cpu_subtype);
776061da546Spatrick         } break;
777061da546Spatrick 
778061da546Spatrick         case KDP_VERSION: {
779061da546Spatrick           const uint32_t version = packet.GetU32(&offset);
780061da546Spatrick           const uint32_t feature = packet.GetU32(&offset);
781061da546Spatrick           s.Printf(" (version=0x%8.8x, feature=0x%8.8x)", version, feature);
782061da546Spatrick         } break;
783061da546Spatrick 
784061da546Spatrick         case KDP_REGIONS: {
785061da546Spatrick           const uint32_t region_count = packet.GetU32(&offset);
786061da546Spatrick           s.Printf(" (count = %u", region_count);
787061da546Spatrick           for (uint32_t i = 0; i < region_count; ++i) {
788dda28197Spatrick             const addr_t region_addr = packet.GetAddress(&offset);
789061da546Spatrick             const uint32_t region_size = packet.GetU32(&offset);
790061da546Spatrick             const uint32_t region_prot = packet.GetU32(&offset);
791061da546Spatrick             s.Printf("\n\tregion[%" PRIu64 "] = { range = [0x%16.16" PRIx64
792061da546Spatrick                      " - 0x%16.16" PRIx64 "), size = 0x%8.8x, prot = %s }",
793061da546Spatrick                      region_addr, region_addr, region_addr + region_size,
794061da546Spatrick                      region_size, GetPermissionsAsCString(region_prot));
795061da546Spatrick           }
796061da546Spatrick         } break;
797061da546Spatrick 
798061da546Spatrick         case KDP_READMEM:
799061da546Spatrick         case KDP_READMEM64:
800061da546Spatrick         case KDP_READPHYSMEM64: {
801061da546Spatrick           const uint32_t error = packet.GetU32(&offset);
802061da546Spatrick           const uint32_t count = packet.GetByteSize() - offset;
803061da546Spatrick           s.Printf(" (error = 0x%8.8x:\n", error);
804061da546Spatrick           if (count > 0)
805061da546Spatrick             DumpDataExtractor(packet,
806061da546Spatrick                               &s,                      // Stream to dump to
807061da546Spatrick                               offset,                  // Offset within "packet"
808061da546Spatrick                               eFormatBytesWithASCII,   // Format to use
809061da546Spatrick                               1,                       // Size of each item
810061da546Spatrick                                                        // in bytes
811061da546Spatrick                               count,                   // Number of items
812061da546Spatrick                               16,                      // Number per line
813061da546Spatrick                               m_last_read_memory_addr, // Don't show addresses
814061da546Spatrick                                                        // before each line
815061da546Spatrick                               0, 0);                   // No bitfields
816061da546Spatrick         } break;
817061da546Spatrick 
818061da546Spatrick         case KDP_READREGS: {
819061da546Spatrick           const uint32_t error = packet.GetU32(&offset);
820061da546Spatrick           const uint32_t count = packet.GetByteSize() - offset;
821061da546Spatrick           s.Printf(" (error = 0x%8.8x regs:\n", error);
822061da546Spatrick           if (count > 0)
823061da546Spatrick             DumpDataExtractor(packet,
824061da546Spatrick                               &s,                       // Stream to dump to
825061da546Spatrick                               offset,                   // Offset within "packet"
826061da546Spatrick                               eFormatHex,               // Format to use
827061da546Spatrick                               m_addr_byte_size,         // Size of each item
828061da546Spatrick                                                         // in bytes
829061da546Spatrick                               count / m_addr_byte_size, // Number of items
830061da546Spatrick                               16 / m_addr_byte_size,    // Number per line
831061da546Spatrick                               LLDB_INVALID_ADDRESS,
832061da546Spatrick                                                         // Don't
833061da546Spatrick                                                         // show addresses before
834061da546Spatrick                                                         // each line
835061da546Spatrick                               0, 0);                    // No bitfields
836061da546Spatrick         } break;
837061da546Spatrick 
838061da546Spatrick         case KDP_KERNELVERSION: {
839061da546Spatrick           const char *kernel_version = packet.PeekCStr(8);
840061da546Spatrick           s.Printf(" (version = \"%s\")", kernel_version);
841061da546Spatrick         } break;
842061da546Spatrick 
843061da546Spatrick         case KDP_MAXBYTES: {
844061da546Spatrick           const uint32_t max_bytes = packet.GetU32(&offset);
845061da546Spatrick           s.Printf(" (max_bytes = 0x%8.8x (%u))", max_bytes, max_bytes);
846061da546Spatrick         } break;
847061da546Spatrick         case KDP_IMAGEPATH: {
848061da546Spatrick           const char *path = packet.GetCStr(&offset);
849061da546Spatrick           s.Printf(" (path = \"%s\")", path);
850061da546Spatrick         } break;
851061da546Spatrick 
852061da546Spatrick         case KDP_READIOPORT:
853061da546Spatrick         case KDP_READMSR64: {
854061da546Spatrick           const uint32_t error = packet.GetU32(&offset);
855061da546Spatrick           const uint32_t count = packet.GetByteSize() - offset;
856061da546Spatrick           s.Printf(" (error = 0x%8.8x io:\n", error);
857061da546Spatrick           if (count > 0)
858061da546Spatrick             DumpDataExtractor(packet,
859061da546Spatrick                               &s,                   // Stream to dump to
860061da546Spatrick                               offset,               // Offset within "packet"
861061da546Spatrick                               eFormatHex,           // Format to use
862061da546Spatrick                               1,                    // Size of each item in bytes
863061da546Spatrick                               count,                // Number of items
864061da546Spatrick                               16,                   // Number per line
865061da546Spatrick                               LLDB_INVALID_ADDRESS, // Don't show addresses
866061da546Spatrick                                                     // before each line
867061da546Spatrick                               0, 0);                // No bitfields
868061da546Spatrick         } break;
869061da546Spatrick         case KDP_DUMPINFO: {
870061da546Spatrick           const uint32_t count = packet.GetByteSize() - offset;
871061da546Spatrick           s.Printf(" (count = %u, bytes = \n", count);
872061da546Spatrick           if (count > 0)
873061da546Spatrick             DumpDataExtractor(packet,
874061da546Spatrick                               &s,                   // Stream to dump to
875061da546Spatrick                               offset,               // Offset within "packet"
876061da546Spatrick                               eFormatHex,           // Format to use
877061da546Spatrick                               1,                    // Size of each item in
878061da546Spatrick                                                     // bytes
879061da546Spatrick                               count,                // Number of items
880061da546Spatrick                               16,                   // Number per line
881061da546Spatrick                               LLDB_INVALID_ADDRESS, // Don't show addresses
882061da546Spatrick                                                     // before each line
883061da546Spatrick                               0, 0);                // No bitfields
884061da546Spatrick 
885061da546Spatrick         } break;
886061da546Spatrick 
887061da546Spatrick         default:
888061da546Spatrick           s.Printf(" (add support for dumping this packet reply!!!");
889061da546Spatrick           break;
890061da546Spatrick         }
891061da546Spatrick       } else {
892061da546Spatrick         // Dump request packets
893061da546Spatrick         switch (command) {
894061da546Spatrick         case KDP_CONNECT: {
895061da546Spatrick           const uint16_t reply_port = ntohs(packet.GetU16(&offset));
896061da546Spatrick           const uint16_t exc_port = ntohs(packet.GetU16(&offset));
897061da546Spatrick           s.Printf(" (reply_port = %u, exc_port = %u, greeting = \"%s\")",
898061da546Spatrick                    reply_port, exc_port, packet.GetCStr(&offset));
899061da546Spatrick         } break;
900061da546Spatrick 
901061da546Spatrick         case KDP_DISCONNECT:
902061da546Spatrick         case KDP_HOSTREBOOT:
903061da546Spatrick         case KDP_HOSTINFO:
904061da546Spatrick         case KDP_VERSION:
905061da546Spatrick         case KDP_REGIONS:
906061da546Spatrick         case KDP_KERNELVERSION:
907061da546Spatrick         case KDP_MAXBYTES:
908061da546Spatrick         case KDP_IMAGEPATH:
909061da546Spatrick         case KDP_SUSPEND:
910061da546Spatrick           // No args, just the header in the request...
911061da546Spatrick           s.PutCString(" ()");
912061da546Spatrick           break;
913061da546Spatrick 
914061da546Spatrick         case KDP_RESUMECPUS: {
915061da546Spatrick           const uint32_t cpu_mask = packet.GetU32(&offset);
916061da546Spatrick           s.Printf(" (cpu_mask = 0x%8.8x)", cpu_mask);
917061da546Spatrick         } break;
918061da546Spatrick 
919061da546Spatrick         case KDP_READMEM: {
920061da546Spatrick           const uint32_t addr = packet.GetU32(&offset);
921061da546Spatrick           const uint32_t size = packet.GetU32(&offset);
922061da546Spatrick           s.Printf(" (addr = 0x%8.8x, size = %u)", addr, size);
923061da546Spatrick           m_last_read_memory_addr = addr;
924061da546Spatrick         } break;
925061da546Spatrick 
926061da546Spatrick         case KDP_WRITEMEM: {
927061da546Spatrick           const uint32_t addr = packet.GetU32(&offset);
928061da546Spatrick           const uint32_t size = packet.GetU32(&offset);
929061da546Spatrick           s.Printf(" (addr = 0x%8.8x, size = %u, bytes = \n", addr, size);
930061da546Spatrick           if (size > 0)
931061da546Spatrick             DumpHexBytes(&s, packet.GetData(&offset, size), size, 32, addr);
932061da546Spatrick         } break;
933061da546Spatrick 
934061da546Spatrick         case KDP_READMEM64: {
935061da546Spatrick           const uint64_t addr = packet.GetU64(&offset);
936061da546Spatrick           const uint32_t size = packet.GetU32(&offset);
937061da546Spatrick           s.Printf(" (addr = 0x%16.16" PRIx64 ", size = %u)", addr, size);
938061da546Spatrick           m_last_read_memory_addr = addr;
939061da546Spatrick         } break;
940061da546Spatrick 
941061da546Spatrick         case KDP_READPHYSMEM64: {
942061da546Spatrick           const uint64_t addr = packet.GetU64(&offset);
943061da546Spatrick           const uint32_t size = packet.GetU32(&offset);
944061da546Spatrick           const uint32_t lcpu = packet.GetU16(&offset);
945061da546Spatrick           s.Printf(" (addr = 0x%16.16llx, size = %u, lcpu = %u)", addr, size,
946061da546Spatrick                    lcpu);
947061da546Spatrick           m_last_read_memory_addr = addr;
948061da546Spatrick         } break;
949061da546Spatrick 
950061da546Spatrick         case KDP_WRITEMEM64: {
951061da546Spatrick           const uint64_t addr = packet.GetU64(&offset);
952061da546Spatrick           const uint32_t size = packet.GetU32(&offset);
953061da546Spatrick           s.Printf(" (addr = 0x%16.16" PRIx64 ", size = %u, bytes = \n", addr,
954061da546Spatrick                    size);
955061da546Spatrick           if (size > 0)
956061da546Spatrick             DumpHexBytes(&s, packet.GetData(&offset, size), size, 32, addr);
957061da546Spatrick         } break;
958061da546Spatrick 
959061da546Spatrick         case KDP_WRITEPHYSMEM64: {
960061da546Spatrick           const uint64_t addr = packet.GetU64(&offset);
961061da546Spatrick           const uint32_t size = packet.GetU32(&offset);
962061da546Spatrick           const uint32_t lcpu = packet.GetU16(&offset);
963061da546Spatrick           s.Printf(" (addr = 0x%16.16llx, size = %u, lcpu = %u, bytes = \n",
964061da546Spatrick                    addr, size, lcpu);
965061da546Spatrick           if (size > 0)
966061da546Spatrick             DumpHexBytes(&s, packet.GetData(&offset, size), size, 32, addr);
967061da546Spatrick         } break;
968061da546Spatrick 
969061da546Spatrick         case KDP_READREGS: {
970061da546Spatrick           const uint32_t cpu = packet.GetU32(&offset);
971061da546Spatrick           const uint32_t flavor = packet.GetU32(&offset);
972061da546Spatrick           s.Printf(" (cpu = %u, flavor = %u)", cpu, flavor);
973061da546Spatrick         } break;
974061da546Spatrick 
975061da546Spatrick         case KDP_WRITEREGS: {
976061da546Spatrick           const uint32_t cpu = packet.GetU32(&offset);
977061da546Spatrick           const uint32_t flavor = packet.GetU32(&offset);
978061da546Spatrick           const uint32_t nbytes = packet.GetByteSize() - offset;
979061da546Spatrick           s.Printf(" (cpu = %u, flavor = %u, regs = \n", cpu, flavor);
980061da546Spatrick           if (nbytes > 0)
981061da546Spatrick             DumpDataExtractor(packet,
982061da546Spatrick                               &s,                        // Stream to dump to
983061da546Spatrick                               offset,                    // Offset within
984061da546Spatrick                                                          // "packet"
985061da546Spatrick                               eFormatHex,                // Format to use
986061da546Spatrick                               m_addr_byte_size,          // Size of each item in
987061da546Spatrick                                                          // bytes
988061da546Spatrick                               nbytes / m_addr_byte_size, // Number of items
989061da546Spatrick                               16 / m_addr_byte_size,     // Number per line
990061da546Spatrick                               LLDB_INVALID_ADDRESS,      // Don't show addresses
991061da546Spatrick                                                          // before each line
992061da546Spatrick                               0, 0);                // No bitfields
993061da546Spatrick         } break;
994061da546Spatrick 
995061da546Spatrick         case KDP_BREAKPOINT_SET:
996061da546Spatrick         case KDP_BREAKPOINT_REMOVE: {
997061da546Spatrick           const uint32_t addr = packet.GetU32(&offset);
998061da546Spatrick           s.Printf(" (addr = 0x%8.8x)", addr);
999061da546Spatrick         } break;
1000061da546Spatrick 
1001061da546Spatrick         case KDP_BREAKPOINT_SET64:
1002061da546Spatrick         case KDP_BREAKPOINT_REMOVE64: {
1003061da546Spatrick           const uint64_t addr = packet.GetU64(&offset);
1004061da546Spatrick           s.Printf(" (addr = 0x%16.16" PRIx64 ")", addr);
1005061da546Spatrick         } break;
1006061da546Spatrick 
1007061da546Spatrick         case KDP_LOAD: {
1008061da546Spatrick           const char *path = packet.GetCStr(&offset);
1009061da546Spatrick           s.Printf(" (path = \"%s\")", path);
1010061da546Spatrick         } break;
1011061da546Spatrick 
1012061da546Spatrick         case KDP_EXCEPTION: {
1013061da546Spatrick           const uint32_t count = packet.GetU32(&offset);
1014061da546Spatrick 
1015061da546Spatrick           for (uint32_t i = 0; i < count; ++i) {
1016061da546Spatrick             const uint32_t cpu = packet.GetU32(&offset);
1017061da546Spatrick             const uint32_t exc = packet.GetU32(&offset);
1018061da546Spatrick             const uint32_t code = packet.GetU32(&offset);
1019061da546Spatrick             const uint32_t subcode = packet.GetU32(&offset);
1020061da546Spatrick             const char *exc_cstr = NULL;
1021061da546Spatrick             switch (exc) {
1022061da546Spatrick             case 1:
1023061da546Spatrick               exc_cstr = "EXC_BAD_ACCESS";
1024061da546Spatrick               break;
1025061da546Spatrick             case 2:
1026061da546Spatrick               exc_cstr = "EXC_BAD_INSTRUCTION";
1027061da546Spatrick               break;
1028061da546Spatrick             case 3:
1029061da546Spatrick               exc_cstr = "EXC_ARITHMETIC";
1030061da546Spatrick               break;
1031061da546Spatrick             case 4:
1032061da546Spatrick               exc_cstr = "EXC_EMULATION";
1033061da546Spatrick               break;
1034061da546Spatrick             case 5:
1035061da546Spatrick               exc_cstr = "EXC_SOFTWARE";
1036061da546Spatrick               break;
1037061da546Spatrick             case 6:
1038061da546Spatrick               exc_cstr = "EXC_BREAKPOINT";
1039061da546Spatrick               break;
1040061da546Spatrick             case 7:
1041061da546Spatrick               exc_cstr = "EXC_SYSCALL";
1042061da546Spatrick               break;
1043061da546Spatrick             case 8:
1044061da546Spatrick               exc_cstr = "EXC_MACH_SYSCALL";
1045061da546Spatrick               break;
1046061da546Spatrick             case 9:
1047061da546Spatrick               exc_cstr = "EXC_RPC_ALERT";
1048061da546Spatrick               break;
1049061da546Spatrick             case 10:
1050061da546Spatrick               exc_cstr = "EXC_CRASH";
1051061da546Spatrick               break;
1052061da546Spatrick             default:
1053061da546Spatrick               break;
1054061da546Spatrick             }
1055061da546Spatrick 
1056061da546Spatrick             s.Printf("{ cpu = 0x%8.8x, exc = %s (%u), code = %u (0x%8.8x), "
1057061da546Spatrick                      "subcode = %u (0x%8.8x)} ",
1058061da546Spatrick                      cpu, exc_cstr, exc, code, code, subcode, subcode);
1059061da546Spatrick           }
1060061da546Spatrick         } break;
1061061da546Spatrick 
1062061da546Spatrick         case KDP_TERMINATION: {
1063061da546Spatrick           const uint32_t term_code = packet.GetU32(&offset);
1064061da546Spatrick           const uint32_t exit_code = packet.GetU32(&offset);
1065061da546Spatrick           s.Printf(" (term_code = 0x%8.8x (%u), exit_code = 0x%8.8x (%u))",
1066061da546Spatrick                    term_code, term_code, exit_code, exit_code);
1067061da546Spatrick         } break;
1068061da546Spatrick 
1069061da546Spatrick         case KDP_REATTACH: {
1070061da546Spatrick           const uint16_t reply_port = ntohs(packet.GetU16(&offset));
1071061da546Spatrick           s.Printf(" (reply_port = %u)", reply_port);
1072061da546Spatrick         } break;
1073061da546Spatrick 
1074061da546Spatrick         case KDP_READMSR64: {
1075061da546Spatrick           const uint32_t address = packet.GetU32(&offset);
1076061da546Spatrick           const uint16_t lcpu = packet.GetU16(&offset);
1077061da546Spatrick           s.Printf(" (address=0x%8.8x, lcpu=0x%4.4x)", address, lcpu);
1078061da546Spatrick         } break;
1079061da546Spatrick 
1080061da546Spatrick         case KDP_WRITEMSR64: {
1081061da546Spatrick           const uint32_t address = packet.GetU32(&offset);
1082061da546Spatrick           const uint16_t lcpu = packet.GetU16(&offset);
1083061da546Spatrick           const uint32_t nbytes = packet.GetByteSize() - offset;
1084061da546Spatrick           s.Printf(" (address=0x%8.8x, lcpu=0x%4.4x, nbytes=0x%8.8x)", lcpu,
1085061da546Spatrick                    address, nbytes);
1086061da546Spatrick           if (nbytes > 0)
1087061da546Spatrick             DumpDataExtractor(packet,
1088061da546Spatrick                               &s,                   // Stream to dump to
1089061da546Spatrick                               offset,               // Offset within "packet"
1090061da546Spatrick                               eFormatHex,           // Format to use
1091061da546Spatrick                               1,                    // Size of each item in
1092061da546Spatrick                                                     // bytes
1093061da546Spatrick                               nbytes,               // Number of items
1094061da546Spatrick                               16,                   // Number per line
1095061da546Spatrick                               LLDB_INVALID_ADDRESS, // Don't show addresses
1096061da546Spatrick                                                     // before each line
1097061da546Spatrick                               0, 0);                // No bitfields
1098061da546Spatrick         } break;
1099061da546Spatrick 
1100061da546Spatrick         case KDP_READIOPORT: {
1101061da546Spatrick           const uint16_t lcpu = packet.GetU16(&offset);
1102061da546Spatrick           const uint16_t address = packet.GetU16(&offset);
1103061da546Spatrick           const uint16_t nbytes = packet.GetU16(&offset);
1104061da546Spatrick           s.Printf(" (lcpu=0x%4.4x, address=0x%4.4x, nbytes=%u)", lcpu, address,
1105061da546Spatrick                    nbytes);
1106061da546Spatrick         } break;
1107061da546Spatrick 
1108061da546Spatrick         case KDP_WRITEIOPORT: {
1109061da546Spatrick           const uint16_t lcpu = packet.GetU16(&offset);
1110061da546Spatrick           const uint16_t address = packet.GetU16(&offset);
1111061da546Spatrick           const uint16_t nbytes = packet.GetU16(&offset);
1112061da546Spatrick           s.Printf(" (lcpu = %u, addr = 0x%4.4x, nbytes = %u, bytes = \n", lcpu,
1113061da546Spatrick                    address, nbytes);
1114061da546Spatrick           if (nbytes > 0)
1115061da546Spatrick             DumpDataExtractor(packet,
1116061da546Spatrick                               &s,                   // Stream to dump to
1117061da546Spatrick                               offset,               // Offset within "packet"
1118061da546Spatrick                               eFormatHex,           // Format to use
1119061da546Spatrick                               1,                    // Size of each item in
1120061da546Spatrick                                                     // bytes
1121061da546Spatrick                               nbytes,               // Number of items
1122061da546Spatrick                               16,                   // Number per line
1123061da546Spatrick                               LLDB_INVALID_ADDRESS, // Don't show addresses
1124061da546Spatrick                                                     // before each line
1125061da546Spatrick                               0, 0);                // No bitfields
1126061da546Spatrick         } break;
1127061da546Spatrick 
1128061da546Spatrick         case KDP_DUMPINFO: {
1129061da546Spatrick           const uint32_t count = packet.GetByteSize() - offset;
1130061da546Spatrick           s.Printf(" (count = %u, bytes = \n", count);
1131061da546Spatrick           if (count > 0)
1132061da546Spatrick             DumpDataExtractor(packet,
1133061da546Spatrick                 &s,                   // Stream to dump to
1134061da546Spatrick                 offset,               // Offset within "packet"
1135061da546Spatrick                 eFormatHex,           // Format to use
1136061da546Spatrick                 1,                    // Size of each item in bytes
1137061da546Spatrick                 count,                // Number of items
1138061da546Spatrick                 16,                   // Number per line
1139061da546Spatrick                 LLDB_INVALID_ADDRESS, // Don't show addresses before each line
1140061da546Spatrick                 0, 0);                // No bitfields
1141061da546Spatrick 
1142061da546Spatrick         } break;
1143061da546Spatrick         }
1144061da546Spatrick       }
1145061da546Spatrick     } else {
1146061da546Spatrick       error_desc = "error: invalid packet command: ";
1147061da546Spatrick     }
1148061da546Spatrick   }
1149061da546Spatrick 
1150061da546Spatrick   if (error_desc) {
1151061da546Spatrick     s.PutCString(error_desc);
1152061da546Spatrick 
1153061da546Spatrick     DumpDataExtractor(packet,
1154061da546Spatrick                       &s,                   // Stream to dump to
1155061da546Spatrick                       0,                    // Offset into "packet"
1156061da546Spatrick                       eFormatBytes,         // Dump as hex bytes
1157061da546Spatrick                       1,                    // Size of each item is 1 for
1158061da546Spatrick                                             // single bytes
1159061da546Spatrick                       packet.GetByteSize(), // Number of bytes
1160061da546Spatrick                       UINT32_MAX,           // Num bytes per line
1161061da546Spatrick                       LLDB_INVALID_ADDRESS, // Base address
1162061da546Spatrick                       0, 0);                // Bitfield info set to not do
1163061da546Spatrick                                             // anything bitfield related
1164061da546Spatrick   }
1165061da546Spatrick }
1166061da546Spatrick 
SendRequestReadRegisters(uint32_t cpu,uint32_t flavor,void * dst,uint32_t dst_len,Status & error)1167061da546Spatrick uint32_t CommunicationKDP::SendRequestReadRegisters(uint32_t cpu,
1168061da546Spatrick                                                     uint32_t flavor, void *dst,
1169061da546Spatrick                                                     uint32_t dst_len,
1170061da546Spatrick                                                     Status &error) {
1171061da546Spatrick   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
1172061da546Spatrick                                   m_byte_order);
1173061da546Spatrick   const CommandType command = KDP_READREGS;
1174061da546Spatrick   // Size is header + 4 byte cpu and 4 byte flavor
1175061da546Spatrick   const uint32_t command_length = 8 + 4 + 4;
1176061da546Spatrick   MakeRequestPacketHeader(command, request_packet, command_length);
1177061da546Spatrick   request_packet.PutHex32(cpu);
1178061da546Spatrick   request_packet.PutHex32(flavor);
1179061da546Spatrick   DataExtractor reply_packet;
1180061da546Spatrick   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
1181061da546Spatrick     lldb::offset_t offset = 8;
1182061da546Spatrick     uint32_t kdp_error = reply_packet.GetU32(&offset);
1183061da546Spatrick     uint32_t src_len = reply_packet.GetByteSize() - 12;
1184061da546Spatrick 
1185061da546Spatrick     if (src_len > 0) {
1186061da546Spatrick       const uint32_t bytes_to_copy = std::min<uint32_t>(src_len, dst_len);
1187061da546Spatrick       const void *src = reply_packet.GetData(&offset, bytes_to_copy);
1188061da546Spatrick       if (src) {
1189061da546Spatrick         ::memcpy(dst, src, bytes_to_copy);
1190061da546Spatrick         error.Clear();
1191061da546Spatrick         // Return the number of bytes we could have returned regardless if we
1192061da546Spatrick         // copied them or not, just so we know when things don't match up
1193061da546Spatrick         return src_len;
1194061da546Spatrick       }
1195061da546Spatrick     }
1196061da546Spatrick     if (kdp_error)
1197061da546Spatrick       error.SetErrorStringWithFormat(
1198061da546Spatrick           "failed to read kdp registers for cpu %u flavor %u (error %u)", cpu,
1199061da546Spatrick           flavor, kdp_error);
1200061da546Spatrick     else
1201061da546Spatrick       error.SetErrorStringWithFormat(
1202061da546Spatrick           "failed to read kdp registers for cpu %u flavor %u", cpu, flavor);
1203061da546Spatrick   } else {
1204061da546Spatrick     error.SetErrorString("failed to send packet");
1205061da546Spatrick   }
1206061da546Spatrick   return 0;
1207061da546Spatrick }
1208061da546Spatrick 
SendRequestWriteRegisters(uint32_t cpu,uint32_t flavor,const void * src,uint32_t src_len,Status & error)1209061da546Spatrick uint32_t CommunicationKDP::SendRequestWriteRegisters(uint32_t cpu,
1210061da546Spatrick                                                      uint32_t flavor,
1211061da546Spatrick                                                      const void *src,
1212061da546Spatrick                                                      uint32_t src_len,
1213061da546Spatrick                                                      Status &error) {
1214061da546Spatrick   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
1215061da546Spatrick                                   m_byte_order);
1216061da546Spatrick   const CommandType command = KDP_WRITEREGS;
1217061da546Spatrick   // Size is header + 4 byte cpu and 4 byte flavor
1218061da546Spatrick   const uint32_t command_length = 8 + 4 + 4 + src_len;
1219061da546Spatrick   MakeRequestPacketHeader(command, request_packet, command_length);
1220061da546Spatrick   request_packet.PutHex32(cpu);
1221061da546Spatrick   request_packet.PutHex32(flavor);
1222061da546Spatrick   request_packet.Write(src, src_len);
1223061da546Spatrick   DataExtractor reply_packet;
1224061da546Spatrick   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
1225061da546Spatrick     lldb::offset_t offset = 8;
1226061da546Spatrick     uint32_t kdp_error = reply_packet.GetU32(&offset);
1227061da546Spatrick     if (kdp_error == 0)
1228061da546Spatrick       return src_len;
1229061da546Spatrick     error.SetErrorStringWithFormat(
1230061da546Spatrick         "failed to read kdp registers for cpu %u flavor %u (error %u)", cpu,
1231061da546Spatrick         flavor, kdp_error);
1232061da546Spatrick   } else {
1233061da546Spatrick     error.SetErrorString("failed to send packet");
1234061da546Spatrick   }
1235061da546Spatrick   return 0;
1236061da546Spatrick }
1237061da546Spatrick 
SendRequestResume()1238061da546Spatrick bool CommunicationKDP::SendRequestResume() {
1239061da546Spatrick   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
1240061da546Spatrick                                   m_byte_order);
1241061da546Spatrick   const CommandType command = KDP_RESUMECPUS;
1242061da546Spatrick   const uint32_t command_length = 12;
1243061da546Spatrick   MakeRequestPacketHeader(command, request_packet, command_length);
1244061da546Spatrick   request_packet.PutHex32(GetCPUMask());
1245061da546Spatrick 
1246061da546Spatrick   DataExtractor reply_packet;
1247061da546Spatrick   return SendRequestAndGetReply(command, request_packet, reply_packet);
1248061da546Spatrick }
1249061da546Spatrick 
SendRequestBreakpoint(bool set,addr_t addr)1250061da546Spatrick bool CommunicationKDP::SendRequestBreakpoint(bool set, addr_t addr) {
1251061da546Spatrick   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
1252061da546Spatrick                                   m_byte_order);
1253061da546Spatrick   bool use_64 = (GetVersion() >= 11);
1254061da546Spatrick   uint32_t command_addr_byte_size = use_64 ? 8 : 4;
1255061da546Spatrick   const CommandType command =
1256061da546Spatrick       set ? (use_64 ? KDP_BREAKPOINT_SET64 : KDP_BREAKPOINT_SET)
1257061da546Spatrick           : (use_64 ? KDP_BREAKPOINT_REMOVE64 : KDP_BREAKPOINT_REMOVE);
1258061da546Spatrick 
1259061da546Spatrick   const uint32_t command_length = 8 + command_addr_byte_size;
1260061da546Spatrick   MakeRequestPacketHeader(command, request_packet, command_length);
1261061da546Spatrick   request_packet.PutMaxHex64(addr, command_addr_byte_size);
1262061da546Spatrick 
1263061da546Spatrick   DataExtractor reply_packet;
1264061da546Spatrick   if (SendRequestAndGetReply(command, request_packet, reply_packet)) {
1265061da546Spatrick     lldb::offset_t offset = 8;
1266061da546Spatrick     uint32_t kdp_error = reply_packet.GetU32(&offset);
1267061da546Spatrick     if (kdp_error == 0)
1268061da546Spatrick       return true;
1269061da546Spatrick   }
1270061da546Spatrick   return false;
1271061da546Spatrick }
1272061da546Spatrick 
SendRequestSuspend()1273061da546Spatrick bool CommunicationKDP::SendRequestSuspend() {
1274061da546Spatrick   PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size,
1275061da546Spatrick                                   m_byte_order);
1276061da546Spatrick   const CommandType command = KDP_SUSPEND;
1277061da546Spatrick   const uint32_t command_length = 8;
1278061da546Spatrick   MakeRequestPacketHeader(command, request_packet, command_length);
1279061da546Spatrick   DataExtractor reply_packet;
1280061da546Spatrick   return SendRequestAndGetReply(command, request_packet, reply_packet);
1281061da546Spatrick }
1282