1 //===-- PlatformAndroidRemoteGDBServer.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 // Other libraries and framework includes 11 #include "lldb/Core/Error.h" 12 #include "lldb/Core/Log.h" 13 #include "lldb/Host/common/TCPSocket.h" 14 #include "AdbClient.h" 15 #include "PlatformAndroidRemoteGDBServer.h" 16 #include "Utility/UriParser.h" 17 18 #include <sstream> 19 20 using namespace lldb; 21 using namespace lldb_private; 22 using namespace platform_android; 23 24 static const lldb::pid_t g_remote_platform_pid = 0; // Alias for the process id of lldb-platform 25 26 static Error 27 ForwardPortWithAdb (const uint16_t local_port, 28 const uint16_t remote_port, 29 const char* remote_socket_name, 30 std::string& device_id) 31 { 32 Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); 33 34 AdbClient adb; 35 auto error = AdbClient::CreateByDeviceID(device_id, adb); 36 if (error.Fail ()) 37 return error; 38 39 device_id = adb.GetDeviceID(); 40 if (log) 41 log->Printf("Connected to Android device \"%s\"", device_id.c_str ()); 42 43 if (remote_port != 0) 44 { 45 if (log) 46 log->Printf("Forwarding remote TCP port %d to local TCP port %d", remote_port, local_port); 47 return adb.SetPortForwarding(local_port, remote_port); 48 } 49 50 if (log) 51 log->Printf("Forwarding remote socket \"%s\" to local TCP port %d", remote_socket_name, local_port); 52 return adb.SetPortForwarding(local_port, remote_socket_name); 53 } 54 55 static Error 56 DeleteForwardPortWithAdb (uint16_t local_port, const std::string& device_id) 57 { 58 AdbClient adb (device_id); 59 return adb.DeletePortForwarding (local_port); 60 } 61 62 static Error 63 FindUnusedPort (uint16_t& port) 64 { 65 Error error; 66 std::unique_ptr<TCPSocket> tcp_socket(new TCPSocket(false, error)); 67 if (error.Fail()) 68 return error; 69 70 error = tcp_socket->Listen("127.0.0.1:0", 1); 71 if (error.Success()) 72 port = tcp_socket->GetLocalPortNumber(); 73 74 return error; 75 } 76 77 PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer () 78 { 79 } 80 81 PlatformAndroidRemoteGDBServer::~PlatformAndroidRemoteGDBServer () 82 { 83 for (const auto& it : m_port_forwards) 84 DeleteForwardPortWithAdb(it.second, m_device_id); 85 } 86 87 bool 88 PlatformAndroidRemoteGDBServer::LaunchGDBServer (lldb::pid_t &pid, std::string &connect_url) 89 { 90 uint16_t remote_port = 0; 91 std::string socket_name; 92 if (!m_gdb_client.LaunchGDBServer ("127.0.0.1", pid, remote_port, socket_name)) 93 return false; 94 95 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 96 97 auto error = MakeConnectURL (pid, 98 remote_port, 99 socket_name.c_str (), 100 connect_url); 101 if (error.Success() && log) 102 log->Printf("gdbserver connect URL: %s", connect_url.c_str()); 103 104 return error.Success(); 105 } 106 107 bool 108 PlatformAndroidRemoteGDBServer::KillSpawnedProcess (lldb::pid_t pid) 109 { 110 DeleteForwardPort (pid); 111 return m_gdb_client.KillSpawnedProcess (pid); 112 } 113 114 Error 115 PlatformAndroidRemoteGDBServer::ConnectRemote (Args& args) 116 { 117 m_device_id.clear(); 118 119 if (args.GetArgumentCount() != 1) 120 return Error("\"platform connect\" takes a single argument: <connect-url>"); 121 122 int remote_port; 123 std::string scheme, host, path; 124 const char *url = args.GetArgumentAtIndex (0); 125 if (!url) 126 return Error("URL is null."); 127 if (!UriParser::Parse (url, scheme, host, remote_port, path)) 128 return Error("Invalid URL: %s", url); 129 if (host != "localhost") 130 m_device_id = host; 131 132 std::string connect_url; 133 auto error = MakeConnectURL (g_remote_platform_pid, 134 (remote_port < 0) ? 0 : remote_port, 135 path.c_str (), 136 connect_url); 137 138 if (error.Fail ()) 139 return error; 140 141 args.ReplaceArgumentAtIndex (0, connect_url.c_str ()); 142 143 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 144 if (log) 145 log->Printf("Rewritten platform connect URL: %s", connect_url.c_str()); 146 147 error = PlatformRemoteGDBServer::ConnectRemote(args); 148 if (error.Fail ()) 149 DeleteForwardPort (g_remote_platform_pid); 150 151 return error; 152 } 153 154 Error 155 PlatformAndroidRemoteGDBServer::DisconnectRemote () 156 { 157 DeleteForwardPort (g_remote_platform_pid); 158 return PlatformRemoteGDBServer::DisconnectRemote (); 159 } 160 161 void 162 PlatformAndroidRemoteGDBServer::DeleteForwardPort (lldb::pid_t pid) 163 { 164 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 165 166 auto it = m_port_forwards.find(pid); 167 if (it == m_port_forwards.end()) 168 return; 169 170 const auto port = it->second; 171 const auto error = DeleteForwardPortWithAdb(port, m_device_id); 172 if (error.Fail()) { 173 if (log) 174 log->Printf("Failed to delete port forwarding (pid=%" PRIu64 ", port=%d, device=%s): %s", 175 pid, port, m_device_id.c_str(), error.AsCString()); 176 } 177 m_port_forwards.erase(it); 178 } 179 180 Error 181 PlatformAndroidRemoteGDBServer::MakeConnectURL(const lldb::pid_t pid, 182 const uint16_t remote_port, 183 const char* remote_socket_name, 184 std::string& connect_url) 185 { 186 static const int kAttempsNum = 5; 187 188 Error error; 189 // There is a race possibility that somebody will occupy 190 // a port while we're in between FindUnusedPort and ForwardPortWithAdb - 191 // adding the loop to mitigate such problem. 192 for (auto i = 0; i < kAttempsNum; ++i) 193 { 194 uint16_t local_port = 0; 195 error = FindUnusedPort(local_port); 196 if (error.Fail()) 197 return error; 198 199 error = ForwardPortWithAdb(local_port, remote_port, remote_socket_name, m_device_id); 200 if (error.Success()) 201 { 202 m_port_forwards[pid] = local_port; 203 std::ostringstream url_str; 204 url_str << "connect://localhost:" << local_port; 205 connect_url = url_str.str(); 206 break; 207 } 208 } 209 210 return error; 211 } 212