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 
14 // Project includes
15 #include "AdbClient.h"
16 #include "PlatformAndroidRemoteGDBServer.h"
17 #include "Utility/UriParser.h"
18 
19 #include <sstream>
20 
21 using namespace lldb;
22 using namespace lldb_private;
23 using namespace platform_android;
24 
25 static const lldb::pid_t g_remote_platform_pid = 0; // Alias for the process id of lldb-platform
26 
27 static Error
28 ForwardPortWithAdb (uint16_t port, std::string& device_id)
29 {
30     Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
31 
32     AdbClient adb;
33     auto error = AdbClient::CreateByDeviceID(device_id, adb);
34     if (error.Fail ())
35         return error;
36 
37     device_id = adb.GetDeviceID();
38     if (log)
39         log->Printf("Connected to Android device \"%s\"", device_id.c_str ());
40 
41     return adb.SetPortForwarding(port);
42 }
43 
44 static Error
45 DeleteForwardPortWithAdb (uint16_t port, const std::string& device_id)
46 {
47     AdbClient adb (device_id);
48     return adb.DeletePortForwarding (port);
49 }
50 
51 PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer ()
52 {
53 }
54 
55 PlatformAndroidRemoteGDBServer::~PlatformAndroidRemoteGDBServer ()
56 {
57     for (const auto& it : m_port_forwards)
58         DeleteForwardPortWithAdb(it.second, m_device_id);
59 }
60 
61 uint16_t
62 PlatformAndroidRemoteGDBServer::LaunchGDBserverAndGetPort (lldb::pid_t &pid)
63 {
64     uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort (pid, "127.0.0.1");
65     if (port == 0)
66         return port;
67 
68     Error error = ForwardPortWithAdb(port, m_device_id);
69     if (error.Fail ())
70         return 0;
71 
72     m_port_forwards[pid] = port;
73 
74     return port;
75 }
76 
77 bool
78 PlatformAndroidRemoteGDBServer::KillSpawnedProcess (lldb::pid_t pid)
79 {
80     DeleteForwardPort (pid);
81     return m_gdb_client.KillSpawnedProcess (pid);
82 }
83 
84 Error
85 PlatformAndroidRemoteGDBServer::ConnectRemote (Args& args)
86 {
87     m_device_id.clear();
88 
89     if (args.GetArgumentCount() != 1)
90         return Error("\"platform connect\" takes a single argument: <connect-url>");
91 
92     int port;
93     std::string scheme, host, path;
94     const char *url = args.GetArgumentAtIndex (0);
95     if (!url)
96         return Error("URL is null.");
97     if (!UriParser::Parse (url, scheme, host, port, path))
98         return Error("Invalid URL: %s", url);
99     if (scheme == "adb")
100         m_device_id = host;
101 
102     Error error = ForwardPortWithAdb(port, m_device_id);
103     if (error.Fail())
104         return error;
105 
106     m_port_forwards[g_remote_platform_pid] = port;
107 
108     error = PlatformRemoteGDBServer::ConnectRemote(args);
109     if (error.Fail ())
110         DeleteForwardPort (g_remote_platform_pid);
111 
112     return error;
113 }
114 
115 Error
116 PlatformAndroidRemoteGDBServer::DisconnectRemote ()
117 {
118     DeleteForwardPort (g_remote_platform_pid);
119     return PlatformRemoteGDBServer::DisconnectRemote ();
120 }
121 
122 void
123 PlatformAndroidRemoteGDBServer::DeleteForwardPort (lldb::pid_t pid)
124 {
125     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
126 
127     auto it = m_port_forwards.find(pid);
128     if (it == m_port_forwards.end())
129         return;
130 
131     const auto port = it->second;
132     const auto error = DeleteForwardPortWithAdb(port, m_device_id);
133     if (error.Fail()) {
134         if (log)
135             log->Printf("Failed to delete port forwarding (pid=%" PRIu64 ", port=%d, device=%s): %s",
136                          pid, port, m_device_id.c_str(), error.AsCString());
137     }
138     m_port_forwards.erase(it);
139 }
140 
141 std::string
142 PlatformAndroidRemoteGDBServer::MakeServerUrl(const char* scheme,
143                                               const char* hostname,
144                                               uint16_t port)
145 {
146     std::ostringstream hostname_str;
147     if (!strcmp(scheme, "adb"))
148         hostname_str << "[" << hostname << "]";
149     else
150         hostname_str << hostname;
151 
152     return PlatformRemoteGDBServer::MakeServerUrl(scheme,
153                                                   hostname_str.str().c_str(),
154                                                   port);
155 }
156