100e305d2STamas Berghammer //===-- PlatformAndroidRemoteGDBServer.cpp ----------------------*- C++ -*-===// 200e305d2STamas Berghammer // 300e305d2STamas Berghammer // The LLVM Compiler Infrastructure 400e305d2STamas Berghammer // 500e305d2STamas Berghammer // This file is distributed under the University of Illinois Open Source 600e305d2STamas Berghammer // License. See LICENSE.TXT for details. 700e305d2STamas Berghammer // 800e305d2STamas Berghammer //===----------------------------------------------------------------------===// 900e305d2STamas Berghammer 1000e305d2STamas Berghammer // Other libraries and framework includes 1100e305d2STamas Berghammer #include "lldb/Core/Error.h" 1205a55de3SOleksiy Vyalov #include "lldb/Core/Log.h" 13e98628ceSOleksiy Vyalov #include "lldb/Host/common/TCPSocket.h" 1405a55de3SOleksiy Vyalov #include "AdbClient.h" 1500e305d2STamas Berghammer #include "PlatformAndroidRemoteGDBServer.h" 1600e305d2STamas Berghammer #include "Utility/UriParser.h" 1700e305d2STamas Berghammer 1854971856SOleksiy Vyalov #include <sstream> 1954971856SOleksiy Vyalov 2000e305d2STamas Berghammer using namespace lldb; 2100e305d2STamas Berghammer using namespace lldb_private; 22db264a6dSTamas Berghammer using namespace platform_android; 2300e305d2STamas Berghammer 2400e305d2STamas Berghammer static const lldb::pid_t g_remote_platform_pid = 0; // Alias for the process id of lldb-platform 2500e305d2STamas Berghammer 2600e305d2STamas Berghammer static Error 27*9fe526c2SOleksiy Vyalov ForwardPortWithAdb (const uint16_t local_port, 28*9fe526c2SOleksiy Vyalov const uint16_t remote_port, 29*9fe526c2SOleksiy Vyalov const char* remote_socket_name, 30*9fe526c2SOleksiy Vyalov std::string& device_id) 3100e305d2STamas Berghammer { 32db264a6dSTamas Berghammer Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); 3300e305d2STamas Berghammer 3405a55de3SOleksiy Vyalov AdbClient adb; 353ea689b3SChaoren Lin auto error = AdbClient::CreateByDeviceID(device_id, adb); 3600e305d2STamas Berghammer if (error.Fail ()) 3700e305d2STamas Berghammer return error; 3800e305d2STamas Berghammer 39f9da9483SOleksiy Vyalov device_id = adb.GetDeviceID(); 4005a55de3SOleksiy Vyalov if (log) 41f9da9483SOleksiy Vyalov log->Printf("Connected to Android device \"%s\"", device_id.c_str ()); 4205a55de3SOleksiy Vyalov 43*9fe526c2SOleksiy Vyalov if (remote_port != 0) 44*9fe526c2SOleksiy Vyalov { 45*9fe526c2SOleksiy Vyalov if (log) 46*9fe526c2SOleksiy Vyalov log->Printf("Forwarding remote TCP port %d to local TCP port %d", remote_port, local_port); 47e7eabbb5SOleksiy Vyalov return adb.SetPortForwarding(local_port, remote_port); 4800e305d2STamas Berghammer } 4900e305d2STamas Berghammer 50*9fe526c2SOleksiy Vyalov if (log) 51*9fe526c2SOleksiy Vyalov log->Printf("Forwarding remote socket \"%s\" to local TCP port %d", remote_socket_name, local_port); 52*9fe526c2SOleksiy Vyalov return adb.SetPortForwarding(local_port, remote_socket_name); 53*9fe526c2SOleksiy Vyalov } 54*9fe526c2SOleksiy Vyalov 5500e305d2STamas Berghammer static Error 56e7eabbb5SOleksiy Vyalov DeleteForwardPortWithAdb (uint16_t local_port, const std::string& device_id) 5700e305d2STamas Berghammer { 5805a55de3SOleksiy Vyalov AdbClient adb (device_id); 59e7eabbb5SOleksiy Vyalov return adb.DeletePortForwarding (local_port); 60e7eabbb5SOleksiy Vyalov } 61e7eabbb5SOleksiy Vyalov 62e7eabbb5SOleksiy Vyalov static Error 63e7eabbb5SOleksiy Vyalov FindUnusedPort (uint16_t& port) 64e7eabbb5SOleksiy Vyalov { 65e98628ceSOleksiy Vyalov Error error; 66e98628ceSOleksiy Vyalov std::unique_ptr<TCPSocket> tcp_socket(new TCPSocket(false, error)); 67e98628ceSOleksiy Vyalov if (error.Fail()) 68e98628ceSOleksiy Vyalov return error; 69e98628ceSOleksiy Vyalov 70e98628ceSOleksiy Vyalov error = tcp_socket->Listen("127.0.0.1:0", 1); 71e7eabbb5SOleksiy Vyalov if (error.Success()) 72e98628ceSOleksiy Vyalov port = tcp_socket->GetLocalPortNumber(); 73e98628ceSOleksiy Vyalov 74e7eabbb5SOleksiy Vyalov return error; 7500e305d2STamas Berghammer } 7600e305d2STamas Berghammer 7700e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer () 7800e305d2STamas Berghammer { 7900e305d2STamas Berghammer } 8000e305d2STamas Berghammer 8100e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::~PlatformAndroidRemoteGDBServer () 8200e305d2STamas Berghammer { 8300e305d2STamas Berghammer for (const auto& it : m_port_forwards) 843ea689b3SChaoren Lin DeleteForwardPortWithAdb(it.second, m_device_id); 8500e305d2STamas Berghammer } 8600e305d2STamas Berghammer 87*9fe526c2SOleksiy Vyalov bool 88*9fe526c2SOleksiy Vyalov PlatformAndroidRemoteGDBServer::LaunchGDBServer (lldb::pid_t &pid, std::string &connect_url) 8900e305d2STamas Berghammer { 90*9fe526c2SOleksiy Vyalov uint16_t remote_port = 0; 91*9fe526c2SOleksiy Vyalov std::string socket_name; 92*9fe526c2SOleksiy Vyalov if (!m_gdb_client.LaunchGDBServer ("127.0.0.1", pid, remote_port, socket_name)) 93*9fe526c2SOleksiy Vyalov return false; 9400e305d2STamas Berghammer 95*9fe526c2SOleksiy Vyalov Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 96*9fe526c2SOleksiy Vyalov 97*9fe526c2SOleksiy Vyalov auto error = MakeConnectURL (pid, 98*9fe526c2SOleksiy Vyalov remote_port, 99*9fe526c2SOleksiy Vyalov socket_name.c_str (), 100*9fe526c2SOleksiy Vyalov connect_url); 101*9fe526c2SOleksiy Vyalov if (error.Success() && log) 102*9fe526c2SOleksiy Vyalov log->Printf("gdbserver connect URL: %s", connect_url.c_str()); 103*9fe526c2SOleksiy Vyalov 104*9fe526c2SOleksiy Vyalov return error.Success(); 10500e305d2STamas Berghammer } 10600e305d2STamas Berghammer 10700e305d2STamas Berghammer bool 10800e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::KillSpawnedProcess (lldb::pid_t pid) 10900e305d2STamas Berghammer { 1101c1d76b3SOleksiy Vyalov DeleteForwardPort (pid); 11100e305d2STamas Berghammer return m_gdb_client.KillSpawnedProcess (pid); 11200e305d2STamas Berghammer } 11300e305d2STamas Berghammer 11400e305d2STamas Berghammer Error 11500e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::ConnectRemote (Args& args) 11600e305d2STamas Berghammer { 1173ea689b3SChaoren Lin m_device_id.clear(); 1183ea689b3SChaoren Lin 11900e305d2STamas Berghammer if (args.GetArgumentCount() != 1) 12000e305d2STamas Berghammer return Error("\"platform connect\" takes a single argument: <connect-url>"); 12100e305d2STamas Berghammer 122e7eabbb5SOleksiy Vyalov int remote_port; 12300e305d2STamas Berghammer std::string scheme, host, path; 12400e305d2STamas Berghammer const char *url = args.GetArgumentAtIndex (0); 1253ea689b3SChaoren Lin if (!url) 1263ea689b3SChaoren Lin return Error("URL is null."); 127e7eabbb5SOleksiy Vyalov if (!UriParser::Parse (url, scheme, host, remote_port, path)) 1283ea689b3SChaoren Lin return Error("Invalid URL: %s", url); 1293ea689b3SChaoren Lin m_device_id = host; 13000e305d2STamas Berghammer 131*9fe526c2SOleksiy Vyalov std::string connect_url; 132*9fe526c2SOleksiy Vyalov auto error = MakeConnectURL (g_remote_platform_pid, 133*9fe526c2SOleksiy Vyalov (remote_port < 0) ? 0 : remote_port, 134*9fe526c2SOleksiy Vyalov path.c_str (), 135*9fe526c2SOleksiy Vyalov connect_url); 136*9fe526c2SOleksiy Vyalov 13700e305d2STamas Berghammer if (error.Fail ()) 13800e305d2STamas Berghammer return error; 13900e305d2STamas Berghammer 140*9fe526c2SOleksiy Vyalov args.ReplaceArgumentAtIndex (0, connect_url.c_str ()); 141e7eabbb5SOleksiy Vyalov 142e7eabbb5SOleksiy Vyalov Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 143e7eabbb5SOleksiy Vyalov if (log) 144*9fe526c2SOleksiy Vyalov log->Printf("Rewritten platform connect URL: %s", connect_url.c_str()); 14500e305d2STamas Berghammer 1461c1d76b3SOleksiy Vyalov error = PlatformRemoteGDBServer::ConnectRemote(args); 1471c1d76b3SOleksiy Vyalov if (error.Fail ()) 1481c1d76b3SOleksiy Vyalov DeleteForwardPort (g_remote_platform_pid); 1491c1d76b3SOleksiy Vyalov 1501c1d76b3SOleksiy Vyalov return error; 15100e305d2STamas Berghammer } 15200e305d2STamas Berghammer 15300e305d2STamas Berghammer Error 15400e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::DisconnectRemote () 15500e305d2STamas Berghammer { 1561c1d76b3SOleksiy Vyalov DeleteForwardPort (g_remote_platform_pid); 1571c1d76b3SOleksiy Vyalov return PlatformRemoteGDBServer::DisconnectRemote (); 15800e305d2STamas Berghammer } 15900e305d2STamas Berghammer 1601c1d76b3SOleksiy Vyalov void 1611c1d76b3SOleksiy Vyalov PlatformAndroidRemoteGDBServer::DeleteForwardPort (lldb::pid_t pid) 1621c1d76b3SOleksiy Vyalov { 1631c1d76b3SOleksiy Vyalov Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 1641c1d76b3SOleksiy Vyalov 1651c1d76b3SOleksiy Vyalov auto it = m_port_forwards.find(pid); 1661c1d76b3SOleksiy Vyalov if (it == m_port_forwards.end()) 1671c1d76b3SOleksiy Vyalov return; 1681c1d76b3SOleksiy Vyalov 1693ea689b3SChaoren Lin const auto port = it->second; 1703ea689b3SChaoren Lin const auto error = DeleteForwardPortWithAdb(port, m_device_id); 1711c1d76b3SOleksiy Vyalov if (error.Fail()) { 1721c1d76b3SOleksiy Vyalov if (log) 1731c1d76b3SOleksiy Vyalov log->Printf("Failed to delete port forwarding (pid=%" PRIu64 ", port=%d, device=%s): %s", 1743ea689b3SChaoren Lin pid, port, m_device_id.c_str(), error.AsCString()); 1751c1d76b3SOleksiy Vyalov } 1761c1d76b3SOleksiy Vyalov m_port_forwards.erase(it); 17700e305d2STamas Berghammer } 17854971856SOleksiy Vyalov 179e7eabbb5SOleksiy Vyalov Error 180*9fe526c2SOleksiy Vyalov PlatformAndroidRemoteGDBServer::MakeConnectURL(const lldb::pid_t pid, 181e7eabbb5SOleksiy Vyalov const uint16_t remote_port, 182*9fe526c2SOleksiy Vyalov const char* remote_socket_name, 183*9fe526c2SOleksiy Vyalov std::string& connect_url) 184e7eabbb5SOleksiy Vyalov { 185e7eabbb5SOleksiy Vyalov static const int kAttempsNum = 5; 186e7eabbb5SOleksiy Vyalov 187e7eabbb5SOleksiy Vyalov Error error; 188e7eabbb5SOleksiy Vyalov // There is a race possibility that somebody will occupy 189e7eabbb5SOleksiy Vyalov // a port while we're in between FindUnusedPort and ForwardPortWithAdb - 190e7eabbb5SOleksiy Vyalov // adding the loop to mitigate such problem. 191e7eabbb5SOleksiy Vyalov for (auto i = 0; i < kAttempsNum; ++i) 192e7eabbb5SOleksiy Vyalov { 193*9fe526c2SOleksiy Vyalov uint16_t local_port = 0; 194e7eabbb5SOleksiy Vyalov error = FindUnusedPort(local_port); 195e7eabbb5SOleksiy Vyalov if (error.Fail()) 196e7eabbb5SOleksiy Vyalov return error; 197e7eabbb5SOleksiy Vyalov 198*9fe526c2SOleksiy Vyalov error = ForwardPortWithAdb(local_port, remote_port, remote_socket_name, m_device_id); 199e7eabbb5SOleksiy Vyalov if (error.Success()) 200e7eabbb5SOleksiy Vyalov { 201e7eabbb5SOleksiy Vyalov m_port_forwards[pid] = local_port; 202*9fe526c2SOleksiy Vyalov std::ostringstream url_str; 203*9fe526c2SOleksiy Vyalov url_str << "connect://localhost:" << local_port; 204*9fe526c2SOleksiy Vyalov connect_url = url_str.str(); 205e7eabbb5SOleksiy Vyalov break; 206e7eabbb5SOleksiy Vyalov } 207e7eabbb5SOleksiy Vyalov } 208e7eabbb5SOleksiy Vyalov 209e7eabbb5SOleksiy Vyalov return error; 210e7eabbb5SOleksiy Vyalov } 211