Coverage Report

Created: 2022-01-25 06:29

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