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 279fe526c2SOleksiy Vyalov ForwardPortWithAdb (const uint16_t local_port, 289fe526c2SOleksiy Vyalov const uint16_t remote_port, 299fe526c2SOleksiy Vyalov const char* remote_socket_name, 309fe526c2SOleksiy 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 439fe526c2SOleksiy Vyalov if (remote_port != 0) 449fe526c2SOleksiy Vyalov { 459fe526c2SOleksiy Vyalov if (log) 469fe526c2SOleksiy 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 509fe526c2SOleksiy Vyalov if (log) 519fe526c2SOleksiy Vyalov log->Printf("Forwarding remote socket \"%s\" to local TCP port %d", remote_socket_name, local_port); 529fe526c2SOleksiy Vyalov return adb.SetPortForwarding(local_port, remote_socket_name); 539fe526c2SOleksiy Vyalov } 549fe526c2SOleksiy 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 879fe526c2SOleksiy Vyalov bool 889fe526c2SOleksiy Vyalov PlatformAndroidRemoteGDBServer::LaunchGDBServer (lldb::pid_t &pid, std::string &connect_url) 8900e305d2STamas Berghammer { 909fe526c2SOleksiy Vyalov uint16_t remote_port = 0; 919fe526c2SOleksiy Vyalov std::string socket_name; 929fe526c2SOleksiy Vyalov if (!m_gdb_client.LaunchGDBServer ("127.0.0.1", pid, remote_port, socket_name)) 939fe526c2SOleksiy Vyalov return false; 9400e305d2STamas Berghammer 959fe526c2SOleksiy Vyalov Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 969fe526c2SOleksiy Vyalov 979fe526c2SOleksiy Vyalov auto error = MakeConnectURL (pid, 989fe526c2SOleksiy Vyalov remote_port, 999fe526c2SOleksiy Vyalov socket_name.c_str (), 1009fe526c2SOleksiy Vyalov connect_url); 1019fe526c2SOleksiy Vyalov if (error.Success() && log) 1029fe526c2SOleksiy Vyalov log->Printf("gdbserver connect URL: %s", connect_url.c_str()); 1039fe526c2SOleksiy Vyalov 1049fe526c2SOleksiy 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); 129*a29d6475SOleksiy Vyalov if (host != "localhost") 1303ea689b3SChaoren Lin m_device_id = host; 13100e305d2STamas Berghammer 1329fe526c2SOleksiy Vyalov std::string connect_url; 1339fe526c2SOleksiy Vyalov auto error = MakeConnectURL (g_remote_platform_pid, 1349fe526c2SOleksiy Vyalov (remote_port < 0) ? 0 : remote_port, 1359fe526c2SOleksiy Vyalov path.c_str (), 1369fe526c2SOleksiy Vyalov connect_url); 1379fe526c2SOleksiy Vyalov 13800e305d2STamas Berghammer if (error.Fail ()) 13900e305d2STamas Berghammer return error; 14000e305d2STamas Berghammer 1419fe526c2SOleksiy Vyalov args.ReplaceArgumentAtIndex (0, connect_url.c_str ()); 142e7eabbb5SOleksiy Vyalov 143e7eabbb5SOleksiy Vyalov Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 144e7eabbb5SOleksiy Vyalov if (log) 1459fe526c2SOleksiy Vyalov log->Printf("Rewritten platform connect URL: %s", connect_url.c_str()); 14600e305d2STamas Berghammer 1471c1d76b3SOleksiy Vyalov error = PlatformRemoteGDBServer::ConnectRemote(args); 1481c1d76b3SOleksiy Vyalov if (error.Fail ()) 1491c1d76b3SOleksiy Vyalov DeleteForwardPort (g_remote_platform_pid); 1501c1d76b3SOleksiy Vyalov 1511c1d76b3SOleksiy Vyalov return error; 15200e305d2STamas Berghammer } 15300e305d2STamas Berghammer 15400e305d2STamas Berghammer Error 15500e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::DisconnectRemote () 15600e305d2STamas Berghammer { 1571c1d76b3SOleksiy Vyalov DeleteForwardPort (g_remote_platform_pid); 1581c1d76b3SOleksiy Vyalov return PlatformRemoteGDBServer::DisconnectRemote (); 15900e305d2STamas Berghammer } 16000e305d2STamas Berghammer 1611c1d76b3SOleksiy Vyalov void 1621c1d76b3SOleksiy Vyalov PlatformAndroidRemoteGDBServer::DeleteForwardPort (lldb::pid_t pid) 1631c1d76b3SOleksiy Vyalov { 1641c1d76b3SOleksiy Vyalov Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); 1651c1d76b3SOleksiy Vyalov 1661c1d76b3SOleksiy Vyalov auto it = m_port_forwards.find(pid); 1671c1d76b3SOleksiy Vyalov if (it == m_port_forwards.end()) 1681c1d76b3SOleksiy Vyalov return; 1691c1d76b3SOleksiy Vyalov 1703ea689b3SChaoren Lin const auto port = it->second; 1713ea689b3SChaoren Lin const auto error = DeleteForwardPortWithAdb(port, m_device_id); 1721c1d76b3SOleksiy Vyalov if (error.Fail()) { 1731c1d76b3SOleksiy Vyalov if (log) 1741c1d76b3SOleksiy Vyalov log->Printf("Failed to delete port forwarding (pid=%" PRIu64 ", port=%d, device=%s): %s", 1753ea689b3SChaoren Lin pid, port, m_device_id.c_str(), error.AsCString()); 1761c1d76b3SOleksiy Vyalov } 1771c1d76b3SOleksiy Vyalov m_port_forwards.erase(it); 17800e305d2STamas Berghammer } 17954971856SOleksiy Vyalov 180e7eabbb5SOleksiy Vyalov Error 1819fe526c2SOleksiy Vyalov PlatformAndroidRemoteGDBServer::MakeConnectURL(const lldb::pid_t pid, 182e7eabbb5SOleksiy Vyalov const uint16_t remote_port, 1839fe526c2SOleksiy Vyalov const char* remote_socket_name, 1849fe526c2SOleksiy Vyalov std::string& connect_url) 185e7eabbb5SOleksiy Vyalov { 186e7eabbb5SOleksiy Vyalov static const int kAttempsNum = 5; 187e7eabbb5SOleksiy Vyalov 188e7eabbb5SOleksiy Vyalov Error error; 189e7eabbb5SOleksiy Vyalov // There is a race possibility that somebody will occupy 190e7eabbb5SOleksiy Vyalov // a port while we're in between FindUnusedPort and ForwardPortWithAdb - 191e7eabbb5SOleksiy Vyalov // adding the loop to mitigate such problem. 192e7eabbb5SOleksiy Vyalov for (auto i = 0; i < kAttempsNum; ++i) 193e7eabbb5SOleksiy Vyalov { 1949fe526c2SOleksiy Vyalov uint16_t local_port = 0; 195e7eabbb5SOleksiy Vyalov error = FindUnusedPort(local_port); 196e7eabbb5SOleksiy Vyalov if (error.Fail()) 197e7eabbb5SOleksiy Vyalov return error; 198e7eabbb5SOleksiy Vyalov 1999fe526c2SOleksiy Vyalov error = ForwardPortWithAdb(local_port, remote_port, remote_socket_name, m_device_id); 200e7eabbb5SOleksiy Vyalov if (error.Success()) 201e7eabbb5SOleksiy Vyalov { 202e7eabbb5SOleksiy Vyalov m_port_forwards[pid] = local_port; 2039fe526c2SOleksiy Vyalov std::ostringstream url_str; 2049fe526c2SOleksiy Vyalov url_str << "connect://localhost:" << local_port; 2059fe526c2SOleksiy Vyalov connect_url = url_str.str(); 206e7eabbb5SOleksiy Vyalov break; 207e7eabbb5SOleksiy Vyalov } 208e7eabbb5SOleksiy Vyalov } 209e7eabbb5SOleksiy Vyalov 210e7eabbb5SOleksiy Vyalov return error; 211e7eabbb5SOleksiy Vyalov } 212