1*00e305d2STamas Berghammer //===-- PlatformAndroidRemoteGDBServer.cpp ----------------------*- C++ -*-===//
2*00e305d2STamas Berghammer //
3*00e305d2STamas Berghammer //                     The LLVM Compiler Infrastructure
4*00e305d2STamas Berghammer //
5*00e305d2STamas Berghammer // This file is distributed under the University of Illinois Open Source
6*00e305d2STamas Berghammer // License. See LICENSE.TXT for details.
7*00e305d2STamas Berghammer //
8*00e305d2STamas Berghammer //===----------------------------------------------------------------------===//
9*00e305d2STamas Berghammer 
10*00e305d2STamas Berghammer // Other libraries and framework includes
11*00e305d2STamas Berghammer #include "lldb/Core/Error.h"
12*00e305d2STamas Berghammer #include "lldb/Host/ConnectionFileDescriptor.h"
13*00e305d2STamas Berghammer #include "llvm/ADT/StringRef.h"
14*00e305d2STamas Berghammer 
15*00e305d2STamas Berghammer // Project includes
16*00e305d2STamas Berghammer #include "PlatformAndroidRemoteGDBServer.h"
17*00e305d2STamas Berghammer #include "Utility/UriParser.h"
18*00e305d2STamas Berghammer 
19*00e305d2STamas Berghammer using namespace lldb;
20*00e305d2STamas Berghammer using namespace lldb_private;
21*00e305d2STamas Berghammer 
22*00e305d2STamas Berghammer static const lldb::pid_t g_remote_platform_pid = 0; // Alias for the process id of lldb-platform
23*00e305d2STamas Berghammer static const uint32_t g_adb_timeout = 10000; // 10 ms
24*00e305d2STamas Berghammer 
25*00e305d2STamas Berghammer static void
26*00e305d2STamas Berghammer SendMessageToAdb (Connection& conn, const std::string& packet, Error& error)
27*00e305d2STamas Berghammer {
28*00e305d2STamas Berghammer     ConnectionStatus status;
29*00e305d2STamas Berghammer 
30*00e305d2STamas Berghammer     char length_buffer[5];
31*00e305d2STamas Berghammer     snprintf (length_buffer, sizeof (length_buffer), "%04zx", packet.size());
32*00e305d2STamas Berghammer 
33*00e305d2STamas Berghammer     conn.Write (length_buffer, 4, status, &error);
34*00e305d2STamas Berghammer     if (error.Fail ())
35*00e305d2STamas Berghammer         return;
36*00e305d2STamas Berghammer 
37*00e305d2STamas Berghammer     conn.Write (packet.c_str(), packet.size(), status, &error);
38*00e305d2STamas Berghammer }
39*00e305d2STamas Berghammer 
40*00e305d2STamas Berghammer static std::string
41*00e305d2STamas Berghammer ReadMessageFromAdb (Connection& conn, bool has_okay, Error& error)
42*00e305d2STamas Berghammer {
43*00e305d2STamas Berghammer     ConnectionStatus status;
44*00e305d2STamas Berghammer 
45*00e305d2STamas Berghammer     char buffer[5];
46*00e305d2STamas Berghammer     buffer[4] = 0;
47*00e305d2STamas Berghammer 
48*00e305d2STamas Berghammer     if (has_okay)
49*00e305d2STamas Berghammer     {
50*00e305d2STamas Berghammer         conn.Read (buffer, 4, g_adb_timeout, status, &error);
51*00e305d2STamas Berghammer         if (error.Fail ())
52*00e305d2STamas Berghammer             return "";
53*00e305d2STamas Berghammer 
54*00e305d2STamas Berghammer         if (strncmp (buffer, "OKAY", 4) != 0)
55*00e305d2STamas Berghammer         {
56*00e305d2STamas Berghammer             error.SetErrorStringWithFormat ("\"OKAY\" expected from adb, received: \"%s\"", buffer);
57*00e305d2STamas Berghammer             return "";
58*00e305d2STamas Berghammer         }
59*00e305d2STamas Berghammer     }
60*00e305d2STamas Berghammer 
61*00e305d2STamas Berghammer     conn.Read (buffer, 4, g_adb_timeout, status, &error);
62*00e305d2STamas Berghammer     if (error.Fail())
63*00e305d2STamas Berghammer         return "";
64*00e305d2STamas Berghammer 
65*00e305d2STamas Berghammer     size_t packet_len = 0;
66*00e305d2STamas Berghammer     sscanf(buffer, "%zx", &packet_len);
67*00e305d2STamas Berghammer     std::string result(packet_len, 0);
68*00e305d2STamas Berghammer     conn.Read (&result[0], packet_len, g_adb_timeout, status, &error);
69*00e305d2STamas Berghammer     if (error.Fail ())
70*00e305d2STamas Berghammer         return "";
71*00e305d2STamas Berghammer 
72*00e305d2STamas Berghammer     return result;
73*00e305d2STamas Berghammer }
74*00e305d2STamas Berghammer 
75*00e305d2STamas Berghammer static Error
76*00e305d2STamas Berghammer ForwardPortWithAdb (uint16_t port, std::string& device_id)
77*00e305d2STamas Berghammer {
78*00e305d2STamas Berghammer     Error error;
79*00e305d2STamas Berghammer 
80*00e305d2STamas Berghammer     {
81*00e305d2STamas Berghammer         // Fetch the device list from ADB and if only 1 device found then use that device
82*00e305d2STamas Berghammer         // TODO: Handle the case when more device is available
83*00e305d2STamas Berghammer         std::unique_ptr<ConnectionFileDescriptor> conn (new ConnectionFileDescriptor ());
84*00e305d2STamas Berghammer         if (conn->Connect ("connect://localhost:5037", &error) != eConnectionStatusSuccess)
85*00e305d2STamas Berghammer             return error;
86*00e305d2STamas Berghammer 
87*00e305d2STamas Berghammer         SendMessageToAdb (*conn, "host:devices", error);
88*00e305d2STamas Berghammer         if (error.Fail ())
89*00e305d2STamas Berghammer             return error;
90*00e305d2STamas Berghammer         std::string in_buffer = ReadMessageFromAdb (*conn, true, error);
91*00e305d2STamas Berghammer 
92*00e305d2STamas Berghammer         llvm::StringRef deviceList(in_buffer);
93*00e305d2STamas Berghammer         std::pair<llvm::StringRef, llvm::StringRef> devices = deviceList.split ('\n');
94*00e305d2STamas Berghammer         if (devices.first.size () == 0 || devices.second.size () > 0)
95*00e305d2STamas Berghammer         {
96*00e305d2STamas Berghammer             error.SetErrorString ("Wrong number of devices returned from ADB");
97*00e305d2STamas Berghammer             return error;
98*00e305d2STamas Berghammer         }
99*00e305d2STamas Berghammer 
100*00e305d2STamas Berghammer         device_id = devices.first.split ('\t').first;
101*00e305d2STamas Berghammer     }
102*00e305d2STamas Berghammer 
103*00e305d2STamas Berghammer     {
104*00e305d2STamas Berghammer         // Forward the port to the (only) connected device
105*00e305d2STamas Berghammer         std::unique_ptr<ConnectionFileDescriptor> conn (new ConnectionFileDescriptor ());
106*00e305d2STamas Berghammer         if (conn->Connect ("connect://localhost:5037", &error) != eConnectionStatusSuccess)
107*00e305d2STamas Berghammer             return error;
108*00e305d2STamas Berghammer 
109*00e305d2STamas Berghammer         char port_buffer[32];
110*00e305d2STamas Berghammer         snprintf (port_buffer, sizeof (port_buffer), "tcp:%d;tcp:%d", port, port);
111*00e305d2STamas Berghammer 
112*00e305d2STamas Berghammer         std::string out_buffer = "host-serial:" + device_id + ":forward:" + port_buffer;
113*00e305d2STamas Berghammer         SendMessageToAdb (*conn, out_buffer, error);
114*00e305d2STamas Berghammer         if (error.Fail ())
115*00e305d2STamas Berghammer             return error;
116*00e305d2STamas Berghammer 
117*00e305d2STamas Berghammer         std::string in_buffer = ReadMessageFromAdb (*conn, false, error);
118*00e305d2STamas Berghammer         if (in_buffer != "OKAY")
119*00e305d2STamas Berghammer             error.SetErrorString (in_buffer.c_str ());
120*00e305d2STamas Berghammer     }
121*00e305d2STamas Berghammer 
122*00e305d2STamas Berghammer     return error;
123*00e305d2STamas Berghammer }
124*00e305d2STamas Berghammer 
125*00e305d2STamas Berghammer static Error
126*00e305d2STamas Berghammer DeleteForwardPortWithAdb (uint16_t port, const std::string& device_id)
127*00e305d2STamas Berghammer {
128*00e305d2STamas Berghammer     Error error;
129*00e305d2STamas Berghammer 
130*00e305d2STamas Berghammer     std::unique_ptr<ConnectionFileDescriptor> conn (new ConnectionFileDescriptor ());
131*00e305d2STamas Berghammer     if (conn->Connect ("connect://localhost:5037", &error) != eConnectionStatusSuccess)
132*00e305d2STamas Berghammer         return error;
133*00e305d2STamas Berghammer 
134*00e305d2STamas Berghammer     char port_buffer[16];
135*00e305d2STamas Berghammer     snprintf (port_buffer, sizeof (port_buffer), "tcp:%d", port);
136*00e305d2STamas Berghammer 
137*00e305d2STamas Berghammer     std::string out_buffer = "host-serial:" + device_id + ":killforward:" + port_buffer;
138*00e305d2STamas Berghammer     SendMessageToAdb (*conn, out_buffer, error);
139*00e305d2STamas Berghammer     if (error.Fail ())
140*00e305d2STamas Berghammer         return error;
141*00e305d2STamas Berghammer 
142*00e305d2STamas Berghammer     std::string in_buffer = ReadMessageFromAdb (*conn, true, error);
143*00e305d2STamas Berghammer     if (in_buffer != "OKAY")
144*00e305d2STamas Berghammer         error.SetErrorString (in_buffer.c_str ());
145*00e305d2STamas Berghammer 
146*00e305d2STamas Berghammer     return error;
147*00e305d2STamas Berghammer }
148*00e305d2STamas Berghammer 
149*00e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer ()
150*00e305d2STamas Berghammer {
151*00e305d2STamas Berghammer }
152*00e305d2STamas Berghammer 
153*00e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::~PlatformAndroidRemoteGDBServer ()
154*00e305d2STamas Berghammer {
155*00e305d2STamas Berghammer     for (const auto& it : m_port_forwards)
156*00e305d2STamas Berghammer     {
157*00e305d2STamas Berghammer         DeleteForwardPortWithAdb (it.second.first, it.second.second);
158*00e305d2STamas Berghammer     }
159*00e305d2STamas Berghammer }
160*00e305d2STamas Berghammer 
161*00e305d2STamas Berghammer uint16_t
162*00e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::LaunchGDBserverAndGetPort (lldb::pid_t &pid)
163*00e305d2STamas Berghammer {
164*00e305d2STamas Berghammer     uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort (pid, "127.0.0.1");
165*00e305d2STamas Berghammer     if (port == 0)
166*00e305d2STamas Berghammer         return port;
167*00e305d2STamas Berghammer 
168*00e305d2STamas Berghammer     std::string device_id;
169*00e305d2STamas Berghammer     Error error = ForwardPortWithAdb (port, device_id);
170*00e305d2STamas Berghammer     if (error.Fail ())
171*00e305d2STamas Berghammer         return 0;
172*00e305d2STamas Berghammer 
173*00e305d2STamas Berghammer     m_port_forwards[pid] = std::make_pair (port, device_id);
174*00e305d2STamas Berghammer 
175*00e305d2STamas Berghammer     return port;
176*00e305d2STamas Berghammer }
177*00e305d2STamas Berghammer 
178*00e305d2STamas Berghammer bool
179*00e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::KillSpawnedProcess (lldb::pid_t pid)
180*00e305d2STamas Berghammer {
181*00e305d2STamas Berghammer     auto it = m_port_forwards.find (pid);
182*00e305d2STamas Berghammer     if (it != m_port_forwards.end ())
183*00e305d2STamas Berghammer     {
184*00e305d2STamas Berghammer         DeleteForwardPortWithAdb (it->second.first, it->second.second);
185*00e305d2STamas Berghammer         m_port_forwards.erase (it);
186*00e305d2STamas Berghammer     }
187*00e305d2STamas Berghammer 
188*00e305d2STamas Berghammer     return m_gdb_client.KillSpawnedProcess (pid);
189*00e305d2STamas Berghammer }
190*00e305d2STamas Berghammer 
191*00e305d2STamas Berghammer Error
192*00e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::ConnectRemote (Args& args)
193*00e305d2STamas Berghammer {
194*00e305d2STamas Berghammer     if (args.GetArgumentCount () != 1)
195*00e305d2STamas Berghammer         return Error ("\"platform connect\" takes a single argument: <connect-url>");
196*00e305d2STamas Berghammer 
197*00e305d2STamas Berghammer     int port;
198*00e305d2STamas Berghammer     std::string scheme, host, path;
199*00e305d2STamas Berghammer     const char *url = args.GetArgumentAtIndex (0);
200*00e305d2STamas Berghammer     if (!UriParser::Parse (url, scheme, host, port, path))
201*00e305d2STamas Berghammer         return Error ("invalid uri");
202*00e305d2STamas Berghammer 
203*00e305d2STamas Berghammer     std::string device_id;
204*00e305d2STamas Berghammer     Error error = ForwardPortWithAdb (port, device_id);
205*00e305d2STamas Berghammer     if (error.Fail ())
206*00e305d2STamas Berghammer         return error;
207*00e305d2STamas Berghammer 
208*00e305d2STamas Berghammer     m_port_forwards[g_remote_platform_pid] = std::make_pair (port, device_id);
209*00e305d2STamas Berghammer 
210*00e305d2STamas Berghammer     return PlatformRemoteGDBServer::ConnectRemote (args);
211*00e305d2STamas Berghammer }
212*00e305d2STamas Berghammer 
213*00e305d2STamas Berghammer Error
214*00e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::DisconnectRemote ()
215*00e305d2STamas Berghammer {
216*00e305d2STamas Berghammer     auto it = m_port_forwards.find (g_remote_platform_pid);
217*00e305d2STamas Berghammer     if (it != m_port_forwards.end ())
218*00e305d2STamas Berghammer     {
219*00e305d2STamas Berghammer         DeleteForwardPortWithAdb (it->second.first, it->second.second);
220*00e305d2STamas Berghammer         m_port_forwards.erase (it);
221*00e305d2STamas Berghammer     }
222*00e305d2STamas Berghammer 
223*00e305d2STamas Berghammer     return PlatformRemoteGDBServer::DisconnectRemote ();
224*00e305d2STamas Berghammer }
225