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/LLDBLog.h"
12 #include "lldb/Utility/Log.h"
13 #include "lldb/Utility/Status.h"
14 #include "lldb/Utility/UriParser.h"
15 
17 
18 #include <optional>
19 #include <sstream>
20 
21 using namespace lldb;
22 using namespace lldb_private;
23 using namespace platform_android;
24 
26  0; // Alias for the process id of lldb-platform
27 
29  const uint16_t local_port, const uint16_t remote_port,
30  llvm::StringRef remote_socket_name,
31  const std::optional<AdbClient::UnixSocketNamespace> &socket_namespace,
32  std::string &device_id) {
33  Log *log = GetLog(LLDBLog::Platform);
34 
35  AdbClient adb;
36  auto error = AdbClient::CreateByDeviceID(device_id, adb);
37  if (error.Fail())
38  return error;
39 
40  device_id = adb.GetDeviceID();
41  LLDB_LOGF(log, "Connected to Android device \"%s\"", device_id.c_str());
42 
43  if (remote_port != 0) {
44  LLDB_LOGF(log, "Forwarding remote TCP port %d to local TCP port %d",
45  remote_port, local_port);
46  return adb.SetPortForwarding(local_port, remote_port);
47  }
48 
49  LLDB_LOGF(log, "Forwarding remote socket \"%s\" to local TCP port %d",
50  remote_socket_name.str().c_str(), local_port);
51 
52  if (!socket_namespace)
53  return Status("Invalid socket namespace");
54 
55  return adb.SetPortForwarding(local_port, remote_socket_name,
56  *socket_namespace);
57 }
58 
60  const std::string &device_id) {
61  AdbClient adb(device_id);
62  return adb.DeletePortForwarding(local_port);
63 }
64 
66  Status error;
67  std::unique_ptr<TCPSocket> tcp_socket(new TCPSocket(true, false));
68  if (error.Fail())
69  return error;
70 
71  error = tcp_socket->Listen("127.0.0.1:0", 1);
72  if (error.Success())
73  port = tcp_socket->GetLocalPortNumber();
74 
75  return error;
76 }
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  assert(IsConnected());
86  uint16_t remote_port = 0;
87  std::string socket_name;
88  if (!m_gdb_client_up->LaunchGDBServer("127.0.0.1", pid, remote_port,
89  socket_name))
90  return false;
91 
92  Log *log = GetLog(LLDBLog::Platform);
93 
94  uint16_t local_port = 0;
95  const char *gdbstub_port = std::getenv("ANDROID_PLATFORM_LOCAL_GDB_PORT");
96  if (gdbstub_port)
97  local_port = std::stoi(gdbstub_port);
98 
99  auto error = MakeConnectURL(pid, local_port, remote_port, socket_name.c_str(),
100  connect_url);
101  if (error.Success() && log)
102  LLDB_LOGF(log, "gdbserver connect URL: %s", connect_url.c_str());
103 
104  return error.Success();
105 }
106 
107 bool PlatformAndroidRemoteGDBServer::KillSpawnedProcess(lldb::pid_t pid) {
108  assert(IsConnected());
109  DeleteForwardPort(pid);
110  return m_gdb_client_up->KillSpawnedProcess(pid);
111 }
112 
113 Status PlatformAndroidRemoteGDBServer::ConnectRemote(Args &args) {
114  m_device_id.clear();
115 
116  if (args.GetArgumentCount() != 1)
117  return Status(
118  "\"platform connect\" takes a single argument: <connect-url>");
119 
120  const char *url = args.GetArgumentAtIndex(0);
121  if (!url)
122  return Status("URL is null.");
123  std::optional<URI> parsed_url = URI::Parse(url);
124  if (!parsed_url)
125  return Status("Invalid URL: %s", url);
126  if (parsed_url->hostname != "localhost")
127  m_device_id = parsed_url->hostname.str();
128 
129  m_socket_namespace.reset();
130  if (parsed_url->scheme == "unix-connect")
131  m_socket_namespace = AdbClient::UnixSocketNamespaceFileSystem;
132  else if (parsed_url->scheme == "unix-abstract-connect")
133  m_socket_namespace = AdbClient::UnixSocketNamespaceAbstract;
134 
135  uint16_t local_port = 0;
136  const char *platform_local_port = std::getenv("ANDROID_PLATFORM_LOCAL_PORT");
137  if (platform_local_port)
138  local_port = std::stoi(platform_local_port);
139 
140  std::string connect_url;
141  auto error = MakeConnectURL(g_remote_platform_pid, local_port,
142  parsed_url->port.value_or(0), parsed_url->path,
143  connect_url);
144 
145  if (error.Fail())
146  return error;
147 
148  args.ReplaceArgumentAtIndex(0, connect_url);
149 
150  Log *log = GetLog(LLDBLog::Platform);
151  LLDB_LOGF(log, "Rewritten platform connect URL: %s", connect_url.c_str());
152 
153  error = PlatformRemoteGDBServer::ConnectRemote(args);
154  if (error.Fail())
155  DeleteForwardPort(g_remote_platform_pid);
156 
157  return error;
158 }
159 
160 Status PlatformAndroidRemoteGDBServer::DisconnectRemote() {
161  DeleteForwardPort(g_remote_platform_pid);
162  return PlatformRemoteGDBServer::DisconnectRemote();
163 }
164 
165 void PlatformAndroidRemoteGDBServer::DeleteForwardPort(lldb::pid_t pid) {
166  Log *log = GetLog(LLDBLog::Platform);
167 
168  auto it = m_port_forwards.find(pid);
169  if (it == m_port_forwards.end())
170  return;
171 
172  const auto port = it->second;
173  const auto error = DeleteForwardPortWithAdb(port, m_device_id);
174  if (error.Fail()) {
175  LLDB_LOGF(log,
176  "Failed to delete port forwarding (pid=%" PRIu64
177  ", port=%d, device=%s): %s",
178  pid, port, m_device_id.c_str(), error.AsCString());
179  }
180  m_port_forwards.erase(it);
181 }
182 
183 Status PlatformAndroidRemoteGDBServer::MakeConnectURL(
184  const lldb::pid_t pid, const uint16_t local_port,
185  const uint16_t remote_port, llvm::StringRef remote_socket_name,
186  std::string &connect_url) {
187  static const int kAttempsNum = 5;
188 
189  Status error;
190 
191  auto forward = [&](const uint16_t local, const uint16_t remote) {
192  error = ForwardPortWithAdb(local, remote, remote_socket_name,
193  m_socket_namespace, m_device_id);
194  if (error.Success()) {
195  m_port_forwards[pid] = local;
196  std::ostringstream url_str;
197  url_str << "connect://127.0.0.1:" << local;
198  connect_url = url_str.str();
199  }
200  return error;
201  };
202 
203  if (local_port != 0)
204  return forward(local_port, remote_port);
205 
206  // There is a race possibility that somebody will occupy a port while we're
207  // in between FindUnusedPort and ForwardPortWithAdb - adding the loop to
208  // mitigate such problem.
209  for (auto i = 0; i < kAttempsNum; ++i) {
210  uint16_t local_port = 0;
211  error = FindUnusedPort(local_port);
212  if (error.Fail())
213  return error;
214 
215  if (forward(local_port, remote_port).Success())
216  break;
217  }
218 
219  return error;
220 }
221 
222 lldb::ProcessSP PlatformAndroidRemoteGDBServer::ConnectProcess(
223  llvm::StringRef connect_url, llvm::StringRef plugin_name,
224  lldb_private::Debugger &debugger, lldb_private::Target *target,
226  // We don't have the pid of the remote gdbserver when it isn't started by us
227  // but we still want to store the list of port forwards we set up in our port
228  // forward map. Generate a fake pid for these cases what won't collide with
229  // any other valid pid on android.
230  static lldb::pid_t s_remote_gdbserver_fake_pid = 0xffffffffffffffffULL;
231 
232  std::optional<URI> parsed_url = URI::Parse(connect_url);
233  if (!parsed_url) {
234  error.SetErrorStringWithFormat("Invalid URL: %s",
235  connect_url.str().c_str());
236  return nullptr;
237  }
238 
239  std::string new_connect_url;
240  error = MakeConnectURL(s_remote_gdbserver_fake_pid--, 0,
241  parsed_url->port.value_or(0), parsed_url->path,
242  new_connect_url);
243  if (error.Fail())
244  return nullptr;
245 
246  return PlatformRemoteGDBServer::ConnectProcess(new_connect_url, plugin_name,
247  debugger, target, error);
248 }
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:338
LLDB_LOGF
#define LLDB_LOGF(log,...)
Definition: Log.h:344
DeleteForwardPortWithAdb
static Status DeleteForwardPortWithAdb(uint16_t local_port, const std::string &device_id)
Definition: PlatformAndroidRemoteGDBServer.cpp:59
lldb_private::Args
Definition: Args.h:33
lldb_private::Target
Definition: Target.h:469
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:127
FindUnusedPort
static Status FindUnusedPort(uint16_t &port)
Definition: PlatformAndroidRemoteGDBServer.cpp:65
ConnectionFileDescriptor.h
lldb_private::Debugger
Definition: Debugger.h:75
string
string(SUBSTRING ${p} 10 -1 pStripped) if($
Definition: Plugins/CMakeLists.txt:40
ForwardPortWithAdb
static Status ForwardPortWithAdb(const uint16_t local_port, const uint16_t remote_port, llvm::StringRef remote_socket_name, const std::optional< AdbClient::UnixSocketNamespace > &socket_namespace, std::string &device_id)
Definition: PlatformAndroidRemoteGDBServer.cpp:28
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:264
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:169
uint16_t
TCPSocket.h
g_remote_platform_pid
static const lldb::pid_t g_remote_platform_pid
Definition: PlatformAndroidRemoteGDBServer.cpp:25
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::LineStatus::Success
@ Success
lldb_private::platform_android::AdbClient::DeletePortForwarding
Status DeletePortForwarding(const uint16_t local_port)
Definition: AdbClient.cpp:201
lldb_private::Log
Definition: Log.h:115
UriParser.h
lldb_private::GetLog
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:309
lldb_private::Args::GetArgumentCount
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition: Args.h:116
lldb
Definition: SBAddress.h:15
LLDBLog.h