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