1 //===-- SBPlatform.cpp ------------------------------------------*- C++ -*-===//
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/API/SBPlatform.h"
10 #include "SBReproducerPrivate.h"
11 #include "lldb/API/SBError.h"
12 #include "lldb/API/SBFileSpec.h"
13 #include "lldb/API/SBLaunchInfo.h"
14 #include "lldb/API/SBUnixSignals.h"
15 #include "lldb/Host/File.h"
16 #include "lldb/Target/Platform.h"
17 #include "lldb/Target/Target.h"
18 #include "lldb/Utility/ArchSpec.h"
19 #include "lldb/Utility/Args.h"
20 #include "lldb/Utility/Status.h"
21 
22 #include "llvm/Support/FileSystem.h"
23 
24 #include <functional>
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 //----------------------------------------------------------------------
30 // PlatformConnectOptions
31 //----------------------------------------------------------------------
32 struct PlatformConnectOptions {
33   PlatformConnectOptions(const char *url = NULL)
34       : m_url(), m_rsync_options(), m_rsync_remote_path_prefix(),
35         m_rsync_enabled(false), m_rsync_omit_hostname_from_remote_path(false),
36         m_local_cache_directory() {
37     if (url && url[0])
38       m_url = url;
39   }
40 
41   ~PlatformConnectOptions() {}
42 
43   std::string m_url;
44   std::string m_rsync_options;
45   std::string m_rsync_remote_path_prefix;
46   bool m_rsync_enabled;
47   bool m_rsync_omit_hostname_from_remote_path;
48   ConstString m_local_cache_directory;
49 };
50 
51 //----------------------------------------------------------------------
52 // PlatformShellCommand
53 //----------------------------------------------------------------------
54 struct PlatformShellCommand {
55   PlatformShellCommand(const char *shell_command = NULL)
56       : m_command(), m_working_dir(), m_status(0), m_signo(0) {
57     if (shell_command && shell_command[0])
58       m_command = shell_command;
59   }
60 
61   ~PlatformShellCommand() {}
62 
63   std::string m_command;
64   std::string m_working_dir;
65   std::string m_output;
66   int m_status;
67   int m_signo;
68   Timeout<std::ratio<1>> m_timeout = llvm::None;
69 };
70 //----------------------------------------------------------------------
71 // SBPlatformConnectOptions
72 //----------------------------------------------------------------------
73 SBPlatformConnectOptions::SBPlatformConnectOptions(const char *url)
74     : m_opaque_ptr(new PlatformConnectOptions(url)) {
75   LLDB_RECORD_CONSTRUCTOR(SBPlatformConnectOptions, (const char *), url);
76 }
77 
78 SBPlatformConnectOptions::SBPlatformConnectOptions(
79     const SBPlatformConnectOptions &rhs)
80     : m_opaque_ptr(new PlatformConnectOptions()) {
81   LLDB_RECORD_CONSTRUCTOR(SBPlatformConnectOptions,
82                           (const lldb::SBPlatformConnectOptions &), rhs);
83 
84   *m_opaque_ptr = *rhs.m_opaque_ptr;
85 }
86 
87 SBPlatformConnectOptions::~SBPlatformConnectOptions() { delete m_opaque_ptr; }
88 
89 void SBPlatformConnectOptions::operator=(const SBPlatformConnectOptions &rhs) {
90   LLDB_RECORD_METHOD(
91       void,
92       SBPlatformConnectOptions, operator=,(
93                                     const lldb::SBPlatformConnectOptions &),
94       rhs);
95 
96   *m_opaque_ptr = *rhs.m_opaque_ptr;
97 }
98 
99 const char *SBPlatformConnectOptions::GetURL() {
100   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBPlatformConnectOptions, GetURL);
101 
102   if (m_opaque_ptr->m_url.empty())
103     return NULL;
104   return m_opaque_ptr->m_url.c_str();
105 }
106 
107 void SBPlatformConnectOptions::SetURL(const char *url) {
108   LLDB_RECORD_METHOD(void, SBPlatformConnectOptions, SetURL, (const char *),
109                      url);
110 
111   if (url && url[0])
112     m_opaque_ptr->m_url = url;
113   else
114     m_opaque_ptr->m_url.clear();
115 }
116 
117 bool SBPlatformConnectOptions::GetRsyncEnabled() {
118   LLDB_RECORD_METHOD_NO_ARGS(bool, SBPlatformConnectOptions, GetRsyncEnabled);
119 
120   return m_opaque_ptr->m_rsync_enabled;
121 }
122 
123 void SBPlatformConnectOptions::EnableRsync(
124     const char *options, const char *remote_path_prefix,
125     bool omit_hostname_from_remote_path) {
126   LLDB_RECORD_METHOD(void, SBPlatformConnectOptions, EnableRsync,
127                      (const char *, const char *, bool), options,
128                      remote_path_prefix, omit_hostname_from_remote_path);
129 
130   m_opaque_ptr->m_rsync_enabled = true;
131   m_opaque_ptr->m_rsync_omit_hostname_from_remote_path =
132       omit_hostname_from_remote_path;
133   if (remote_path_prefix && remote_path_prefix[0])
134     m_opaque_ptr->m_rsync_remote_path_prefix = remote_path_prefix;
135   else
136     m_opaque_ptr->m_rsync_remote_path_prefix.clear();
137 
138   if (options && options[0])
139     m_opaque_ptr->m_rsync_options = options;
140   else
141     m_opaque_ptr->m_rsync_options.clear();
142 }
143 
144 void SBPlatformConnectOptions::DisableRsync() {
145   LLDB_RECORD_METHOD_NO_ARGS(void, SBPlatformConnectOptions, DisableRsync);
146 
147   m_opaque_ptr->m_rsync_enabled = false;
148 }
149 
150 const char *SBPlatformConnectOptions::GetLocalCacheDirectory() {
151   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBPlatformConnectOptions,
152                              GetLocalCacheDirectory);
153 
154   return m_opaque_ptr->m_local_cache_directory.GetCString();
155 }
156 
157 void SBPlatformConnectOptions::SetLocalCacheDirectory(const char *path) {
158   LLDB_RECORD_METHOD(void, SBPlatformConnectOptions, SetLocalCacheDirectory,
159                      (const char *), path);
160 
161   if (path && path[0])
162     m_opaque_ptr->m_local_cache_directory.SetCString(path);
163   else
164     m_opaque_ptr->m_local_cache_directory = ConstString();
165 }
166 
167 //----------------------------------------------------------------------
168 // SBPlatformShellCommand
169 //----------------------------------------------------------------------
170 SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_command)
171     : m_opaque_ptr(new PlatformShellCommand(shell_command)) {
172   LLDB_RECORD_CONSTRUCTOR(SBPlatformShellCommand, (const char *),
173                           shell_command);
174 }
175 
176 SBPlatformShellCommand::SBPlatformShellCommand(
177     const SBPlatformShellCommand &rhs)
178     : m_opaque_ptr(new PlatformShellCommand()) {
179   LLDB_RECORD_CONSTRUCTOR(SBPlatformShellCommand,
180                           (const lldb::SBPlatformShellCommand &), rhs);
181 
182   *m_opaque_ptr = *rhs.m_opaque_ptr;
183 }
184 
185 SBPlatformShellCommand::~SBPlatformShellCommand() { delete m_opaque_ptr; }
186 
187 void SBPlatformShellCommand::Clear() {
188   LLDB_RECORD_METHOD_NO_ARGS(void, SBPlatformShellCommand, Clear);
189 
190   m_opaque_ptr->m_output = std::string();
191   m_opaque_ptr->m_status = 0;
192   m_opaque_ptr->m_signo = 0;
193 }
194 
195 const char *SBPlatformShellCommand::GetCommand() {
196   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBPlatformShellCommand, GetCommand);
197 
198   if (m_opaque_ptr->m_command.empty())
199     return NULL;
200   return m_opaque_ptr->m_command.c_str();
201 }
202 
203 void SBPlatformShellCommand::SetCommand(const char *shell_command) {
204   LLDB_RECORD_METHOD(void, SBPlatformShellCommand, SetCommand, (const char *),
205                      shell_command);
206 
207   if (shell_command && shell_command[0])
208     m_opaque_ptr->m_command = shell_command;
209   else
210     m_opaque_ptr->m_command.clear();
211 }
212 
213 const char *SBPlatformShellCommand::GetWorkingDirectory() {
214   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBPlatformShellCommand,
215                              GetWorkingDirectory);
216 
217   if (m_opaque_ptr->m_working_dir.empty())
218     return NULL;
219   return m_opaque_ptr->m_working_dir.c_str();
220 }
221 
222 void SBPlatformShellCommand::SetWorkingDirectory(const char *path) {
223   LLDB_RECORD_METHOD(void, SBPlatformShellCommand, SetWorkingDirectory,
224                      (const char *), path);
225 
226   if (path && path[0])
227     m_opaque_ptr->m_working_dir = path;
228   else
229     m_opaque_ptr->m_working_dir.clear();
230 }
231 
232 uint32_t SBPlatformShellCommand::GetTimeoutSeconds() {
233   LLDB_RECORD_METHOD_NO_ARGS(uint32_t, SBPlatformShellCommand,
234                              GetTimeoutSeconds);
235 
236   if (m_opaque_ptr->m_timeout)
237     return m_opaque_ptr->m_timeout->count();
238   return UINT32_MAX;
239 }
240 
241 void SBPlatformShellCommand::SetTimeoutSeconds(uint32_t sec) {
242   LLDB_RECORD_METHOD(void, SBPlatformShellCommand, SetTimeoutSeconds,
243                      (uint32_t), sec);
244 
245   if (sec == UINT32_MAX)
246     m_opaque_ptr->m_timeout = llvm::None;
247   else
248     m_opaque_ptr->m_timeout = std::chrono::seconds(sec);
249 }
250 
251 int SBPlatformShellCommand::GetSignal() {
252   LLDB_RECORD_METHOD_NO_ARGS(int, SBPlatformShellCommand, GetSignal);
253 
254   return m_opaque_ptr->m_signo;
255 }
256 
257 int SBPlatformShellCommand::GetStatus() {
258   LLDB_RECORD_METHOD_NO_ARGS(int, SBPlatformShellCommand, GetStatus);
259 
260   return m_opaque_ptr->m_status;
261 }
262 
263 const char *SBPlatformShellCommand::GetOutput() {
264   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBPlatformShellCommand, GetOutput);
265 
266   if (m_opaque_ptr->m_output.empty())
267     return NULL;
268   return m_opaque_ptr->m_output.c_str();
269 }
270 
271 //----------------------------------------------------------------------
272 // SBPlatform
273 //----------------------------------------------------------------------
274 SBPlatform::SBPlatform() : m_opaque_sp() {
275   LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBPlatform);
276 }
277 
278 SBPlatform::SBPlatform(const char *platform_name) : m_opaque_sp() {
279   LLDB_RECORD_CONSTRUCTOR(SBPlatform, (const char *), platform_name);
280 
281   Status error;
282   if (platform_name && platform_name[0])
283     m_opaque_sp = Platform::Create(ConstString(platform_name), error);
284 }
285 
286 SBPlatform::~SBPlatform() {}
287 
288 bool SBPlatform::IsValid() const {
289   LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBPlatform, IsValid);
290 
291   return m_opaque_sp.get() != NULL;
292 }
293 
294 void SBPlatform::Clear() {
295   LLDB_RECORD_METHOD_NO_ARGS(void, SBPlatform, Clear);
296 
297   m_opaque_sp.reset();
298 }
299 
300 const char *SBPlatform::GetName() {
301   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBPlatform, GetName);
302 
303   PlatformSP platform_sp(GetSP());
304   if (platform_sp)
305     return platform_sp->GetName().GetCString();
306   return NULL;
307 }
308 
309 lldb::PlatformSP SBPlatform::GetSP() const { return m_opaque_sp; }
310 
311 void SBPlatform::SetSP(const lldb::PlatformSP &platform_sp) {
312   m_opaque_sp = platform_sp;
313 }
314 
315 const char *SBPlatform::GetWorkingDirectory() {
316   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBPlatform, GetWorkingDirectory);
317 
318   PlatformSP platform_sp(GetSP());
319   if (platform_sp)
320     return platform_sp->GetWorkingDirectory().GetCString();
321   return NULL;
322 }
323 
324 bool SBPlatform::SetWorkingDirectory(const char *path) {
325   LLDB_RECORD_METHOD(bool, SBPlatform, SetWorkingDirectory, (const char *),
326                      path);
327 
328   PlatformSP platform_sp(GetSP());
329   if (platform_sp) {
330     if (path)
331       platform_sp->SetWorkingDirectory(FileSpec(path));
332     else
333       platform_sp->SetWorkingDirectory(FileSpec());
334     return true;
335   }
336   return false;
337 }
338 
339 SBError SBPlatform::ConnectRemote(SBPlatformConnectOptions &connect_options) {
340   LLDB_RECORD_METHOD(lldb::SBError, SBPlatform, ConnectRemote,
341                      (lldb::SBPlatformConnectOptions &), connect_options);
342 
343   SBError sb_error;
344   PlatformSP platform_sp(GetSP());
345   if (platform_sp && connect_options.GetURL()) {
346     Args args;
347     args.AppendArgument(
348         llvm::StringRef::withNullAsEmpty(connect_options.GetURL()));
349     sb_error.ref() = platform_sp->ConnectRemote(args);
350   } else {
351     sb_error.SetErrorString("invalid platform");
352   }
353   return LLDB_RECORD_RESULT(sb_error);
354 }
355 
356 void SBPlatform::DisconnectRemote() {
357   LLDB_RECORD_METHOD_NO_ARGS(void, SBPlatform, DisconnectRemote);
358 
359   PlatformSP platform_sp(GetSP());
360   if (platform_sp)
361     platform_sp->DisconnectRemote();
362 }
363 
364 bool SBPlatform::IsConnected() {
365   LLDB_RECORD_METHOD_NO_ARGS(bool, SBPlatform, IsConnected);
366 
367   PlatformSP platform_sp(GetSP());
368   if (platform_sp)
369     return platform_sp->IsConnected();
370   return false;
371 }
372 
373 const char *SBPlatform::GetTriple() {
374   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBPlatform, GetTriple);
375 
376   PlatformSP platform_sp(GetSP());
377   if (platform_sp) {
378     ArchSpec arch(platform_sp->GetSystemArchitecture());
379     if (arch.IsValid()) {
380       // Const-ify the string so we don't need to worry about the lifetime of
381       // the string
382       return ConstString(arch.GetTriple().getTriple().c_str()).GetCString();
383     }
384   }
385   return NULL;
386 }
387 
388 const char *SBPlatform::GetOSBuild() {
389   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBPlatform, GetOSBuild);
390 
391   PlatformSP platform_sp(GetSP());
392   if (platform_sp) {
393     std::string s;
394     if (platform_sp->GetOSBuildString(s)) {
395       if (!s.empty()) {
396         // Const-ify the string so we don't need to worry about the lifetime of
397         // the string
398         return ConstString(s.c_str()).GetCString();
399       }
400     }
401   }
402   return NULL;
403 }
404 
405 const char *SBPlatform::GetOSDescription() {
406   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBPlatform, GetOSDescription);
407 
408   PlatformSP platform_sp(GetSP());
409   if (platform_sp) {
410     std::string s;
411     if (platform_sp->GetOSKernelDescription(s)) {
412       if (!s.empty()) {
413         // Const-ify the string so we don't need to worry about the lifetime of
414         // the string
415         return ConstString(s.c_str()).GetCString();
416       }
417     }
418   }
419   return NULL;
420 }
421 
422 const char *SBPlatform::GetHostname() {
423   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBPlatform, GetHostname);
424 
425   PlatformSP platform_sp(GetSP());
426   if (platform_sp)
427     return platform_sp->GetHostname();
428   return NULL;
429 }
430 
431 uint32_t SBPlatform::GetOSMajorVersion() {
432   LLDB_RECORD_METHOD_NO_ARGS(uint32_t, SBPlatform, GetOSMajorVersion);
433 
434   llvm::VersionTuple version;
435   if (PlatformSP platform_sp = GetSP())
436     version = platform_sp->GetOSVersion();
437   return version.empty() ? UINT32_MAX : version.getMajor();
438 }
439 
440 uint32_t SBPlatform::GetOSMinorVersion() {
441   LLDB_RECORD_METHOD_NO_ARGS(uint32_t, SBPlatform, GetOSMinorVersion);
442 
443   llvm::VersionTuple version;
444   if (PlatformSP platform_sp = GetSP())
445     version = platform_sp->GetOSVersion();
446   return version.getMinor().getValueOr(UINT32_MAX);
447 }
448 
449 uint32_t SBPlatform::GetOSUpdateVersion() {
450   LLDB_RECORD_METHOD_NO_ARGS(uint32_t, SBPlatform, GetOSUpdateVersion);
451 
452   llvm::VersionTuple version;
453   if (PlatformSP platform_sp = GetSP())
454     version = platform_sp->GetOSVersion();
455   return version.getSubminor().getValueOr(UINT32_MAX);
456 }
457 
458 SBError SBPlatform::Get(SBFileSpec &src, SBFileSpec &dst) {
459   LLDB_RECORD_METHOD(lldb::SBError, SBPlatform, Get,
460                      (lldb::SBFileSpec &, lldb::SBFileSpec &), src, dst);
461 
462   SBError sb_error;
463   PlatformSP platform_sp(GetSP());
464   if (platform_sp) {
465     sb_error.ref() = platform_sp->GetFile(src.ref(), dst.ref());
466   } else {
467     sb_error.SetErrorString("invalid platform");
468   }
469   return LLDB_RECORD_RESULT(sb_error);
470 }
471 
472 SBError SBPlatform::Put(SBFileSpec &src, SBFileSpec &dst) {
473   LLDB_RECORD_METHOD(lldb::SBError, SBPlatform, Put,
474                      (lldb::SBFileSpec &, lldb::SBFileSpec &), src, dst);
475   return LLDB_RECORD_RESULT(
476       ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
477         if (src.Exists()) {
478           uint32_t permissions =
479               FileSystem::Instance().GetPermissions(src.ref());
480           if (permissions == 0) {
481             if (FileSystem::Instance().IsDirectory(src.ref()))
482               permissions = eFilePermissionsDirectoryDefault;
483             else
484               permissions = eFilePermissionsFileDefault;
485           }
486 
487           return platform_sp->PutFile(src.ref(), dst.ref(), permissions);
488         }
489 
490         Status error;
491         error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'",
492                                        src.ref().GetPath().c_str());
493         return error;
494       }));
495 }
496 
497 SBError SBPlatform::Install(SBFileSpec &src, SBFileSpec &dst) {
498   LLDB_RECORD_METHOD(lldb::SBError, SBPlatform, Install,
499                      (lldb::SBFileSpec &, lldb::SBFileSpec &), src, dst);
500   return LLDB_RECORD_RESULT(
501       ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
502         if (src.Exists())
503           return platform_sp->Install(src.ref(), dst.ref());
504 
505         Status error;
506         error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'",
507                                        src.ref().GetPath().c_str());
508         return error;
509       }));
510 }
511 
512 SBError SBPlatform::Run(SBPlatformShellCommand &shell_command) {
513   LLDB_RECORD_METHOD(lldb::SBError, SBPlatform, Run,
514                      (lldb::SBPlatformShellCommand &), shell_command);
515   return LLDB_RECORD_RESULT(ExecuteConnected([&](const lldb::PlatformSP
516                                                      &platform_sp) {
517     const char *command = shell_command.GetCommand();
518     if (!command)
519       return Status("invalid shell command (empty)");
520 
521     const char *working_dir = shell_command.GetWorkingDirectory();
522     if (working_dir == NULL) {
523       working_dir = platform_sp->GetWorkingDirectory().GetCString();
524       if (working_dir)
525         shell_command.SetWorkingDirectory(working_dir);
526     }
527     return platform_sp->RunShellCommand(command, FileSpec(working_dir),
528                                         &shell_command.m_opaque_ptr->m_status,
529                                         &shell_command.m_opaque_ptr->m_signo,
530                                         &shell_command.m_opaque_ptr->m_output,
531                                         shell_command.m_opaque_ptr->m_timeout);
532   }));
533 }
534 
535 SBError SBPlatform::Launch(SBLaunchInfo &launch_info) {
536   LLDB_RECORD_METHOD(lldb::SBError, SBPlatform, Launch, (lldb::SBLaunchInfo &),
537                      launch_info);
538   return LLDB_RECORD_RESULT(
539       ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
540         ProcessLaunchInfo info = launch_info.ref();
541         Status error = platform_sp->LaunchProcess(info);
542         launch_info.set_ref(info);
543         return error;
544       }));
545 }
546 
547 SBError SBPlatform::Kill(const lldb::pid_t pid) {
548   LLDB_RECORD_METHOD(lldb::SBError, SBPlatform, Kill, (const lldb::pid_t), pid);
549   return LLDB_RECORD_RESULT(
550       ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
551         return platform_sp->KillProcess(pid);
552       }));
553 }
554 
555 SBError SBPlatform::ExecuteConnected(
556     const std::function<Status(const lldb::PlatformSP &)> &func) {
557   SBError sb_error;
558   const auto platform_sp(GetSP());
559   if (platform_sp) {
560     if (platform_sp->IsConnected())
561       sb_error.ref() = func(platform_sp);
562     else
563       sb_error.SetErrorString("not connected");
564   } else
565     sb_error.SetErrorString("invalid platform");
566 
567   return sb_error;
568 }
569 
570 SBError SBPlatform::MakeDirectory(const char *path, uint32_t file_permissions) {
571   LLDB_RECORD_METHOD(lldb::SBError, SBPlatform, MakeDirectory,
572                      (const char *, uint32_t), path, file_permissions);
573 
574   SBError sb_error;
575   PlatformSP platform_sp(GetSP());
576   if (platform_sp) {
577     sb_error.ref() =
578         platform_sp->MakeDirectory(FileSpec(path), file_permissions);
579   } else {
580     sb_error.SetErrorString("invalid platform");
581   }
582   return LLDB_RECORD_RESULT(sb_error);
583 }
584 
585 uint32_t SBPlatform::GetFilePermissions(const char *path) {
586   LLDB_RECORD_METHOD(uint32_t, SBPlatform, GetFilePermissions, (const char *),
587                      path);
588 
589   PlatformSP platform_sp(GetSP());
590   if (platform_sp) {
591     uint32_t file_permissions = 0;
592     platform_sp->GetFilePermissions(FileSpec(path), file_permissions);
593     return file_permissions;
594   }
595   return 0;
596 }
597 
598 SBError SBPlatform::SetFilePermissions(const char *path,
599                                        uint32_t file_permissions) {
600   LLDB_RECORD_METHOD(lldb::SBError, SBPlatform, SetFilePermissions,
601                      (const char *, uint32_t), path, file_permissions);
602 
603   SBError sb_error;
604   PlatformSP platform_sp(GetSP());
605   if (platform_sp) {
606     sb_error.ref() =
607         platform_sp->SetFilePermissions(FileSpec(path), file_permissions);
608   } else {
609     sb_error.SetErrorString("invalid platform");
610   }
611   return LLDB_RECORD_RESULT(sb_error);
612 }
613 
614 SBUnixSignals SBPlatform::GetUnixSignals() const {
615   LLDB_RECORD_METHOD_CONST_NO_ARGS(lldb::SBUnixSignals, SBPlatform,
616                                    GetUnixSignals);
617 
618   if (auto platform_sp = GetSP())
619     return LLDB_RECORD_RESULT(SBUnixSignals{platform_sp});
620 
621   return LLDB_RECORD_RESULT(SBUnixSignals());
622 }
623