blob: 2d9522bbe3a4a3eaad3f61b57a11151c357125cb [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 {
Greg Clayton8d2ea282011-07-17 20:36:25 +0000105 if (WaitForPacketWithTimeoutMicroSecondsNoLock (reply_packet, GetPacketTimeoutInMicroSeconds ()))
Greg Claytond52d00f2011-07-16 03:19:08 +0000106 {
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 Clayton8d2ea282011-07-17 20:36:25 +0000134 DataExtractor::DumpHexBytes (&log_strm, packet_data, packet_size, UINT32_MAX, LLDB_INVALID_ADDRESS);
Greg Claytond52d00f2011-07-16 03:19:08 +0000135
Greg Clayton8d2ea282011-07-17 20:36:25 +0000136 log->Printf("send kdp-packet: %.*s",
137 (uint32_t)log_strm.GetSize(),
138 log_strm.GetData());
Greg Clayton1e5b0212011-07-15 16:31:38 +0000139 }
Greg Clayton363be3f2011-07-15 03:27:12 +0000140 ConnectionStatus status = eConnectionStatusSuccess;
Greg Clayton363be3f2011-07-15 03:27:12 +0000141
Greg Clayton1e5b0212011-07-15 16:31:38 +0000142 size_t bytes_written = Write (packet_data,
143 packet_size,
144 status,
145 NULL);
146
147 if (bytes_written == packet_size)
148 return true;
149
150 if (log)
151 log->Printf ("error: failed to send packet entire packet %zu of %zu bytes sent", bytes_written, packet_size);
152 }
153 return false;
Greg Clayton363be3f2011-07-15 03:27:12 +0000154}
155
156bool
157CommunicationKDP::GetSequenceMutex (Mutex::Locker& locker)
158{
159 return locker.TryLock (m_sequence_mutex.GetMutex());
160}
161
162
163bool
164CommunicationKDP::WaitForNotRunningPrivate (const TimeValue *timeout_ptr)
165{
166 return m_private_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL);
167}
168
169size_t
Greg Claytond52d00f2011-07-16 03:19:08 +0000170CommunicationKDP::WaitForPacketWithTimeoutMicroSeconds (DataExtractor &packet, uint32_t timeout_usec)
Greg Clayton363be3f2011-07-15 03:27:12 +0000171{
172 Mutex::Locker locker(m_sequence_mutex);
173 return WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec);
174}
175
176size_t
Greg Claytond52d00f2011-07-16 03:19:08 +0000177CommunicationKDP::WaitForPacketWithTimeoutMicroSecondsNoLock (DataExtractor &packet, uint32_t timeout_usec)
Greg Clayton363be3f2011-07-15 03:27:12 +0000178{
179 uint8_t buffer[8192];
180 Error error;
181
182 LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS | KDP_LOG_VERBOSE));
183
184 // Check for a packet from our cache first without trying any reading...
185 if (CheckForPacket (NULL, 0, packet))
Greg Claytond52d00f2011-07-16 03:19:08 +0000186 return packet.GetByteSize();
Greg Clayton363be3f2011-07-15 03:27:12 +0000187
188 bool timed_out = false;
189 while (IsConnected() && !timed_out)
190 {
191 lldb::ConnectionStatus status;
192 size_t bytes_read = Read (buffer, sizeof(buffer), timeout_usec, status, &error);
193
194 if (log)
195 log->Printf ("%s: Read (buffer, (sizeof(buffer), timeout_usec = 0x%x, status = %s, error = %s) => bytes_read = %zu",
196 __PRETTY_FUNCTION__,
197 timeout_usec,
198 Communication::ConnectionStatusAsCString (status),
199 error.AsCString(),
200 bytes_read);
201
202 if (bytes_read > 0)
203 {
204 if (CheckForPacket (buffer, bytes_read, packet))
Greg Claytond52d00f2011-07-16 03:19:08 +0000205 return packet.GetByteSize();
Greg Clayton363be3f2011-07-15 03:27:12 +0000206 }
207 else
208 {
209 switch (status)
210 {
211 case eConnectionStatusTimedOut:
212 timed_out = true;
213 break;
214 case eConnectionStatusSuccess:
215 //printf ("status = success but error = %s\n", error.AsCString("<invalid>"));
216 break;
217
218 case eConnectionStatusEndOfFile:
219 case eConnectionStatusNoConnection:
220 case eConnectionStatusLostConnection:
221 case eConnectionStatusError:
222 Disconnect();
223 break;
224 }
225 }
226 }
227 packet.Clear ();
228 return 0;
229}
230
231bool
Greg Claytond52d00f2011-07-16 03:19:08 +0000232CommunicationKDP::CheckForPacket (const uint8_t *src, size_t src_len, DataExtractor &packet)
Greg Clayton363be3f2011-07-15 03:27:12 +0000233{
234 // Put the packet data into the buffer in a thread safe fashion
235 Mutex::Locker locker(m_bytes_mutex);
236
237 LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS));
238
239 if (src && src_len > 0)
240 {
241 if (log && log->GetVerbose())
242 {
Greg Claytond52d00f2011-07-16 03:19:08 +0000243 PacketStreamType log_strm;
Greg Clayton8d2ea282011-07-17 20:36:25 +0000244 DataExtractor::DumpHexBytes (&log_strm, src, src_len, UINT32_MAX, LLDB_INVALID_ADDRESS);
Greg Claytond52d00f2011-07-16 03:19:08 +0000245 log->Printf ("CommunicationKDP::%s adding %u bytes: %s",
Greg Clayton363be3f2011-07-15 03:27:12 +0000246 __FUNCTION__,
247 (uint32_t)src_len,
Greg Claytond52d00f2011-07-16 03:19:08 +0000248 log_strm.GetData());
Greg Clayton363be3f2011-07-15 03:27:12 +0000249 }
250 m_bytes.append ((const char *)src, src_len);
251 }
252
Greg Claytond52d00f2011-07-16 03:19:08 +0000253 // Make sure we at least have enough bytes for a packet header
254 const size_t bytes_available = m_bytes.size();
255 if (bytes_available >= 8)
Greg Clayton363be3f2011-07-15 03:27:12 +0000256 {
Greg Claytond52d00f2011-07-16 03:19:08 +0000257 packet.SetData (&m_bytes[0], bytes_available, m_byte_order);
258 uint32_t offset = 0;
259 uint8_t reply_command = packet.GetU8(&offset);
260 switch (reply_command)
261 {
262 case ePacketTypeReply | eCommandTypeConnect:
263 case ePacketTypeReply | eCommandTypeDisconnect:
264 case ePacketTypeReply | eCommandTypeHostInfo:
265 case ePacketTypeReply | eCommandTypeVersion:
266 case ePacketTypeReply | eCommandTypeMaxBytes:
267 case ePacketTypeReply | eCommandTypeReadMemory:
268 case ePacketTypeReply | eCommandTypeWriteMemory:
269 case ePacketTypeReply | eCommandTypeReadRegisters:
270 case ePacketTypeReply | eCommandTypeWriteRegisters:
271 case ePacketTypeReply | eCommandTypeLoad:
272 case ePacketTypeReply | eCommandTypeImagePath:
273 case ePacketTypeReply | eCommandTypeSuspend:
274 case ePacketTypeReply | eCommandTypeResume:
275 case ePacketTypeReply | eCommandTypeException:
276 case ePacketTypeReply | eCommandTypeTermination:
277 case ePacketTypeReply | eCommandTypeBreakpointSet:
278 case ePacketTypeReply | eCommandTypeBreakpointRemove:
279 case ePacketTypeReply | eCommandTypeRegions:
280 case ePacketTypeReply | eCommandTypeReattach:
281 case ePacketTypeReply | eCommandTypeHostReboot:
282 case ePacketTypeReply | eCommandTypeReadMemory64:
283 case ePacketTypeReply | eCommandTypeWriteMemory64:
284 case ePacketTypeReply | eCommandTypeBreakpointSet64:
285 case ePacketTypeReply | eCommandTypeBreakpointRemove64:
286 case ePacketTypeReply | eCommandTypeKernelVersion:
287 {
288 offset = 2;
289 const uint16_t length = packet.GetU16 (&offset);
290 if (length <= bytes_available)
291 {
292 // We have an entire packet ready, we need to copy the data
293 // bytes into a buffer that will be owned by the packet and
294 // erase the bytes from our communcation buffer "m_bytes"
295 packet.SetData (DataBufferSP (new DataBufferHeap (&m_bytes[0], length)));
296 m_bytes.erase (0, length);
Greg Clayton8d2ea282011-07-17 20:36:25 +0000297
298 if (log)
299 {
300 PacketStreamType log_strm;
301 packet.Dump (&log_strm, // Stream to dump to
302 0, // Offset into "packet"
303 eFormatBytes, // Dump as hex bytes
304 1, // Size of each item is 1 for single bytes
305 length, // Number of bytes
306 UINT32_MAX, // Num bytes per line
307 LLDB_INVALID_ADDRESS, // Base address
308 0, 0); // Bitfield info set to not do anything bitfield related
309
310 log->Printf("recv kdp-packet: %.*s",
311 (uint32_t)log_strm.GetSize(),
312 log_strm.GetData());
313 }
Greg Claytond52d00f2011-07-16 03:19:08 +0000314 return true;
315 }
316 }
317 break;
318
319 default:
320 // Unrecognized reply command byte, erase this byte and try to get back on track
321 if (log)
322 log->Printf ("CommunicationKDP::%s: tossing junk byte: 0x%2.2x",
323 __FUNCTION__,
324 (uint8_t)m_bytes[0]);
325 m_bytes.erase(0, 1);
326 break;
327 }
Greg Clayton363be3f2011-07-15 03:27:12 +0000328 }
329 packet.Clear();
330 return false;
331}
332
Greg Clayton1e5b0212011-07-15 16:31:38 +0000333
Greg Claytond52d00f2011-07-16 03:19:08 +0000334bool
Greg Clayton8d2ea282011-07-17 20:36:25 +0000335CommunicationKDP::SendRequestConnect (uint16_t reply_port,
336 uint16_t exc_port,
337 const char *greeting)
Greg Clayton1e5b0212011-07-15 16:31:38 +0000338{
Greg Claytond52d00f2011-07-16 03:19:08 +0000339 PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order);
340 if (greeting == NULL)
341 greeting = "";
342
343 const CommandType command = eCommandTypeConnect;
Greg Clayton8d2ea282011-07-17 20:36:25 +0000344 // Length is 82 uint16_t and the length of the greeting C string with the terminating NULL
345 const uint32_t command_length = 8 + 2 + 2 + ::strlen(greeting) + 1;
Greg Claytond52d00f2011-07-16 03:19:08 +0000346 const uint32_t request_sequence_id = m_request_sequence_id;
347 MakeRequestPacketHeader (command, request_packet, command_length);
Greg Clayton8d2ea282011-07-17 20:36:25 +0000348 // Always send connect ports as little endian
349 request_packet.SetByteOrder (eByteOrderLittle);
350 request_packet.PutHex16 (reply_port);
351 request_packet.PutHex16 (exc_port);
352 request_packet.SetByteOrder (m_byte_order);
353 request_packet.PutCString (greeting);
Greg Claytond52d00f2011-07-16 03:19:08 +0000354 DataExtractor reply_packet;
355 return SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet);
Greg Clayton1e5b0212011-07-15 16:31:38 +0000356}
357
Greg Claytond52d00f2011-07-16 03:19:08 +0000358void
359CommunicationKDP::ClearKDPSettings ()
360{
361 m_request_sequence_id = 0;
362 m_kdp_version_version = 0;
363 m_kdp_version_feature = 0;
364 m_kdp_hostinfo_cpu_mask = 0;
365 m_kdp_hostinfo_cpu_type = 0;
366 m_kdp_hostinfo_cpu_subtype = 0;
367}
368
369bool
Greg Clayton8d2ea282011-07-17 20:36:25 +0000370CommunicationKDP::SendRequestReattach (uint16_t reply_port)
Greg Claytond52d00f2011-07-16 03:19:08 +0000371{
372 PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order);
373 const CommandType command = eCommandTypeReattach;
374 // Length is 8 bytes for the header plus 2 bytes for the reply UDP port
375 const uint32_t command_length = 8 + 2;
376 const uint32_t request_sequence_id = m_request_sequence_id;
377 MakeRequestPacketHeader (command, request_packet, command_length);
Greg Clayton8d2ea282011-07-17 20:36:25 +0000378 // Always send connect ports as little endian
379 request_packet.SetByteOrder (eByteOrderLittle);
Greg Claytond52d00f2011-07-16 03:19:08 +0000380 request_packet.PutHex16(reply_port);
Greg Clayton8d2ea282011-07-17 20:36:25 +0000381 request_packet.SetByteOrder (m_byte_order);
Greg Claytond52d00f2011-07-16 03:19:08 +0000382 DataExtractor reply_packet;
383 if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet))
384 {
385 // Reset the sequence ID to zero for reattach
386 ClearKDPSettings ();
387 uint32_t offset = 4;
388 m_session_key = reply_packet.GetU32 (&offset);
389 return true;
390 }
391 return false;
392}
393
394uint32_t
395CommunicationKDP::GetVersion ()
396{
397 if (!VersionIsValid())
398 SendRequestVersion();
399 return m_kdp_version_version;
400}
401
402uint32_t
403CommunicationKDP::GetFeatureFlags ()
404{
405 if (!VersionIsValid())
406 SendRequestVersion();
407 return m_kdp_version_feature;
408}
409
410bool
411CommunicationKDP::SendRequestVersion ()
412{
413 PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order);
414 const CommandType command = eCommandTypeVersion;
415 const uint32_t command_length = 8;
416 const uint32_t request_sequence_id = m_request_sequence_id;
417 MakeRequestPacketHeader (command, request_packet, command_length);
418 DataExtractor reply_packet;
419 if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet))
420 {
421 // Reset the sequence ID to zero for reattach
422 uint32_t offset = 8;
423 m_kdp_version_version = reply_packet.GetU32 (&offset);
424 m_kdp_version_feature = reply_packet.GetU32 (&offset);
425 return true;
426 }
427 return false;
428}
429
430uint32_t
431CommunicationKDP::GetCPUMask ()
432{
433 if (!HostInfoIsValid())
434 SendRequestHostInfo();
435 return m_kdp_hostinfo_cpu_mask;
436}
437
438uint32_t
439CommunicationKDP::GetCPUType ()
440{
441 if (!HostInfoIsValid())
442 SendRequestHostInfo();
443 return m_kdp_hostinfo_cpu_type;
444}
445
446uint32_t
447CommunicationKDP::GetCPUSubtype ()
448{
449 if (!HostInfoIsValid())
450 SendRequestHostInfo();
451 return m_kdp_hostinfo_cpu_subtype;
452}
453
454bool
455CommunicationKDP::SendRequestHostInfo ()
456{
457 PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order);
458 const CommandType command = eCommandTypeHostInfo;
459 const uint32_t command_length = 8;
460 const uint32_t request_sequence_id = m_request_sequence_id;
461 MakeRequestPacketHeader (command, request_packet, command_length);
462 DataExtractor reply_packet;
463 if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet))
464 {
465 // Reset the sequence ID to zero for reattach
466 uint32_t offset = 8;
467 m_kdp_hostinfo_cpu_mask = reply_packet.GetU32 (&offset);
468 m_kdp_hostinfo_cpu_type = reply_packet.GetU32 (&offset);
469 m_kdp_hostinfo_cpu_subtype = reply_packet.GetU32 (&offset);
470 return true;
471 }
472 return false;
473}
474
475bool
Greg Clayton8d2ea282011-07-17 20:36:25 +0000476CommunicationKDP::SendRequestDisconnect ()
Greg Clayton1e5b0212011-07-15 16:31:38 +0000477{
Greg Claytond52d00f2011-07-16 03:19:08 +0000478 PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order);
479 const CommandType command = eCommandTypeDisconnect;
480 const uint32_t command_length = 8;
481 const uint32_t request_sequence_id = m_request_sequence_id;
482 MakeRequestPacketHeader (command, request_packet, command_length);
483 DataExtractor reply_packet;
484 if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet))
485 {
486 // Are we supposed to get a reply for disconnect?
487 }
488 ClearKDPSettings ();
489 return true;
Greg Clayton1e5b0212011-07-15 16:31:38 +0000490}
491