Coverage Report

Created: 2023-09-30 09:22

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- PlatformRemoteGDBServer.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 "PlatformRemoteGDBServer.h"
10
#include "lldb/Host/Config.h"
11
12
#include "lldb/Breakpoint/BreakpointLocation.h"
13
#include "lldb/Core/Debugger.h"
14
#include "lldb/Core/Module.h"
15
#include "lldb/Core/ModuleList.h"
16
#include "lldb/Core/ModuleSpec.h"
17
#include "lldb/Core/PluginManager.h"
18
#include "lldb/Host/ConnectionFileDescriptor.h"
19
#include "lldb/Host/Host.h"
20
#include "lldb/Host/HostInfo.h"
21
#include "lldb/Host/PosixApi.h"
22
#include "lldb/Target/Process.h"
23
#include "lldb/Target/Target.h"
24
#include "lldb/Utility/FileSpec.h"
25
#include "lldb/Utility/LLDBLog.h"
26
#include "lldb/Utility/Log.h"
27
#include "lldb/Utility/ProcessInfo.h"
28
#include "lldb/Utility/Status.h"
29
#include "lldb/Utility/StreamString.h"
30
#include "lldb/Utility/UriParser.h"
31
#include "llvm/ADT/StringSet.h"
32
#include "llvm/Support/FormatAdapters.h"
33
34
#include "Plugins/Process/Utility/GDBRemoteSignals.h"
35
#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
36
#include <mutex>
37
#include <optional>
38
39
using namespace lldb;
40
using namespace lldb_private;
41
using namespace lldb_private::platform_gdb_server;
42
43
LLDB_PLUGIN_DEFINE_ADV(PlatformRemoteGDBServer, PlatformGDB)
44
45
static bool g_initialized = false;
46
// UnixSignals does not store the signal names or descriptions itself.
47
// It holds onto StringRefs. Becaue we may get signal information dynamically
48
// from the remote, these strings need persistent storage client-side.
49
static std::mutex g_signal_string_mutex;
50
static llvm::StringSet<> g_signal_string_storage;
51
52
3.92k
void PlatformRemoteGDBServer::Initialize() {
53
3.92k
  Platform::Initialize();
54
55
3.92k
  if (!g_initialized) {
56
3.92k
    g_initialized = true;
57
3.92k
    PluginManager::RegisterPlugin(
58
3.92k
        PlatformRemoteGDBServer::GetPluginNameStatic(),
59
3.92k
        PlatformRemoteGDBServer::GetDescriptionStatic(),
60
3.92k
        PlatformRemoteGDBServer::CreateInstance);
61
3.92k
  }
62
3.92k
}
63
64
3.92k
void PlatformRemoteGDBServer::Terminate() {
65
3.92k
  if (g_initialized) {
66
3.92k
    g_initialized = false;
67
3.92k
    PluginManager::UnregisterPlugin(PlatformRemoteGDBServer::CreateInstance);
68
3.92k
  }
69
70
3.92k
  Platform::Terminate();
71
3.92k
}
72
73
PlatformSP PlatformRemoteGDBServer::CreateInstance(bool force,
74
256
                                                   const ArchSpec *arch) {
75
256
  bool create = force;
76
256
  if (!create) {
77
231
    create = !arch->TripleVendorWasSpecified() && 
!arch->TripleOSWasSpecified()40
;
78
231
  }
79
256
  if (create)
80
49
    return PlatformSP(new PlatformRemoteGDBServer());
81
207
  return PlatformSP();
82
256
}
83
84
3.92k
llvm::StringRef PlatformRemoteGDBServer::GetDescriptionStatic() {
85
3.92k
  return "A platform that uses the GDB remote protocol as the communication "
86
3.92k
         "transport.";
87
3.92k
}
88
89
0
llvm::StringRef PlatformRemoteGDBServer::GetDescription() {
90
0
  if (m_platform_description.empty()) {
91
0
    if (IsConnected()) {
92
      // Send the get description packet
93
0
    }
94
0
  }
95
96
0
  if (!m_platform_description.empty())
97
0
    return m_platform_description.c_str();
98
0
  return GetDescriptionStatic();
99
0
}
100
101
bool PlatformRemoteGDBServer::GetModuleSpec(const FileSpec &module_file_spec,
102
                                            const ArchSpec &arch,
103
0
                                            ModuleSpec &module_spec) {
104
0
  Log *log = GetLog(LLDBLog::Platform);
105
106
0
  const auto module_path = module_file_spec.GetPath(false);
107
108
0
  if (!m_gdb_client_up ||
109
0
      !m_gdb_client_up->GetModuleInfo(module_file_spec, arch, module_spec)) {
110
0
    LLDB_LOGF(
111
0
        log,
112
0
        "PlatformRemoteGDBServer::%s - failed to get module info for %s:%s",
113
0
        __FUNCTION__, module_path.c_str(),
114
0
        arch.GetTriple().getTriple().c_str());
115
0
    return false;
116
0
  }
117
118
0
  if (log) {
119
0
    StreamString stream;
120
0
    module_spec.Dump(stream);
121
0
    LLDB_LOGF(log,
122
0
              "PlatformRemoteGDBServer::%s - got module info for (%s:%s) : %s",
123
0
              __FUNCTION__, module_path.c_str(),
124
0
              arch.GetTriple().getTriple().c_str(), stream.GetData());
125
0
  }
126
127
0
  return true;
128
0
}
129
130
Status PlatformRemoteGDBServer::GetFileWithUUID(const FileSpec &platform_file,
131
                                                const UUID *uuid_ptr,
132
41
                                                FileSpec &local_file) {
133
  // Default to the local case
134
41
  local_file = platform_file;
135
41
  return Status();
136
41
}
137
138
/// Default Constructor
139
PlatformRemoteGDBServer::PlatformRemoteGDBServer()
140
56
    : Platform(/*is_host=*/false) {}
141
142
/// Destructor.
143
///
144
/// The destructor is virtual since this class is designed to be
145
/// inherited from by the plug-in instance.
146
56
PlatformRemoteGDBServer::~PlatformRemoteGDBServer() = default;
147
148
size_t PlatformRemoteGDBServer::GetSoftwareBreakpointTrapOpcode(
149
0
    Target &target, BreakpointSite *bp_site) {
150
  // This isn't needed if the z/Z packets are supported in the GDB remote
151
  // server. But we might need a packet to detect this.
152
0
  return 0;
153
0
}
154
155
13
bool PlatformRemoteGDBServer::GetRemoteOSVersion() {
156
13
  if (m_gdb_client_up)
157
13
    m_os_version = m_gdb_client_up->GetOSVersion();
158
13
  return !m_os_version.empty();
159
13
}
160
161
41
std::optional<std::string> PlatformRemoteGDBServer::GetRemoteOSBuildString() {
162
41
  if (!m_gdb_client_up)
163
0
    return std::nullopt;
164
41
  return m_gdb_client_up->GetOSBuildString();
165
41
}
166
167
std::optional<std::string>
168
13
PlatformRemoteGDBServer::GetRemoteOSKernelDescription() {
169
13
  if (!m_gdb_client_up)
170
0
    return std::nullopt;
171
13
  return m_gdb_client_up->GetOSKernelDescription();
172
13
}
173
174
// Remote Platform subclasses need to override this function
175
16
ArchSpec PlatformRemoteGDBServer::GetRemoteSystemArchitecture() {
176
16
  if (!m_gdb_client_up)
177
0
    return ArchSpec();
178
16
  return m_gdb_client_up->GetSystemArchitecture();
179
16
}
180
181
31
FileSpec PlatformRemoteGDBServer::GetRemoteWorkingDirectory() {
182
31
  if (IsConnected()) {
183
14
    Log *log = GetLog(LLDBLog::Platform);
184
14
    FileSpec working_dir;
185
14
    if (m_gdb_client_up->GetWorkingDir(working_dir) && 
log13
)
186
0
      LLDB_LOGF(log,
187
14
                "PlatformRemoteGDBServer::GetRemoteWorkingDirectory() -> '%s'",
188
14
                working_dir.GetPath().c_str());
189
14
    return working_dir;
190
17
  } else {
191
17
    return Platform::GetRemoteWorkingDirectory();
192
17
  }
193
31
}
194
195
bool PlatformRemoteGDBServer::SetRemoteWorkingDirectory(
196
1
    const FileSpec &working_dir) {
197
1
  if (IsConnected()) {
198
    // Clear the working directory it case it doesn't get set correctly. This
199
    // will for use to re-read it
200
1
    Log *log = GetLog(LLDBLog::Platform);
201
1
    LLDB_LOGF(log, "PlatformRemoteGDBServer::SetRemoteWorkingDirectory('%s')",
202
1
              working_dir.GetPath().c_str());
203
1
    return m_gdb_client_up->SetWorkingDir(working_dir) == 0;
204
1
  } else
205
0
    return Platform::SetRemoteWorkingDirectory(working_dir);
206
1
}
207
208
273
bool PlatformRemoteGDBServer::IsConnected() const {
209
273
  if (m_gdb_client_up) {
210
172
    assert(m_gdb_client_up->IsConnected());
211
172
    return true;
212
172
  }
213
101
  return false;
214
273
}
215
216
16
Status PlatformRemoteGDBServer::ConnectRemote(Args &args) {
217
16
  Status error;
218
16
  if (IsConnected()) {
219
0
    error.SetErrorStringWithFormat("the platform is already connected to '%s', "
220
0
                                   "execute 'platform disconnect' to close the "
221
0
                                   "current connection",
222
0
                                   GetHostname());
223
0
    return error;
224
0
  }
225
226
16
  if (args.GetArgumentCount() != 1) {
227
0
    error.SetErrorString(
228
0
        "\"platform connect\" takes a single argument: <connect-url>");
229
0
    return error;
230
0
  }
231
232
16
  const char *url = args.GetArgumentAtIndex(0);
233
16
  if (!url)
234
0
    return Status("URL is null.");
235
236
16
  std::optional<URI> parsed_url = URI::Parse(url);
237
16
  if (!parsed_url)
238
0
    return Status("Invalid URL: %s", url);
239
240
  // We're going to reuse the hostname when we connect to the debugserver.
241
16
  m_platform_scheme = parsed_url->scheme.str();
242
16
  m_platform_hostname = parsed_url->hostname.str();
243
244
16
  auto client_up =
245
16
      std::make_unique<process_gdb_remote::GDBRemoteCommunicationClient>();
246
16
  client_up->SetPacketTimeout(
247
16
      process_gdb_remote::ProcessGDBRemote::GetPacketTimeout());
248
16
  client_up->SetConnection(std::make_unique<ConnectionFileDescriptor>());
249
16
  client_up->Connect(url, &error);
250
251
16
  if (error.Fail())
252
0
    return error;
253
254
16
  if (client_up->HandshakeWithServer(&error)) {
255
16
    m_gdb_client_up = std::move(client_up);
256
16
    m_gdb_client_up->GetHostInfo();
257
    // If a working directory was set prior to connecting, send it down
258
    // now.
259
16
    if (m_working_dir)
260
1
      m_gdb_client_up->SetWorkingDir(m_working_dir);
261
262
16
    m_supported_architectures.clear();
263
16
    ArchSpec remote_arch = m_gdb_client_up->GetSystemArchitecture();
264
16
    if (remote_arch) {
265
1
      m_supported_architectures.push_back(remote_arch);
266
1
      if (remote_arch.GetTriple().isArch64Bit())
267
1
        m_supported_architectures.push_back(
268
1
            ArchSpec(remote_arch.GetTriple().get32BitArchVariant()));
269
1
    }
270
16
  } else {
271
0
    client_up->Disconnect();
272
0
    if (error.Success())
273
0
      error.SetErrorString("handshake failed");
274
0
  }
275
16
  return error;
276
16
}
277
278
16
Status PlatformRemoteGDBServer::DisconnectRemote() {
279
16
  Status error;
280
16
  m_gdb_client_up.reset();
281
16
  m_remote_signals_sp.reset();
282
16
  return error;
283
16
}
284
285
14
const char *PlatformRemoteGDBServer::GetHostname() {
286
14
  if (m_gdb_client_up)
287
14
    m_gdb_client_up->GetHostname(m_hostname);
288
14
  if (m_hostname.empty())
289
14
    return nullptr;
290
0
  return m_hostname.c_str();
291
14
}
292
293
std::optional<std::string>
294
4
PlatformRemoteGDBServer::DoGetUserName(UserIDResolver::id_t uid) {
295
4
  std::string name;
296
4
  if (m_gdb_client_up && m_gdb_client_up->GetUserName(uid, name))
297
0
    return std::move(name);
298
4
  return std::nullopt;
299
4
}
300
301
std::optional<std::string>
302
4
PlatformRemoteGDBServer::DoGetGroupName(UserIDResolver::id_t gid) {
303
4
  std::string name;
304
4
  if (m_gdb_client_up && m_gdb_client_up->GetGroupName(gid, name))
305
0
    return std::move(name);
306
4
  return std::nullopt;
307
4
}
308
309
uint32_t PlatformRemoteGDBServer::FindProcesses(
310
    const ProcessInstanceInfoMatch &match_info,
311
4
    ProcessInstanceInfoList &process_infos) {
312
4
  if (m_gdb_client_up)
313
4
    return m_gdb_client_up->FindProcesses(match_info, process_infos);
314
0
  return 0;
315
4
}
316
317
bool PlatformRemoteGDBServer::GetProcessInfo(
318
6
    lldb::pid_t pid, ProcessInstanceInfo &process_info) {
319
6
  if (m_gdb_client_up)
320
0
    return m_gdb_client_up->GetProcessInfo(pid, process_info);
321
6
  return false;
322
6
}
323
324
0
Status PlatformRemoteGDBServer::LaunchProcess(ProcessLaunchInfo &launch_info) {
325
0
  Log *log = GetLog(LLDBLog::Platform);
326
0
  Status error;
327
328
0
  LLDB_LOGF(log, "PlatformRemoteGDBServer::%s() called", __FUNCTION__);
329
330
0
  if (!IsConnected())
331
0
    return Status("Not connected.");
332
0
  auto num_file_actions = launch_info.GetNumFileActions();
333
0
  for (decltype(num_file_actions) i = 0; i < num_file_actions; ++i) {
334
0
    const auto file_action = launch_info.GetFileActionAtIndex(i);
335
0
    if (file_action->GetAction() != FileAction::eFileActionOpen)
336
0
      continue;
337
0
    switch (file_action->GetFD()) {
338
0
    case STDIN_FILENO:
339
0
      m_gdb_client_up->SetSTDIN(file_action->GetFileSpec());
340
0
      break;
341
0
    case STDOUT_FILENO:
342
0
      m_gdb_client_up->SetSTDOUT(file_action->GetFileSpec());
343
0
      break;
344
0
    case STDERR_FILENO:
345
0
      m_gdb_client_up->SetSTDERR(file_action->GetFileSpec());
346
0
      break;
347
0
    }
348
0
  }
349
350
0
  m_gdb_client_up->SetDisableASLR(
351
0
      launch_info.GetFlags().Test(eLaunchFlagDisableASLR));
352
0
  m_gdb_client_up->SetDetachOnError(
353
0
      launch_info.GetFlags().Test(eLaunchFlagDetachOnError));
354
355
0
  FileSpec working_dir = launch_info.GetWorkingDirectory();
356
0
  if (working_dir) {
357
0
    m_gdb_client_up->SetWorkingDir(working_dir);
358
0
  }
359
360
  // Send the environment and the program + arguments after we connect
361
0
  m_gdb_client_up->SendEnvironment(launch_info.GetEnvironment());
362
363
0
  ArchSpec arch_spec = launch_info.GetArchitecture();
364
0
  const char *arch_triple = arch_spec.GetTriple().str().c_str();
365
366
0
  m_gdb_client_up->SendLaunchArchPacket(arch_triple);
367
0
  LLDB_LOGF(
368
0
      log,
369
0
      "PlatformRemoteGDBServer::%s() set launch architecture triple to '%s'",
370
0
      __FUNCTION__, arch_triple ? arch_triple : "<NULL>");
371
372
0
  {
373
    // Scope for the scoped timeout object
374
0
    process_gdb_remote::GDBRemoteCommunication::ScopedTimeout timeout(
375
0
        *m_gdb_client_up, std::chrono::seconds(5));
376
    // Since we can't send argv0 separate from the executable path, we need to
377
    // make sure to use the actual executable path found in the launch_info...
378
0
    Args args = launch_info.GetArguments();
379
0
    if (FileSpec exe_file = launch_info.GetExecutableFile())
380
0
      args.ReplaceArgumentAtIndex(0, exe_file.GetPath(false));
381
0
    if (llvm::Error err = m_gdb_client_up->LaunchProcess(args)) {
382
0
      error.SetErrorStringWithFormatv("Cannot launch '{0}': {1}",
383
0
                                      args.GetArgumentAtIndex(0),
384
0
                                      llvm::fmt_consume(std::move(err)));
385
0
      return error;
386
0
    }
387
0
  }
388
389
0
  const auto pid = m_gdb_client_up->GetCurrentProcessID(false);
390
0
  if (pid != LLDB_INVALID_PROCESS_ID) {
391
0
    launch_info.SetProcessID(pid);
392
0
    LLDB_LOGF(log,
393
0
              "PlatformRemoteGDBServer::%s() pid %" PRIu64
394
0
              " launched successfully",
395
0
              __FUNCTION__, pid);
396
0
  } else {
397
0
    LLDB_LOGF(log,
398
0
              "PlatformRemoteGDBServer::%s() launch succeeded but we "
399
0
              "didn't get a valid process id back!",
400
0
              __FUNCTION__);
401
0
    error.SetErrorString("failed to get PID");
402
0
  }
403
0
  return error;
404
0
}
405
406
0
Status PlatformRemoteGDBServer::KillProcess(const lldb::pid_t pid) {
407
0
  if (!KillSpawnedProcess(pid))
408
0
    return Status("failed to kill remote spawned process");
409
0
  return Status();
410
0
}
411
412
lldb::ProcessSP
413
PlatformRemoteGDBServer::DebugProcess(ProcessLaunchInfo &launch_info,
414
                                      Debugger &debugger, Target &target,
415
1
                                      Status &error) {
416
1
  lldb::ProcessSP process_sp;
417
1
  if (IsRemote()) {
418
1
    if (IsConnected()) {
419
1
      lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
420
1
      std::string connect_url;
421
1
      if (!LaunchGDBServer(debugserver_pid, connect_url)) {
422
0
        error.SetErrorStringWithFormat("unable to launch a GDB server on '%s'",
423
0
                                       GetHostname());
424
1
      } else {
425
        // The darwin always currently uses the GDB remote debugger plug-in
426
        // so even when debugging locally we are debugging remotely!
427
1
        process_sp = target.CreateProcess(launch_info.GetListener(),
428
1
                                          "gdb-remote", nullptr, true);
429
430
1
        if (process_sp) {
431
1
          process_sp->HijackProcessEvents(launch_info.GetHijackListener());
432
1
          process_sp->SetShadowListener(launch_info.GetShadowListener());
433
434
1
          error = process_sp->ConnectRemote(connect_url.c_str());
435
          // Retry the connect remote one time...
436
1
          if (error.Fail())
437
0
            error = process_sp->ConnectRemote(connect_url.c_str());
438
1
          if (error.Success())
439
1
            error = process_sp->Launch(launch_info);
440
0
          else if (debugserver_pid != LLDB_INVALID_PROCESS_ID) {
441
0
            printf("error: connect remote failed (%s)\n", error.AsCString());
442
0
            KillSpawnedProcess(debugserver_pid);
443
0
          }
444
1
        }
445
1
      }
446
1
    } else {
447
0
      error.SetErrorString("not connected to remote gdb server");
448
0
    }
449
1
  }
450
1
  return process_sp;
451
1
}
452
453
bool PlatformRemoteGDBServer::LaunchGDBServer(lldb::pid_t &pid,
454
1
                                              std::string &connect_url) {
455
1
  assert(IsConnected());
456
457
1
  ArchSpec remote_arch = GetRemoteSystemArchitecture();
458
1
  llvm::Triple &remote_triple = remote_arch.GetTriple();
459
460
1
  uint16_t port = 0;
461
1
  std::string socket_name;
462
1
  bool launch_result = false;
463
1
  if (remote_triple.getVendor() == llvm::Triple::Apple &&
464
1
      remote_triple.getOS() == llvm::Triple::IOS) {
465
    // When remote debugging to iOS, we use a USB mux that always talks to
466
    // localhost, so we will need the remote debugserver to accept connections
467
    // only from localhost, no matter what our current hostname is
468
0
    launch_result =
469
0
        m_gdb_client_up->LaunchGDBServer("127.0.0.1", pid, port, socket_name);
470
1
  } else {
471
    // All other hosts should use their actual hostname
472
1
    launch_result =
473
1
        m_gdb_client_up->LaunchGDBServer(nullptr, pid, port, socket_name);
474
1
  }
475
476
1
  if (!launch_result)
477
0
    return false;
478
479
1
  connect_url =
480
1
      MakeGdbServerUrl(m_platform_scheme, m_platform_hostname, port,
481
1
                       (socket_name.empty()) ? nullptr : 
socket_name.c_str()0
);
482
1
  return true;
483
1
}
484
485
0
bool PlatformRemoteGDBServer::KillSpawnedProcess(lldb::pid_t pid) {
486
0
  assert(IsConnected());
487
0
  return m_gdb_client_up->KillSpawnedProcess(pid);
488
0
}
489
490
lldb::ProcessSP PlatformRemoteGDBServer::Attach(
491
    ProcessAttachInfo &attach_info, Debugger &debugger,
492
    Target *target, // Can be NULL, if NULL create a new target, else use
493
                    // existing one
494
0
    Status &error) {
495
0
  lldb::ProcessSP process_sp;
496
0
  if (IsRemote()) {
497
0
    if (IsConnected()) {
498
0
      lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
499
0
      std::string connect_url;
500
0
      if (!LaunchGDBServer(debugserver_pid, connect_url)) {
501
0
        error.SetErrorStringWithFormat("unable to launch a GDB server on '%s'",
502
0
                                       GetHostname());
503
0
      } else {
504
0
        if (target == nullptr) {
505
0
          TargetSP new_target_sp;
506
507
0
          error = debugger.GetTargetList().CreateTarget(
508
0
              debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
509
0
          target = new_target_sp.get();
510
0
        } else
511
0
          error.Clear();
512
513
0
        if (target && error.Success()) {
514
          // The darwin always currently uses the GDB remote debugger plug-in
515
          // so even when debugging locally we are debugging remotely!
516
0
          process_sp =
517
0
              target->CreateProcess(attach_info.GetListenerForProcess(debugger),
518
0
                                    "gdb-remote", nullptr, true);
519
0
          if (process_sp) {
520
0
            error = process_sp->ConnectRemote(connect_url.c_str());
521
0
            if (error.Success()) {
522
0
              ListenerSP listener_sp = attach_info.GetHijackListener();
523
0
              if (listener_sp)
524
0
                process_sp->HijackProcessEvents(listener_sp);
525
0
              process_sp->SetShadowListener(attach_info.GetShadowListener());
526
0
              error = process_sp->Attach(attach_info);
527
0
            }
528
529
0
            if (error.Fail() && debugserver_pid != LLDB_INVALID_PROCESS_ID) {
530
0
              KillSpawnedProcess(debugserver_pid);
531
0
            }
532
0
          }
533
0
        }
534
0
      }
535
0
    } else {
536
0
      error.SetErrorString("not connected to remote gdb server");
537
0
    }
538
0
  }
539
0
  return process_sp;
540
0
}
541
542
Status PlatformRemoteGDBServer::MakeDirectory(const FileSpec &file_spec,
543
0
                                              uint32_t mode) {
544
0
  if (!IsConnected())
545
0
    return Status("Not connected.");
546
0
  Status error = m_gdb_client_up->MakeDirectory(file_spec, mode);
547
0
  Log *log = GetLog(LLDBLog::Platform);
548
0
  LLDB_LOGF(log,
549
0
            "PlatformRemoteGDBServer::MakeDirectory(path='%s', mode=%o) "
550
0
            "error = %u (%s)",
551
0
            file_spec.GetPath().c_str(), mode, error.GetError(),
552
0
            error.AsCString());
553
0
  return error;
554
0
}
555
556
Status PlatformRemoteGDBServer::GetFilePermissions(const FileSpec &file_spec,
557
2
                                                   uint32_t &file_permissions) {
558
2
  if (!IsConnected())
559
0
    return Status("Not connected.");
560
2
  Status error =
561
2
      m_gdb_client_up->GetFilePermissions(file_spec, file_permissions);
562
2
  Log *log = GetLog(LLDBLog::Platform);
563
2
  LLDB_LOGF(log,
564
2
            "PlatformRemoteGDBServer::GetFilePermissions(path='%s', "
565
2
            "file_permissions=%o) error = %u (%s)",
566
2
            file_spec.GetPath().c_str(), file_permissions, error.GetError(),
567
2
            error.AsCString());
568
2
  return error;
569
2
}
570
571
Status PlatformRemoteGDBServer::SetFilePermissions(const FileSpec &file_spec,
572
0
                                                   uint32_t file_permissions) {
573
0
  if (!IsConnected())
574
0
    return Status("Not connected.");
575
0
  Status error =
576
0
      m_gdb_client_up->SetFilePermissions(file_spec, file_permissions);
577
0
  Log *log = GetLog(LLDBLog::Platform);
578
0
  LLDB_LOGF(log,
579
0
            "PlatformRemoteGDBServer::SetFilePermissions(path='%s', "
580
0
            "file_permissions=%o) error = %u (%s)",
581
0
            file_spec.GetPath().c_str(), file_permissions, error.GetError(),
582
0
            error.AsCString());
583
0
  return error;
584
0
}
585
586
lldb::user_id_t PlatformRemoteGDBServer::OpenFile(const FileSpec &file_spec,
587
                                                  File::OpenOptions flags,
588
                                                  uint32_t mode,
589
3
                                                  Status &error) {
590
3
  if (IsConnected())
591
3
    return m_gdb_client_up->OpenFile(file_spec, flags, mode, error);
592
0
  return LLDB_INVALID_UID;
593
3
}
594
595
3
bool PlatformRemoteGDBServer::CloseFile(lldb::user_id_t fd, Status &error) {
596
3
  if (IsConnected())
597
3
    return m_gdb_client_up->CloseFile(fd, error);
598
0
  error = Status("Not connected.");
599
0
  return false;
600
3
}
601
602
lldb::user_id_t
603
3
PlatformRemoteGDBServer::GetFileSize(const FileSpec &file_spec) {
604
3
  if (IsConnected())
605
3
    return m_gdb_client_up->GetFileSize(file_spec);
606
0
  return LLDB_INVALID_UID;
607
3
}
608
609
void PlatformRemoteGDBServer::AutoCompleteDiskFileOrDirectory(
610
5
    CompletionRequest &request, bool only_dir) {
611
5
  if (IsConnected())
612
5
    m_gdb_client_up->AutoCompleteDiskFileOrDirectory(request, only_dir);
613
5
}
614
615
uint64_t PlatformRemoteGDBServer::ReadFile(lldb::user_id_t fd, uint64_t offset,
616
                                           void *dst, uint64_t dst_len,
617
2
                                           Status &error) {
618
2
  if (IsConnected())
619
2
    return m_gdb_client_up->ReadFile(fd, offset, dst, dst_len, error);
620
0
  error = Status("Not connected.");
621
0
  return 0;
622
2
}
623
624
uint64_t PlatformRemoteGDBServer::WriteFile(lldb::user_id_t fd, uint64_t offset,
625
                                            const void *src, uint64_t src_len,
626
5
                                            Status &error) {
627
5
  if (IsConnected())
628
5
    return m_gdb_client_up->WriteFile(fd, offset, src, src_len, error);
629
0
  error = Status("Not connected.");
630
0
  return 0;
631
5
}
632
633
Status PlatformRemoteGDBServer::PutFile(const FileSpec &source,
634
                                        const FileSpec &destination,
635
0
                                        uint32_t uid, uint32_t gid) {
636
0
  return Platform::PutFile(source, destination, uid, gid);
637
0
}
638
639
Status PlatformRemoteGDBServer::CreateSymlink(
640
    const FileSpec &src, // The name of the link is in src
641
    const FileSpec &dst) // The symlink points to dst
642
0
{
643
0
  if (!IsConnected())
644
0
    return Status("Not connected.");
645
0
  Status error = m_gdb_client_up->CreateSymlink(src, dst);
646
0
  Log *log = GetLog(LLDBLog::Platform);
647
0
  LLDB_LOGF(log,
648
0
            "PlatformRemoteGDBServer::CreateSymlink(src='%s', dst='%s') "
649
0
            "error = %u (%s)",
650
0
            src.GetPath().c_str(), dst.GetPath().c_str(), error.GetError(),
651
0
            error.AsCString());
652
0
  return error;
653
0
}
654
655
1
Status PlatformRemoteGDBServer::Unlink(const FileSpec &file_spec) {
656
1
  if (!IsConnected())
657
0
    return Status("Not connected.");
658
1
  Status error = m_gdb_client_up->Unlink(file_spec);
659
1
  Log *log = GetLog(LLDBLog::Platform);
660
1
  LLDB_LOGF(log, "PlatformRemoteGDBServer::Unlink(path='%s') error = %u (%s)",
661
1
            file_spec.GetPath().c_str(), error.GetError(), error.AsCString());
662
1
  return error;
663
1
}
664
665
5
bool PlatformRemoteGDBServer::GetFileExists(const FileSpec &file_spec) {
666
5
  if (IsConnected())
667
5
    return m_gdb_client_up->GetFileExists(file_spec);
668
0
  return false;
669
5
}
670
671
Status PlatformRemoteGDBServer::RunShellCommand(
672
    llvm::StringRef shell, llvm::StringRef command,
673
    const FileSpec &
674
        working_dir, // Pass empty FileSpec to use the current working directory
675
    int *status_ptr, // Pass NULL if you don't want the process exit status
676
    int *signo_ptr,  // Pass NULL if you don't want the signal that caused the
677
                     // process to exit
678
    std::string
679
        *command_output, // Pass NULL if you don't want the command output
680
0
    const Timeout<std::micro> &timeout) {
681
0
  if (!IsConnected())
682
0
    return Status("Not connected.");
683
0
  return m_gdb_client_up->RunShellCommand(command, working_dir, status_ptr,
684
0
                                          signo_ptr, command_output, timeout);
685
0
}
686
687
0
void PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames() {
688
0
  m_trap_handlers.push_back(ConstString("_sigtramp"));
689
0
}
690
691
1
const UnixSignalsSP &PlatformRemoteGDBServer::GetRemoteUnixSignals() {
692
1
  if (!IsConnected())
693
0
    return Platform::GetRemoteUnixSignals();
694
695
1
  if (m_remote_signals_sp)
696
0
    return m_remote_signals_sp;
697
698
  // If packet not implemented or JSON failed to parse, we'll guess the signal
699
  // set based on the remote architecture.
700
1
  m_remote_signals_sp = UnixSignals::Create(GetRemoteSystemArchitecture());
701
702
1
  StringExtractorGDBRemote response;
703
1
  auto result =
704
1
      m_gdb_client_up->SendPacketAndWaitForResponse("jSignalsInfo", response);
705
706
1
  if (result != decltype(result)::Success ||
707
1
      response.GetResponseType() != response.eResponse)
708
0
    return m_remote_signals_sp;
709
710
1
  auto object_sp = StructuredData::ParseJSON(response.GetStringRef());
711
1
  if (!object_sp || 
!object_sp->IsValid()0
)
712
1
    return m_remote_signals_sp;
713
714
0
  auto array_sp = object_sp->GetAsArray();
715
0
  if (!array_sp || !array_sp->IsValid())
716
0
    return m_remote_signals_sp;
717
718
0
  auto remote_signals_sp = std::make_shared<lldb_private::GDBRemoteSignals>();
719
720
0
  bool done = array_sp->ForEach(
721
0
      [&remote_signals_sp](StructuredData::Object *object) -> bool {
722
0
        if (!object || !object->IsValid())
723
0
          return false;
724
725
0
        auto dict = object->GetAsDictionary();
726
0
        if (!dict || !dict->IsValid())
727
0
          return false;
728
729
        // Signal number and signal name are required.
730
0
        uint64_t signo;
731
0
        if (!dict->GetValueForKeyAsInteger("signo", signo))
732
0
          return false;
733
734
0
        llvm::StringRef name;
735
0
        if (!dict->GetValueForKeyAsString("name", name))
736
0
          return false;
737
738
        // We can live without short_name, description, etc.
739
0
        bool suppress{false};
740
0
        auto object_sp = dict->GetValueForKey("suppress");
741
0
        if (object_sp && object_sp->IsValid())
742
0
          suppress = object_sp->GetBooleanValue();
743
744
0
        bool stop{false};
745
0
        object_sp = dict->GetValueForKey("stop");
746
0
        if (object_sp && object_sp->IsValid())
747
0
          stop = object_sp->GetBooleanValue();
748
749
0
        bool notify{false};
750
0
        object_sp = dict->GetValueForKey("notify");
751
0
        if (object_sp && object_sp->IsValid())
752
0
          notify = object_sp->GetBooleanValue();
753
754
0
        std::string description;
755
0
        object_sp = dict->GetValueForKey("description");
756
0
        if (object_sp && object_sp->IsValid())
757
0
          description = std::string(object_sp->GetStringValue());
758
759
0
        llvm::StringRef name_backed, description_backed;
760
0
        {
761
0
          std::lock_guard<std::mutex> guard(g_signal_string_mutex);
762
0
          name_backed =
763
0
              g_signal_string_storage.insert(name).first->getKeyData();
764
0
          if (!description.empty())
765
0
            description_backed =
766
0
                g_signal_string_storage.insert(description).first->getKeyData();
767
0
        }
768
769
0
        remote_signals_sp->AddSignal(signo, name_backed, suppress, stop, notify,
770
0
                                     description_backed);
771
0
        return true;
772
0
      });
773
774
0
  if (done)
775
0
    m_remote_signals_sp = std::move(remote_signals_sp);
776
777
0
  return m_remote_signals_sp;
778
0
}
779
780
std::string PlatformRemoteGDBServer::MakeGdbServerUrl(
781
    const std::string &platform_scheme, const std::string &platform_hostname,
782
1
    uint16_t port, const char *socket_name) {
783
1
  const char *override_scheme =
784
1
      getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_SCHEME");
785
1
  const char *override_hostname =
786
1
      getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME");
787
1
  const char *port_offset_c_str =
788
1
      getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET");
789
1
  int port_offset = port_offset_c_str ? 
::atoi(port_offset_c_str)0
: 0;
790
791
1
  return MakeUrl(override_scheme ? 
override_scheme0
: platform_scheme.c_str(),
792
1
                 override_hostname ? 
override_hostname0
793
1
                                   : platform_hostname.c_str(),
794
1
                 port + port_offset, socket_name);
795
1
}
796
797
std::string PlatformRemoteGDBServer::MakeUrl(const char *scheme,
798
                                             const char *hostname,
799
1
                                             uint16_t port, const char *path) {
800
1
  StreamString result;
801
1
  result.Printf("%s://[%s]", scheme, hostname);
802
1
  if (port != 0)
803
1
    result.Printf(":%u", port);
804
1
  if (path)
805
0
    result.Write(path, strlen(path));
806
1
  return std::string(result.GetString());
807
1
}
808
809
size_t PlatformRemoteGDBServer::ConnectToWaitingProcesses(Debugger &debugger,
810
13
                                                          Status &error) {
811
13
  std::vector<std::string> connection_urls;
812
13
  GetPendingGdbServerList(connection_urls);
813
814
13
  for (size_t i = 0; i < connection_urls.size(); 
++i0
) {
815
0
    ConnectProcess(connection_urls[i].c_str(), "gdb-remote", debugger, nullptr, error);
816
0
    if (error.Fail())
817
0
      return i; // We already connected to i process successfully
818
0
  }
819
13
  return connection_urls.size();
820
13
}
821
822
size_t PlatformRemoteGDBServer::GetPendingGdbServerList(
823
13
    std::vector<std::string> &connection_urls) {
824
13
  std::vector<std::pair<uint16_t, std::string>> remote_servers;
825
13
  if (!IsConnected())
826
0
    return 0;
827
13
  m_gdb_client_up->QueryGDBServer(remote_servers);
828
13
  for (const auto &gdbserver : remote_servers) {
829
0
    const char *socket_name_cstr =
830
0
        gdbserver.second.empty() ? nullptr : gdbserver.second.c_str();
831
0
    connection_urls.emplace_back(
832
0
        MakeGdbServerUrl(m_platform_scheme, m_platform_hostname,
833
0
                         gdbserver.first, socket_name_cstr));
834
0
  }
835
13
  return connection_urls.size();
836
13
}