GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qSpeedTest( StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("qSpeedTest:")); llvm::StringRef key; llvm::StringRef value; bool success = packet.GetNameColonValue(key, value); if (success && key.equals("response_size")) { uint32_t response_size = 0; if (!value.getAsInteger(0, response_size)) { if (response_size == 0) return SendOKResponse(); StreamString response; uint32_t bytes_left = response_size; response.PutCString("data:"); while (bytes_left > 0) { if (bytes_left >= 26) { response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); bytes_left -= 26; } else { response.Printf("%*.*s;", bytes_left, bytes_left, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); bytes_left = 0; } } return SendPacketNoLock(response.GetString()); } } return SendErrorResponse(7); }
GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet) { #ifdef _WIN32 return SendErrorResponse(9); #else // Spawn a local debugserver as a platform so we can then attach or launch // a process... Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (log) log->Printf ("GDBRemoteCommunicationServerPlatform::%s() called", __FUNCTION__); ConnectionFileDescriptor file_conn; std::string hostname; packet.SetFilePos(::strlen ("qLaunchGDBServer;")); std::string name; std::string value; uint16_t port = UINT16_MAX; while (packet.GetNameColonValue(name, value)) { if (name.compare ("host") == 0) hostname.swap(value); else if (name.compare ("port") == 0) port = StringConvert::ToUInt32(value.c_str(), 0, 0); } lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; std::string socket_name; Error error = LaunchGDBServer(Args(), hostname, debugserver_pid, port, socket_name); if (error.Fail()) { if (log) log->Printf("GDBRemoteCommunicationServerPlatform::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ()); return SendErrorResponse(9); } if (log) log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid); StreamGDBRemote response; response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); if (!socket_name.empty()) { response.PutCString("socket_name:"); response.PutCStringAsRawHex8(socket_name.c_str()); response.PutChar(';'); } PacketResult packet_result = SendPacketNoLock(response.GetData(), response.GetSize()); if (packet_result != PacketResult::Success) { if (debugserver_pid != LLDB_INVALID_PROCESS_ID) ::kill (debugserver_pid, SIGINT); } return packet_result; #endif }
GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("qSpeedTest:")); std::string key; std::string value; bool success = packet.GetNameColonValue(key, value); if (success && key.compare("response_size") == 0) { uint32_t response_size = Args::StringToUInt32(value.c_str(), 0, 0, &success); if (success) { if (response_size == 0) return SendOKResponse(); StreamString response; uint32_t bytes_left = response_size; response.PutCString("data:"); while (bytes_left > 0) { if (bytes_left >= 26) { response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); bytes_left -= 26; } else { response.Printf ("%*.*s;", bytes_left, bytes_left, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); bytes_left = 0; } } return SendPacketNoLock (response.GetData(), response.GetSize()); } } return SendErrorResponse (7); }
GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet) { #ifdef _WIN32 // No unix sockets on windows return false; #else // Spawn a local debugserver as a platform so we can then attach or launch // a process... if (m_is_platform) { // Sleep and wait a bit for debugserver to start to listen... ConnectionFileDescriptor file_conn; Error error; std::string hostname; // TODO: /tmp/ should not be hardcoded. User might want to override /tmp // with the TMPDIR environnement variable packet.SetFilePos(::strlen ("qLaunchGDBServer;")); std::string name; std::string value; uint16_t port = UINT16_MAX; while (packet.GetNameColonValue(name, value)) { if (name.compare ("host") == 0) hostname.swap(value); else if (name.compare ("port") == 0) port = Args::StringToUInt32(value.c_str(), 0, 0); } if (port == UINT16_MAX) port = GetNextAvailablePort(); // Spawn a new thread to accept the port that gets bound after // binding to port 0 (zero). if (error.Success()) { // Spawn a debugserver and try to get the port it listens to. ProcessLaunchInfo debugserver_launch_info; StreamString host_and_port; if (hostname.empty()) hostname = "localhost"; host_and_port.Printf("%s:%u", hostname.c_str(), port); const char *host_and_port_cstr = host_and_port.GetString().c_str(); Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (log) log->Printf("Launching debugserver with: %s...\n", host_and_port_cstr); debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false); error = StartDebugserverProcess (host_and_port_cstr, debugserver_launch_info, port); lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); if (debugserver_pid != LLDB_INVALID_PROCESS_ID) { Mutex::Locker locker (m_spawned_pids_mutex); m_spawned_pids.insert(debugserver_pid); if (port > 0) AssociatePortWithProcess(port, debugserver_pid); } else { if (port > 0) FreePort (port); } if (error.Success()) { char response[256]; const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); assert (response_len < sizeof(response)); PacketResult packet_result = SendPacketNoLock (response, response_len); if (packet_result != PacketResult::Success) { if (debugserver_pid != LLDB_INVALID_PROCESS_ID) ::kill (debugserver_pid, SIGINT); } return packet_result; } } } return SendErrorResponse (9); #endif }
GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &packet) { m_proc_infos_index = 0; m_proc_infos.Clear(); ProcessInstanceInfoMatch match_info; packet.SetFilePos(::strlen ("qfProcessInfo")); if (packet.GetChar() == ':') { std::string key; std::string value; while (packet.GetNameColonValue(key, value)) { bool success = true; if (key.compare("name") == 0) { StringExtractor extractor; extractor.GetStringRef().swap(value); extractor.GetHexByteString (value); match_info.GetProcessInfo().GetExecutableFile().SetFile(value.c_str(), false); } else if (key.compare("name_match") == 0) { if (value.compare("equals") == 0) { match_info.SetNameMatchType (eNameMatchEquals); } else if (value.compare("starts_with") == 0) { match_info.SetNameMatchType (eNameMatchStartsWith); } else if (value.compare("ends_with") == 0) { match_info.SetNameMatchType (eNameMatchEndsWith); } else if (value.compare("contains") == 0) { match_info.SetNameMatchType (eNameMatchContains); } else if (value.compare("regex") == 0) { match_info.SetNameMatchType (eNameMatchRegularExpression); } else { success = false; } } else if (key.compare("pid") == 0) { match_info.GetProcessInfo().SetProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success)); } else if (key.compare("parent_pid") == 0) { match_info.GetProcessInfo().SetParentProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success)); } else if (key.compare("uid") == 0) { match_info.GetProcessInfo().SetUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success)); } else if (key.compare("gid") == 0) { match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success)); } else if (key.compare("euid") == 0) { match_info.GetProcessInfo().SetEffectiveUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success)); } else if (key.compare("egid") == 0) { match_info.GetProcessInfo().SetEffectiveGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success)); } else if (key.compare("all_users") == 0) { match_info.SetMatchAllUsers(Args::StringToBoolean(value.c_str(), false, &success)); } else if (key.compare("triple") == 0) { match_info.GetProcessInfo().GetArchitecture().SetTriple (value.c_str(), NULL); } else { success = false; } if (!success) return SendErrorResponse (2); } } if (Host::FindProcesses (match_info, m_proc_infos)) { // We found something, return the first item by calling the get // subsequent process info packet handler... return Handle_qsProcessInfo (packet); } return SendErrorResponse (3); }
bool GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet) { #ifdef _WIN32 // No unix sockets on windows return false; #else // Spawn a local debugserver as a platform so we can then attach or launch // a process... if (m_is_platform) { // Sleep and wait a bit for debugserver to start to listen... ConnectionFileDescriptor file_conn; char connect_url[PATH_MAX]; Error error; std::string hostname; // TODO: /tmp/ should not be hardcoded. User might want to override /tmp // with the TMPDIR environnement variable packet.SetFilePos(::strlen ("qLaunchGDBServer;")); std::string name; std::string value; uint16_t port = UINT16_MAX; while (packet.GetNameColonValue(name, value)) { if (name.compare ("host") == 0) hostname.swap(value); else if (name.compare ("port") == 0) port = Args::StringToUInt32(value.c_str(), 0, 0); } if (port == UINT16_MAX) port = GetNextAvailablePort(); // Spawn a new thread to accept the port that gets bound after // binding to port 0 (zero). lldb::thread_t accept_thread = LLDB_INVALID_HOST_THREAD; const char *unix_socket_name = NULL; char unix_socket_name_buf[PATH_MAX] = "/tmp/XXXXXXXXX"; if (port == 0) { if (::mkstemp (unix_socket_name_buf) == 0) { unix_socket_name = unix_socket_name_buf; ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name); accept_thread = Host::ThreadCreate (unix_socket_name, AcceptPortFromInferior, connect_url, &error); } else { error.SetErrorStringWithFormat("failed to make temporary path for a unix socket: %s", strerror(errno)); } } if (error.Success()) { // Spawn a debugserver and try to get the port it listens to. ProcessLaunchInfo debugserver_launch_info; StreamString host_and_port; if (hostname.empty()) hostname = "localhost"; host_and_port.Printf("%s:%u", hostname.c_str(), port); const char *host_and_port_cstr = host_and_port.GetString().c_str(); Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (log) log->Printf("Launching debugserver with: %s...\n", host_and_port_cstr); debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false); error = StartDebugserverProcess (host_and_port_cstr, unix_socket_name, debugserver_launch_info); lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); if (debugserver_pid != LLDB_INVALID_PROCESS_ID) { Mutex::Locker locker (m_spawned_pids_mutex); m_spawned_pids.insert(debugserver_pid); if (port > 0) AssociatePortWithProcess(port, debugserver_pid); } else { if (port > 0) FreePort (port); } if (error.Success()) { bool success = false; if (IS_VALID_LLDB_HOST_THREAD(accept_thread)) { thread_result_t accept_thread_result = NULL; if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error)) { if (accept_thread_result) { port = (intptr_t)accept_thread_result; char response[256]; const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); assert (response_len < sizeof(response)); //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); success = SendPacketNoLock (response, response_len) > 0; } } } else { char response[256]; const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); assert (response_len < sizeof(response)); //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); success = SendPacketNoLock (response, response_len) > 0; } Host::Unlink (unix_socket_name); if (!success) { if (debugserver_pid != LLDB_INVALID_PROCESS_ID) ::kill (debugserver_pid, SIGINT); } return success; } else if (accept_thread) { Host::Unlink (unix_socket_name); } } } return SendErrorResponse (9); #endif }
GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo( StringExtractorGDBRemote &packet) { m_proc_infos_index = 0; m_proc_infos.Clear(); ProcessInstanceInfoMatch match_info; packet.SetFilePos(::strlen("qfProcessInfo")); if (packet.GetChar() == ':') { llvm::StringRef key; llvm::StringRef value; while (packet.GetNameColonValue(key, value)) { bool success = true; if (key.equals("name")) { StringExtractor extractor(value); std::string file; extractor.GetHexByteString(file); match_info.GetProcessInfo().GetExecutableFile().SetFile(file.c_str(), false); } else if (key.equals("name_match")) { NameMatchType name_match = llvm::StringSwitch<NameMatchType>(value) .Case("equals", eNameMatchEquals) .Case("starts_with", eNameMatchStartsWith) .Case("ends_with", eNameMatchEndsWith) .Case("contains", eNameMatchContains) .Case("regex", eNameMatchRegularExpression) .Default(eNameMatchIgnore); match_info.SetNameMatchType(name_match); if (name_match == eNameMatchIgnore) return SendErrorResponse(2); } else if (key.equals("pid")) { lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; if (value.getAsInteger(0, pid)) return SendErrorResponse(2); match_info.GetProcessInfo().SetProcessID(pid); } else if (key.equals("parent_pid")) { lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; if (value.getAsInteger(0, pid)) return SendErrorResponse(2); match_info.GetProcessInfo().SetParentProcessID(pid); } else if (key.equals("uid")) { uint32_t uid = UINT32_MAX; if (value.getAsInteger(0, uid)) return SendErrorResponse(2); match_info.GetProcessInfo().SetUserID(uid); } else if (key.equals("gid")) { uint32_t gid = UINT32_MAX; if (value.getAsInteger(0, gid)) return SendErrorResponse(2); match_info.GetProcessInfo().SetGroupID(gid); } else if (key.equals("euid")) { uint32_t uid = UINT32_MAX; if (value.getAsInteger(0, uid)) return SendErrorResponse(2); match_info.GetProcessInfo().SetEffectiveUserID(uid); } else if (key.equals("egid")) { uint32_t gid = UINT32_MAX; if (value.getAsInteger(0, gid)) return SendErrorResponse(2); match_info.GetProcessInfo().SetEffectiveGroupID(gid); } else if (key.equals("all_users")) { match_info.SetMatchAllUsers( Args::StringToBoolean(value, false, &success)); } else if (key.equals("triple")) { match_info.GetProcessInfo().GetArchitecture().SetTriple( value.str().c_str(), NULL); } else { success = false; } if (!success) return SendErrorResponse(2); } } if (Host::FindProcesses(match_info, m_proc_infos)) { // We found something, return the first item by calling the get // subsequent process info packet handler... return Handle_qsProcessInfo(packet); } return SendErrorResponse(3); }
GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet) { #ifdef _WIN32 return SendErrorResponse(9); #else // Spawn a local debugserver as a platform so we can then attach or launch // a process... Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (log) log->Printf ("GDBRemoteCommunicationServerPlatform::%s() called", __FUNCTION__); // Sleep and wait a bit for debugserver to start to listen... ConnectionFileDescriptor file_conn; std::string hostname; // TODO: /tmp/ should not be hardcoded. User might want to override /tmp // with the TMPDIR environment variable packet.SetFilePos(::strlen ("qLaunchGDBServer;")); std::string name; std::string value; uint16_t port = UINT16_MAX; while (packet.GetNameColonValue(name, value)) { if (name.compare ("host") == 0) hostname.swap(value); else if (name.compare ("port") == 0) port = StringConvert::ToUInt32(value.c_str(), 0, 0); } if (port == UINT16_MAX) port = GetNextAvailablePort(); // Spawn a new thread to accept the port that gets bound after // binding to port 0 (zero). // ignore the hostname send from the remote end, just use the ip address // that we're currently communicating with as the hostname // Spawn a debugserver and try to get the port it listens to. ProcessLaunchInfo debugserver_launch_info; if (hostname.empty()) hostname = "127.0.0.1"; if (log) log->Printf("Launching debugserver with: %s:%u...\n", hostname.c_str(), port); // Do not run in a new session so that it can not linger after the // platform closes. debugserver_launch_info.SetLaunchInSeparateProcessGroup(false); debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false); std::string platform_scheme; std::string platform_ip; int platform_port; std::string platform_path; bool ok = UriParser::Parse(GetConnection()->GetURI().c_str(), platform_scheme, platform_ip, platform_port, platform_path); assert(ok); Error error = StartDebugserverProcess ( platform_ip.c_str(), port, debugserver_launch_info, port); lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); if (debugserver_pid != LLDB_INVALID_PROCESS_ID) { Mutex::Locker locker (m_spawned_pids_mutex); m_spawned_pids.insert(debugserver_pid); if (port > 0) AssociatePortWithProcess(port, debugserver_pid); } else { if (port > 0) FreePort (port); } if (error.Success()) { if (log) log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid); char response[256]; const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); assert (response_len < (int)sizeof(response)); PacketResult packet_result = SendPacketNoLock (response, response_len); if (packet_result != PacketResult::Success) { if (debugserver_pid != LLDB_INVALID_PROCESS_ID) ::kill (debugserver_pid, SIGINT); } return packet_result; } else { if (log) log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ()); } return SendErrorResponse (9); #endif }