LLDB  mainline
PlatformAndroidRemoteGDBServer.cpp
Go to the documentation of this file.
1 //===-- PlatformAndroidRemoteGDBServer.cpp --------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
11 #include "lldb/Utility/Log.h"
12 #include "lldb/Utility/Status.h"
13 #include "lldb/Utility/UriParser.h"
14 
16 
17 #include <sstream>
18 
19 using namespace lldb;
20 using namespace lldb_private;
21 using namespace platform_android;
22 
24  0; // Alias for the process id of lldb-platform
25 
27  const uint16_t local_port, const uint16_t remote_port,
28  llvm::StringRef remote_socket_name,
29  const llvm::Optional<AdbClient::UnixSocketNamespace> &socket_namespace,
30  std::string &device_id) {
32 
33  AdbClient adb;
34  auto error = AdbClient::CreateByDeviceID(device_id, adb);
35  if (error.Fail())
36  return error;
37 
38  device_id = adb.GetDeviceID();
39  LLDB_LOGF(log, "Connected to Android device \"%s\"", device_id.c_str());
40 
41  if (remote_port != 0) {
42  LLDB_LOGF(log, "Forwarding remote TCP port %d to local TCP port %d",
43  remote_port, local_port);
44  return adb.SetPortForwarding(local_port, remote_port);
45  }
46 
47  LLDB_LOGF(log, "Forwarding remote socket \"%s\" to local TCP port %d",
48  remote_socket_name.str().c_str(), local_port);
49 
50  if (!socket_namespace)
51  return Status("Invalid socket namespace");
52 
53  return adb.SetPortForwarding(local_port, remote_socket_name,
54  *socket_namespace);
55 }
56 
58  const std::string &device_id) {
59  AdbClient adb(device_id);
60  return adb.DeletePortForwarding(local_port);
61 }
62 
64  Status error;
65  std::unique_ptr<TCPSocket> tcp_socket(new TCPSocket(true, false));
66  if (error.Fail())
67  return error;
68 
69  error = tcp_socket->Listen("127.0.0.1:0", 1);
70  if (error.Success())
71  port = tcp_socket->GetLocalPortNumber();
72 
73  return error;
74 }
75 
76 PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer() = default;
77 
78 PlatformAndroidRemoteGDBServer::~PlatformAndroidRemoteGDBServer() {
79  for (const auto &it : m_port_forwards)
80  DeleteForwardPortWithAdb(it.second, m_device_id);
81 }
82 
83 bool PlatformAndroidRemoteGDBServer::LaunchGDBServer(lldb::pid_t &pid,
84  std::string &connect_url) {
85  uint16_t remote_port = 0;
86  std::string socket_name;
87  if (!m_gdb_client.LaunchGDBServer("127.0.0.1", pid, remote_port, socket_name))
88  return false;
89 
91 
92  auto error =
93  MakeConnectURL(pid, remote_port, socket_name.c_str(), connect_url);
94  if (error.Success() && log)
95  LLDB_LOGF(log, "gdbserver connect URL: %s", connect_url.c_str());
96 
97  return error.Success();
98 }
99 
100 bool PlatformAndroidRemoteGDBServer::KillSpawnedProcess(lldb::pid_t pid) {
101  DeleteForwardPort(pid);
102  return m_gdb_client.KillSpawnedProcess(pid);
103 }
104 
105 Status PlatformAndroidRemoteGDBServer::ConnectRemote(Args &args) {
106  m_device_id.clear();
107 
108  if (args.GetArgumentCount() != 1)
109  return Status(
110  "\"platform connect\" takes a single argument: <connect-url>");
111 
112  int remote_port;
113  llvm::StringRef scheme, host, path;
114  const char *url = args.GetArgumentAtIndex(0);
115  if (!url)
116  return Status("URL is null.");
117  if (!UriParser::Parse(url, scheme, host, remote_port, path))
118  return Status("Invalid URL: %s", url);
119  if (host != "localhost")
120  m_device_id = std::string(host);
121 
122  m_socket_namespace.reset();
123  if (scheme == ConnectionFileDescriptor::UNIX_CONNECT_SCHEME)
124  m_socket_namespace = AdbClient::UnixSocketNamespaceFileSystem;
125  else if (scheme == ConnectionFileDescriptor::UNIX_ABSTRACT_CONNECT_SCHEME)
126  m_socket_namespace = AdbClient::UnixSocketNamespaceAbstract;
127 
128  std::string connect_url;
129  auto error =
130  MakeConnectURL(g_remote_platform_pid, (remote_port < 0) ? 0 : remote_port,
131  path, connect_url);
132 
133  if (error.Fail())
134  return error;
135 
136  args.ReplaceArgumentAtIndex(0, connect_url);
137 
139  LLDB_LOGF(log, "Rewritten platform connect URL: %s", connect_url.c_str());
140 
141  error = PlatformRemoteGDBServer::ConnectRemote(args);
142  if (error.Fail())
143  DeleteForwardPort(g_remote_platform_pid);
144 
145  return error;
146 }
147 
148 Status PlatformAndroidRemoteGDBServer::DisconnectRemote() {
149  DeleteForwardPort(g_remote_platform_pid);
150  return PlatformRemoteGDBServer::DisconnectRemote();
151 }
152 
153 void PlatformAndroidRemoteGDBServer::DeleteForwardPort(lldb::pid_t pid) {
155 
156  auto it = m_port_forwards.find(pid);
157  if (it == m_port_forwards.end())
158  return;
159 
160  const auto port = it->second;
161  const auto error = DeleteForwardPortWithAdb(port, m_device_id);
162  if (error.Fail()) {
163  LLDB_LOGF(log,
164  "Failed to delete port forwarding (pid=%" PRIu64
165  ", port=%d, device=%s): %s",
166  pid, port, m_device_id.c_str(), error.AsCString());
167  }
168  m_port_forwards.erase(it);
169 }
170 
171 Status PlatformAndroidRemoteGDBServer::MakeConnectURL(
172  const lldb::pid_t pid, const uint16_t remote_port,
173  llvm::StringRef remote_socket_name, std::string &connect_url) {
174  static const int kAttempsNum = 5;
175 
176  Status error;
177  // There is a race possibility that somebody will occupy a port while we're
178  // in between FindUnusedPort and ForwardPortWithAdb - adding the loop to
179  // mitigate such problem.
180  for (auto i = 0; i < kAttempsNum; ++i) {
181  uint16_t local_port = 0;
182  error = FindUnusedPort(local_port);
183  if (error.Fail())
184  return error;
185 
186  error = ForwardPortWithAdb(local_port, remote_port, remote_socket_name,
187  m_socket_namespace, m_device_id);
188  if (error.Success()) {
189  m_port_forwards[pid] = local_port;
190  std::ostringstream url_str;
191  url_str << "connect://127.0.0.1:" << local_port;
192  connect_url = url_str.str();
193  break;
194  }
195  }
196 
197  return error;
198 }
199 
200 lldb::ProcessSP PlatformAndroidRemoteGDBServer::ConnectProcess(
201  llvm::StringRef connect_url, llvm::StringRef plugin_name,
202  lldb_private::Debugger &debugger, lldb_private::Target *target,
204  // We don't have the pid of the remote gdbserver when it isn't started by us
205  // but we still want to store the list of port forwards we set up in our port
206  // forward map. Generate a fake pid for these cases what won't collide with
207  // any other valid pid on android.
208  static lldb::pid_t s_remote_gdbserver_fake_pid = 0xffffffffffffffffULL;
209 
210  int remote_port;
211  llvm::StringRef scheme, host, path;
212  if (!UriParser::Parse(connect_url, scheme, host, remote_port, path)) {
213  error.SetErrorStringWithFormat("Invalid URL: %s",
214  connect_url.str().c_str());
215  return nullptr;
216  }
217 
218  std::string new_connect_url;
219  error = MakeConnectURL(s_remote_gdbserver_fake_pid--,
220  (remote_port < 0) ? 0 : remote_port, path,
221  new_connect_url);
222  if (error.Fail())
223  return nullptr;
224 
225  return PlatformRemoteGDBServer::ConnectProcess(new_connect_url, plugin_name,
226  debugger, target, error);
227 }
lldb_private::Args::ReplaceArgumentAtIndex
void ReplaceArgumentAtIndex(size_t idx, llvm::StringRef arg_str, char quote_char='\0')
Replaces the argument value at index idx to arg_str if idx is a valid argument index.
Definition: Args.cpp:333
LLDB_LOGF
#define LLDB_LOGF(log,...)
Definition: Log.h:249
DeleteForwardPortWithAdb
static Status DeleteForwardPortWithAdb(uint16_t local_port, const std::string &device_id)
Definition: PlatformAndroidRemoteGDBServer.cpp:57
LIBLLDB_LOG_PLATFORM
#define LIBLLDB_LOG_PLATFORM
Definition: Logging.h:39
lldb_private::Args
Definition: Args.h:33
lldb_private::Target
Definition: Target.h:454
error
static llvm::raw_ostream & error(Stream &strm)
Definition: CommandReturnObject.cpp:17
Log.h
lldb_private::platform_android::AdbClient::GetDeviceID
const std::string & GetDeviceID() const
Definition: AdbClient.cpp:131
FindUnusedPort
static Status FindUnusedPort(uint16_t &port)
Definition: PlatformAndroidRemoteGDBServer.cpp:63
lldb_private::GetLogIfAllCategoriesSet
Log * GetLogIfAllCategoriesSet(uint32_t mask)
Definition: Logging.cpp:58
ConnectionFileDescriptor.h
lldb_private::Debugger
Definition: Debugger.h:70
string
string(SUBSTRING ${p} 10 -1 pStripped) if($
Definition: Plugins/CMakeLists.txt:39
lldb_private::Status
Definition: Status.h:44
lldb_private::Args::GetArgumentAtIndex
const char * GetArgumentAtIndex(size_t idx) const
Gets the NULL terminated C string argument pointer for the argument at index idx.
Definition: Args.cpp:259
lldb_private::platform_android::AdbClient
Definition: AdbClient.h:26
PlatformAndroidRemoteGDBServer.h
lldb::pid_t
uint64_t pid_t
Definition: lldb-types.h:85
lldb_private::platform_android::AdbClient::SetPortForwarding
Status SetPortForwarding(const uint16_t local_port, const uint16_t remote_port)
Definition: AdbClient.cpp:173
uint16_t
TCPSocket.h
g_remote_platform_pid
static const lldb::pid_t g_remote_platform_pid
Definition: PlatformAndroidRemoteGDBServer.cpp:23
Status.h
lldb_private::TCPSocket
Definition: TCPSocket.h:17
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
lldb_private::platform_android::AdbClient::DeletePortForwarding
Status DeletePortForwarding(const uint16_t local_port)
Definition: AdbClient.cpp:205
lldb_private::Log
Definition: Log.h:49
UriParser.h
lldb_private::Args::GetArgumentCount
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition: Args.h:118
lldb
Definition: SBAddress.h:15
ForwardPortWithAdb
static Status ForwardPortWithAdb(const uint16_t local_port, const uint16_t remote_port, llvm::StringRef remote_socket_name, const llvm::Optional< AdbClient::UnixSocketNamespace > &socket_namespace, std::string &device_id)
Definition: PlatformAndroidRemoteGDBServer.cpp:26