1 //===-- SBPlatform.cpp ------------------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "lldb/API/SBPlatform.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 {
PlatformConnectOptionsPlatformConnectOptions33 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
~PlatformConnectOptionsPlatformConnectOptions41 ~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 {
PlatformShellCommandPlatformShellCommand55 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
~PlatformShellCommandPlatformShellCommand61 ~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 //----------------------------------------------------------------------
SBPlatformConnectOptions(const char * url)73 SBPlatformConnectOptions::SBPlatformConnectOptions(const char *url)
74 : m_opaque_ptr(new PlatformConnectOptions(url)) {}
75
SBPlatformConnectOptions(const SBPlatformConnectOptions & rhs)76 SBPlatformConnectOptions::SBPlatformConnectOptions(
77 const SBPlatformConnectOptions &rhs)
78 : m_opaque_ptr(new PlatformConnectOptions()) {
79 *m_opaque_ptr = *rhs.m_opaque_ptr;
80 }
81
~SBPlatformConnectOptions()82 SBPlatformConnectOptions::~SBPlatformConnectOptions() { delete m_opaque_ptr; }
83
operator =(const SBPlatformConnectOptions & rhs)84 void SBPlatformConnectOptions::operator=(const SBPlatformConnectOptions &rhs) {
85 *m_opaque_ptr = *rhs.m_opaque_ptr;
86 }
87
GetURL()88 const char *SBPlatformConnectOptions::GetURL() {
89 if (m_opaque_ptr->m_url.empty())
90 return NULL;
91 return m_opaque_ptr->m_url.c_str();
92 }
93
SetURL(const char * url)94 void SBPlatformConnectOptions::SetURL(const char *url) {
95 if (url && url[0])
96 m_opaque_ptr->m_url = url;
97 else
98 m_opaque_ptr->m_url.clear();
99 }
100
GetRsyncEnabled()101 bool SBPlatformConnectOptions::GetRsyncEnabled() {
102 return m_opaque_ptr->m_rsync_enabled;
103 }
104
EnableRsync(const char * options,const char * remote_path_prefix,bool omit_hostname_from_remote_path)105 void SBPlatformConnectOptions::EnableRsync(
106 const char *options, const char *remote_path_prefix,
107 bool omit_hostname_from_remote_path) {
108 m_opaque_ptr->m_rsync_enabled = true;
109 m_opaque_ptr->m_rsync_omit_hostname_from_remote_path =
110 omit_hostname_from_remote_path;
111 if (remote_path_prefix && remote_path_prefix[0])
112 m_opaque_ptr->m_rsync_remote_path_prefix = remote_path_prefix;
113 else
114 m_opaque_ptr->m_rsync_remote_path_prefix.clear();
115
116 if (options && options[0])
117 m_opaque_ptr->m_rsync_options = options;
118 else
119 m_opaque_ptr->m_rsync_options.clear();
120 }
121
DisableRsync()122 void SBPlatformConnectOptions::DisableRsync() {
123 m_opaque_ptr->m_rsync_enabled = false;
124 }
125
GetLocalCacheDirectory()126 const char *SBPlatformConnectOptions::GetLocalCacheDirectory() {
127 return m_opaque_ptr->m_local_cache_directory.GetCString();
128 }
129
SetLocalCacheDirectory(const char * path)130 void SBPlatformConnectOptions::SetLocalCacheDirectory(const char *path) {
131 if (path && path[0])
132 m_opaque_ptr->m_local_cache_directory.SetCString(path);
133 else
134 m_opaque_ptr->m_local_cache_directory = ConstString();
135 }
136
137 //----------------------------------------------------------------------
138 // SBPlatformShellCommand
139 //----------------------------------------------------------------------
SBPlatformShellCommand(const char * shell_command)140 SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_command)
141 : m_opaque_ptr(new PlatformShellCommand(shell_command)) {}
142
SBPlatformShellCommand(const SBPlatformShellCommand & rhs)143 SBPlatformShellCommand::SBPlatformShellCommand(
144 const SBPlatformShellCommand &rhs)
145 : m_opaque_ptr(new PlatformShellCommand()) {
146 *m_opaque_ptr = *rhs.m_opaque_ptr;
147 }
148
~SBPlatformShellCommand()149 SBPlatformShellCommand::~SBPlatformShellCommand() { delete m_opaque_ptr; }
150
Clear()151 void SBPlatformShellCommand::Clear() {
152 m_opaque_ptr->m_output = std::string();
153 m_opaque_ptr->m_status = 0;
154 m_opaque_ptr->m_signo = 0;
155 }
156
GetCommand()157 const char *SBPlatformShellCommand::GetCommand() {
158 if (m_opaque_ptr->m_command.empty())
159 return NULL;
160 return m_opaque_ptr->m_command.c_str();
161 }
162
SetCommand(const char * shell_command)163 void SBPlatformShellCommand::SetCommand(const char *shell_command) {
164 if (shell_command && shell_command[0])
165 m_opaque_ptr->m_command = shell_command;
166 else
167 m_opaque_ptr->m_command.clear();
168 }
169
GetWorkingDirectory()170 const char *SBPlatformShellCommand::GetWorkingDirectory() {
171 if (m_opaque_ptr->m_working_dir.empty())
172 return NULL;
173 return m_opaque_ptr->m_working_dir.c_str();
174 }
175
SetWorkingDirectory(const char * path)176 void SBPlatformShellCommand::SetWorkingDirectory(const char *path) {
177 if (path && path[0])
178 m_opaque_ptr->m_working_dir = path;
179 else
180 m_opaque_ptr->m_working_dir.clear();
181 }
182
GetTimeoutSeconds()183 uint32_t SBPlatformShellCommand::GetTimeoutSeconds() {
184 if (m_opaque_ptr->m_timeout)
185 return m_opaque_ptr->m_timeout->count();
186 return UINT32_MAX;
187 }
188
SetTimeoutSeconds(uint32_t sec)189 void SBPlatformShellCommand::SetTimeoutSeconds(uint32_t sec) {
190 if (sec == UINT32_MAX)
191 m_opaque_ptr->m_timeout = llvm::None;
192 else
193 m_opaque_ptr->m_timeout = std::chrono::seconds(sec);
194 }
195
GetSignal()196 int SBPlatformShellCommand::GetSignal() { return m_opaque_ptr->m_signo; }
197
GetStatus()198 int SBPlatformShellCommand::GetStatus() { return m_opaque_ptr->m_status; }
199
GetOutput()200 const char *SBPlatformShellCommand::GetOutput() {
201 if (m_opaque_ptr->m_output.empty())
202 return NULL;
203 return m_opaque_ptr->m_output.c_str();
204 }
205
206 //----------------------------------------------------------------------
207 // SBPlatform
208 //----------------------------------------------------------------------
SBPlatform()209 SBPlatform::SBPlatform() : m_opaque_sp() {}
210
SBPlatform(const char * platform_name)211 SBPlatform::SBPlatform(const char *platform_name) : m_opaque_sp() {
212 Status error;
213 if (platform_name && platform_name[0])
214 m_opaque_sp = Platform::Create(ConstString(platform_name), error);
215 }
216
~SBPlatform()217 SBPlatform::~SBPlatform() {}
218
IsValid() const219 bool SBPlatform::IsValid() const { return m_opaque_sp.get() != NULL; }
220
Clear()221 void SBPlatform::Clear() { m_opaque_sp.reset(); }
222
GetName()223 const char *SBPlatform::GetName() {
224 PlatformSP platform_sp(GetSP());
225 if (platform_sp)
226 return platform_sp->GetName().GetCString();
227 return NULL;
228 }
229
GetSP() const230 lldb::PlatformSP SBPlatform::GetSP() const { return m_opaque_sp; }
231
SetSP(const lldb::PlatformSP & platform_sp)232 void SBPlatform::SetSP(const lldb::PlatformSP &platform_sp) {
233 m_opaque_sp = platform_sp;
234 }
235
GetWorkingDirectory()236 const char *SBPlatform::GetWorkingDirectory() {
237 PlatformSP platform_sp(GetSP());
238 if (platform_sp)
239 return platform_sp->GetWorkingDirectory().GetCString();
240 return NULL;
241 }
242
SetWorkingDirectory(const char * path)243 bool SBPlatform::SetWorkingDirectory(const char *path) {
244 PlatformSP platform_sp(GetSP());
245 if (platform_sp) {
246 if (path)
247 platform_sp->SetWorkingDirectory(FileSpec(path));
248 else
249 platform_sp->SetWorkingDirectory(FileSpec());
250 return true;
251 }
252 return false;
253 }
254
ConnectRemote(SBPlatformConnectOptions & connect_options)255 SBError SBPlatform::ConnectRemote(SBPlatformConnectOptions &connect_options) {
256 SBError sb_error;
257 PlatformSP platform_sp(GetSP());
258 if (platform_sp && connect_options.GetURL()) {
259 Args args;
260 args.AppendArgument(
261 llvm::StringRef::withNullAsEmpty(connect_options.GetURL()));
262 sb_error.ref() = platform_sp->ConnectRemote(args);
263 } else {
264 sb_error.SetErrorString("invalid platform");
265 }
266 return sb_error;
267 }
268
DisconnectRemote()269 void SBPlatform::DisconnectRemote() {
270 PlatformSP platform_sp(GetSP());
271 if (platform_sp)
272 platform_sp->DisconnectRemote();
273 }
274
IsConnected()275 bool SBPlatform::IsConnected() {
276 PlatformSP platform_sp(GetSP());
277 if (platform_sp)
278 return platform_sp->IsConnected();
279 return false;
280 }
281
GetTriple()282 const char *SBPlatform::GetTriple() {
283 PlatformSP platform_sp(GetSP());
284 if (platform_sp) {
285 ArchSpec arch(platform_sp->GetSystemArchitecture());
286 if (arch.IsValid()) {
287 // Const-ify the string so we don't need to worry about the lifetime of
288 // the string
289 return ConstString(arch.GetTriple().getTriple().c_str()).GetCString();
290 }
291 }
292 return NULL;
293 }
294
GetOSBuild()295 const char *SBPlatform::GetOSBuild() {
296 PlatformSP platform_sp(GetSP());
297 if (platform_sp) {
298 std::string s;
299 if (platform_sp->GetOSBuildString(s)) {
300 if (!s.empty()) {
301 // Const-ify the string so we don't need to worry about the lifetime of
302 // the string
303 return ConstString(s.c_str()).GetCString();
304 }
305 }
306 }
307 return NULL;
308 }
309
GetOSDescription()310 const char *SBPlatform::GetOSDescription() {
311 PlatformSP platform_sp(GetSP());
312 if (platform_sp) {
313 std::string s;
314 if (platform_sp->GetOSKernelDescription(s)) {
315 if (!s.empty()) {
316 // Const-ify the string so we don't need to worry about the lifetime of
317 // the string
318 return ConstString(s.c_str()).GetCString();
319 }
320 }
321 }
322 return NULL;
323 }
324
GetHostname()325 const char *SBPlatform::GetHostname() {
326 PlatformSP platform_sp(GetSP());
327 if (platform_sp)
328 return platform_sp->GetHostname();
329 return NULL;
330 }
331
GetOSMajorVersion()332 uint32_t SBPlatform::GetOSMajorVersion() {
333 llvm::VersionTuple version;
334 if (PlatformSP platform_sp = GetSP())
335 version = platform_sp->GetOSVersion();
336 return version.empty() ? UINT32_MAX : version.getMajor();
337 }
338
GetOSMinorVersion()339 uint32_t SBPlatform::GetOSMinorVersion() {
340 llvm::VersionTuple version;
341 if (PlatformSP platform_sp = GetSP())
342 version = platform_sp->GetOSVersion();
343 return version.getMinor().getValueOr(UINT32_MAX);
344 }
345
GetOSUpdateVersion()346 uint32_t SBPlatform::GetOSUpdateVersion() {
347 llvm::VersionTuple version;
348 if (PlatformSP platform_sp = GetSP())
349 version = platform_sp->GetOSVersion();
350 return version.getSubminor().getValueOr(UINT32_MAX);
351 }
352
Get(SBFileSpec & src,SBFileSpec & dst)353 SBError SBPlatform::Get(SBFileSpec &src, SBFileSpec &dst) {
354 SBError sb_error;
355 PlatformSP platform_sp(GetSP());
356 if (platform_sp) {
357 sb_error.ref() = platform_sp->GetFile(src.ref(), dst.ref());
358 } else {
359 sb_error.SetErrorString("invalid platform");
360 }
361 return sb_error;
362 }
363
Put(SBFileSpec & src,SBFileSpec & dst)364 SBError SBPlatform::Put(SBFileSpec &src, SBFileSpec &dst) {
365 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
366 if (src.Exists()) {
367 uint32_t permissions = FileSystem::Instance().GetPermissions(src.ref());
368 if (permissions == 0) {
369 if (FileSystem::Instance().IsDirectory(src.ref()))
370 permissions = eFilePermissionsDirectoryDefault;
371 else
372 permissions = eFilePermissionsFileDefault;
373 }
374
375 return platform_sp->PutFile(src.ref(), dst.ref(), permissions);
376 }
377
378 Status error;
379 error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'",
380 src.ref().GetPath().c_str());
381 return error;
382 });
383 }
384
Install(SBFileSpec & src,SBFileSpec & dst)385 SBError SBPlatform::Install(SBFileSpec &src, SBFileSpec &dst) {
386 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
387 if (src.Exists())
388 return platform_sp->Install(src.ref(), dst.ref());
389
390 Status error;
391 error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'",
392 src.ref().GetPath().c_str());
393 return error;
394 });
395 }
396
Run(SBPlatformShellCommand & shell_command)397 SBError SBPlatform::Run(SBPlatformShellCommand &shell_command) {
398 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
399 const char *command = shell_command.GetCommand();
400 if (!command)
401 return Status("invalid shell command (empty)");
402
403 const char *working_dir = shell_command.GetWorkingDirectory();
404 if (working_dir == NULL) {
405 working_dir = platform_sp->GetWorkingDirectory().GetCString();
406 if (working_dir)
407 shell_command.SetWorkingDirectory(working_dir);
408 }
409 return platform_sp->RunShellCommand(command, FileSpec(working_dir),
410 &shell_command.m_opaque_ptr->m_status,
411 &shell_command.m_opaque_ptr->m_signo,
412 &shell_command.m_opaque_ptr->m_output,
413 shell_command.m_opaque_ptr->m_timeout);
414 });
415 }
416
Launch(SBLaunchInfo & launch_info)417 SBError SBPlatform::Launch(SBLaunchInfo &launch_info) {
418 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
419 ProcessLaunchInfo info = launch_info.ref();
420 Status error = platform_sp->LaunchProcess(info);
421 launch_info.set_ref(info);
422 return error;
423 });
424 }
425
Kill(const lldb::pid_t pid)426 SBError SBPlatform::Kill(const lldb::pid_t pid) {
427 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
428 return platform_sp->KillProcess(pid);
429 });
430 }
431
ExecuteConnected(const std::function<Status (const lldb::PlatformSP &)> & func)432 SBError SBPlatform::ExecuteConnected(
433 const std::function<Status(const lldb::PlatformSP &)> &func) {
434 SBError sb_error;
435 const auto platform_sp(GetSP());
436 if (platform_sp) {
437 if (platform_sp->IsConnected())
438 sb_error.ref() = func(platform_sp);
439 else
440 sb_error.SetErrorString("not connected");
441 } else
442 sb_error.SetErrorString("invalid platform");
443
444 return sb_error;
445 }
446
MakeDirectory(const char * path,uint32_t file_permissions)447 SBError SBPlatform::MakeDirectory(const char *path, uint32_t file_permissions) {
448 SBError sb_error;
449 PlatformSP platform_sp(GetSP());
450 if (platform_sp) {
451 sb_error.ref() =
452 platform_sp->MakeDirectory(FileSpec(path), file_permissions);
453 } else {
454 sb_error.SetErrorString("invalid platform");
455 }
456 return sb_error;
457 }
458
GetFilePermissions(const char * path)459 uint32_t SBPlatform::GetFilePermissions(const char *path) {
460 PlatformSP platform_sp(GetSP());
461 if (platform_sp) {
462 uint32_t file_permissions = 0;
463 platform_sp->GetFilePermissions(FileSpec(path), file_permissions);
464 return file_permissions;
465 }
466 return 0;
467 }
468
SetFilePermissions(const char * path,uint32_t file_permissions)469 SBError SBPlatform::SetFilePermissions(const char *path,
470 uint32_t file_permissions) {
471 SBError sb_error;
472 PlatformSP platform_sp(GetSP());
473 if (platform_sp) {
474 sb_error.ref() =
475 platform_sp->SetFilePermissions(FileSpec(path), file_permissions);
476 } else {
477 sb_error.SetErrorString("invalid platform");
478 }
479 return sb_error;
480 }
481
GetUnixSignals() const482 SBUnixSignals SBPlatform::GetUnixSignals() const {
483 if (auto platform_sp = GetSP())
484 return SBUnixSignals{platform_sp};
485
486 return {};
487 }
488