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