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 "PlatformAndroidRemoteGDBServer.h" 15 #include "Utility/UriParser.h" 16 17 #include <sstream> 18 19 using namespace lldb; 20 using namespace lldb_private; 21 using namespace platform_android; 22 23 static const lldb::pid_t g_remote_platform_pid = 0; // Alias for the process id of lldb-platform 24 25 static Error 26 ForwardPortWithAdb (const uint16_t local_port, 27 const uint16_t remote_port, 28 const char* remote_socket_name, 29 const llvm::Optional<AdbClient::UnixSocketNamespace>& socket_namespace, 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 53 if (!socket_namespace) 54 return Error("Invalid socket namespace"); 55 56 return adb.SetPortForwarding(local_port, remote_socket_name, *socket_namespace); 57 } 58 59 static Error 60 DeleteForwardPortWithAdb (uint16_t local_port, const std::string& device_id) 61 { 62 AdbClient adb (device_id); 63 return adb.DeletePortForwarding (local_port); 64 } 65 66 static Error 67 FindUnusedPort (uint16_t& port) 68 { 69 Error error; 70 std::unique_ptr<TCPSocket> tcp_socket(new TCPSocket(false, error)); 71 if (error.Fail()) 72 return error; 73 74 error = tcp_socket->Listen("127.0.0.1:0", 1); 75 if (error.Success()) 76 port = tcp_socket->GetLocalPortNumber(); 77 78 return error; 79 } 80 81 PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer () 82 { 83 } 84 85 PlatformAndroidRemoteGDBServer::~PlatformAndroidRemoteGDBServer () 86 { 87 for (const auto& it : m_port_forwards) 88 DeleteForwardPortWithAdb(it.second, m_device_id); 89 } 90 91 bool 92 PlatformAndroidRemoteGDBServer::LaunchGDBServer (lldb::pid_t &pid, std::string &connect_url) 93 { 94 uint16_t remote_port = 0; 95 std::string socket_name; 96 if (!m_gdb_client.LaunchGDBServer ("127.0.0.1", pid, remote_port, socket_name)) 97 return false; 98 99 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 100 101 auto error = MakeConnectURL (pid, 102 remote_port, 103 socket_name.c_str (), 104 connect_url); 105 if (error.Success() && log) 106 log->Printf("gdbserver connect URL: %s", connect_url.c_str()); 107 108 return error.Success(); 109 } 110 111 bool 112 PlatformAndroidRemoteGDBServer::KillSpawnedProcess (lldb::pid_t pid) 113 { 114 DeleteForwardPort (pid); 115 return m_gdb_client.KillSpawnedProcess (pid); 116 } 117 118 Error 119 PlatformAndroidRemoteGDBServer::ConnectRemote (Args& args) 120 { 121 m_device_id.clear(); 122 123 if (args.GetArgumentCount() != 1) 124 return Error("\"platform connect\" takes a single argument: <connect-url>"); 125 126 int remote_port; 127 std::string scheme, host, path; 128 const char *url = args.GetArgumentAtIndex (0); 129 if (!url) 130 return Error("URL is null."); 131 if (!UriParser::Parse (url, scheme, host, remote_port, path)) 132 return Error("Invalid URL: %s", url); 133 if (host != "localhost") 134 m_device_id = host; 135 136 m_socket_namespace.reset(); 137 if (scheme == ConnectionFileDescriptor::UNIX_CONNECT_SCHEME) 138 m_socket_namespace = AdbClient::UnixSocketNamespaceFileSystem; 139 else if (scheme == ConnectionFileDescriptor::UNIX_ABSTRACT_CONNECT_SCHEME) 140 m_socket_namespace = AdbClient::UnixSocketNamespaceAbstract; 141 142 std::string connect_url; 143 auto error = MakeConnectURL (g_remote_platform_pid, 144 (remote_port < 0) ? 0 : remote_port, 145 path.c_str (), 146 connect_url); 147 148 if (error.Fail ()) 149 return error; 150 151 args.ReplaceArgumentAtIndex (0, connect_url.c_str ()); 152 153 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 154 if (log) 155 log->Printf("Rewritten platform connect URL: %s", connect_url.c_str()); 156 157 error = PlatformRemoteGDBServer::ConnectRemote(args); 158 if (error.Fail ()) 159 DeleteForwardPort (g_remote_platform_pid); 160 161 return error; 162 } 163 164 Error 165 PlatformAndroidRemoteGDBServer::DisconnectRemote () 166 { 167 DeleteForwardPort (g_remote_platform_pid); 168 return PlatformRemoteGDBServer::DisconnectRemote (); 169 } 170 171 void 172 PlatformAndroidRemoteGDBServer::DeleteForwardPort (lldb::pid_t pid) 173 { 174 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 175 176 auto it = m_port_forwards.find(pid); 177 if (it == m_port_forwards.end()) 178 return; 179 180 const auto port = it->second; 181 const auto error = DeleteForwardPortWithAdb(port, m_device_id); 182 if (error.Fail()) { 183 if (log) 184 log->Printf("Failed to delete port forwarding (pid=%" PRIu64 ", port=%d, device=%s): %s", 185 pid, port, m_device_id.c_str(), error.AsCString()); 186 } 187 m_port_forwards.erase(it); 188 } 189 190 Error 191 PlatformAndroidRemoteGDBServer::MakeConnectURL(const lldb::pid_t pid, 192 const uint16_t remote_port, 193 const char* remote_socket_name, 194 std::string& connect_url) 195 { 196 static const int kAttempsNum = 5; 197 198 Error error; 199 // There is a race possibility that somebody will occupy 200 // a port while we're in between FindUnusedPort and ForwardPortWithAdb - 201 // adding the loop to mitigate such problem. 202 for (auto i = 0; i < kAttempsNum; ++i) 203 { 204 uint16_t local_port = 0; 205 error = FindUnusedPort(local_port); 206 if (error.Fail()) 207 return error; 208 209 error = ForwardPortWithAdb(local_port, 210 remote_port, 211 remote_socket_name, 212 m_socket_namespace, 213 m_device_id); 214 if (error.Success()) 215 { 216 m_port_forwards[pid] = local_port; 217 std::ostringstream url_str; 218 url_str << "connect://localhost:" << local_port; 219 connect_url = url_str.str(); 220 break; 221 } 222 } 223 224 return error; 225 } 226 227 lldb::ProcessSP 228 PlatformAndroidRemoteGDBServer::ConnectProcess(const char* connect_url, 229 const char* plugin_name, 230 lldb_private::Debugger &debugger, 231 lldb_private::Target *target, 232 lldb_private::Error &error) 233 { 234 // We don't have the pid of the remote gdbserver when it isn't started by us but we still want 235 // to store the list of port forwards we set up in our port forward map. Generate a fake pid for 236 // these cases what won't collide with any other valid pid on android. 237 static lldb::pid_t s_remote_gdbserver_fake_pid = 0xffffffffffffffffULL; 238 239 int remote_port; 240 std::string scheme, host, path; 241 if (!UriParser::Parse(connect_url, scheme, host, remote_port, path)) 242 { 243 error.SetErrorStringWithFormat("Invalid URL: %s", connect_url); 244 return nullptr; 245 } 246 247 std::string new_connect_url; 248 error = MakeConnectURL(s_remote_gdbserver_fake_pid--, 249 (remote_port < 0) ? 0 : remote_port, 250 path.c_str(), 251 new_connect_url); 252 if (error.Fail()) 253 return nullptr; 254 255 return PlatformRemoteGDBServer::ConnectProcess(new_connect_url.c_str(), 256 plugin_name, 257 debugger, 258 target, 259 error); 260 } 261