blob: c3ac577febdb9ee12fcb4771658467b3bc1f078d [file] [log] [blame]
Greg Clayton363be3f2011-07-15 03:27:12 +00001//===-- CommunicationKDP.cpp ------------------------------*- C++ -*-===//
2//
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
19#include "lldb/Core/Log.h"
20#include "lldb/Core/StreamString.h"
21#include "lldb/Host/FileSpec.h"
22#include "lldb/Host/Host.h"
23#include "lldb/Host/TimeValue.h"
24#include "lldb/Target/Process.h"
25#include "Utility/StringExtractor.h"
26
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),
40 m_packet_timeout (1),
41 m_sequence_mutex (Mutex::eMutexTypeRecursive),
42 m_public_is_running (false),
43 m_private_is_running (false),
44 m_send_acks (true)
45{
46}
47
48//----------------------------------------------------------------------
49// Destructor
50//----------------------------------------------------------------------
51CommunicationKDP::~CommunicationKDP()
52{
53 if (IsConnected())
54 {
55 Disconnect();
56 }
57}
58
59char
60CommunicationKDP::CalculcateChecksum (const char *payload, size_t payload_length)
61{
62 int checksum = 0;
63
64 // We only need to compute the checksum if we are sending acks
65 if (GetSendAcks ())
66 {
67 for (size_t i = 0; i < payload_length; ++i)
68 checksum += payload[i];
69 }
70 return checksum & 255;
71}
72
73size_t
74CommunicationKDP::SendAck ()
75{
76 LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS));
77 if (log)
78 log->Printf ("send packet: +");
79 ConnectionStatus status = eConnectionStatusSuccess;
80 char ack_char = '+';
81 return Write (&ack_char, 1, status, NULL);
82}
83
84size_t
85CommunicationKDP::SendNack ()
86{
87 LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS));
88 if (log)
89 log->Printf ("send packet: -");
90 ConnectionStatus status = eConnectionStatusSuccess;
91 char nack_char = '-';
92 return Write (&nack_char, 1, status, NULL);
93}
94
95size_t
96CommunicationKDP::SendPacket (lldb_private::StreamString &payload)
97{
98 Mutex::Locker locker(m_sequence_mutex);
99 const std::string &p (payload.GetString());
100 return SendPacketNoLock (p.c_str(), p.size());
101}
102
103size_t
104CommunicationKDP::SendPacket (const char *payload)
105{
106 Mutex::Locker locker(m_sequence_mutex);
107 return SendPacketNoLock (payload, ::strlen (payload));
108}
109
110size_t
111CommunicationKDP::SendPacket (const char *payload, size_t payload_length)
112{
113 Mutex::Locker locker(m_sequence_mutex);
114 return SendPacketNoLock (payload, payload_length);
115}
116
117size_t
118CommunicationKDP::SendPacketNoLock (const char *payload, size_t payload_length)
119{
120 if (IsConnected())
121 {
122 StreamString packet(0, 4, eByteOrderBig);
123
124 packet.PutChar('$');
125 packet.Write (payload, payload_length);
126 packet.PutChar('#');
127 packet.PutHex8(CalculcateChecksum (payload, payload_length));
128
129 LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS));
130 if (log)
131 log->Printf ("send packet: %.*s", (int)packet.GetSize(), packet.GetData());
132 ConnectionStatus status = eConnectionStatusSuccess;
133 size_t bytes_written = Write (packet.GetData(), packet.GetSize(), status, NULL);
134 if (bytes_written == packet.GetSize())
135 {
136 if (GetSendAcks ())
137 {
138 if (GetAck () != '+')
139 {
140 printf("get ack failed...");
141 return 0;
142 }
143 }
144 }
145 else
146 {
147 LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS));
148 if (log)
149 log->Printf ("error: failed to send packet: %.*s", (int)packet.GetSize(), packet.GetData());
150 }
151 return bytes_written;
152 }
153 return 0;
154}
155
156char
157CommunicationKDP::GetAck ()
158{
159 StringExtractor packet;
160 if (WaitForPacketWithTimeoutMicroSeconds (packet, GetPacketTimeoutInMicroSeconds ()) == 1)
161 return packet.GetChar();
162 return 0;
163}
164
165bool
166CommunicationKDP::GetSequenceMutex (Mutex::Locker& locker)
167{
168 return locker.TryLock (m_sequence_mutex.GetMutex());
169}
170
171
172bool
173CommunicationKDP::WaitForNotRunningPrivate (const TimeValue *timeout_ptr)
174{
175 return m_private_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL);
176}
177
178size_t
179CommunicationKDP::WaitForPacketWithTimeoutMicroSeconds (StringExtractor &packet, uint32_t timeout_usec)
180{
181 Mutex::Locker locker(m_sequence_mutex);
182 return WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec);
183}
184
185size_t
186CommunicationKDP::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractor &packet, uint32_t timeout_usec)
187{
188 uint8_t buffer[8192];
189 Error error;
190
191 LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS | KDP_LOG_VERBOSE));
192
193 // Check for a packet from our cache first without trying any reading...
194 if (CheckForPacket (NULL, 0, packet))
195 return packet.GetStringRef().size();
196
197 bool timed_out = false;
198 while (IsConnected() && !timed_out)
199 {
200 lldb::ConnectionStatus status;
201 size_t bytes_read = Read (buffer, sizeof(buffer), timeout_usec, status, &error);
202
203 if (log)
204 log->Printf ("%s: Read (buffer, (sizeof(buffer), timeout_usec = 0x%x, status = %s, error = %s) => bytes_read = %zu",
205 __PRETTY_FUNCTION__,
206 timeout_usec,
207 Communication::ConnectionStatusAsCString (status),
208 error.AsCString(),
209 bytes_read);
210
211 if (bytes_read > 0)
212 {
213 if (CheckForPacket (buffer, bytes_read, packet))
214 return packet.GetStringRef().size();
215 }
216 else
217 {
218 switch (status)
219 {
220 case eConnectionStatusTimedOut:
221 timed_out = true;
222 break;
223 case eConnectionStatusSuccess:
224 //printf ("status = success but error = %s\n", error.AsCString("<invalid>"));
225 break;
226
227 case eConnectionStatusEndOfFile:
228 case eConnectionStatusNoConnection:
229 case eConnectionStatusLostConnection:
230 case eConnectionStatusError:
231 Disconnect();
232 break;
233 }
234 }
235 }
236 packet.Clear ();
237 return 0;
238}
239
240bool
241CommunicationKDP::CheckForPacket (const uint8_t *src, size_t src_len, StringExtractor &packet)
242{
243 // Put the packet data into the buffer in a thread safe fashion
244 Mutex::Locker locker(m_bytes_mutex);
245
246 LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS));
247
248 if (src && src_len > 0)
249 {
250 if (log && log->GetVerbose())
251 {
252 StreamString s;
253 log->Printf ("CommunicationKDP::%s adding %u bytes: %.*s",
254 __FUNCTION__,
255 (uint32_t)src_len,
256 (uint32_t)src_len,
257 src);
258 }
259 m_bytes.append ((const char *)src, src_len);
260 }
261
262 // Parse up the packets into gdb remote packets
263 if (!m_bytes.empty())
264 {
265 // end_idx must be one past the last valid packet byte. Start
266 // it off with an invalid value that is the same as the current
267 // index.
268 size_t content_start = 0;
269 size_t content_length = 0;
270 size_t total_length = 0;
271 size_t checksum_idx = std::string::npos;
272
273 switch (m_bytes[0])
274 {
275 case '+': // Look for ack
276 case '-': // Look for cancel
277 case '\x03': // ^C to halt target
278 content_length = total_length = 1; // The command is one byte long...
279 break;
280
281 case '$':
282 // Look for a standard gdb packet?
283 {
284 size_t hash_pos = m_bytes.find('#');
285 if (hash_pos != std::string::npos)
286 {
287 if (hash_pos + 2 < m_bytes.size())
288 {
289 checksum_idx = hash_pos + 1;
290 // Skip the dollar sign
291 content_start = 1;
292 // Don't include the # in the content or the $ in the content length
293 content_length = hash_pos - 1;
294
295 total_length = hash_pos + 3; // Skip the # and the two hex checksum bytes
296 }
297 else
298 {
299 // Checksum bytes aren't all here yet
300 content_length = std::string::npos;
301 }
302 }
303 }
304 break;
305
306 default:
307 {
308 // We have an unexpected byte and we need to flush all bad
309 // data that is in m_bytes, so we need to find the first
310 // byte that is a '+' (ACK), '-' (NACK), \x03 (CTRL+C interrupt),
311 // or '$' character (start of packet header) or of course,
312 // the end of the data in m_bytes...
313 const size_t bytes_len = m_bytes.size();
314 bool done = false;
315 uint32_t idx;
316 for (idx = 1; !done && idx < bytes_len; ++idx)
317 {
318 switch (m_bytes[idx])
319 {
320 case '+':
321 case '-':
322 case '\x03':
323 case '$':
324 done = true;
325 break;
326
327 default:
328 break;
329 }
330 }
331 if (log)
332 log->Printf ("CommunicationKDP::%s tossing %u junk bytes: '%.*s'",
333 __FUNCTION__, idx, idx, m_bytes.c_str());
334 m_bytes.erase(0, idx);
335 }
336 break;
337 }
338
339 if (content_length == std::string::npos)
340 {
341 packet.Clear();
342 return false;
343 }
344 else if (total_length > 0)
345 {
346
347 // We have a valid packet...
348 assert (content_length <= m_bytes.size());
349 assert (total_length <= m_bytes.size());
350 assert (content_length <= total_length);
351
352 bool success = true;
353 std::string &packet_str = packet.GetStringRef();
354 packet_str.assign (m_bytes, content_start, content_length);
355 if (m_bytes[0] == '$')
356 {
357 assert (checksum_idx < m_bytes.size());
358 if (::isxdigit (m_bytes[checksum_idx+0]) ||
359 ::isxdigit (m_bytes[checksum_idx+1]))
360 {
361 if (GetSendAcks ())
362 {
363 const char *packet_checksum_cstr = &m_bytes[checksum_idx];
364 char packet_checksum = strtol (packet_checksum_cstr, NULL, 16);
365 char actual_checksum = CalculcateChecksum (packet_str.c_str(), packet_str.size());
366 success = packet_checksum == actual_checksum;
367 if (!success)
368 {
369 if (log)
370 log->Printf ("error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x",
371 (int)(total_length),
372 m_bytes.c_str(),
373 (uint8_t)packet_checksum,
374 (uint8_t)actual_checksum);
375 }
376 // Send the ack or nack if needed
377 if (!success)
378 SendNack();
379 else
380 SendAck();
381 }
382 if (success)
383 {
384 if (log)
385 log->Printf ("read packet: %.*s", (int)(total_length), m_bytes.c_str());
386 }
387 }
388 else
389 {
390 success = false;
391 if (log)
392 log->Printf ("error: invalid checksum in packet: '%s'\n", (int)(total_length), m_bytes.c_str());
393 }
394 }
395 m_bytes.erase(0, total_length);
396 packet.SetFilePos(0);
397 return success;
398 }
399 }
400 packet.Clear();
401 return false;
402}
403