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