Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp
Line
Count
Source (jump to first uncovered line)
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
9
#include "lldb/Host/ConnectionFileDescriptor.h"
10
#include "lldb/Host/common/TCPSocket.h"
11
#include "lldb/Utility/Log.h"
12
#include "lldb/Utility/Status.h"
13
#include "lldb/Utility/UriParser.h"
14
15
#include "PlatformAndroidRemoteGDBServer.h"
16
17
#include <sstream>
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 =
24
    0; // Alias for the process id of lldb-platform
25
26
static Status ForwardPortWithAdb(
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
0
    std::string &device_id) {
31
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
32
33
0
  AdbClient adb;
34
0
  auto error = AdbClient::CreateByDeviceID(device_id, adb);
35
0
  if (error.Fail())
36
0
    return error;
37
38
0
  device_id = adb.GetDeviceID();
39
0
  LLDB_LOGF(log, "Connected to Android device \"%s\"", device_id.c_str());
40
41
0
  if (remote_port != 0) {
42
0
    LLDB_LOGF(log, "Forwarding remote TCP port %d to local TCP port %d",
43
0
              remote_port, local_port);
44
0
    return adb.SetPortForwarding(local_port, remote_port);
45
0
  }
46
47
0
  LLDB_LOGF(log, "Forwarding remote socket \"%s\" to local TCP port %d",
48
0
            remote_socket_name.str().c_str(), local_port);
49
50
0
  if (!socket_namespace)
51
0
    return Status("Invalid socket namespace");
52
53
0
  return adb.SetPortForwarding(local_port, remote_socket_name,
54
0
                               *socket_namespace);
55
0
}
56
57
static Status DeleteForwardPortWithAdb(uint16_t local_port,
58
0
                                       const std::string &device_id) {
59
0
  AdbClient adb(device_id);
60
0
  return adb.DeletePortForwarding(local_port);
61
0
}
62
63
0
static Status FindUnusedPort(uint16_t &port) {
64
0
  Status error;
65
0
  std::unique_ptr<TCPSocket> tcp_socket(new TCPSocket(true, false));
66
0
  if (error.Fail())
67
0
    return error;
68
69
0
  error = tcp_socket->Listen("127.0.0.1:0", 1);
70
0
  if (error.Success())
71
0
    port = tcp_socket->GetLocalPortNumber();
72
73
0
  return error;
74
0
}
75
76
0
PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer() = default;
77
78
0
PlatformAndroidRemoteGDBServer::~PlatformAndroidRemoteGDBServer() {
79
0
  for (const auto &it : m_port_forwards)
80
0
    DeleteForwardPortWithAdb(it.second, m_device_id);
81
0
}
82
83
bool PlatformAndroidRemoteGDBServer::LaunchGDBServer(lldb::pid_t &pid,
84
0
                                                     std::string &connect_url) {
85
0
  assert(IsConnected());
86
0
  uint16_t remote_port = 0;
87
0
  std::string socket_name;
88
0
  if (!m_gdb_client_up->LaunchGDBServer("127.0.0.1", pid, remote_port,
89
0
                                        socket_name))
90
0
    return false;
91
92
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
93
94
0
  auto error =
95
0
      MakeConnectURL(pid, remote_port, socket_name.c_str(), connect_url);
96
0
  if (error.Success() && log)
97
0
    LLDB_LOGF(log, "gdbserver connect URL: %s", connect_url.c_str());
98
99
0
  return error.Success();
100
0
}
101
102
0
bool PlatformAndroidRemoteGDBServer::KillSpawnedProcess(lldb::pid_t pid) {
103
0
  assert(IsConnected());
104
0
  DeleteForwardPort(pid);
105
0
  return m_gdb_client_up->KillSpawnedProcess(pid);
106
0
}
107
108
0
Status PlatformAndroidRemoteGDBServer::ConnectRemote(Args &args) {
109
0
  m_device_id.clear();
110
111
0
  if (args.GetArgumentCount() != 1)
112
0
    return Status(
113
0
        "\"platform connect\" takes a single argument: <connect-url>");
114
115
0
  const char *url = args.GetArgumentAtIndex(0);
116
0
  if (!url)
117
0
    return Status("URL is null.");
118
0
  llvm::Optional<URI> parsed_url = URI::Parse(url);
119
0
  if (!parsed_url)
120
0
    return Status("Invalid URL: %s", url);
121
0
  if (parsed_url->hostname != "localhost")
122
0
    m_device_id = parsed_url->hostname.str();
123
124
0
  m_socket_namespace.reset();
125
0
  if (parsed_url->scheme == "unix-connect")
126
0
    m_socket_namespace = AdbClient::UnixSocketNamespaceFileSystem;
127
0
  else if (parsed_url->scheme == "unix-abstract-connect")
128
0
    m_socket_namespace = AdbClient::UnixSocketNamespaceAbstract;
129
130
0
  std::string connect_url;
131
0
  auto error =
132
0
      MakeConnectURL(g_remote_platform_pid, parsed_url->port.getValueOr(0),
133
0
                     parsed_url->path, connect_url);
134
135
0
  if (error.Fail())
136
0
    return error;
137
138
0
  args.ReplaceArgumentAtIndex(0, connect_url);
139
140
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
141
0
  LLDB_LOGF(log, "Rewritten platform connect URL: %s", connect_url.c_str());
142
143
0
  error = PlatformRemoteGDBServer::ConnectRemote(args);
144
0
  if (error.Fail())
145
0
    DeleteForwardPort(g_remote_platform_pid);
146
147
0
  return error;
148
0
}
149
150
0
Status PlatformAndroidRemoteGDBServer::DisconnectRemote() {
151
0
  DeleteForwardPort(g_remote_platform_pid);
152
0
  return PlatformRemoteGDBServer::DisconnectRemote();
153
0
}
154
155
0
void PlatformAndroidRemoteGDBServer::DeleteForwardPort(lldb::pid_t pid) {
156
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
157
158
0
  auto it = m_port_forwards.find(pid);
159
0
  if (it == m_port_forwards.end())
160
0
    return;
161
162
0
  const auto port = it->second;
163
0
  const auto error = DeleteForwardPortWithAdb(port, m_device_id);
164
0
  if (error.Fail()) {
165
0
    LLDB_LOGF(log,
166
0
              "Failed to delete port forwarding (pid=%" PRIu64
167
0
              ", port=%d, device=%s): %s",
168
0
              pid, port, m_device_id.c_str(), error.AsCString());
169
0
  }
170
0
  m_port_forwards.erase(it);
171
0
}
172
173
Status PlatformAndroidRemoteGDBServer::MakeConnectURL(
174
    const lldb::pid_t pid, const uint16_t remote_port,
175
0
    llvm::StringRef remote_socket_name, std::string &connect_url) {
176
0
  static const int kAttempsNum = 5;
177
178
0
  Status error;
179
  // There is a race possibility that somebody will occupy a port while we're
180
  // in between FindUnusedPort and ForwardPortWithAdb - adding the loop to
181
  // mitigate such problem.
182
0
  for (auto i = 0; i < kAttempsNum; ++i) {
183
0
    uint16_t local_port = 0;
184
0
    error = FindUnusedPort(local_port);
185
0
    if (error.Fail())
186
0
      return error;
187
188
0
    error = ForwardPortWithAdb(local_port, remote_port, remote_socket_name,
189
0
                               m_socket_namespace, m_device_id);
190
0
    if (error.Success()) {
191
0
      m_port_forwards[pid] = local_port;
192
0
      std::ostringstream url_str;
193
0
      url_str << "connect://127.0.0.1:" << local_port;
194
0
      connect_url = url_str.str();
195
0
      break;
196
0
    }
197
0
  }
198
199
0
  return error;
200
0
}
201
202
lldb::ProcessSP PlatformAndroidRemoteGDBServer::ConnectProcess(
203
    llvm::StringRef connect_url, llvm::StringRef plugin_name,
204
    lldb_private::Debugger &debugger, lldb_private::Target *target,
205
0
    lldb_private::Status &error) {
206
  // We don't have the pid of the remote gdbserver when it isn't started by us
207
  // but we still want to store the list of port forwards we set up in our port
208
  // forward map. Generate a fake pid for these cases what won't collide with
209
  // any other valid pid on android.
210
0
  static lldb::pid_t s_remote_gdbserver_fake_pid = 0xffffffffffffffffULL;
211
212
0
  llvm::Optional<URI> parsed_url = URI::Parse(connect_url);
213
0
  if (!parsed_url) {
214
0
    error.SetErrorStringWithFormat("Invalid URL: %s",
215
0
                                   connect_url.str().c_str());
216
0
    return nullptr;
217
0
  }
218
219
0
  std::string new_connect_url;
220
0
  error = MakeConnectURL(s_remote_gdbserver_fake_pid--,
221
0
                         parsed_url->port.getValueOr(0), parsed_url->path,
222
0
                         new_connect_url);
223
0
  if (error.Fail())
224
0
    return nullptr;
225
226
0
  return PlatformRemoteGDBServer::ConnectProcess(new_connect_url, plugin_name,
227
0
                                                 debugger, target, error);
228
0
}