File: | tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp |
Location: | line 791, column 21 |
Description: | Call to function 'mktemp' is insecure as it always creates or uses insecure temporary file. Use 'mkstemp' instead |
1 | //===-- GDBRemoteCommunication.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 "GDBRemoteCommunication.h" |
12 | |
13 | // C Includes |
14 | #include <limits.h> |
15 | #include <string.h> |
16 | #include <sys/stat.h> |
17 | |
18 | // C++ Includes |
19 | // Other libraries and framework includes |
20 | #include "lldb/Core/Log.h" |
21 | #include "lldb/Core/StreamFile.h" |
22 | #include "lldb/Core/StreamString.h" |
23 | #include "lldb/Host/ConnectionFileDescriptor.h" |
24 | #include "lldb/Host/FileSpec.h" |
25 | #include "lldb/Host/Host.h" |
26 | #include "lldb/Host/HostInfo.h" |
27 | #include "lldb/Host/Pipe.h" |
28 | #include "lldb/Host/Socket.h" |
29 | #include "lldb/Host/StringConvert.h" |
30 | #include "lldb/Host/ThreadLauncher.h" |
31 | #include "lldb/Host/TimeValue.h" |
32 | #include "lldb/Target/Process.h" |
33 | |
34 | // Project includes |
35 | #include "ProcessGDBRemoteLog.h" |
36 | |
37 | #if defined(__APPLE__) |
38 | # define DEBUGSERVER_BASENAME"lldb-gdbserver" "debugserver" |
39 | #else |
40 | # define DEBUGSERVER_BASENAME"lldb-gdbserver" "lldb-gdbserver" |
41 | #endif |
42 | |
43 | using namespace lldb; |
44 | using namespace lldb_private; |
45 | |
46 | GDBRemoteCommunication::History::History (uint32_t size) : |
47 | m_packets(), |
48 | m_curr_idx (0), |
49 | m_total_packet_count (0), |
50 | m_dumped_to_log (false) |
51 | { |
52 | m_packets.resize(size); |
53 | } |
54 | |
55 | GDBRemoteCommunication::History::~History () |
56 | { |
57 | } |
58 | |
59 | void |
60 | GDBRemoteCommunication::History::AddPacket (char packet_char, |
61 | PacketType type, |
62 | uint32_t bytes_transmitted) |
63 | { |
64 | const size_t size = m_packets.size(); |
65 | if (size > 0) |
66 | { |
67 | const uint32_t idx = GetNextIndex(); |
68 | m_packets[idx].packet.assign (1, packet_char); |
69 | m_packets[idx].type = type; |
70 | m_packets[idx].bytes_transmitted = bytes_transmitted; |
71 | m_packets[idx].packet_idx = m_total_packet_count; |
72 | m_packets[idx].tid = Host::GetCurrentThreadID(); |
73 | } |
74 | } |
75 | |
76 | void |
77 | GDBRemoteCommunication::History::AddPacket (const std::string &src, |
78 | uint32_t src_len, |
79 | PacketType type, |
80 | uint32_t bytes_transmitted) |
81 | { |
82 | const size_t size = m_packets.size(); |
83 | if (size > 0) |
84 | { |
85 | const uint32_t idx = GetNextIndex(); |
86 | m_packets[idx].packet.assign (src, 0, src_len); |
87 | m_packets[idx].type = type; |
88 | m_packets[idx].bytes_transmitted = bytes_transmitted; |
89 | m_packets[idx].packet_idx = m_total_packet_count; |
90 | m_packets[idx].tid = Host::GetCurrentThreadID(); |
91 | } |
92 | } |
93 | |
94 | void |
95 | GDBRemoteCommunication::History::Dump (lldb_private::Stream &strm) const |
96 | { |
97 | const uint32_t size = GetNumPacketsInHistory (); |
98 | const uint32_t first_idx = GetFirstSavedPacketIndex (); |
99 | const uint32_t stop_idx = m_curr_idx + size; |
100 | for (uint32_t i = first_idx; i < stop_idx; ++i) |
101 | { |
102 | const uint32_t idx = NormalizeIndex (i); |
103 | const Entry &entry = m_packets[idx]; |
104 | if (entry.type == ePacketTypeInvalid || entry.packet.empty()) |
105 | break; |
106 | strm.Printf ("history[%u] tid=0x%4.4" PRIx64"l" "x" " <%4u> %s packet: %s\n", |
107 | entry.packet_idx, |
108 | entry.tid, |
109 | entry.bytes_transmitted, |
110 | (entry.type == ePacketTypeSend) ? "send" : "read", |
111 | entry.packet.c_str()); |
112 | } |
113 | } |
114 | |
115 | void |
116 | GDBRemoteCommunication::History::Dump (lldb_private::Log *log) const |
117 | { |
118 | if (log && !m_dumped_to_log) |
119 | { |
120 | m_dumped_to_log = true; |
121 | const uint32_t size = GetNumPacketsInHistory (); |
122 | const uint32_t first_idx = GetFirstSavedPacketIndex (); |
123 | const uint32_t stop_idx = m_curr_idx + size; |
124 | for (uint32_t i = first_idx; i < stop_idx; ++i) |
125 | { |
126 | const uint32_t idx = NormalizeIndex (i); |
127 | const Entry &entry = m_packets[idx]; |
128 | if (entry.type == ePacketTypeInvalid || entry.packet.empty()) |
129 | break; |
130 | log->Printf ("history[%u] tid=0x%4.4" PRIx64"l" "x" " <%4u> %s packet: %s", |
131 | entry.packet_idx, |
132 | entry.tid, |
133 | entry.bytes_transmitted, |
134 | (entry.type == ePacketTypeSend) ? "send" : "read", |
135 | entry.packet.c_str()); |
136 | } |
137 | } |
138 | } |
139 | |
140 | //---------------------------------------------------------------------- |
141 | // GDBRemoteCommunication constructor |
142 | //---------------------------------------------------------------------- |
143 | GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, |
144 | const char *listener_name, |
145 | bool is_platform) : |
146 | Communication(comm_name), |
147 | #ifdef LLDB_CONFIGURATION_DEBUG |
148 | m_packet_timeout (1000), |
149 | #else |
150 | m_packet_timeout (1), |
151 | #endif |
152 | m_sequence_mutex (Mutex::eMutexTypeRecursive), |
153 | m_public_is_running (false), |
154 | m_private_is_running (false), |
155 | m_history (512), |
156 | m_send_acks (true), |
157 | m_is_platform (is_platform), |
158 | m_listen_url () |
159 | { |
160 | } |
161 | |
162 | //---------------------------------------------------------------------- |
163 | // Destructor |
164 | //---------------------------------------------------------------------- |
165 | GDBRemoteCommunication::~GDBRemoteCommunication() |
166 | { |
167 | if (IsConnected()) |
168 | { |
169 | Disconnect(); |
170 | } |
171 | } |
172 | |
173 | char |
174 | GDBRemoteCommunication::CalculcateChecksum (const char *payload, size_t payload_length) |
175 | { |
176 | int checksum = 0; |
177 | |
178 | for (size_t i = 0; i < payload_length; ++i) |
179 | checksum += payload[i]; |
180 | |
181 | return checksum & 255; |
182 | } |
183 | |
184 | size_t |
185 | GDBRemoteCommunication::SendAck () |
186 | { |
187 | Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS(1u << 3))); |
188 | ConnectionStatus status = eConnectionStatusSuccess; |
189 | char ch = '+'; |
190 | const size_t bytes_written = Write (&ch, 1, status, NULL__null); |
191 | if (log) |
192 | log->Printf ("<%4" PRIu64"l" "u" "> send packet: %c", (uint64_t)bytes_written, ch); |
193 | m_history.AddPacket (ch, History::ePacketTypeSend, bytes_written); |
194 | return bytes_written; |
195 | } |
196 | |
197 | size_t |
198 | GDBRemoteCommunication::SendNack () |
199 | { |
200 | Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS(1u << 3))); |
201 | ConnectionStatus status = eConnectionStatusSuccess; |
202 | char ch = '-'; |
203 | const size_t bytes_written = Write (&ch, 1, status, NULL__null); |
204 | if (log) |
205 | log->Printf("<%4" PRIu64"l" "u" "> send packet: %c", (uint64_t)bytes_written, ch); |
206 | m_history.AddPacket (ch, History::ePacketTypeSend, bytes_written); |
207 | return bytes_written; |
208 | } |
209 | |
210 | GDBRemoteCommunication::PacketResult |
211 | GDBRemoteCommunication::SendPacket (const char *payload, size_t payload_length) |
212 | { |
213 | Mutex::Locker locker(m_sequence_mutex); |
214 | return SendPacketNoLock (payload, payload_length); |
215 | } |
216 | |
217 | GDBRemoteCommunication::PacketResult |
218 | GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_length) |
219 | { |
220 | if (IsConnected()) |
221 | { |
222 | StreamString packet(0, 4, eByteOrderBig); |
223 | |
224 | packet.PutChar('$'); |
225 | packet.Write (payload, payload_length); |
226 | packet.PutChar('#'); |
227 | packet.PutHex8(CalculcateChecksum (payload, payload_length)); |
228 | |
229 | Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS(1u << 3))); |
230 | ConnectionStatus status = eConnectionStatusSuccess; |
231 | const char *packet_data = packet.GetData(); |
232 | const size_t packet_length = packet.GetSize(); |
233 | size_t bytes_written = Write (packet_data, packet_length, status, NULL__null); |
234 | if (log) |
235 | { |
236 | size_t binary_start_offset = 0; |
237 | if (strncmp(packet_data, "$vFile:pwrite:", strlen("$vFile:pwrite:")) == 0) |
238 | { |
239 | const char *first_comma = strchr(packet_data, ','); |
240 | if (first_comma) |
241 | { |
242 | const char *second_comma = strchr(first_comma + 1, ','); |
243 | if (second_comma) |
244 | binary_start_offset = second_comma - packet_data + 1; |
245 | } |
246 | } |
247 | |
248 | // If logging was just enabled and we have history, then dump out what |
249 | // we have to the log so we get the historical context. The Dump() call that |
250 | // logs all of the packet will set a boolean so that we don't dump this more |
251 | // than once |
252 | if (!m_history.DidDumpToLog ()) |
253 | m_history.Dump (log); |
254 | |
255 | if (binary_start_offset) |
256 | { |
257 | StreamString strm; |
258 | // Print non binary data header |
259 | strm.Printf("<%4" PRIu64"l" "u" "> send packet: %.*s", (uint64_t)bytes_written, (int)binary_start_offset, packet_data); |
260 | const uint8_t *p; |
261 | // Print binary data exactly as sent |
262 | for (p = (uint8_t*)packet_data + binary_start_offset; *p != '#'; ++p) |
263 | strm.Printf("\\x%2.2x", *p); |
264 | // Print the checksum |
265 | strm.Printf("%*s", (int)3, p); |
266 | log->PutCString(strm.GetString().c_str()); |
267 | } |
268 | else |
269 | log->Printf("<%4" PRIu64"l" "u" "> send packet: %.*s", (uint64_t)bytes_written, (int)packet_length, packet_data); |
270 | } |
271 | |
272 | m_history.AddPacket (packet.GetString(), packet_length, History::ePacketTypeSend, bytes_written); |
273 | |
274 | |
275 | if (bytes_written == packet_length) |
276 | { |
277 | if (GetSendAcks ()) |
278 | return GetAck (); |
279 | else |
280 | return PacketResult::Success; |
281 | } |
282 | else |
283 | { |
284 | if (log) |
285 | log->Printf ("error: failed to send packet: %.*s", (int)packet_length, packet_data); |
286 | } |
287 | } |
288 | return PacketResult::ErrorSendFailed; |
289 | } |
290 | |
291 | GDBRemoteCommunication::PacketResult |
292 | GDBRemoteCommunication::GetAck () |
293 | { |
294 | StringExtractorGDBRemote packet; |
295 | PacketResult result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, GetPacketTimeoutInMicroSeconds ()); |
296 | if (result == PacketResult::Success) |
297 | { |
298 | if (packet.GetResponseType() == StringExtractorGDBRemote::ResponseType::eAck) |
299 | return PacketResult::Success; |
300 | else |
301 | return PacketResult::ErrorSendAck; |
302 | } |
303 | return result; |
304 | } |
305 | |
306 | bool |
307 | GDBRemoteCommunication::GetSequenceMutex (Mutex::Locker& locker, const char *failure_message) |
308 | { |
309 | if (IsRunning()) |
310 | return locker.TryLock (m_sequence_mutex, failure_message); |
311 | |
312 | locker.Lock (m_sequence_mutex); |
313 | return true; |
314 | } |
315 | |
316 | |
317 | bool |
318 | GDBRemoteCommunication::WaitForNotRunningPrivate (const TimeValue *timeout_ptr) |
319 | { |
320 | return m_private_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL__null); |
321 | } |
322 | |
323 | GDBRemoteCommunication::PacketResult |
324 | GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &packet, uint32_t timeout_usec) |
325 | { |
326 | uint8_t buffer[8192]; |
327 | Error error; |
328 | |
329 | Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS(1u << 3) | GDBR_LOG_VERBOSE(1u << 0))); |
330 | |
331 | // Check for a packet from our cache first without trying any reading... |
332 | if (CheckForPacket (NULL__null, 0, packet)) |
333 | return PacketResult::Success; |
334 | |
335 | bool timed_out = false; |
336 | bool disconnected = false; |
337 | while (IsConnected() && !timed_out) |
338 | { |
339 | lldb::ConnectionStatus status = eConnectionStatusNoConnection; |
340 | size_t bytes_read = Read (buffer, sizeof(buffer), timeout_usec, status, &error); |
341 | |
342 | if (log) |
343 | log->Printf ("%s: Read (buffer, (sizeof(buffer), timeout_usec = 0x%x, status = %s, error = %s) => bytes_read = %" PRIu64"l" "u", |
344 | __PRETTY_FUNCTION__, |
345 | timeout_usec, |
346 | Communication::ConnectionStatusAsCString (status), |
347 | error.AsCString(), |
348 | (uint64_t)bytes_read); |
349 | |
350 | if (bytes_read > 0) |
351 | { |
352 | if (CheckForPacket (buffer, bytes_read, packet)) |
353 | return PacketResult::Success; |
354 | } |
355 | else |
356 | { |
357 | switch (status) |
358 | { |
359 | case eConnectionStatusTimedOut: |
360 | case eConnectionStatusInterrupted: |
361 | timed_out = true; |
362 | break; |
363 | case eConnectionStatusSuccess: |
364 | //printf ("status = success but error = %s\n", error.AsCString("<invalid>")); |
365 | break; |
366 | |
367 | case eConnectionStatusEndOfFile: |
368 | case eConnectionStatusNoConnection: |
369 | case eConnectionStatusLostConnection: |
370 | case eConnectionStatusError: |
371 | disconnected = true; |
372 | Disconnect(); |
373 | break; |
374 | } |
375 | } |
376 | } |
377 | packet.Clear (); |
378 | if (disconnected) |
379 | return PacketResult::ErrorDisconnected; |
380 | if (timed_out) |
381 | return PacketResult::ErrorReplyTimeout; |
382 | else |
383 | return PacketResult::ErrorReplyFailed; |
384 | } |
385 | |
386 | bool |
387 | GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, StringExtractorGDBRemote &packet) |
388 | { |
389 | // Put the packet data into the buffer in a thread safe fashion |
390 | Mutex::Locker locker(m_bytes_mutex); |
391 | |
392 | Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS(1u << 3))); |
393 | |
394 | if (src && src_len > 0) |
395 | { |
396 | if (log && log->GetVerbose()) |
397 | { |
398 | StreamString s; |
399 | log->Printf ("GDBRemoteCommunication::%s adding %u bytes: %.*s", |
400 | __FUNCTION__, |
401 | (uint32_t)src_len, |
402 | (uint32_t)src_len, |
403 | src); |
404 | } |
405 | m_bytes.append ((const char *)src, src_len); |
406 | } |
407 | |
408 | // Parse up the packets into gdb remote packets |
409 | if (!m_bytes.empty()) |
410 | { |
411 | // end_idx must be one past the last valid packet byte. Start |
412 | // it off with an invalid value that is the same as the current |
413 | // index. |
414 | size_t content_start = 0; |
415 | size_t content_length = 0; |
416 | size_t total_length = 0; |
417 | size_t checksum_idx = std::string::npos; |
418 | |
419 | switch (m_bytes[0]) |
420 | { |
421 | case '+': // Look for ack |
422 | case '-': // Look for cancel |
423 | case '\x03': // ^C to halt target |
424 | content_length = total_length = 1; // The command is one byte long... |
425 | break; |
426 | |
427 | case '$': |
428 | // Look for a standard gdb packet? |
429 | { |
430 | size_t hash_pos = m_bytes.find('#'); |
431 | if (hash_pos != std::string::npos) |
432 | { |
433 | if (hash_pos + 2 < m_bytes.size()) |
434 | { |
435 | checksum_idx = hash_pos + 1; |
436 | // Skip the dollar sign |
437 | content_start = 1; |
438 | // Don't include the # in the content or the $ in the content length |
439 | content_length = hash_pos - 1; |
440 | |
441 | total_length = hash_pos + 3; // Skip the # and the two hex checksum bytes |
442 | } |
443 | else |
444 | { |
445 | // Checksum bytes aren't all here yet |
446 | content_length = std::string::npos; |
447 | } |
448 | } |
449 | } |
450 | break; |
451 | |
452 | default: |
453 | { |
454 | // We have an unexpected byte and we need to flush all bad |
455 | // data that is in m_bytes, so we need to find the first |
456 | // byte that is a '+' (ACK), '-' (NACK), \x03 (CTRL+C interrupt), |
457 | // or '$' character (start of packet header) or of course, |
458 | // the end of the data in m_bytes... |
459 | const size_t bytes_len = m_bytes.size(); |
460 | bool done = false; |
461 | uint32_t idx; |
462 | for (idx = 1; !done && idx < bytes_len; ++idx) |
463 | { |
464 | switch (m_bytes[idx]) |
465 | { |
466 | case '+': |
467 | case '-': |
468 | case '\x03': |
469 | case '$': |
470 | done = true; |
471 | break; |
472 | |
473 | default: |
474 | break; |
475 | } |
476 | } |
477 | if (log) |
478 | log->Printf ("GDBRemoteCommunication::%s tossing %u junk bytes: '%.*s'", |
479 | __FUNCTION__, idx - 1, idx - 1, m_bytes.c_str()); |
480 | m_bytes.erase(0, idx - 1); |
481 | } |
482 | break; |
483 | } |
484 | |
485 | if (content_length == std::string::npos) |
486 | { |
487 | packet.Clear(); |
488 | return false; |
489 | } |
490 | else if (total_length > 0) |
491 | { |
492 | |
493 | // We have a valid packet... |
494 | assert (content_length <= m_bytes.size())((content_length <= m_bytes.size()) ? static_cast<void> (0) : __assert_fail ("content_length <= m_bytes.size()", "/tmp/buildd/llvm-toolchain-snapshot-3.7~svn227243/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp" , 494, __PRETTY_FUNCTION__)); |
495 | assert (total_length <= m_bytes.size())((total_length <= m_bytes.size()) ? static_cast<void> (0) : __assert_fail ("total_length <= m_bytes.size()", "/tmp/buildd/llvm-toolchain-snapshot-3.7~svn227243/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp" , 495, __PRETTY_FUNCTION__)); |
496 | assert (content_length <= total_length)((content_length <= total_length) ? static_cast<void> (0) : __assert_fail ("content_length <= total_length", "/tmp/buildd/llvm-toolchain-snapshot-3.7~svn227243/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp" , 496, __PRETTY_FUNCTION__)); |
497 | const size_t content_end = content_start + content_length; |
498 | |
499 | bool success = true; |
500 | std::string &packet_str = packet.GetStringRef(); |
501 | |
502 | |
503 | if (log) |
504 | { |
505 | // If logging was just enabled and we have history, then dump out what |
506 | // we have to the log so we get the historical context. The Dump() call that |
507 | // logs all of the packet will set a boolean so that we don't dump this more |
508 | // than once |
509 | if (!m_history.DidDumpToLog ()) |
510 | m_history.Dump (log); |
511 | |
512 | bool binary = false; |
513 | // Only detect binary for packets that start with a '$' and have a '#CC' checksum |
514 | if (m_bytes[0] == '$' && total_length > 4) |
515 | { |
516 | for (size_t i=0; !binary && i<total_length; ++i) |
517 | { |
518 | if (isprint(m_bytes[i]) == 0) |
519 | binary = true; |
520 | } |
521 | } |
522 | if (binary) |
523 | { |
524 | StreamString strm; |
525 | // Packet header... |
526 | strm.Printf("<%4" PRIu64"l" "u" "> read packet: %c", (uint64_t)total_length, m_bytes[0]); |
527 | for (size_t i=content_start; i<content_end; ++i) |
528 | { |
529 | // Remove binary escaped bytes when displaying the packet... |
530 | const char ch = m_bytes[i]; |
531 | if (ch == 0x7d) |
532 | { |
533 | // 0x7d is the escape character. The next character is to |
534 | // be XOR'd with 0x20. |
535 | const char escapee = m_bytes[++i] ^ 0x20; |
536 | strm.Printf("%2.2x", escapee); |
537 | } |
538 | else |
539 | { |
540 | strm.Printf("%2.2x", (uint8_t)ch); |
541 | } |
542 | } |
543 | // Packet footer... |
544 | strm.Printf("%c%c%c", m_bytes[total_length-3], m_bytes[total_length-2], m_bytes[total_length-1]); |
545 | log->PutCString(strm.GetString().c_str()); |
546 | } |
547 | else |
548 | { |
549 | log->Printf("<%4" PRIu64"l" "u" "> read packet: %.*s", (uint64_t)total_length, (int)(total_length), m_bytes.c_str()); |
550 | } |
551 | } |
552 | |
553 | m_history.AddPacket (m_bytes.c_str(), total_length, History::ePacketTypeRecv, total_length); |
554 | |
555 | // Clear packet_str in case there is some existing data in it. |
556 | packet_str.clear(); |
557 | // Copy the packet from m_bytes to packet_str expanding the |
558 | // run-length encoding in the process. |
559 | // Reserve enough byte for the most common case (no RLE used) |
560 | packet_str.reserve(m_bytes.length()); |
561 | for (std::string::const_iterator c = m_bytes.begin() + content_start; c != m_bytes.begin() + content_end; ++c) |
562 | { |
563 | if (*c == '*') |
564 | { |
565 | // '*' indicates RLE. Next character will give us the |
566 | // repeat count and previous character is what is to be |
567 | // repeated. |
568 | char char_to_repeat = packet_str.back(); |
569 | // Number of time the previous character is repeated |
570 | int repeat_count = *++c + 3 - ' '; |
571 | // We have the char_to_repeat and repeat_count. Now push |
572 | // it in the packet. |
573 | for (int i = 0; i < repeat_count; ++i) |
574 | packet_str.push_back(char_to_repeat); |
575 | } |
576 | else if (*c == 0x7d) |
577 | { |
578 | // 0x7d is the escape character. The next character is to |
579 | // be XOR'd with 0x20. |
580 | char escapee = *++c ^ 0x20; |
581 | packet_str.push_back(escapee); |
582 | } |
583 | else |
584 | { |
585 | packet_str.push_back(*c); |
586 | } |
587 | } |
588 | |
589 | if (m_bytes[0] == '$') |
590 | { |
591 | assert (checksum_idx < m_bytes.size())((checksum_idx < m_bytes.size()) ? static_cast<void> (0) : __assert_fail ("checksum_idx < m_bytes.size()", "/tmp/buildd/llvm-toolchain-snapshot-3.7~svn227243/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp" , 591, __PRETTY_FUNCTION__)); |
592 | if (::isxdigit (m_bytes[checksum_idx+0]) || |
593 | ::isxdigit (m_bytes[checksum_idx+1])) |
594 | { |
595 | if (GetSendAcks ()) |
596 | { |
597 | const char *packet_checksum_cstr = &m_bytes[checksum_idx]; |
598 | char packet_checksum = strtol (packet_checksum_cstr, NULL__null, 16); |
599 | char actual_checksum = CalculcateChecksum (packet_str.c_str(), packet_str.size()); |
600 | success = packet_checksum == actual_checksum; |
601 | if (!success) |
602 | { |
603 | if (log) |
604 | log->Printf ("error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x", |
605 | (int)(total_length), |
606 | m_bytes.c_str(), |
607 | (uint8_t)packet_checksum, |
608 | (uint8_t)actual_checksum); |
609 | } |
610 | // Send the ack or nack if needed |
611 | if (!success) |
612 | SendNack(); |
613 | else |
614 | SendAck(); |
615 | } |
616 | } |
617 | else |
618 | { |
619 | success = false; |
620 | if (log) |
621 | log->Printf ("error: invalid checksum in packet: '%s'\n", m_bytes.c_str()); |
622 | } |
623 | } |
624 | |
625 | m_bytes.erase(0, total_length); |
626 | packet.SetFilePos(0); |
627 | return success; |
628 | } |
629 | } |
630 | packet.Clear(); |
631 | return false; |
632 | } |
633 | |
634 | Error |
635 | GDBRemoteCommunication::StartListenThread (const char *hostname, uint16_t port) |
636 | { |
637 | Error error; |
638 | if (m_listen_thread.IsJoinable()) |
639 | { |
640 | error.SetErrorString("listen thread already running"); |
641 | } |
642 | else |
643 | { |
644 | char listen_url[512]; |
645 | if (hostname && hostname[0]) |
646 | snprintf(listen_url, sizeof(listen_url), "listen://%s:%i", hostname, port); |
647 | else |
648 | snprintf(listen_url, sizeof(listen_url), "listen://%i", port); |
649 | m_listen_url = listen_url; |
650 | SetConnection(new ConnectionFileDescriptor()); |
651 | m_listen_thread = ThreadLauncher::LaunchThread(listen_url, GDBRemoteCommunication::ListenThread, this, &error); |
652 | } |
653 | return error; |
654 | } |
655 | |
656 | bool |
657 | GDBRemoteCommunication::JoinListenThread () |
658 | { |
659 | if (m_listen_thread.IsJoinable()) |
660 | m_listen_thread.Join(nullptr); |
661 | return true; |
662 | } |
663 | |
664 | lldb::thread_result_t |
665 | GDBRemoteCommunication::ListenThread (lldb::thread_arg_t arg) |
666 | { |
667 | GDBRemoteCommunication *comm = (GDBRemoteCommunication *)arg; |
668 | Error error; |
669 | ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)comm->GetConnection (); |
670 | |
671 | if (connection) |
672 | { |
673 | // Do the listen on another thread so we can continue on... |
674 | if (connection->Connect(comm->m_listen_url.c_str(), &error) != eConnectionStatusSuccess) |
675 | comm->SetConnection(NULL__null); |
676 | } |
677 | return NULL__null; |
678 | } |
679 | |
680 | Error |
681 | GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, |
682 | uint16_t in_port, |
683 | lldb_private::ProcessLaunchInfo &launch_info, |
684 | uint16_t &out_port) |
685 | { |
686 | Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS(1u << 1))); |
687 | if (log) |
688 | log->Printf ("GDBRemoteCommunication::%s(hostname=%s, in_port=%" PRIu16"u" ", out_port=%" PRIu16"u", __FUNCTION__, hostname ? hostname : "<empty>", in_port, out_port); |
689 | |
690 | out_port = in_port; |
691 | Error error; |
692 | // If we locate debugserver, keep that located version around |
693 | static FileSpec g_debugserver_file_spec; |
694 | |
695 | char debugserver_path[PATH_MAX4096]; |
696 | FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); |
697 | |
698 | // Always check to see if we have an environment override for the path |
699 | // to the debugserver to use and use it if we do. |
700 | const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); |
701 | if (env_debugserver_path) |
702 | { |
703 | debugserver_file_spec.SetFile (env_debugserver_path, false); |
704 | if (log) |
705 | log->Printf ("GDBRemoteCommunication::%s() gdb-remote stub exe path set from environment variable: %s", __FUNCTION__, env_debugserver_path); |
706 | } |
707 | else |
708 | debugserver_file_spec = g_debugserver_file_spec; |
709 | bool debugserver_exists = debugserver_file_spec.Exists(); |
710 | if (!debugserver_exists) |
711 | { |
712 | // The debugserver binary is in the LLDB.framework/Resources |
713 | // directory. |
714 | if (HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, debugserver_file_spec)) |
715 | { |
716 | debugserver_file_spec.AppendPathComponent (DEBUGSERVER_BASENAME"lldb-gdbserver"); |
717 | debugserver_exists = debugserver_file_spec.Exists(); |
718 | if (debugserver_exists) |
719 | { |
720 | if (log) |
721 | log->Printf ("GDBRemoteCommunication::%s() found gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ()); |
722 | |
723 | g_debugserver_file_spec = debugserver_file_spec; |
724 | } |
725 | else |
726 | { |
727 | if (log) |
728 | log->Printf ("GDBRemoteCommunication::%s() could not find gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ()); |
729 | |
730 | g_debugserver_file_spec.Clear(); |
731 | debugserver_file_spec.Clear(); |
732 | } |
733 | } |
734 | } |
735 | |
736 | if (debugserver_exists) |
737 | { |
738 | debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path)); |
739 | |
740 | Args &debugserver_args = launch_info.GetArguments(); |
741 | debugserver_args.Clear(); |
742 | char arg_cstr[PATH_MAX4096]; |
743 | |
744 | // Start args with "debugserver /file/path -r --" |
745 | debugserver_args.AppendArgument(debugserver_path); |
746 | |
747 | // If a host and port is supplied then use it |
748 | char host_and_port[128]; |
749 | if (hostname) |
750 | { |
751 | snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port); |
752 | debugserver_args.AppendArgument(host_and_port); |
753 | } |
754 | else |
755 | { |
756 | host_and_port[0] = '\0'; |
757 | } |
758 | |
759 | // use native registers, not the GDB registers |
760 | debugserver_args.AppendArgument("--native-regs"); |
761 | // make debugserver run in its own session so signals generated by |
762 | // special terminal key sequences (^C) don't affect debugserver |
763 | debugserver_args.AppendArgument("--setsid"); |
764 | |
765 | char named_pipe_path[PATH_MAX4096]; |
766 | named_pipe_path[0] = '\0'; |
767 | Pipe port_named_pipe; |
768 | |
769 | bool listen = false; |
770 | if (host_and_port[0]) |
771 | { |
772 | // Create a temporary file to get the stdout/stderr and redirect the |
773 | // output of the command into this file. We will later read this file |
774 | // if all goes well and fill the data into "command_output_ptr" |
775 | |
776 | if (in_port == 0) |
777 | { |
778 | // Binding to port zero, we need to figure out what port it ends up |
779 | // using using a named pipe... |
780 | FileSpec tmpdir_file_spec; |
781 | if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) |
782 | { |
783 | tmpdir_file_spec.AppendPathComponent("debugserver-named-pipe.XXXXXX"); |
784 | strncpy(named_pipe_path, tmpdir_file_spec.GetPath().c_str(), sizeof(named_pipe_path)); |
785 | } |
786 | else |
787 | { |
788 | strncpy(named_pipe_path, "/tmp/debugserver-named-pipe.XXXXXX", sizeof(named_pipe_path)); |
789 | } |
790 | |
791 | if (::mktemp (named_pipe_path)) |
Call to function 'mktemp' is insecure as it always creates or uses insecure temporary file. Use 'mkstemp' instead | |
792 | { |
793 | error = port_named_pipe.CreateNew(named_pipe_path, false); |
794 | if (error.Fail()) |
795 | return error; |
796 | debugserver_args.AppendArgument("--named-pipe"); |
797 | debugserver_args.AppendArgument(named_pipe_path); |
798 | } |
799 | } |
800 | else |
801 | { |
802 | listen = true; |
803 | } |
804 | } |
805 | else |
806 | { |
807 | // No host and port given, so lets listen on our end and make the debugserver |
808 | // connect to us.. |
809 | error = StartListenThread ("127.0.0.1", 0); |
810 | if (error.Fail()) |
811 | return error; |
812 | |
813 | ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection (); |
814 | // Wait for 10 seconds to resolve the bound port |
815 | out_port = connection->GetListeningPort(10); |
816 | if (out_port > 0) |
817 | { |
818 | char port_cstr[32]; |
819 | snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", out_port); |
820 | // Send the host and port down that debugserver and specify an option |
821 | // so that it connects back to the port we are listening to in this process |
822 | debugserver_args.AppendArgument("--reverse-connect"); |
823 | debugserver_args.AppendArgument(port_cstr); |
824 | } |
825 | else |
826 | { |
827 | error.SetErrorString ("failed to bind to port 0 on 127.0.0.1"); |
828 | return error; |
829 | } |
830 | } |
831 | |
832 | const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); |
833 | if (env_debugserver_log_file) |
834 | { |
835 | ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file); |
836 | debugserver_args.AppendArgument(arg_cstr); |
837 | } |
838 | |
839 | const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); |
840 | if (env_debugserver_log_flags) |
841 | { |
842 | ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); |
843 | debugserver_args.AppendArgument(arg_cstr); |
844 | } |
845 | |
846 | // Add additional args, starting with LLDB_DEBUGSERVER_EXTRA_ARG_1 until an env var doesn't come back. |
847 | uint32_t env_var_index = 1; |
848 | bool has_env_var; |
849 | do |
850 | { |
851 | char env_var_name[64]; |
852 | snprintf (env_var_name, sizeof (env_var_name), "LLDB_DEBUGSERVER_EXTRA_ARG_%" PRIu32"u", env_var_index++); |
853 | const char *extra_arg = getenv(env_var_name); |
854 | has_env_var = extra_arg != nullptr; |
855 | |
856 | if (has_env_var) |
857 | { |
858 | debugserver_args.AppendArgument (extra_arg); |
859 | if (log) |
860 | log->Printf ("GDBRemoteCommunication::%s adding env var %s contents to stub command line (%s)", __FUNCTION__, env_var_name, extra_arg); |
861 | } |
862 | } while (has_env_var); |
863 | |
864 | // Close STDIN, STDOUT and STDERR. |
865 | launch_info.AppendCloseFileAction (STDIN_FILENO0); |
866 | launch_info.AppendCloseFileAction (STDOUT_FILENO1); |
867 | launch_info.AppendCloseFileAction (STDERR_FILENO2); |
868 | |
869 | // Redirect STDIN, STDOUT and STDERR to "/dev/null". |
870 | launch_info.AppendSuppressFileAction (STDIN_FILENO0, true, false); |
871 | launch_info.AppendSuppressFileAction (STDOUT_FILENO1, false, true); |
872 | launch_info.AppendSuppressFileAction (STDERR_FILENO2, false, true); |
873 | |
874 | error = Host::LaunchProcess(launch_info); |
875 | |
876 | if (error.Success() && launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID0) |
877 | { |
878 | if (named_pipe_path[0]) |
879 | { |
880 | error = port_named_pipe.OpenAsReader(named_pipe_path, false); |
881 | if (error.Success()) |
882 | { |
883 | char port_cstr[256]; |
884 | port_cstr[0] = '\0'; |
885 | size_t num_bytes = sizeof(port_cstr); |
886 | // Read port from pipe with 10 second timeout. |
887 | error = port_named_pipe.ReadWithTimeout(port_cstr, num_bytes, std::chrono::microseconds(10 * 1000000), num_bytes); |
888 | if (error.Success()) |
889 | { |
890 | assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0')((num_bytes > 0 && port_cstr[num_bytes-1] == '\0') ? static_cast<void> (0) : __assert_fail ("num_bytes > 0 && port_cstr[num_bytes-1] == '\\0'" , "/tmp/buildd/llvm-toolchain-snapshot-3.7~svn227243/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp" , 890, __PRETTY_FUNCTION__)); |
891 | out_port = StringConvert::ToUInt32(port_cstr, 0); |
892 | if (log) |
893 | log->Printf("GDBRemoteCommunication::%s() debugserver listens %u port", __FUNCTION__, out_port); |
894 | } |
895 | else |
896 | { |
897 | if (log) |
898 | log->Printf("GDBRemoteCommunication::%s() failed to read a port value from named pipe %s: %s", __FUNCTION__, named_pipe_path, error.AsCString()); |
899 | |
900 | } |
901 | port_named_pipe.Close(); |
902 | } |
903 | else |
904 | { |
905 | if (log) |
906 | log->Printf("GDBRemoteCommunication::%s() failed to open named pipe %s for reading: %s", __FUNCTION__, named_pipe_path, error.AsCString()); |
907 | } |
908 | const auto err = port_named_pipe.Delete(named_pipe_path); |
909 | if (err.Fail()) |
910 | { |
911 | if (log) |
912 | log->Printf ("GDBRemoteCommunication::%s failed to delete pipe %s: %s", __FUNCTION__, named_pipe_path, err.AsCString()); |
913 | } |
914 | } |
915 | else if (listen) |
916 | { |
917 | |
918 | } |
919 | else |
920 | { |
921 | // Make sure we actually connect with the debugserver... |
922 | JoinListenThread(); |
923 | } |
924 | } |
925 | } |
926 | else |
927 | { |
928 | error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME"lldb-gdbserver" ); |
929 | } |
930 | return error; |
931 | } |
932 | |
933 | void |
934 | GDBRemoteCommunication::DumpHistory(Stream &strm) |
935 | { |
936 | m_history.Dump (strm); |
937 | } |