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"
1300e305d2STamas Berghammer 
1400e305d2STamas Berghammer // Project includes
1505a55de3SOleksiy Vyalov #include "AdbClient.h"
1600e305d2STamas Berghammer #include "PlatformAndroidRemoteGDBServer.h"
1700e305d2STamas Berghammer #include "Utility/UriParser.h"
1800e305d2STamas Berghammer 
19*54971856SOleksiy Vyalov #include <sstream>
20*54971856SOleksiy Vyalov 
2100e305d2STamas Berghammer using namespace lldb;
2200e305d2STamas Berghammer using namespace lldb_private;
23db264a6dSTamas Berghammer using namespace platform_android;
2400e305d2STamas Berghammer 
2500e305d2STamas Berghammer static const lldb::pid_t g_remote_platform_pid = 0; // Alias for the process id of lldb-platform
2600e305d2STamas Berghammer 
2700e305d2STamas Berghammer static Error
2800e305d2STamas Berghammer ForwardPortWithAdb (uint16_t port, std::string& device_id)
2900e305d2STamas Berghammer {
30db264a6dSTamas Berghammer     Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
3100e305d2STamas Berghammer 
3205a55de3SOleksiy Vyalov     AdbClient adb;
333ea689b3SChaoren Lin     auto error = AdbClient::CreateByDeviceID(device_id, adb);
3400e305d2STamas Berghammer     if (error.Fail ())
3500e305d2STamas Berghammer         return error;
3600e305d2STamas Berghammer 
37f9da9483SOleksiy Vyalov     device_id = adb.GetDeviceID();
3805a55de3SOleksiy Vyalov     if (log)
39f9da9483SOleksiy Vyalov         log->Printf("Connected to Android device \"%s\"", device_id.c_str ());
4005a55de3SOleksiy Vyalov 
4105a55de3SOleksiy Vyalov     return adb.SetPortForwarding(port);
4200e305d2STamas Berghammer }
4300e305d2STamas Berghammer 
4400e305d2STamas Berghammer static Error
4500e305d2STamas Berghammer DeleteForwardPortWithAdb (uint16_t port, const std::string& device_id)
4600e305d2STamas Berghammer {
4705a55de3SOleksiy Vyalov     AdbClient adb (device_id);
4805a55de3SOleksiy Vyalov     return adb.DeletePortForwarding (port);
4900e305d2STamas Berghammer }
5000e305d2STamas Berghammer 
5100e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer ()
5200e305d2STamas Berghammer {
5300e305d2STamas Berghammer }
5400e305d2STamas Berghammer 
5500e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::~PlatformAndroidRemoteGDBServer ()
5600e305d2STamas Berghammer {
5700e305d2STamas Berghammer     for (const auto& it : m_port_forwards)
583ea689b3SChaoren Lin         DeleteForwardPortWithAdb(it.second, m_device_id);
5900e305d2STamas Berghammer }
6000e305d2STamas Berghammer 
6100e305d2STamas Berghammer uint16_t
6200e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::LaunchGDBserverAndGetPort (lldb::pid_t &pid)
6300e305d2STamas Berghammer {
6400e305d2STamas Berghammer     uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort (pid, "127.0.0.1");
6500e305d2STamas Berghammer     if (port == 0)
6600e305d2STamas Berghammer         return port;
6700e305d2STamas Berghammer 
683ea689b3SChaoren Lin     Error error = ForwardPortWithAdb(port, m_device_id);
6900e305d2STamas Berghammer     if (error.Fail ())
7000e305d2STamas Berghammer         return 0;
7100e305d2STamas Berghammer 
723ea689b3SChaoren Lin     m_port_forwards[pid] = port;
7300e305d2STamas Berghammer 
7400e305d2STamas Berghammer     return port;
7500e305d2STamas Berghammer }
7600e305d2STamas Berghammer 
7700e305d2STamas Berghammer bool
7800e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::KillSpawnedProcess (lldb::pid_t pid)
7900e305d2STamas Berghammer {
801c1d76b3SOleksiy Vyalov     DeleteForwardPort (pid);
8100e305d2STamas Berghammer     return m_gdb_client.KillSpawnedProcess (pid);
8200e305d2STamas Berghammer }
8300e305d2STamas Berghammer 
8400e305d2STamas Berghammer Error
8500e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::ConnectRemote (Args& args)
8600e305d2STamas Berghammer {
873ea689b3SChaoren Lin     m_device_id.clear();
883ea689b3SChaoren Lin 
8900e305d2STamas Berghammer     if (args.GetArgumentCount() != 1)
9000e305d2STamas Berghammer         return Error("\"platform connect\" takes a single argument: <connect-url>");
9100e305d2STamas Berghammer 
9200e305d2STamas Berghammer     int port;
9300e305d2STamas Berghammer     std::string scheme, host, path;
9400e305d2STamas Berghammer     const char *url = args.GetArgumentAtIndex (0);
953ea689b3SChaoren Lin     if (!url)
963ea689b3SChaoren Lin         return Error("URL is null.");
9700e305d2STamas Berghammer     if (!UriParser::Parse (url, scheme, host, port, path))
983ea689b3SChaoren Lin         return Error("Invalid URL: %s", url);
993ea689b3SChaoren Lin     if (scheme == "adb")
1003ea689b3SChaoren Lin         m_device_id = host;
10100e305d2STamas Berghammer 
1023ea689b3SChaoren Lin     Error error = ForwardPortWithAdb(port, m_device_id);
10300e305d2STamas Berghammer     if (error.Fail())
10400e305d2STamas Berghammer         return error;
10500e305d2STamas Berghammer 
1063ea689b3SChaoren Lin     m_port_forwards[g_remote_platform_pid] = port;
10700e305d2STamas Berghammer 
1081c1d76b3SOleksiy Vyalov     error = PlatformRemoteGDBServer::ConnectRemote(args);
1091c1d76b3SOleksiy Vyalov     if (error.Fail ())
1101c1d76b3SOleksiy Vyalov         DeleteForwardPort (g_remote_platform_pid);
1111c1d76b3SOleksiy Vyalov 
1121c1d76b3SOleksiy Vyalov     return error;
11300e305d2STamas Berghammer }
11400e305d2STamas Berghammer 
11500e305d2STamas Berghammer Error
11600e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::DisconnectRemote ()
11700e305d2STamas Berghammer {
1181c1d76b3SOleksiy Vyalov     DeleteForwardPort (g_remote_platform_pid);
1191c1d76b3SOleksiy Vyalov     return PlatformRemoteGDBServer::DisconnectRemote ();
12000e305d2STamas Berghammer }
12100e305d2STamas Berghammer 
1221c1d76b3SOleksiy Vyalov void
1231c1d76b3SOleksiy Vyalov PlatformAndroidRemoteGDBServer::DeleteForwardPort (lldb::pid_t pid)
1241c1d76b3SOleksiy Vyalov {
1251c1d76b3SOleksiy Vyalov     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
1261c1d76b3SOleksiy Vyalov 
1271c1d76b3SOleksiy Vyalov     auto it = m_port_forwards.find(pid);
1281c1d76b3SOleksiy Vyalov     if (it == m_port_forwards.end())
1291c1d76b3SOleksiy Vyalov         return;
1301c1d76b3SOleksiy Vyalov 
1313ea689b3SChaoren Lin     const auto port = it->second;
1323ea689b3SChaoren Lin     const auto error = DeleteForwardPortWithAdb(port, m_device_id);
1331c1d76b3SOleksiy Vyalov     if (error.Fail()) {
1341c1d76b3SOleksiy Vyalov         if (log)
1351c1d76b3SOleksiy Vyalov             log->Printf("Failed to delete port forwarding (pid=%" PRIu64 ", port=%d, device=%s): %s",
1363ea689b3SChaoren Lin                          pid, port, m_device_id.c_str(), error.AsCString());
1371c1d76b3SOleksiy Vyalov     }
1381c1d76b3SOleksiy Vyalov     m_port_forwards.erase(it);
13900e305d2STamas Berghammer }
140*54971856SOleksiy Vyalov 
141*54971856SOleksiy Vyalov std::string
142*54971856SOleksiy Vyalov PlatformAndroidRemoteGDBServer::MakeServerUrl(const char* scheme,
143*54971856SOleksiy Vyalov                                               const char* hostname,
144*54971856SOleksiy Vyalov                                               uint16_t port)
145*54971856SOleksiy Vyalov {
146*54971856SOleksiy Vyalov     std::ostringstream hostname_str;
147*54971856SOleksiy Vyalov     if (!strcmp(scheme, "adb"))
148*54971856SOleksiy Vyalov         hostname_str << "[" << hostname << "]";
149*54971856SOleksiy Vyalov     else
150*54971856SOleksiy Vyalov         hostname_str << hostname;
151*54971856SOleksiy Vyalov 
152*54971856SOleksiy Vyalov     return PlatformRemoteGDBServer::MakeServerUrl(scheme,
153*54971856SOleksiy Vyalov                                                   hostname_str.str().c_str(),
154*54971856SOleksiy Vyalov                                                   port);
155*54971856SOleksiy Vyalov }
156