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