GDBRemoteCommunication.cpp revision a9eb8277e616463fcf611abb3a77a5f0831bc1b2
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 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 26// Project includes 27#include "ProcessGDBRemoteLog.h" 28 29#define DEBUGSERVER_BASENAME "debugserver" 30 31using namespace lldb; 32using namespace lldb_private; 33 34//---------------------------------------------------------------------- 35// GDBRemoteCommunication constructor 36//---------------------------------------------------------------------- 37GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, 38 const char *listener_name, 39 bool is_platform) : 40 Communication(comm_name), 41 m_packet_timeout (1), 42 m_sequence_mutex (Mutex::eMutexTypeRecursive), 43 m_public_is_running (false), 44 m_private_is_running (false), 45 m_send_acks (true), 46 m_is_platform (is_platform) 47{ 48} 49 50//---------------------------------------------------------------------- 51// Destructor 52//---------------------------------------------------------------------- 53GDBRemoteCommunication::~GDBRemoteCommunication() 54{ 55 if (IsConnected()) 56 { 57 Disconnect(); 58 } 59} 60 61char 62GDBRemoteCommunication::CalculcateChecksum (const char *payload, size_t payload_length) 63{ 64 int checksum = 0; 65 66 // We only need to compute the checksum if we are sending acks 67 if (GetSendAcks ()) 68 { 69 for (size_t i = 0; i < payload_length; ++i) 70 checksum += payload[i]; 71 } 72 return checksum & 255; 73} 74 75size_t 76GDBRemoteCommunication::SendAck () 77{ 78 LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); 79 if (log) 80 log->Printf ("send packet: +"); 81 ConnectionStatus status = eConnectionStatusSuccess; 82 char ack_char = '+'; 83 return Write (&ack_char, 1, status, NULL); 84} 85 86size_t 87GDBRemoteCommunication::SendNack () 88{ 89 LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); 90 if (log) 91 log->Printf ("send packet: -"); 92 ConnectionStatus status = eConnectionStatusSuccess; 93 char nack_char = '-'; 94 return Write (&nack_char, 1, status, NULL); 95} 96 97size_t 98GDBRemoteCommunication::SendPacket (lldb_private::StreamString &payload) 99{ 100 Mutex::Locker locker(m_sequence_mutex); 101 const std::string &p (payload.GetString()); 102 return SendPacketNoLock (p.c_str(), p.size()); 103} 104 105size_t 106GDBRemoteCommunication::SendPacket (const char *payload) 107{ 108 Mutex::Locker locker(m_sequence_mutex); 109 return SendPacketNoLock (payload, ::strlen (payload)); 110} 111 112size_t 113GDBRemoteCommunication::SendPacket (const char *payload, size_t payload_length) 114{ 115 Mutex::Locker locker(m_sequence_mutex); 116 return SendPacketNoLock (payload, payload_length); 117} 118 119size_t 120GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_length) 121{ 122 if (IsConnected()) 123 { 124 StreamString packet(0, 4, eByteOrderBig); 125 126 packet.PutChar('$'); 127 packet.Write (payload, payload_length); 128 packet.PutChar('#'); 129 packet.PutHex8(CalculcateChecksum (payload, payload_length)); 130 131 LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); 132 if (log) 133 log->Printf ("send packet: %.*s", (int)packet.GetSize(), packet.GetData()); 134 ConnectionStatus status = eConnectionStatusSuccess; 135 size_t bytes_written = Write (packet.GetData(), packet.GetSize(), status, NULL); 136 if (bytes_written == packet.GetSize()) 137 { 138 if (GetSendAcks ()) 139 { 140 if (GetAck () != '+') 141 { 142 printf("get ack failed..."); 143 return 0; 144 } 145 } 146 } 147 else 148 { 149 LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); 150 if (log) 151 log->Printf ("error: failed to send packet: %.*s", (int)packet.GetSize(), packet.GetData()); 152 } 153 return bytes_written; 154 } 155 return 0; 156} 157 158char 159GDBRemoteCommunication::GetAck () 160{ 161 StringExtractorGDBRemote packet; 162 if (WaitForPacketWithTimeoutMicroSeconds (packet, GetPacketTimeoutInMicroSeconds ()) == 1) 163 return packet.GetChar(); 164 return 0; 165} 166 167bool 168GDBRemoteCommunication::GetSequenceMutex (Mutex::Locker& locker) 169{ 170 return locker.TryLock (m_sequence_mutex.GetMutex()); 171} 172 173 174bool 175GDBRemoteCommunication::WaitForNotRunningPrivate (const TimeValue *timeout_ptr) 176{ 177 return m_private_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL); 178} 179 180size_t 181GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSeconds (StringExtractorGDBRemote &packet, uint32_t timeout_usec) 182{ 183 Mutex::Locker locker(m_sequence_mutex); 184 return WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec); 185} 186 187size_t 188GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &packet, uint32_t timeout_usec) 189{ 190 uint8_t buffer[8192]; 191 Error error; 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 while (IsConnected()) 198 { 199 lldb::ConnectionStatus status; 200 size_t bytes_read = Read (buffer, sizeof(buffer), timeout_usec, status, &error); 201 if (bytes_read > 0) 202 { 203 if (CheckForPacket (buffer, bytes_read, packet)) 204 return packet.GetStringRef().size(); 205 } 206 else 207 { 208 switch (status) 209 { 210 case eConnectionStatusSuccess: 211 case eConnectionStatusTimedOut: 212 break; 213 214 case eConnectionStatusEndOfFile: 215 case eConnectionStatusNoConnection: 216 case eConnectionStatusLostConnection: 217 case eConnectionStatusError: 218 Disconnect(); 219 break; 220 } 221 222 // Get out of the while loop we we finally timeout without getting any data 223 break; 224 } 225 } 226 packet.Clear (); 227 return 0; 228} 229 230bool 231GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, StringExtractorGDBRemote &packet) 232{ 233 // Put the packet data into the buffer in a thread safe fashion 234 Mutex::Locker locker(m_bytes_mutex); 235 236 LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); 237 238 if (src && src_len > 0) 239 { 240 if (log) 241 { 242 StreamString s; 243 log->Printf ("GDBRemoteCommunication::%s adding %zu bytes: %s\n",__FUNCTION__, src_len, src); 244 } 245 m_bytes.append ((const char *)src, src_len); 246 } 247 248 // Parse up the packets into gdb remote packets 249 if (!m_bytes.empty()) 250 { 251 // end_idx must be one past the last valid packet byte. Start 252 // it off with an invalid value that is the same as the current 253 // index. 254 size_t content_start = 0; 255 size_t content_length = 0; 256 size_t total_length = 0; 257 size_t checksum_idx = std::string::npos; 258 259 switch (m_bytes[0]) 260 { 261 case '+': // Look for ack 262 case '-': // Look for cancel 263 case '\x03': // ^C to halt target 264 content_length = total_length = 1; // The command is one byte long... 265 break; 266 267 case '$': 268 // Look for a standard gdb packet? 269 { 270 size_t hash_pos = m_bytes.find('#'); 271 if (hash_pos != std::string::npos) 272 { 273 if (hash_pos + 2 < m_bytes.size()) 274 { 275 checksum_idx = hash_pos + 1; 276 // Skip the dollar sign 277 content_start = 1; 278 // Don't include the # in the content or the $ in the content length 279 content_length = hash_pos - 1; 280 281 total_length = hash_pos + 3; // Skip the # and the two hex checksum bytes 282 } 283 else 284 { 285 // Checksum bytes aren't all here yet 286 content_length = std::string::npos; 287 } 288 } 289 } 290 break; 291 292 default: 293 { 294 // We have an unexpected byte and we need to flush all bad 295 // data that is in m_bytes, so we need to find the first 296 // byte that is a '+' (ACK), '-' (NACK), \x03 (CTRL+C interrupt), 297 // or '$' character (start of packet header) or of course, 298 // the end of the data in m_bytes... 299 const size_t bytes_len = m_bytes.size(); 300 bool done = false; 301 uint32_t idx; 302 for (idx = 1; !done && idx < bytes_len; ++idx) 303 { 304 switch (m_bytes[idx]) 305 { 306 case '+': 307 case '-': 308 case '\x03': 309 case '$': 310 done = true; 311 break; 312 313 default: 314 break; 315 } 316 } 317 if (log) 318 log->Printf ("GDBRemoteCommunication::%s tossing %u junk bytes: '%.*s'", 319 __FUNCTION__, idx, idx, m_bytes.c_str()); 320 m_bytes.erase(0, idx); 321 } 322 break; 323 } 324 325 if (content_length == std::string::npos) 326 { 327 packet.Clear(); 328 return false; 329 } 330 else if (total_length > 0) 331 { 332 333 // We have a valid packet... 334 assert (content_length <= m_bytes.size()); 335 assert (total_length <= m_bytes.size()); 336 assert (content_length <= total_length); 337 338 bool success = true; 339 std::string &packet_str = packet.GetStringRef(); 340 packet_str.assign (m_bytes, content_start, content_length); 341 if (m_bytes[0] == '$') 342 { 343 assert (checksum_idx < m_bytes.size()); 344 if (::isxdigit (m_bytes[checksum_idx+0]) || 345 ::isxdigit (m_bytes[checksum_idx+1])) 346 { 347 if (GetSendAcks ()) 348 { 349 const char *packet_checksum_cstr = &m_bytes[checksum_idx]; 350 char packet_checksum = strtol (packet_checksum_cstr, NULL, 16); 351 char actual_checksum = CalculcateChecksum (packet_str.c_str(), packet_str.size()); 352 success = packet_checksum == actual_checksum; 353 if (!success) 354 { 355 if (log) 356 log->Printf ("error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x", 357 (int)(total_length), 358 m_bytes.c_str(), 359 (uint8_t)packet_checksum, 360 (uint8_t)actual_checksum); 361 } 362 // Send the ack or nack if needed 363 if (!success) 364 SendNack(); 365 else 366 SendAck(); 367 } 368 if (success) 369 { 370 if (log) 371 log->Printf ("read packet: %.*s", (int)(total_length), m_bytes.c_str()); 372 } 373 } 374 else 375 { 376 success = false; 377 if (log) 378 log->Printf ("error: invalid checksum in packet: '%s'\n", (int)(total_length), m_bytes.c_str()); 379 } 380 } 381 m_bytes.erase(0, total_length); 382 packet.SetFilePos(0); 383 return success; 384 } 385 } 386 packet.Clear(); 387 return false; 388} 389 390Error 391GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url, 392 const char *unix_socket_name, // For handshaking 393 lldb_private::ProcessLaunchInfo &launch_info) 394{ 395 Error error; 396 // If we locate debugserver, keep that located version around 397 static FileSpec g_debugserver_file_spec; 398 399 // This function will fill in the launch information for the debugserver 400 // instance that gets launched. 401 launch_info.Clear(); 402 403 char debugserver_path[PATH_MAX]; 404 FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); 405 406 // Always check to see if we have an environment override for the path 407 // to the debugserver to use and use it if we do. 408 const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); 409 if (env_debugserver_path) 410 debugserver_file_spec.SetFile (env_debugserver_path, false); 411 else 412 debugserver_file_spec = g_debugserver_file_spec; 413 bool debugserver_exists = debugserver_file_spec.Exists(); 414 if (!debugserver_exists) 415 { 416 // The debugserver binary is in the LLDB.framework/Resources 417 // directory. 418 if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec)) 419 { 420 debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME); 421 debugserver_exists = debugserver_file_spec.Exists(); 422 if (debugserver_exists) 423 { 424 g_debugserver_file_spec = debugserver_file_spec; 425 } 426 else 427 { 428 g_debugserver_file_spec.Clear(); 429 debugserver_file_spec.Clear(); 430 } 431 } 432 } 433 434 if (debugserver_exists) 435 { 436 debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path)); 437 438 Args &debugserver_args = launch_info.GetArguments(); 439 debugserver_args.Clear(); 440 char arg_cstr[PATH_MAX]; 441 442 // Start args with "debugserver /file/path -r --" 443 debugserver_args.AppendArgument(debugserver_path); 444 debugserver_args.AppendArgument(debugserver_url); 445 // use native registers, not the GDB registers 446 debugserver_args.AppendArgument("--native-regs"); 447 // make debugserver run in its own session so signals generated by 448 // special terminal key sequences (^C) don't affect debugserver 449 debugserver_args.AppendArgument("--setsid"); 450 451 if (unix_socket_name && unix_socket_name[0]) 452 { 453 debugserver_args.AppendArgument("--unix-socket"); 454 debugserver_args.AppendArgument(unix_socket_name); 455 } 456 457 const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); 458 if (env_debugserver_log_file) 459 { 460 ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file); 461 debugserver_args.AppendArgument(arg_cstr); 462 } 463 464 const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); 465 if (env_debugserver_log_flags) 466 { 467 ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); 468 debugserver_args.AppendArgument(arg_cstr); 469 } 470 // debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt"); 471 // debugserver_args.AppendArgument("--log-flags=0x802e0e"); 472 473 // We currently send down all arguments, attach pids, or attach 474 // process names in dedicated GDB server packets, so we don't need 475 // to pass them as arguments. This is currently because of all the 476 // things we need to setup prior to launching: the environment, 477 // current working dir, file actions, etc. 478#if 0 479 // Now append the program arguments 480 if (inferior_argv) 481 { 482 // Terminate the debugserver args so we can now append the inferior args 483 debugserver_args.AppendArgument("--"); 484 485 for (int i = 0; inferior_argv[i] != NULL; ++i) 486 debugserver_args.AppendArgument (inferior_argv[i]); 487 } 488 else if (attach_pid != LLDB_INVALID_PROCESS_ID) 489 { 490 ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid); 491 debugserver_args.AppendArgument (arg_cstr); 492 } 493 else if (attach_name && attach_name[0]) 494 { 495 if (wait_for_launch) 496 debugserver_args.AppendArgument ("--waitfor"); 497 else 498 debugserver_args.AppendArgument ("--attach"); 499 debugserver_args.AppendArgument (attach_name); 500 } 501#endif 502 503 // Close STDIN, STDOUT and STDERR. We might need to redirect them 504 // to "/dev/null" if we run into any problems. 505// launch_info.AppendCloseFileAction (STDIN_FILENO); 506// launch_info.AppendCloseFileAction (STDOUT_FILENO); 507// launch_info.AppendCloseFileAction (STDERR_FILENO); 508 509 error = Host::LaunchProcess(launch_info); 510 } 511 else 512 { 513 error.SetErrorStringWithFormat ("Unable to locate " DEBUGSERVER_BASENAME ".\n"); 514 } 515 return error; 516} 517 518