blob: 06096afb0463a40be2fb297ecdc7236a0ce8f454 [file] [log] [blame]
Greg Clayton269f91e2011-07-15 18:02:58 +00001//===-- CommunicationKDP.cpp ------------------------------------*- C++ -*-===//
Greg Clayton363be3f2011-07-15 03:27:12 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10
11#include "CommunicationKDP.h"
12
13// C Includes
14#include <limits.h>
15#include <string.h>
16
17// C++ Includes
18// Other libraries and framework includes
Greg Claytond52d00f2011-07-16 03:19:08 +000019#include "lldb/Core/DataBufferHeap.h"
Greg Clayton1e5b0212011-07-15 16:31:38 +000020#include "lldb/Core/DataExtractor.h"
Greg Clayton363be3f2011-07-15 03:27:12 +000021#include "lldb/Core/Log.h"
Greg Clayton363be3f2011-07-15 03:27:12 +000022#include "lldb/Host/FileSpec.h"
23#include "lldb/Host/Host.h"
24#include "lldb/Host/TimeValue.h"
25#include "lldb/Target/Process.h"
Greg Clayton363be3f2011-07-15 03:27:12 +000026
27// Project includes
28#include "ProcessKDPLog.h"
29
30#define DEBUGSERVER_BASENAME "debugserver"
31
32using namespace lldb;
33using namespace lldb_private;
34
35//----------------------------------------------------------------------
36// CommunicationKDP constructor
37//----------------------------------------------------------------------
38CommunicationKDP::CommunicationKDP (const char *comm_name) :
39 Communication(comm_name),
Greg Claytond52d00f2011-07-16 03:19:08 +000040 m_byte_order (eByteOrderLittle),
Greg Clayton363be3f2011-07-15 03:27:12 +000041 m_packet_timeout (1),
42 m_sequence_mutex (Mutex::eMutexTypeRecursive),
43 m_public_is_running (false),
44 m_private_is_running (false),
Greg Claytond52d00f2011-07-16 03:19:08 +000045 m_session_key (0u),
46 m_request_sequence_id (0u),
47 m_exception_sequence_id (0u),
48 m_kdp_version_version (0u),
49 m_kdp_version_feature (0u),
50 m_kdp_hostinfo_cpu_mask (0u),
51 m_kdp_hostinfo_cpu_type (0u),
52 m_kdp_hostinfo_cpu_subtype (0u)
Greg Clayton363be3f2011-07-15 03:27:12 +000053{
54}
55
56//----------------------------------------------------------------------
57// Destructor
58//----------------------------------------------------------------------
59CommunicationKDP::~CommunicationKDP()
60{
61 if (IsConnected())
62 {
63 Disconnect();
64 }
65}
66
Greg Clayton1e5b0212011-07-15 16:31:38 +000067bool
Greg Claytond52d00f2011-07-16 03:19:08 +000068CommunicationKDP::SendRequestPacket (const PacketStreamType &request_packet)
Greg Clayton363be3f2011-07-15 03:27:12 +000069{
70 Mutex::Locker locker(m_sequence_mutex);
Greg Clayton1e5b0212011-07-15 16:31:38 +000071 return SendRequestPacketNoLock (request_packet);
Greg Clayton363be3f2011-07-15 03:27:12 +000072}
73
Greg Claytond52d00f2011-07-16 03:19:08 +000074#if 0
75typedef struct {
76 uint8_t request; // Either: CommandType | ePacketTypeRequest, or CommandType | ePacketTypeReply
77 uint8_t sequence;
78 uint16_t length; // Length of entire packet including this header
79 uint32_t key; // Session key
80} kdp_hdr_t;
81#endif
82
Greg Clayton1e5b0212011-07-15 16:31:38 +000083void
Greg Claytond52d00f2011-07-16 03:19:08 +000084CommunicationKDP::MakeRequestPacketHeader (CommandType request_type,
85 PacketStreamType &request_packet,
86 uint16_t request_length)
Greg Clayton363be3f2011-07-15 03:27:12 +000087{
Greg Clayton1e5b0212011-07-15 16:31:38 +000088 request_packet.Clear();
Greg Claytond52d00f2011-07-16 03:19:08 +000089 request_packet.PutHex8 (request_type | ePacketTypeRequest); // Set the request type
90 request_packet.PutHex8 (m_request_sequence_id++); // Sequence number
91 request_packet.PutHex16 (request_length); // Length of the packet including this header
92 request_packet.PutHex32 (m_session_key); // Session key
Greg Clayton363be3f2011-07-15 03:27:12 +000093}
94
Greg Claytond52d00f2011-07-16 03:19:08 +000095bool
96CommunicationKDP::SendRequestAndGetReply (const CommandType command,
97 const uint8_t request_sequence_id,
98 const PacketStreamType &request_packet,
99 DataExtractor &reply_packet)
100{
101
102 Mutex::Locker locker(m_sequence_mutex);
103 if (SendRequestPacketNoLock(request_packet))
104 {
105 if (WaitForPacketWithTimeoutMicroSecondsNoLock (reply_packet, m_packet_timeout))
106 {
107 uint32_t offset = 0;
108 const uint8_t reply_command = reply_packet.GetU8 (&offset);
109 const uint8_t reply_sequence_id = reply_packet.GetU8 (&offset);
110 if ((reply_command & eCommandTypeMask) == command)
111 {
112 if (request_sequence_id == reply_sequence_id)
113 return true;
114 }
115 }
116 }
117 reply_packet.Clear();
118 return false;
119}
Greg Clayton363be3f2011-07-15 03:27:12 +0000120
Greg Clayton1e5b0212011-07-15 16:31:38 +0000121bool
Greg Claytond52d00f2011-07-16 03:19:08 +0000122CommunicationKDP::SendRequestPacketNoLock (const PacketStreamType &request_packet)
Greg Clayton363be3f2011-07-15 03:27:12 +0000123{
124 if (IsConnected())
125 {
Greg Clayton1e5b0212011-07-15 16:31:38 +0000126 const char *packet_data = request_packet.GetData();
127 const size_t packet_size = request_packet.GetSize();
Greg Clayton363be3f2011-07-15 03:27:12 +0000128
129 LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS));
130 if (log)
Greg Clayton1e5b0212011-07-15 16:31:38 +0000131 {
Greg Claytond52d00f2011-07-16 03:19:08 +0000132 PacketStreamType log_strm;
Greg Clayton1e5b0212011-07-15 16:31:38 +0000133
Greg Claytond52d00f2011-07-16 03:19:08 +0000134 DataExtractor::DumpHexBytes (&log_strm, packet_data, packet_size, 0);
135
136 log->Printf("request packet: <%u>\n%s", packet_size, log_strm.GetData());
Greg Clayton1e5b0212011-07-15 16:31:38 +0000137 }
Greg Clayton363be3f2011-07-15 03:27:12 +0000138 ConnectionStatus status = eConnectionStatusSuccess;
Greg Clayton363be3f2011-07-15 03:27:12 +0000139
Greg Clayton1e5b0212011-07-15 16:31:38 +0000140 size_t bytes_written = Write (packet_data,
141 packet_size,
142 status,
143 NULL);
144
145 if (bytes_written == packet_size)
146 return true;
147
148 if (log)
149 log->Printf ("error: failed to send packet entire packet %zu of %zu bytes sent", bytes_written, packet_size);
150 }
151 return false;
Greg Clayton363be3f2011-07-15 03:27:12 +0000152}
153
154bool
155CommunicationKDP::GetSequenceMutex (Mutex::Locker& locker)
156{
157 return locker.TryLock (m_sequence_mutex.GetMutex());
158}
159
160
161bool
162CommunicationKDP::WaitForNotRunningPrivate (const TimeValue *timeout_ptr)
163{
164 return m_private_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL);
165}
166
167size_t
Greg Claytond52d00f2011-07-16 03:19:08 +0000168CommunicationKDP::WaitForPacketWithTimeoutMicroSeconds (DataExtractor &packet, uint32_t timeout_usec)
Greg Clayton363be3f2011-07-15 03:27:12 +0000169{
170 Mutex::Locker locker(m_sequence_mutex);
171 return WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec);
172}
173
174size_t
Greg Claytond52d00f2011-07-16 03:19:08 +0000175CommunicationKDP::WaitForPacketWithTimeoutMicroSecondsNoLock (DataExtractor &packet, uint32_t timeout_usec)
Greg Clayton363be3f2011-07-15 03:27:12 +0000176{
177 uint8_t buffer[8192];
178 Error error;
179
180 LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS | KDP_LOG_VERBOSE));
181
182 // Check for a packet from our cache first without trying any reading...
183 if (CheckForPacket (NULL, 0, packet))
Greg Claytond52d00f2011-07-16 03:19:08 +0000184 return packet.GetByteSize();
Greg Clayton363be3f2011-07-15 03:27:12 +0000185
186 bool timed_out = false;
187 while (IsConnected() && !timed_out)
188 {
189 lldb::ConnectionStatus status;
190 size_t bytes_read = Read (buffer, sizeof(buffer), timeout_usec, status, &error);
191
192 if (log)
193 log->Printf ("%s: Read (buffer, (sizeof(buffer), timeout_usec = 0x%x, status = %s, error = %s) => bytes_read = %zu",
194 __PRETTY_FUNCTION__,
195 timeout_usec,
196 Communication::ConnectionStatusAsCString (status),
197 error.AsCString(),
198 bytes_read);
199
200 if (bytes_read > 0)
201 {
202 if (CheckForPacket (buffer, bytes_read, packet))
Greg Claytond52d00f2011-07-16 03:19:08 +0000203 return packet.GetByteSize();
Greg Clayton363be3f2011-07-15 03:27:12 +0000204 }
205 else
206 {
207 switch (status)
208 {
209 case eConnectionStatusTimedOut:
210 timed_out = true;
211 break;
212 case eConnectionStatusSuccess:
213 //printf ("status = success but error = %s\n", error.AsCString("<invalid>"));
214 break;
215
216 case eConnectionStatusEndOfFile:
217 case eConnectionStatusNoConnection:
218 case eConnectionStatusLostConnection:
219 case eConnectionStatusError:
220 Disconnect();
221 break;
222 }
223 }
224 }
225 packet.Clear ();
226 return 0;
227}
228
229bool
Greg Claytond52d00f2011-07-16 03:19:08 +0000230CommunicationKDP::CheckForPacket (const uint8_t *src, size_t src_len, DataExtractor &packet)
Greg Clayton363be3f2011-07-15 03:27:12 +0000231{
232 // Put the packet data into the buffer in a thread safe fashion
233 Mutex::Locker locker(m_bytes_mutex);
234
235 LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS));
236
237 if (src && src_len > 0)
238 {
239 if (log && log->GetVerbose())
240 {
Greg Claytond52d00f2011-07-16 03:19:08 +0000241 PacketStreamType log_strm;
242 DataExtractor::DumpHexBytes (&log_strm, src, src_len, 0);
243 log->Printf ("CommunicationKDP::%s adding %u bytes: %s",
Greg Clayton363be3f2011-07-15 03:27:12 +0000244 __FUNCTION__,
245 (uint32_t)src_len,
Greg Claytond52d00f2011-07-16 03:19:08 +0000246 log_strm.GetData());
Greg Clayton363be3f2011-07-15 03:27:12 +0000247 }
248 m_bytes.append ((const char *)src, src_len);
249 }
250
Greg Claytond52d00f2011-07-16 03:19:08 +0000251 // Make sure we at least have enough bytes for a packet header
252 const size_t bytes_available = m_bytes.size();
253 if (bytes_available >= 8)
Greg Clayton363be3f2011-07-15 03:27:12 +0000254 {
Greg Claytond52d00f2011-07-16 03:19:08 +0000255 packet.SetData (&m_bytes[0], bytes_available, m_byte_order);
256 uint32_t offset = 0;
257 uint8_t reply_command = packet.GetU8(&offset);
258 switch (reply_command)
259 {
260 case ePacketTypeReply | eCommandTypeConnect:
261 case ePacketTypeReply | eCommandTypeDisconnect:
262 case ePacketTypeReply | eCommandTypeHostInfo:
263 case ePacketTypeReply | eCommandTypeVersion:
264 case ePacketTypeReply | eCommandTypeMaxBytes:
265 case ePacketTypeReply | eCommandTypeReadMemory:
266 case ePacketTypeReply | eCommandTypeWriteMemory:
267 case ePacketTypeReply | eCommandTypeReadRegisters:
268 case ePacketTypeReply | eCommandTypeWriteRegisters:
269 case ePacketTypeReply | eCommandTypeLoad:
270 case ePacketTypeReply | eCommandTypeImagePath:
271 case ePacketTypeReply | eCommandTypeSuspend:
272 case ePacketTypeReply | eCommandTypeResume:
273 case ePacketTypeReply | eCommandTypeException:
274 case ePacketTypeReply | eCommandTypeTermination:
275 case ePacketTypeReply | eCommandTypeBreakpointSet:
276 case ePacketTypeReply | eCommandTypeBreakpointRemove:
277 case ePacketTypeReply | eCommandTypeRegions:
278 case ePacketTypeReply | eCommandTypeReattach:
279 case ePacketTypeReply | eCommandTypeHostReboot:
280 case ePacketTypeReply | eCommandTypeReadMemory64:
281 case ePacketTypeReply | eCommandTypeWriteMemory64:
282 case ePacketTypeReply | eCommandTypeBreakpointSet64:
283 case ePacketTypeReply | eCommandTypeBreakpointRemove64:
284 case ePacketTypeReply | eCommandTypeKernelVersion:
285 {
286 offset = 2;
287 const uint16_t length = packet.GetU16 (&offset);
288 if (length <= bytes_available)
289 {
290 // We have an entire packet ready, we need to copy the data
291 // bytes into a buffer that will be owned by the packet and
292 // erase the bytes from our communcation buffer "m_bytes"
293 packet.SetData (DataBufferSP (new DataBufferHeap (&m_bytes[0], length)));
294 m_bytes.erase (0, length);
295 return true;
296 }
297 }
298 break;
299
300 default:
301 // Unrecognized reply command byte, erase this byte and try to get back on track
302 if (log)
303 log->Printf ("CommunicationKDP::%s: tossing junk byte: 0x%2.2x",
304 __FUNCTION__,
305 (uint8_t)m_bytes[0]);
306 m_bytes.erase(0, 1);
307 break;
308 }
Greg Clayton363be3f2011-07-15 03:27:12 +0000309 }
310 packet.Clear();
311 return false;
312}
313
Greg Clayton1e5b0212011-07-15 16:31:38 +0000314
Greg Claytond52d00f2011-07-16 03:19:08 +0000315bool
Greg Clayton1e5b0212011-07-15 16:31:38 +0000316CommunicationKDP::Connect (uint16_t reply_port,
317 uint16_t exc_port,
318 const char *greeting)
319{
Greg Claytond52d00f2011-07-16 03:19:08 +0000320 PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order);
321 if (greeting == NULL)
322 greeting = "";
323
324 const CommandType command = eCommandTypeConnect;
325 // Length is 82 uint16_t and the length of the greeting C string
326 const uint32_t command_length = 8 + 2 + 2 + ::strlen(greeting);
327 const uint32_t request_sequence_id = m_request_sequence_id;
328 MakeRequestPacketHeader (command, request_packet, command_length);
Greg Clayton1e5b0212011-07-15 16:31:38 +0000329 request_packet.PutHex16(reply_port);
330 request_packet.PutHex16(exc_port);
331 request_packet.PutCString(greeting);
Greg Claytond52d00f2011-07-16 03:19:08 +0000332 DataExtractor reply_packet;
333 return SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet);
Greg Clayton1e5b0212011-07-15 16:31:38 +0000334}
335
Greg Claytond52d00f2011-07-16 03:19:08 +0000336void
337CommunicationKDP::ClearKDPSettings ()
338{
339 m_request_sequence_id = 0;
340 m_kdp_version_version = 0;
341 m_kdp_version_feature = 0;
342 m_kdp_hostinfo_cpu_mask = 0;
343 m_kdp_hostinfo_cpu_type = 0;
344 m_kdp_hostinfo_cpu_subtype = 0;
345}
346
347bool
348CommunicationKDP::Reattach (uint16_t reply_port)
349{
350 PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order);
351 const CommandType command = eCommandTypeReattach;
352 // Length is 8 bytes for the header plus 2 bytes for the reply UDP port
353 const uint32_t command_length = 8 + 2;
354 const uint32_t request_sequence_id = m_request_sequence_id;
355 MakeRequestPacketHeader (command, request_packet, command_length);
356 request_packet.PutHex16(reply_port);
357 DataExtractor reply_packet;
358 if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet))
359 {
360 // Reset the sequence ID to zero for reattach
361 ClearKDPSettings ();
362 uint32_t offset = 4;
363 m_session_key = reply_packet.GetU32 (&offset);
364 return true;
365 }
366 return false;
367}
368
369uint32_t
370CommunicationKDP::GetVersion ()
371{
372 if (!VersionIsValid())
373 SendRequestVersion();
374 return m_kdp_version_version;
375}
376
377uint32_t
378CommunicationKDP::GetFeatureFlags ()
379{
380 if (!VersionIsValid())
381 SendRequestVersion();
382 return m_kdp_version_feature;
383}
384
385bool
386CommunicationKDP::SendRequestVersion ()
387{
388 PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order);
389 const CommandType command = eCommandTypeVersion;
390 const uint32_t command_length = 8;
391 const uint32_t request_sequence_id = m_request_sequence_id;
392 MakeRequestPacketHeader (command, request_packet, command_length);
393 DataExtractor reply_packet;
394 if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet))
395 {
396 // Reset the sequence ID to zero for reattach
397 uint32_t offset = 8;
398 m_kdp_version_version = reply_packet.GetU32 (&offset);
399 m_kdp_version_feature = reply_packet.GetU32 (&offset);
400 return true;
401 }
402 return false;
403}
404
405uint32_t
406CommunicationKDP::GetCPUMask ()
407{
408 if (!HostInfoIsValid())
409 SendRequestHostInfo();
410 return m_kdp_hostinfo_cpu_mask;
411}
412
413uint32_t
414CommunicationKDP::GetCPUType ()
415{
416 if (!HostInfoIsValid())
417 SendRequestHostInfo();
418 return m_kdp_hostinfo_cpu_type;
419}
420
421uint32_t
422CommunicationKDP::GetCPUSubtype ()
423{
424 if (!HostInfoIsValid())
425 SendRequestHostInfo();
426 return m_kdp_hostinfo_cpu_subtype;
427}
428
429bool
430CommunicationKDP::SendRequestHostInfo ()
431{
432 PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order);
433 const CommandType command = eCommandTypeHostInfo;
434 const uint32_t command_length = 8;
435 const uint32_t request_sequence_id = m_request_sequence_id;
436 MakeRequestPacketHeader (command, request_packet, command_length);
437 DataExtractor reply_packet;
438 if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet))
439 {
440 // Reset the sequence ID to zero for reattach
441 uint32_t offset = 8;
442 m_kdp_hostinfo_cpu_mask = reply_packet.GetU32 (&offset);
443 m_kdp_hostinfo_cpu_type = reply_packet.GetU32 (&offset);
444 m_kdp_hostinfo_cpu_subtype = reply_packet.GetU32 (&offset);
445 return true;
446 }
447 return false;
448}
449
450bool
Greg Clayton1e5b0212011-07-15 16:31:38 +0000451CommunicationKDP::Disconnect ()
452{
Greg Claytond52d00f2011-07-16 03:19:08 +0000453 PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order);
454 const CommandType command = eCommandTypeDisconnect;
455 const uint32_t command_length = 8;
456 const uint32_t request_sequence_id = m_request_sequence_id;
457 MakeRequestPacketHeader (command, request_packet, command_length);
458 DataExtractor reply_packet;
459 if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet))
460 {
461 // Are we supposed to get a reply for disconnect?
462 }
463 ClearKDPSettings ();
464 return true;
Greg Clayton1e5b0212011-07-15 16:31:38 +0000465}
466